Skip to content

Instantly share code, notes, and snippets.

@hayatbiralem
Created May 13, 2022 22:57
Show Gist options
  • Save hayatbiralem/94d3137c09cbaddfe8fb06697c454220 to your computer and use it in GitHub Desktop.
Save hayatbiralem/94d3137c09cbaddfe8fb06697c454220 to your computer and use it in GitHub Desktop.
RunCloud Hub WPML Support
<?php
/**
* @wordpress-plugin
* Plugin Name: RunCloud Hub
* Description: RunCloud server-side caching for WordPress, Nginx FastCGI/Proxy Cache and Redis Object Cache
* Author: RunCloud
* Author URI: https://runcloud.io/
* Version: 1.2.1
* Requires at least: 4.9
* License: GPL-2.0 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: runcloud-hub
* Domain Path: /languages
*/
/*
Copyright 2020 RunCloud.io
All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
with this program. If not, visit: https://www.gnu.org/licenses/
*/
/*
More informations:
RunCloud Hub
https://blog.runcloud.io/runcloud-hub/
RunCache - Nginx FastCGI/Proxy Cache
https://blog.runcloud.io/nginx-fastcgi-cache/
Redis Object Cache
https://blog.runcloud.io/redis-object-cache/
*/
if (!defined('WPINC') || defined('RUNCLOUD_HUB_HOOK')) {
exit;
}
/**
* constant
*/
define('RUNCLOUD_HUB_FILE', __FILE__);
define('RUNCLOUD_HUB_HOOK', plugin_basename(RUNCLOUD_HUB_FILE));
define('RUNCLOUD_HUB_PATH', realpath(plugin_dir_path(RUNCLOUD_HUB_FILE)) . '/');
define('RUNCLOUD_HUB_PATH_LANG', RUNCLOUD_HUB_PATH . 'languages/');
define('RUNCLOUD_HUB_PATH_VIEW', RUNCLOUD_HUB_PATH . 'partials/');
define('RUNCLOUD_HUB_PATH_RSC', RUNCLOUD_HUB_PATH . 'assets/');
define('RUNCLOUD_HUB_PATH_LIB', RUNCLOUD_HUB_PATH . 'library/');
if (!defined('RUNCLOUD_HUB_VERSION')) {
define('RUNCLOUD_HUB_VERSION', '1.2.1');
}
if (!defined('RUNCLOUD_HUB_VERSION_PREV')) {
define('RUNCLOUD_HUB_VERSION_PREV', '1.2.0');
}
final class RunCloud_Hub
{
// reference
private static $name = 'RunCloud Hub';
private static $slug = 'runcloud-hub';
private static $islug = 'runcloud';
private static $db_version = 'runcloud_hub_version';
private static $db_setting = 'runcloud_hub_config';
private static $db_stats = 'runcloud_hub_stats';
private static $db_type = 'runcloud_hub_type';
private static $db_notice = 'runcloud_hub_notice';
private static $db_preload = 'runcloud_hub_preload';
private static $db_network = 'runcloud_hub_network';
private static $db_cloudflare = 'runcloud_hub_cloudflare';
// version
private static $version = RUNCLOUD_HUB_VERSION;
private static $version_prev = RUNCLOUD_HUB_VERSION_PREV;
// later
private static $hook = '';
private static $cache_path = '';
private static $ordfirst;
private static $ordlast;
// url
private static $plugin_url = '';
private static $plugin_url_assets = '';
// view
private static $checked = [];
private static $value = [];
// is cond
private static $is_purge_cache_home = false;
private static $is_purge_cache_content = false;
private static $is_purge_cache_archive = false;
private static $is_purge_cache_urlpath = false;
private static $is_run_preload = false;
private static $is_run_preload_post = false;
private static $is_redis_debug = false;
private static $is_html_footprint = false;
// purge prefix
private static $purge_prefix_var = 'runcache-purge';
private static $purge_prefix_all = 'runcache-purgeall';
// done purge
private static $done_purgeall = false;
private static $done_purgesiteall = false;
// misc
private static $dropin_file = 'object-cache.php';
private static $dropin_source = 'wp-object-cache.php';
private static $dropin_config = 'rcwp-redis-config.php';
private static $transientk = 'runcloudhub';
private static $magictoken = '__rcmagictoken';
private static $magicuserid = '__rcmagicuserid';
private static $magicexpiry = '__rcmagicexpiry';
private static $optpage = false;
private static $onfirehooks = false;
// api
private static $endpoint = 'https://manage.runcloud.io/api/runcloud-hub';
// update
private static $trunk = 'https://manage.runcloud.io/resources/runcloud-hub/latest_version';
/**
* is_wp_ssl.
*/
private static function is_wp_ssl()
{
$scheme = parse_url(get_site_url(), PHP_URL_SCHEME);
return ('https' === $scheme ? true : false);
}
/**
* is_wp_cli.
*/
private static function is_wp_cli()
{
return (defined('WP_CLI') && WP_CLI);
}
/**
* is_defined_halt.
*/
private static function is_defined_halt()
{
return defined('RUNCLOUD_HUB_HALT');
}
/**
* define_halt.
*/
private static function define_halt()
{
if (!self::is_defined_halt() && !self::is_wp_cli()) {
define('RUNCLOUD_HUB_HALT', true);
}
}
/**
* is_apache.
*/
private static function is_apache()
{
if (false !== strpos($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
return true;
}
if ('apache2handler' === php_sapi_name()) {
return true;
}
return false;
}
/**
* is_nginx.
*/
private static function is_nginx()
{
if (isset($GLOBALS['is_nginx']) && (bool) $GLOBALS['is_nginx']) {
return true;
}
if (false !== strpos($_SERVER['SERVER_SOFTWARE'], 'nginx')) {
return true;
}
return false;
}
/**
* is_srcache.
*/
private static function is_srcache()
{
if (is_multisite()) {
$blog_id = self::get_main_site_id();
switch_to_blog($blog_id);
}
$type = get_option(self::$db_type);
if (is_multisite()) {
restore_current_blog();
}
return ( $type === 'sr' || $type === 'srcache' ? true : false );
}
/**
* switch_cache_type.
*/
private static function switch_cache_type( $status = false )
{
if ( self::is_srcache() ) {
$updated = self::update_cache_type('fastcgi');
$debug_message = sprintf( esc_html__('Switching cache purger type from %s to %s', 'runcloud-hub'), 'sr', 'fastcgi' );
}
else {
$updated = self::update_cache_type('sr');
$debug_message = sprintf( esc_html__('Switching cache purger type from %s to %s', 'runcloud-hub'), 'fastcgi', 'sr' );
}
self::debug(__METHOD__, $debug_message);
if ( $updated ) {
$req_status = [
'code' => 200,
'status' => esc_html__('Switching cache purger type was successful.', 'runcloud-hub'),
];
}
else {
$req_status = [
'code' => 0,
'status' => esc_html__('Switching cache purger type was failed.', 'runcloud-hub'),
];
}
return $req_status;
}
/**
* update_cache_type.
*/
public static function update_cache_type($type, &$message = '') {
$cache_type = get_option(self::$db_type);
if ( $cache_type === $type ) {
$message = sprintf( esc_html__('Updating the cache type is not needed. Cache type: %s', 'runcloud-hub'), $type );
self::debug(__METHOD__, $message);
return true;
}
$updated = update_option(self::$db_type, $type);
if ($updated) {
$message = sprintf( esc_html__('Updating the cache type was successful. Cache type: %s', 'runcloud-hub'), $type );
}
else {
$message = esc_html__('Updating the cache type was failed.', 'runcloud-hub');
}
self::debug(__METHOD__, $message);
return $updated;
}
/**
* is_ajax.
*/
private static function is_ajax()
{
if ( wp_doing_ajax() ) {
return true;
}
if ( ! empty( $_SERVER[ 'HTTP_X_REQUESTED_WITH' ] ) && 'xmlhttprequest' === strtolower( $_SERVER[ 'HTTP_X_REQUESTED_WITH' ]) ) {
return true;
}
return false;
}
/**
* is_fl_builder.
*/
private static function is_fl_builder()
{
if ( isset($_POST) && isset($_POST['fl_builder']) ) {
return true;
}
if ( isset($_GET) && isset($_GET['fl_builder']) ) {
return true;
}
return false;
}
/**
* fastcgi_close.
*/
private static function fastcgi_close()
{
if ((php_sapi_name() === 'fpm-fcgi')
&& function_exists('fastcgi_finish_request')) {
@session_write_close();
@fastcgi_finish_request();
}
}
/**
* close_exit.
*/
private static function close_exit($content = '')
{
if (!empty($content)) {
if (is_array($content)) {
header('Content-Type: application/json');
echo json_encode($content, JSON_UNESCAPED_SLASHES);
}
else {
echo esc_html($content);
}
}
self::fastcgi_close();
exit;
}
/**
* register_locale.
*/
private static function register_locale()
{
add_action(
'plugins_loaded',
function () {
load_plugin_textdomain(
'runcloud-hub',
false,
RUNCLOUD_HUB_PATH_LANG
);
},
0
);
}
public static function wp_cache_delete() {
wp_cache_delete('uninstall_plugins', 'options');
wp_cache_delete('alloptions', 'options');
wp_cache_delete('notoptions', 'options');
wp_cache_delete(self::get_main_site_id().'-alloptions', 'site-options');
wp_cache_delete(self::get_main_site_id().'-notoptions', 'site-options');
wp_cache_delete(self::get_main_site_id().'-active_sitewide_plugins', 'site-options');
}
/**
* register_init.
*/
public static function register_init()
{
self::register_locale();
self::register_wpcli_hooks();
self::$hook = RUNCLOUD_HUB_HOOK;
self::$plugin_url = plugin_dir_url(RUNCLOUD_HUB_FILE);
self::$plugin_url_assets = self::$plugin_url . 'assets/';
self::$cache_path = (defined('RUNCLOUD_HUB_PATH_CACHE') ? trailingslashit(RUNCLOUD_HUB_PATH_CACHE) : WP_CONTENT_DIR . '/cache/' . self::$slug . '/');
self::$ordfirst = -PHP_INT_MAX;
self::$ordlast = PHP_INT_MAX;
$__varfunc_maybe_clear_alloptions_cache = function ($option) {
if (!wp_installing()) {
$alloptions = wp_load_alloptions();
if (isset($alloptions[$option])) {
self::wp_cache_delete();
}
}
};
add_action('added_option', $__varfunc_maybe_clear_alloptions_cache);
add_action('updated_option', $__varfunc_maybe_clear_alloptions_cache);
add_action('deleted_option', $__varfunc_maybe_clear_alloptions_cache);
self::reset_purge_action();
if (defined('RUNCLOUD_HUB_OPTPAGE') && (bool) RUNCLOUD_HUB_OPTPAGE) {
self::$optpage = true;
}
define('RUNCLOUD_HUB_INIT', true);
}
/**
* register_cron_schedules.
*/
private static function register_cron_schedules()
{
add_action(
'cron_schedules',
function ($schedules) {
$name = self::$slug . '-minute';
$schedules[$name] = [
'interval' => MINUTE_IN_SECONDS,
'display' => $name,
];
$name = self::$slug . '-hour';
$schedules[$name] = [
'interval' => HOUR_IN_SECONDS,
'display' => $name,
];
$name = self::$slug . '-day';
$schedules[$name] = [
'interval' => DAY_IN_SECONDS,
'display' => $name,
];
$name = self::$slug . '-week';
$schedules[$name] = [
'interval' => WEEK_IN_SECONDS,
'display' => $name,
];
$name = self::$slug . '-month';
$schedules[$name] = [
'interval' => MONTH_IN_SECONDS,
'display' => $name,
];
$name = self::$slug . '-year';
$schedules[$name] = [
'interval' => YEAR_IN_SECONDS,
'display' => $name,
];
return $schedules;
},
self::$ordlast
);
}
/**
* default_settings.
*/
private static function default_settings()
{
$options = [
'purge_permalink_onn' => 1,
'purge_theme_switch_onn' => 1,
'purge_customize_onn' => 0,
'purge_upgrader_onn' => 0,
'purge_plugin_onn' => 0,
'purge_navmenu_onn' => 0,
'purge_sidebar_onn' => 0,
'purge_widget_onn' => 0,
'homepage_post_onn' => 1,
'homepage_removed_onn' => 1,
'content_publish_onn' => 1,
'content_comment_approved_onn' => 1,
'archives_content_onn' => 1,
'archives_category_onn' => 1,
'archives_cpt_onn' => 1,
'archives_author_onn' => 0,
'archives_feed_onn' => 0,
'redis_cache_onn' => 0,
'redis_prefix' => '',
'redis_maxttl_onn' => 1,
'redis_maxttl_int' => 1,
'redis_maxttl_unt' => 86400,
'redis_maxttl_var' => 86400,
'redis_ignored_groups_onn' => 1,
'redis_ignored_groups_mch' => [
'counts',
'plugins',
'themes',
'comment',
'wc_session_id',
'bp_notifications',
'bp_messages',
'bp_pages',
],
'redis_debug_onn' => 0,
'rcapi_key' => '',
'rcapi_secret' => '',
'rcapi_webapp_id' => '',
'rcapi_magiclink_onn' => 1,
'stats_onn' => 1,
'stats_schedule_onn' => 1,
'stats_schedule_int' => 1,
'stats_schedule_unt' => 86400,
'stats_schedule_var' => 86400,
'stats_transfer_onn' => 1,
'stats_transfer_var' => 'daily',
'stats_health_onn' => 1,
'stats_health_var' => 'hourly',
'allow_cloudflare_onn' => 0,
'exclude_url_onn' => 1,
'exclude_url_mch' => [
'/.well-known.*',
'/wp-admin/',
'wp-.*.php',
'index.php',
'/feed/',
'sitemap.*.xml',
'/login.*',
'/cart.*',
'/checkout.*',
'/my-account.*',
],
'exclude_cookie_onn' => 1,
'exclude_cookie_mch' => [
'wordpress_sec_[a-f0-9]+',
'wordpress_logged_in',
'woocommerce_cart_hash',
'woocommerce_items_in_cart',
'wp_woocommerce_session',
],
'exclude_auto_onn' => 1,
'exclude_browser_onn' => 0,
'exclude_browser_mch' => [],
'exclude_visitorip_onn' => 0,
'exclude_visitorip_mch' => [],
'ignore_query_onn' => 1,
'ignore_query_mch' => [
'utm_source',
'utm_medium',
'utm_campaign',
'utm_expid',
'fb_action_ids',
'fb_action_types',
'fb_source',
'fbclid',
'gclid',
'age-verified',
'ao_noptimize',
'usqp',
'cn-reloaded',
'_ga',
],
'allow_query_onn' => 0,
'allow_query_mch' => [],
'exclude_query_onn' => 0,
'exclude_query_mch' => [],
'schedule_purge_onn' => 0,
'schedule_purge_int' => 12,
'schedule_purge_unt' => 3600,
'schedule_purge_var' => 43200,
'url_path_onn' => 0,
'url_path_mch' => [],
'html_footprint_onn' => 0,
'cache_key_extra_onn' => 0,
'cache_key_extra_var' => '',
'preload_speed' => 12,
'preload_post_onn' => 0,
'preload_onn' => 0,
'preload_schedule_onn' => 0,
'preload_schedule_int' => 1,
'preload_schedule_unt' => 86400,
'preload_schedule_var' => 86400,
'preload_path_onn' => 0,
'preload_path_mch' => [],
'cloudflare_onn' => 0,
'cloudflare_email' => '',
'cloudflare_apikey' => '',
'cloudflare_purgeall_onn' => 0,
'cloudflare_purgeurl_onn' => 0,
];
return $options;
}
/**
* can_manage_network_options.
*/
private static function can_manage_network_options()
{
return (is_multisite() && current_user_can(apply_filters('capability', 'manage_network_options')));
}
/**
* can_manage_network_plugins.
*/
private static function can_manage_network_plugins()
{
return (is_multisite() && current_user_can(apply_filters('capability_network', 'manage_network_plugins')));
}
/**
* can_manage_options.
*/
private static function can_manage_options()
{
return (current_user_can(apply_filters('capability', 'manage_options')));
}
/**
* is_client_mode.
*/
public static function is_client_mode()
{
return ( defined('RUNCLOUD_HUB_CLIENT_MODE') && RUNCLOUD_HUB_CLIENT_MODE ? true : false );
}
/**
* get_main_site_id.
*/
public static function get_main_site_id()
{
return get_main_site_id();
}
/**
* get_main_site_url.
*/
public static function get_main_site_url()
{
return get_site_url(self::get_main_site_id());
}
/**
* is_main_site.
*/
public static function is_main_site()
{
return is_main_site();
}
/**
* is_subdirectory.
*/
public static function is_subdirectory()
{
if ( is_multisite() ) {
return false;
}
$url = untrailingslashit(self::home_url());
$part = wp_parse_url($url);
return (!empty($part['path']) ? true : false);
}
/**
* home_url.
*/
private static function home_url( $path = '', $scheme = null ) {
return self::get_home_url( null, $path, $scheme );
}
/**
* get_home_url.
*/
private static function get_home_url( $blog_id = null, $path = '', $scheme = null ) {
global $pagenow;
$orig_scheme = $scheme;
if ( empty( $blog_id ) || ! is_multisite() ) {
$url = get_option( 'home' );
} else {
switch_to_blog( $blog_id );
$url = get_option( 'home' );
restore_current_blog();
}
if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ), true ) ) {
if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $pagenow ) {
$scheme = 'https';
} else {
$scheme = parse_url( $url, PHP_URL_SCHEME );
}
}
$url = set_url_scheme( $url, $scheme );
if ( $path && is_string( $path ) ) {
$url .= '/' . ltrim( $path, '/' );
}
return $url;
}
/**
* remove_protocol.
*/
private static function remove_protocol($host)
{
return preg_replace('@^(https?://|//)@', '', trim($host));
}
/**
* remove_www.
*/
private static function remove_www($host)
{
return preg_replace('/^www\./', '', $host);
}
/**
* is_num.
*/
public static function is_num($str)
{
return preg_match('@^\d+$@', $str);
}
/**
* install_options.
*/
private static function install_options($all_site = false)
{
$__varfunc_install = function ($blog_id) {
$options = self::default_settings();
$options['redis_prefix'] = self::redis_key_prefix($options['redis_prefix'], $blog_id);
add_option(self::$db_setting, $options);
self::register_cron_hooks();
};
if (is_multisite() && self::can_manage_network_options() && $all_site) {
foreach (get_sites(array('number' => 2000)) as $site) {
switch_to_blog($site->blog_id);
$__varfunc_install($site->blog_id);
restore_current_blog();
}
} else {
$__varfunc_install(get_current_blog_id());
}
}
/**
* uninstall_options.
*/
private static function uninstall_options($all_site = false)
{
self::wp_cache_delete();
if ( !self::$onfirehooks ) {
if (is_multisite()) {
self::late_purge_cache_redis_all();
}
else {
self::late_purge_cache_redis();
}
}
$__varfunc_uninstall = function () {
delete_option(self::$db_setting);
self::register_cron_hooks(false);
};
if (is_multisite() && self::can_manage_network_options() && $all_site) {
foreach (get_sites(array('number' => 2000)) as $site) {
switch_to_blog($site->blog_id);
$__varfunc_uninstall();
restore_current_blog();
}
} else {
$__varfunc_uninstall();
}
}
/**
* stats_is_enabled.
*/
private static function stats_is_enabled() {
$options = self::get_setting();
if (empty($options['rcapi_key']) || empty($options['rcapi_secret']) || empty($options['rcapi_webapp_id'])) {
return false;
}
if (empty($options['stats_onn'])) {
return false;
}
if (empty($options['stats_transfer_onn']) && empty($options['stats_health_onn'])) {
return false;
}
return true;
}
/**
* redis_is_connect.
*/
public static function redis_is_connect()
{
global $wp_object_cache;
if ( method_exists( $wp_object_cache, 'redis_status' ) ) {
return $wp_object_cache->redis_status();
}
return false;
}
/**
* redis_is_enabled.
*/
public static function redis_is_enabled()
{
if (!is_multisite()) {
return self::get_setting('redis_cache_onn');
}
else {
if(defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
$blog_id = self::get_main_site_id();
return self::get_setting('redis_cache_onn', $blog_id);
}
else {
return self::get_setting('redis_cache_onn');
}
}
else {
$blog_id = self::get_main_site_id();
return self::get_setting('redis_cache_onn', $blog_id);
}
}
return false;
}
/**
* redis_can_enable.
*/
public static function redis_can_enable()
{
if (!is_multisite()) {
return true;
}
else {
if (self::is_main_site()) {
return true;
}
else {
if(defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
return false;
}
else {
return true;
}
}
}
}
return false;
}
/**
* add_redis_stats.
*/
public static function add_redis_stats() {
if (!self::can_manage_options()) {
return;
}
if (!self::redis_is_enabled()) {
return;
}
if (defined('DOING_AJAX') && DOING_AJAX) {
return;
}
if (defined('DOING_CRON') && DOING_CRON) {
return;
}
if (defined('WP_CLI') && WP_CLI) {
return;
}
if (defined('REST_REQUEST') && REST_REQUEST) {
return;
}
if (function_exists('wp_is_json_request') && wp_is_json_request()) {
return;
}
// jetpack stats
if (isset($_GET['noheader'])) {
return;
}
$output = '';
if (self::redis_is_connect()) {
global $wp_object_cache;
if (method_exists($wp_object_cache, 'info')) {
$info = $wp_object_cache->info();
$info_hits = isset($info->hits) ? $info->hits : '';
$info_misses = isset($info->misses) ? $info->misses : '';
$info_ratio = isset($info->ratio) ? $info->ratio : '';
$info_bytes = isset($info->bytes) ? size_format( $info->bytes, 2 ) : '';
$output = sprintf(esc_html__('Redis Object Cache: Hits %s, Misses %s, Hit Ratio %s%s, Size %s', 'runcloud-hub'), $info_hits, $info_misses, $info_ratio, '%', $info_bytes);
}
else {
$output = esc_html__('Redis Object Cache: Could not get statistics info', 'runcloud-hub');
}
}
else {
$output = esc_html__('Redis Object Cache: Not connected', 'runcloud-hub');
}
if (!empty($output)) {
echo '<style>.rc-redis-debug{background:#23282d;color:#ccc;text-align:center;padding:10px;font-size:14px;line-height:20px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;}.wp-admin .rc-redis-debug{margin-left:160px;}.wp-admin.folded .rc-redis-debug{margin-left:36px;}</style>';
echo '<div class="rc-redis-debug">';
echo esc_html($output);
echo '</div>';
}
}
/**
* redis_key_prefix.
*/
public static function redis_key_prefix($salt = '', $blog_id = '')
{
if (empty($blog_id)) {
$blog_id = get_current_blog_id();
}
if (empty($salt)) {
$salt = self::get_hash(get_site_url() . md5(time() . $blog_id), 14);
}
$key = self::get_hash($salt . $blog_id, 14);
return $key;
}
/**
* get_dropin_source_file.
*/
private static function get_dropin_source_file()
{
return RUNCLOUD_HUB_PATH_LIB . self::$dropin_source;
}
/**
* get_dropin_file.
*/
private static function get_dropin_file()
{
return WP_CONTENT_DIR . '/' . self::$dropin_file;
}
/**
* get_dropin_config_file.
*/
private static function get_dropin_config_file()
{
return WP_CONTENT_DIR . '/' . self::$dropin_config;
}
/**
* is_dropin_exists.
*/
private static function is_dropin_exists()
{
$file = self::get_dropin_file();
if (is_file($file) && is_readable($file)) {
clearstatcache(true, $file);
return true;
}
return false;
}
/**
* is_dropin_config_exist.
*/
private static function is_dropin_config_exist()
{
$file = self::get_dropin_config_file();
if (is_file($file) && is_readable($file)) {
clearstatcache(true, $file);
return true;
}
return false;
}
/**
* is_dropin_hub.
*/
private static function is_dropin_hub()
{
if ( !self::is_dropin_exists() ) {
return false;
}
$dropin = get_plugin_data( self::get_dropin_file() );
if (strpos($dropin['Description'], 'RunCloud Hub') === false) {
return false;
}
return true;
}
/**
* is_dropin_valid.
*/
private static function is_dropin_valid()
{
if ( !self::is_dropin_exists() ) {
return false;
}
$dropin = get_plugin_data( self::get_dropin_file() );
$source = get_plugin_data( self::get_dropin_source_file() );
if (strpos($dropin['Description'], 'RunCloud Hub') === false) {
return false;
}
if (strcmp( $dropin['Version'], $source['Version'] ) !== 0) {
return false;
}
return true;
}
/**
* is_dropin_active.
*/
private static function is_dropin_active()
{
if ( defined('RCWP_REDIS_DISABLED') && RCWP_REDIS_DISABLED ) {
return false;
}
if ( !self::is_dropin_exists() ) {
return false;
}
$dropin = get_plugin_data( self::get_dropin_file() );
if (strpos($dropin[ 'Description' ], 'RunCloud Hub') === false) {
return false;
}
if ( defined('RCWP_REDIS_DROPIN') && RCWP_REDIS_DROPIN ) {
return true;
}
else {
return false;
}
}
/**
* is_dropin_need_install.
*/
private static function is_dropin_need_install()
{
if ( defined('RUNCLOUD_HUB_INSTALL_DROPIN') && !RUNCLOUD_HUB_INSTALL_DROPIN ) {
return false;
}
if ( self::is_dropin_exists() ) {
return false;
}
if (!is_multisite()) {
return (self::get_setting('redis_cache_onn') ? true : false);
}
else {
if(defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
$blog_id = self::get_main_site_id();
return (self::get_setting('redis_cache_onn', $blog_id) ? true : false);
}
else {
return (self::get_setting('redis_cache_onn') ? true : false);
}
}
else {
$blog_id = self::get_main_site_id();
return (self::get_setting('redis_cache_onn', $blog_id) ? true : false);
}
}
return true;
}
/**
* is_dropin_need_remove.
*/
private static function is_dropin_need_remove()
{
$is_exist = self::is_dropin_exists() && self::is_dropin_hub() ? true : false;
$is_needed = true;
if (!is_multisite()) {
$is_needed = (self::get_setting('redis_cache_onn') ? true : false);
}
else {
if(defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
$blog_id = self::get_main_site_id();
$is_needed = (self::get_setting('redis_cache_onn', $blog_id) ? true : false);
}
}
else {
$blog_id = self::get_main_site_id();
$is_needed = (self::get_setting('redis_cache_onn', $blog_id) ? true : false);
}
}
if ($is_exist && !$is_needed) {
return true;
}
else {
return false;
}
}
/**
* is_dropin_need_update.
*/
private static function is_dropin_need_update()
{
if ( defined('RCWP_REDIS_DISABLED') && RCWP_REDIS_DISABLED ) {
return false;
}
if ( !self::is_dropin_exists() ) {
return false;
}
// drop-in is enabled by other plugin
if ( self::is_dropin_exists() && !self::is_dropin_hub() ) {
return false;
}
if ( self::is_dropin_hub() && self::is_dropin_valid() ) {
return false;
}
return true;
}
/**
* is_dropin_need_replace.
*/
private static function is_dropin_need_replace()
{
if ( self::is_dropin_exists() && !self::is_dropin_hub() ) {
return true;
}
else {
return false;
}
}
/**
* is_dropin_need_install.
*/
private static function is_dropin_config_need_install()
{
if ( defined('RUNCLOUD_HUB_INSTALL_DROPIN') && !RUNCLOUD_HUB_INSTALL_DROPIN ) {
return false;
}
if ( ! self::is_dropin_active() ) {
return false;
}
if ( self::is_dropin_config_exist() ) {
return false;
}
return true;
}
/**
* is_dropin_config_need_update.
*/
private static function is_dropin_config_need_update()
{
if ( ! self::is_dropin_active() ) {
return false;
}
$file_dropin_config = self::get_dropin_config_file();
if ( !file_exists( $file_dropin_config ) ) {
return true;
}
$config = file_exists($file_dropin_config) ? @include($file_dropin_config) : array();
$main_blog_id = is_multisite() ? self::get_main_site_id() : '';
$options = self::get_setting('', $main_blog_id);
if (!isset($config['prefix'], $config['maxttl'])) {
return true;
}
if ($config['prefix'] !== $options['redis_prefix']) {
return true;
}
if ($config['maxttl'] !== (int) $options['redis_maxttl_var']) {
return true;
}
$main_status_ok = false;
$blog_status_ok = false;
$main_status = $options['redis_cache_onn'];
if ($main_status === 1 && isset($config['status']) && $config['status'] === 1) {
$main_status_ok = true;
}
elseif ($main_status !== 1 && isset($config['status']) && $config['status'] !== 1) {
$main_status_ok = true;
}
if (is_multisite() && defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
$blog_status_ok = true;
}
else {
$blog_id = get_current_blog_id();
$blog_status = self::get_setting('redis_cache_onn', $blog_id);
$url = self::home_url();
$part = wp_parse_url($url);
$host = $part['host'];
if ($blog_status === 1 && isset($config['status_sites'][$host]) && $config['status_sites'][$host] === 1) {
$blog_status_ok = true;
}
elseif ($blog_status !== 1 && isset($config['status_sites'][$host]) && $config['status_sites'][$host] !== 1) {
$blog_status_ok = true;
}
}
}
else {
$blog_status_ok = true;
}
if ($main_status_ok && $blog_status_ok) {
return false;
}
else {
return true;
}
}
/**
* try_fix_dropin.
*/
public static function try_fix_dropin()
{
self::debug(__METHOD__, 'event run');
if ( self::is_ourscreen() ) {
$req_status = null;
if (self::is_dropin_need_install() || self::is_dropin_need_update()) {
$req_status = self::install_dropin(true, true);
}
elseif (self::is_dropin_need_remove()) {
$req_status = self::uninstall_dropin(true, true);
}
if (self::is_dropin_config_need_install() || self::is_dropin_config_need_update()) {
$req_status = self::install_dropin_config(true, true);
}
if (!empty($req_status)) {
update_option(self::$db_notice, $req_status);
}
}
}
/**
* try_setup_dropin.
*/
public static function try_setup_dropin()
{
self::debug(__METHOD__, 'event run');
if (self::is_dropin_need_install() || self::is_dropin_need_update()) {
self::install_dropin(true);
}
elseif (self::is_dropin_need_remove()) {
self::uninstall_dropin(false);
}
if (self::is_dropin_config_need_install() || self::is_dropin_config_need_update()) {
self::install_dropin_config(true);
}
}
/**
* update_setting_redis.
*/
public static function update_setting_redis($value = 1)
{
if (is_multisite()) {
if (self::is_main_site()) {
self::update_setting_var('redis_cache_onn', $value);
$redis_action = $value === 1 ? 'enableall' : 'disableall';
}
else {
return array(
'code' => 0,
'status' => esc_html__('Redis Object Cache can be enabled/disabled only via Network Admin page', 'runcloud-hub'),
);
}
}
else {
self::update_setting_var('redis_cache_onn', $value);
$redis_action = $value === 1 ? 'enable' : 'disable';
}
self::wp_cache_delete();
if ($value === 1) {
$return = self::install_dropin(true, true);
}
else {
$return = self::uninstall_dropin(true, true);
}
if ($return['code'] === 200) {
update_option(self::$db_notice.'_redis_reload', 1);
update_option(self::$db_notice.'_redis_action', $redis_action);
}
return $return;
}
/**
* update_setting_redis_subsite.
*/
public static function update_setting_redis_subsite($value = 1)
{
if (is_multisite()) {
if ( defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL ) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
return array(
'code' => 0,
'status' => esc_html__('Redis Object Cache can not be enabled/disabled per site in WordPress Multisite Subdomain because of RCWP_REDIS_NETWORK_ACTIVE constant', 'runcloud-hub'),
);
}
else {
self::update_setting_var('redis_cache_onn', $value);
}
}
else {
return array(
'code' => 0,
'status' => esc_html__('Redis Object Cache can not be enabled/disabled per site in WordPress Multisite Subdirectory', 'runcloud-hub'),
);
}
}
else {
return array(
'code' => 0,
'status' => esc_html__('This feature is available only for WordPress Multisite Subdomain', 'runcloud-hub'),
);
}
self::wp_cache_delete();
$return = null;
if (self::is_dropin_need_install() || self::is_dropin_need_update()) {
$return = self::install_dropin(true, true);
}
elseif (self::is_dropin_need_remove()) {
$return = self::uninstall_dropin(true, true);
}
if (self::is_dropin_config_need_install() || self::is_dropin_config_need_update()) {
$return = self::install_dropin_config(true, true);
}
$redis_action = $value === 1 ? 'enable' : 'disable';
if ($return['code'] === 200) {
update_option(self::$db_notice.'_redis_reload', 1);
update_option(self::$db_notice.'_redis_action', $redis_action);
}
return $return;
}
/**
* update_setting_redis_all.
*/
public static function update_setting_redis_all($value = 1)
{
if (is_multisite()) {
if ( defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL ) {
if ( false !== strpos(wp_get_referer(), '/network/settings.php')) {
if(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE) {
return array(
'code' => 0,
'status' => esc_html__('This feature is not available because of RCWP_REDIS_NETWORK_ACTIVE constant', 'runcloud-hub'),
);
}
else {
foreach (get_sites(array('number' => 2000)) as $site) {
switch_to_blog($site->blog_id);
self::debug(__METHOD__.'update_setting_var:redis_cache_onn='.$redis_cache_onn, ['multisite'=>get_site_url()]);
self::update_setting_var('redis_cache_onn', $value);
restore_current_blog();
}
}
}
else {
return array(
'code' => 0,
'status' => esc_html__('This feature is available only for Network Admin', 'runcloud-hub'),
);
}
}
else {
return array(
'code' => 0,
'status' => esc_html__('This feature is available only for WordPress Multisite Subdomain', 'runcloud-hub'),
);
}
}
else {
return array(
'code' => 0,
'status' => esc_html__('This feature is available only for WordPress Multisite Subdomain', 'runcloud-hub'),
);
}
self::wp_cache_delete();
$return = null;
if ($value === 1) {
$return = self::install_dropin(true, true);
}
else {
$return = self::uninstall_dropin(true, true);
}
if (self::is_dropin_config_need_install() || self::is_dropin_config_need_update()) {
$return = self::install_dropin_config(true, true);
}
$redis_action = $value === 1 ? 'enableall' : 'disableall';
if ($return['code'] === 200) {
update_option(self::$db_notice.'_redis_reload', 1);
update_option(self::$db_notice.'_redis_action', $redis_action);
}
return $return;
}
/**
* install_dropin.
*/
public static function install_dropin($force = false, $status = false)
{
self::debug(__METHOD__, 'event run');
if ( defined('RUNCLOUD_HUB_INSTALL_DROPIN') && !RUNCLOUD_HUB_INSTALL_DROPIN ) {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Install Drop-in Stopped - RUNCLOUD_HUB_INSTALL_DROPIN', 'runcloud-hub'),
);
}
return false;
}
$file_dropin_source = self::get_dropin_source_file();
$file_dropin = self::get_dropin_file();
$perm = self::get_fileperms('file');
if (!file_exists($file_dropin_source)) {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Install Drop-in Stopped - Drop-in source file does not exist', 'runcloud-hub'),
);
}
return false;
}
$need_install = self::is_dropin_need_install();
$need_update = self::is_dropin_need_update();
if ($force || $need_install || $need_update) {
// self::wp_cache_delete();
if ($force || $need_update) {
if (file_exists($file_dropin)) {
$remove = @unlink($file_dropin);
if (!$remove) {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Install Drop-in Stopped - Drop-in file was not writable', 'runcloud-hub'),
);
}
return false;
}
}
}
if ( !file_exists($file_dropin) ) {
$buff = file_get_contents($file_dropin_source);
if ( !empty($buff) && file_put_contents($file_dropin, $buff, LOCK_EX) ) {
@chmod($file_dropin, $perm);
if (!$force) {
if ($status) {
return array(
'code' => 200,
'status' => esc_html__('Installing/updating object cache drop-in was successful', 'runcloud-hub'),
);
}
return true;
}
else {
return self::install_dropin_config($force, $status);
}
}
else {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Installing/updating object cache drop-in failed', 'runcloud-hub'),
);
}
return false;
}
}
else {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Install Drop-in Stopped - Drop-in file could not be updated', 'runcloud-hub'),
);
}
return false;
}
}
}
/**
* install_dropin_config.
*/
public static function install_dropin_config($force = false, $status = false)
{
self::debug(__METHOD__, 'event run');
if ( defined('RUNCLOUD_HUB_INSTALL_DROPIN') && !RUNCLOUD_HUB_INSTALL_DROPIN ) {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Update Drop-in Config Stopped - RUNCLOUD_HUB_INSTALL_DROPIN', 'runcloud-hub'),
);
}
return false;
}
$file_dropin_config = self::get_dropin_config_file();
$perm = self::get_fileperms('file');
$need_install = self::is_dropin_config_need_install();
$need_update = self::is_dropin_config_need_update();
if ($force || $need_install || $need_update) {
self::wp_cache_delete();
$dropin_config = self::get_dropin_config();
self::debug(__METHOD__, $dropin_config);
if ($force || $need_update) {
if (file_exists($file_dropin_config)) {
$remove = @unlink($file_dropin_config);
if (!$remove) {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Update Drop-in Config Stopped - Drop-in config file was not writable', 'runcloud-hub'),
);
}
return false;
}
}
}
if ( !file_exists($file_dropin_config) ) {
$buff = '<?php '.PHP_EOL.'return '.var_export($dropin_config,1).';'.PHP_EOL;
if ( !empty($buff) && file_put_contents($file_dropin_config, $buff, LOCK_EX) ) {
self::wp_cache_delete();
if ( !self::$onfirehooks ) {
wp_cache_flush();
}
@chmod($file_dropin_config, $perm);
if ($status) {
return array(
'code' => 200,
'status' => esc_html__('Updating object cache drop-in config was successful', 'runcloud-hub'),
);
}
return true;
}
else {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Updating object cache drop-in config failed', 'runcloud-hub'),
);
}
return false;
}
}
else {
if ($status) {
return array(
'code' => 0,
'status' => esc_html__('Install Drop-in Config Stopped - Drop-in config file could not be updated', 'runcloud-hub'),
);
}
return false;
}
}
}
/**
* get_dropin_config.
*/
private static function get_dropin_config()
{
$config = array(
'type' => '',
);
if (is_multisite()) {
if(defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
$config['type'] = 'multisite_subdomain';
}
else {
$config['type'] = 'multisite_subdirectory';
}
$url = self::get_main_site_url();
$part = wp_parse_url($url);
$config['domain'] = $part['host'];
$config['path'] = (!empty($part['path']) ? str_replace('/', '__', trim( $part['path'], '/' ) ) : '');
}
else {
$url = untrailingslashit(self::home_url());
$part = wp_parse_url($url);
if(empty($part['path'])) {
$config['type'] = 'single_domain';
}
else {
$config['type'] = 'single_subdirectory';
}
$config['domain'] = $part['host'];
$config['path'] = (!empty($part['path']) ? str_replace('/', '__', trim( $part['path'], '/' ) ) : '');
}
if (is_multisite()) {
$main_site_id = self::get_main_site_id();
switch_to_blog($main_site_id);
}
$options = self::get_setting();
$config['status'] = $options['redis_cache_onn'];
$config['prefix'] = $options['redis_prefix'];
$config['maxttl'] = (int) $options['redis_maxttl_var'];
if (!empty($options['redis_ignored_groups_onn']) && !empty($options['redis_ignored_groups_mch']) && is_array($options['redis_ignored_groups_mch'])) {
$ignored_groups = (array) $options['redis_ignored_groups_mch'];
$config['ignored_groups'] = $ignored_groups;
}
else {
$config['ignored_groups'] = [];
}
if (is_multisite()) {
restore_current_blog();
}
if ($config['type'] == 'multisite_subdomain') {
if (!(defined('RCWP_REDIS_NETWORK_ACTIVE') && RCWP_REDIS_NETWORK_ACTIVE)) {
foreach (get_sites(array('number' => 2000)) as $site) {
$blog_id = $site->blog_id;
$url = self::get_home_url($blog_id);
$part = wp_parse_url($url);
$host = $part['host'];
$config['status_sites'][$host] = self::get_setting('redis_cache_onn', $blog_id);
}
}
}
return $config;
}
/**
* uninstall_dropin.
*/
public static function uninstall_dropin($config = true, $status = false)
{
self::debug(__METHOD__, 'event run');
$removed = false;
$file_dropin = self::get_dropin_file();
if (file_exists($file_dropin)) {
self::debug(__METHOD__, 'remove dropin');
$removed = @unlink($file_dropin);
}
if ($config) {
$file_dropin_config = self::get_dropin_config_file();
if (file_exists($file_dropin_config)) {
self::debug(__METHOD__, 'remove dropin config');
@unlink($file_dropin_config);
}
}
wp_cache_flush();
if ($status) {
if ($removed) {
return array(
'code' => 200,
'status' => esc_html__('Removing object cache drop-in was successful', 'runcloud-hub'),
);
}
else {
return array(
'code' => 0,
'status' => esc_html__('Removing object cache drop-in failed', 'runcloud-hub'),
);
}
}
return $removed;
}
/**
* is_plugin_active.
*/
public static function is_plugin_active($plugin)
{
if (!function_exists('is_plugin_active')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
return is_plugin_active($plugin);
}
/**
* is_plugin_active_for_network.
*/
private static function is_plugin_active_for_network($plugin)
{
if (!function_exists('is_plugin_active_for_network')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
return is_plugin_active_for_network($plugin);
}
/**
* force_site_deactivate_plugin.
*/
private static function force_site_deactivate_plugin()
{
if ((self::can_manage_network_plugins() || self::is_wp_cli())
&& self::is_plugin_active_for_network(self::$hook)) {
foreach (get_sites(array('number' => 2000)) as $site) {
switch_to_blog($site->blog_id);
deactivate_plugins(self::$hook, true, false);
restore_current_blog();
}
}
}
/**
* callback_links.
*/
public static function callback_links($links)
{
array_unshift(
$links,
sprintf(
'<a href="%s">%s</a>',
admin_url('options-general.php?page=' . self::$slug),
esc_html__('Settings', 'runcloud-hub')
)
);
return $links;
}
/**
* callback_page.
*/
public static function callback_page()
{
$hook_id = add_submenu_page(
'options-general.php',
self::$name,
self::$name,
apply_filters('capability', 'manage_options'),
self::$slug,
[__CLASS__, 'view_index']
);
}
/**
* callback_network_page.
*/
public static function callback_network_page()
{
$hook_id = add_submenu_page(
'settings.php',
self::$name,
self::$name,
apply_filters('capability', 'manage_network_options'),
self::$slug,
[__CLASS__, 'view_network_index']
);
}
/**
* is_ourscreen.
*/
private static function is_ourscreen()
{
if(!function_exists('get_current_screen')) {
return false;
}
$screen = get_current_screen();
$allowed_screens = array(
'settings_page_'.self::$slug,
'settings_page_'.self::$slug.'-network',
);
if ( !empty($screen->id) && in_array($screen->id, $allowed_screens) ) {
return true;
}
return false;
}
/**
* view_timeduration_select.
*/
private static function view_timeduration_select($selected = '60', $skip = '')
{
$lists = [
[
'id' => 'minute',
'sec' => MINUTE_IN_SECONDS,
'txt' => esc_html__('Minutes', 'runcloud-hub'),
],
[
'id' => 'hour',
'sec' => HOUR_IN_SECONDS,
'txt' => esc_html__('Hours', 'runcloud-hub'),
],
[
'id' => 'day',
'sec' => DAY_IN_SECONDS,
'txt' => esc_html__('Days', 'runcloud-hub'),
],
[
'id' => 'week',
'sec' => WEEK_IN_SECONDS,
'txt' => esc_html__('Weeks', 'runcloud-hub'),
],
[
'id' => 'month',
'sec' => MONTH_IN_SECONDS,
'txt' => esc_html__('Months', 'runcloud-hub'),
],
[
'id' => 'year',
'sec' => YEAR_IN_SECONDS,
'txt' => esc_html__('Years', 'runcloud-hub'),
],
];
foreach ($lists as $arr) {
$id = $arr['id'];
$val = $arr['sec'];
$txt = $arr['txt'];
if (!empty($skip)) {
if (is_array($skip) && in_array($id, $skip)) {
continue;
} elseif ($skip === $id) {
continue;
}
}
echo '<option value="' . esc_attr($val) . '"' . ($val == $selected ? ' selected' : '') . '>' . esc_html($txt) . '</option>';
}
}
/**
* view_timeduration_select.
*/
private static function view_number_select($selected = 0, $min = 0, $max = 100)
{
for ($x = $min; $x <= $max; $x++) {
echo '<option value="' . esc_attr($x) . '"' . ($x == $selected ? ' selected' : '') . '>' . esc_html($x) . '</option>';
}
}
/**
* view_stats_select.
*/
private static function view_stats_select($selected = 'hourly', $skip = '')
{
$types = [
'hourly' => esc_html__('Hourly', 'runcloud-hub'),
'daily' => esc_html__('Daily', 'runcloud-hub'),
'monthly' => esc_html__('Monthly', 'runcloud-hub'),
];
foreach ($types as $id => $name) {
if (!empty($skip) && $skip === $id) {
continue;
}
echo '<option value="' . esc_attr($id) . '"' . ($id == $selected ? ' selected' : '') . '>' . esc_html($name) . '</option>';
}
}
/**
* view_action_link.
*/
private static function view_action_link($type)
{
echo esc_url_raw( self::get_action_link($type) );
}
/**
* view_site_select.
*/
private static function view_site_select()
{
foreach (get_sites(array('number' => 2000)) as $site) {
$n = $site->blog_id;
$v = self::remove_protocol(self::get_home_url($n));
if ((int) $n === (int) self::get_main_site_id()) {
$v = $v . ' '.esc_html__('(primary)', 'runcloud-hub');
}
echo '<option value="' . esc_attr($n) . '"' . ($n == $selected ? ' selected' : '') . '>' . esc_html($v) . '</option>';
}
}
/**
* view_site_switch.
*/
private static function view_site_switch()
{
if (!is_multisite()) {
return;
}
$network_active = is_plugin_active_for_network( self::$slug.'/'.self::$slug.'.php' );
$current_blog_id = get_current_blog_id();
$main_site_id = self::get_main_site_id();
if (is_network_admin()) {
echo '<option value="">' . esc_html__('Select Site', 'runcloud-hub') . '</option>';
}
if ($network_active && !is_network_admin()) {
$admin_url = network_admin_url('settings.php?page=' . self::$slug);
echo '<option value="'.esc_attr($admin_url).'">' . esc_html__('Network Admin Settings', 'runcloud-hub') . '</option>';
}
$sites = get_sites(array('number' => 2000));
foreach ($sites as $site) {
$blog_id = $site->blog_id;
switch_to_blog($blog_id);
if (!$network_active) {
$active = is_plugin_active( self::$slug.'/'.self::$slug.'.php' );
if (!$active) {
restore_current_blog();
continue;
}
}
$label = self::home_url();
$label = self::remove_protocol($label);
if ($main_site_id == $blog_id) {
$label = $label . ' '.esc_html__('(primary)', 'runcloud-hub');
}
$admin_url = admin_url('options-general.php?page=' . self::$slug);
echo '<option value="' . esc_attr($admin_url) . '"' . (!is_network_admin() && $blog_id == $current_blog_id ? ' selected' : '') . '>' . esc_html($label) . '</option>';
restore_current_blog();
}
}
/**
* view_fattr.
*/
private static function view_fattr()
{
echo 'autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"';
}
/**
* view_fname.
*/
private static function view_fname($name)
{
echo self::$db_setting . '[' . esc_attr($name) . ']';
}
/**
* view_checked.
*
* @since 0.0.0
*/
private static function view_checked($name)
{
echo (isset(self::$checked[$name]) ? esc_attr(self::$checked[$name]) : '');
}
/**
* view_rvalue.
*/
private static function view_rvalue($name)
{
return (isset(self::$value[$name]) ? self::$value[$name] : '');
}
/**
* view_fvalue.
*/
private static function view_fvalue($name)
{
echo self::view_rvalue($name);
}
/**
* view_do_preload.
*/
private static function view_do_preload()
{
$preload = get_option(self::$db_preload);
if (empty($preload)) {
return;
}
if (!isset($preload['num'], $preload['total'], $preload['type'])) {
return;
}
$num = $preload['num'];
$total = $preload['total'];
$type = $preload['type'];
if (!$total || ($total && $num >= $total)) {
delete_option(self::$db_preload);
return;
}
if ($type === 'admin') {
if ($num == 0) {
// preload homepage
$preload_url = self::home_url('/');
self::fetch_preload($preload_url, false);
// preload path
$options = self::get_setting();
if (!empty($options['preload_path_onn']) && !empty($options['preload_path_mch']) && is_array($options['preload_path_mch'])) {
foreach ($options['preload_path_mch'] as $path) {
if ('/' === $path) {
continue;
}
$path = strtolower($path);
$preload_url = self::home_url('/') . ltrim($path, '/');
self::fetch_preload($preload_url, false);
}
}
}
$time = time();
$link_cancel = self::get_action_link('preload_cancel');
$link_run_background = self::get_action_link('preload_run_background');
$inc = self::get_preload_inc();
$interval = self::get_preload_interval();
$link_trigger = admin_url('admin-post.php?action=' . self::get_hash(self::$slug . '_preload') . '&_preload=' . $time);
$link_trigger = add_query_arg('_wpnonce', wp_create_nonce('preload' . $time), $link_trigger);
echo '<div class="notice notice-info" id="runcloud-preload" ';
echo 'data-preload-abort="' . esc_url_raw($link_cancel) . '" ';
echo 'data-preload-trigger="' . esc_url_raw($link_trigger) . '" ';
echo 'data-preload-num="' . esc_attr($num) . '" ';
echo 'data-preload-total="' . esc_attr($total) . '" ';
echo 'data-preload-inc="' . esc_attr($inc) . '" ';
echo 'data-preload-interval="' . esc_attr($interval) . '">';
echo '<p id="preload-text"><strong>';
if ($num) {
esc_html_e('Preloading is running... Please wait...', 'runcloud-hub');
}
else {
esc_html_e('Preloading is started... Please wait...', 'runcloud-hub');
}
echo '</strong></p>';
echo '<p id="preload-button">';
echo '<a href="' . esc_url_raw($link_cancel) . '" class="preload-stop button button-primary">'.esc_html__('Cancel', 'runcloud-hub').'</a>';
echo '<a href="' . esc_url_raw($link_run_background) . '" class="preload-switch button-light">'.esc_html__('Switch to run in the background', 'runcloud-hub').'</a>';
echo '</p>';
echo '</div>';
}
else {
$link_cancel = self::get_action_link('preload_cancel');
$link_run_admin = self::get_action_link('preload_run_admin');
echo '<div class="notice notice-info" id="runcloud-preload">';
echo '<p id="preload-text"><strong>';
printf( esc_html__('Preloading is running in the background (%s/%s). Please refresh to see the progress.', 'runcloud-hub'), $num, $total );
echo '</strong></p>';
echo '<p id="preload-button">';
echo '<a href="' . esc_url_raw($link_cancel) . '" class="preload-stop button button-primary">'.esc_html__('Stop', 'runcloud-hub').'</a>';
echo '<a href="' . esc_url_raw($link_run_admin) . '" class="preload-switch button-light">'.esc_html__('Switch to run in the browser', 'runcloud-hub').'</a>';
echo '</p>';
echo '</div>';
}
}
/**
* callback_view_preload.
*/
public static function callback_view_preload()
{
if (!isset($_GET['_wpnonce'], $_GET['_preload'])) {
self::debug(__METHOD__, esc_html__('Invalid request', 'runcloud-hub'));
delete_option(self::$db_preload);
self::close_exit(esc_html__('Invalid request', 'runcloud-hub'));
}
if (!wp_verify_nonce($_GET['_wpnonce'], 'preload' . $_GET['_preload'])) {
self::debug(__METHOD__, esc_html__('Invalid nonce', 'runcloud-hub'));
delete_option(self::$db_preload);
self::close_exit(esc_html__('Invalid nonce', 'runcloud-hub'));
}
$preload = get_option(self::$db_preload);
if (!empty($preload) && is_array($preload)) {
if (isset($_GET['num']) && self::is_num($_GET['num'])) {
$num = (int) $_GET['num'];
if ($num >= (int) $preload['total']) {
delete_option(self::$db_preload);
self::close_exit('Done');
}
else {
$inc = self::get_preload_inc();
$urls = self::get_preload_urls($preload['num'], $inc);
if (!empty($urls)) {
foreach ($urls as $url) {
$num++;
self::debug(__METHOD__, sprintf( esc_html__('Browser Preload %s / %s : %s', 'runcloud-hub'), $num, $preload['total'], $url ) );
self::fetch_preload($url, false);
}
$preload['num'] = $num;
update_option(self::$db_preload, $preload, false);
self::close_exit($url);
}
else {
self::debug(__METHOD__, sprintf( esc_html__('Browser Preload %s / %s : %s', 'runcloud-hub'), $num, $preload['total'], esc_html__('Preload URL is empty', 'runcloud-hub') ) );
self::close_exit();
}
}
}
}
self::debug(__METHOD__, esc_html__('Browser Preload : URL is empty', 'runcloud-hub') );
self::close_exit();
}
/**
* view_do_network.
*/
private static function view_do_network()
{
if (!is_network_admin()) {
return;
}
$network = get_option(self::$db_network);
if (empty($network)) {
return;
}
if (!isset($network['num'], $network['total'], $network['type'])) {
return;
}
$num = $network['num'];
$total = $network['total'];
$type = $network['type'];
if (!$total || ($total && $num >= $total)) {
delete_option(self::$db_network);
return;
}
$time = time();
$link_cancel = self::get_action_link('network_cancel');
$inc = 1;
$interval = 2;
$link_trigger = admin_url('admin-post.php?action=' . self::get_hash(self::$slug . '_network') . '&_network=' . $time);
$link_trigger = add_query_arg('_wpnonce', wp_create_nonce('network' . $time), $link_trigger);
echo '<div class="notice notice-info" id="runcloud-network" ';
echo 'data-network-abort="' . esc_url_raw($link_cancel) . '" ';
echo 'data-network-trigger="' . esc_url_raw($link_trigger) . '" ';
echo 'data-network-num="' . esc_attr($num) . '" ';
echo 'data-network-total="' . esc_attr($total) . '" ';
echo 'data-network-inc="' . esc_attr($inc) . '" ';
echo 'data-network-interval="' . esc_attr($interval) . '">';
echo '<p id="network-text"><strong>';
if ($num) {
esc_html_e('Please wait...', 'runcloud-hub');
}
else {
esc_html_e('Please wait...', 'runcloud-hub');
}
echo '</strong></p>';
echo '<p id="network-button">';
echo '<a href="' . esc_url_raw($link_cancel) . '" class="network-stop button button-primary">'.esc_html__('Cancel', 'runcloud-hub').'</a>';
echo '</p>';
echo '</div>';
}
/**
* callback_view_network.
*/
public static function callback_view_network()
{
if (!isset($_GET['_wpnonce'], $_GET['_network'])) {
self::debug(__METHOD__, esc_html__('Invalid request', 'runcloud-hub'));
delete_option(self::$db_network);
self::close_exit(esc_html__('Invalid request', 'runcloud-hub'));
}
if (!wp_verify_nonce($_GET['_wpnonce'], 'network' . $_GET['_network'])) {
self::debug(__METHOD__, esc_html__('Invalid nonce', 'runcloud-hub'));
delete_option(self::$db_network);
self::close_exit(esc_html__('Invalid nonce', 'runcloud-hub'));
}
$network = get_option(self::$db_network);
if (!empty($network) && is_array($network)) {
if (isset($_GET['num']) && self::is_num($_GET['num'])) {
$num = (int) $_GET['num'];
if ($num >= (int) $network['total']) {
delete_option(self::$db_network);
self::close_exit('Done');
}
else {
$sites = get_sites(['number' => 1, 'offset' => $num]);
if (!empty($sites)) {
$num++;
$network['num'] = $num;
update_option(self::$db_network, $network, false);
$message = '';
foreach ($sites as $site) {
switch_to_blog($site->blog_id);
if ($network['type'] == 'purge') {
$purge = self::purge_cache_all();
$message = self::home_url('/').' - '.$purge['status'];
}
restore_current_blog();
}
self::close_exit($message);
}
}
}
}
self::close_exit();
}
/**
* view_page.
*/
public static function view_page($name, $once = false)
{
$__varfunc_view = function ($name, $once = false) {
$file = RUNCLOUD_HUB_PATH_VIEW . $name . '.php';
if (is_file($file) && is_readable($file)) {
clearstatcache(true, $file);
if ($once) {
include_once $file;
} else {
include $file;
}
} else {
echo sprintf( esc_html__( 'Cannot read "%s" file', 'runcloud-hub'), $name ).'<br>';
}
};
if (!empty($name)) {
if (is_array($name)) {
foreach ($name as $nm) {
$__varfunc_view($nm);
}
} else {
$__varfunc_view($name);
}
}
}
/**
* view_index.
*/
public static function view_index($page = '')
{
$options_default = self::default_settings();
$options = self::get_setting();
self::$checked = [];
if (!empty($options) && is_array($options)) {
foreach ($options as $key => $val) {
if (preg_match('/.*_onn$/', $key)) {
$val = (int) $val;
self::$checked[$key] = (1 === $val ? ' checked' : '');
self::$value[$key] = $val;
} elseif (preg_match('/.*_mch$/', $key)) {
$ckey = str_replace('_mch', '_onn', $key);
if (!empty($val) && is_array($val)) {
self::$value[$key] = implode("\n", $val);
} else {
self::$checked[$ckey] = '';
self::$value[$key] = (!empty($options_default[$key]) && is_array($options_default[$key]) ? implode("\n", $options_default[$key]) : '');
}
} elseif (preg_match('/^rcapi.*_id$/', $key)) {
self::$value[$key] = (empty($val) ? '' : $val);
} else {
self::$value[$key] = $val;
}
}
}
$page = (!empty($page) ? esc_attr($page) : 'admin');
self::view_page($page);
}
/**
* view_network_index.
*/
public static function view_network_index()
{
self::view_index('admin-network');
}
/**
* assets_version.
*/
private static function assets_version($file)
{
$fm = RUNCLOUD_HUB_PATH_RSC . $file;
if (file_exists($fm)) {
return self::get_hash(filemtime($fm));
}
return self::get_hash(self::$version);
}
/**
* admin_assets.
*/
public static function admin_assets()
{
if ( self::can_manage_options() ) {
$fm = 'css/' . self::$islug . '-wp.css';
wp_enqueue_style(
self::$slug . '-wp',
self::$plugin_url_assets . $fm,
[],
self::assets_version($fm),
'all'
);
}
if(!self::is_ourscreen()) {
return;
}
$fm = 'css/' . self::$islug . '.css';
wp_enqueue_style(
self::$slug,
self::$plugin_url_assets . $fm,
[],
self::assets_version($fm),
'all'
);
$fm = 'js/' . self::$islug . '.js';
wp_enqueue_script(
self::$slug,
self::$plugin_url_assets . $fm,
['jquery'],
self::assets_version($fm),
true
);
}
/**
* append_wp_http_referer.
*/
private static function append_wp_http_referer()
{
$referer = '';
if (!empty($_SERVER['REQUEST_URI'])) {
$referer = filter_var(wp_unslash($_SERVER['REQUEST_URI']), FILTER_SANITIZE_URL);
$referer = '&_wp_http_referer=' . rawurlencode(remove_query_arg('fl_builder', $referer));
}
return $referer;
}
/**
* callback_bar_menu.
*/
public static function callback_bar_menu($wp_admin_bar)
{
if (!self::can_manage_options()) {
return;
}
if (is_network_admin() && !self::is_plugin_active_for_network(self::$hook)) {
return;
}
global $pagenow, $post;
$referer = self::append_wp_http_referer();
$wp_admin_bar->add_menu(
[
'id' => self::$slug,
'title' => self::$name,
]
);
$admin_url = (is_network_admin() ? network_admin_url('settings.php?page=' . self::$slug) : admin_url('options-general.php?page=' . self::$slug));
if (!self::$optpage) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-setting',
'title' => esc_html__('Settings', 'runcloud-hub'),
'href' => $admin_url . (self::is_ourscreen() ? '#setting' : ''),
]
);
}
if (is_admin()) {
if ($post && 'post.php' === $pagenow && isset($_GET['action'], $_GET['post'])) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcachepost',
'title' => esc_html__('Clear Cache Of This Post', 'runcloud-hub'),
'href' => self::get_action_link('purgepost-' . get_the_ID()),
]
);
}
} else {
if (is_singular()) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcachepost',
'title' => esc_html__('Clear Cache Of This Post', 'runcloud-hub'),
'href' => self::get_action_link('purgepost-' . get_the_ID()),
]
);
}
else {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcacheurl',
'title' => esc_html__('Clear Cache Of This URL', 'runcloud-hub'),
'href' => self::get_action_link('purgeurl'),
]
);
}
}
if (!is_network_admin()) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcacheall',
'title' => esc_html__('Clear All Cache', 'runcloud-hub'),
'href' => self::get_action_link('purgeall'),
]
);
if (self::redis_is_connect() && self::is_dropin_active()) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcacheredis',
'title' => esc_html__('Clear Redis Object Cache', 'runcloud-hub'),
'href' => self::get_action_link('purgeredis'),
]
);
}
}
else {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcacheallsites',
'title' => esc_html__('Clear All Sites Cache', 'runcloud-hub'),
'href' => self::get_action_link('purgesiteall'),
]
);
if (self::redis_is_connect() && self::is_dropin_active()) {
$wp_admin_bar->add_menu(
[
'parent' => self::$slug,
'id' => self::$slug . '-clearcacheredis',
'title' => esc_html__('Clear All Sites Redis Object Cache', 'runcloud-hub'),
'href' => self::get_action_link('purgeredisall'),
]
);
}
}
}
/**
* after_update_setting.
*/
public static function after_update_setting($old, $options)
{
if (!empty($options)) {
self::wp_cache_delete();
// 2 = reset with current changes
self::schedule_cron_purge(2);
self::schedule_cron_preload(2);
self::schedule_cron_rcstats(2);
$referer = wp_get_raw_referer();
// update rcapi push
if (!empty($referer) && preg_match('@#runcache-rules?$@', $referer, $mm)) {
add_action('shutdown', [__CLASS__, 'rcapi_push'], self::$ordlast);
}
// check cloudflare
if (!empty($referer) && preg_match('@#cloudflare?$@', $referer, $mm)) {
add_action('shutdown', [__CLASS__, 'cloudflare_update_settings'], self::$ordlast);
}
// fetch stats if stats is empty
if (!empty($referer)) {
add_action('shutdown', [__CLASS__, 'rcapi_fetch_stats'], self::$ordlast);
}
}
}
/**
* callback_register_setting.
*/
public static function callback_register_setting()
{
register_setting(
self::$slug,
self::$db_setting,
[__CLASS__, 'update_setting']
);
}
/**
* callback_notices.
*/
public static function callback_notices()
{
if (!is_admin()) {
return;
}
if (defined('DOING_AUTOSAVE') || self::is_ajax() ) {
return;
}
if (self::can_manage_options()) {
add_action('all_admin_notices', [__CLASS__, 'callback_compatibility'], self::$ordlast);
add_action('all_admin_notices', [__CLASS__, 'callback_use_permalink'], self::$ordlast);
add_action('all_admin_notices', [__CLASS__, 'callback_action_notice'], self::$ordlast);
add_action('all_admin_notices', [__CLASS__, 'callback_redis_connect'], self::$ordlast);
}
}
/**
* callback_compatibility.
*/
public static function callback_compatibility()
{
if (self::maybe_deactivate_runcache_purger()) {
$msg = esc_html__('RunCache Purger has been automatically deactivated due to superseded by the RunCloud Hub Plugin', 'runcloud-hub');
echo '<div id="rc-notice" class="notice notice-info is-dismissible">';
echo '<p>';
if (!self::is_ourscreen()) {
echo '<strong>' . self::$name . ':</strong>&nbsp;' . esc_html($msg);
} else {
echo '<strong>' . esc_html($msg) . '</strong>';
}
echo '</p>';
echo '</div>';
}
}
/**
* callback_use_permalink.
*/
public static function callback_use_permalink()
{
if (get_option('permalink_structure')) {
return;
}
if(function_exists('get_current_screen')) {
$screen = get_current_screen();
if (!empty($screen->id) && $screen->id === 'options-permalink') {
return;
}
}
$msg = esc_html__('Server-side page caching requires custom permalink structure to work properly.', 'runcloud-hub');
echo '<div id="rc-redis-notice" class="notice notice-error">';
echo '<p>';
if (!self::is_ourscreen()) {
echo '<strong>' . esc_html(self::$name) . ':</strong>&nbsp;' . esc_html($msg);
}
else {
echo '<strong>' . esc_html($msg) . '</strong>';
}
echo '</p>';
echo '<p><a class="button" href="'.esc_url(admin_url('options-permalink.php')).'">'.esc_html__('Go To Permalink Settings', 'runcloud-hub').'</a></p>';
echo '</div>';
}
/**
* callback_redis_connect.
*/
public static function callback_redis_connect()
{
if (!self::redis_is_enabled()) {
return;
}
if (!self::is_dropin_hub()) {
return;
}
if (self::redis_is_connect()) {
return;
}
$msg = esc_html__('Redis Object Cache issue - Redis is not connected!', 'runcloud-hub');
echo '<div id="rc-redis-notice" class="notice notice-error">';
echo '<p>';
if (!self::is_ourscreen()) {
echo '<strong>' . esc_html(self::$name) . ':</strong>&nbsp;' . esc_html($msg);
}
else {
echo '<strong>' . esc_html($msg) . '</strong>';
}
echo '</p>';
if (self::redis_can_enable()) {
echo '<p>'.esc_html__('Please check Redis service in your server or disable Redis object cache.', 'runcloud-hub').'</p>';
}
else {
echo '<p>'.esc_html__('Please contact site administrator to check Redis object cache.', 'runcloud-hub').'</p>';
}
echo '</div>';
}
/**
* get_action_link.
*/
private static function get_action_link($type)
{
$tag = 'action';
$referer = self::append_wp_http_referer();
if (!is_admin()) {
$referer .= '&__notadmin=1';
}
else {
$referer .= '&__admin=1';
}
return wp_nonce_url(admin_url('admin-post.php?action=' . self::get_hash(self::$slug . '_' . $tag) . '&type=' . $type . $referer), $tag . '_' . $type);
}
/**
* get_setting.
*/
public static function get_setting($key = '', $blog_id = '')
{
if ($blog_id && is_multisite()) {
switch_to_blog($blog_id);
}
$options = get_option(self::$db_setting, self::default_settings());
if (!empty($options) && is_array($options)) {
$options = array_merge(self::default_settings(), $options);
} else {
$options = [];
}
if (!empty($key)) {
if (isset($options[$key])) {
$return = $options[$key];
}
else {
$return = null;
}
}
else {
$return = $options;
}
if ($blog_id && is_multisite()) {
restore_current_blog();
}
return $return;
}
/**
* get_setting.
*/
public static function get_main_setting($key = '')
{
if (!is_multisite()) {
return self::get_setting($key);
}
else {
$network_id = self::get_main_site_id();
return self::get_setting($key, $network_id);
}
}
/**
* dump_setting.
*/
public static function dump_setting($all = true)
{
$__varfunc_options = function () {
$options = get_option(self::$db_setting, self::default_settings());
if (!empty($options) && is_array($options)) {
$options = array_merge(self::default_settings(), $options);
} else {
$options = [];
}
return $options;
};
if (is_multisite()) {
if ($all) {
$results = [];
$num = 0;
foreach (get_sites(array('number' => 2000)) as $site) {
$num++;
switch_to_blog($site->blog_id);
$results[$num]['blog_id'] = $site->blog_id;
$results[$num]['url'] = self::home_url();
$results[$num]['options'] = $__varfunc_options();
restore_current_blog();
}
return $results;
}
}
return $__varfunc_options();
}
/**
* set_settings.
*/
public static function reset_purge_action()
{
self::$is_purge_cache_home = false;
self::$is_purge_cache_content = false;
self::$is_purge_cache_archive = false;
self::$is_purge_cache_urlpath = false;
self::$is_run_preload = false;
self::$is_run_preload_post = false;
self::$is_redis_debug = false;
self::$is_html_footprint = false;
$options = self::get_setting();
if (!empty($options)) {
if (!empty($options['url_path_onn'])) {
self::$is_purge_cache_urlpath = true;
}
if (!empty($options['preload_onn'])) {
self::$is_run_preload = true;
}
if (!empty($options['preload_post_onn'])) {
self::$is_run_preload_post = true;
}
if (!empty($options['redis_debug_onn'])) {
self::$is_redis_debug = true;
}
if (!empty($options['html_footprint_onn'])) {
self::$is_html_footprint = true;
}
}
}
/**
* setting_cast_int.
*/
private static function setting_cast_int($input)
{
if (!empty($input) && is_array($input)) {
foreach ($input as $key => $val) {
if (preg_match('/.*(_onn|_int|_unt)$/', $key)) {
$input[$key] = (int) $val;
}
}
}
return $input;
}
/**
* sanitize_input.
*/
private static function sanitize_input($input)
{
if (!empty($input) && is_array($input)) {
$input = self::setting_cast_int($input);
foreach ($input as $key => $val) {
if (preg_match('/.*_int$/', $key)) {
if (('schedule_purge_int' === $key || 'preload_schedule_int' === $key) && empty($val)) {
$val = 1;
}
$key_prefix = str_replace('_int', '', $key);
$unt_key = $key_prefix . '_unt';
if (isset($input[$unt_key])) {
$unt_key_var = $key_prefix . '_var';
$input[$unt_key_var] = (0 !== $val ? ((int) $val * (int) $input[$unt_key]) : 0);
}
} elseif ( 'rcapi_webapp_id' === $key ) {
$key = trim($key);
$input[$key] = (self::is_num($val) ? (int) $val : '');
} elseif ( 'rcapi_key' === $key || 'rcapi_secret' === $key ) {
$input[$key] = trim($val);
} elseif (preg_match('/.*_mch$/', $key) && !is_array($val)) {
$list = explode("\n", str_replace(["\n", "\r"], "\n", $val));
$list = array_unique($list);
foreach ($list as $num => $lst) {
if (empty($lst)) {
unset($list[$num]);
}
if ('url_path_mch' === $key || 'exclude_url_mch' === $key || 'preload_path_mch' === $key) {
$path = wp_parse_url($lst, PHP_URL_PATH);
if (!empty($path)) {
$path = strtolower($path);
if ('/' !== $path) {
$list[$num] = $path;
} else {
unset($list[$num]);
}
}
}
}
if (!empty($list) && is_array($list)) {
$list = array_values($list);
}
$input[$key] = (is_array($list) && count($list) > 0 ? $list : []);
} elseif ('redis_prefix' === $key && empty($val)) {
$input[$key] = self::redis_key_prefix();
} elseif ('redis_port' === $key && !self::is_num($val)) {
unset($input[$key]); // reset default
} elseif ('cache_key_extra_var' === $key) {
$val = preg_replace('@[^A-Za-z0-9_$]@', '', trim($val));
if (empty($val)) {
$input['cache_key_extra_onn'] = 0;
} else {
if ( '$' !== substr($val, 0, 1) ) {
$val = '$' . $val;
}
}
$input[$key] = $val;
}
}
}
return $input;
}
/**
* update_setting.
*/
public static function update_setting($input)
{
$options = array_merge(self::default_settings(), self::get_setting());
if (!empty($input) && is_array($input)) {
foreach ($options as $key => $val) {
if (preg_match('/.*_onn$/', $key)) {
if (!isset($input[$key])) {
$input[$key] = 0;
}
}
}
} else {
$input = self::default_settings();
}
$input = self::sanitize_input($input);
$options = array_merge($options, $input);
$options['timestamp'] = gmdate('Y-m-d H:i:s') . ' UTC';
$options['update_reason'] = 'update_setting';
// rcapi key/secret only for main site
if (!self::is_main_site()) {
$options['rcapi_key'] = '';
$options['rcapi_secret'] = '';
$options['rcapi_webapp_id'] = '';
}
if (isset($options['stats_onn'])) {
$options['stats_schedule_onn'] = $options['stats_onn'];
}
if (empty($options['stats_transfer_onn']) && empty($options['stats_health_onn'])) {
$options['stats_onn'] = 0;
}
return $options;
}
/**
* update_setting_var.
*/
public static function update_setting_var($key, $value)
{
$options = self::get_setting();
if (isset($options[$key])) {
$options[$key] = $value;
$options = self::sanitize_input($options);
$options['timestamp'] = gmdate('Y-m-d H:i:s') . ' UTC';
$options['update_reason'] = 'update_setting_var_'.$key;
return update_option(self::$db_setting, $options);
}
return false;
}
/**
* update_setting_cli.
*/
public static function update_setting_cli($input)
{
$options = self::get_setting();
$input = self::sanitize_input($input);
$options = array_merge($options, $input);
$options['timestamp'] = gmdate('Y-m-d H:i:s') . ' UTC';
$options['update_reason'] = 'update_setting_cli';
return update_option(self::$db_setting, $options);
}
/**
* register_admin_hooks.
*/
public static function register_admin_hooks()
{
if (!self::$optpage) {
add_filter('plugin_action_links_' . self::$hook, [__CLASS__, 'callback_links'], self::$ordfirst);
}
add_action('admin_menu', [__CLASS__, 'callback_page'], self::$ordfirst);
if (self::is_plugin_active_for_network(self::$hook)) {
add_action('network_admin_menu', [__CLASS__, 'callback_network_page'], self::$ordfirst);
}
add_action('admin_enqueue_scripts', [__CLASS__, 'admin_assets'], self::$ordlast);
add_action('admin_bar_menu', [__CLASS__, 'callback_bar_menu'], self::$ordlast);
add_action('update_option_' . self::$db_setting, [__CLASS__, 'after_update_setting'], self::$ordlast, 2);
add_action('admin_init', [__CLASS__, 'callback_register_setting'], self::$ordfirst);
add_action('admin_post_' . self::get_hash(self::$slug . '_action'), [__CLASS__, 'callback_action'], self::$ordlast);
add_action('admin_post_' . self::$slug . '_deactivate_plugin', [__CLASS__, 'callback_deactivate_plugin']);
add_action('plugins_loaded', [__CLASS__, 'callback_notices'], self::$ordfirst);
// autologin
add_action('init', [__CLASS__, 'callback_magiclink_login'], self::$ordlast);
// cron
add_action('cron_purge_' . self::get_hash(self::$slug . 'cron_purge'), [__CLASS__, 'callback_cron_purge'], self::$ordfirst);
add_action('cron_preload_' . self::get_hash(self::$slug . 'cron_preload'), [__CLASS__, 'callback_cron_preload'], self::$ordfirst);
add_action('cron_rcstats_' . self::get_hash(self::$slug . 'cron_rcstats'), [__CLASS__, 'callback_cron_rcstats'], self::$ordfirst);
// preload
add_action('admin_post_' . self::get_hash(self::$slug . '_preload'), [__CLASS__, 'callback_view_preload'], self::$ordfirst);
add_action('preload_batch_' . self::get_hash(self::$slug . '_preload_batch'), [__CLASS__, 'callback_preload_batch'], self::$ordfirst);
// network
add_action('admin_post_' . self::get_hash(self::$slug . '_network'), [__CLASS__, 'callback_view_network'], self::$ordfirst);
}
/**
* get_user_ip.
*/
private static function get_user_ip()
{
foreach ([
'HTTP_CF_CONNECTING_IP',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_X_REAL_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR',
] as $key) {
if (!empty($_SERVER[$key])) {
$ip = explode(',', $_SERVER[$key]);
$ip = end($ip);
if (false !== filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
}
return '0.0.0.0';
}
/**
* get_user_agent.
*/
private static function get_user_agent($fallback_default = false)
{
$comp_ua = '(compatible; RunCloud-Plugin ' . self::$version . '; +https://runcloud.io)';
$default_ua = 'Mozilla/5.0 ' . $comp_ua;
$ua = '';
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
if (false === strpos($_SERVER['HTTP_USER_AGENT'], 'RunCloud-Plugin')) {
$ua = $_SERVER['HTTP_USER_AGENT'] . ' ' . $comp_ua;
} else {
$ua = $_SERVER['HTTP_USER_AGENT'];
}
}
if ($fallback_default && empty($ua)) {
$ua = $default_ua;
}
return $ua;
}
/**
* __curl_resolve_loopback.
*/
public static function __curl_resolve_loopback($handle, $r, $url)
{
$myhost = parse_url(get_site_url(), PHP_URL_HOST);
$url_host = parse_url($url, PHP_URL_HOST);
$url_scheme = parse_url($url, PHP_URL_SCHEME);
$url_port = parse_url($url, PHP_URL_PORT);
if ($myhost !== $url_host) {
return;
}
$port = 80;
if ('https' === $url_scheme) {
$port = 443;
}
if (!empty($url_port) && $url_port !== $port) {
$port = $url_port;
}
curl_setopt(
$handle,
CURLOPT_RESOLVE,
[
$url_host . ':' . $port . ':127.0.0.1',
]
);
curl_setopt(
$handle,
CURLOPT_DNS_USE_GLOBAL_CACHE,
false
);
}
/**
* purge_request.
*/
private static function purge_request($url, $options = [])
{
if (self::is_defined_halt()) {
return false;
}
$hostname = parse_url($url, PHP_URL_HOST);
static $done = [];
if (isset($done[$hostname][$url])) {
return;
}
$args = [
'method' => 'GET',
'timeout' => 10,
'redirection' => 5,
'httpversion' => '1.1',
'user-agent' => self::get_user_agent(),
'blocking' => true,
'headers' => ['Host' => $hostname],
'cookies' => [],
'body' => null,
'compress' => false,
'decompress' => true,