diff --git a/Cli.php b/Cli.php index 1d9fd4d..efb6d8c 100644 --- a/Cli.php +++ b/Cli.php @@ -33,8 +33,7 @@ function fix_environment( $args = array(), $vars = array() ) { $environment = Dispatcher::component( 'Root_Environment' ); $environment->fix_in_wpadmin( $config, true ); } catch ( Util_Environment_Exceptions $e ) { - \WP_CLI::error( __( 'Environment adjustment failed with error', 'w3-total-cache' ), - $e->getCombinedMessage() ); + \WP_CLI::error( __( 'Environment adjustment failed with error:' . $e->getCombinedMessage(), 'w3-total-cache' ) ); } \WP_CLI::success( __( 'Environment adjusted.', 'w3-total-cache' ) ); @@ -217,7 +216,6 @@ function option( $args = array(), $vars = array() ) { if ( empty( $name ) ) { \WP_CLI::error( __( ' parameter is not specified', 'w3-total-cache' ) ); - return; } if ( strpos( $name, '::' ) !== FALSE ) { $name = explode('::', $name); @@ -249,7 +247,6 @@ function option( $args = array(), $vars = array() ) { $v = json_encode( $c->get_array( $name ), JSON_PRETTY_PRINT ); else { \WP_CLI::error( __( 'Unknown type ' . $type, 'w3-total-cache' ) ); - return; } echo $v . "\n"; @@ -258,7 +255,6 @@ function option( $args = array(), $vars = array() ) { if ( count( $args ) <= 0 ) { \WP_CLI::error( __( ' parameter is not specified', 'w3-total-cache' ) ); - return; } $value = array_shift( $args ); @@ -269,7 +265,6 @@ function option( $args = array(), $vars = array() ) { $v = false; else { \WP_CLI::error( __( ' parameter ' . $value . ' is not boolean', 'w3-total-cache' ) ); - return; } } elseif ( $type == 'integer' ) $v = (integer)$value; @@ -280,7 +275,6 @@ function option( $args = array(), $vars = array() ) { $v = explode($delimiter, $value ); } else { \WP_CLI::error( __( 'Unknown type ' . $type, 'w3-total-cache' ) ); - return; } try { @@ -305,9 +299,7 @@ function querystring() { $w3_querystring->browsercache_flush(); } catch ( \Exception $e ) { - \WP_CLI::error( sprintf( - __( 'updating the query string failed. with error %s', 'w3-total-cache' ), - $e ) ); + \WP_CLI::error( __( 'updating the query string failed. with error: ' . $e->getMessage(), 'w3-total-cache' ) ); } \WP_CLI::success( __( 'The query string was updated successfully.', 'w3-total-cache' ) ); @@ -331,7 +323,7 @@ function cdn_purge( $args = array() ) { $w3_cdn_purge->cdn_purge_files( $purgeitems ); } catch ( \Exception $e ) { - \WP_CLI::error( __( 'Files did not successfully purge with error %s', 'w3-total-cache' ), $e ); + \WP_CLI::error( __( 'Files did not successfully purge with error: ' . $e->getMessage(), 'w3-total-cache' ) ); } \WP_CLI::success( __( 'Files purged successfully.', 'w3-total-cache' ) ); @@ -367,14 +359,14 @@ function opcache_flush_file( $args = array() ) { ); $result = wp_remote_post( $url, $post ); if ( is_wp_error( $result ) ) { - \WP_CLI::error( __( 'Files did not successfully reload with error %s', 'w3-total-cache' ), $result ); + \WP_CLI::error( __( 'Files did not successfully reload with error: ' . $result, 'w3-total-cache' ) ); } elseif ( $result['response']['code'] != '200' ) { \WP_CLI::error( __( 'Files did not successfully reload with message: ', 'w3-total-cache' ) . $result['body'] ); } } } catch ( \Exception $e ) { - \WP_CLI::error( __( 'Files did not successfully reload with error %s', 'w3-total-cache' ), $e ); + \WP_CLI::error( __( 'Files did not successfully reload with error: ' . $e->getMessage(), 'w3-total-cache' ) ); } \WP_CLI::success( __( 'Files reloaded successfully.', 'w3-total-cache' ) ); @@ -410,14 +402,14 @@ function opcache_flush( $args = array() ) { ); $result = wp_remote_post( $url, $post ); if ( is_wp_error( $result ) ) { - \WP_CLI::error( __( 'Files did not successfully delete with error %s', 'w3-total-cache' ), $result ); + \WP_CLI::error( __( 'Files did not successfully delete with error ' . $result, 'w3-total-cache' ) ); } elseif ( $result['response']['code'] != '200' ) { \WP_CLI::error( __( 'Files did not successfully delete with message: ', 'w3-total-cache' ). $result['body'] ); } } } catch ( \Exception $e ) { - \WP_CLI::error( __( 'Files did not successfully delete with error %s', 'w3-total-cache' ), $e ); + \WP_CLI::error( __( 'Files did not successfully delete with error: ' . $e->getMessage(), 'w3-total-cache' ) ); } \WP_CLI::success( __( 'Files deleted successfully.', 'w3-total-cache' ) ); @@ -431,16 +423,104 @@ function pgcache_cleanup() { $pgcache_cleanup = Dispatcher::component( 'PgCache_Plugin_Admin' ); $pgcache_cleanup->cleanup(); } catch ( \Exception $e ) { - \WP_CLI::error( __( 'PageCache Garbage cleanup did not start with error %s', - 'w3-total-cache' ), $e ); + \WP_CLI::error( __( 'PageCache Garbage cleanup did not start with error: ' . $e->getMessage(), 'w3-total-cache' ) ); } - \WP_CLI::success( __( 'PageCache Garbage cleanup triggered successfully.', - 'w3-total-cache' ) ); + \WP_CLI::success( __( 'PageCache Garbage cleanup triggered successfully.', 'w3-total-cache' ) ); } -} - + /** + * Prime the page cache (cache preloader) + * + * ## OPTIONS + * + * [] + * : Stop the active page cache prime session. + * + * [--batch=] + * : Max number of pages to create per batch. If not set, the value given in + * W3TC's Page Cache > Pages per Interval field is used. If size is 0 then + * all pages within the sitemap will be created/cached without the use of a + * batch and without waiting. + * + * [--interval=] + * : Number of seconds to wait before creating another batch. If not set, + * the value given in W3TC's Page Cache > Update Interval field is used. + * + * [--sitemap=] + * : The sitemap url specifying the pages to prime cache. If not set, the + * value given in W3TC's Page Cache > Sitemap URL field is used. + * + * ## EXAMPLES + * + * # Prime the page cache using settings held within the W3TC config. + * $ wp w3-total-cache prime + * + * # Stop the currently active prime process. + * $ wp w3-total-cache prime stop + * + * # Prime the page cache (2 pages every 30 seconds). + * $ wp w3-total-cache prime --batch=2 --interval=30 + * + * # Prime the page cache every 30 seconds using the given sitemap. + * $ wp w3-total-cache prime --interval=30 --sitemap=http://site.com/sitemap.xml + */ + function prime( $args = array() , $vars = array() ) { + try { + $action = array_shift( $args ) ; + $w3_prime = Dispatcher::component( 'PgCache_Plugin_Admin' ); + + if ( $action == 'stop' ) { + if ( w3tc_wpcli_stop_prime( $result ) == false ) { + \WP_CLI::warning( __( $result, 'w3-total-cache' ) ); + } else { + \WP_CLI::success( __( 'Page cache priming stopped.', 'w3-total-cache' ) ); + } + } elseif ( strlen( $action ) > 0 ) { + $val = \WP_CLI::colorize( __( "%Y$action%n", 'w3-total-cache' ) ); + \WP_CLI::error( __( "Unrecognized argument - $val.", 'w3-total-cache' ) ); + } else { + $config = Dispatcher::config(); + $user_limit = - 1; + $user_interval = - 1; + $user_sitemap = ""; + + if ( isset( $vars['interval'] ) && is_numeric( $vars['interval'] ) ) { + $user_interval = intval( $vars['interval'] ); + } + + if ( isset( $vars['batch'] ) && is_numeric( $vars['batch'] ) ) { + $user_limit = intval( $vars['batch'] ); + } + + if ( isset( $vars['sitemap'] ) && !empty( $vars['sitemap'] ) ) { + $user_sitemap = trim( $vars['sitemap'] ); + } + + $limit = $user_limit == - 1 ? $config->get_integer( 'pgcache.prime.limit' ) : $user_limit; + $interval = $user_interval == - 1 ? $config->get_integer( 'pgcache.prime.interval' ) : $user_interval; + $sitemap = empty( $user_sitemap ) ? $config->get_string( 'pgcache.prime.sitemap' ) : $user_sitemap; + + if ( empty( $sitemap ) ) { + \WP_CLI::error( __( "Prime page cache halted - Unable to load sitemap. A sitemap is needed to prime the page cache.", 'w3-total-cache' ) ); + } elseif ( ( $res = $w3_prime->prime_cli( $limit, $interval, $sitemap, 0, true ) ) === false ) { + \WP_CLI::warning( __( 'Page cache priming is already active.', 'w3-total-cache' ) ); + } else { + /** + * Use inter-process messaging, if available, to help manage the prime + */ + if ( extension_loaded( 'sysvmsg' ) ) { + msg_send( msg_get_queue( 99909 ) , 99, "prime_started" ); + } + + \WP_CLI::success( __( "Page cache priming started $res.", 'w3-total-cache' ) ); + } + } + } catch( \Exception $e ) { + \WP_CLI::error( __( 'Error: ' . $e->getMessage(), 'w3-total-cache' ) ); + } + } +} if ( method_exists( '\WP_CLI', 'add_command' ) ) { \WP_CLI::add_command( 'w3-total-cache', '\W3TC\W3TotalCache_Command' ); diff --git a/PgCache_Plugin.php b/PgCache_Plugin.php index 4ce9c21..f460f42 100644 --- a/PgCache_Plugin.php +++ b/PgCache_Plugin.php @@ -58,6 +58,8 @@ function run() { } add_action( 'w3_pgcache_prime', array( $this, 'prime' ) ); + + add_action( 'w3_pgcache_prime_cli', array( $this, 'prime_cli' ), 10, 4 ); Util_AttachToActions::flush_posts_on_actions(); @@ -115,6 +117,20 @@ function prime( $start = 0 ) { $this->_get_admin()->prime( $start ); } + /** + * Prime cache (WP_CLI) + * + * @param integer $user_limit Pages per batch size + * @param integer $user_interval Number of seconds to wait before creating another batch + * @param string $user_sitemap The sitemap url to use + * @param integer $start Index position within the sitemap to prime cache + * @param boolean $boot Indicates if the prime cache is about to start for the first time + * @return void + */ + function prime_cli( $user_limit, $user_interval, $user_sitemap, $start, $boot = false ) { + $this->_get_admin()->prime_cli( $user_limit, $user_interval, $user_sitemap, $start, $boot ); + } + /** * Instantiates worker on demand */ diff --git a/PgCache_Plugin_Admin.php b/PgCache_Plugin_Admin.php index f56b42b..6a616fd 100644 --- a/PgCache_Plugin_Admin.php +++ b/PgCache_Plugin_Admin.php @@ -120,6 +120,15 @@ function prime( $start = 0 ) { } } + /** + * If priming is actively running and the user stops the priming + * via unchecking "Automatically prime the page cache" this will + * forceably stop the priming process in its track. + */ + if ( !$this->_config->get_boolean( 'pgcache.prime.enabled' ) ) { + return; + } + $interval = $this->_config->get_integer( 'pgcache.prime.interval' ); $limit = $this->_config->get_integer( 'pgcache.prime.limit' ); $sitemap = $this->_config->get_string( 'pgcache.prime.sitemap' ); @@ -129,6 +138,14 @@ function prime( $start = 0 ) { */ $urls = $this->parse_sitemap( $sitemap ); + /** + * The user can set the "Pages per interval" value to 0 which + * indicates there is no batch size limit. + */ + if ( $limit <= 0 ) { + $limit = count( $urls ); + } + /** * Queue URLs */ @@ -152,6 +169,281 @@ function prime( $start = 0 ) { Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) ); } + /** + * Prime cache (WP-CLI) + * + * Since we are dealing with CLI and the priming could take a long time, an + * asynchronous approach is used so no shell blocking occurs while the priming + * process is done in the background. Upon starting a new prime task it generates + * a bootstrap scheduled event to start the async priming process -- unblocking the CLI. + * + * If you'd like more info on how this all works -- happy to help: core905atGmail + * + * @param integer $limit Pages per batch size + * @param integer $interval Number of seconds to wait before creating another batch + * @param string $sitemap The sitemap url to use + * @param integer $start Index position within the sitemap to prime cache + * @param boolean $boot Indicates if the prime cache is about to start for the first time + * @return boolean + */ + function prime_cli( $limit = 0, $interval = 0, $sitemap = "", $start, $boot = false ) { + if ( $boot ) { + /** + * Don't start cache prime if queues are still scheduled + */ + if ( extension_loaded( 'sysvmsg' ) ) { + $que = msg_stat_queue( msg_get_queue( 99909 ) ); + if ( $que['msg_qnum'] > 0 ) { + return false; + } + } + + if ( $this->get_cli_pids() !== false ) { + return false; + } + + $crons = _get_cron_array(); + + foreach ( $crons as $timestamp => $hooks ) { + foreach ( $hooks as $hook => $keys ) { + foreach ( $keys as $key => $data ) { + if ( $hook == 'w3_pgcache_prime_cli' && count( $data['args'] ) ) { + return false; + } + } + } + } + + /** + * Bootstrap the page cache prime process by scheduling it as an event. + * This is needed to make this CLI action asychronous + */ + $this->delete_cli_urls(); + + if ( $limit < 0 ) { + $limit = 0; + } + + if ( $interval < 0 ) { + $interval = 0; + } + + wp_schedule_single_event( time(), 'w3_pgcache_prime_cli', array( + $limit, + $interval, + $sitemap, + $start + ) ); + + return "(" . ( $limit == 0 ? "" : "batch: $limit pages every $interval secs - " ) . "sitemap: $sitemap)"; + } else { + /** + * Get and parse the XML sitemap + */ + $write = true; + + if ( ( $urls = $this->get_cli_urls() ) === false ) { + $urls = $this->parse_sitemap( $sitemap ); + } else { + $write = false; + } + + if ( $limit == 0 ) { + $limit = count( $urls ); + } + + if ( count( $urls ) == 0 ) { + error_log( 'WP-CLI: Prime page cache halted - Unable to load sitemap. A sitemap is needed to prime the page cache.' ); + return; + } elseif ( $write && ( $start + $limit ) < count( $urls ) ) { + $this->set_cli_urls( $urls ); + } + + /** + * Extract a slice of URLs for priming + */ + $queue = array_slice( $urls, $start, $limit ); + + if ( count( $queue ) > 0 ) { + $usefile=true; + $msgidmain = null; + $msgidproc = null; + + if ( extension_loaded( 'sysvmsg' ) ) { + $usefile = false; + $msgidmain = msg_get_queue( 99909 ); + $msgidproc = msg_get_queue( 99910 ); + + msg_send( $msgidproc,99,"prime_proc" ); + } + + /** + * Get and store this process id in case the user decides to stop the prime process + */ + if ( $usefile ) { + $pid = getmypid(); + + if ( ( $pids = $this->get_cli_pids() ) === false ) { + $pids = array(); + } + + $pids[] = $pid; + $this->set_cli_pids( $pids ); + } + + /** + * Schedule the next batch of URLs to be primed + */ + if ( count( $urls ) > ( $start + $limit ) ) { + wp_schedule_single_event( time() + $interval, 'w3_pgcache_prime_cli', array( + $limit, + $interval, + $sitemap, + $start + $limit + ) ); + } + else { + $done = true; + } + + /** + * Make HTTP requests -- prime cache + */ + foreach ( $queue as $url ) { + Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) ); + if ( $msgidmain != null ) { + $que = msg_stat_queue( $msgidmain ); + if ( $que['msg_qnum'] == 0 ) { + break; + } + } + } + + /** + * This process slice has completed its portion to prime URLs. + * Let's do some clean up + */ + if ( $usefile ) { + if ( ( $pids = $this->get_cli_pids() ) !== false ) { + unset( $pids[array_search( $pid, $pids )] ); + $this->set_cli_pids( $pids ); + } + + if ( isset( $done ) && ( $pids === false || count( $pids ) == 0) ) { + $this->delete_cli_pids(); + $this->delete_cli_urls(); + + exit( "Page cache priming via WP-CLI has successfully completed.\n" ); + } + } + else { + msg_receive( $msgidproc, 99, $t, 1024, $data, true, MSG_IPC_NOWAIT ); + $que = msg_stat_queue( $msgidproc ); + + if ( $que['msg_qnum'] == 0 ) { + msg_remove_queue( $msgidproc ); + $que = msg_stat_queue( $msgidmain ); + + if ( $que['msg_qnum'] == 0 ) { + msg_remove_queue( $msgidmain ); + + if ( isset( $done ) ) { + $this->delete_cli_urls(); + } + } + } + } + } + } + } + + /** + * Gets all the active process ids handling the WP-CLI prime caching + * + * @return array + */ + function get_cli_pids() + { + return w3tc_lock_read( $this->generate_filename( W3TC_CLI_PIDS ) ); + } + + /** + * Store the list of process ids that are handling the WP-CLI prime caching + * + * @param array $data A collecton of process ids + * @return void + */ + function set_cli_pids( $data ) + { + w3tc_lock_write( $this->generate_filename( W3TC_CLI_PIDS ), $data ); + } + + /** + * Deletes the WP-CLI prime caching support file + * + * @return void + */ + function delete_cli_pids() + { + @unlink( $this->generate_filename( W3TC_CLI_PIDS ) ); + } + + /** + * This helper function reduces the load of needing to parse the sitemap + * repeatedly during the prime cache process. It returns the list of urls + * needed to be primed. + * + * @return array + */ + function get_cli_urls() + { + return w3tc_lock_read( $this->generate_filename( W3TC_CLI_URLS ) ); + } + + /** + * Stores the list of urls to be used for prime caching. This helper + * function reduces the load of needing to parse the sitemap repeatedly. + * + * @param array $data A collection of urls to store + * @return void + */ + function set_cli_urls( $data ) + { + w3tc_lock_write( $this->generate_filename( W3TC_CLI_URLS ), $data ); + } + + /** + * Deletes the WP-CLI prime caching support file + * + * @return void + */ + function delete_cli_urls() + { + @unlink( $this->generate_filename( W3TC_CLI_URLS ) ); + } + + /** + * Constructs a writable temporary CLI file path to use for holding pids or urls + * + * @param string $file Filename to use + * @param string $dir Optional directory location + * @return string + */ + function generate_filename( $file, $dir = W3TC_CACHE_TMP_DIR ) + { + if ( !is_dir( $dir ) || !is_writable( $dir ) ) { + Util_File::mkdir_from( $dir, W3TC_CACHE_DIR ); + + if ( !is_dir( $dir ) || !is_writable( $dir ) ) { + $dir=""; + } + + $dir = rtrim( $dir, "/" ); + } + + return $dir . ( empty( $dir ) ? "" : "/" ) . $file; + } + /** * Parses sitemap * diff --git a/Root_Loader.php b/Root_Loader.php index b4f4242..35cd216 100644 --- a/Root_Loader.php +++ b/Root_Loader.php @@ -115,6 +115,7 @@ public function activate( $network_wide ) { * Deactivation action hook */ public function deactivate() { + w3tc_wpcli_stop_prime(); // Stop the WP-CLI page cache prime if it's still running Root_AdminActivation::deactivate(); } diff --git a/inc/options/pgcache.php b/inc/options/pgcache.php index 5001d74..53e6918 100644 --- a/inc/options/pgcache.php +++ b/inc/options/pgcache.php @@ -142,7 +142,7 @@ value="_config->get_integer( 'pgcache.prime.limit' ) ); ?>" size="8" />
- + diff --git a/w3-total-cache-api.php b/w3-total-cache-api.php index aa2f4d8..82316dc 100644 --- a/w3-total-cache-api.php +++ b/w3-total-cache-api.php @@ -23,6 +23,8 @@ define( 'W3TC_SUPPORT_SERVICES_URL', 'https://www.w3-edge.com/w3tc/premium-widget.json' ); define( 'W3TC_TRACK_URL', 'https://www.w3-edge.com/w3tc/track/' ); define( 'W3TC_MAILLINGLIST_SIGNUP_URL', 'https://www.w3-edge.com/w3tc/emailsignup/' ); +define( 'W3TC_CLI_PIDS', '.w3tc_cli_pids'); +define( 'W3TC_CLI_URLS', '.w3tc_cli_urls'); define( 'NEWRELIC_SIGNUP_URL', 'http://bit.ly/w3tc-partner-newrelic-signup' ); define( 'MAXCDN_SIGNUP_URL', 'http://bit.ly/w3tc-cdn-maxcdn-create-account' ); define( 'MAXCDN_AUTHORIZE_URL', 'http://bit.ly/w3tc-cdn-maxcdn-authorize' ); @@ -238,7 +240,174 @@ function w3tc_flush_url( $url ) { $o->flush_url( $url ); } +/** + * Shared read-locking access to retrieve contents + * of an existing file. Although available for use by all, + * this was made to assist WP-CLI prime caching. + * + * @param string $file File path to read + * @param boolean $serialized Is the file serialized (to unserialize it when returning) + * @return string + */ +function w3tc_lock_read( $file, $serialized = true ) { + $res = false; + $h = @fopen( $file, 'r' ); + + if ( $h !== false ) + { + flock( $h, LOCK_SH ); + + clearstatcache( true, $file ); + $sz = filesize( $file ); + + if ( $sz > 0 ) + $res = fread( $h, $sz ); + else + $res = ""; + + flock( $h, LOCK_UN ); + fclose( $h ); + + if ( $serialized ) { + $res = unserialize( $res ); + } + } + + return $res; +} + +/** + * Exclusive lock access to write contents to a file. + * Although available for use by all, this was made to + * assist WP-CLI prime caching. + * + * @param string $file File path to write to + * @param string $data The data to write + * @param boolean $serialized Should the data be serialized + * @return string + */ +function w3tc_lock_write( $file, $data, $serialized = true ) { + $res = false; + $h = @fopen( $file, 'c' ); + + if ( $h !== false ) + { + flock( $h, LOCK_EX ); + + ftruncate( $h, 0 ); + + if ( $serialized ) { + $data = serialize( $data ); + } + + $res = fwrite( $h, $data ); + fflush( $h ); + flock( $h, LOCK_UN ); + fclose( $h ); + } + + return $res; +} + +/** + * Unschedule an event by using a given hook name + * + * @param string $hook The action hook name to unschedule + * @return boolean + */ +function w3tc_clear_hook_crons( $hook ) { + $res = false; + $crons = _get_cron_array(); + if ( empty( $crons ) ) { + return false; + } + foreach( $crons as $timestamp => $cron ) { + if ( ! empty( $cron[$hook] ) ) { + unset( $crons[$timestamp][$hook] ); + $res = true; + } + + if ( empty( $crons[$timestamp] ) ) { + unset( $crons[$timestamp] ); + } + } + _set_cron_array( $crons ); + return $res; +} +/** + * Stops an actively running WP-CLI page cache prime session. + * + * NOTE: + * ==== + * + * Because not every PHP environment is the same, if the user requests to stop + * an actively running WP-CLI prime session this checks for and uses either the + * sysvmsg or posix extension, if available, or the exec() function as a last + * resort. It does this because the cli priming is carefully managed across + * separate scheduled event processes and so we keep track of who those + * active processes are and end them individually when requested to stop. + * + * @param string &$result A text message result sent back to the caller + * @return boolean + */ +function w3tc_wpcli_stop_prime( &$result = "" ) { + $w3_prime = \W3TC\Dispatcher::component( 'PgCache_Plugin_Admin' ); + + if ( extension_loaded( 'sysvmsg' ) ) { + /** + * Inter-process messaging is available and was used to manage pids + */ + $pids = true; + $que = msg_stat_queue( msg_get_queue( 99909 ) ); + + if ( $que['msg_qnum'] > 0 ) { + msg_remove_queue( msg_get_queue( 99909 ) ); + } else { + $pids = false; + } + } elseif (false !== ( $pids = $w3_prime->get_cli_pids() ) ) { + foreach( $pids as $pid ) { + if ( extension_loaded( 'posix' ) && w3tc_cmd_enabled( "posix_kill" ) ) { + /** + * The posix extension is available - managed wp-cli pids will be stopped this way + */ + @posix_kill( $pid, SIGTERM ); + } elseif ( w3tc_cmd_enabled( "exec" ) ) { + /** + * This is the fallback option since the other two aren't available. + * We use the exec to stop our managed wp-cli pids. + */ + @exec( "kill -9 $pid >/dev/null 2>&1" ); + } else { + $result = "Can't issue the command to stop running process(es). Need either: exec, posix, or sysvmsg."; + return false; + } + } + + $w3_prime->delete_cli_pids(); + } + + $w3_prime->delete_cli_urls(); + + if ( w3tc_clear_hook_crons( 'w3_pgcache_prime_cli' ) === false && $pids === false ) { + $result = "No page cache priming to stop. Either the priming has completed or was already stopped."; + return false; + } + + return true; +} + +/** + * Check if PHP function is available to use + * + * @param string $cmd The PHP function name to check + * @return boolean + */ +function w3tc_cmd_enabled( $cmd ) { + $disabled = explode( ',', @ini_get( 'disable_functions' ) ); + return !in_array( $cmd, $disabled ); +} /** * deprecated @@ -329,7 +498,7 @@ function w3tc_cdn_purge_files( $files ) { * Prints script tag for scripts group * * @param string $location - * @retun void + * @return void */ function w3tc_minify_script_group( $location ) { $o = \W3TC\Dispatcher::component( 'Minify_Plugin' ); @@ -344,7 +513,7 @@ function w3tc_minify_script_group( $location ) { * Prints style tag for styles group * * @param string $location - * @retun void + * @return void */ function w3tc_minify_style_group( $location ) { $o = \W3TC\Dispatcher::component( 'Minify_Plugin' ); @@ -559,7 +728,7 @@ public function __construct( $master = false, $blog_id = null ) { if ( $master ) $blog_id = 0; - return parent::__construct($blog_id); + return parent::__construct( $blog_id ); } } }