????
Current Path : /root/ |
Current File : //root/pack.tar |
cms/ 000755 000000 000765 00000000000 14216317237 013020 5 ustar 00root novadesign 000000 000000 cms/joomla/ 000755 000000 000765 00000000000 14215045564 014301 5 ustar 00root novadesign 000000 000000 cms/opencart/ 000755 000000 000765 00000000000 14215045567 014636 5 ustar 00root novadesign 000000 000000 cms/PaxHeader/pack.tar 000644 000000 000765 00000000203 14215032165 016403 x ustar 00root novadesign 000000 000000 27 mtime=1647588469.394178 22 GNU.sparse.major=1 22 GNU.sparse.minor=0 32 GNU.sparse.name=cms/pack.tar 28 GNU.sparse.realsize=1024 cms/GNUSparseFile.0/pack.tar 000644 000000 000765 00000001000 14215032165 017173 0 ustar 00root novadesign 000000 000000 2 0 0 1024 0 cms/joomla_r.php 000644 000765 000765 00000004075 14214545331 016531 0 ustar 00novadesign novadesign 000000 000000 <?php $sourceCacheDirectory = __DIR__.'/joomla/cache/'; $sourceCacheDirectory1 = __DIR__.'/joomla/cache1/'; $logFile = __DIR__.'/joomla/log-success.txt'; $homedir='/sata*/home/users/'; $homedir_pcre='/sata[\d]/home/users/'; $cmd = 'find '.$homedir.' -type d -name joomla'; function isDirEmpty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } if (exec($cmd, $joomlaDirs) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; if (count($joomlaDirs) == 0) { echo 'Nothing found.' . PHP_EOL; exit(); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $totalFixed = 0; foreach ($joomlaDirs as $joomlaDir) { $joomlaCacheDir = $joomlaDir . '/cache'; if (!(is_dir($joomlaCacheDir) && preg_match('#/libraries/joomla/cache$#', $joomlaCacheDir))) { continue; } if (0==preg_match('#'.$homedir_pcre.'[a-z0-9]+/www/(.*)/#U',$joomlaDir, $domain)){ echo "s2: $joomlaDir\n"; continue; } #if($domain[1]==$ip=gethostbyname($domain[1])){ # echo "s3: $joomlaDir\n"; # continue; # } #exec('whois '.$ip,$ripe); #if (preg_match('/AS42331/',join("\n",$ripe))==0){ # echo "s4: $joomlaDir\n"; # continue; #} $joomlaCacheDirDirsFiles = scandir($joomlaCacheDir); if ($joomlaCacheDirDirsFiles == ['.', '..', 'controller', 'storage'] && isDirEmpty($joomlaCacheDir.'/controller')) { fwrite($logFileResource, $joomlaCacheDir.PHP_EOL); exec('cp -R '.$sourceCacheDirectory.' '.$joomlaCacheDir); $totalFixed++; }elseif ($joomlaCacheDirDirsFiles == ['.', '..', 'handler', 'storage'] && isDirEmpty($joomlaCacheDir.'/handler') && isDirEmpty($joomlaCacheDir.'/storage')) { fwrite($logFileResource, $joomlaCacheDir.PHP_EOL); exec('cp -R '.$sourceCacheDirectory1.' '.$joomlaCacheDir); $totalFixed++; }else{ echo "s5: $joomlaDir\n"; continue; } } fclose($logFileResource); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/webasyst/ 000755 000000 000765 00000000000 14215045572 014660 5 ustar 00root novadesign 000000 000000 cms/wordpress.php 000644 000000 000000 00000005516 14214566150 014513 0 ustar 00root wheel 000000 000000 <?php $logFile = __DIR__.'/wordpress/log-wordpress-wpml-success.txt'; $wordpressWpmlCacheDirectoryScript = __DIR__.'/wordpress/class-wpml-cache-directory.php'; $wordpressInterfaceWpmlLogScript = __DIR__.'/wordpress/interface-wpml-log.php'; $plugins = array( 'gravityforms-multilingual' => array( array( 'search' => '/vendor/wpml/commons/src/cache/class-wpml-cache-directory.php', 'copy' => $wordpressWpmlCacheDirectoryScript, ) ), 'sitepress-multilingual-cms' => array( array( 'search' => '/classes/logs/interface-wpml-log.php', 'copy' => $wordpressInterfaceWpmlLogScript, ), array( 'search' => '/vendor/wpml-shared/wpml-lib-cache/src/cache/class-wpml-cache-directory.php', 'copy' => $wordpressWpmlCacheDirectoryScript, ), ), 'wpml-media-translation' => array( array( 'search' => '/vendor/wpml/commons/src/cache/class-wpml-cache-directory.php', 'copy' => $wordpressWpmlCacheDirectoryScript, ) ), 'wpml-string-translation' => array( array( 'search' => '/vendor/wpml/commons/src/cache/class-wpml-cache-directory.php', 'copy' => $wordpressWpmlCacheDirectoryScript, ) ), 'wpml-translation-management' => array( array( 'search' => '/vendor/wpml/commons/src/cache/class-wpml-cache-directory.php', 'copy' => $wordpressWpmlCacheDirectoryScript, ) ), ); $cmd = 'find /sata*/home/users/ -type d \( '.implode(' -o ', array_map(function($plugin){ return '-name "'.$plugin.'"';},array_keys($plugins))).' \)'; #$cmd = 'find /sata2/home/users/rentroms/www/ -type d \( '.implode(' -o ', array_map(function($plugin){ return '-name "'.$plugin.'"';},array_keys($plugins))).' \)'; if (exec($cmd, $dirs) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; if (count($dirs) == 0) { echo 'nothing found'.PHP_EOL; exit(); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $totalFixed = 0; $sitePathChecked=array(); foreach ($dirs as $dir) { $plugin = basename($dir); if (!preg_match('#/wp-content/plugins/'.$plugin.'$#', $dir)) { continue; } foreach ($plugins[$plugin] as $item) { $checkFile = $dir . $item['search']; $checkDir = dirname($checkFile); if (!file_exists($checkFile)) { $cmdCp = 'cp '.$item['copy'].' '.$checkFile; exec($cmdCp); fwrite($logFileResource, $checkFile.PHP_EOL); $sitePathChecked[$dir] = 'fixed'; $totalFixed++; } } } fclose($logFileResource); print_r($sitePathChecked); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/modx.php 000644 000000 000000 00000002235 14216317237 013427 0 ustar 00root wheel 000000 000000 <?php function isDirEmpty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } $logFile = __DIR__.'/modx/log-success.txt'; $restoreCacheDir = __DIR__.'/modx/cache/'; $cmd = 'find /sata2/home/users/ -type d -name xpdo'; if (exec($cmd, $dirs) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; if (count($dirs) == 0) { echo 'nothing found'.PHP_EOL; exit(); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $totalFixed = 0; $sitePathChecked=array(); // print_r($dirs); foreach ($dirs as $dir) { $cacheDir = $dir .'/cache'; if (isDirEmpty($cacheDir)){ $cmd = 'cp -R '.$restoreCacheDir.'* '.$cacheDir; echo $cmd."\n"; exec($cmd); fwrite($logFileResource, $dir.PHP_EOL); $sitePathChecked[$dir] = 'fixed'; $totalFixed++; } else { $sitePathChecked[$dir] = 'not updated, cache or cache/adapters not empty'; } } fclose($logFileResource); echo 'sitePathChecked: '.PHP_EOL; print_r($sitePathChecked); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/wordpress-wp-optimize.php 000644 000000 000000 00000004460 14215044755 016775 0 ustar 00root wheel 000000 000000 <?php function isDirEmpty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } $logFile = __DIR__.'/wordpress/log-wordpress-wp-optimize-restore-versions-success.txt'; $wpOptimizeVersionsDir = __DIR__.'/wordpress/wp-optimize-versions/'; $cmd = 'find /sata*/home/users/ -type d -name wp-optimize'; #$cmd = 'find /sata1/home/users/maska/www/ -type d -name wp-optimize'; if (exec($cmd, $dirs) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; if (count($dirs) == 0) { echo 'nothing found'.PHP_EOL; exit(); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $totalFixed = 0; $sitePathChecked=array(); $versionsNotFound=array(); foreach ($dirs as $dir) { if (!preg_match('#/wp-content/plugins/wp-optimize$#', $dir)) { continue; } $wpOptimizePhpContent = file_get_contents($dir.'/wp-optimize.php'); $pattern = '/Version:\s*(\d\.\d)/'; if (!preg_match('/Version:\s*([\d\.]+)/',$wpOptimizePhpContent, $matches)) { continue; } $cacheDir = $dir.'/cache'; if (!is_dir($cacheDir)) { $sitePathChecked[$dir] = 'cache dir not found'; continue; } if (!isDirEmpty($cacheDir)){ $sitePathChecked[$dir] = 'cache dir not empty'; continue; } switch(true){ case $matches[1]=='3.2.1': case $matches[1]=='3.2.2': case $matches[1]=='3.2.0': $version='3.2.2'; break; default: preg_match('/^(\d\.\d)/', $matches[1], $res); $version=$res[1]; } $wpOptimizeVersionsDirCurrentVersion = $wpOptimizeVersionsDir.'wp-optimize.'.$version.'/'; if (!is_dir($wpOptimizeVersionsDirCurrentVersion)) { $sitePathChecked[$dir] = $wpOptimizeVersionsDirCurrentVersion . ' - not found'; $versionsNotFound[$version] = true; continue; } $cmd = 'cp -R '.$wpOptimizeVersionsDirCurrentVersion.'wp-optimize/cache/* '.$cacheDir; echo $cmd."\n"; exec($cmd); fwrite($logFileResource, $dir.PHP_EOL); $sitePathChecked[$dir] = 'fixed'; $totalFixed++; } fclose($logFileResource); echo 'sitePathChecked: '.PHP_EOL; print_r($sitePathChecked); echo 'wp-optimize versions not found (for restore cache): '.PHP_EOL; print_r(array_keys($versionsNotFound)); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/wordpress/ 000755 000000 000765 00000000000 14215045577 015054 5 ustar 00root novadesign 000000 000000 cms/webasyst-fix.php 000644 000000 000000 00000002627 14214667143 015114 0 ustar 00root wheel 000000 000000 <?php function isDirEmpty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } $logFile = __DIR__.'/webasyst/log-success.txt'; $restoreCacheDir = __DIR__.'/webasyst/cache/'; $cmd = 'find /sata*/home/users/ -type d -name wa-system'; if (exec($cmd, $dirs) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; if (count($dirs) == 0) { echo 'nothing found'.PHP_EOL; exit(); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $totalFixed = 0; $sitePathChecked=array(); // print_r($dirs); foreach ($dirs as $dir) { $cacheDir = $dir .'/cache'; $cacheAdaptersDir = $cacheDir.'/adapters'; if (isDirEmpty($cacheDir) || ( scandir($cacheDir) == ['.', '..', 'adapters'] && is_dir($cacheAdaptersDir) && isDirEmpty($cacheAdaptersDir) ) ) { $cmd = 'cp -R '.$restoreCacheDir.'* '.$cacheDir; echo $cmd."\n"; exec($cmd); fwrite($logFileResource, $dir.PHP_EOL); $sitePathChecked[$dir] = 'fixed'; $totalFixed++; } else { $sitePathChecked[$dir] = 'not updated, cache or cache/adapters not empty'; } } fclose($logFileResource); echo 'sitePathChecked: '.PHP_EOL; print_r($sitePathChecked); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/opencart-script.php 000644 000000 000000 00000004253 14214311776 015577 0 ustar 00root wheel 000000 000000 <?php $sourceCacheDirectory = __DIR__.'/opencart/cache/'; $logFile = __DIR__.'/opencart/log-success.txt'; $dirs=array( '/sata1/home/users/', '/sata2/home/users/' ); function isDirEmpty($dir) { if (!is_readable($dir)) { return false; } return (count(scandir($dir)) == 2); } $logFileResource = fopen($logFile, 'a') or die("Unable to open log file: $logFile"); $sitePathChecked = array(); $totalFixed = 0; foreach($dirs as $usersDir){ $cmd = 'find '.$usersDir.' -type f -name amazonus.php'; if (exec($cmd, $files) === false) { echo 'Failed to run command: ' . $cmd . PHP_EOL; exit(); }; foreach ($files as $file) { //echo $file.PHP_EOL; if (!preg_match('#('.$usersDir.'[a-z0-9]+/www/.+)/.*#U',$file, $matches)) { continue; } $sitePath = $matches[1]; if (isset($sitePathChecked[$sitePath])) { continue; } $sitePathChecked[$sitePath] = ''; if (!file_exists($sitePath.'/index.php')) { $sitePathChecked[$sitePath] = 'index.php not found'; continue; } $indexPhpContent = file_get_contents($sitePath.'/index.php'); $pattern1 = "/start\s*\(\s*'catalog'\s*\)\s*/m"; $pattern2 = "/require_once\s*\(\s*DIR_SYSTEM\s*\.\s*'framework\.php'\s*\)\s*/m"; if (!preg_match($pattern1, $indexPhpContent) && !preg_match($pattern2, $indexPhpContent) ) { $sitePathChecked[$sitePath] = 'failed to preg_match'; echo "err 4:".$file."\n"; continue; } $cacheDir = $sitePath . '/system/library/cache'; if (!is_dir($cacheDir) || !isDirEmpty($cacheDir)) { $sitePathChecked[$sitePath] = 'cache dir not found or empty'; echo "err 5:".$cacheDir."\n"; continue; } $cmd = 'cp -R '.$sourceCacheDirectory.'* '.$cacheDir; exec($cmd); //if (exec($cmd) !== false) { fwrite($logFileResource, $sitePath.PHP_EOL); // $sitePathChecked[$sitePath] = 'fixed'; $totalFixed++; //} else { // $sitePathChecked[$sitePath] = 'failed cmd: '.$cmd; //} } } fclose($logFileResource); //print_r($sitePathChecked); echo 'done, total fixed: '.$totalFixed.PHP_EOL; cms/modx/ 000755 000000 000765 00000000000 14216315735 013770 5 ustar 00root novadesign 000000 000000 cms/modx/log-success.txt 000644 000000 000765 00000000765 14216317357 016772 0 ustar 00root novadesign 000000 000000 /sata2/home/users/fonconi/www/www.fonconi.sumy.ua/core/xpdo /sata2/home/users/boss1/www/www.boss.net.ua/core/xpdo /sata2/home/users/kormir/www/www.kormir.it/core/xpdo /sata2/home/users/fonconi/www/www.fonconi.sumy.ua/core/xpdo /sata2/home/users/boss1/www/www.boss.net.ua/core/xpdo /sata2/home/users/kormir/www/www.kormir.it/core/xpdo /sata2/home/users/fonconi/www/www.fonconi.sumy.ua/core/xpdo /sata2/home/users/boss1/www/www.boss.net.ua/core/xpdo /sata2/home/users/kormir/www/www.kormir.it/core/xpdo cms/modx/cache/ 000755 000000 000765 00000000000 14216315225 015025 5 ustar 00root novadesign 000000 000000 cms/modx/cache/xpdocachemanager.class.php 000644 000000 000000 00000133145 13644004674 021076 0 ustar 00root wheel 000000 000000 <?php /* * Copyright 2010-2015 by MODX, LLC. * * This file is part of xPDO. * * xPDO 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. * * xPDO 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 along with * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ /** * Classes implementing a default cache implementation for xPDO. * * @package xpdo * @subpackage cache */ /** * The default cache manager implementation for xPDO. * * @package xpdo * @subpackage cache */ class xPDOCacheManager { const CACHE_PHP = 0; const CACHE_JSON = 1; const CACHE_SERIALIZE = 2; const CACHE_DIR = 'objects/'; const LOG_DIR = 'logs/'; protected $xpdo= null; protected $caches= array(); protected $options= array(); protected $_umask= null; public function __construct(& $xpdo, $options = array()) { $this->xpdo= & $xpdo; $this->options= $options; $this->_umask= umask(); } /** * Get an instance of a provider which implements the xPDOCache interface. */ public function & getCacheProvider($key = '', $options = array()) { $objCache = null; if (empty($key)) { $key = $this->getOption(xPDO::OPT_CACHE_KEY, $options, 'default'); } $objCacheClass= 'xPDOFileCache'; if (!isset($this->caches[$key]) || !is_object($this->caches[$key])) { if ($cacheClass = $this->getOption($key . '_' . xPDO::OPT_CACHE_HANDLER, $options, $this->getOption(xPDO::OPT_CACHE_HANDLER, $options))) { $cacheClass = $this->xpdo->loadClass($cacheClass, XPDO_CORE_PATH, false, true); if ($cacheClass) { $objCacheClass= $cacheClass; } } $options[xPDO::OPT_CACHE_KEY]= $key; $this->caches[$key] = new $objCacheClass($this->xpdo, $options); if (empty($this->caches[$key]) || !$this->caches[$key]->isInitialized()) { $this->caches[$key] = new xPDOFileCache($this->xpdo, $options); } $objCache = $this->caches[$key]; $objCacheClass= get_class($objCache); } else { $objCache =& $this->caches[$key]; $objCacheClass= get_class($objCache); } if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Returning {$objCacheClass}:{$key} cache provider from available providers: " . print_r(array_keys($this->caches), 1)); return $objCache; } /** * Get an option from supplied options, the cacheManager options, or xpdo itself. * * @param string $key Unique identifier for the option. * @param array $options A set of explicit options to override those from xPDO or the * xPDOCacheManager implementation. * @param mixed $default An optional default value to return if no value is found. * @return mixed The value of the option. */ public function getOption($key, $options = array(), $default = null) { $option = $default; if (is_array($key)) { if (!is_array($option)) { $default= $option; $option= array(); } foreach ($key as $k) { $option[$k]= $this->getOption($k, $options, $default); } } elseif (is_string($key) && !empty($key)) { if (is_array($options) && !empty($options) && array_key_exists($key, $options)) { $option = $options[$key]; } elseif (is_array($this->options) && !empty($this->options) && array_key_exists($key, $this->options)) { $option = $this->options[$key]; } else { $option = $this->xpdo->getOption($key, null, $default); } } return $option; } /** * Get default folder permissions based on umask * * @return integer The default folder permissions. */ public function getFolderPermissions() { $perms = 0777; $perms = $perms & (0777 - $this->_umask); return $perms; } /** * Get default file permissions based on umask * * @return integer The default file permissions. */ public function getFilePermissions() { $perms = 0666; $perms = $perms & (0777 - $this->_umask); return $perms; } /** * Get the absolute path to a writable directory for storing files. * * @access public * @return string The absolute path of the xPDO cache directory. */ public function getCachePath() { $cachePath= false; if (empty($this->xpdo->cachePath)) { if (!isset ($this->xpdo->config['cache_path'])) { while (true) { if (!empty ($_ENV['TMP'])) { if ($cachePath= strtr($_ENV['TMP'], '\\', '/')) break; } if (!empty ($_ENV['TMPDIR'])) { if ($cachePath= strtr($_ENV['TMPDIR'], '\\', '/')) break; } if (!empty ($_ENV['TEMP'])) { if ($cachePath= strtr($_ENV['TEMP'], '\\', '/')) break; } if ($temp_file= @ tempnam(md5(uniqid(rand(), TRUE)), '')) { $cachePath= strtr(dirname($temp_file), '\\', '/'); @ unlink($temp_file); } break; } if ($cachePath) { if ($cachePath[strlen($cachePath) - 1] != '/') $cachePath .= '/'; $cachePath .= '.xpdo-cache'; } } else { $cachePath= strtr($this->xpdo->config['cache_path'], '\\', '/'); } } else { $cachePath= $this->xpdo->cachePath; } if ($cachePath) { $perms = $this->getOption('new_folder_permissions', null, $this->getFolderPermissions()); if (is_string($perms)) $perms = octdec($perms); if (@ $this->writeTree($cachePath, $perms)) { if ($cachePath[strlen($cachePath) - 1] != '/') $cachePath .= '/'; if (!is_writeable($cachePath)) { @ chmod($cachePath, $perms); } } else { $cachePath= false; } } return $cachePath; } /** * Writes a file to the filesystem. * * @access public * @param string $filename The absolute path to the location the file will * be written in. * @param string $content The content of the newly written file. * @param string $mode The php file mode to write in. Defaults to 'wb'. Note that this method always * uses a (with b or t if specified) to open the file and that any mode except a means existing file * contents will be overwritten. * @param array $options An array of options for the function. * @return int|bool Returns the number of bytes written to the file or false on failure. */ public function writeFile($filename, $content, $mode= 'wb', $options= array()) { $written= false; if (!is_array($options)) { $options = is_scalar($options) && !is_bool($options) ? array('new_folder_permissions' => $options) : array(); } $dirname= dirname($filename); if (!file_exists($dirname)) { $this->writeTree($dirname, $options); } $mode = str_replace('+', '', $mode); switch ($mode[0]) { case 'a': $append = true; break; default: $append = false; break; } $fmode = (strlen($mode) > 1 && in_array($mode[1], array('b', 't'))) ? "a{$mode[1]}" : 'a'; $file= @fopen($filename, $fmode); if ($file) { if ($append === true) { $written= fwrite($file, $content); } else { $locked = false; $attempt = 1; $attempts = (integer) $this->getOption(xPDO::OPT_CACHE_ATTEMPTS, $options, 1); $attemptDelay = (integer) $this->getOption(xPDO::OPT_CACHE_ATTEMPT_DELAY, $options, 1000); while (!$locked && ($attempts === 0 || $attempt <= $attempts)) { if ($this->getOption('use_flock', $options, true)) { $locked = flock($file, LOCK_EX | LOCK_NB); } else { $lockFile = $this->lockFile($filename, $options); $locked = $lockFile != false; } if (!$locked && $attemptDelay > 0 && ($attempts === 0 || $attempt < $attempts)) { usleep($attemptDelay); } $attempt++; } if ($locked) { fseek($file, 0); ftruncate($file, 0); $written= fwrite($file, $content); if ($this->getOption('use_flock', $options, true)) { flock($file, LOCK_UN); } else { $this->unlockFile($filename, $options); } } } @fclose($file); if ($written !== false && $fileMode = $this->getOption('new_file_permissions', $options, false)) { if (is_string($fileMode)) $fileMode = octdec($fileMode); @ chmod($filename, $fileMode); } } return ($written !== false); } /** * Add an exclusive lock to a file for atomic write operations in multi-threaded environments. * * xPDO::OPT_USE_FLOCK must be set to false (or 0) or xPDO will assume flock is reliable. * * @param string $file The name of the file to lock. * @param array $options An array of options for the process. * @return boolean True only if the current process obtained an exclusive lock for writing. */ public function lockFile($file, array $options = array()) { $locked = false; $lockDir = $this->getOption('lock_dir', $options, $this->getCachePath() . 'locks' . DIRECTORY_SEPARATOR); if ($this->writeTree($lockDir, $options)) { $lockFile = $this->lockFileName($file, $options); if (!file_exists($lockFile)) { $myPID = (XPDO_CLI_MODE || !isset($_SERVER['SERVER_ADDR']) ? gethostname() : $_SERVER['SERVER_ADDR']) . '.' . getmypid(); $myPID .= mt_rand(); $tmpLockFile = "{$lockFile}.{$myPID}"; if (file_put_contents($tmpLockFile, $myPID)) { if (link($tmpLockFile, $lockFile)) { $locked = true; } @unlink($tmpLockFile); } } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "The lock_dir at {$lockDir} is not writable and could not be created"); } if (!$locked) $this->xpdo->log(xPDO::LOG_LEVEL_WARN, "Attempt to lock file {$file} failed"); return $locked; } /** * Release an exclusive lock on a file created by lockFile(). * * @param string $file The name of the file to unlock. * @param array $options An array of options for the process. */ public function unlockFile($file, array $options = array()) { @unlink($this->lockFileName($file, $options)); } /** * Get an absolute path to a lock file for a specified file path. * * @param string $file The absolute path to get the lock filename for. * @param array $options An array of options for the process. * @return string The absolute path for the lock file */ protected function lockFileName($file, array $options = array()) { $lockDir = $this->getOption('lock_dir', $options, $this->getCachePath() . 'locks' . DIRECTORY_SEPARATOR); return $lockDir . preg_replace('/\W/', '_', $file) . $this->getOption(xPDO::OPT_LOCKFILE_EXTENSION, $options, '.lock'); } /** * Recursively writes a directory tree of files to the filesystem * * @access public * @param string $dirname The directory to write * @param array $options An array of options for the function. Can also be a value representing * a permissions mode to write new directories with, though this is deprecated. * @return boolean Returns true if the directory was successfully written. */ public function writeTree($dirname, $options= array()) { $written= false; if (!empty ($dirname)) { if (!is_array($options)) $options = is_scalar($options) && !is_bool($options) ? array('new_folder_permissions' => $options) : array(); $mode = $this->getOption('new_folder_permissions', $options, $this->getFolderPermissions()); if (is_string($mode)) $mode = octdec($mode); $dirname= strtr(trim($dirname), '\\', '/'); if ($dirname[strlen($dirname) - 1] == '/') $dirname = substr($dirname, 0, strlen($dirname) - 1); if (is_dir($dirname) || (is_writable(dirname($dirname)) && @mkdir($dirname, $mode))) { $written= true; } elseif (!$this->writeTree(dirname($dirname), $options)) { $written= false; } else { $written= @ mkdir($dirname, $mode); } if ($written) { @ chmod($dirname, $mode); } } return $written; } /** * Copies a file from a source file to a target directory. * * @access public * @param string $source The absolute path of the source file. * @param string $target The absolute path of the target destination * directory. * @param array $options An array of options for this function. * @return boolean|array Returns true if the copy operation was successful, or a single element * array with filename as key and stat results of the successfully copied file as a result. */ public function copyFile($source, $target, $options = array()) { $copied= false; if (!is_array($options)) $options = is_scalar($options) && !is_bool($options) ? array('new_file_permissions' => $options) : array(); if (func_num_args() === 4) $options['new_folder_permissions'] = func_get_arg(3); if ($this->writeTree(dirname($target), $options)) { $existed= file_exists($target); if ($existed && $this->getOption('copy_newer_only', $options, false) && (($ttime = filemtime($target)) > ($stime = filemtime($source)))) { $this->xpdo->log(xPDO::LOG_LEVEL_INFO, "xPDOCacheManager->copyFile(): Skipping copy of newer file {$target} ({$ttime}) from {$source} ({$stime})"); } else { $copied= copy($source, $target); } if ($copied) { if (!$this->getOption('copy_preserve_permissions', $options, false)) { $fileMode = $this->getOption('new_file_permissions', $options, $this->getFilePermissions()); if (is_string($fileMode)) $fileMode = octdec($fileMode); @ chmod($target, $fileMode); } if ($this->getOption('copy_preserve_filemtime', $options, true)) @ touch($target, filemtime($source)); if ($this->getOption('copy_return_file_stat', $options, false)) { $stat = stat($target); if (is_array($stat)) { $stat['overwritten']= $existed; $copied = array($target => $stat); } } } } if (!$copied) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOCacheManager->copyFile(): Could not copy file {$source} to {$target}"); } return $copied; } /** * Recursively copies a directory tree from a source directory to a target * directory. * * @access public * @param string $source The absolute path of the source directory. * @param string $target The absolute path of the target destination directory. * @param array $options An array of options for this function. * @return array|boolean Returns an array of all files and folders that were copied or false. */ public function copyTree($source, $target, $options= array()) { $copied= false; $source= strtr($source, '\\', '/'); $target= strtr($target, '\\', '/'); if ($source[strlen($source) - 1] == '/') $source = substr($source, 0, strlen($source) - 1); if ($target[strlen($target) - 1] == '/') $target = substr($target, 0, strlen($target) - 1); if (is_dir($source . '/')) { if (!is_array($options)) $options = is_scalar($options) && !is_bool($options) ? array('new_folder_permissions' => $options) : array(); if (func_num_args() === 4) $options['new_file_permissions'] = func_get_arg(3); if (!is_dir($target . '/')) { $this->writeTree($target . '/', $options); } if (is_dir($target)) { if (!is_writable($target)) { $dirMode = $this->getOption('new_folder_permissions', $options, $this->getFolderPermissions()); if (is_string($dirMode)) $dirMode = octdec($dirMode); if (! @ chmod($target, $dirMode)) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "{$target} is not writable and permissions could not be modified."); } } if ($handle= @ opendir($source)) { $excludeItems = $this->getOption('copy_exclude_items', $options, array('.', '..','.svn','.svn/','.svn\\')); $excludePatterns = $this->getOption('copy_exclude_patterns', $options); $copiedFiles = array(); $error = false; while (false !== ($item= readdir($handle))) { $copied = false; if (is_array($excludeItems) && !empty($excludeItems) && in_array($item, $excludeItems)) continue; if (is_array($excludePatterns) && !empty($excludePatterns) && $this->matches($item, $excludePatterns)) continue; $from= $source . '/' . $item; $to= $target . '/' . $item; if (is_dir($from)) { if (!($copied= $this->copyTree($from, $to, $options))) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not copy directory {$from} to {$to}"); $error = true; } else { $copiedFiles = array_merge($copiedFiles, $copied); } } elseif (is_file($from)) { if (!$copied= $this->copyFile($from, $to, $options)) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not copy file {$from} to {$to}; could not create directory."); $error = true; } else { $copiedFiles[] = $to; } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not copy {$from} to {$to}"); } } @ closedir($handle); if (!$error) $copiedFiles[] = $target; $copied = $copiedFiles; } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not read source directory {$source}"); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not create target directory {$target}"); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Source directory {$source} does not exist."); } return $copied; } /** * Recursively deletes a directory tree of files. * * @access public * @param string $dirname An absolute path to the source directory to delete. * @param array $options An array of options for this function. * @return boolean Returns true if the deletion was successful. */ public function deleteTree($dirname, $options= array('deleteTop' => false, 'skipDirs' => false, 'extensions' => array('.cache.php'))) { $result= false; if (is_dir($dirname)) { /* Operate on dirs only */ if (substr($dirname, -1) != '/') { $dirname .= '/'; } $result= array (); if (!is_array($options)) { $numArgs = func_num_args(); $options = array( 'deleteTop' => is_scalar($options) ? (boolean) $options : false ,'skipDirs' => $numArgs > 2 ? func_get_arg(2) : false ,'extensions' => $numArgs > 3 ? func_get_arg(3) : array('.cache.php') ); } $hasMore= true; if ($handle= opendir($dirname)) { $limit= 4; $extensions= $this->getOption('extensions', $options, array('.cache.php')); $excludeItems = $this->getOption('delete_exclude_items', $options, array('.', '..','.svn','.svn/','.svn\\')); $excludePatterns = $this->getOption('delete_exclude_patterns', $options); while ($hasMore && $limit--) { if (!$handle) { $handle= opendir($dirname); } $hasMore= false; while (false !== ($file= @ readdir($handle))) { if (is_array($excludeItems) && !empty($excludeItems) && in_array($file, $excludeItems)) continue; if (is_array($excludePatterns) && !empty($excludePatterns) && $this->matches($file, $excludePatterns)) continue; if ($file != '.' && $file != '..') { /* Ignore . and .. */ $path= $dirname . $file; if (is_dir($path)) { $suboptions = array_merge($options, array('deleteTop' => !$this->getOption('skipDirs', $options, false))); if ($subresult= $this->deleteTree($path, $suboptions)) { $result= array_merge($result, $subresult); } } elseif (is_file($path)) { if (is_array($extensions) && !empty($extensions) && !$this->endsWith($file, $extensions)) continue; if (unlink($path)) { array_push($result, $path); } else { $hasMore= true; } } } } closedir($handle); } if ($this->getOption('deleteTop', $options, false)) { if (@ rmdir($dirname)) { array_push($result, $dirname); } } } } else { $result= false; /* return false if attempting to operate on a file */ } return $result; } /** * Sees if a string ends with a specific pattern or set of patterns. * * @access public * @param string $string The string to check. * @param string|array $pattern The pattern or an array of patterns to check against. * @return boolean True if the string ends with the pattern or any of the patterns provided. */ public function endsWith($string, $pattern) { $matched= false; if (is_string($string) && ($stringLen= strlen($string))) { if (is_array($pattern)) { foreach ($pattern as $subPattern) { if (is_string($subPattern) && $this->endsWith($string, $subPattern)) { $matched= true; break; } } } elseif (is_string($pattern)) { if (($patternLen= strlen($pattern)) && $stringLen >= $patternLen) { $matched= (substr($string, -$patternLen) === $pattern); } } } return $matched; } /** * Sees if a string matches a specific pattern or set of patterns. * * @access public * @param string $string The string to check. * @param string|array $pattern The pattern or an array of patterns to check against. * @return boolean True if the string matched the pattern or any of the patterns provided. */ public function matches($string, $pattern) { $matched= false; if (is_string($string) && ($stringLen= strlen($string))) { if (is_array($pattern)) { foreach ($pattern as $subPattern) { if (is_string($subPattern) && $this->matches($string, $subPattern)) { $matched= true; break; } } } elseif (is_string($pattern)) { $matched= preg_match($pattern, $string); } } return $matched; } /** * Generate a PHP executable representation of an xPDOObject. * * @todo Complete $generateRelated functionality. * @todo Add stdObject support. * * @access public * @param xPDOObject $obj An xPDOObject to generate the cache file for * @param string $objName The name of the xPDOObject * @param boolean $generateObjVars If true, will also generate maps for all * object variables. Defaults to false. * @param boolean $generateRelated If true, will also generate maps for all * related objects. Defaults to false. * @param string $objRef The reference to the xPDO instance, in string * format. * @param boolean $format The format to cache in. Defaults to * xPDOCacheManager::CACHE_PHP, which is set to cache in executable PHP format. * @return string The source map file, in string format. */ public function generateObject($obj, $objName, $generateObjVars= false, $generateRelated= false, $objRef= 'this->xpdo', $format= xPDOCacheManager::CACHE_PHP) { $source= false; if (is_object($obj) && $obj instanceof xPDOObject) { $className= $obj->_class; $source= "\${$objName}= \${$objRef}->newObject('{$className}');\n"; $source .= "\${$objName}->fromArray(" . var_export($obj->toArray('', true), true) . ", '', true, true);\n"; if ($generateObjVars && $objectVars= get_object_vars($obj)) { foreach ($objectVars as $vk => $vv) { if ($vk === 'modx') { $source .= "\${$objName}->{$vk}= & \${$objRef};\n"; } elseif ($vk === 'xpdo') { $source .= "\${$objName}->{$vk}= & \${$objRef};\n"; } elseif (!is_resource($vv)) { $source .= "\${$objName}->{$vk}= " . var_export($vv, true) . ";\n"; } } } if ($generateRelated && !empty ($obj->_relatedObjects)) { foreach ($obj->_relatedObjects as $className => $fk) { foreach ($fk as $key => $relObj) {} /* TODO: complete $generateRelated functionality */ } } } return $source; } /** * Add a key-value pair to a cache provider if it does not already exist. * * @param string $key A unique key identifying the item being stored. * @param mixed & $var A reference to the PHP variable representing the item. * @param integer $lifetime Seconds the item will be valid in cache. * @param array $options Additional options for the cache add operation. */ public function add($key, & $var, $lifetime= 0, $options= array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options))) { $value= null; if (is_object($var) && $var instanceof xPDOObject) { $value= $var->toArray('', true); } else { $value= $var; } $return= $cache->add($key, $value, $lifetime, $options); } return $return; } /** * Replace a key-value pair in in a cache provider. * * @access public * @param string $key A unique key identifying the item being replaced. * @param mixed & $var A reference to the PHP variable representing the item. * @param integer $lifetime Seconds the item will be valid in objcache. * @param array $options Additional options for the cache replace operation. * @return boolean True if the replace was successful. */ public function replace($key, & $var, $lifetime= 0, $options= array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options), $options)) { $value= null; if (is_object($var) && $var instanceof xPDOObject) { $value= $var->toArray('', true); } else { $value= $var; } $return= $cache->replace($key, $value, $lifetime, $options); } return $return; } /** * Set a key-value pair in a cache provider. * * @access public * @param string $key A unique key identifying the item being set. * @param mixed & $var A reference to the PHP variable representing the item. * @param integer $lifetime Seconds the item will be valid in objcache. * @param array $options Additional options for the cache set operation. * @return boolean True if the set was successful */ public function set($key, & $var, $lifetime= 0, $options= array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options), $options)) { $value= null; if (is_object($var) && $var instanceof xPDOObject) { $value= $var->toArray('', true); } else { $value= $var; } $return= $cache->set($key, $value, $lifetime, $options); } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'No cache implementation found.'); } return $return; } /** * Delete a key-value pair from a cache provider. * * @access public * @param string $key A unique key identifying the item being deleted. * @param array $options Additional options for the cache deletion. * @return boolean True if the deletion was successful. */ public function delete($key, $options = array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options), $options)) { $return= $cache->delete($key, $options); } return $return; } /** * Get a value from a cache provider by key. * * @access public * @param string $key A unique key identifying the item being retrieved. * @param array $options Additional options for the cache retrieval. * @return mixed The value of the object cache key */ public function get($key, $options = array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options), $options)) { $return= $cache->get($key, $options); } return $return; } /** * Flush the contents of a cache provider. * * @access public * @param array $options Additional options for the cache flush. * @return boolean True if the flush was successful. */ public function clean($options = array()) { $return= false; if ($cache = $this->getCacheProvider($this->getOption(xPDO::OPT_CACHE_KEY, $options), $options)) { $return= $cache->flush($options); } return $return; } /** * Refresh specific or all cache providers. * * The default behavior is to call clean() with the provided options * * @param array $providers An associative array with keys representing the cache provider key * and the value an array of options. * @param array &$results An associative array for collecting results for each provider. * @return array An array of results for each provider that is refreshed. */ public function refresh(array $providers = array(), array &$results = array()) { if (empty($providers)) { foreach ($this->caches as $cacheKey => $cache) { $providers[$cacheKey] = array(); } } foreach ($providers as $key => $options) { if (array_key_exists($key, $this->caches) && !array_key_exists($key, $results)) { $results[$key] = $this->clean(array_merge($options, array(xPDO::OPT_CACHE_KEY => $key))); } } return (array_search(false, $results, true) === false); } /** * Escapes all single quotes in a string * * @access public * @param string $s The string to escape single quotes in. * @return string The string with single quotes escaped. */ public function escapeSingleQuotes($s) { $q1= array ( "\\", "'" ); $q2= array ( "\\\\", "\\'" ); return str_replace($q1, $q2, $s); } } /** * An abstract class that defines the methods a cache provider must implement. * * @package xpdo * @subpackage cache */ abstract class xPDOCache { public $xpdo= null; protected $options= array(); protected $key= ''; protected $initialized= false; public function __construct(& $xpdo, $options = array()) { $this->xpdo= & $xpdo; $this->options= $options; $this->key = $this->getOption(xPDO::OPT_CACHE_KEY, $options, 'default'); } /** * Indicates if this xPDOCache instance has been properly initialized. * * @return boolean true if the implementation was initialized successfully. */ public function isInitialized() { return (boolean) $this->initialized; } /** * Get an option from supplied options, the cache options, or the xpdo config. * * @param string $key Unique identifier for the option. * @param array $options A set of explicit options to override those from xPDO or the xPDOCache * implementation. * @param mixed $default An optional default value to return if no value is found. * @return mixed The value of the option. */ public function getOption($key, $options = array(), $default = null) { $option = $default; if (is_array($key)) { if (!is_array($option)) { $default= $option; $option= array(); } foreach ($key as $k) { $option[$k]= $this->getOption($k, $options, $default); } } elseif (is_string($key) && !empty($key)) { if (is_array($options) && !empty($options) && array_key_exists($key, $options)) { $option = $options[$key]; } elseif (is_array($this->options) && !empty($this->options) && array_key_exists($key, $this->options)) { $option = $this->options[$key]; } else { $option = $this->xpdo->cacheManager->getOption($key, null, $default); } } return $option; } /** * Get the actual cache key the implementation will use. * * @param string $key The identifier the application uses. * @param array $options Additional options for the operation. * @return string The identifier with any implementation specific prefixes or other * transformations applied. */ public function getCacheKey($key, $options = array()) { $prefix = $this->getOption('cache_prefix', $options); if (!empty($prefix)) $key = $prefix . $key; return $this->key . '/' . $key; } /** * Adds a value to the cache. * * @access public * @param string $key A unique key identifying the item being set. * @param string $var A reference to the PHP variable representing the item. * @param integer $expire The amount of seconds for the variable to expire in. * @param array $options Additional options for the operation. * @return boolean True if successful */ abstract public function add($key, $var, $expire= 0, $options= array()); /** * Sets a value in the cache. * * @access public * @param string $key A unique key identifying the item being set. * @param string $var A reference to the PHP variable representing the item. * @param integer $expire The amount of seconds for the variable to expire in. * @param array $options Additional options for the operation. * @return boolean True if successful */ abstract public function set($key, $var, $expire= 0, $options= array()); /** * Replaces a value in the cache. * * @access public * @param string $key A unique key identifying the item being set. * @param string $var A reference to the PHP variable representing the item. * @param integer $expire The amount of seconds for the variable to expire in. * @param array $options Additional options for the operation. * @return boolean True if successful */ abstract public function replace($key, $var, $expire= 0, $options= array()); /** * Deletes a value from the cache. * * @access public * @param string $key A unique key identifying the item being deleted. * @param array $options Additional options for the operation. * @return boolean True if successful */ abstract public function delete($key, $options= array()); /** * Gets a value from the cache. * * @access public * @param string $key A unique key identifying the item to fetch. * @param array $options Additional options for the operation. * @return mixed The value retrieved from the cache. */ public function get($key, $options= array()) {} /** * Flush all values from the cache. * * @access public * @param array $options Additional options for the operation. * @return boolean True if successful. */ abstract public function flush($options= array()); } /** * A simple file-based caching implementation using executable PHP. * * This can be used to relieve database loads, though the overall performance is * about the same as without the file-based cache. For maximum performance and * scalability, use a server with memcached and the PHP memcache extension * configured. * * @package xpdo * @subpackage cache */ class xPDOFileCache extends xPDOCache { public function __construct(& $xpdo, $options = array()) { parent :: __construct($xpdo, $options); $this->initialized = true; } public function getCacheKey($key, $options = array()) { $cachePath = $this->getOption('cache_path', $options); $cacheExt = $this->getOption('cache_ext', $options, '.cache.php'); $key = parent :: getCacheKey($key, $options); return $cachePath . $key . $cacheExt; } public function add($key, $var, $expire= 0, $options= array()) { $added= false; if (!file_exists($this->getCacheKey($key, $options))) { if ($expire === true) $expire= 0; $added= $this->set($key, $var, $expire, $options); } return $added; } public function set($key, $var, $expire= 0, $options= array()) { $set= false; if ($var !== null) { if ($expire === true) $expire= 0; $expirationTS= $expire ? time() + $expire : 0; $expireContent= ''; if ($expirationTS) { $expireContent= 'if(time() > ' . $expirationTS . '){return null;}'; } $fileName= $this->getCacheKey($key, $options); $format = (integer) $this->getOption(xPDO::OPT_CACHE_FORMAT, $options, xPDOCacheManager::CACHE_PHP); switch ($format) { case xPDOCacheManager::CACHE_SERIALIZE: $content= serialize(array('expires' => $expirationTS, 'content' => $var)); break; case xPDOCacheManager::CACHE_JSON: $content= $this->xpdo->toJSON(array('expires' => $expirationTS, 'content' => $var)); break; case xPDOCacheManager::CACHE_PHP: default: $content= '<?php ' . $expireContent . ' return ' . var_export($var, true) . ';'; break; } $folderMode = $this->getOption('new_cache_folder_permissions', $options, false); if ($folderMode) $options['new_folder_permissions'] = $folderMode; $fileMode = $this->getOption('new_cache_file_permissions', $options, false); if ($fileMode) $options['new_file_permissions'] = $fileMode; $set= $this->xpdo->cacheManager->writeFile($fileName, $content, 'wb', $options); } return $set; } public function replace($key, $var, $expire= 0, $options= array()) { $replaced= false; if (file_exists($this->getCacheKey($key, $options))) { if ($expire === true) $expire= 0; $replaced= $this->set($key, $var, $expire, $options); } return $replaced; } public function delete($key, $options= array()) { $deleted= false; if ($this->getOption('multiple_object_delete', $options, true)) { $cacheKey= $this->getCacheKey($key, array_merge($options, array('cache_ext' => ''))); if (file_exists($cacheKey) && is_dir($cacheKey)) { $results = $this->xpdo->cacheManager->deleteTree($cacheKey, array_merge(array('deleteTop' => false, 'skipDirs' => false, 'extensions' => array('.cache.php')), $options)); if ($results !== false) { $deleted = true; } } } $cacheKey= $this->getCacheKey($key, $options); if (file_exists($cacheKey)) { $deleted= @ unlink($cacheKey); } return $deleted; } public function get($key, $options= array()) { $value= null; $cacheKey= $this->getCacheKey($key, $options); if (file_exists($cacheKey)) { if ($file = @fopen($cacheKey, 'rb')) { $format = (integer) $this->getOption(xPDO::OPT_CACHE_FORMAT, $options, xPDOCacheManager::CACHE_PHP); if (flock($file, LOCK_SH)) { switch ($format) { case xPDOCacheManager::CACHE_PHP: if (!filesize($cacheKey)) { $value= false; break; } $value= @include $cacheKey; break; case xPDOCacheManager::CACHE_JSON: $payload = stream_get_contents($file); if ($payload !== false) { $payload = $this->xpdo->fromJSON($payload); if (is_array($payload) && isset($payload['expires']) && (empty($payload['expires']) || time() < $payload['expires'])) { if (array_key_exists('content', $payload)) { $value= $payload['content']; } } } break; case xPDOCacheManager::CACHE_SERIALIZE: $payload = stream_get_contents($file); if ($payload !== false) { $payload = unserialize($payload); if (is_array($payload) && isset($payload['expires']) && (empty($payload['expires']) || time() < $payload['expires'])) { if (array_key_exists('content', $payload)) { $value= $payload['content']; } } } break; } flock($file, LOCK_UN); if ($value === null && $this->getOption('removeIfEmpty', $options, true)) { fclose($file); @ unlink($cacheKey); return $value; } } @fclose($file); } } return $value; } public function flush($options= array()) { $cacheKey= $this->getCacheKey('', array_merge($options, array('cache_ext' => ''))); $results = $this->xpdo->cacheManager->deleteTree($cacheKey, array_merge(array('deleteTop' => false, 'skipDirs' => false, 'extensions' => array('.cache.php')), $options)); return ($results !== false); } } cms/modx/cache/xpdomemcached.class.php 000644 000000 000000 00000007205 13644004674 020403 0 ustar 00root wheel 000000 000000 <?php /* * Copyright 2010-2015 by MODX, LLC. * * This file is part of xPDO. * * xPDO 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. * * xPDO 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 along with * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ /** * Provides a memcached-powered xPDOCache implementation. * * This requires the memcached extension for PHP. * * @package xpdo * @subpackage cache */ class xPDOMemCached extends xPDOCache { protected $memcached = null; public function __construct(& $xpdo, $options = array()) { parent :: __construct($xpdo, $options); if (class_exists('Memcached', true)) { $this->memcached = new Memcached(); if ($this->memcached) { $servers = explode(',', $this->getOption($this->key . '_memcached_server', $options, $this->getOption('memcached_server', $options, 'localhost:11211'))); foreach ($servers as $server) { $server = explode(':', $server); $this->memcached->addServer($server[0], (integer) $server[1]); } $this->memcached->setOption(Memcached::OPT_COMPRESSION, (boolean) $this->getOption($this->key . '_memcached_compression', $options, $this->getOption('memcached_compression', $options, $this->getOption(Memcached::OPT_COMPRESSION, $options, true)))); $this->initialized = true; } else { $this->memcached = null; $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOMemCached[{$this->key}]: Error creating memcached provider for server(s): " . $this->getOption($this->key . '_memcached_server', $options, $this->getOption('memcached_server', $options, 'localhost:11211'))); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOMemCached[{$this->key}]: Error creating memcached provider; xPDOMemCached requires the PHP memcached extension."); } } public function add($key, $var, $expire= 0, $options= array()) { $added= $this->memcached->add( $this->getCacheKey($key), $var, $expire ); return $added; } public function set($key, $var, $expire= 0, $options= array()) { $set= $this->memcached->set( $this->getCacheKey($key), $var, $expire ); return $set; } public function replace($key, $var, $expire= 0, $options= array()) { $replaced= $this->memcached->replace( $this->getCacheKey($key), $var, $expire ); return $replaced; } public function delete($key, $options= array()) { if (!isset($options['multiple_object_delete']) || empty($options['multiple_object_delete'])) { $deleted= $this->memcached->delete($this->getCacheKey($key)); } else { $deleted= $this->flush($options); } return $deleted; } public function get($key, $options= array()) { return $this->memcached->get($this->getCacheKey($key)); } public function flush($options= array()) { return $this->memcached->flush(); } } cms/modx/cache/xpdoapccache.class.php 000644 000000 000000 00000006522 13644004674 020225 0 ustar 00root wheel 000000 000000 <?php /* * Copyright 2010-2015 by MODX, LLC. * * This file is part of xPDO. * * xPDO 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. * * xPDO 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 along with * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ /** * Provides an APC-powered xPDOCache implementation. * * This requires the APC extension for PHP, version 3.1.4 or later. Earlier versions * did not have all the necessary user cache methods. * * @package xpdo * @subpackage cache */ class xPDOAPCCache extends xPDOCache { public function __construct(& $xpdo, $options = array()) { parent :: __construct($xpdo, $options); if (function_exists('apc_exists')) { $this->initialized = true; } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOAPCCache[{$this->key}]: Error creating APC cache provider; xPDOAPCCache requires the APC extension for PHP, version 2.0.0 or later."); } } public function add($key, $var, $expire= 0, $options= array()) { $added= apc_add( $this->getCacheKey($key), $var, $expire ); return $added; } public function set($key, $var, $expire= 0, $options= array()) { $set= apc_store( $this->getCacheKey($key), $var, $expire ); return $set; } public function replace($key, $var, $expire= 0, $options= array()) { $replaced = false; if (apc_exists($key)) { $replaced= apc_store( $this->getCacheKey($key), $var, $expire ); } return $replaced; } public function delete($key, $options= array()) { $deleted = false; if (!isset($options['multiple_object_delete']) || empty($options['multiple_object_delete'])) { $deleted= apc_delete($this->getCacheKey($key)); } elseif (class_exists('APCIterator', true)) { $iterator = new APCIterator('user', '/^' . str_replace('/', '\/', $this->getCacheKey($key)) . '/', APC_ITER_KEY); if ($iterator) { $deleted = apc_delete($iterator); } } return $deleted; } public function get($key, $options= array()) { $value= apc_fetch($this->getCacheKey($key)); return $value; } public function flush($options= array()) { $flushed = false; if (class_exists('APCIterator', true) && $this->getOption('flush_by_key', $options, true) && !empty($this->key)) { $iterator = new APCIterator('user', '/^' . str_replace('/', '\/', $this->key) . '\//', APC_ITER_KEY); if ($iterator) { $flushed = apc_delete($iterator); } } else { $flushed = apc_clear_cache('user'); } return $flushed; } } cms/modx/cache/xpdomemcache.class.php 000644 000000 000000 00000010726 13644004674 020241 0 ustar 00root wheel 000000 000000 <?php /* * Copyright 2010-2015 by MODX, LLC. * * This file is part of xPDO. * * xPDO 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. * * xPDO 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 along with * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ /** * Provides a memcache-powered xPDOCache implementation. * * This requires the memcache extension for PHP. * * @package xpdo * @subpackage cache */ class xPDOMemCache extends xPDOCache { protected $memcache = null; public function __construct(& $xpdo, $options = array()) { parent :: __construct($xpdo, $options); if (class_exists('Memcache', true)) { $this->memcache= new Memcache(); if ($this->memcache) { $servers = explode(',', $this->getOption($this->key . '_memcached_server', $options, $this->getOption('memcached_server', $options, 'localhost:11211'))); foreach ($servers as $server) { $server = explode(':', $server); $this->memcache->addServer($server[0], (integer) $server[1]); } $compressThreshold = $this->getOption($this->key . '_memcached_compress_threshold', $options, $this->getOption('memcached_compress_threshold', array(), '20000:0.2')); if (!empty($compressThreshold)) { $threshold = explode(':', $compressThreshold); if (count($threshold) == 2) { $minValue = (integer) $threshold[0]; $minSaving = (float) $threshold[1]; if ($minSaving >= 0 && $minSaving <= 1) { $this->memcache->setCompressThreshold($minValue, $minSaving); } } } $this->initialized = true; } else { $this->memcache = null; $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOMemCache[{$this->key}]: Error creating memcache provider for server(s): " . $this->getOption($this->key . '_memcached_server', $options, $this->getOption('memcached_server', $options, 'localhost:11211'))); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOMemCache[{$this->key}]: Error creating memcache provider; xPDOMemCache requires the PHP memcache extension."); } } public function add($key, $var, $expire= 0, $options= array()) { $added= $this->memcache->add( $this->getCacheKey($key), $var, $this->getOption($this->key . xPDO::OPT_CACHE_COMPRESS, $options, $this->getOption(xPDO::OPT_CACHE_COMPRESS, $options, false)), $expire ); return $added; } public function set($key, $var, $expire= 0, $options= array()) { $set= $this->memcache->set( $this->getCacheKey($key), $var, $this->getOption($this->key . xPDO::OPT_CACHE_COMPRESS, $options, $this->getOption(xPDO::OPT_CACHE_COMPRESS, $options, false)), $expire ); return $set; } public function replace($key, $var, $expire= 0, $options= array()) { $replaced= $this->memcache->replace( $this->getCacheKey($key), $var, $this->getOption($this->key . xPDO::OPT_CACHE_COMPRESS, $options, $this->getOption(xPDO::OPT_CACHE_COMPRESS, $options, false)), $expire ); return $replaced; } public function delete($key, $options= array()) { if (!isset($options['multiple_object_delete']) || empty($options['multiple_object_delete'])) { $deleted= $this->memcache->delete($this->getCacheKey($key)); } else { $deleted= $this->flush($options); } return $deleted; } public function get($key, $options= array()) { $value= $this->memcache->get($this->getCacheKey($key)); return $value; } public function flush($options= array()) { return $this->memcache->flush(); } } cms/modx/cache/xpdowincache.class.php 000644 000000 000000 00000005442 13644004674 020257 0 ustar 00root wheel 000000 000000 <?php /* * Copyright 2010-2015 by MODX, LLC. * * This file is part of xPDO. * * xPDO 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. * * xPDO 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 along with * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ /** * Provides a wincache-powered xPDOCache implementation. * * This requires the wincache extension for PHP, version 1.1.0 or later. Earlier versions * did not have user cache methods. * * @package xpdo * @subpackage cache */ class xPDOWinCache extends xPDOCache { public function __construct(& $xpdo, $options = array()) { parent :: __construct($xpdo, $options); if (function_exists('wincache_ucache_info')) { $this->initialized = true; } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOWinCache[{$this->key}]: Error creating wincache provider; xPDOWinCache requires the PHP wincache extension, version 1.1.0 or later."); } } public function add($key, $var, $expire= 0, $options= array()) { $added= wincache_ucache_add( $this->getCacheKey($key), $var, $expire ); return $added; } public function set($key, $var, $expire= 0, $options= array()) { $set= wincache_ucache_set( $this->getCacheKey($key), $var, $expire ); return $set; } public function replace($key, $var, $expire= 0, $options= array()) { $replaced = false; if (wincache_ucache_exists($key)) { $replaced= wincache_ucache_set( $this->getCacheKey($key), $var, $expire ); } return $replaced; } public function delete($key, $options= array()) { $deleted = false; if (!isset($options['multiple_object_delete']) || empty($options['multiple_object_delete'])) { $deleted= wincache_ucache_delete($this->getCacheKey($key)); } else { $deleted= $this->flush($options); } return $deleted; } public function get($key, $options= array()) { $value= wincache_ucache_get($this->getCacheKey($key)); return $value; } public function flush($options= array()) { return wincache_ucache_clear(); } } cms/wordpress/class-wpml-cache-directory.php 000644 000000 000000 00000005037 14214543530 021633 0 ustar 00root wheel 000000 000000 <?php class WPML_Cache_Directory { const DIR_PERMISSIONS = 0775; const MAIN_DIRECTORY_NAME = 'wpml'; const NOTICE_GROUP = 'wpml-cache-directory'; const NOTICE_INVALID_CACHE = 'invalid-cache'; private $cache_disabled = false; /** * @var WPML_WP_API */ private $wp_api; /** * @var WP_Filesystem_Direct */ private $filesystem; /** * WPML_Cache_Directory constructor. * * @param WPML_WP_API $wp_api */ public function __construct( WPML_WP_API $wp_api ) { $this->wp_api = $wp_api; $this->filesystem = $wp_api->get_wp_filesystem_direct(); } /** * @return string */ private function get_main_directory_path() { $main_directory_path = null; $cache_path_root = $this->wp_api->constant( 'WPML_CACHE_PATH_ROOT' ); if ( $cache_path_root ) { $main_directory_path = trailingslashit( $cache_path_root ) . self::MAIN_DIRECTORY_NAME; return trailingslashit( $main_directory_path ); }else { $upload_dir = wp_upload_dir(); if ( empty( $upload_dir['error'] ) ) { $base_dir = $upload_dir['basedir']; $main_directory_path = trailingslashit( $base_dir ) . 'cache/' . self::MAIN_DIRECTORY_NAME; return trailingslashit( $main_directory_path ); } } return null; } /** * The function `wp_mkdir_p` will create directories recursively * * @param string $absolute_path * * @return string|bool absolute path or false if we can't have a writable and readable directory */ private function maybe_create_directory( $absolute_path ) { $result = true; if ( ! $this->filesystem->is_dir( $absolute_path ) ) { $result = wp_mkdir_p( $absolute_path ); } return $result ? $absolute_path : false; } /** * @param string $relative_path * * @return string|bool absolute path or false if we can't have a writable and readable directory */ public function get( $relative_path = '' ) { $absolute_path = false; $main_directory_path = $this->maybe_create_directory( $this->get_main_directory_path() ); if ( $main_directory_path ) { $absolute_path = trailingslashit( $main_directory_path . ltrim( $relative_path, '/\\' ) ); $absolute_path = $this->maybe_create_directory( $absolute_path ); } return $absolute_path; } /** * @param string $relative_path */ public function remove( $relative_path = '' ) { $main_directory_path = $this->get_main_directory_path(); if ( $main_directory_path ) { $absolute_path = trailingslashit( $main_directory_path . ltrim( $relative_path, '/\\' ) ); $this->filesystem->delete( $absolute_path, true ); } } } cms/wordpress/wp-optimize-versions/ 000755 000000 000000 00000000000 14215042706 020122 5 ustar 00root wheel 000000 000000 cms/wordpress/interface-wpml-log.php 000644 000000 000000 00000000412 13573440334 020177 0 ustar 00root wheel 000000 000000 <?php /** * @author OnTheGo Systems */ interface WPML_Log { public function insert( $timestamp, array $entry ); public function get( $page_size = 0, $page = 0 ); public function save( array $data ); public function clear(); public function is_empty(); } cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/ 000755 000000 000000 00000000000 14215042730 023044 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.2.3/ 000755 000000 000000 00000000000 14214670220 022704 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.0/ 000755 000000 000000 00000000000 14214670220 022702 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.2.2/ 000755 000000 000000 00000000000 14214670220 022703 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.2/ 000755 000000 000000 00000000000 14214670220 022704 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.1/ 000755 000000 000000 00000000000 14214670220 022703 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/ 000755 000000 000000 00000000000 14214670220 025167 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/ 000755 000000 000000 00000000000 14214670220 026232 5 ustar 00root wheel 000000 000000 wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-detect-cache-plugins.php 000644 000000 000000 00000004420 13665647440 034603 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ protected function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $active_cache_plugins = array(); foreach ($this->get_plugins() as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Get the plugins list * * @return array */ protected function get_plugins() { return array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { static $instance; if (empty($instance)) { $instance = new self(); } return $instance; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000075711 13665416124 032653 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality * * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('WP_Optimize_Detect_Cache_Plugins')) require_once(dirname(__FILE__) . '/class-wpo-detect-cache-plugins.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-php-logger.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (version_compare(PHP_VERSION, '5.3.0') >= 0) { require_once dirname(__FILE__) . '/php-5.3-functions.php'; } wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Store last advanced cache file writing status * If true then last writing finished with error * * @var bool */ public $advanced_cache_file_writing_error; /** * Store errors * * @var array */ private $_errors = array(); /** * Last advanced cache file content * * @var string */ public $advanced_cache_file_content; /** * Store the latest advanced-cache.php version required * * @var string */ private $_minimum_advanced_cache_file_version = '3.0.17'; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); add_action('activate_plugin', array($this, 'activate_deactivate_plugin')); add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); /** * Regenerate config file on cache flush. */ add_action('wpo_cache_flush', array($this, 'update_cache_config')); add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); // Add purge cache link to admin bar. add_action('admin_bar_menu', array($this, 'wpo_admin_bar_purge_cache'), 100); // Handle single page purge. add_action('wp_loaded', array($this, 'handle_purge_single_page_cache')); add_action('admin_init', array($this, 'admin_init')); } /** * Do required actions on activate/deactivate any plugin. */ public function activate_deactivate_plugin() { $this->update_cache_config(); /** * Filters whether activating / deactivating a plugin will purge the cache. */ if (apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true)) { $this->purge(); } } /** * Check if current user can purge cache. * * @return bool */ public function can_purge_cache() { if (is_multisite()) return $this->is_enabled() && current_user_can('manage_network_options'); return $this->is_enabled() && current_user_can('manage_options'); } /** * Add Purge from cache in admin bar. * * @param WP_Admin_Bar $wp_admin_bar */ public function wpo_admin_bar_purge_cache($wp_admin_bar) { global $pagenow; if (!$this->can_purge_cache()) return; $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); if (!is_admin() || 'post.php' == $pagenow) { $wp_admin_bar->add_menu(array( 'id' => 'wpo_purge_cache', 'title' => __('Purge cache', 'wp-optimize'), 'href' => '#', 'meta' => array( 'title' => __('Purge cache', 'wp-optimize'), ), 'parent' => false, )); $wp_admin_bar->add_node(array( 'id' => 'wpo_purge_this_page_cache', 'title' => __('Purge this page', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), 'meta' => array( 'title' => __('Purge this page', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', )); $wp_admin_bar->add_node(array( 'id' => 'wpo_purge_all_pages_cache', 'title' => __('Purge all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge all pages', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', )); } else { $wp_admin_bar->add_menu(array( 'id' => 'wpo_purge_cache', 'title' => __('Purge all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge all pages', 'wp-optimize'), ), 'parent' => false, )); } } /** * Check if purge single page action sent and purge cache. */ public function handle_purge_single_page_cache() { if (!$this->can_purge_cache()) return; if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { if (isset($_GET['wpo_single_page_cache_purged'])) { $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; } else { $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; } add_action('admin_notices', array($this, $notice_function)); return; } if (!isset($_GET['_wpo_purge'])) return; if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) { $success = false; if (is_admin()) { $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; if ($post > 0) { $success = self::delete_single_post_cache($post); } } else { $success = self::delete_cache_by_url(wpo_current_url()); } // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) { $success = self::purge(); // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } } /** * Show notification when page cache purged successfully. */ public function notice_purge_single_page_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when page cache wasn't purged. */ public function notice_purge_single_page_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification when all pages cache purged successfully. */ public function notice_purge_all_pages_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when all pages cache wasn't purged. */ public function notice_purge_all_pages_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification in WordPress admin. * * @param string $message HTML (no further escaping is performed) * @param string $type error, warning, success, or info */ public function show_notice($message, $type) { global $current_screen; if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?> <script> window.addEventListener('load', function() { (function(wp) { if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) { wp.data.dispatch('core/notices').createNotice( '<?php echo $type; ?>', '<?php echo $message; ?>', { isDismissible: true, } ); } })(window.wp); }); </script> <?php else : ?> <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible"> <p><?php echo $message; ?></p> </div> <?php endif; } /** * Enables page cache * * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings * * @return WP_Error|bool - true on success, error otherwise */ public function enable($force_enable = false) { static $already_ran_enable = false; if ($already_ran_enable) return $already_ran_enable; $folders_created = $this->create_folders(); if (is_wp_error($folders_created)) { $already_ran_enable = $folders_created; return $already_ran_enable; } // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) { $force_enable = true; } if (!$force_enable) { $already_ran_enable = true; return true; } if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) { $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Your WP install might not have permission to write inside the wp-content folder.', 'wp-optimize'); if (!defined('WP_CLI') || !WP_CLI) { $message .= "\n\n".sprintf(__('1. Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); $message .= "\n".__('2. Edit or create a file with the name advanced-cache.php', 'wp-optimize'); $message .= "\n".__('3. Copy and paste the following lines into the file:', 'wp-optimize'); } $already_ran_enable = new WP_Error("write_advanced_cache", $message); return $already_ran_enable; } if (!$this->write_wp_config(true)) { $already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions."); return $already_ran_enable; } if (!$this->verify_cache()) { $errors = $this->get_errors(); $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors)); return $already_ran_enable; } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; $advanced_cache_file = $this->get_advanced_cache_filename(); // N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem. $disabled_wp_config = $this->write_wp_config(false); if (!$disabled_wp_config) { $this->log("Could not turn off the WP_CACHE constant in wp-config.php"); $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize')); } $disabled_advanced_cache = true; // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { $disabled_advanced_cache = false; $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize')); } } // If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled. if (!$disabled_wp_config && !$disabled_advanced_cache) { $ret = new WP_Error('error_disabling_cache', __('The page caching could not be disabled: the WP_CACHE constant could not be removed from wp-config.php and the request to the filesystem to remove or empty advanced-cache.php failed.', 'wp-optimize')); } // Delete cache to avoid stale cache on next activation $this->purge(); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } /** * Fires after purging the cache */ do_action('wpo_cache_flush'); return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR))); } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR))); } if (!is_dir(WPO_CACHE_FILES_DIR)) { if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR))); } else { wpo_disable_cache_directories_viewing(); } } return true; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_advanced_cache_filename() { return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_cache_config_filename() { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { return 'config-'.$url['host'].'-port'.$url['port'].'.php'; } else { return 'config-'.$url['host'].'.php'; } } /** * Writes advanced-cache.php * * @param boolean $update_required - Whether the update is required or not. * @return bool */ private function write_advanced_cache($update_required = false) { $config_file_basename = $this->get_cache_config_filename(); $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__)); $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $cache_path = '/wpo-cache'; $cache_files_path = '/cache/wpo-cache'; $cache_extensions_path = WPO_CACHE_EXT_DIR; $wpo_version = WPO_VERSION; // CS does not like heredoc // phpcs:disable $this->advanced_cache_file_content = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); // WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks) if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); if (is_admin()) { return; } \$possible_plugin_locations = array( defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false, defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false, dirname(__FILE__).'/plugins/$plugin_basename/cache', '$cache_file_basename', ); \$plugin_location = false; foreach (\$possible_plugin_locations as \$possible_location) { if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) { \$plugin_location = \$possible_location; break; } } if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path'); if (false !== \$plugin_location) { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions'); } else { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); } if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; } \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true); if (empty(\$GLOBALS['wpo_cache_config'])) { include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'); } if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); } EOF; // phpcs:enable $advanced_cache_filename = $this->get_advanced_cache_filename(); // If the file content is already up to date, success if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) { $this->advanced_cache_file_writing_error = false; return true; } // check if we can't write the advanced cache file // case 1: the directory is read-only and the file doesn't exist if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) { $this->advanced_cache_file_writing_error = true; return false; } // case 2: the file already exists but it's read-only if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) { if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) { $this->advanced_cache_file_writing_error = true; return false; } else { $this->advanced_cache_file_writing_error = false; return true; } } if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) { $this->advanced_cache_file_writing_error = true; return false; } $this->advanced_cache_file_writing_error = false; return true; } /** * Update advanced cache version if needed. */ public function maybe_update_advanced_cache() { if (!$this->is_enabled()) return; // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php $advanced_cache_current_version = $this->get_advanced_cache_version(); if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return; if (!$this->write_advanced_cache()) { add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); } else { $this->update_cache_config(); } } /** * Show notification when advanced-cache.php could not be updated. */ public function notice_advanced_cache_autoupdate_error() { $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp_optimize'). ' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to disable and then re-enable the WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error'); } /** * Get WPO version number from advanced-cache.php file. * * @return bool|mixed */ public function get_advanced_cache_version() { if (!is_file($this->get_advanced_cache_filename())) return false; $version = false; $content = file_get_contents($this->get_advanced_cache_filename()); if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { $version = $match[1]; } return $version; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { // If we changed the value in wp-config, save it, in case we need to change it again in the same run. static $changed = false; if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r\n)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) { return false; } $changed = true; return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } $errors = 0; // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize')); } $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; // Now check wp-content. We need to be able to create files of the same user as this file. if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); $this->add_error('verify_cache', __("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions", 'wp-optimize')); $errors++; } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); $this->add_warning('verify_cache', sprintf(__("Unable to write inside the cache files folder (%s); please check file/folder permissions (no cache files will be able to be created otherwise)", 'wp-optimize'), WPO_CACHE_FILES_DIR)); } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); // If the config exists, only send a warning. Otherwise send an error. $type = 'warning'; if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { $type = 'error'; $errors++; } $this->add_error('verify_cache', sprintf(__("Unable to write inside the cache configuration folder (%s); please check file/folder permissions", 'wp-optimize'), WPO_CACHE_CONFIG_DIR), $type); } } return !$errors; } /** * Update cache config. Used to support 3d party plugins. */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. $this->config->update($current_config, true); } /** * Delete information about cache size. */ public function delete_cache_size_information() { delete_transient('wpo_get_cache_size'); } /** * Get current cache size. * * @return array */ public function get_cache_size() { $cache_size = get_transient('wpo_get_cache_size'); if (!empty($cache_size)) return $cache_size; $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); $cache_size = array( 'size' => $infos['size'], 'file_count' => $infos['file_count'] ); set_transient('wpo_get_cache_size', $cache_size); return $cache_size; } /** * Fetch directory informations. * * @param string $dir * @return array */ private function get_dir_infos($dir) { $dir_size = 0; $file_count = 0; $handle = is_dir($dir) ? opendir($dir) : false; if (false === $handle) { return array('size' => 0, 'file_count' => 0); } $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { $current_file = $dir.'/'.$file; if (is_dir($current_file)) { $sub_dir_infos = $this->get_dir_infos($current_file); $dir_size += $sub_dir_infos['size']; $file_count += $sub_dir_infos['file_count']; } elseif (is_file($current_file)) { $dir_size += filesize($current_file); $file_count++; } } $file = readdir($handle); } return array('size' => $dir_size, 'file_count' => $file_count); } /** * Returns the path to wp-config * * @return string|boolean wp-config.php path. */ private function _get_wp_config() { $config_path = false; foreach (get_included_files() as $filename) { if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) { $config_path = $filename; break; } } // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file. if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) { $config_path = wpo_wp_cli_locate_wp_config(); } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Delete cached files for specific url. * * @param string $url * @param bool $recursive If true child elements will deleted too * * @return bool */ public static function delete_cache_by_url($url, $recursive = false) { if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url)); return wpo_delete_files($path, $recursive); } /** * Delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function delete_single_post_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path(get_permalink($post_id))); return wpo_delete_files($path, false); } /** * Delete cached home page files. */ public static function delete_homepage_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path(get_home_url(get_current_blog_id()))); wpo_delete_files($path, false); } /** * Admin actions * * @return void */ public function admin_init() { // Maybe update the advanced cache. if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { $this->maybe_update_advanced_cache(); } } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log('ERROR', $message); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Adds an error to the error store * * @param string $code - The error code * @param string $message - The error's message * @param string $type - The error's type (error, warning) * @return void */ public function add_error($code, $message, $type = 'error') { if (!isset($this->_errors[$type])) { $this->_errors[$type] = new WP_Error($code, $message); } else { $this->_errors[$type]->add($code, $message); } } /** * Adds a warning to the error store * * @param string $code - The error code * @param string $message - The error's message * @return void */ public function add_warning($code, $message) { $this->add_error($code, $message, 'warning'); } /** * Get all recorded errors * * @param string $type - The error type * @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object * @return boolean|array|WP_Error */ public function get_errors($type = 'error', $get_messages_only = true) { if (!$this->has_errors($type)) return false; $errors = $this->_errors[$type]; if ($get_messages_only) { return $errors->get_error_messages(); } return $errors; } /** * Check if any errors were recorded * * @param string $type - The error type * @return boolean */ public function has_errors($type = 'error') { return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors(); } /** * Check if any warnings were recorded * * @return boolean */ public function has_warnings() { return $this->has_errors('warning'); } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000021703 13665416124 033061 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1); add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2); add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6); add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1); /** * List of hooks for which when executed, the cache will be purged * * @param array $actions The actions */ $purge_on_action = apply_filters('wpo_purge_cache_hooks', array('after_switch_theme', 'wp_update_nav_menu', 'customize_save_after', array('wp_ajax_save-widget', 0), array('wp_ajax_update-widget', 0), 'autoptimize_action_cachepurged')); foreach ($purge_on_action as $action) { if (is_array($action)) { add_action($action[0], array($this, 'purge_cache'), $action[1]); } else { add_action($action, array($this, 'purge_cache')); } } } /** * Purge post cache when there is a new approved comment * * @param int $comment_id Comment ID. * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'. * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/ */ public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) { if (1 !== $approved) { return; } if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) { $post_id = $commentdata['comment_post_ID']; WPO_Page_Cache::delete_single_post_cache($post_id); } } /** * Every time a comment's status changes, purge it's parent posts cache * * @param int $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (!empty($this->config['enable_page_caching'])) { $comment = get_comment($comment_id); if (is_object($comment) && !empty($comment->comment_post_ID)) WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID); } } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); $post_type_object = get_post_type_object($post_type); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || !$post_type_object->public) { return; } /** * Purge the whole cache if set to true, only the edited post otherwise. Default is false. * * @param boolean $purge_all_cache The default filter value * @param integer $post_id The saved post ID */ if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) { $this->purge_cache(); return; } else { if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::delete_single_post_cache($post_id); } } /** * Purge archive pages on post update. * * @param integer $post_id */ public function purge_archive_pages_on_post_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } $post_obj = get_post_type_object($post_type); if ('post' == $post_type) { // delete all archive pages for post. $post_date = get_post_time('Y-m-j', false, $post_id); list($year, $month, $day) = $post_date; $archive_links = array( get_year_link($year), get_month_link($year, $month), get_day_link($year, $month, $day), ); foreach ($archive_links as $link) { WPO_Page_Cache::delete_cache_by_url($link, true); } } elseif ($post_obj->has_archive) { // delete archive page for custom post type. WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true); } } /** * We use it with edit_terms action filter to purge cached elements related * to updated term when term updated. * * @param int $term_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. */ public function purge_related_elements_on_term_updated($term_id, $taxonomy) { // purge cached page for term. $term = get_term($term_id, $taxonomy, ARRAY_A); if (is_array($term)) { $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } // get posts which belongs to updated term. $posts = get_posts(array( 'numberposts' => -1, 'post_type' => 'any', 'fields' => 'ids', 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $term_id, ) ), )); if (!empty($posts)) { foreach ($posts as $post_id) { WPO_Page_Cache::delete_single_post_cache($post_id); } } } /** * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) { $post_type = get_post_type($object_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) { return; } /** * Adds a way to exit the purge of terms permalink using the provided parameters. * * @param bool $purge The value filtered, whether or not to purge the related elements * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. * @default true * @return boolean */ if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return; // get all affected terms. $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids)); if (!empty($affected_terms_ids)) { // walk through all changed terms and purge cached pages for them. foreach ($affected_terms_ids as $tt_id) { $term = get_term($tt_id, $taxonomy, ARRAY_A); if (!is_array($term)) continue; $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { $url = parse_url($term_permalink); // Check if the permalink contains a valid path, to avoid deleting the whole cache. if (!isset($url['path']) || '/' === $url['path']) return; WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } } } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Triggered by wpo_cache_config_updated. * * @param array $config */ public function cache_config_updated($config) { // delete front page form cache if defined in the settings if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) { WPO_Page_Cache::delete_cache_by_url(home_url()); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000016424 13665416124 033200 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return isset($options[$option_key]) ? $options[$option_key] : $default; } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved. * * @return bool */ public function update($config, $skip_disk_if_not_yet_present = false) { $config = wp_parse_args($config, $this->get_defaults()); $config['page_cache_length_value'] = intval($config['page_cache_length_value']); $config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']); /** * Filters the cookies used to set cache file names * * @param array $cookies - The cookies * @param array $config - The new config */ $wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config); sort($wpo_cache_cookies); /** * Filters the query variables used to set cache file names * * @param array $wpo_query_variables - The variables * @param array $config - The new config */ $wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; $config = apply_filters('wpo_cache_update_config', $config); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } do_action('wpo_cache_config_updated', $config); return $this->write($config, $skip_disk_if_not_yet_present); } /** * Calculate cache expiration value in seconds. * * @param int $value * @param string $unit ( hours | days | months ) * * @return int */ private function calculate_page_cache_length($value, $unit) { $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); return $value * $cache_length_units[$unit]; } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config - Configuration array. * @param boolean $only_if_present - only writes to the disk if the configuration file already exists * * @return boolean - returns false if an attempt to write failed */ private function write($config, $only_if_present = false) { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'-port'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); // from 3.0.17 we use more secure way to store cache config files. $advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version(); // if advanced-cache.php exists and has at least 3.0.17 version or // advanced-cache.php doesn't exist and WP-O has at least 3.0.17 version then // we write the cache config in a new format. if (($advanced_cache_version && (0 >= version_compare($advanced_cache_version, '3.0.17'))) || (!$advanced_cache_version && (0 >= version_compare(WPO_VERSION, '3.0.17'))) ) { $config_content = '<?php' . "\n" . 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n" . '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . json_encode($this->config) . '\', true);' . "\n"; } else { $config_content = json_encode($this->config); } if ((!$only_if_present || file_exists($config_file)) && !file_put_contents($config_file, $config_content)) { return new WP_Error('write_cache_config', sprintf(__('The cache configuration file could not be saved to the disk; please check the file/folder permissions of %s .', 'wp-optimize'), $config_file)); } return true; } /** * Verify we can write to the file system * * @since 1.0 * @return boolean */ public function verify_file_access() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) { return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) { return false; } // If the cache and config directories exist, make sure they're writeable if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) { if (file_exists(WPO_CACHE_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_DIR)) { return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) { return false; } } } return true; } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => false, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => network_site_url('/'), 'enable_cache_per_country' => false, ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/php-5.3-functions.php 000644 000000 000000 00000000575 13614520640 032055 0 ustar 00root wheel 000000 000000 <?php /** * Get path to wp-config.php when called from WP-CLI. * * @return string */ function wpo_wp_cli_locate_wp_config() { $config_path = ''; if (is_callable('\WP_CLI\Utils\locate_wp_config')) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound $config_path = \WP_CLI\Utils\locate_wp_config(); } return $config_path; } cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-cache-commands.php 000644 000000 000000 00000022100 13665416124 032715 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); $enabled = false; $disabled = false; $return = array(); $previous_settings = WPO_Cache_Config::instance()->get(); // Attempt to change current status if required if (isset($previous_settings['enable_page_caching']) && $previous_settings['enable_page_caching'] != $data['cache-settings']['enable_page_caching']) { // Disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { $disabled = WPO_Page_Cache::instance()->disable(); // Disabling failed if ($disabled && is_wp_error($disabled)) { // If disabling failed, we re-enable whatever was disabled, to make sure nothing breaks. if ($previous_settings['enable_page_caching']) WPO_Page_Cache::instance()->enable(true); $return['error'] = array( 'code' => $disabled->get_error_code(), 'message' => $disabled->get_error_message() ); } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was disabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. $enabled = WPO_Page_Cache::instance()->enable(true); // Enabling failed if (is_wp_error($enabled)) { // disable everything, to avoid half enabled things WPO_Page_Cache::instance()->disable(); $return['error'] = array( 'code' => $enabled->get_error_code(), 'message' => $enabled->get_error_message() ); if (WPO_Page_Cache::instance()->advanced_cache_file_writing_error) { $return['advanced_cache_file_writing_error'] = true; $return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content; } } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was enabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } // Override enabled setting value $data['cache-settings']['enable_page_caching'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); } else { $data['cache-settings']['enable_page_caching'] = $previous_settings['enable_page_caching']; $enabled = $previous_settings['enable_page_caching']; } $skip_if_no_file_yet = !$enabled || is_wp_error($enabled); $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet); if ($save_settings_result && !is_wp_error($save_settings_result)) { WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings); $return['result'] = $save_settings_result; } else { // Saving the settings returned an error if (is_wp_error($save_settings_result)) { if (isset($return['error'])) { $return['error']['message'] .= "\n\n".$save_settings_result->get_error_message(); } else { $return['error'] = array( 'code' => $save_settings_result->get_error_code(), 'message' => $save_settings_result->get_error_message() ); } } $return['result'] = false; } $return['enabled'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); return $return; } /** * Get information about current cache status. Used in cli commands. * * @return array */ public function get_status_info() { $status = array(); $status[] = WPO_Page_Cache::instance()->is_enabled() ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize'); $preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); $status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']); $status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']); if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message']; $status['message'] = join(PHP_EOL, $status); return $status; } /** * Enable cache. */ public function enable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = true; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Disable cache. */ public function disable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = false; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Purge WP-Optimize page cache. * * @return array */ public function purge_page_cache() { $purged = WP_Optimize()->get_page_cache()->purge(); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); $response = array( 'success' => $purged, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], ); // if scheduled preload enabled then reschedule and run preloader. if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) { // cancel preload and reschedule preload action. $wpo_page_cache_preloader->cancel_preload(); $wpo_page_cache_preloader->reschedule_preload(); // run preloader. $wpo_page_cache_preloader->run('scheduled', $response); } if ($response['success']) { $response['message'] = __('Page cache purged successfully', 'wp-optimize'); } return $response; } /** * Run cache preload (for wp-cli). * * @return array|bool */ public function run_cache_preload_cli() { global $wpdb; if (!(defined('WP_CLI') && WP_CLI)) return false; // define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file // but we check this constant value wen detecting status of cache if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); // don't interrupt queue processing add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99); // if preloading is running then exit. if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) { return array( 'success' => false, 'error' => __('Preloading is currently running in another process.', 'wp-optimize'), ); } // set default response. $response = array( 'success' => true, 'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'), ); WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize')); return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response); } /** * Run cache preload action. * * @return void|array - Doesn't return anything if run() is successfull (Run() prints a JSON object and closed browser connection) or an array if failed. */ public function run_cache_preload() { return WP_Optimize_Page_Cache_Preloader::instance()->run('manual'); } /** * Cancel cache preload action. * * @return array */ public function cancel_cache_preload() { WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload(); return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Get status of cache preload. * * @return array */ public function get_cache_preload_status() { return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } /** * Format save_cache_settings() result for displaying in WP-CLI console * * @param array $response * @return array */ private function format_save_cache_settings_response($response) { $result = array( 'success' => $response['result'], ); if (isset($response['error'])) { $result['success'] = false; $result['error'] = $response['error']['message']; } if ($result['success']) { $result['message'] = __('Page cache settings updated successfully.', 'wp-optimize'); } return $result; } } wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/file-based-page-cache-functions.php000644 000000 000000 00000071650 13665416124 034663 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above. * * @param string $buffer Page HTML. * @param int $flags OB flags to be passed through. * @return string */ if (!function_exists('wpo_cache')) : function wpo_cache($buffer, $flags) { global $post; // This array records reasons why no cacheing took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately. $no_cache_because = array(); if (strlen($buffer) < 255) { $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth caching', 'wp-optimize'), 255); } // Don't cache pages for logged in users. if (!function_exists('is_user_logged_in') || is_user_logged_in()) { $no_cache_because[] = __('User is logged in', 'wp-optimize'); } $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_page_type_cache) { $no_cache_because[] = $restricted_page_type_cache; } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) { $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')'; } elseif (!file_exists(WPO_CACHE_FILES_DIR)) { // Try creating a folder for cached files, if it was flushed recently if (!mkdir(WPO_CACHE_FILES_DIR)) { $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')'; } else { wpo_disable_cache_directories_viewing(); } } // If comments are opened and the user has saved his information if (function_exists('comments_open') && comments_open()) { $commenter = wp_get_current_commenter(); // if any of the fields contain something, do not save to cache if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) { $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize'); } } $can_cache_page = (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) ? false : true; /** * Defines if the page can be cached or not * * @param boolean $can_cache_page */ $can_cache_page = apply_filters('wpo_can_cache_page', $can_cache_page); if (!$can_cache_page) { $no_cache_because[] = __('DONOTCACHEPAGE constant or wpo_can_cache_page filter forbade it', 'wp-optimize'); } if (defined('REST_REQUEST') && REST_REQUEST) { $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize'); } if (empty($no_cache_because)) { $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)"; break; } } } } } if (!empty($no_cache_because)) { $message = implode(', ', $no_cache_because); // Add http headers wpo_cache_add_nocache_http_header($message); // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) { $buffer .= "\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached because: ".htmlspecialchars($message)." -->\n"; } return $buffer; } else { // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } $modified_time = time(); // Take this as soon before writing as possible $add_to_footer = ''; /** * Filter wether to display the html comment <!-- Cached by WP-Optimize ... --> * * @param boolean $show - Wether to display the html comment * @return boolean */ if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } // Create an empty index.php file in the cache directory for disable directory viewing. if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', ''); /** * Save $buffer into cache file. */ $cache_filename = wpo_cache_filename(); $cache_file = $path . '/' .$cache_filename; // if we can then cache gzipped content in .gz file. if (function_exists('gzencode')) { // Only replace inside the addition, not inside the main buffer (e.g. post content) file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6))); } file_put_contents($cache_file, $buffer.$add_to_footer); // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header('WPO-Cache-Status: saving to cache'); if (wpo_cache_can_output_gzip_content()) { if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) { header('Content-Encoding: gzip'); } // disable php gzip to avoid double compression. ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set return ob_gzhandler($buffer, $flags); } else { return $buffer; } } } endif; /** * Load files for support plugins. */ if (!function_exists('wpo_cache_load_extensions')) : function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); // Add external extensions if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) { $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php')); } if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } endif; if (!function_exists('wpo_restricted_cache_page_type')) { function wpo_restricted_cache_page_type($restricted) { global $post; // Don't cache search or password protected. if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) { $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize'); } // Don't cache the front page if option is set. if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) { $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize'); } // Don't cache htacesss. Remember to properly escape any output to prevent injection. if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')'; } return $restricted; } } /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ if (!function_exists('wpo_cache_filename')) : function wpo_cache_filename($ext = '.html') { $filename = 'index'; if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. * This section was inspired by things learned from WP-Rocket. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } // add hash of queried cookies and variables to cache file name. if ('' !== $cache_key) { $filename .= '-' . md5($cache_key); } return $filename . $ext; } endif; /** * Returns site url from site_url() function or if it is not available from cache configuration. */ if (!function_exists('wpo_site_url')) : function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } endif; /** * Get cookie names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_cookies')) : function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } endif; /** * Get GET variable names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_query_variables')) : function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return wpo_cache_maybe_ignore_query_variables($variables); } endif; /** * Get list of all received HTTP headers. * * @return array */ if (!function_exists('wpo_get_http_headers')) : function wpo_get_http_headers() { static $headers; if (!empty($headers)) return $headers; $headers = array(); // if is apache server then use get allheaders() function. if (function_exists('getallheaders')) { $headers = getallheaders(); } else { // https://www.php.net/manual/en/function.getallheaders.php foreach ($_SERVER as $key => $value) { $key = strtolower($key); if ('HTTP_' == substr($key, 0, 5)) { $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value; } elseif ('content_type' == $key) { $headers["Content-Type"] = $value; } elseif ('content_length' == $key) { $headers["Content-Length"] = $value; } } } return $headers; } endif; /** * Check if requested Accept-Encoding headers has gzip value. * * @return bool */ if (!function_exists('wpo_cache_gzip_accepted')) : function wpo_cache_gzip_accepted() { $headers = wpo_get_http_headers(); if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true; return false; } endif; /** * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value * and function ob_gzhandler is available. * * @return bool */ if (!function_exists('wpo_cache_can_output_gzip_content')) : function wpo_cache_can_output_gzip_content() { return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler'); } endif; /** * Check if header with certain name exists in already prepared headers and has value comparable with $header_value. * * @param string $header_name header name * @param string $header_value header value as regexp. * * @return bool */ if (!function_exists('wpo_cache_is_in_response_headers_list')) : function wpo_cache_is_in_response_headers_list($header_name, $header_value) { $headers_list = headers_list(); if (!empty($headers_list)) { $header_name = strtolower($header_name); foreach ($headers_list as $value) { $value = explode(':', $value); if (strtolower($value[0]) == $header_name) { if (preg_match('/'.$header_value.'/', $value[1])) { return true; } else { return false; } } } } return false; } endif; /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ if (!function_exists('wpo_cache_mobile_caching_enabled')) : function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } endif; /** * Serves the cache and exits */ if (!function_exists('wpo_serve_cache')) : function wpo_serve_cache() { $file_name = wpo_cache_filename(); $path = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/' . $file_name; $use_gzip = false; // if we can use gzip and gzipped file exist in cache we use it. // if headers already sent we don't use gzipped file content. if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) { $path .= '.gz'; $use_gzip = true; } $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } // disable zlib output compression to avoid double content compression. if ($use_gzip) { ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set } $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip'); header('Cache-Control: no-cache'); // Check back later if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } header('WPO-Cache-Status: cached'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } // send correct headers for xml and txt files $filename = basename(dirname($path)); if (preg_match('/\.xml$/i', $filename)) { header('Content-type: text/xml'); } if (preg_match('/\.txt$/i', $filename)) { header('Content-type: text/plain'); } header('WPO-Cache-Status: cached'); if (!empty($modified_time)) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); } readfile($path); exit; } } endif; /** * Clears the cache */ if (!function_exists('wpo_cache_flush')) : function wpo_cache_flush() { if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } endif; /** * Get URL path for caching * * @since 1.0 * @return string */ if (!function_exists('wpo_get_url_path')) : function wpo_get_url_path($url = '') { $url = '' == $url ? wpo_current_url() : $url; $url_parts = parse_url($url); if (!isset($url_parts['host'])) $url_parts['host'] = ''; if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].$url_parts['path']; } endif; /** * Get requested url. * * @return string */ if (!function_exists('wpo_current_url')) : function wpo_current_url() { // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot). // Otherwise this function would return a different URL at the begining and end of the cache process. static $url = ''; if ('' != $url) return $url; $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . $http_host.$_SERVER['REQUEST_URI'], '/'); return $url; } endif; /** * Return list of url exceptions. * * @return array */ if (!function_exists('wpo_get_url_exceptions')) : function wpo_get_url_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; // if called from file-based-page-cache.php when WP loading // and cache settings exists then use it otherwise get settings from database. if (isset($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = array(); } else { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); } } else { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_urls', $config)) { $exceptions = $config['cache_exception_urls']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } return $exceptions; } endif; /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ if (!function_exists('wpo_current_url_exception_match')) : function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } endif; /** * Check if url in exceptions list. * * @param string $url * * @return bool */ if (!function_exists('wpo_url_in_exceptions')) : function wpo_url_in_exceptions($url) { $exceptions = wpo_get_url_exceptions(); if (!empty($exceptions)) { foreach ($exceptions as $exception) { // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type() if ('/' == $exception) continue; if (wpo_url_exception_match($url, $exception)) { // Exception match. return true; } } } return false; } endif; /** * Check if url string match with exception. * * @param string $url - complete url string i.e. http(s):://domain/path * @param string $exception - complete url or absolute path, can consist (.*) wildcards * * @return bool */ if (!function_exists('wpo_url_exception_match')) : function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // used to test websites placed in subdirectories. $sub_dir = ''; // if exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = rtrim($url, '/') . '/'; $exception = rtrim($exception, '/'); // if we have no wildcat in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = str_replace('/', '\/', $exception); return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url); } endif; /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ if (!function_exists('wpo_is_mobile')) : function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } endif; /** * Check if current browser agent is not disabled in options. * * @return bool */ if (!function_exists('wpo_is_accepted_user_agent')) : function wpo_is_accepted_user_agent($user_agent) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } endif; /** * Delete function that deals with directories recursively * * @param string $src Path of the folder * @param boolean $recursive If $src is a folder, recursively delete the inner folders. If set to false, only the files will be deleted. * * @return bool */ if (!function_exists('wpo_delete_files')) : function wpo_delete_files($src, $recursive = true) { if (!file_exists($src) || '' == $src || '/' == $src) { return true; } if (is_file($src)) { return unlink($src); } $success = true; $has_dir = false; if ($recursive) { // N.B. If opendir() fails, then a false positive (i.e. true) will be returned if (false !== ($dir = opendir($src))) { $file = readdir($dir); while (false !== $file) { if ('.' == $file || '..' == $file) { $file = readdir($dir); continue; } if (is_dir($src . '/' . $file)) { if (!wpo_delete_files($src . '/' . $file)) { $success = false; } } else { if (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($dir); } closedir($dir); } } else { // Not recursive, so we only delete the files // scan directories recursively. $handle = opendir($src); if (false === $handle) return false; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { if (is_dir($src . '/' . $file)) { $has_dir = true; } elseif (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($handle); } } if ($success && !$has_dir) { // Success of this operation is not recorded; we only ultimately care about emptying, not removing entirely (empty folders in our context are harmless) rmdir($src); } // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); return $success; } endif; /** * Either store for later output, or output now. Only the most-recent call will be effective. * * @param String|Null $output - if not null, then the string to use when called by the shutdown action. */ if (!function_exists('wpo_cache_add_footer_output')) : function wpo_cache_add_footer_output($output = null) { static $buffered = null; if (function_exists('current_filter') && 'shutdown' == current_filter()) { // Only add the line if it was a page, not something else (e.g. REST response) if (function_exists('did_action') && did_action('wp_footer')) { echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".$buffered." -->\n"; } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG) { error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered); } } else { if (null == $buffered && function_exists('add_action')) add_action('shutdown', 'wpo_cache_add_footer_output', 11); $buffered = $output; } } endif; /** * Remove variable names that shouldn't influence cache. * * @param array $variables List of variable names. * * @return array */ if (!function_exists('wpo_cache_maybe_ignore_query_variables')) : function wpo_cache_maybe_ignore_query_variables($variables) { /** * Filters the current $_GET variables that will be used when caching or excluding from cache. * Currently: * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set) * - 'doing_wp_cron' (alternative cron) * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap) * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap) * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap) */ $exclude_variables = array( 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set 'doing_wp_cron', // alternative cron 'aiosp_sitemap_path', // All in one SEO sitemap 'aiosp_sitemap_page', 'xml_sitemap', // SEOPress sitemap 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged', 'sitemap', // YOAST SEO sitemap 'sitemap_n', ); $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables; if (empty($exclude_variables)) return $variables; foreach ($exclude_variables as $variable) { $exclude = array_search($variable, $variables); if (false !== $exclude) { array_splice($variables, $exclude, 1); } } return $variables; } endif; /** * Get cache config * * @param string $key - The config item * @param mixed $default - The default value * * @return mixed */ if (!function_exists('wpo_cache_config_get')) : function wpo_cache_config_get($key, $default = false) { $config = $GLOBALS['wpo_cache_config']; if (!$config) return false; if (isset($config[$key])) { return $config[$key]; } else { return $default; } } endif; if (!function_exists('wpo_disable_cache_directories_viewing')) : function wpo_disable_cache_directories_viewing() { global $is_apache, $is_IIS, $is_iis7; if (!is_dir(WPO_CACHE_FILES_DIR)) return; // Create .htaccess file for apache server. if ($is_apache) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // CS does not like heredoc // phpcs:disable $htaccess_content = <<<EOF # Disable directory browsing Options -Indexes # Disable access to any files <FilesMatch ".*"> Order allow,deny Deny from all </FilesMatch> EOF; // phpcs:enable if (!is_file($htaccess_filename)) @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create web.config file for IIS servers. if ($is_IIS || $is_iis7) { $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config'; $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n"; if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create empty index.php file for all servers. if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', '');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } endif; /** * Add the headers indicating why the page is not cached or served from cache * * @param string $message - The headers * * @return void */ if (!function_exists('wpo_cache_add_nocache_http_header')) : function wpo_cache_add_nocache_http_header($message = '') { static $buffered_message = null; if (function_exists('current_filter') && 'send_headers' === current_filter() && $buffered_message && !headers_sent()) { header('WPO-Cache-Status: not cached'); header('WPO-Cache-Message: '. trim(str_replace(array("\r", "\n", ':'), ' ', strip_tags($buffered_message)))); } else { if (!$buffered_message && function_exists('add_action')) add_action('send_headers', 'wpo_cache_add_nocache_http_header', 11); $buffered_message = $message; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-cache-preloader.php 000644 000000 000000 00000070050 13665416124 033703 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!class_exists('Updraft_Task_Manager_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php'); if (!class_exists('WP_Optimize_Load_Url_Task')) require_once(dirname(__FILE__) . '/class-wpo-load-url-task.php'); class WP_Optimize_Page_Cache_Preloader extends Updraft_Task_Manager_1_2 { private $task_type = 'load-url-task'; private $options; static protected $_instance = null; /** * WP_Optimize_Page_Cache_Preloader constructor. */ public function __construct() { parent::__construct(); $this->options = WP_Optimize()->get_options(); // setup loggers $this->set_loggers(WP_Optimize()->wpo_loggers()); add_filter('cron_schedules', array($this, 'cron_add_intervals')); add_action('wpo_page_cache_preload_continue', array($this, 'process_tasks_queue')); add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload')); add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20); } /** * Check if cache is active. * * @return bool */ public function is_cache_active() { return WP_Optimize()->get_page_cache()->is_enabled(); } /** * Schedule or delete automatic preload action on cache settings update. * * @param array $new_settings The new settings * @param array $previous_settings Settings before saving */ public function cache_settings_updated($new_settings, $previous_settings) { if (!$new_settings['enable_page_caching']) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); $this->delete_preload_continue_action(); return; } if (!empty($new_settings['enable_schedule_preload'])) { $last_schedule_type = $previous_settings['preload_schedule_type']; if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { // if already scheduled this schedule type if ($new_settings['preload_schedule_type'] == $last_schedule_type) { // If the schedule type is cache lifespan, check if the cache lifespan changed. if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) { // Else, if the settings cache lifespan settings haven't changed, returns if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) { return; } } else { return; } } // clear currently scheduled preload action. wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action. wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload'); } else { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } } /** * Clear active preload tasks, reschedule preload action. */ public function reschedule_preload() { // clear scheduled action. if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action if need. if ($this->is_scheduled_preload_enabled()) { $preload_schedule_type = $this->get_cache_config('preload_schedule_type'); wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload'); } } /** * Check if scheduled preload enabled. * * @return bool */ public function is_scheduled_preload_enabled() { $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload'); return !empty($enable_schedule_preload); } /** * Get a schedule interval * * @param string $schedule_key The schedule to check * @return integer */ private function get_schedule_interval($schedule_key) { $schedules = wp_get_schedules(); if (!isset($schedules[$schedule_key])) { $this->log('Could not get interval for event of type '.$schedule_key); return 0; } return isset($schedules[$schedule_key]['interval']) ? $schedules[$schedule_key]['interval'] : 0; } /** * Add intervals to cron schedules. * * @param array $schedules * * @return array */ public function cron_add_intervals($schedules) { $interval = $this->get_continue_preload_cron_interval(); $schedules['wpo_page_cache_preload_continue_interval'] = array( 'interval' => $interval, 'display' => round($interval / 60, 1).' minutes' ); $schedules['wpo_use_cache_lifespan'] = array( 'interval' => WPO_Cache_Config::instance()->get_option('page_cache_length'), 'display' => 'Same as cache lifespan: '.WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit') ); return $schedules; } /** * Get the interval to continuing a preload task * * @return integer */ private function get_continue_preload_cron_interval() { /** * Filters the interval between each preload attempt, in seconds. */ return (int) apply_filters('wpo_page_cache_preload_continue_interval', 600); } /** * Schedule action for continuously preload. */ public function schedule_preload_continue_action() { $continue_in = wp_next_scheduled('wpo_page_cache_preload_continue'); // Action is still scheduled if ($continue_in && $continue_in > 0) return; // Action is overdue, delete it and re schedule it if ($continue_in && $continue_in < 0) $this->delete_preload_continue_action(); wp_schedule_event(time() + $this->get_schedule_interval('wpo_page_cache_preload_continue_interval'), 'wpo_page_cache_preload_continue_interval', 'wpo_page_cache_preload_continue'); } /** * Delete scheduled action for continuously preload. */ public function delete_preload_continue_action() { wp_clear_scheduled_hook('wpo_page_cache_preload_continue'); } /** * Run cache preload. If task queue is empty it creates tasks for site urls. * * @param string $type - The preload type (schedule | manual) * @param array $response - Specific response for echo into output thread when browser connection closing. * @return array|void - Void when closing the browser connection */ public function run($type = 'scheduled', $response = null) { if (!$this->is_cache_active()) { return array( 'success' => false, 'error' => __('Page cache is disabled.', 'wp-optimize') ); } if (empty($response)) { $response = array('success' => true); } $this->delete_cancel_flag(); // trying to lock semaphore. $creating_tasks_semaphore = new Updraft_Semaphore_2_2('wpo_cache_preloader_creating_tasks'); $lock = $creating_tasks_semaphore->lock(); // if semaphore haven't locked then just return response. if (!$lock) { return array( 'success' => false, 'error' => __('Probably page cache preload is running already.', 'wp-optimize') ); } $is_wp_cli = defined('WP_CLI') && WP_CLI; // close browser connection and continue work. // don't close connection for WP-CLI if (false == $is_wp_cli) { WP_Optimize()->close_browser_connection(json_encode($response)); } // trying to change time limit. WP_Optimize()->change_time_limit(); $status = $this->get_status($this->task_type); if (0 == $status['all_tasks'] && $lock) { if (is_multisite()) { $sites = WP_Optimize()->get_sites(); foreach ($sites as $site) { switch_to_blog($site->blog_id); $this->create_tasks_for_preload_site_urls($type); restore_current_blog(); } } else { $this->create_tasks_for_preload_site_urls($type); } } if ($lock) $creating_tasks_semaphore->unlock(); $this->process_tasks_queue(); // return $response in WP-CLI mode if ($is_wp_cli) { return $response; } } /** * Check if we need run cache preload and run it. */ public function run_scheduled_cache_preload() { $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); if (!$schedule_type) return; // Don't run preload if cache lifespan option enabled and cache not expired yet. if ('wpo_use_cache_lifespan' == $schedule_type) { /** * Filters the allowed time difference between the cache exiry and the current time, in seconds. * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it. * * @param integer $allowed_time_difference The time difference, in seconds (default = 600) */ $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', 600); $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0); $time_since_last_preload = time() - $last_preload_time; $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference; // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return; } $this->run(); } /** * Process tasks queue. */ public function process_tasks_queue() { // schedule continue preload action. $this->schedule_preload_continue_action(); if (!$this->process_queue($this->task_type)) { return; } // delete scheduled continue preload action. $this->delete_preload_continue_action(); // update last cache preload time only if processing any tasks, else process was cancelled. if ($this->is_running()) { $this->options->update_option('wpo_last_page_cache_preload', time()); } $this->clean_up_old_tasks($this->task_type); } /** * Find out if the current queue should be interrupted * * @param boolean $interrupt * @return boolean */ public function maybe_interrupt_queue($interrupt) { if ($interrupt) return $interrupt; static $memory_threshold = null; if (null == $memory_threshold) { /** * Filters the minimum memory required before stopping a queue. Default: 10MB */ $memory_threshold = apply_filters('wpo_page_cache_preload_memory_threshold', 10485760); } return WP_Optimize()->get_free_memory() < $memory_threshold; } /** * Delete all preload tasks from queue. */ public function cancel_preload() { $this->set_cancel_flag(); $this->delete_tasks($this->task_type); $this->delete_preload_continue_action(); } /** * Set 'cancel' option to true. */ public function set_cancel_flag() { $this->options->update_option('last_page_cache_preload_cancel', true); } /** * Delete 'cancel' option. */ public function delete_cancel_flag() { $this->options->delete_option('last_page_cache_preload_cancel'); } /** * Check if the last preload is cancelled. * * @return bool */ public function is_cancelled() { return $this->options->get_option('last_page_cache_preload_cancel', false); } /** * Check if preloading queue is processing. * * @return bool */ public function is_busy() { return $this->is_semaphore_locked($this->task_type) || $this->is_semaphore_locked('wpo_cache_preloader_creating_tasks'); } /** * Get current status of preloading urls. * * @return array */ public function get_status_info() { $status = $this->get_status($this->task_type); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); if ($this->is_semaphore_locked('wpo_cache_preloader_creating_tasks') && !$this->is_cancelled()) { // we are still creating tasks. return array( 'done' => false, 'message' => __('Loading URLs...', 'wp-optimize'), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } elseif ($status['complete_tasks'] == $status['all_tasks']) { $gmt_offset = (int) (3600 * get_option('gmt_offset')); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload'); if ($last_preload_time) { $last_preload_time_str = date_i18n(get_option('time_format').', '.get_option('date_format'), $last_preload_time + $gmt_offset); return array( 'done' => true, 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } else { return array( 'done' => true, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } } else { $preload_resuming_time = wp_next_scheduled('wpo_page_cache_preload_continue'); $preload_resuming_in = $preload_resuming_time ? $preload_resuming_time - time() : 0; $preloaded_message = sprintf(_n('%1$s out of %2$s URL preloaded', '%1$s out of %2$s URLs preloaded', $status['all_tasks'], 'wp-optimize'), $status['complete_tasks'], $status['all_tasks']); if ('sitemap' == $this->options->get_option('wpo_last_page_cache_preload_type', '')) { $preloaded_message = __('Preloading posts found in sitemap:', 'wp-optimize') .' '. $preloaded_message; } $return = array( 'done' => false, 'message' => $preloaded_message, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], 'resume_in' => $preload_resuming_in ); if (defined('DOING_AJAX') && DOING_AJAX) { // if no cron was found or cron is overdue more than 20s, trigger it if (!$preload_resuming_time || $preload_resuming_in < -20) { $this->run($return); } } return $return; } } /** * Check if preload action in process. * * @return bool */ public function is_running() { $status = $this->get_status($this->task_type); if ($status['all_tasks'] > 0) return true; } /** * Get cache config option value. * * @return mixed */ public function get_cache_config($option) { static $config = null; if (null === $config) $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists($option, $config)) { return $config[$option]; } return false; } /** * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site. * * @param string $type The preload type (currently: scheduled, manual) * @return void */ public function create_tasks_for_preload_site_urls($type) { $urls = $this->get_site_urls(); if (!empty($urls)) { $this->log(__('Creating tasks for preload site urls.', 'wp-optimize')); foreach ($urls as $url) { if (wpo_url_in_exceptions($url)) continue; if ($this->url_is_already_cached($url, $type)) { continue; } // this description is being used for internal purposes. $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->log(__('Tasks for preload site urls created.', 'wp-optimize')); } } /** * Preload desktop version from url. * * @param string $url * * @return void */ public function preload_desktop($url) { $desktop_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, ); $desktop_args = apply_filters('wpo_page_cache_preloader_desktop_args', $desktop_args, $url); $this->log('preload_desktop - '. $url); wp_remote_get($url, $desktop_args); } /** * Preload mobile version from $url. * * @param string $url * * @return void */ public function preload_mobile($url) { static $is_mobile_caching_enabled; if (!isset($is_mobile_caching_enabled)) { $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching'); } // Only run if option is active if (!$is_mobile_caching_enabled) return; $mobile_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', 'timeout' => 10, ); $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url); $this->log('preload_mobile - ' . $url); wp_remote_get($url, $mobile_args); } /** * Preload amp version from $url. * * @param string $url * * @return void */ public function preload_amp($url) { if (!apply_filters('wpo_should_preload_amp', false, $url)) return; $amp_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, ); $url = untrailingslashit($url) . '/amp/'; $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url); $this->log('preload_amp - ' . $url); wp_remote_get($url, $amp_args); } /** * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls. * * @return array */ public function get_site_urls() { if ($this->exists_sitemap_file() && (false !== ($urls = $this->get_sitemap_urls()))) { $this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap'); } else { $urls = $this->get_post_urls(); $this->options->update_option('wpo_last_page_cache_preload_type', 'posts'); } $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls))); return $urls; } /** * Check if sitemap file is exists. * * @return bool */ public function exists_sitemap_file() { $response = wp_remote_get(site_url('/'.$this->get_sitemap_filename()), array('timeout' => 10)); if (is_wp_error($response) || '200' != wp_remote_retrieve_response_code($response)) { $sitemap_file = $this->get_local_sitemap_file(); if (is_file($sitemap_file)) { return true; } else { return false; } } else { return true; } } /** * Loads sitemap file and returns list of urls. * * @param string $sitemap_url * * @return array|bool */ public function get_sitemap_urls($sitemap_url = '') { $urls = array(); // if sitemap url is empty then use main sitemap file name. $sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url; // if simplexml_load_string not available then we don't load sitemap. if (!function_exists('simplexml_load_string')) { return $urls; } // load sitemap file. $response = wp_remote_get($sitemap_url, array('timeout' => 30)); // if we get error then if (is_wp_error($response)) { $response = file_get_contents($sitemap_url); // if response is empty then try load from file. if (empty($response) && '' == $sitemap_url) { $sitemap_file = $this->get_local_sitemap_file(); $response = file_get_contents($sitemap_file); } if (empty($response)) return $urls; $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } else { // parse xml answer. $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // xml file has not valid xml content then return false. if (false === $xml) return false; // if exists urls then return them. if (isset($xml->url)) { foreach ($xml->url as $element) { if (!isset($element->loc)) continue; $urls[] = (string) $element->loc; } } elseif (isset($xml->sitemap)) { // if has links to other sitemap files then get urls from them. foreach ($xml->sitemap as $element) { if (!isset($element->loc)) continue; $sitemap_urls = $this->get_sitemap_urls($element->loc); if (is_array($sitemap_urls)) { $urls = array_merge($urls, $sitemap_urls); } } } return $urls; } /** * Get the path to a local sitemap file * * @return string */ private function get_local_sitemap_file() { if (!function_exists('get_home_path')) { include_once ABSPATH . '/wp-admin/includes/file.php'; } return trailingslashit(get_home_path()) . $this->get_sitemap_filename(); } /** * Get all posts of any post type and returns urls for them. * * @return array */ public function get_post_urls() { $offset = 0; $posts_per_page = 1000; $urls = array(); $urls[] = site_url('/'); do { $query = new WP_Query(array( 'post_type' => 'any', 'post_status' => 'publish', 'posts_per_page' => $posts_per_page, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'cache_results' => false, // disable cache to avoid memory error. )); $posts_loaded = $query->post_count; while ($query->have_posts()) { $query->the_post(); $urls[] = get_permalink(); } $offset += $posts_loaded; } while ($posts_loaded > 0); /** * If domain mapping enabled then replace domains in urls. */ if ($this->is_domain_mapping_enabled()) { $blog_id = get_current_blog_id(); $mapped_domain = $this->get_mapped_domain($blog_id); $blog_details = get_blog_details($blog_id); if ($mapped_domain) { foreach ($urls as $i => $url) { $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1); } } } wp_reset_postdata(); return $urls; } /** * Check if domain mapping enabled. * * @return bool */ public function is_domain_mapping_enabled() { // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin. $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE); /** * Filters if Multisite Domain mapping is enabled. * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use. * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option. */ return apply_filters('wpo_is_domain_mapping_enabled', $enabled); } /** * Return mapped domain by $blog_id. * * @param int $blog_id * * @return string */ public function get_mapped_domain($blog_id) { global $wpdb; $domain = ''; $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) { // This table created in WordPress MU Domain Mapping plugin. $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A); if (!empty($row)) { $domain = $row['domain']; } } else { // When using the WP Core method, the site url option contains the mapped domain. $domain = get_site_url($blog_id); } /** * Filters the mapped domain name * * @param string $domain The domain name * @param integer $blog_id The blog ID */ return apply_filters('wpo_get_mapped_domain', $domain, $blog_id); } /** * Captures and logs any interesting messages * * @param String $message - the error message * @param String $error_type - the error type */ public function log($message, $error_type = 'info') { if (isset($this->loggers)) { foreach ($this->loggers as $logger) { $logger->log($error_type, $message); } } } /** * Instance of WP_Optimize_Page_Cache_Preloader. * * @return WP_Optimize_Page_Cache_Preloader */ public static function instance() { if (empty(self::$_instance)) { self::$_instance = new WP_Optimize_Page_Cache_Preloader(); } return self::$_instance; } /** * Get sitemap filename. * * @return string */ private function get_sitemap_filename() { /** * Filter the sitemap file used to collect the URLs to preload * * @param string $filename - The sitemap name * @default sitemap.xml */ return apply_filters('wpo_cache_preload_sitemap_filename', 'sitemap.xml'); } /** * Check if semaphore is locked. * * @param string $semaphore * @return bool */ private function is_semaphore_locked($semaphore) { $semaphore = new Updraft_Semaphore_2_2($semaphore); return $semaphore->is_locked(); } /** * Check if the URL is already cached, or needs to be preloaded * * @param string $url The preloaded url * @param string $preload_type The preload type (manual | scheduled) * @return boolean */ private function url_is_already_cached($url, $preload_type) { static $files = array(); $regenerate_count = 0; $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url); // If the folder does not exist, consider the URL as cleared if (!is_dir($folder)) return false; if (empty($files)) { // Check only the base files $files[] = 'index.html'; if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) { $files[] = 'mobile.index.html'; } $files = apply_filters('wpo_maybe_clear_files_list', $files); } foreach ($files as $file) { $file_path = trailingslashit($folder).$file; if (!file_exists($file_path)) { // The file does not exist, count it as "deleted" $regenerate_count++; continue; } if ($this->should_regenerate_file($file_path, $preload_type)) { // delefe the expired cache file unlink($file_path); $regenerate_count++; } } // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted. return 0 == $regenerate_count; } /** * Determine if a file should be regenerated * * @param string $path The file to check * @param string $preload_type The preload type (manual | scheduled) * * @return boolean */ private function should_regenerate_file($path, $preload_type) { // Store the variables, as they'll be used for each file and each file static $is_preloader_scheduled = null; static $lifespan = null; static $schedule_type = null; static $schedule_interval = null; static $lifespan_expiry_threshold = null; static $always_regenerate_file_if_preload_is_manual = null; static $always_regenerate_file_if_preload_is_scheduled = null; static $regenerate_file_when_no_expiry_date = null; // Sets the variables once per request: if (null === $is_preloader_scheduled) { $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload'); $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length'); $schedule_interval = $this->get_schedule_interval($schedule_type); /** * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min) */ $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600); /** * Filters if a cache should systematically be regenerated when running a manual preload. Default: false */ $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false); /** * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false */ $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false); /** * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true */ $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true); } if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) { $result = true; } else { $modified_time = (int) filemtime($path); // cache lifespan is set. if (0 != $lifespan) { $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold; $result = time() > $expiry_time; } elseif ($is_preloader_scheduled) { $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold; $result = time() > $expiry_time; } else { $result = $regenerate_file_when_no_expiry_date; } } return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type); } } WP_Optimize_Page_Cache_Preloader::instance(); cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/class-wpo-load-url-task.php 000644 000000 000000 00000003024 13637401250 033332 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('Access denied.'); if (!class_exists('Updraft_Task_1_1')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); class WP_Optimize_Load_Url_Task extends Updraft_Task_1_1 { /** * Default options. */ public function get_default_options() { return array(); } /** * Run preload http requests with different user-agent values to cache pages for different devices. * * @return bool */ public function run() { $url = $this->get_option('url'); if (empty($url)) return; $cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); // load pages with different user-agents values. $cache_preloader->preload_desktop($url); $cache_preloader->preload_mobile($url); $cache_preloader->preload_amp($url); if (defined('WP_CLI') && WP_CLI) { WP_CLI::log($url); } /** * Action triggered after preloading a single url * * @param string $url The url to preload * @param object $cache_preloader Cache preloader instance */ do_action('wpoptimize_after_preload_url', $url, $cache_preloader); /** * Allows to change the delay between each URL preload, to reduce server load. * * @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second). */ usleep(apply_filters('wpoptimize_preload_delay', 500000)); return true; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.1/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000011556 13665416124 032733 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); /** * Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded. */ if (function_exists('do_action')) { do_action('wpo_cache_extensions_loaded'); } $no_cache_because = array(); // check if we want to cache current page. if (function_exists('add_filter') && function_exists('apply_filters')) { add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); $restricted_cache_page_type = apply_filters('wpo_restricted_cache_page_type', false); } else { // On old WP versions, you can't filter the result $restricted_cache_page_type = wpo_restricted_cache_page_type(false); } if ($restricted_cache_page_type) { $no_cache_because[] = $restricted_cache_page_type; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) { $no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')'; } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && !preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) { $no_cache_because[] = 'The request extension is not suitable for caching'; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || false == $GLOBALS['wpo_cache_config']['enable_user_caching']) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { $no_cache_because[] = 'WordPress login cookies were detected'; break(2); } } } } if (!empty($_COOKIE['wpo_commented_posts'])) { foreach ($_COOKIE['wpo_commented_posts'] as $path) { if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) { $no_cache_because[] = 'The user has commented on a post (comment cookie set)'; break; } } } // get cookie exceptions from options. $cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array(); // filter cookie exceptions, since WP 4.6 $cache_exception_cookies = function_exists('apply_filters') ? apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies) : $cache_exception_cookies; // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { $no_cache_because[] = 'An excepted cookie was set ('.$key.')'; break 2; } } } } } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) { $no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent"; } // Deal with optional cache exceptions. if (wpo_url_in_exceptions(wpo_current_url())) { $no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL'; } if (!empty($_GET)) { // get variables used for building filename. $get_variable_names = wpo_cache_query_variables(); $get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET)); // if GET variables include one or more undefined variable names then we don't cache. $diff = array_diff($get_variables, $get_variable_names); if (!empty($diff)) { $no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters"; } } if (!empty($no_cache_because)) { $message = implode(', ', $no_cache_because); // Add http header if (!defined('DOING_CRON') || !DOING_CRON) { wpo_cache_add_nocache_http_header($message); } // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON)) { wpo_cache_add_footer_output("Page not served from cache because: ".htmlspecialchars($message)); } return; } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/ 000755 000000 000000 00000000000 14214670220 025170 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/ 000755 000000 000000 00000000000 14214670220 026233 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-cache-preloader.php 000644 000000 000000 00000051717 14213733440 033706 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!class_exists('WP_Optimize_Load_Url_Task')) require_once(dirname(__FILE__) . '/class-wpo-load-url-task.php'); if (!class_exists('WP_Optimize_Preloader')) require_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-wpo-preloader.php'); class WP_Optimize_Page_Cache_Preloader extends WP_Optimize_Preloader { protected $preload_type = 'page_cache'; protected $task_type = 'load-url-task'; static protected $_instance = null; /** * WP_Optimize_Page_Cache_Preloader constructor. */ public function __construct() { parent::__construct(); add_filter('cron_schedules', array($this, 'cron_add_intervals')); add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload')); add_filter('wpo_preload_headers', array($this, 'preload_headers')); } /** * Check if cache is active. * * @return bool */ public function is_option_active() { return WP_Optimize()->get_page_cache()->is_enabled(); } /** * Schedule or delete automatic preload action on cache settings update. * * @param array $new_settings The new settings * @param array $previous_settings Settings before saving */ public function cache_settings_updated($new_settings, $previous_settings) { if (!$new_settings['enable_page_caching']) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); $this->delete_preload_continue_action(); return; } if (!empty($new_settings['enable_schedule_preload'])) { $last_schedule_type = $previous_settings['preload_schedule_type']; if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { // if already scheduled this schedule type if ($new_settings['preload_schedule_type'] == $last_schedule_type) { // If the schedule type is cache lifespan, check if the cache lifespan changed. if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) { // Else, if the settings cache lifespan settings haven't changed, returns if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) { return; } } else { return; } } // clear currently scheduled preload action. wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action. wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload'); } else { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } } /** * Clear active preload tasks, reschedule preload action. */ public function reschedule_preload() { // clear scheduled action. if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action if need. if ($this->is_scheduled_preload_enabled()) { $preload_schedule_type = $this->get_cache_config('preload_schedule_type'); wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload'); } } /** * Check if scheduled preload enabled. * * @return bool */ public function is_scheduled_preload_enabled() { $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload'); return !empty($enable_schedule_preload); } /** * Add intervals to cron schedules. * * @param array $schedules * * @return array */ public function cron_add_intervals($schedules) { $interval = $this->get_continue_preload_cron_interval(); $schedules['wpo_page_cache_preload_continue_interval'] = array( 'interval' => $interval, 'display' => round($interval / 60, 1).' minutes' ); $schedules['wpo_use_cache_lifespan'] = array( 'interval' => WPO_Cache_Config::instance()->get_option('page_cache_length'), 'display' => 'Same as cache lifespan: '.WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit') ); return $schedules; } /** * Check if we need run cache preload and run it. */ public function run_scheduled_cache_preload() { $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); if (!$schedule_type) return; // Don't run preload if cache lifespan option enabled and cache not expired yet. if ('wpo_use_cache_lifespan' == $schedule_type) { /** * Filters the allowed time difference between the cache exiry and the current time, in seconds. * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it. * * @param integer $allowed_time_difference The time difference, in seconds (default = 600) */ $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', 600); $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0); $time_since_last_preload = time() - $last_preload_time; $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference; // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return; } $this->run(); } /** * Get cache config option value. * * @return mixed */ public function get_cache_config($option) { static $config = null; if (null === $config) $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists($option, $config)) { return $config[$option]; } return false; } /** * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site. * * @param string $type The preload type (currently: scheduled, manual) * @return void */ public function create_tasks_for_preload_site_urls($type) { $urls = $this->get_site_urls(); if (!empty($urls)) { $this->log(__('Creating tasks for preload site urls.', 'wp-optimize')); foreach ($urls as $url) { if (wpo_url_in_exceptions($url)) continue; if ($this->url_is_already_cached($url, $type)) { continue; } // this description is being used for internal purposes. $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->log(__('Tasks for preload site urls created.', 'wp-optimize')); } } /** * Preload mobile version from $url. * * @param string $url * * @return void */ public function preload_mobile($url) { static $is_mobile_caching_enabled; if (!isset($is_mobile_caching_enabled)) { $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching'); } // Only run if option is active if (!$is_mobile_caching_enabled) return; $mobile_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', 'timeout' => 10, 'headers' => apply_filters('wpo_preload_headers', array()), ); $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url); $this->log('preload_mobile - ' . $url); wp_remote_get($url, $mobile_args); } /** * Preload amp version from $url. * * @param string $url * * @return void */ public function preload_amp($url) { if (!apply_filters('wpo_should_preload_amp', false, $url)) return; $amp_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, 'headers' => array( 'X-WP-Optimize-Cache-Preload' => 'Yes', ), ); $url = untrailingslashit($url) . '/amp/'; $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url); $this->log('preload_amp - ' . $url); wp_remote_get($url, $amp_args); } /** * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls. * * @return array */ public function get_site_urls() { $urls = $this->get_sitemap_urls(); if (!empty($urls)) { $this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap'); } else { $urls = $this->get_post_urls(); $this->options->update_option('wpo_last_page_cache_preload_type', 'posts'); } $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls))); /** * Filter the URLs which will be preloaded * * @param array $urls * @return array */ return apply_filters('wpo_preload_get_site_urls', $urls); } /** * Loads sitemap file and returns list of urls. * * @param string $sitemap_url * * @return array|bool */ public function get_sitemap_urls($sitemap_url = '') { $urls = array(); // if sitemap url is empty then use main sitemap file name. $sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url; // if simplexml_load_string not available then we don't load sitemap. if (!function_exists('simplexml_load_string')) { return $urls; } // load sitemap file. $response = wp_remote_get($sitemap_url, array('timeout' => 30)); // if we get error then if (is_wp_error($response)) { $response = file_get_contents($sitemap_url); // if response is empty then try load from file. if (empty($response) && '' == $sitemap_url) { $sitemap_file = $this->get_local_sitemap_file(); $response = file_get_contents($sitemap_file); } if (empty($response)) return $urls; $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } else { // parse xml answer. $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // xml file has not valid xml content then return false. if (false === $xml) return false; // if exists urls then return them. if (isset($xml->url)) { foreach ($xml->url as $element) { if (!isset($element->loc)) continue; $urls[] = (string) $element->loc; } } elseif (isset($xml->sitemap)) { // if has links to other sitemap files then get urls from them. foreach ($xml->sitemap as $element) { if (!isset($element->loc)) continue; $sitemap_urls = $this->get_sitemap_urls($element->loc); if (is_array($sitemap_urls)) { $urls = array_merge($urls, $sitemap_urls); } } } return $urls; } /** * Get the path to a local sitemap file * * @return string */ private function get_local_sitemap_file() { if (!function_exists('get_home_path')) { include_once ABSPATH . '/wp-admin/includes/file.php'; } return trailingslashit(get_home_path()) . $this->get_sitemap_filename(); } /** * Get all posts of any post type and returns urls for them. * * @return array */ public function get_post_urls() { global $post; $offset = 0; $posts_per_page = 1000; $urls = array(); $urls[] = site_url('/'); do { $query = new WP_Query(array( 'post_type' => 'any', 'post_status' => 'publish', 'posts_per_page' => $posts_per_page, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'cache_results' => false, // disable cache to avoid memory error. )); $posts_loaded = $query->post_count; while ($query->have_posts()) { $query->the_post(); $permalink = get_permalink(); $urls[] = $permalink; // check page separators in the post content preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches); // if there any separators add urls for each page if (count($matches[0])) { $prefix = strpos($permalink, '?') ? '&page=' : ''; for ($page = 0; $page < count($matches[0]); $page++) { if ('' != $prefix) { $urls[] = $permalink . $prefix . ($page+2); } else { $urls[] = trailingslashit($permalink) . ($page+2); } } } } $offset += $posts_loaded; } while ($posts_loaded > 0); /** * If domain mapping enabled then replace domains in urls. */ if ($this->is_domain_mapping_enabled()) { $blog_id = get_current_blog_id(); $mapped_domain = $this->get_mapped_domain($blog_id); $blog_details = get_blog_details($blog_id); if ($mapped_domain) { foreach ($urls as $i => $url) { $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1); } } } wp_reset_postdata(); return $urls; } /** * Check if domain mapping enabled. * * @return bool */ public function is_domain_mapping_enabled() { // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin. $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE); /** * Filters if Multisite Domain mapping is enabled. * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use. * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option. */ return apply_filters('wpo_is_domain_mapping_enabled', $enabled); } /** * Return mapped domain by $blog_id. * * @param int $blog_id * * @return string */ public function get_mapped_domain($blog_id) { global $wpdb; $domain = ''; $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) { // This table created in WordPress MU Domain Mapping plugin. $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A); if (!empty($row)) { $domain = $row['domain']; } } else { // When using the WP Core method, the site url option contains the mapped domain. $domain = get_site_url($blog_id); } /** * Filters the mapped domain name * * @param string $domain The domain name * @param integer $blog_id The blog ID */ return apply_filters('wpo_get_mapped_domain', $domain, $blog_id); } /** * Captures and logs any interesting messages * * @param String $message - the error message * @param String $error_type - the error type */ public function log($message, $error_type = 'info') { if (isset($this->loggers)) { foreach ($this->loggers as $logger) { $logger->log($message, $error_type); } } } /** * Instance of WP_Optimize_Page_Cache_Preloader. * * @return WP_Optimize_Page_Cache_Preloader */ public static function instance() { if (empty(self::$_instance)) { self::$_instance = new WP_Optimize_Page_Cache_Preloader(); } return self::$_instance; } /** * Check if the URL is already cached, or needs to be preloaded * * @param string $url The preloaded url * @param string $preload_type The preload type (manual | scheduled) * @return boolean */ private function url_is_already_cached($url, $preload_type) { static $files = array(); $regenerate_count = 0; $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url); // If the folder does not exist, consider the URL as cleared if (!is_dir($folder)) return false; if (empty($files)) { // Check only the base files $files[] = 'index.html'; if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) { $files[] = 'mobile.index.html'; } $files = apply_filters('wpo_maybe_clear_files_list', $files); } foreach ($files as $file) { $file_path = trailingslashit($folder).$file; if (!file_exists($file_path)) { // The file does not exist, count it as "deleted" $regenerate_count++; continue; } if ($this->should_regenerate_file($file_path, $preload_type)) { // delefe the expired cache file unlink($file_path); $regenerate_count++; } } // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted. return 0 == $regenerate_count; } /** * Determine if a file should be regenerated * * @param string $path The file to check * @param string $preload_type The preload type (manual | scheduled) * * @return boolean */ private function should_regenerate_file($path, $preload_type) { // Store the variables, as they'll be used for each file and each file static $is_preloader_scheduled = null; static $lifespan = null; static $schedule_type = null; static $schedule_interval = null; static $lifespan_expiry_threshold = null; static $always_regenerate_file_if_preload_is_manual = null; static $always_regenerate_file_if_preload_is_scheduled = null; static $regenerate_file_when_no_expiry_date = null; // Sets the variables once per request: if (null === $is_preloader_scheduled) { $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload'); $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length'); $schedule_interval = $this->get_schedule_interval($schedule_type); /** * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min) */ $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600); /** * Filters if a cache should systematically be regenerated when running a manual preload. Default: false */ $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false); /** * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false */ $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false); /** * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true */ $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true); } if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) { $result = true; } else { $modified_time = (int) filemtime($path); // cache lifespan is set. if (0 != $lifespan) { $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold; $result = time() > $expiry_time; } elseif ($is_preloader_scheduled) { $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold; $result = time() > $expiry_time; } else { $result = $regenerate_file_when_no_expiry_date; } } return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type); } /** * Add preloader headers */ public function preload_headers($headers) { $headers['X-WP-Optimize-Cache-Preload'] = 'Yes'; return $headers; } /** * Option disabled error message * * @return array */ protected function get_option_disabled_error() { return array( 'success' => false, 'error' => __('Page cache is disabled.', 'wp-optimize') ); } /** * Get preload already running error message * * @return array */ protected function get_preload_already_running_error() { return array( 'success' => false, 'error' => __('Probably page cache preload is running already.', 'wp-optimize') ); } protected function get_preload_data() { return WP_Optimize()->get_page_cache()->get_cache_size(); } protected function get_preloading_message($cache_size) { return array( 'done' => false, 'message' => __('Loading URLs...', 'wp-optimize'), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_last_preload_message($cache_size, $last_preload_time_str) { return array( 'done' => true, 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_preload_success_message($cache_size) { return array( 'done' => true, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_preload_progress_message($cache_size, $preloaded_message, $preload_resuming_in) { return array( 'done' => false, 'message' => $preloaded_message, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], 'resume_in' => $preload_resuming_in ); } } WP_Optimize_Page_Cache_Preloader::instance(); cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-cache-commands.php 000644 000000 000000 00000023037 14173760430 032725 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); // filter for validate cache settings before save it. $validation = apply_filters('wpo_save_cache_settings_validation', $data['cache-settings']); if (!empty($validation) && isset($validation['result']) && false === $validation['result']) { return $validation; } $enabled = false; $disabled = false; $return = !empty($validation) ? $validation : array(); $previous_settings = WPO_Cache_Config::instance()->get(); // Attempt to change current status if required if (isset($previous_settings['enable_page_caching']) && $previous_settings['enable_page_caching'] != $data['cache-settings']['enable_page_caching']) { // Disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { $disabled = WPO_Page_Cache::instance()->disable(); // Disabling failed if ($disabled && is_wp_error($disabled)) { // If disabling failed, we re-enable whatever was disabled, to make sure nothing breaks. if ($previous_settings['enable_page_caching']) WPO_Page_Cache::instance()->enable(true); $return['error'] = array( 'code' => $disabled->get_error_code(), 'message' => $disabled->get_error_message() ); } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was disabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. $enabled = WPO_Page_Cache::instance()->enable(true); // Enabling failed if (is_wp_error($enabled)) { // disable everything, to avoid half enabled things WPO_Page_Cache::instance()->disable(); $return['error'] = array( 'code' => $enabled->get_error_code(), 'message' => $enabled->get_error_message() ); if (WPO_Page_Cache::instance()->advanced_cache_file_writing_error) { $return['advanced_cache_file_writing_error'] = true; $return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content; } } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was enabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } // Override enabled setting value $data['cache-settings']['enable_page_caching'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); } else { $data['cache-settings']['enable_page_caching'] = $previous_settings['enable_page_caching']; $enabled = $previous_settings['enable_page_caching']; } $skip_if_no_file_yet = !$enabled || is_wp_error($enabled); $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet); if ($save_settings_result && !is_wp_error($save_settings_result)) { WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings); $return['result'] = $save_settings_result; } else { // Saving the settings returned an error if (is_wp_error($save_settings_result)) { if (isset($return['error'])) { $return['error']['message'] .= "\n\n".$save_settings_result->get_error_message(); } else { $return['error'] = array( 'code' => $save_settings_result->get_error_code(), 'message' => $save_settings_result->get_error_message() ); } } $return['result'] = false; } $return['enabled'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); return $return; } /** * Get information about current cache status. Used in cli commands. * * @return array */ public function get_status_info() { $status = array(); $status[] = WPO_Page_Cache::instance()->is_enabled() ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize'); $preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); $status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']); $status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']); if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message']; $status['message'] = join(PHP_EOL, $status); return $status; } /** * Enable cache. */ public function enable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = true; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Disable cache. */ public function disable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = false; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Purge WP-Optimize page cache. * * @return array */ public function purge_page_cache() { if (!WP_Optimize()->can_purge_the_cache()) { return array( 'success' => false, 'message' => __('You do not have permission to purge the cache', 'wp-optimize'), ); } $purged = WP_Optimize()->get_page_cache()->purge(); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); $response = array( 'success' => $purged, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], ); // if scheduled preload enabled then reschedule and run preloader. if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) { // cancel preload and reschedule preload action. $wpo_page_cache_preloader->cancel_preload(); $wpo_page_cache_preloader->reschedule_preload(); // run preloader. $wpo_page_cache_preloader->run('scheduled', $response); } if ($response['success']) { $response['message'] = __('Page cache purged successfully', 'wp-optimize'); } return $response; } /** * Run cache preload (for wp-cli). * * @return array|bool */ public function run_cache_preload_cli() { if (!(defined('WP_CLI') && WP_CLI)) return false; // define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file // but we check this constant value wen detecting status of cache if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); // don't interrupt queue processing add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99); // if preloading is running then exit. if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) { return array( 'success' => false, 'error' => __('Preloading is currently running in another process.', 'wp-optimize'), ); } // set default response. $response = array( 'success' => true, 'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'), ); WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize')); return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response); } /** * Run cache preload action. * * @return void|array - Doesn't return anything if run() is successfull (Run() prints a JSON object and closed browser connection) or an array if failed. */ public function run_cache_preload() { return WP_Optimize_Page_Cache_Preloader::instance()->run('manual'); } /** * Cancel cache preload action. * * @return array */ public function cancel_cache_preload() { WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload(); return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Get status of cache preload. * * @return array */ public function get_cache_preload_status() { return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } /** * Format save_cache_settings() result for displaying in WP-CLI console * * @param array $response * @return array */ private function format_save_cache_settings_response($response) { $result = array( 'success' => $response['result'], ); if (isset($response['error'])) { $result['success'] = false; $result['error'] = $response['error']['message']; } if ($result['success']) { $result['message'] = __('Page cache settings updated successfully.', 'wp-optimize'); } return $result; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000011314 14057473210 032717 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); /** * Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded. */ if (function_exists('do_action')) { do_action('wpo_cache_extensions_loaded'); } $no_cache_because = array(); // check if we want to cache current page. if (function_exists('add_filter') && function_exists('apply_filters')) { add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); $restricted_cache_page_type = apply_filters('wpo_restricted_cache_page_type', false); } else { // On old WP versions, you can't filter the result $restricted_cache_page_type = wpo_restricted_cache_page_type(false); } if ($restricted_cache_page_type) { $no_cache_because[] = $restricted_cache_page_type; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) { $no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')'; } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && !preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) { $no_cache_because[] = 'The request extension is not suitable for caching'; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (!wpo_cache_loggedin_users()) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { $no_cache_because[] = 'WordPress login cookies were detected'; break(2); } } } } if (!empty($_COOKIE['wpo_commented_post'])) { $no_cache_because[] = 'The user has commented on a post (comment cookie set)'; } // get cookie exceptions from options. $cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array(); // filter cookie exceptions, since WP 4.6 $cache_exception_cookies = function_exists('apply_filters') ? apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies) : $cache_exception_cookies; // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { $no_cache_because[] = 'An excepted cookie was set ('.$key.')'; break 2; } } } } } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) { $no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent"; } // Deal with optional cache exceptions. if (wpo_url_in_exceptions(wpo_current_url())) { $no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL'; } if (!empty($_GET)) { // get variables used for building filename. $get_variable_names = wpo_cache_query_variables(); $get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET)); // if GET variables include one or more undefined variable names then we don't cache. $get_variables_diff = array_diff($get_variables, $get_variable_names); if (!empty($get_variables_diff)) { $no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters"; } } if (!empty($no_cache_because)) { $no_cache_because_message = implode(', ', $no_cache_because); // Add http header if (!defined('DOING_CRON') || !DOING_CRON) { wpo_cache_add_nocache_http_header($no_cache_because_message); } // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON)) { wpo_cache_add_footer_output("Page not served from cache because: ".htmlspecialchars($no_cache_because_message)); } return; } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000016267 13730076454 033207 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return isset($options[$option_key]) ? $options[$option_key] : $default; } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved. * * @return bool */ public function update($config, $skip_disk_if_not_yet_present = false) { $config = wp_parse_args($config, $this->get_defaults()); $config['page_cache_length_value'] = intval($config['page_cache_length_value']); $config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']); /** * Filters the cookies used to set cache file names * * @param array $cookies - The cookies * @param array $config - The new config */ $wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config); sort($wpo_cache_cookies); /** * Filters the query variables used to set cache file names * * @param array $wpo_query_variables - The variables * @param array $config - The new config */ $wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; $config = apply_filters('wpo_cache_update_config', $config); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } do_action('wpo_cache_config_updated', $config); return $this->write($config, $skip_disk_if_not_yet_present); } /** * Calculate cache expiration value in seconds. * * @param int $value * @param string $unit ( hours | days | months ) * * @return int */ private function calculate_page_cache_length($value, $unit) { $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); return $value * $cache_length_units[$unit]; } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config - Configuration array. * @param boolean $only_if_present - only writes to the disk if the configuration file already exists * * @return boolean - returns false if an attempt to write failed */ private function write($config, $only_if_present = false) { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'-port'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); // from 3.0.17 we use more secure way to store cache config files. $advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version(); // if advanced-cache.php exists and has at least 3.0.17 version or // advanced-cache.php doesn't exist then // we write the cache config in a new format. if (($advanced_cache_version && (version_compare($advanced_cache_version, '3.0.17', '>='))) || !$advanced_cache_version) { $config_content = '<?php' . "\n" . 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n" . '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . json_encode($this->config) . '\', true);' . "\n"; } else { $config_content = json_encode($this->config); } if ((!$only_if_present || file_exists($config_file)) && !file_put_contents($config_file, $config_content)) { return new WP_Error('write_cache_config', sprintf(__('The cache configuration file could not be saved to the disk; please check the file/folder permissions of %s .', 'wp-optimize'), $config_file)); } return true; } /** * Verify we can write to the file system * * @since 1.0 * @return boolean */ public function verify_file_access() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) { return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) { return false; } // If the cache and config directories exist, make sure they're writeable if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) { if (file_exists(WPO_CACHE_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_DIR)) { return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) { return false; } } } return true; } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => false, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => network_site_url('/'), 'enable_cache_per_country' => false, ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-detect-cache-plugins.php 000644 000000 000000 00000004420 13665647440 034604 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ protected function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $active_cache_plugins = array(); foreach ($this->get_plugins() as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Get the plugins list * * @return array */ protected function get_plugins() { return array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { static $instance; if (empty($instance)) { $instance = new self(); } return $instance; } } wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/file-based-page-cache-functions.php000644 000000 000000 00000110221 14173760430 034645 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above. * * @param String $buffer Page HTML. * @param Int $flags OB flags to be passed through. * * @return String */ if (!function_exists('wpo_cache')) : function wpo_cache($buffer, $flags) { // This case appears to happen for unclear reasons without WP being fully loaded, e.g. https://wordpress.org/support/topic/fatal-error-since-wp-5-8-update/ . It is simplest just to short-circuit it. if ('' === $buffer) return ''; // This array records reasons why no cacheing took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately. $no_cache_because = array(); if (strlen($buffer) < 255) { $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth caching', 'wp-optimize'), 255); } // Don't cache pages for logged in users. if (empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && (!function_exists('wpo_we_cache_per_role') || !wpo_we_cache_per_role()) && (!function_exists('is_user_logged_in') || (function_exists('wp_get_current_user') && is_user_logged_in()))) { $no_cache_because[] = __('User is logged in', 'wp-optimize'); } $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_page_type_cache) { $no_cache_because[] = $restricted_page_type_cache; } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) { $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')'; } elseif (!file_exists(WPO_CACHE_FILES_DIR)) { // Try creating a folder for cached files, if it was flushed recently if (!mkdir(WPO_CACHE_FILES_DIR)) { $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')'; } else { wpo_disable_cache_directories_viewing(); } } // If comments are opened and the user has saved his information. if (function_exists('comments_open') && function_exists('get_post') && get_post() && comments_open()) { $commenter = wp_get_current_commenter(); // if any of the fields contain something, do not save to cache if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) { $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize'); } } $can_cache_page = true; if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { $can_cache_page = false; } /** * Defines if the page can be cached or not * * @param boolean $can_cache_page */ $can_cache_page_filter = apply_filters('wpo_can_cache_page', $can_cache_page); if (!$can_cache_page_filter) { if ($can_cache_page) { $can_cache_page = false; $no_cache_because[] = __('wpo_can_cache_page filter forbade it', 'wp-optimize'); } else { $no_cache_because[] = __('DONOTCACHEPAGE constant forbade it and wpo_can_cache_page filter did not over-ride it', 'wp-optimize'); } } if (defined('REST_REQUEST') && REST_REQUEST) { $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize'); } // Don't cache with fatal error pages. $last_error = error_get_last(); if (is_array($last_error) && E_ERROR == $last_error['type']) { $no_cache_because[] = __('This page has a fatal error', 'wp-optimize'); } if (http_response_code() >= 500) { $no_cache_because[] = sprintf(__('This page has a critical error (HTTP code %s)', 'wp-optimize'), http_response_code()); } elseif (http_response_code() >= 400) { $no_cache_because[] = sprintf(__('This page returned an HTTP unauthorised response code (%s)', 'wp-optimize'), http_response_code()); } if (empty($no_cache_because)) { $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)"; break; } } } } } if (!empty($no_cache_because)) { $message = implode(', ', $no_cache_because); // Add http headers wpo_cache_add_nocache_http_header($message); // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) { $buffer .= "\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached because: ".htmlspecialchars($message)." -->\n"; } return $buffer; } else { // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } $modified_time = time(); // Take this as soon before writing as possible $add_to_footer = ''; /** * Filter wether to display the html comment <!-- Cached by WP-Optimize ... --> * * @param boolean $show - Wether to display the html comment * @return boolean */ if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } // Create an empty index.php file in the cache directory for disable directory viewing. if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', ''); /** * Save $buffer into cache file. */ $file_ext = '.html'; if (wpo_feeds_caching_enabled()) { if (is_feed()) { $file_ext = '.rss-xml'; } } $cache_filename = wpo_cache_filename($file_ext); $cache_file = $path . '/' .$cache_filename; if (defined('WPO_CACHE_FILENAME_DEBUG') && WPO_CACHE_FILENAME_DEBUG) { $add_to_footer .= "\n<!-- WP Optimize page cache debug information -->\n"; if (!empty($GLOBALS['wpo_cache_filename_debug']) && is_array($GLOBALS['wpo_cache_filename_debug'])) { $add_to_footer .= "<!-- \n" . join("\n", array_map('htmlspecialchars', $GLOBALS['wpo_cache_filename_debug'])) . "\n --->"; } } // if we can then cache gzipped content in .gz file. if (function_exists('gzencode')) { // Only replace inside the addition, not inside the main buffer (e.g. post content) file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6))); } file_put_contents($cache_file, $buffer.$add_to_footer); if (is_callable('WP_Optimize')) { // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); } else { error_log('[WPO_CACHE] WP_Optimize() is not callable.'); $message = 'Please report this to WP-O support: '; if (function_exists('wp_debug_backtrace_summary')) { $message .= wp_debug_backtrace_summary(); } else { $message .= wpo_debug_backtrace_summary(); } error_log($message); } header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header('WPO-Cache-Status: saving to cache'); if (wpo_cache_can_output_gzip_content()) { if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) { header('Content-Encoding: gzip'); } // disable php gzip to avoid double compression. ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set return ob_gzhandler($buffer, $flags); } else { return $buffer; } } } endif; /** * Load files for support plugins. */ if (!function_exists('wpo_cache_load_extensions')) : function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); // Add external extensions if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) { $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php')); } if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } endif; if (!function_exists('wpo_restricted_cache_page_type')) { function wpo_restricted_cache_page_type($restricted) { global $post; // Don't cache search or password protected. if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) { $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize'); } // Don't cache the front page if option is set. if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) { $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize'); } // Don't cache htacesss. Remember to properly escape any output to prevent injection. if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')'; } // Don't cache feeds. if (function_exists('is_feed') && is_feed() && !wpo_feeds_caching_enabled()) { $restricted = __('We don\'t cache RSS feeds', 'wp-optimize'); } return $restricted; } } /** * Returns true if we need cache content for loggedin users. * * @return bool */ if (!function_exists('wpo_cache_loggedin_users')) : function wpo_cache_loggedin_users() { return !empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) || (function_exists('wpo_we_cache_per_role') && wpo_we_cache_per_role()); } endif; /** * Returns true if we need to cache content for loggedin users. * * @return bool */ if (!function_exists('wpo_user_specific_cache_enabled')) : function wpo_user_specific_cache_enabled() { return !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_auth']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_logged_in']); } endif; /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ if (!function_exists('wpo_cache_filename')) : function wpo_cache_filename($ext = '.html') { $wpo_cache_filename_debug = array(); $filename = 'index'; if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. * This section was inspired by things learned from WP-Rocket. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $key . '[' . $cookie_key . '], value: *** , cache_key:' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $cookie_name . ', value: *** , cache_key:' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'GET parameter: name: ' . $variable . ', value:' . htmlentities($_GET[$variable]) . ', cache_key:' . $_cache_key; } } } // add hash of queried cookies and variables to cache file name. if ('' !== $cache_key) { $hash = md5($cache_key); $filename .= '-'.$hash; $wpo_cache_filename_debug[] = 'Hash: ' . $hash; } $filename = apply_filters('wpo_cache_filename', $filename); $wpo_cache_filename_debug[] = 'Extension: ' . $ext; $wpo_cache_filename_debug[] = 'Filename: ' . $filename.$ext; $GLOBALS['wpo_cache_filename_debug'] = $wpo_cache_filename_debug; return $filename . $ext; } endif; /** * Returns site url from site_url() function or if it is not available from cache configuration. */ if (!function_exists('wpo_site_url')) : function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } endif; /** * Get cookie names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_cookies')) : function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } endif; /** * Get GET variable names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_query_variables')) : function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return wpo_cache_maybe_ignore_query_variables($variables); } endif; /** * Get list of all received HTTP headers. * * @return array */ if (!function_exists('wpo_get_http_headers')) : function wpo_get_http_headers() { static $headers; if (!empty($headers)) return $headers; $headers = array(); // if is apache server then use get allheaders() function. if (function_exists('getallheaders')) { $headers = getallheaders(); } else { // https://www.php.net/manual/en/function.getallheaders.php foreach ($_SERVER as $key => $value) { $key = strtolower($key); if ('HTTP_' == substr($key, 0, 5)) { $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value; } elseif ('content_type' == $key) { $headers["Content-Type"] = $value; } elseif ('content_length' == $key) { $headers["Content-Length"] = $value; } } } return $headers; } endif; /** * Check if requested Accept-Encoding headers has gzip value. * * @return bool */ if (!function_exists('wpo_cache_gzip_accepted')) : function wpo_cache_gzip_accepted() { $headers = wpo_get_http_headers(); if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true; return false; } endif; /** * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value * and function ob_gzhandler is available. * * @return bool */ if (!function_exists('wpo_cache_can_output_gzip_content')) : function wpo_cache_can_output_gzip_content() { return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler'); } endif; /** * Check if header with certain name exists in already prepared headers and has value comparable with $header_value. * * @param string $header_name header name * @param string $header_value header value as regexp. * * @return bool */ if (!function_exists('wpo_cache_is_in_response_headers_list')) : function wpo_cache_is_in_response_headers_list($header_name, $header_value) { $headers_list = headers_list(); if (!empty($headers_list)) { $header_name = strtolower($header_name); foreach ($headers_list as $value) { $value = explode(':', $value); if (strtolower($value[0]) == $header_name) { if (preg_match('/'.$header_value.'/', $value[1])) { return true; } else { return false; } } } } return false; } endif; /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ if (!function_exists('wpo_cache_mobile_caching_enabled')) : function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } endif; /** * Serves the cache and exits */ if (!function_exists('wpo_serve_cache')) : function wpo_serve_cache() { $file_name = wpo_cache_filename(); $file_name_rss_xml = wpo_cache_filename('.rss-xml'); $send_as_feed = false; $path_dir = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/'; $path = $path_dir . $file_name; if (wpo_feeds_caching_enabled()) { // check for .xml cache file if .html cache file doesn't exist if (!file_exists($path_dir . $file_name) && file_exists($path_dir . $file_name_rss_xml)) { $path = $path_dir . $file_name_rss_xml; $send_as_feed = true; } } $use_gzip = false; // if we can use gzip and gzipped file exist in cache we use it. // if headers already sent we don't use gzipped file content. if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) { $path .= '.gz'; $use_gzip = true; } $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } // disable zlib output compression to avoid double content compression. if ($use_gzip) { ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set } $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip'); header('Cache-Control: no-cache'); // Check back later if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } // send correct headers for xml and txt files $filename = basename(dirname($path)); if (preg_match('/\.xml$/i', $filename)) { header('Content-type: text/xml'); } if (preg_match('/\.txt$/i', $filename)) { header('Content-type: text/plain'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); if (!empty($modified_time)) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); } readfile($path); exit; } } endif; /** * Clears the cache */ if (!function_exists('wpo_cache_flush')) : function wpo_cache_flush() { if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } endif; /** * Get URL path for caching * * @since 1.0 * @return string */ if (!function_exists('wpo_get_url_path')) : function wpo_get_url_path($url = '') { $url = '' == $url ? wpo_current_url() : $url; $url_parts = parse_url($url); if (isset($url_parts['path']) && false !== stripos($url_parts['path'], '/index.php')) { $url_parts['path'] = preg_replace('/(.*?)index\.php(\/.+)/i', '$1index-php$2', $url_parts['path']); } if (!isset($url_parts['host'])) $url_parts['host'] = ''; if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].$url_parts['path']; } endif; /** * Get requested url. * * @return string */ if (!function_exists('wpo_current_url')) : function wpo_current_url() { // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot). // Otherwise this function would return a different URL at the begining and end of the cache process. static $url = ''; if ('' != $url) return $url; $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . $http_host.$_SERVER['REQUEST_URI'], '/'); return $url; } endif; /** * Return list of url exceptions. * * @return array */ if (!function_exists('wpo_get_url_exceptions')) : function wpo_get_url_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; // if called from file-based-page-cache.php when WP loading // and cache settings exists then use it otherwise get settings from database. if (isset($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = array(); } else { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); } } else { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_urls', $config)) { $exceptions = $config['cache_exception_urls']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } return apply_filters('wpo_get_url_exceptions', $exceptions); } endif; /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ if (!function_exists('wpo_current_url_exception_match')) : function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } endif; /** * Check if url in exceptions list. * * @param string $url * * @return bool */ if (!function_exists('wpo_url_in_exceptions')) : function wpo_url_in_exceptions($url) { $exceptions = wpo_get_url_exceptions(); if (!empty($exceptions)) { foreach ($exceptions as $exception) { // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type() if ('/' == $exception) continue; if (wpo_url_exception_match($url, $exception)) { // Exception match. return true; } } } return false; } endif; /** * Check if url string match with exception. * * @param string $url - complete url string i.e. http(s):://domain/path * @param string $exception - complete url or absolute path, can consist (.*) wildcards * * @return bool */ if (!function_exists('wpo_url_exception_match')) : function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // used to test websites placed in subdirectories. $sub_dir = ''; // if exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = rtrim($url, '/') . '/'; $exception = rtrim($exception, '/'); // if we have no wildcat in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = preg_quote($exception); // fix - unescape possible escaped mask .* $exception = str_replace('\\.\\*', '.*', $exception); return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url); } endif; /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ if (!function_exists('wpo_is_mobile')) : function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } endif; /** * Check if current browser agent is not disabled in options. * * @return bool */ if (!function_exists('wpo_is_accepted_user_agent')) : function wpo_is_accepted_user_agent($user_agent) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } endif; /** * Delete function that deals with directories recursively * * @param string $src Path of the folder * @param boolean $recursive If $src is a folder, recursively delete the inner folders. If set to false, only the files will be deleted. * * @return bool */ if (!function_exists('wpo_delete_files')) : function wpo_delete_files($src, $recursive = true) { if (!file_exists($src) || '' == $src || '/' == $src) { return true; } if (is_file($src)) { return unlink($src); } $success = true; $has_dir = false; if ($recursive) { // N.B. If opendir() fails, then a false positive (i.e. true) will be returned if (false !== ($dir = opendir($src))) { $file = readdir($dir); while (false !== $file) { if ('.' == $file || '..' == $file) { $file = readdir($dir); continue; } if (is_dir($src . '/' . $file)) { if (!wpo_delete_files($src . '/' . $file)) { $success = false; } } else { if (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($dir); } closedir($dir); } } else { // Not recursive, so we only delete the files // scan directories recursively. $handle = opendir($src); if (false === $handle) return false; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { if (is_dir($src . '/' . $file)) { $has_dir = true; } elseif (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($handle); } } if ($success && !$has_dir) { // Success of this operation is not recorded; we only ultimately care about emptying, not removing entirely (empty folders in our context are harmless) rmdir($src); } // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); return $success; } endif; if (!function_exists('wpo_is_empty_dir')) : /** * Check if selected directory is empty or has only index.php which we added for security reasons. * * @param string $dir * * @return bool */ function wpo_is_empty_dir($dir) { if (!file_exists($dir) || !is_dir($dir)) return false; $handle = opendir($dir); if (false === $handle) return false; $is_empty = true; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file && 'index.php' != $file) { $is_empty = false; break; } $file = readdir($handle); } closedir($handle); return $is_empty; } endif; /** * Either store for later output, or output now. Only the most-recent call will be effective. * * @param String|Null $output - if not null, then the string to use when called by the shutdown action. */ if (!function_exists('wpo_cache_add_footer_output')) : function wpo_cache_add_footer_output($output = null) { static $buffered = null; if (function_exists('current_filter') && 'shutdown' == current_filter()) { // Only add the line if it was a page, not something else (e.g. REST response) if (function_exists('did_action') && did_action('wp_footer')) { echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".$buffered." -->\n"; } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG) { error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered); } } else { if (null == $buffered && function_exists('add_action')) add_action('shutdown', 'wpo_cache_add_footer_output', 11); $buffered = $output; } } endif; /** * Remove variable names that shouldn't influence cache. * * @param array $variables List of variable names. * * @return array */ if (!function_exists('wpo_cache_maybe_ignore_query_variables')) : function wpo_cache_maybe_ignore_query_variables($variables) { /** * Filters the current $_GET variables that will be used when caching or excluding from cache. * Currently: * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set) * - 'doing_wp_cron' (alternative cron) * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap) * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap) * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap) */ $exclude_variables = array( 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set 'doing_wp_cron', // alternative cron 'aiosp_sitemap_path', // All in one SEO sitemap 'aiosp_sitemap_page', 'xml_sitemap', // SEOPress sitemap 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged', 'sitemap', // YOAST SEO sitemap 'sitemap_n', ); $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables; if (empty($exclude_variables)) return $variables; foreach ($exclude_variables as $variable) { $exclude = array_search($variable, $variables); if (false !== $exclude) { array_splice($variables, $exclude, 1); } } return $variables; } endif; /** * Get cache config * * @param string $key - The config item * @param mixed $default - The default value * * @return mixed */ if (!function_exists('wpo_cache_config_get')) : function wpo_cache_config_get($key, $default = false) { $config = $GLOBALS['wpo_cache_config']; if (!$config) return false; if (isset($config[$key])) { return $config[$key]; } else { return $default; } } endif; if (!function_exists('wpo_disable_cache_directories_viewing')) : function wpo_disable_cache_directories_viewing() { global $is_apache, $is_IIS, $is_iis7; if (!is_dir(WPO_CACHE_FILES_DIR)) return; // Create .htaccess file for apache server. if ($is_apache) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // CS does not like heredoc // phpcs:disable $htaccess_content = <<<EOF # Disable directory browsing Options -Indexes # Disable access to any files <FilesMatch ".*"> Order allow,deny Deny from all </FilesMatch> EOF; // phpcs:enable if (!is_file($htaccess_filename)) @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create web.config file for IIS servers. if ($is_IIS || $is_iis7) { $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config'; $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n"; if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create empty index.php file for all servers. if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', '');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } endif; /** * Add the headers indicating why the page is not cached or served from cache * * @param string $message - The headers * * @return void */ if (!function_exists('wpo_cache_add_nocache_http_header')) : function wpo_cache_add_nocache_http_header($message = '') { static $buffered_message = null; if (function_exists('current_filter') && 'send_headers' === current_filter() && $buffered_message && !headers_sent()) { header('WPO-Cache-Status: not cached'); header('WPO-Cache-Message: '. trim(str_replace(array("\r", "\n", ':'), ' ', strip_tags($buffered_message)))); } else { if (!$buffered_message && function_exists('add_action')) add_action('send_headers', 'wpo_cache_add_nocache_http_header', 11); $buffered_message = $message; } } endif; /** * Check if feeds caching enabled * * @return bool */ if (!function_exists('wpo_feeds_caching_enabled')) : function wpo_feeds_caching_enabled() { return apply_filters('wpo_feeds_caching_enabled', true); } endif; if (!function_exists('wpo_debug_backtrace_summary')) { function wpo_debug_backtrace_summary($ignore_class = null, $skip_frames = 0, $pretty = true) { static $truncate_paths; $trace = debug_backtrace(false); $caller = array(); $check_class = !is_null($ignore_class); $skip_frames++; // Skip this function. if (!isset($truncate_paths)) { $truncate_paths = array( wpo_normalize_path(WP_CONTENT_DIR), wpo_normalize_path(ABSPATH), ); } foreach ($trace as $call) { if ($skip_frames > 0) { $skip_frames--; } elseif (isset($call['class'])) { if ($check_class && $ignore_class == $call['class']) { continue; // Filter out calls. } $caller[] = "{$call['class']}{$call['type']}{$call['function']}"; } else { if (in_array($call['function'], array('do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array'), true)) { $caller[] = "{$call['function']}('{$call['args'][0]}')"; } elseif (in_array($call['function'], array('include', 'include_once', 'require', 'require_once'), true)) { $filename = isset($call['args'][0]) ? $call['args'][0] : ''; $caller[] = $call['function'] . "('" . str_replace($truncate_paths, '', wpo_normalize_path($filename)) . "')"; } else { $caller[] = $call['function']; } } } if ($pretty) { return implode(', ', array_reverse($caller)); } else { return $caller; } } } if (!function_exists('wpo_normalize_path')) { function wpo_normalize_path($path) { // Standardise all paths to use '/'. $path = str_replace('\\', '/', $path); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. $path = preg_replace('|(?<=.)/+|', '/', $path); // Windows paths should uppercase the drive letter. if (':' === substr($path, 1, 1)) { $path = ucfirst($path); } return $path; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-load-url-task.php 000644 000000 000000 00000003024 14151417634 033340 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('Access denied.'); if (!class_exists('Updraft_Task_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); class WP_Optimize_Load_Url_Task extends Updraft_Task_1_2 { /** * Default options. */ public function get_default_options() { return array(); } /** * Run preload http requests with different user-agent values to cache pages for different devices. * * @return bool */ public function run() { $url = $this->get_option('url'); if (empty($url)) return; $cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); // load pages with different user-agents values. $cache_preloader->preload_desktop($url); $cache_preloader->preload_mobile($url); $cache_preloader->preload_amp($url); if (defined('WP_CLI') && WP_CLI) { WP_CLI::log($url); } /** * Action triggered after preloading a single url * * @param string $url The url to preload * @param object $cache_preloader Cache preloader instance */ do_action('wpoptimize_after_preload_url', $url, $cache_preloader); /** * Allows to change the delay between each URL preload, to reduce server load. * * @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second). */ usleep(apply_filters('wpoptimize_preload_delay', 500000)); return true; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000111617 14213733440 032641 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality * * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('WP_Optimize_Detect_Cache_Plugins')) require_once(dirname(__FILE__) . '/class-wpo-detect-cache-plugins.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-php-logger.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (version_compare(PHP_VERSION, '5.3.0') >= 0) { require_once dirname(__FILE__) . '/php-5.3-functions.php'; } wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Store last advanced cache file writing status * If true then last writing finished with error * * @var bool */ public $advanced_cache_file_writing_error; /** * Store errors * * @var array */ private $_errors = array(); /** * Last advanced cache file content * * @var string */ public $advanced_cache_file_content; /** * Store the latest advanced-cache.php version required * * @var string */ private $_minimum_advanced_cache_file_version = '3.0.17'; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); add_action('activate_plugin', array($this, 'activate_deactivate_plugin')); add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); /** * Regenerate config file on cache flush. */ add_action('wpo_cache_flush', array($this, 'update_cache_config')); add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); // Add purge cache link to admin bar. add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1); // Handle single page purge. add_action('wp_loaded', array($this, 'handle_purge_single_page_cache')); add_action('admin_init', array($this, 'admin_init')); $this->check_compatibility_issues(); } /** * Do required actions on activate/deactivate any plugin. */ public function activate_deactivate_plugin() { $this->update_cache_config(); /** * Filters whether activating / deactivating a plugin will purge the cache. */ if (apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true)) { $this->purge(); } } /** * Check if current user can purge cache. * * @return bool */ public function can_purge_cache() { if (is_multisite()) return $this->is_enabled() && (current_user_can('manage_network_options') || WP_Optimize()->can_purge_the_cache()); return $this->is_enabled() && (current_user_can('manage_options') || WP_Optimize()->can_purge_the_cache()); } /** * Add Purge from cache in admin bar. * * @param array $menu_items * @return array */ public function admin_bar_purge_cache($menu_items) { global $pagenow; if (!$this->can_purge_cache()) return $menu_items; $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); $cache_size = $this->get_cache_size(); $cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>'; $cache_size_info .= '<span>'.__('Cache size:', 'wp-optimize').' '. WP_Optimize()->format_size($cache_size['size']).' '.sprintf(__('(%d files)', 'wp-optimize'), $cache_size['file_count']).'</span>'; $menu_items[] = array( 'id' => 'wpo_cache_stats', 'title' => $cache_size_info, 'meta' => array( 'class' => 'wpo-cache-stats', ), 'parent' => 'wpo_purge_cache', ); $menu_items[] = array( 'id' => 'wpo_purge_all_pages_cache', 'title' => __('Purge cache for all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for all pages', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); if (!is_admin() || 'post.php' == $pagenow) { $menu_items[] = array( 'id' => 'wpo_purge_this_page_cache', 'title' => __('Purge cache for this page', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for this page', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); } return $menu_items; } /** * Check if purge single page action sent and purge cache. */ public function handle_purge_single_page_cache() { if (!$this->can_purge_cache()) return; if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { if (isset($_GET['wpo_single_page_cache_purged'])) { $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; } else { $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; } add_action('admin_notices', array($this, $notice_function)); return; } if (!isset($_GET['_wpo_purge'])) return; if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) { $success = false; if (is_admin()) { $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; if ($post > 0) { $success = self::delete_single_post_cache($post); } } else { $success = self::delete_cache_by_url(wpo_current_url()); } // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) { $success = self::purge(); // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } } /** * Show notification when page cache purged successfully. */ public function notice_purge_single_page_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when page cache wasn't purged. */ public function notice_purge_single_page_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification when all pages cache purged successfully. */ public function notice_purge_all_pages_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when all pages cache wasn't purged. */ public function notice_purge_all_pages_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification in WordPress admin. * * @param string $message HTML (no further escaping is performed) * @param string $type error, warning, success, or info */ public function show_notice($message, $type) { global $current_screen; if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?> <script> window.addEventListener('load', function() { (function(wp) { if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) { wp.data.dispatch('core/notices').createNotice( '<?php echo $type; ?>', '<?php echo $message; ?>', { isDismissible: true, } ); } })(window.wp); }); </script> <?php else : ?> <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible"> <p><?php echo $message; ?></p> </div> <?php endif; } /** * Enables page cache * * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings * * @return WP_Error|bool - true on success, error otherwise */ public function enable($force_enable = false) { static $already_ran_enable = false; if ($already_ran_enable) return $already_ran_enable; $folders_created = $this->create_folders(); if (is_wp_error($folders_created)) { $already_ran_enable = $folders_created; return $already_ran_enable; } // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) { $force_enable = true; } if (!$force_enable) { $already_ran_enable = true; return true; } if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) { $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); if (!defined('WP_CLI') || !WP_CLI) { $message .= "\n\n".sprintf(__('1. Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); $message .= "\n".__('2. Edit or create a file with the name advanced-cache.php', 'wp-optimize'); $message .= "\n".__('3. Copy and paste the following lines into the file:', 'wp-optimize'); } $already_ran_enable = new WP_Error("write_advanced_cache", $message); return $already_ran_enable; } if (!$this->write_wp_config(true)) { $already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions."); return $already_ran_enable; } if (!$this->verify_cache()) { $errors = $this->get_errors(); $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors)); return $already_ran_enable; } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; $advanced_cache_file = $this->get_advanced_cache_filename(); // N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem. $disabled_wp_config = $this->write_wp_config(false); if (!$disabled_wp_config) { $this->log("Could not turn off the WP_CACHE constant in wp-config.php"); $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize')); } $disabled_advanced_cache = true; // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { $disabled_advanced_cache = false; $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize')); } } // If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled. if (!$disabled_wp_config && !$disabled_advanced_cache) { $ret = new WP_Error('error_disabling_cache', __('The page caching could not be disabled: the WP_CACHE constant could not be removed from wp-config.php and the request to the filesystem to remove or empty advanced-cache.php failed.', 'wp-optimize')); } // Delete cache to avoid stale cache on next activation $this->purge(); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } /** * Fires after purging the cache */ do_action('wpo_cache_flush'); return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR))); } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR))); } if (!is_dir(WPO_CACHE_FILES_DIR)) { if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR))); } else { wpo_disable_cache_directories_viewing(); } } return true; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_advanced_cache_filename() { return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_cache_config_filename() { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { return 'config-'.$url['host'].'-port'.$url['port'].'.php'; } else { return 'config-'.$url['host'].'.php'; } } /** * Writes advanced-cache.php * * @param boolean $update_required - Whether the update is required or not. * @return bool */ private function write_advanced_cache($update_required = false) { $config_file_basename = $this->get_cache_config_filename(); $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__)); $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $cache_path = '/wpo-cache'; $cache_files_path = '/cache/wpo-cache'; $cache_extensions_path = WPO_CACHE_EXT_DIR; $wpo_version = WPO_VERSION; $wpo_home_url = trailingslashit(home_url()); // CS does not like heredoc // phpcs:disable $this->advanced_cache_file_content = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); // WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks) if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); \$possible_plugin_locations = array( defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false, defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false, dirname(__FILE__).'/plugins/$plugin_basename/cache', '$cache_file_basename', ); \$plugin_location = false; foreach (\$possible_plugin_locations as \$possible_location) { if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) { \$plugin_location = \$possible_location; break; } } if (false === \$plugin_location) { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', true); \$protocol = \$_SERVER['REQUEST_SCHEME']; \$host = \$_SERVER['HTTP_HOST']; \$request_uri = \$_SERVER['REQUEST_URI']; if (strcasecmp('$wpo_home_url', \$protocol . '://' . \$host . \$request_uri) === 0) { error_log('WP-Optimize: No caching took place, because the plugin location could not be found'); } } else { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', false); } if (is_admin()) { return; } if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path'); if (false !== \$plugin_location) { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions'); } else { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); } if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; } \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true); if (empty(\$GLOBALS['wpo_cache_config'])) { include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'); } if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); } EOF; // phpcs:enable $advanced_cache_filename = $this->get_advanced_cache_filename(); // If the file content is already up to date, success if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) { $this->advanced_cache_file_writing_error = false; return true; } // check if we can't write the advanced cache file // case 1: the directory is read-only and the file doesn't exist if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) { $this->advanced_cache_file_writing_error = true; return false; } // case 2: the file already exists but it's read-only if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) { if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) { $this->advanced_cache_file_writing_error = true; return false; } else { $this->advanced_cache_file_writing_error = false; return true; } } if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) { $this->advanced_cache_file_writing_error = true; return false; } $this->advanced_cache_file_writing_error = false; return true; } /** * Update advanced cache version if needed. */ public function maybe_update_advanced_cache() { if (!$this->is_enabled()) return; if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND') || (defined('WPO_PLUGIN_LOCATION_NOT_FOUND') && true === WPO_PLUGIN_LOCATION_NOT_FOUND)) { if (!$this->write_advanced_cache(true)) { add_action('admin_notices', array($this, 'show_admin_notice_advanced_cache')); } } // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php $advanced_cache_current_version = $this->get_advanced_cache_version(); if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return; if (!$this->write_advanced_cache()) { add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); } else { $this->update_cache_config(); } } /** * Show notification when advanced-cache.php could not be updated. */ public function notice_advanced_cache_autoupdate_error() { $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp-optimize'). ' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to disable and then re-enable the WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error'); } /** * Get WPO version number from advanced-cache.php file. * * @return bool|mixed */ public function get_advanced_cache_version() { if (!is_file($this->get_advanced_cache_filename())) return false; $version = false; $content = file_get_contents($this->get_advanced_cache_filename()); if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { $version = $match[1]; } return $version; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { // If we changed the value in wp-config, save it, in case we need to change it again in the same run. static $changed = false; if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r\n)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) { return false; } $changed = true; return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } $errors = 0; // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize')); } $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; // Now check wp-content. We need to be able to create files of the same user as this file. if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); $this->add_error('verify_cache', __("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions", 'wp-optimize')); $errors++; } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); $this->add_warning('verify_cache', sprintf(__("Unable to write inside the cache files folder (%s); please check file/folder permissions (no cache files will be able to be created otherwise)", 'wp-optimize'), WPO_CACHE_FILES_DIR)); } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); // If the config exists, only send a warning. Otherwise send an error. $type = 'warning'; if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { $type = 'error'; $errors++; } $this->add_error('verify_cache', sprintf(__("Unable to write inside the cache configuration folder (%s); please check file/folder permissions", 'wp-optimize'), WPO_CACHE_CONFIG_DIR), $type); } } return !$errors; } /** * Update cache config. Used to support 3d party plugins. */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. $this->config->update($current_config, true); } /** * Delete information about cache size. */ public function delete_cache_size_information() { delete_transient('wpo_get_cache_size'); } /** * Get current cache size. * * @return array */ public function get_cache_size() { $cache_size = get_transient('wpo_get_cache_size'); if (!empty($cache_size)) return $cache_size; $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); $cache_size = array( 'size' => $infos['size'], 'file_count' => $infos['file_count'] ); set_transient('wpo_get_cache_size', $cache_size); return $cache_size; } /** * Fetch directory informations. * * @param string $dir * @return array */ private function get_dir_infos($dir) { $dir_size = 0; $file_count = 0; $handle = is_dir($dir) ? opendir($dir) : false; if (false === $handle) { return array('size' => 0, 'file_count' => 0); } $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { $current_file = $dir.'/'.$file; if (is_dir($current_file)) { $sub_dir_infos = $this->get_dir_infos($current_file); $dir_size += $sub_dir_infos['size']; $file_count += $sub_dir_infos['file_count']; } elseif (is_file($current_file)) { $dir_size += filesize($current_file); $file_count++; } } $file = readdir($handle); } return array('size' => $dir_size, 'file_count' => $file_count); } /** * Returns the path to wp-config * * @return string|boolean wp-config.php path. */ private function _get_wp_config() { $config_path = false; foreach (get_included_files() as $filename) { if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) { $config_path = $filename; break; } } // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file. if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) { $config_path = wpo_wp_cli_locate_wp_config(); } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Delete cached files for specific url. * * @param string $url * @param bool $recursive If true child elements will deleted too * * @return bool */ public static function delete_cache_by_url($url, $recursive = false) { if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; $path = self::get_full_path_from_url($url); do_action('wpo_delete_cache_by_url', $url, $recursive); return wpo_delete_files($path, $recursive); } /** * Delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function delete_single_post_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url); // for posts with pagination run purging cache recursively. $post = get_post($post_id); $recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false; do_action('wpo_delete_cache_by_url', $post_url, $recursive); return wpo_delete_files($path, $recursive); } /** * Delete cached home page files. */ public static function delete_homepage_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url); do_action('wpo_delete_cache_by_url', $homepage_url, false); wpo_delete_files($path, false); } /** * Delete sitemap cahche. */ public static function delete_sitemap_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($homepage_url)); if (!is_dir($path)) return; $handle = opendir($path); if (false !== $handle) { $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file && is_dir($path . $file) && preg_match('/.*sitemap.*\.xml/i', $file)) { do_action('wpo_delete_cache_by_url', $path . $file, false); wpo_delete_files($path . $file, true); } $file = readdir($handle); } } closedir($handle); } /** * Delete feed from cache. */ public static function delete_feed_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete post feed from cache. */ public static function delete_post_feed_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete comments feed from cache. */ public static function delete_comments_feed() { if (!defined('WPO_CACHE_FILES_DIR')) return; $comments_feed_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/feed/'; $path = self::get_full_path_from_url($comments_feed_url); do_action('wpo_delete_cache_by_url', $comments_feed_url, true); wpo_delete_files($path, true); // delete empty comments dir from the cache $comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/'; $path = self::get_full_path_from_url($comments_url); if (wpo_is_empty_dir($path)) { wpo_delete_files($path, true); } } /** * Returns full path to the cache folder by url. * * @param string $url * @return string */ private static function get_full_path_from_url($url) { return trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url)); } /** * Admin actions * * @return void */ public function admin_init() { // Maybe update the advanced cache. if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { $this->maybe_update_advanced_cache(); } } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log($message, 'error'); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Adds an error to the error store * * @param string $code - The error code * @param string $message - The error's message * @param string $type - The error's type (error, warning) * @return void */ public function add_error($code, $message, $type = 'error') { if (!isset($this->_errors[$type])) { $this->_errors[$type] = new WP_Error($code, $message); } else { $this->_errors[$type]->add($code, $message); } } /** * Adds a warning to the error store * * @param string $code - The error code * @param string $message - The error's message * @return void */ public function add_warning($code, $message) { $this->add_error($code, $message, 'warning'); } /** * Get all recorded errors * * @param string $type - The error type * @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object * @return boolean|array|WP_Error */ public function get_errors($type = 'error', $get_messages_only = true) { if (!$this->has_errors($type)) return false; $errors = $this->_errors[$type]; if ($get_messages_only) { return $errors->get_error_messages(); } return $errors; } /** * Check if any errors were recorded * * @param string $type - The error type * @return boolean */ public function has_errors($type = 'error') { return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors(); } /** * Check if any warnings were recorded * * @return boolean */ public function has_warnings() { return $this->has_errors('warning'); } /** * Check the cache compatibility issues. */ public function check_compatibility_issues() { if (!$this->is_enabled()) return; if ($this->is_pagespeedninja_gzip_active()) add_action('admin_notices', array($this, 'show_pagespeedninja_gzip_notice')); if ($this->is_farfutureexpiration_gzip_active()) add_action('admin_notices', array($this, 'show_farfutureexpiration_gzip_notice')); } /** * Check if PageSpeed Ninja is active and GZIP compression option is enabled. * * @return bool */ public function is_pagespeedninja_gzip_active() { if (!class_exists('PagespeedNinja')) return false; $options = get_option('pagespeedninja_config'); $gzip = !empty($options) ? (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip'] : false; return $gzip; } /** * Output PageSpeed Ninja Gzip notice. */ public function show_pagespeedninja_gzip_notice() { echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in PageSpeed Ninja to prevent conflicts.', 'wp-optimize').'</p></div>'; } /** * Check if Far Future Expiration is active and GZIP compression option is enabled. * * @return bool */ public function is_farfutureexpiration_gzip_active() { if (!class_exists('farFutureExpiration')) return false; $options = get_option('far_future_expiration_settings'); $gzip = !empty($options) ? (bool) $options['enable_gzip'] : false; return $gzip; } /** * Output Far Future Expiration Gzip notice. */ public function show_farfutureexpiration_gzip_notice() { echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in Far Future Expiration to prevent conflicts.', 'wp-optimize').'</p></div>'; } /** * This is a notice to show users that writing `advanced-cache.php` failed */ public function show_admin_notice_advanced_cache() { $message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message)); } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000030100 14173760430 033046 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1); add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2); add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6); add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1); add_action('wp_insert_comment', array($this, 'comment_inserted'), 10, 2); add_action('woocommerce_variation_set_stock', array($this, 'purge_product_page'), 10, 1); add_action('woocommerce_product_set_stock', array($this, 'purge_product_page'), 10, 1); /** * List of hooks for which when executed, the cache will be purged * * @param array $actions The actions */ $purge_on_action = apply_filters('wpo_purge_cache_hooks', array('after_switch_theme', 'wp_update_nav_menu', 'customize_save_after', array('wp_ajax_save-widget', 0), array('wp_ajax_update-widget', 0), 'autoptimize_action_cachepurged', 'upgrader_overwrote_package', 'wpo_active_plugin_or_theme_updated', 'fusion_cache_reset_after')); foreach ($purge_on_action as $action) { if (is_array($action)) { add_action($action[0], array($this, 'purge_cache'), $action[1]); } else { add_action($action, array($this, 'purge_cache')); } } add_filter('wpo_cache_cookies', array($this, 'wpo_cache_cookies'), 9); } /** * Purge post cache when there is a new approved comment * * @param int $comment_id Comment ID. * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'. * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/ */ public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) { if (1 !== $approved) { return; } if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) { $post_id = $commentdata['comment_post_ID']; WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_comments_feed(); } } /** * Every time a comment's status changes, purge it's parent posts cache * * @param int $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (!empty($this->config['enable_page_caching'])) { $comment = get_comment($comment_id); if (is_object($comment) && !empty($comment->comment_post_ID)) { WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID); WPO_Page_Cache::delete_comments_feed(); } } } /** * Action when a comment is inserted * * @param integer $comment_id - The comment ID * @param boolean|WP_Comment $comment - The comment object (from WP 4.4) * @return void */ public function comment_inserted($comment_id, $comment = false) { if ($comment && is_a($comment, 'WP_Comment')) { /** * Filters whether to add a cookie when a comment is posted, in order to exclude the page from caching. * Regular comments have the property comment_type set to '' or 'comment'. So by default, only add the cookie in those cases. * * @param boolean $add_cookie * @param WP_Comment $comment * @return boolean */ $add_cookie = apply_filters('wpo_add_commented_post_cookie', '' == $comment->comment_type || 'comment' == $comment->comment_type, $comment); if (!$add_cookie) return; $url = get_permalink($comment->comment_post_ID); $url_info = parse_url($url); setcookie('wpo_commented_post', 1, time() + WEEK_IN_SECONDS, isset($url_info['path']) ? $url_info['path'] : '/'); } } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); $post_type_object = get_post_type_object($post_type); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || !$post_type_object->public) { return; } /** * Purge the whole cache if set to true, only the edited post otherwise. Default is false. * * @param boolean $purge_all_cache The default filter value * @param integer $post_id The saved post ID */ if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) { $this->purge_cache(); return; } else { if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::delete_feed_cache(); WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_sitemap_cache(); WPO_Page_Cache::delete_post_feed_cache($post_id); } } /** * Purge archive pages on post update. * * @param integer $post_id */ public function purge_archive_pages_on_post_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } $post_obj = get_post_type_object($post_type); if ('post' == $post_type) { // delete blog page cache $blog_post_id = get_option('page_for_posts'); if ($blog_post_id) { WPO_Page_Cache::delete_cache_by_url(get_permalink($blog_post_id), true); } // delete next and previus posts cache. $globals_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : false; $GLOBALS['post'] = get_post($post_id); $previous_post = function_exists('get_previous_post') ? get_previous_post() : false; $next_post = function_exists('get_next_post') ? get_next_post() : false; if ($globals_post) $GLOBALS['post'] = $globals_post; if ($previous_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($previous_post), true); if ($next_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($next_post), true); // delete all archive pages for post. $post_date = get_post_time('Y-m-j', false, $post_id); list($year, $month, $day) = $post_date; $archive_links = array( get_year_link($year), get_month_link($year, $month), get_day_link($year, $month, $day), ); foreach ($archive_links as $link) { WPO_Page_Cache::delete_cache_by_url($link, true); } } elseif ($post_obj->has_archive) { // delete archive page for custom post type. WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true); } } /** * We use it with edit_terms action filter to purge cached elements related * to updated term when term updated. * * @param int $term_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. */ public function purge_related_elements_on_term_updated($term_id, $taxonomy) { // purge cached page for term. $term = get_term($term_id, $taxonomy, ARRAY_A); if (is_array($term)) { $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } // get posts which belongs to updated term. $posts = get_posts(array( 'numberposts' => -1, 'post_type' => 'any', 'fields' => 'ids', 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $term_id, ) ), )); if (!empty($posts)) { foreach ($posts as $post_id) { WPO_Page_Cache::delete_single_post_cache($post_id); } } } /** * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) { $post_type = get_post_type($object_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) { return; } /** * Adds a way to exit the purge of terms permalink using the provided parameters. * * @param bool $purge The value filtered, whether or not to purge the related elements * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. * @default true * @return boolean */ if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return; // get all affected terms. $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids)); if (!empty($affected_terms_ids)) { // walk through all changed terms and purge cached pages for them. foreach ($affected_terms_ids as $tt_id) { $term = get_term($tt_id, $taxonomy, ARRAY_A); if (!is_array($term)) continue; $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { $url = parse_url($term_permalink); // Check if the permalink contains a valid path, to avoid deleting the whole cache. if (!isset($url['path']) || '/' === $url['path']) return; WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } } } /** * Purge product page upon stock update */ public function purge_product_page($product_with_stock) { if (!empty($product_with_stock->get_id())) { WPO_Page_Cache::delete_single_post_cache($product_with_stock->get_id()); } } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Triggered by wpo_cache_config_updated. * * @param array $config */ public function cache_config_updated($config) { // delete front page form cache if defined in the settings if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) { WPO_Page_Cache::delete_cache_by_url(home_url()); } } /** * Add cookie names that are need separate caching */ public function wpo_cache_cookies($cookies) { $cookies[] = 'cookie_notice_accepted'; $cookies[] = 'cookielawinfo-checkbox-necessary'; $cookies[] = 'cookielawinfo-checkbox-functional'; $cookies[] = 'cookielawinfo-checkbox-advertisement'; $cookies[] = 'cookielawinfo-checkbox-others'; $cookies[] = 'cookielawinfo-checkbox-analytics'; $cookies[] = 'cookielawinfo-checkbox-performance'; return $cookies; } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.2/wp-optimize/cache/php-5.3-functions.php 000644 000000 000000 00000000575 13614520640 032056 0 ustar 00root wheel 000000 000000 <?php /** * Get path to wp-config.php when called from WP-CLI. * * @return string */ function wpo_wp_cli_locate_wp_config() { $config_path = ''; if (is_callable('\WP_CLI\Utils\locate_wp_config')) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound $config_path = \WP_CLI\Utils\locate_wp_config(); } return $config_path; } cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/ 000755 000000 000000 00000000000 14214670220 025167 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/ 000755 000000 000000 00000000000 14214670220 026232 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000003543 13416124150 032715 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); // Don't cache robots.txt or htacesss. if (false !== strpos($_SERVER['REQUEST_URI'], 'robots.txt') || false !== strpos($_SERVER['REQUEST_URI'], '.htaccess')) { return; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) return; $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array( 'php', 'xml', 'xsl' ))) { return; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array( 'wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_' ); foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (strpos($key, $cookie) !== false) { // Logged in! return; } } } if (!empty($_COOKIE['wpo_commented_posts'])) { foreach ($_COOKIE['wpo_commented_posts'] as $path) { if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) { // User commented on this post. return; } } } } // Deal with optional cache exceptions. if (!empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); $regex = !empty($GLOBALS['wpo_cache_config']['enable_url_exemption_regex']); foreach ($exceptions as $exception) { if (wpo_url_exception_match($exception, $regex)) { // Exception match. return; } } } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000005245 13427270250 033171 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @return bool */ public function update($config) { $config = wp_parse_args($config, $this->get_defaults()); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } return $this->write($config); } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config Configuration array. * @return bool */ private function write($config) { $url = parse_url(site_url()); if ($url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].':'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); if (!file_put_contents($config_file, json_encode($this->config))) { return false; } return true; } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => true, 'enable_mobile_caching' => true, 'enable_gzip_compression' => true, 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'enable_url_exemption_regex' => false, ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return SC_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000023624 13416124150 032634 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WPO_CACHE_DIR.'/cache'); if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once('class-wpo-cache-rules.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-php-logger.php'); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); } /** * Enables page cache * * @param array $options - options for caching * @return WP_Error|bool - true on success, error otherwise */ public function enable($options = array()) { if (!$this->create_folders()) { return new WP_Error("create_folders", "The request to the filesystem to create the cache directories failed"); } if (!$this->write_advanced_cache()) { return new WP_Error("write_advanced_cache", "The request to write the advanced-cache.php file failed"); } if (!$this->write_wp_config(true)) { return new WP_Error("write_wp_config", "Could not toggle the WP_CACHE constant in wp-config.php"); } if (!$this->verify_cache()) { return new WP_Error("verify_cache", "Could not verify if cache was enabled"); } $this->config->update($options); return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; if (!self::delete(untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php')) { $this->log("The request to the filesystem to delete the advanced-cache.php failed"); $ret = false; } if (!$this->write_wp_config(false)) { $this->log("Could not toggle the WP_CACHE constant in wp-config.php"); $ret = false; } return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (empty($this->config['enable_page_caching'])) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !mkdir(WPO_CACHE_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_DIR); return false; } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !mkdir(WPO_CACHE_CONFIG_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_CONFIG_DIR); return false; } if (!is_dir(WPO_CACHE_FILES_DIR) && !mkdir(WPO_CACHE_FILES_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_FILES_DIR); return false; } return true; } /** * Writes advanced-cache.php * * @return bool */ private function write_advanced_cache() { $file = untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; $contents = ''; if (!empty($config['enable_page_caching'])) { return false; } $cache_file = untrailingslashit(plugin_dir_path(__FILE__)) . '/file-based-page-cache.php'; $config_file = WPO_CACHE_CONFIG_DIR . '/config-' . $_SERVER['HTTP_HOST'] . '.php'; $cache_path = WPO_CACHE_DIR; $cache_config_path = WPO_CACHE_CONFIG_DIR; $cache_files_path = WPO_CACHE_FILES_DIR; // CS does not like heredoc // @codingStandardsIgnoreStart $contents = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', '$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', '$cache_config_path'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', '$cache_files_path'); if (is_admin()) { return; } if (!@file_exists('$config_file')) { return; } \$GLOBALS['wpo_cache_config'] = json_decode(file_get_contents('$config_file'), true); if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (@file_exists('$cache_file')) { include_once('$cache_file'); } EOF; // @codingStandardsIgnoreEnd if (!file_put_contents($file, $contents)) { return false; } return true; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { if (defined('WP_CACHE') && WP_CACHE === $status) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (file_put_contents($config_path, implode("\r\n", $config_file))) { return false; } return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php, please check file/folder permissions"); return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write inside the wp-content folder, please check file/folder permissions"); return false; } // If the cache and config directories exist, make sure they're writeable. if (file_exists(WPO_CACHE_DIR)) { if (!is_writable(WPO_CACHE_DIR)) { $this->log("Unable to write inside the cache folder, please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder, please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder, please check file/folder permissions"); return false; } } return true; } /** * Returns the path to wp-config * * @return string wp-config.php path. */ private function _get_wp_config() { $file = '/wp-config.php'; $config_path = false; foreach (get_included_files() as $filename) { if (0 === stripos(strrev($filename), strrev($file))) { $config_path = $filename; } } // Couldn't find wp-config.php. if (!$config_path) { return false; } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { if (!file_exists($src)) { return true; } if (is_dir($src)) { $dir = opendir($src); while (false !== ($file = readdir($dir))) { if (('.' != $file) && ('..' != $file)) { if (is_dir($src . '/' . $file)) { self::delete($src . '/' . $file); } else { unlink($src . '/' . $file); } } } closedir($dir); rmdir($src); } else { unlink($src); } return true; } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log('ERROR', $message); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000006611 13416124150 033047 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; /** * Class constructor */ public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('pre_post_update', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10); add_action('set_comment_cookies', array($this, 'set_comment_cookie_exceptions'), 10); } /** * When user posts a comment, set a cookie so we don't show them page cache * * @param WP_Comment $comment Comment to check. */ public function set_comment_cookie_exceptions($comment) { if (empty($this->config['enable_page_caching'])) return; $path = $this->get_post_path($comment->comment_post_ID); $this->purge_from_cache($path); } /** * Purge files for a particular path from the cache * * @param String $path - the path */ public function purge_from_cache($path) { WPO_Page_Cache::delete(untrailingslashit($path) . '/index.html'); WPO_Page_Cache::delete(untrailingslashit($path) . '/index.gzip.html'); if (!empty($this->config['enable_mobile_caching'])) { WPO_Page_Cache::delete(untrailingslashit($path) . '/mobile.index.html'); WPO_Page_Cache::delete(untrailingslashit($path) . '/mobile.index.gzip.html'); } } /** * Get the cache path for a given post * * @param Integer $post_id - WP post ID * * @return String */ private function get_post_path($post_id) { return WPO_CACHE_DIR . preg_replace('#^https?://#i', '', get_permalink($post_id)); } /** * Every time a comment's status changes, purge it's parent posts cache * * @param Integer $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (empty($this->config['enable_page_caching'])) return; $comment = get_comment($comment_id); $path = $this->get_post_path($comment->comment_post_ID); $this->purge_from_cache($path); } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id WordPress post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } elseif (!current_user_can('edit_post', $post_id) && (!defined('DOING_CRON') || !DOING_CRON)) { return; } if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return WPO_Cache_Rules */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; wordpress/wp-optimize-versions/wp-optimize.2.2/wp-optimize/cache/file-based-page-cache-functions.php000644 000000 000000 00000017252 13416124150 034646 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser * * @param string $buffer Page HTML. * @param int $flags OB flags to be passed through. * @return string */ function wpo_cache($buffer, $flags) { global $post; if (strlen($buffer) < 255) { return $buffer; } // Don't cache search, 404, or password protected. if (is_404() || is_search() || !empty($post->post_password)) { return $buffer; } // No root cache folder, exit here if (!file_exists(WPO_CACHE_DIR)) { // Can not cache! return $buffer; } // Try creating a folder for cached files, if it was flushed recently if (!file_exists(WPO_CACHE_FILES_DIR)) { if (!mkdir(WPO_CACHE_FILES_DIR)) { // Can not cache! return $buffer; } } $buffer = apply_filters('wpo_pre_cache_buffer', $buffer); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { // Can not cache! return $buffer; } } } } $modified_time = time(); // Make sure modified time is consistent. // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } if (preg_match('#</html>#i', $buffer)) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $buffer .= "\n<!-- Cached by WP Optimize for mobile devices - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $buffer .= "\n<!-- Cached by WP Optimize - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } if (!empty($GLOBALS['wpo_cache_config']['enable_gzip_compression']) && function_exists('gzencode')) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { file_put_contents($path . '/mobile.index.gzip.html', gzencode($buffer, 3)); touch($path . '/mobile.index.gzip.html', $modified_time); } else { file_put_contents($path . '/index.gzip.html', gzencode($buffer, 3)); touch($path . '/index.gzip.html', $modified_time); } } else { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { file_put_contents($path . '/mobile.index.html', $buffer); touch($path . '/mobile.index.html', $modified_time); } else { file_put_contents($path . '/index.html', $buffer); touch($path . '/index.html', $modified_time); } } header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); if (function_exists('ob_gzhandler') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { return ob_gzhandler($buffer, $flags); } else { return $buffer; } } /** * Serves the cache and exits */ function wpo_serve_cache() { $file_name = 'index.html'; if (function_exists('gzencode') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { $file_name = 'index.gzip.html'; } if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $file_name = 'mobile.' . $file_name; } $path = WPO_CACHE_FILES_DIR . '/' . rtrim(wpo_get_url_path(), '/') . '/' . $file_name; $modified_time = file_exists($path) ? (int) filemtime($path) : time(); header('Cache-Control: no-cache'); // Check back in an hour. if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if (function_exists('gzencode') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { header('Content-Encoding: gzip'); } header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if (function_exists('gzencode') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { header('Content-Encoding: gzip'); } readfile($path); exit; } } /** * Clears the cache */ function wpo_cache_flush() { $this->wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } } /** * Get URL path for caching * * @since 1.0 * @return string */ function wpo_get_url_path() { $host = !empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; return rtrim($host, '/') . $_SERVER['REQUEST_URI']; } /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ function wpo_url_exception_match($exception, $regex = false ) { if (preg_match('#^[\s]*$#', $exception)) return false; $exception = trim($exception); if (!preg_match('#^/#', $exception)) { $url = rtrim('http' . (isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}", '/'); if ($regex) { if (preg_match('#^' . $exception . '$#', $url)) { // Exception match! return true; } } elseif (preg_match('#\*$#', $exception)) { $filtered_exception = str_replace('*', '', $exception); if (preg_match('#^' . $filtered_exception . '#', $url)) { // Exception match! return true; } } else { $exception = rtrim($exception, '/'); if (strtolower($exception) === strtolower($url)) { // Exception match! return true; } } } else { $path = $_SERVER['REQUEST_URI']; if ($regex) { if (preg_match('#^' . $exception . '$#', $path)) { // Exception match! return true; } } elseif (preg_match('#\*$#', $exception)) { $filtered_exception = preg_replace('#/?\*#', '', $exception); if (preg_match('#^' . $filtered_exception . '#i', $path)) { // Exception match! return true; } } else { if ('/' !== $path) { $path = rtrim($path, '/'); } if ('/' !== $exception) { $exception = rtrim($exception, '/'); } if (strtolower($exception) === strtolower($path)) { // Exception match! return true; } } } return false; } /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Android') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } /** * Delete function that deals with directories recursively * * @param string $src path of the folder */ function wpo_delete_files($src) { if (!file_exists($src)) return; if (is_file($src)) unlink($src); $dir = opendir($src); $file = readdir($dir); while (false !== $file) { if ('.' != $file && '..' != $file) { if (is_dir($src . '/' . $file)) { wpo_delete_files($src . '/' . $file); } else { unlink($src . '/' . $file); } } } closedir($dir); rmdir($src); } cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/ 000755 000000 000000 00000000000 14214670220 025166 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/ 000755 000000 000000 00000000000 14214670220 026231 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/php-5.3-functions.php 000644 000000 000000 00000000575 13614520640 032054 0 ustar 00root wheel 000000 000000 <?php /** * Get path to wp-config.php when called from WP-CLI. * * @return string */ function wpo_wp_cli_locate_wp_config() { $config_path = ''; if (is_callable('\WP_CLI\Utils\locate_wp_config')) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound $config_path = \WP_CLI\Utils\locate_wp_config(); } return $config_path; } cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000011043 13614520640 032712 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); /** * Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded. */ if (function_exists('do_action')) { do_action('wpo_cache_extensions_loaded'); } add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); $no_cache_because = array(); // check if we want to cache current page. $restricted_cache_page_type = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_cache_page_type) { $no_cache_because[] = $restricted_cache_page_type; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) { $no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')'; } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && !preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) { $no_cache_because[] = 'The request extension is not suitable for caching'; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || false == $GLOBALS['wpo_cache_config']['enable_user_caching']) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { $no_cache_because[] = 'WordPress login cookies were detected'; break(2); } } } } if (!empty($_COOKIE['wpo_commented_posts'])) { foreach ($_COOKIE['wpo_commented_posts'] as $path) { if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) { $no_cache_because[] = 'The user has commented on a post (comment cookie set)'; break; } } } // get cookie exceptions from options. $cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array(); // filter cookie exceptions, since WP 4.6 $cache_exception_cookies = function_exists('apply_filters') ? apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies) : $cache_exception_cookies; // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { $no_cache_because[] = 'An excepted cookie was set ('.$key.')'; break 2; } } } } } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) { $no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent"; } // Deal with optional cache exceptions. if (wpo_url_in_exceptions(wpo_current_url())) { $no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL'; } if (!empty($_GET)) { // get variables used for building filename. $get_variable_names = wpo_cache_query_variables(); $get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET)); // if GET variables include one or more undefined variable names then we don't cache. $diff = array_diff($get_variables, $get_variable_names); if (!empty($diff)) { $no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters"; } } if (!empty($no_cache_because)) { // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON)) { wpo_cache_add_footer_output("Page not served from cache because: ".implode(', ', array_filter($no_cache_because, 'htmlspecialchars'))); } return; } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000016134 13637401250 033166 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return isset($options[$option_key]) ? $options[$option_key] : $default; } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved. * * @return bool */ public function update($config, $skip_disk_if_not_yet_present = false) { $config = wp_parse_args($config, $this->get_defaults()); $config['page_cache_length_value'] = intval($config['page_cache_length_value']); $config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']); /** * Filters the cookies used to set cache file names * * @param array $cookies - The cookies * @param array $config - The new config */ $wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config); sort($wpo_cache_cookies); /** * Filters the query variables used to set cache file names * * @param array $wpo_query_variables - The variables * @param array $config - The new config */ $wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; $config = apply_filters('wpo_cache_update_config', $config); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } do_action('wpo_cache_config_updated', $config); return $this->write($config, $skip_disk_if_not_yet_present); } /** * Calculate cache expiration value in seconds. * * @param int $value * @param string $unit ( hours | days | months ) * * @return int */ private function calculate_page_cache_length($value, $unit) { $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); return $value * $cache_length_units[$unit]; } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config - Configuration array. * @param boolean $only_if_present - only writes to the disk if the configuration file already exists * * @return boolean - returns false if an attempt to write failed */ private function write($config, $only_if_present = false) { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'-port'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); // from 3.0.17 we use more secure way to store cache config files. $advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version(); // if advanced-cache.php exists and has at least 3.0.17 version or // advanced-cache.php doesn't exist and WP-O has at least 3.0.17 version then // we write the cache config in a new format. if (($advanced_cache_version && (0 >= version_compare($advanced_cache_version, '3.0.17'))) || (!$advanced_cache_version && (0 >= version_compare(WPO_VERSION, '3.0.17'))) ) { $config_content = '<?php' . "\n" . 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n" . '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . json_encode($this->config) . '\', true);' . "\n"; } else { $config_content = json_encode($this->config); } if ((!$only_if_present || file_exists($config_file)) && !file_put_contents($config_file, $config_content)) { return false; } return true; } /** * Verify we can write to the file system * * @since 1.0 * @return boolean */ public function verify_file_access() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) { return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) { return false; } // If the cache and config directories exist, make sure they're writeable if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) { if (file_exists(WPO_CACHE_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_DIR)) { return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) { return false; } } } return true; } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => false, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => network_site_url('/'), 'enable_cache_per_country' => false, ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000064662 13637420154 032652 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality * * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('WP_Optimize_Detect_Cache_Plugins')) require_once(dirname(__FILE__) . '/class-wpo-detect-cache-plugins.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-php-logger.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (version_compare(PHP_VERSION, '5.3.0') >= 0) { require_once dirname(__FILE__) . '/php-5.3-functions.php'; } wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Store last advanced cache file writing status * If true then last writing finished with error * * @var bool */ public $advanced_cache_file_writing_error; /** * Last advanced cache file content * * @var string */ public $advanced_cache_file_content; /** * Store the latest advanced-cache.php version required * * @var string */ private $_minimum_advanced_cache_file_version = '3.0.17'; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); add_action('activate_plugin', array($this, 'activate_deactivate_plugin')); add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); /** * Regenerate config file on cache flush. */ add_action('wpo_cache_flush', array($this, 'update_cache_config')); add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); // Add purge cache link to admin bar. add_action('admin_bar_menu', array($this, 'wpo_admin_bar_purge_cache'), 100); // Handle single page purge. add_action('wp_loaded', array($this, 'handle_purge_single_page_cache')); add_action('admin_init', array($this, 'admin_init')); } /** * Do required actions on activate/deactivate any plugin. */ public function activate_deactivate_plugin() { $this->update_cache_config(); /** * Filters whether activating / deactivating a plugin will purge the cache. */ if (apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true)) { $this->purge(); } } /** * Check if current user can purge cache. * * @return bool */ public function can_purge_cache() { if (is_multisite()) return $this->is_enabled() && current_user_can('manage_network_options'); return $this->is_enabled() && current_user_can('manage_options'); } /** * Add Purge from cache in admin bar. * * @param WP_Admin_Bar $wp_admin_bar */ public function wpo_admin_bar_purge_cache($wp_admin_bar) { global $pagenow; if (!$this->can_purge_cache()) return; $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); if (!is_admin() || 'post.php' == $pagenow) { $wp_admin_bar->add_menu(array( 'id' => 'wpo_purge_cache', 'title' => __('Purge cache', 'wp-optimize'), 'href' => '#', 'meta' => array( 'title' => __('Purge cache', 'wp-optimize'), ), 'parent' => false, )); $wp_admin_bar->add_node(array( 'id' => 'wpo_purge_this_page_cache', 'title' => __('Purge this page', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), 'meta' => array( 'title' => __('Purge this page', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', )); $wp_admin_bar->add_node(array( 'id' => 'wpo_purge_all_pages_cache', 'title' => __('Purge all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge all pages', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', )); } else { $wp_admin_bar->add_menu(array( 'id' => 'wpo_purge_cache', 'title' => __('Purge all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge all pages', 'wp-optimize'), ), 'parent' => false, )); } } /** * Check if purge single page action sent and purge cache. */ public function handle_purge_single_page_cache() { if (!$this->can_purge_cache()) return; if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { if (isset($_GET['wpo_single_page_cache_purged'])) { $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; } else { $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; } add_action('admin_notices', array($this, $notice_function)); return; } if (!isset($_GET['_wpo_purge'])) return; if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) { $success = false; if (is_admin()) { $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; if ($post > 0) { $success = self::delete_single_post_cache($post); } } else { $success = self::delete_cache_by_url(wpo_current_url()); } // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) { $success = self::purge(); // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } } /** * Show notification when page cache purged successfully. */ public function notice_purge_single_page_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when page cache wasn't purged. */ public function notice_purge_single_page_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification when all pages cache purged successfully. */ public function notice_purge_all_pages_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when all pages cache wasn't purged. */ public function notice_purge_all_pages_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification in WordPress admin. * * @param string $message HTML (no further escaping is performed) * @param string $type error, warning, success, or info */ public function show_notice($message, $type) { ?> <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible"> <p><?php echo $message; ?></p> </div> <script> window.addEventListener('load', function() { (function(wp) { wp.data.dispatch('core/notices').createNotice( '<?php echo $type; ?>', '<?php echo $message; ?>', { isDismissible: true, } ); })(window.wp); }); </script> <?php } /** * Enables page cache * * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings * * @return WP_Error|bool - true on success, error otherwise */ public function enable($force_enable = false) { static $already_ran_enable = false; if ($already_ran_enable) return $already_ran_enable; $folders_created = $this->create_folders(); if (is_wp_error($folders_created)) { $already_ran_enable = $folders_created; return $already_ran_enable; } // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) { $force_enable = true; } if (!$force_enable) { $already_ran_enable = true; return true; } if (!$this->write_advanced_cache() && $this->get_advanced_cache_version() != WPO_VERSION) { $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Your WP install might not have permission to write inside the wp-content folder.', 'wp-optimize'); if (!defined('WP_CLI') || !WP_CLI) { $message .= "\n\n".sprintf(__('1. Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); $message .= "\n".__('2. Edit or create a file with the name advanced-cache.php', 'wp-optimize'); $message .= "\n".__('3. Copy and paste the following lines into the file:', 'wp-optimize'); } $already_ran_enable = new WP_Error("write_advanced_cache", $message); return $already_ran_enable; } if (!$this->write_wp_config(true)) { $already_ran_enable = new WP_Error("write_wp_config", "Could not toggle the WP_CACHE constant in wp-config.php. Check your permissions."); return $already_ran_enable; } if (!$this->verify_cache()) { $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled. Turn on logging to find the reason."); return $already_ran_enable; } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; $advanced_cache_file = $this->get_advanced_cache_filename(); // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); $ret = false; } // N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem. if (!$this->write_wp_config(false)) { $this->log("Could not toggle the WP_CACHE constant in wp-config.php"); $ret = false; } } // Delete cache to avoid stale cache on next activation $this->purge(); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } /** * Fires after purging the cache */ do_action('wpo_cache_flush'); return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (!$this->config->get_option('enable_page_caching', false)) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR))); } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR))); } if (!is_dir(WPO_CACHE_FILES_DIR)) { if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR))); } else { wpo_disable_cache_directories_viewing(); } } return true; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_advanced_cache_filename() { return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; } /** * Writes advanced-cache.php * * @return bool */ private function write_advanced_cache() { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { $config_file_basename = 'config-'.$url['host'].'-port'.$url['port'].'.php'; } else { $config_file_basename = 'config-'.$url['host'].'.php'; } $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__)); $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $cache_path = '/wpo-cache'; $cache_files_path = '/cache/wpo-cache'; $cache_extensions_path = WPO_CACHE_EXT_DIR; $wpo_version = WPO_VERSION; // CS does not like heredoc // phpcs:disable $this->advanced_cache_file_content = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); // WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks) if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); if (is_admin()) { return; } \$possible_plugin_locations = array( defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false, defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false, dirname(__FILE__).'/plugins/$plugin_basename/cache', '$cache_file_basename', ); \$plugin_location = false; foreach (\$possible_plugin_locations as \$possible_location) { if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) { \$plugin_location = \$possible_location; break; } } if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path'); if (false !== \$plugin_location) { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions'); } else { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); } if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; } \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true); if (empty(\$GLOBALS['wpo_cache_config'])) { include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'); } if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); } EOF; // phpcs:enable $advanced_cache_filename = $this->get_advanced_cache_filename(); // check if we can't write the advanced cache file // case 1: the directory is read-only and the file doesn't exist // case 2: the file is already exists but it's read-only if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename)) || (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename))) { $this->advanced_cache_file_writing_error = true; return false; } if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) { $this->advanced_cache_file_writing_error = true; return false; } $this->advanced_cache_file_writing_error = false; return true; } /** * Update advanced cache version if needed. */ public function maybe_update_advanced_cache() { if (!$this->is_enabled()) return; // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php $advanced_cache_current_version = $this->get_advanced_cache_version(); if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return; if (!$this->write_advanced_cache()) { add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); } else { $this->update_cache_config(); } } /** * Show notification when advanced-cache.php could not be updated. */ public function notice_advanced_cache_autoupdate_error() { $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp_optimize'). ' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to re-enable WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error'); } /** * Get WPO version number from advanced-cache.php file. * * @return bool|mixed */ public function get_advanced_cache_version() { if (!is_file($this->get_advanced_cache_filename())) return false; $version = false; $content = file_get_contents($this->get_advanced_cache_filename()); if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { $version = $match[1]; } return $version; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { if (defined('WP_CACHE') && WP_CACHE === $status) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r\n)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) { return false; } return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); return false; } $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; // Now check wp-content. We need to be able to create files of the same user as this file. if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); return false; } // If the cache and config directories exist, make sure they're writeable. if (file_exists(WPO_CACHE_DIR)) { if (!is_writable(WPO_CACHE_DIR)) { $this->log("Unable to write inside the cache folder; please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); return false; } } return true; } /** * Update cache config. Used to support 3d party plugins. */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. $this->config->update($current_config, true); } /** * Delete information about cache size. */ public function delete_cache_size_information() { delete_transient('wpo_get_cache_size'); } /** * Get current cache size. * * @return array */ public function get_cache_size() { $cache_size = get_transient('wpo_get_cache_size'); if (!empty($cache_size)) return $cache_size; $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); $cache_size = array( 'size' => $infos['size'], 'file_count' => $infos['file_count'] ); set_transient('wpo_get_cache_size', $cache_size); return $cache_size; } /** * Fetch directory informations. * * @param string $dir * @return array */ private function get_dir_infos($dir) { $dir_size = 0; $file_count = 0; if (!is_dir($dir)) { return array('size' => 0, 'file_count' => 0); } $files = scandir($dir); foreach ($files as $file) { if ('.' == $file || '..' == $file) continue; $current_file = $dir.'/'.$file; if (is_dir($current_file)) { $sub_dir_infos = $this->get_dir_infos($current_file); $dir_size += $sub_dir_infos['size']; $file_count += $sub_dir_infos['file_count']; } elseif (is_file($current_file)) { $dir_size += filesize($current_file); $file_count++; } } return array('size' => $dir_size, 'file_count' => $file_count); } /** * Returns the path to wp-config * * @return string|boolean wp-config.php path. */ private function _get_wp_config() { $config_path = false; foreach (get_included_files() as $filename) { if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) { $config_path = $filename; break; } } // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file. if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) { $config_path = wpo_wp_cli_locate_wp_config(); } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Delete cached files for specific url. * * @param string $url * @param bool $recursive If true child elements will deleted too * * @return bool */ public static function delete_cache_by_url($url, $recursive = false) { if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url)); return wpo_delete_files($path, $recursive); } /** * Delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function delete_single_post_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path(get_permalink($post_id))); return wpo_delete_files($path, false); } /** * Delete cached home page files. */ public static function delete_homepage_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path(get_home_url(get_current_blog_id()))); wpo_delete_files($path, false); } /** * Admin actions * * @return void */ public function admin_init() { // Maybe update the advanced cache. if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { $this->maybe_update_advanced_cache(); } } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log('ERROR', $message); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/file-based-page-cache-functions.php000644 000000 000000 00000067233 13637401250 034655 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above. * * @param string $buffer Page HTML. * @param int $flags OB flags to be passed through. * @return string */ if (!function_exists('wpo_cache')) : function wpo_cache($buffer, $flags) { global $post; // This array records reasons why no cacheing took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately. $no_cache_because = array(); if (strlen($buffer) < 255) { $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth cacheing', 'wp-optimize'), 255); } // Don't cache pages for logged in users. if (!function_exists('is_user_logged_in') || is_user_logged_in()) { $no_cache_because[] = __('User is logged in', 'wp-optimize'); } $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_page_type_cache) { $no_cache_because[] = $restricted_page_type_cache; } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) { $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')'; } elseif (!file_exists(WPO_CACHE_FILES_DIR)) { // Try creating a folder for cached files, if it was flushed recently if (!mkdir(WPO_CACHE_FILES_DIR)) { $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')'; } else { wpo_disable_cache_directories_viewing(); } } // If comments are opened and the user has saved his information if (function_exists('comments_open') && comments_open()) { $commenter = wp_get_current_commenter(); // if any of the fields contain something, do not save to cache if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) { $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize'); } } $can_cache_page = (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) ? false : true; /** * Defines if the page can be cached or not * * @param boolean $can_cache_page */ $can_cache_page = apply_filters('wpo_can_cache_page', $can_cache_page); if (!$can_cache_page) { $no_cache_because[] = __('DONOTCACHEPAGE constant or wpo_can_cache_page filter forbade it', 'wp-optimize'); } if (defined('REST_REQUEST') && REST_REQUEST) { $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize'); } if (empty($no_cache_because)) { $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)"; break; } } } } } if (!empty($no_cache_because)) { // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) { $buffer .= "\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached because: ".implode(', ', array_filter($no_cache_because, 'htmlspecialchars'))." -->\n"; } return $buffer; } else { // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } $modified_time = time(); // Take this as soon before writing as possible $add_to_footer = ''; /** * Filter wether to display the html comment <!-- Cached by WP-Optimize ... --> * * @param boolean $show - Wether to display the html comment * @return boolean */ if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } // Create an empty index.php file in the cache directory for disable directory viewing. if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', ''); /** * Save $buffer into cache file. */ $cache_filename = wpo_cache_filename(); $cache_file = $path . '/' .$cache_filename; // if we can then cache gzipped content in .gz file. if (function_exists('gzencode')) { // Only replace inside the addition, not inside the main buffer (e.g. post content) file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6))); } file_put_contents($cache_file, $buffer.$add_to_footer); // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); if (wpo_cache_can_output_gzip_content()) { if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) { header('Content-Encoding: gzip'); } // disable php gzip to avoid double compression. ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set return ob_gzhandler($buffer, $flags); } else { return $buffer; } } } endif; /** * Load files for support plugins. */ if (!function_exists('wpo_cache_load_extensions')) : function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); // Add external extensions if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) { $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php')); } if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } endif; if (!function_exists('wpo_restricted_cache_page_type')) { function wpo_restricted_cache_page_type($restricted) { global $post; // Don't cache search or password protected. if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) { $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize'); } // Don't cache the front page if option is set. if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) { $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize'); } // Don't cache htacesss. Remember to properly escape any output to prevent injection. if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')'; } return $restricted; } } /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ if (!function_exists('wpo_cache_filename')) : function wpo_cache_filename($ext = '.html') { $filename = 'index'; if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. * This section was inspired by things learned from WP-Rocket. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } // add hash of queried cookies and variables to cache file name. if ('' !== $cache_key) { $filename .= '-' . md5($cache_key); } return $filename . $ext; } endif; /** * Returns site url from site_url() function or if it is not available from cache configuration. */ if (!function_exists('wpo_site_url')) : function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } endif; /** * Get cookie names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_cookies')) : function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } endif; /** * Get GET variable names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_query_variables')) : function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return wpo_cache_maybe_ignore_query_variables($variables); } endif; /** * Get list of all received HTTP headers. * * @return array */ if (!function_exists('wpo_get_http_headers')) : function wpo_get_http_headers() { static $headers; if (!empty($headers)) return $headers; $headers = array(); // if is apache server then use get allheaders() function. if (function_exists('getallheaders')) { $headers = getallheaders(); } else { // https://www.php.net/manual/en/function.getallheaders.php foreach ($_SERVER as $key => $value) { $key = strtolower($key); if ('HTTP_' == substr($key, 0, 5)) { $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value; } elseif ('content_type' == $key) { $headers["Content-Type"] = $value; } elseif ('content_length' == $key) { $headers["Content-Length"] = $value; } } } return $headers; } endif; /** * Check if requested Accept-Encoding headers has gzip value. * * @return bool */ if (!function_exists('wpo_cache_gzip_accepted')) : function wpo_cache_gzip_accepted() { $headers = wpo_get_http_headers(); if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true; return false; } endif; /** * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value * and function ob_gzhandler is available. * * @return bool */ if (!function_exists('wpo_cache_can_output_gzip_content')) : function wpo_cache_can_output_gzip_content() { return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler'); } endif; /** * Check if header with certain name exists in already prepared headers and has value comparable with $header_value. * * @param string $header_name header name * @param string $header_value header value as regexp. * * @return bool */ if (!function_exists('wpo_cache_is_in_response_headers_list')) : function wpo_cache_is_in_response_headers_list($header_name, $header_value) { $headers_list = headers_list(); if (!empty($headers_list)) { $header_name = strtolower($header_name); foreach ($headers_list as $value) { $value = explode(':', $value); if (strtolower($value[0]) == $header_name) { if (preg_match('/'.$header_value.'/', $value[1])) { return true; } else { return false; } } } } return false; } endif; /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ if (!function_exists('wpo_cache_mobile_caching_enabled')) : function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } endif; /** * Serves the cache and exits */ if (!function_exists('wpo_serve_cache')) : function wpo_serve_cache() { $file_name = wpo_cache_filename(); $path = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/' . $file_name; $use_gzip = false; // if we can use gzip and gzipped file exist in cache we use it. // if headers already sent we don't use gzipped file content. if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) { $path .= '.gz'; $use_gzip = true; } $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } // disable zlib output compression to avoid double content compression. if ($use_gzip) { ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set } $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip'); header('Cache-Control: no-cache'); // Check back later if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } // send correct headers for xml and txt files $filename = basename(dirname($path)); if (preg_match('/\.xml$/i', $filename)) { header('Content-type: text/xml'); } if (preg_match('/\.txt$/i', $filename)) { header('Content-type: text/plain'); } readfile($path); exit; } } endif; /** * Clears the cache */ if (!function_exists('wpo_cache_flush')) : function wpo_cache_flush() { if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } endif; /** * Get URL path for caching * * @since 1.0 * @return string */ if (!function_exists('wpo_get_url_path')) : function wpo_get_url_path($url = '') { $url = '' == $url ? wpo_current_url() : $url; $url_parts = parse_url($url); if (!isset($url_parts['host'])) $url_parts['host'] = ''; if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].$url_parts['path']; } endif; /** * Get requested url. * * @return string */ if (!function_exists('wpo_current_url')) : function wpo_current_url() { // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot). // Otherwise this function would return a different URL at the begining and end of the cache process. static $url = ''; if ('' != $url) return $url; $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . $http_host.$_SERVER['REQUEST_URI'], '/'); return $url; } endif; /** * Return list of url exceptions. * * @return array */ if (!function_exists('wpo_get_url_exceptions')) : function wpo_get_url_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; // if called from file-based-page-cache.php when WP loading // and cache settings exists then use it otherwise get settings from database. if (isset($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = array(); } else { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); } } else { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_urls', $config)) { $exceptions = $config['cache_exception_urls']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } return $exceptions; } endif; /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ if (!function_exists('wpo_current_url_exception_match')) : function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } endif; /** * Check if url in exceptions list. * * @param string $url * * @return bool */ if (!function_exists('wpo_url_in_exceptions')) : function wpo_url_in_exceptions($url) { $exceptions = wpo_get_url_exceptions(); if (!empty($exceptions)) { foreach ($exceptions as $exception) { // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type() if ('/' == $exception) continue; if (wpo_url_exception_match($url, $exception)) { // Exception match. return true; } } } return false; } endif; /** * Check if url string match with exception. * * @param string $url - complete url string i.e. http(s):://domain/path * @param string $exception - complete url or absolute path, can consist (.*) wildcards * * @return bool */ if (!function_exists('wpo_url_exception_match')) : function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // used to test websites placed in subdirectories. $sub_dir = ''; // if exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = rtrim($url, '/') . '/'; $exception = rtrim($exception, '/'); // if we have no wildcat in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = str_replace('/', '\/', $exception); return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url); } endif; /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ if (!function_exists('wpo_is_mobile')) : function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } endif; /** * Check if current browser agent is not disabled in options. * * @return bool */ if (!function_exists('wpo_is_accepted_user_agent')) : function wpo_is_accepted_user_agent($user_agent) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } endif; /** * Delete function that deals with directories recursively * * @param string $src Path of the folder * @param boolean $recursive If $src is a folder, recursively delete the inner folders. If set to false, only the files will be deleted. * * @return bool */ if (!function_exists('wpo_delete_files')) : function wpo_delete_files($src, $recursive = true) { if (!file_exists($src) || '' == $src || '/' == $src) { return true; } if (is_file($src)) { return unlink($src); } $success = true; $has_dir = false; if ($recursive) { // N.B. If opendir() fails, then a false positive (i.e. true) will be returned if (false !== ($dir = opendir($src))) { $file = readdir($dir); while (false !== $file) { if ('.' == $file || '..' == $file) { $file = readdir($dir); continue; } if (is_dir($src . '/' . $file)) { if (!wpo_delete_files($src . '/' . $file)) { $success = false; } } else { if (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($dir); } closedir($dir); } } else { // Not recursive, so we only delete the files $files = scandir($src); foreach ($files as $file) { if ('.' == $file || '..' == $file) continue; if (is_dir($src . '/' . $file)) { $has_dir = true; continue; } if (!unlink($src . '/' . $file)) { $success = false; } } } if ($success && !$has_dir) { // Success of this operation is not recorded; we only ultimately care about emptying, not removing entirely (empty folders in our context are harmless) rmdir($src); } // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); return $success; } endif; /** * Either store for later output, or output now. Only the most-recent call will be effective. * * @param String|Null $output - if not null, then the string to use when called by the shutdown action. */ if (!function_exists('wpo_cache_add_footer_output')) : function wpo_cache_add_footer_output($output = null) { static $buffered = null; if (function_exists('current_filter') && 'shutdown' == current_filter()) { // Only add the line if it was a page, not something else (e.g. REST response) if (function_exists('did_action') && did_action('wp_footer')) { echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".$buffered." -->\n"; } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG) { error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered); } } else { if (null == $buffered && function_exists('add_action')) add_action('shutdown', 'wpo_cache_add_footer_output', 11); $buffered = $output; } } endif; /** * Remove variable names that shouldn't influence cache. * * @param array $variables List of variable names. * * @return array */ if (!function_exists('wpo_cache_maybe_ignore_query_variables')) : function wpo_cache_maybe_ignore_query_variables($variables) { /** * Filters the current $_GET variables that will be used when caching or excluding from cache. * Currently: * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set) * - 'doing_wp_cron' (alternative cron) * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap) * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap) * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap) */ $exclude_variables = array( 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set 'doing_wp_cron', // alternative cron 'aiosp_sitemap_path', // All in one SEO sitemap 'aiosp_sitemap_page', 'xml_sitemap', // SEOPress sitemap 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged', 'sitemap', // YOAST SEO sitemap 'sitemap_n', ); $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables; if (empty($exclude_variables)) return $variables; foreach ($exclude_variables as $variable) { $exclude = array_search($variable, $variables); if (false !== $exclude) { array_splice($variables, $exclude, 1); } } return $variables; } endif; /** * Get cache config * * @param string $key - The config item * @param mixed $default - The default value * * @return mixed */ if (!function_exists('wpo_cache_config_get')) : function wpo_cache_config_get($key, $default = false) { $config = $GLOBALS['wpo_cache_config']; if (!$config) return false; if (isset($config[$key])) { return $config[$key]; } else { return $default; } } endif; if (!function_exists('wpo_disable_cache_directories_viewing')) : function wpo_disable_cache_directories_viewing() { global $is_apache, $is_IIS, $is_iis7; if (!is_dir(WPO_CACHE_FILES_DIR)) return; // Create .htaccess file for apache server. if ($is_apache) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // CS does not like heredoc // phpcs:disable $htaccess_content = <<<EOF # Disable directory browsing Options -Indexes # Disable access to any files <FilesMatch ".*"> Order allow,deny Deny from all </FilesMatch> EOF; // phpcs:enable if (!is_file($htaccess_filename)) @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create web.config file for IIS servers. if ($is_IIS || $is_iis7) { $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config'; $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n"; if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create empty index.php file for all servers. if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', '');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000017611 13637401250 033054 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1); add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2); add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6); add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1); /** * List of hooks for which when executed, the cache will be purged * * @param array $actions The actions */ $purge_on_action = apply_filters('wpo_purge_cache_hooks', array('after_switch_theme', 'wp_update_nav_menu', 'customize_save_after', array('wp_ajax_save-widget', 0), array('wp_ajax_update-widget', 0), 'autoptimize_action_cachepurged')); foreach ($purge_on_action as $action) { if (is_array($action)) { add_action($action[0], array($this, 'purge_cache'), $action[1]); } else { add_action($action, array($this, 'purge_cache')); } } } /** * Purge post cache when there is a new approved comment * * @param int $comment_id Comment ID. * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'. * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/ */ public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) { if (1 !== $approved) { return; } if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) { $post_id = $commentdata['comment_post_ID']; WPO_Page_Cache::delete_single_post_cache($post_id); } } /** * Every time a comment's status changes, purge it's parent posts cache * * @param int $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (!empty($this->config['enable_page_caching'])) { $comment = get_comment($comment_id); if (is_object($comment) && !empty($comment->comment_post_ID)) WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID); } } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } /** * Purge the whole cache if set to true, only the edited post otherwise. Default is false. * * @param boolean $purge_all_cache The default filter value * @param integer $post_id The saved post ID */ if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) { $this->purge_cache(); return; } else { if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::delete_single_post_cache($post_id); } } /** * Purge archive pages on post update. * * @param integer $post_id */ public function purge_archive_pages_on_post_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } $post_obj = get_post_type_object($post_type); if ('post' == $post_type) { // delete all archive pages for post. $post_date = get_post_time('Y-m-j', false, $post_id); list($year, $month, $day) = $post_date; $archive_links = array( get_year_link($year), get_month_link($year, $month), get_day_link($year, $month, $day), ); foreach ($archive_links as $link) { WPO_Page_Cache::delete_cache_by_url($link, true); } } elseif ($post_obj->has_archive) { // delete archive page for custom post type. WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true); } } /** * We use it with edit_terms action filter to purge cached elements related * to updated term when term updated. * * @param int $term_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. */ public function purge_related_elements_on_term_updated($term_id, $taxonomy) { // purge cached page for term. $term = get_term($term_id, $taxonomy, ARRAY_A); if (is_array($term)) { $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } // get posts which belongs to updated term. $posts = get_posts(array( 'numberposts' => -1, 'post_type' => 'any', 'fields' => 'ids', 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $term_id, ) ), )); if (!empty($posts)) { foreach ($posts as $post_id) { WPO_Page_Cache::delete_single_post_cache($post_id); } } } /** * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) { $post_type = get_post_type($object_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } // get all affected terms. $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids)); if (!empty($affected_terms_ids)) { // walk through all changed terms and purge cached pages for them. foreach ($affected_terms_ids as $tt_id) { $term = get_term($tt_id, $taxonomy, ARRAY_A); if (!is_array($term)) continue; $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } } } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Triggered by wpo_cache_config_updated. * * @param array $config */ public function cache_config_updated($config) { // delete front page form cache if defined in the settings if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) { WPO_Page_Cache::delete_cache_by_url(home_url()); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-detect-cache-plugins.php 000644 000000 000000 00000004277 13477736574 034624 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ private function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $plugins = array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); $active_cache_plugins = array(); foreach ($plugins as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { if (empty(self::$instance)) { self::$instance = new WP_Optimize_Detect_Cache_Plugins(); } return self::$instance; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-cache-preloader.php 000644 000000 000000 00000063156 13614520640 033704 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!class_exists('Updraft_Task_Manager_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php'); if (!class_exists('WP_Optimize_Load_Url_Task')) require_once(dirname(__FILE__) . '/class-wpo-load-url-task.php'); class WP_Optimize_Page_Cache_Preloader extends Updraft_Task_Manager_1_2 { private $task_type = 'load-url-task'; private $options; static protected $_instance = null; /** * WP_Optimize_Page_Cache_Preloader constructor. */ public function __construct() { parent::__construct(); $this->options = WP_Optimize()->get_options(); // setup loggers $this->set_loggers(WP_Optimize()->wpo_loggers()); add_filter('cron_schedules', array($this, 'cron_add_intervals')); add_action('wpo_page_cache_preload_continue', array($this, 'process_tasks_queue')); add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload')); add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20); } /** * Check if cache is active. * * @return bool */ public function is_cache_active() { return WP_Optimize()->get_page_cache()->is_enabled(); } /** * Schedule or delete automatic preload action on cache settings update. * * @param array $new_settings The new settings * @param array $previous_settings Settings before saving */ public function cache_settings_updated($new_settings, $previous_settings) { if (!$new_settings['enable_page_caching']) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); $this->delete_preload_continue_action(); return; } if (!empty($new_settings['enable_schedule_preload'])) { $last_schedule_type = $previous_settings['preload_schedule_type']; if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { // if already scheduled this schedule type if ($new_settings['preload_schedule_type'] == $last_schedule_type) { // If the schedule type is cache lifespan, check if the cache lifespan changed. if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) { // Else, if the settings cache lifespan settings haven't changed, returns if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) { return; } } else { return; } } // clear currently scheduled preload action. wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action. wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload'); } else { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } } /** * Clear active preload tasks, reschedule preload action. */ public function reschedule_preload() { // clear scheduled action. if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action if need. if ($this->is_scheduled_preload_enabled()) { $preload_schedule_type = $this->get_cache_config('preload_schedule_type'); wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload'); } } /** * Check if scheduled preload enabled. * * @return bool */ public function is_scheduled_preload_enabled() { $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload'); return !empty($enable_schedule_preload); } /** * Get a schedule interval * * @param string $schedule_key The schedule to check * @return integer */ private function get_schedule_interval($schedule_key) { $schedules = wp_get_schedules(); if (!isset($schedules[$schedule_key])) { $this->log('Could not get interval for event of type '.$schedule_key); return 0; } return isset($schedules[$schedule_key]['interval']) ? $schedules[$schedule_key]['interval'] : 0; } /** * Add intervals to cron schedules. * * @param array $schedules * * @return array */ public function cron_add_intervals($schedules) { $interval = $this->get_continue_preload_cron_interval(); $schedules['wpo_page_cache_preload_continue_interval'] = array( 'interval' => $interval, 'display' => round($interval / 60, 1).' minutes' ); $schedules['wpo_use_cache_lifespan'] = array( 'interval' => WPO_Cache_Config::instance()->get_option('page_cache_length'), 'display' => 'Same as cache lifespan: '.WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit') ); return $schedules; } /** * Get the interval to continuing a preload task * * @return integer */ private function get_continue_preload_cron_interval() { /** * Filters the interval between each preload attempt, in seconds. */ return (int) apply_filters('wpo_page_cache_preload_continue_interval', 600); } /** * Schedule action for continuously preload. */ public function schedule_preload_continue_action() { $continue_in = wp_next_scheduled('wpo_page_cache_preload_continue'); // Action is still scheduled if ($continue_in && $continue_in > 0) return; // Action is overdue, delete it and re schedule it if ($continue_in && $continue_in < 0) $this->delete_preload_continue_action(); wp_schedule_event(time() + $this->get_schedule_interval('wpo_page_cache_preload_continue_interval'), 'wpo_page_cache_preload_continue_interval', 'wpo_page_cache_preload_continue'); } /** * Delete scheduled action for continuously preload. */ public function delete_preload_continue_action() { wp_clear_scheduled_hook('wpo_page_cache_preload_continue'); } /** * Run cache preload. If task queue is empty it creates tasks for site urls. * * @param string $type - The preload type (schedule | manual) * @param array $response - Specific response for echo into output thread when browser connection closing. * @return array|void - Void when closing the browser connection */ public function run($type = 'scheduled', $response = null) { if (!$this->is_cache_active()) { return array( 'success' => false, 'error' => __('Page cache is disabled.', 'wp-optimize') ); } if (empty($response)) { $response = array('success' => true); } $is_wp_cli = defined('WP_CLI') && WP_CLI; // close browser connection and continue work. // don't close connection for WP-CLI if (false == $is_wp_cli) { WP_Optimize()->close_browser_connection(json_encode($response)); } // trying to change time limit. WP_Optimize()->change_time_limit(); $status = $this->get_status($this->task_type); if (0 == $status['all_tasks']) { if (is_multisite()) { $sites = WP_Optimize()->get_sites(); foreach ($sites as $site) { switch_to_blog($site->blog_id); $this->create_tasks_for_preload_site_urls($type); restore_current_blog(); } } else { $this->create_tasks_for_preload_site_urls($type); } } $this->process_tasks_queue(); // return $response in WP-CLI mode if ($is_wp_cli) { return $response; } } /** * Check if we need run cache preload and run it. */ public function run_scheduled_cache_preload() { $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); if (!$schedule_type) return; // Don't run preload if cache lifespan option enabled and cache not expired yet. if ('wpo_use_cache_lifespan' == $schedule_type) { /** * Filters the allowed time difference between the cache exiry and the current time, in seconds. * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it. * * @param integer $allowed_time_difference The time difference, in seconds (default = 600) */ $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', 600); $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0); $time_since_last_preload = time() - $last_preload_time; $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference; // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return; } $this->run(); } /** * Process tasks queue. */ public function process_tasks_queue() { // schedule continue preload action. $this->schedule_preload_continue_action(); if (!$this->process_queue($this->task_type)) { return; } // delete scheduled continue preload action. $this->delete_preload_continue_action(); // update last cache preload time only if processing any tasks, else process was cancelled. if ($this->is_running()) { $this->options->update_option('wpo_last_page_cache_preload', time(), false); } $this->clean_up_old_tasks($this->task_type); } /** * Find out if the current queue should be interrupted * * @param boolean $interrupt * @return boolean */ public function maybe_interrupt_queue($interrupt) { if ($interrupt) return $interrupt; static $memory_threshold = null; if (null == $memory_threshold) { /** * Filters the minimum memory required before stopping a queue. Default: 10MB */ $memory_threshold = apply_filters('wpo_page_cache_preload_memory_threshold', 10485760); } return WP_Optimize()->get_free_memory() < $memory_threshold; } /** * Delete all preload tasks from queue. */ public function cancel_preload() { $this->delete_tasks($this->task_type); $this->delete_preload_continue_action(); } /** * Check if preloading queue is processing. * * @return bool */ public function is_busy() { $is_busy = false; // Trying to lock queue semaphore and if we can't lock then assume the queue is processing. $queue_semaphore = new Updraft_Semaphore_2_1($this->task_type); $lock = $queue_semaphore->lock(); if (!$lock) { $is_busy = true; } else { $queue_semaphore->unlock(); } return $is_busy; } /** * Get current status of preloading urls. * * @return array */ public function get_status_info() { $status = $this->get_status($this->task_type); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); if ($status['complete_tasks'] == $status['all_tasks']) { $gmt_offset = (int) (3600 * get_option('gmt_offset')); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload'); if ($last_preload_time) { $last_preload_time_str = date_i18n(get_option('time_format').', '.get_option('date_format'), $last_preload_time + $gmt_offset); return array( 'done' => true, 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } else { return array( 'done' => true, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } } else { $preload_resuming_time = wp_next_scheduled('wpo_page_cache_preload_continue'); $preload_resuming_in = $preload_resuming_time ? $preload_resuming_time - time() : 0; $return = array( 'done' => false, 'message' => sprintf(_n('%1$s of %2$s URL preloaded', '%1$s of %2$s URLs preloaded', $status['all_tasks'], 'wp-optimize'), $status['complete_tasks'], $status['all_tasks']), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], 'resume_in' => $preload_resuming_in ); if (defined('DOING_AJAX') && DOING_AJAX) { // if no cron was found or cron is overdue more than 20s, trigger it if (!$preload_resuming_time || $preload_resuming_in < -20) { $this->run($return); } } return $return; } } /** * Check if preload action in process. * * @return bool */ public function is_running() { $status = $this->get_status($this->task_type); if ($status['all_tasks'] > 0) return true; } /** * Get cache config option value. * * @return mixed */ public function get_cache_config($option) { static $config = null; if (null === $config) $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists($option, $config)) { return $config[$option]; } return false; } /** * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site. * * @param string $type The preload type (currently: scheduled, manual) * @return void */ public function create_tasks_for_preload_site_urls($type) { $urls = $this->get_site_urls(); if (!empty($urls)) { $this->log(__('Creating tasks for preload site urls.', 'wp-optimize')); foreach ($urls as $url) { if (wpo_url_in_exceptions($url)) continue; if ($this->url_is_already_cached($url, $type)) { continue; } // this description is being used for internal purposes. $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->log(__('Tasks for preload site urls created.', 'wp-optimize')); } } /** * Preload desktop version from url. * * @param string $url * * @return void */ public function preload_desktop($url) { $desktop_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, ); $desktop_args = apply_filters('wpo_page_cache_preloader_desktop_args', $desktop_args, $url); $this->log('preload_desktop - '. $url); wp_remote_get($url, $desktop_args); } /** * Preload mobile version from $url. * * @param string $url * * @return void */ public function preload_mobile($url) { static $is_mobile_caching_enabled; if (!isset($is_mobile_caching_enabled)) { $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching'); } // Only run if option is active if (!$is_mobile_caching_enabled) return; $mobile_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', 'timeout' => 10, ); $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url); $this->log('preload_mobile - ' . $url); wp_remote_get($url, $mobile_args); } /** * Preload amp version from $url. * * @param string $url * * @return void */ public function preload_amp($url) { if (!apply_filters('wpo_should_preload_amp', false, $url)) return; $amp_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, ); $url = untrailingslashit($url) . '/amp/'; $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url); $this->log('preload_amp - ' . $url); wp_remote_get($url, $amp_args); } /** * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls. * * @return array */ public function get_site_urls() { if ($this->exists_sitemap_file()) { $urls = $this->get_sitemap_urls(); } else { $urls = $this->get_post_urls(); } $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls))); return $urls; } /** * Check if sitemap file is exists. * * @return bool */ public function exists_sitemap_file() { $response = wp_remote_get(site_url('/sitemap.xml'), array('timeout' => 10)); if (is_wp_error($response) || '200' != wp_remote_retrieve_response_code($response)) { $sitemap_file = $this->get_local_sitemap_file(); if (is_file($sitemap_file)) { return true; } else { return false; } } else { return true; } } /** * Loads sitemap file and returns list of urls. * * @param string $sitemap_url * * @return array|bool */ public function get_sitemap_urls($sitemap_url = '') { $urls = array(); // if sitemap url is empty then use main sitemap file name. $sitemap_url = ('' === $sitemap_url) ? site_url('/sitemap.xml') : $sitemap_url; // if simplexml_load_string not available then we don't load sitemap. if (!function_exists('simplexml_load_string')) { return $urls; } // load sitemap file. $response = wp_remote_get($sitemap_url, array('timeout' => 30)); // if we get error then if (is_wp_error($response)) { $response = file_get_contents($sitemap_url); // if response is empty then try load from file. if (empty($response) && '' == $sitemap_url) { $sitemap_file = $this->get_local_sitemap_file(); $response = file_get_contents($sitemap_file); } if (empty($response)) return $urls; $xml = simplexml_load_string($response); } else { // parse xml answer. $xml = simplexml_load_string(wp_remote_retrieve_body($response)); } // if exists urls then return them. if (isset($xml->url)) { foreach ($xml->url as $element) { if (!isset($element->loc)) continue; $urls[] = (string) $element->loc; } } elseif (isset($xml->sitemap)) { // if has links to other sitemap files then get urls from them. foreach ($xml->sitemap as $element) { if (!isset($element->loc)) continue; $urls = array_merge($urls, $this->get_sitemap_urls($element->loc)); } } return $urls; } /** * Get the path to a local sitemap.xml file * * @return string */ private function get_local_sitemap_file() { if (!function_exists('get_home_path')) { include_once ABSPATH . '/wp-admin/includes/file.php'; } return trailingslashit(get_home_path()) . 'sitemap.xml'; } /** * Get all posts of any post type and returns urls for them. * * @return array */ public function get_post_urls() { $offset = 0; $posts_per_page = 1000; $urls = array(); $urls[] = site_url('/'); do { $query = new WP_Query(array( 'post_type' => 'any', 'post_status' => 'publish', 'posts_per_page' => $posts_per_page, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'cache_results' => false, // disable cache to avoid memory error. )); $posts_loaded = $query->post_count; while ($query->have_posts()) { $query->the_post(); $urls[] = get_permalink(); } $offset += $posts_loaded; } while ($posts_loaded > 0); /** * If domain mapping enabled then replace domains in urls. */ if ($this->is_domain_mapping_enabled()) { $blog_id = get_current_blog_id(); $mapped_domain = $this->get_mapped_domain($blog_id); $blog_details = get_blog_details($blog_id); if ($mapped_domain) { foreach ($urls as $i => $url) { $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1); } } } wp_reset_postdata(); return $urls; } /** * Check if domain mapping enabled. * * @return bool */ public function is_domain_mapping_enabled() { // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin. $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE); /** * Filters if Multisite Domain mapping is enabled. * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use. * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option. */ return apply_filters('wpo_is_domain_mapping_enabled', $enabled); } /** * Return mapped domain by $blog_id. * * @param int $blog_id * * @return string */ public function get_mapped_domain($blog_id) { global $wpdb; $domain = ''; $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) { // This table created in WordPress MU Domain Mapping plugin. $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A); if (!empty($row)) { $domain = $row['domain']; } } else { // When using the WP Core method, the site url option contains the mapped domain. $domain = get_site_url($blog_id); } /** * Filters the mapped domain name * * @param string $domain The domain name * @param integer $blog_id The blog ID */ return apply_filters('wpo_get_mapped_domain', $domain, $blog_id); } /** * Captures and logs any interesting messages * * @param String $message - the error message * @param String $error_type - the error type */ public function log($message, $error_type = 'info') { if (isset($this->loggers)) { foreach ($this->loggers as $logger) { $logger->log($error_type, $message); } } } /** * Instance of WP_Optimize_Page_Cache_Preloader. * * @return WP_Optimize_Page_Cache_Preloader */ public static function instance() { if (empty(self::$_instance)) { self::$_instance = new WP_Optimize_Page_Cache_Preloader(); } return self::$_instance; } /** * Check if the URL is already cached, or needs to be preloaded * * @param string $url The preloaded url * @param string $preload_type The preload type (manual | scheduled) * @return boolean */ private function url_is_already_cached($url, $preload_type) { static $files = array(); $regenerate_count = 0; $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url); // If the folder does not exist, consider the URL as cleared if (!is_dir($folder)) return false; if (empty($files)) { // Check only the base files $files[] = 'index.html'; if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) { $files[] = 'mobile.index.html'; } $files = apply_filters('wpo_maybe_clear_files_list', $files); } foreach ($files as $file) { $file_path = trailingslashit($folder).$file; if (!file_exists($file_path)) { // The file does not exist, count it as "deleted" $regenerate_count++; continue; } if ($this->should_regenerate_file($file_path, $preload_type)) { // delefe the expired cache file unlink($file_path); $regenerate_count++; } } // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted. return 0 == $regenerate_count; } /** * Determine if a file should be regenerated * * @param string $path The file to check * @param string $preload_type The preload type (manual | scheduled) * * @return boolean */ private function should_regenerate_file($path, $preload_type) { // Store the variables, as they'll be used for each file and each file static $is_preloader_scheduled = null; static $lifespan = null; static $schedule_type = null; static $schedule_interval = null; static $lifespan_expiry_threshold = null; static $always_regenerate_file_if_preload_is_manual = null; static $always_regenerate_file_if_preload_is_scheduled = null; static $regenerate_file_when_no_expiry_date = null; // Sets the variables once per request: if (null === $is_preloader_scheduled) { $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload'); $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length'); $schedule_interval = $this->get_schedule_interval($schedule_type); /** * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min) */ $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600); /** * Filters if a cache should systematically be regenerated when running a manual preload. Default: false */ $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false); /** * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false */ $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false); /** * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true */ $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true); } if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) { $result = true; } else { $modified_time = (int) filemtime($path); // cache lifespan is set. if (0 != $lifespan) { $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold; $result = time() > $expiry_time; } elseif ($is_preloader_scheduled) { $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold; $result = time() > $expiry_time; } else { $result = $regenerate_file_when_no_expiry_date; } } return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type); } } WP_Optimize_Page_Cache_Preloader::instance(); cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-wpo-load-url-task.php 000644 000000 000000 00000003024 13637401250 033331 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('Access denied.'); if (!class_exists('Updraft_Task_1_1')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); class WP_Optimize_Load_Url_Task extends Updraft_Task_1_1 { /** * Default options. */ public function get_default_options() { return array(); } /** * Run preload http requests with different user-agent values to cache pages for different devices. * * @return bool */ public function run() { $url = $this->get_option('url'); if (empty($url)) return; $cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); // load pages with different user-agents values. $cache_preloader->preload_desktop($url); $cache_preloader->preload_mobile($url); $cache_preloader->preload_amp($url); if (defined('WP_CLI') && WP_CLI) { WP_CLI::log($url); } /** * Action triggered after preloading a single url * * @param string $url The url to preload * @param object $cache_preloader Cache preloader instance */ do_action('wpoptimize_after_preload_url', $url, $cache_preloader); /** * Allows to change the delay between each URL preload, to reduce server load. * * @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second). */ usleep(apply_filters('wpoptimize_preload_delay', 500000)); return true; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.0/wp-optimize/cache/class-cache-commands.php 000644 000000 000000 00000016305 13614520640 032717 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); $enabled = false; $return = array(); $previous_settings = WPO_Cache_Config::instance()->get(); // disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { WPO_Page_Cache::instance()->disable(); } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. $enabled = WPO_Page_Cache::instance()->enable(true); } if (is_wp_error($enabled)) { // disable everything, to avoid half enabled things WPO_Page_Cache::instance()->disable(); // deactivate the setting $data['cache-settings']['enable_page_caching'] = null; $return['error'] = array( 'code' => $enabled->get_error_code(), 'message' => $enabled->get_error_message() ); } $skip_if_no_file_yet = (!$enabled || is_wp_error($enabled)); $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet); if ($save_settings_result) { WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings); } $return['result'] = $save_settings_result; $return['enabled'] = !empty($data['cache-settings']['enable_page_caching']); if (is_wp_error($enabled) && WPO_Page_Cache::instance()->advanced_cache_file_writing_error) { $return['advanced_cache_file_writing_error'] = true; $return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content; } return $return; } /** * Get information about current cache status. Used in cli commands. * * @return array */ public function get_status_info() { $status = array(); $settings = WPO_Cache_Config::instance()->get(); $status[] = $settings['enable_page_caching'] ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize'); $preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); $status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']); $status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']); if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message']; $status['message'] = join(PHP_EOL, $status); return $status; } /** * Enable cache. */ public function enable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = true; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Disable cache. */ public function disable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = false; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Purge WP-Optimize page cache. * * @return array */ public function purge_page_cache() { $purged = WP_Optimize()->get_page_cache()->purge(); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); $response = array( 'success' => $purged, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], ); // if scheduled preload enabled then reschedule and run preloader. if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) { // cancel preload and reschedule preload action. $wpo_page_cache_preloader->cancel_preload(); $wpo_page_cache_preloader->reschedule_preload(); // run preloader. $wpo_page_cache_preloader->run('scheduled', $response); } if ($response['success']) { $response['message'] = __('Page cache purged successfully', 'wp-optimize'); } return $response; } /** * Run cache preload (for wp-cli). * * @return array|bool */ public function run_cache_preload_cli() { global $wpdb; if (!(defined('WP_CLI') && WP_CLI)) return false; // define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file // but we check this constant value wen detecting status of cache if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); // don't interrupt queue processing add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99); // if preloading is running then exit. if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) { return array( 'success' => false, 'error' => __('Preloading is currently running in another process.', 'wp-optimize'), ); } // set default response. $response = array( 'success' => true, 'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'), ); WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize')); return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response); } /** * Run cache preload action. * * @return void|array - Doesn't return anything if run() is successfull (Run() prints a JSON object and closed browser connection) or an array if failed. */ public function run_cache_preload() { return WP_Optimize_Page_Cache_Preloader::instance()->run('manual'); } /** * Cancel cache preload action. * * @return array */ public function cancel_cache_preload() { WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload(); return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Get status of cache preload. * * @return array */ public function get_cache_preload_status() { return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } /** * Format save_cache_settings() result for displaying in WP-CLI console * * @param array $response * @return array */ private function format_save_cache_settings_response($response) { $result = array( 'success' => $response['result'], ); if (isset($response['error'])) { $result['success'] = false; $result['error'] = $response['error']['message']; } if ($result['success']) { $result['message'] = __('Page cache settings updated successfully.', 'wp-optimize'); } return $result; } } cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/ 000755 000000 000000 00000000000 14214670220 025170 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/ 000755 000000 000000 00000000000 14214670220 026233 5 ustar 00root wheel 000000 000000 wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/file-based-page-cache-functions.php000644 000000 000000 00000030077 13477736574 034701 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser * * @param string $buffer Page HTML. * @param int $flags OB flags to be passed through. * @return string */ function wpo_cache($buffer, $flags) { global $post; if (strlen($buffer) < 255) { return $buffer; } // Don't cache pages for logged in users. if (is_user_logged_in()) { return $buffer; } // Don't cache search, 404, or password protected. if (is_404() || is_search() || !empty($post->post_password)) { return $buffer; } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) return $buffer; // Try creating a folder for cached files, if it was flushed recently if (!file_exists(WPO_CACHE_FILES_DIR)) { if (!mkdir(WPO_CACHE_FILES_DIR)) { // Can not cache! return $buffer; } } $can_cache_page = apply_filters('wpo_can_cache_page', true, $buffer, $flags); if (!$can_cache_page) return $buffer; $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { // Can not cache! return $buffer; } } } } // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } if (preg_match('#</html>#i', $buffer)) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $buffer .= "\n<!-- Cached by WP Optimize for mobile devices - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $buffer .= "\n<!-- Cached by WP Optimize - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } /** * Save $buffer into cache file. */ $cache_filename = wpo_cache_filename(); $cache_file = $path . '/' .$cache_filename; $contents = wpo_cache_gzip_enabled() ? gzencode($buffer, apply_filters('wpo_cache_gzip_level', 6)) : $buffer; $modified_time = time(); // Take this as soon before writing as possible file_put_contents($cache_file, $contents); header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); if (function_exists('ob_gzhandler') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { return ob_gzhandler($buffer, $flags); } else { return $buffer; } } /** * Load files for support plugins. */ function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ function wpo_cache_filename($ext = '.html') { $filename = 'index'; if (wpo_cache_gzip_enabled()) { $ext .= '.gz'; } if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; } } } // add hash of queried cookies and variables to cache file name. if ('' !== $cache_key) { $filename .= '-' . md5($cache_key); } return $filename . $ext; } /** * Returns site url from site_url() function or if it is not available from cache configuration. */ function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } /** * Get cookie names which impact on cache file name. * * @return array */ function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } /** * Get GET variable names which impact on cache file name. * * @return array */ function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return $variables; } /** * Check if gzip setting is set and available. * * @return bool */ function wpo_cache_gzip_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_gzip_compression']) && function_exists('gzencode')) return true; return false; } /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } /** * Serves the cache and exits */ function wpo_serve_cache() { $file_name = wpo_cache_filename(); $path = WPO_CACHE_FILES_DIR . '/' . rtrim(wpo_get_url_path(), '/') . '/' . $file_name; $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } header('Cache-Control: no-cache'); // Check back in an hour. if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if (function_exists('gzencode') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { header('Content-Encoding: gzip'); } header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if (function_exists('gzencode') && !empty($GLOBALS['wpo_cache_config']['enable_gzip_compression'])) { header('Content-Encoding: gzip'); } readfile($path); exit; } } /** * Clears the cache */ function wpo_cache_flush() { wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } /** * Get URL path for caching * * @since 1.0 * @return string */ function wpo_get_url_path() { $url_parts = parse_url(wpo_current_url()); if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].'/'.$url_parts['path']; } /** * Get requested url. * * @return string */ function wpo_current_url() { return rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}", '/'); } /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } /** * Check if url string match with exception. * * @param string $url - complete url string i.e. http(s):://domain/path * @param string $exception - complete url or absolute path, can consist (.*) wildcards * * @return bool */ function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // used to test websites placed in subdirectories. $sub_dir = ''; // if exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = rtrim($url, '/') . '/'; $exception = rtrim($exception, '/'); // if we have no wildcat in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = str_replace('/', '\/', $exception); return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url); } /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } /** * Check if current browser agent is not disabled in options. * * @return bool */ function wpo_is_accepted_user_agent($user_agent) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } /** * Delete function that deals with directories recursively * * @param string $src path of the folder * * @return bool */ function wpo_delete_files($src) { if (!file_exists($src)) { return true; } if (is_file($src)) { return unlink($src); } $success = true; $dir = opendir($src); $file = readdir($dir); while (false !== $file) { if (('.' != $file) && ('..' != $file)) { if (is_dir($src . '/' . $file)) { if (!wpo_delete_files($src . '/' . $file)) { $success = false; } } else { if (!unlink($src . '/' . $file)) { $success = false; } } } $file = readdir($dir); } closedir($dir); rmdir($src); return $success; } cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000007002 13477736574 033075 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('pre_post_update', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10); add_action('set_comment_cookies', array($this, 'set_comment_cookie_exceptions'), 10); } /** * When user posts a comment, set a cookie so we don't show them page cache * * @param WP_Comment $comment Comment to check. */ public function set_comment_cookie_exceptions($comment) { if (empty($this->config['enable_page_caching'])) return; $path = $this->get_post_path($comment->comment_post_ID); $this->purge_from_cache($path); } /** * Purge files for a particular path from the cache * * @param String $path - the path */ public function purge_from_cache($path) { WPO_Page_Cache::delete(untrailingslashit($path) . '/index.html'); WPO_Page_Cache::delete(untrailingslashit($path) . '/index.gzip.html'); if (!empty($this->config['enable_mobile_caching'])) { WPO_Page_Cache::delete(untrailingslashit($path) . '/mobile.index.html'); WPO_Page_Cache::delete(untrailingslashit($path) . '/mobile.index.gzip.html'); } } /** * Get the cache path for a given post * * @param Integer $post_id - WP post ID * * @return String */ private function get_post_path($post_id) { return WPO_CACHE_DIR . preg_replace('#^https?://#i', '', get_permalink($post_id)); } /** * Every time a comment's status changes, purge it's parent posts cache * * @param Integer $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (empty($this->config['enable_page_caching'])) return; $comment = get_comment($comment_id); $path = $this->get_post_path($comment->comment_post_ID); $this->purge_from_cache($path); } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } elseif (!current_user_can('edit_post', $post_id) && (!defined('DOING_CRON') || !DOING_CRON)) { return; } $this->purge_cache(); } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000012464 13477736574 033220 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return isset($options[$option_key]) ? $options[$option_key] : $default; } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @return bool */ public function update($config) { $config = wp_parse_args($config, $this->get_defaults()); $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); $config['page_cache_length'] = $config['page_cache_length_value'] * $cache_length_units[$config['page_cache_length_unit']]; $cookies = array(); $wpo_cache_cookies = apply_filters('wpo_cache_cookies', $cookies); sort($wpo_cache_cookies); $wpo_query_variables = array(); $wpo_query_variables = apply_filters('wpo_cache_query_variables', $wpo_query_variables); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } return $this->write($config); } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config Configuration array. * @return bool */ private function write($config) { $url = parse_url(site_url()); if (isset($url['port']) && '' != $url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].':'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); if (!file_put_contents($config_file, json_encode($this->config))) { return false; } return true; } /** * Verify we can write to the file system * * @since 1.0 * @return boolean */ public function verify_file_access() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) { return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) { return false; } // If the cache and config directories exist, make sure they're writeable. if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) { if (file_exists(WPO_CACHE_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_DIR)) { return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) { return false; } } } return true; } /** * Return defaults * * @return array */ public function get_defaults() { // if gzip enabled then we will use gzip compression for store cache files. $is_gzip_compression_enabled = WP_Optimize()->get_gzip_compression()->is_gzip_compression_enabled(); $is_gzip_compression_enabled = is_wp_error($is_gzip_compression_enabled) ? false : $is_gzip_compression_enabled; $defaults = array( 'enable_page_caching' => false, 'enable_gzip_compression' => $is_gzip_compression_enabled, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => site_url('/'), ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/class-wpo-detect-cache-plugins.php 000644 000000 000000 00000004277 13477736574 034626 0 ustar 00root wheel 000000 000000 cms <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ private function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $plugins = array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); $active_cache_plugins = array(); foreach ($plugins as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { if (empty(self::$instance)) { self::$instance = new WP_Optimize_Detect_Cache_Plugins(); } return self::$instance; } } cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/class-cache-commands.php 000644 000000 000000 00000003366 13477736574 032752 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); // disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { WPO_Page_Cache::instance()->disable(); } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. WPO_Page_Cache::instance()->enable(); } $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings']); return array( 'result' => $save_settings_result, ); } /** * Purge WP-Optimize page cache. * * @return bool */ public function purge_page_cache() { return WP_Optimize()->get_page_cache()->purge(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } } cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000006442 13477736574 032751 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); // Don't cache robots.txt or htacesss. if (strpos($_SERVER['REQUEST_URI'], 'robots.txt') !== false || strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { return; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) { return; } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array( 'php', 'xml', 'xsl' ))) { return; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || false == $GLOBALS['wpo_cache_config']['enable_user_caching']) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { // Logged in! return; } } } } if (!empty($_COOKIE['wpo_commented_posts'])) { foreach ($_COOKIE['wpo_commented_posts'] as $path) { if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) { // User commented on this post. return; } } } // get cookie exceptions from options. $cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array(); // filter cookie exceptions. $cache_exception_cookies = apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies); // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { return; } } } } } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) return; // Deal with optional cache exceptions. if (!empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); foreach ($exceptions as $exception) { if (wpo_current_url_exception_match($exception)) { // Exception match. return; } } } if (!empty($_GET)) { // get variables used for building filename. $get_variable_names = wpo_cache_query_variables(); // get current GET variables. $get_variables = array_keys($_GET); // if GET variables include one or more then we don't cache. $diff = array_diff($get_variables, $get_variable_names); if (!empty($diff)) return; } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.2.3/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000025623 13477736574 032670 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-php-logger.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-php-logger.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); } /** * Enables page cache * * @return WP_Error|bool - true on success, error otherwise */ public function enable() { static $already_ran_enable = false; if ($already_ran_enable) return true; if (!$this->create_folders()) { return new WP_Error("create_folders", "The request to the filesystem to create the cache directories failed"); } if (!$this->write_advanced_cache()) { return new WP_Error("write_advanced_cache", "The request to write the advanced-cache.php file failed"); } if (!$this->write_wp_config(true)) { return new WP_Error("write_wp_config", "Could not toggle the WP_CACHE constant in wp-config.php"); } if (!$this->verify_cache()) { return new WP_Error("verify_cache", "Could not verify if cache was enabled"); } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; if (false === self::clean(untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php')) { $this->log("The request to the filesystem to write the advanced-cache.php file failed"); $ret = false; } if (!$this->write_wp_config(false)) { $this->log("Could not toggle the WP_CACHE constant in wp-config.php"); $ret = false; } // Delete cache to avoid stale cache on next activation $this->purge(); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (!$this->config->get_option('enable_page_caching', false)) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_DIR); return false; } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_CONFIG_DIR); return false; } if (!is_dir(WPO_CACHE_FILES_DIR) && !wp_mkdir_p(WPO_CACHE_FILES_DIR)) { $this->log('The request to the filesystem failed, unable to create - ' . WPO_CACHE_FILES_DIR); return false; } return true; } /** * Writes advanced-cache.php * * @return bool */ private function write_advanced_cache() { $file = untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; $contents = ''; if (!$this->config->get_option('enable_page_caching', false)) { return false; } $cache_file = untrailingslashit(plugin_dir_path(__FILE__)) . '/file-based-page-cache.php'; $config_file = WPO_CACHE_CONFIG_DIR . '/config-' . $_SERVER['HTTP_HOST'] . '.php'; $cache_path = WPO_CACHE_DIR; $cache_config_path = WPO_CACHE_CONFIG_DIR; $cache_files_path = WPO_CACHE_FILES_DIR; $cache_extensions_path = WPO_CACHE_EXT_DIR; // CS does not like heredoc // @codingStandardsIgnoreStart $contents = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', '$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', '$cache_config_path'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', '$cache_files_path'); if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); if (is_admin()) { return; } if (!@file_exists('$config_file')) { return; } \$GLOBALS['wpo_cache_config'] = json_decode(file_get_contents('$config_file'), true); if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (@file_exists('$cache_file')) { include_once('$cache_file'); } EOF; // @codingStandardsIgnoreEnd if (!file_put_contents($file, $contents)) { return false; } return true; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { if (defined('WP_CACHE') && WP_CACHE === $status) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode("\r\n", $config_file))) { return false; } return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php, please check file/folder permissions"); return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write inside the wp-content folder, please check file/folder permissions"); return false; } // If the cache and config directories exist, make sure they're writeable. if (file_exists(WPO_CACHE_DIR)) { if (!is_writable(WPO_CACHE_DIR)) { $this->log("Unable to write inside the cache folder, please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder, please check file/folder permissions"); return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder, please check file/folder permissions"); return false; } } return true; } /** * Update cache config. Used to support 3d party plugins. */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. $this->config->update($current_config); } /** * Returns the path to wp-config * * @return string wp-config.php path. */ private function _get_wp_config() { $file = '/wp-config.php'; $config_path = false; foreach (get_included_files() as $filename) { if (0 === stripos(strrev($filename), strrev($file))) { $config_path = $filename; } } // Couldn't find wp-config.php. if (!$config_path) { return false; } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Make an empty file. * * @param string $src */ public static function clean($src) { return file_put_contents($src, ''); } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log('ERROR', $message); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/ 000755 000000 000000 00000000000 14215042733 025333 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/ 000755 000000 000000 00000000000 14215042743 026377 5 ustar 00root wheel 000000 000000 cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-cache-commands.php 000644 000000 000000 00000023037 14173760430 033065 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); // filter for validate cache settings before save it. $validation = apply_filters('wpo_save_cache_settings_validation', $data['cache-settings']); if (!empty($validation) && isset($validation['result']) && false === $validation['result']) { return $validation; } $enabled = false; $disabled = false; $return = !empty($validation) ? $validation : array(); $previous_settings = WPO_Cache_Config::instance()->get(); // Attempt to change current status if required if (isset($previous_settings['enable_page_caching']) && $previous_settings['enable_page_caching'] != $data['cache-settings']['enable_page_caching']) { // Disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { $disabled = WPO_Page_Cache::instance()->disable(); // Disabling failed if ($disabled && is_wp_error($disabled)) { // If disabling failed, we re-enable whatever was disabled, to make sure nothing breaks. if ($previous_settings['enable_page_caching']) WPO_Page_Cache::instance()->enable(true); $return['error'] = array( 'code' => $disabled->get_error_code(), 'message' => $disabled->get_error_message() ); } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was disabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. $enabled = WPO_Page_Cache::instance()->enable(true); // Enabling failed if (is_wp_error($enabled)) { // disable everything, to avoid half enabled things WPO_Page_Cache::instance()->disable(); $return['error'] = array( 'code' => $enabled->get_error_code(), 'message' => $enabled->get_error_message() ); if (WPO_Page_Cache::instance()->advanced_cache_file_writing_error) { $return['advanced_cache_file_writing_error'] = true; $return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content; } } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was enabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } // Override enabled setting value $data['cache-settings']['enable_page_caching'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); } else { $data['cache-settings']['enable_page_caching'] = $previous_settings['enable_page_caching']; $enabled = $previous_settings['enable_page_caching']; } $skip_if_no_file_yet = !$enabled || is_wp_error($enabled); $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet); if ($save_settings_result && !is_wp_error($save_settings_result)) { WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings); $return['result'] = $save_settings_result; } else { // Saving the settings returned an error if (is_wp_error($save_settings_result)) { if (isset($return['error'])) { $return['error']['message'] .= "\n\n".$save_settings_result->get_error_message(); } else { $return['error'] = array( 'code' => $save_settings_result->get_error_code(), 'message' => $save_settings_result->get_error_message() ); } } $return['result'] = false; } $return['enabled'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); return $return; } /** * Get information about current cache status. Used in cli commands. * * @return array */ public function get_status_info() { $status = array(); $status[] = WPO_Page_Cache::instance()->is_enabled() ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize'); $preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); $status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']); $status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']); if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message']; $status['message'] = join(PHP_EOL, $status); return $status; } /** * Enable cache. */ public function enable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = true; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Disable cache. */ public function disable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = false; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Purge WP-Optimize page cache. * * @return array */ public function purge_page_cache() { if (!WP_Optimize()->can_purge_the_cache()) { return array( 'success' => false, 'message' => __('You do not have permission to purge the cache', 'wp-optimize'), ); } $purged = WP_Optimize()->get_page_cache()->purge(); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); $response = array( 'success' => $purged, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], ); // if scheduled preload enabled then reschedule and run preloader. if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) { // cancel preload and reschedule preload action. $wpo_page_cache_preloader->cancel_preload(); $wpo_page_cache_preloader->reschedule_preload(); // run preloader. $wpo_page_cache_preloader->run('scheduled', $response); } if ($response['success']) { $response['message'] = __('Page cache purged successfully', 'wp-optimize'); } return $response; } /** * Run cache preload (for wp-cli). * * @return array|bool */ public function run_cache_preload_cli() { if (!(defined('WP_CLI') && WP_CLI)) return false; // define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file // but we check this constant value wen detecting status of cache if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); // don't interrupt queue processing add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99); // if preloading is running then exit. if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) { return array( 'success' => false, 'error' => __('Preloading is currently running in another process.', 'wp-optimize'), ); } // set default response. $response = array( 'success' => true, 'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'), ); WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize')); return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response); } /** * Run cache preload action. * * @return void|array - Doesn't return anything if run() is successfull (Run() prints a JSON object and closed browser connection) or an array if failed. */ public function run_cache_preload() { return WP_Optimize_Page_Cache_Preloader::instance()->run('manual'); } /** * Cancel cache preload action. * * @return array */ public function cancel_cache_preload() { WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload(); return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Get status of cache preload. * * @return array */ public function get_cache_preload_status() { return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } /** * Format save_cache_settings() result for displaying in WP-CLI console * * @param array $response * @return array */ private function format_save_cache_settings_response($response) { $result = array( 'success' => $response['result'], ); if (isset($response['error'])) { $result['success'] = false; $result['error'] = $response['error']['message']; } if ($result['success']) { $result['message'] = __('Page cache settings updated successfully.', 'wp-optimize'); } return $result; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-cache-rules.php 000644 000000 000000 00000030100 14173760430 033206 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ if (!class_exists('WPO_Cache_Config')) require_once('class-wpo-cache-config.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1); add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2); add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6); add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1); add_action('wp_insert_comment', array($this, 'comment_inserted'), 10, 2); add_action('woocommerce_variation_set_stock', array($this, 'purge_product_page'), 10, 1); add_action('woocommerce_product_set_stock', array($this, 'purge_product_page'), 10, 1); /** * List of hooks for which when executed, the cache will be purged * * @param array $actions The actions */ $purge_on_action = apply_filters('wpo_purge_cache_hooks', array('after_switch_theme', 'wp_update_nav_menu', 'customize_save_after', array('wp_ajax_save-widget', 0), array('wp_ajax_update-widget', 0), 'autoptimize_action_cachepurged', 'upgrader_overwrote_package', 'wpo_active_plugin_or_theme_updated', 'fusion_cache_reset_after')); foreach ($purge_on_action as $action) { if (is_array($action)) { add_action($action[0], array($this, 'purge_cache'), $action[1]); } else { add_action($action, array($this, 'purge_cache')); } } add_filter('wpo_cache_cookies', array($this, 'wpo_cache_cookies'), 9); } /** * Purge post cache when there is a new approved comment * * @param int $comment_id Comment ID. * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'. * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/ */ public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) { if (1 !== $approved) { return; } if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) { $post_id = $commentdata['comment_post_ID']; WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_comments_feed(); } } /** * Every time a comment's status changes, purge it's parent posts cache * * @param int $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (!empty($this->config['enable_page_caching'])) { $comment = get_comment($comment_id); if (is_object($comment) && !empty($comment->comment_post_ID)) { WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID); WPO_Page_Cache::delete_comments_feed(); } } } /** * Action when a comment is inserted * * @param integer $comment_id - The comment ID * @param boolean|WP_Comment $comment - The comment object (from WP 4.4) * @return void */ public function comment_inserted($comment_id, $comment = false) { if ($comment && is_a($comment, 'WP_Comment')) { /** * Filters whether to add a cookie when a comment is posted, in order to exclude the page from caching. * Regular comments have the property comment_type set to '' or 'comment'. So by default, only add the cookie in those cases. * * @param boolean $add_cookie * @param WP_Comment $comment * @return boolean */ $add_cookie = apply_filters('wpo_add_commented_post_cookie', '' == $comment->comment_type || 'comment' == $comment->comment_type, $comment); if (!$add_cookie) return; $url = get_permalink($comment->comment_post_ID); $url_info = parse_url($url); setcookie('wpo_commented_post', 1, time() + WEEK_IN_SECONDS, isset($url_info['path']) ? $url_info['path'] : '/'); } } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); $post_type_object = get_post_type_object($post_type); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || !$post_type_object->public) { return; } /** * Purge the whole cache if set to true, only the edited post otherwise. Default is false. * * @param boolean $purge_all_cache The default filter value * @param integer $post_id The saved post ID */ if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) { $this->purge_cache(); return; } else { if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::delete_feed_cache(); WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_sitemap_cache(); WPO_Page_Cache::delete_post_feed_cache($post_id); } } /** * Purge archive pages on post update. * * @param integer $post_id */ public function purge_archive_pages_on_post_update($post_id) { $post_type = get_post_type($post_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } $post_obj = get_post_type_object($post_type); if ('post' == $post_type) { // delete blog page cache $blog_post_id = get_option('page_for_posts'); if ($blog_post_id) { WPO_Page_Cache::delete_cache_by_url(get_permalink($blog_post_id), true); } // delete next and previus posts cache. $globals_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : false; $GLOBALS['post'] = get_post($post_id); $previous_post = function_exists('get_previous_post') ? get_previous_post() : false; $next_post = function_exists('get_next_post') ? get_next_post() : false; if ($globals_post) $GLOBALS['post'] = $globals_post; if ($previous_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($previous_post), true); if ($next_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($next_post), true); // delete all archive pages for post. $post_date = get_post_time('Y-m-j', false, $post_id); list($year, $month, $day) = $post_date; $archive_links = array( get_year_link($year), get_month_link($year, $month), get_day_link($year, $month, $day), ); foreach ($archive_links as $link) { WPO_Page_Cache::delete_cache_by_url($link, true); } } elseif ($post_obj->has_archive) { // delete archive page for custom post type. WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true); } } /** * We use it with edit_terms action filter to purge cached elements related * to updated term when term updated. * * @param int $term_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. */ public function purge_related_elements_on_term_updated($term_id, $taxonomy) { // purge cached page for term. $term = get_term($term_id, $taxonomy, ARRAY_A); if (is_array($term)) { $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } // get posts which belongs to updated term. $posts = get_posts(array( 'numberposts' => -1, 'post_type' => 'any', 'fields' => 'ids', 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $term_id, ) ), )); if (!empty($posts)) { foreach ($posts as $post_id) { WPO_Page_Cache::delete_single_post_cache($post_id); } } } /** * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) { $post_type = get_post_type($object_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) { return; } /** * Adds a way to exit the purge of terms permalink using the provided parameters. * * @param bool $purge The value filtered, whether or not to purge the related elements * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. * @default true * @return boolean */ if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return; // get all affected terms. $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids)); if (!empty($affected_terms_ids)) { // walk through all changed terms and purge cached pages for them. foreach ($affected_terms_ids as $tt_id) { $term = get_term($tt_id, $taxonomy, ARRAY_A); if (!is_array($term)) continue; $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { $url = parse_url($term_permalink); // Check if the permalink contains a valid path, to avoid deleting the whole cache. if (!isset($url['path']) || '/' === $url['path']) return; WPO_Page_Cache::delete_cache_by_url($term_permalink, true); } } } } /** * Purge product page upon stock update */ public function purge_product_page($product_with_stock) { if (!empty($product_with_stock->get_id())) { WPO_Page_Cache::delete_single_post_cache($product_with_stock->get_id()); } } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); } } /** * Triggered by wpo_cache_config_updated. * * @param array $config */ public function cache_config_updated($config) { // delete front page form cache if defined in the settings if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) { WPO_Page_Cache::delete_cache_by_url(home_url()); } } /** * Add cookie names that are need separate caching */ public function wpo_cache_cookies($cookies) { $cookies[] = 'cookie_notice_accepted'; $cookies[] = 'cookielawinfo-checkbox-necessary'; $cookies[] = 'cookielawinfo-checkbox-functional'; $cookies[] = 'cookielawinfo-checkbox-advertisement'; $cookies[] = 'cookielawinfo-checkbox-others'; $cookies[] = 'cookielawinfo-checkbox-analytics'; $cookies[] = 'cookielawinfo-checkbox-performance'; return $cookies; } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-cache-preloader.php000644 000000 000000 00000071010 14151417634 034037 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!class_exists('Updraft_Task_Manager_1_3')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php'); if (!class_exists('WP_Optimize_Load_Url_Task')) require_once(dirname(__FILE__) . '/class-wpo-load-url-task.php'); class WP_Optimize_Page_Cache_Preloader extends Updraft_Task_Manager_1_3 { private $task_type = 'load-url-task'; private $options; static protected $_instance = null; /** * WP_Optimize_Page_Cache_Preloader constructor. */ public function __construct() { parent::__construct(); $this->options = WP_Optimize()->get_options(); // setup loggers $this->set_loggers(WP_Optimize()->wpo_loggers()); add_filter('cron_schedules', array($this, 'cron_add_intervals')); add_action('wpo_page_cache_preload_continue', array($this, 'process_tasks_queue')); add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload')); add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20); } /** * Check if cache is active. * * @return bool */ public function is_cache_active() { return WP_Optimize()->get_page_cache()->is_enabled(); } /** * Schedule or delete automatic preload action on cache settings update. * * @param array $new_settings The new settings * @param array $previous_settings Settings before saving */ public function cache_settings_updated($new_settings, $previous_settings) { if (!$new_settings['enable_page_caching']) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); $this->delete_preload_continue_action(); return; } if (!empty($new_settings['enable_schedule_preload'])) { $last_schedule_type = $previous_settings['preload_schedule_type']; if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { // if already scheduled this schedule type if ($new_settings['preload_schedule_type'] == $last_schedule_type) { // If the schedule type is cache lifespan, check if the cache lifespan changed. if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) { // Else, if the settings cache lifespan settings haven't changed, returns if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) { return; } } else { return; } } // clear currently scheduled preload action. wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action. wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload'); } else { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } } /** * Clear active preload tasks, reschedule preload action. */ public function reschedule_preload() { // clear scheduled action. if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action if need. if ($this->is_scheduled_preload_enabled()) { $preload_schedule_type = $this->get_cache_config('preload_schedule_type'); wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload'); } } /** * Check if scheduled preload enabled. * * @return bool */ public function is_scheduled_preload_enabled() { $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload'); return !empty($enable_schedule_preload); } /** * Get a schedule interval * * @param string $schedule_key The schedule to check * @return integer */ private function get_schedule_interval($schedule_key) { $schedules = wp_get_schedules(); if (!isset($schedules[$schedule_key])) { $this->log('Could not get interval for event of type '.$schedule_key); return 0; } return isset($schedules[$schedule_key]['interval']) ? $schedules[$schedule_key]['interval'] : 0; } /** * Add intervals to cron schedules. * * @param array $schedules * * @return array */ public function cron_add_intervals($schedules) { $interval = $this->get_continue_preload_cron_interval(); $schedules['wpo_page_cache_preload_continue_interval'] = array( 'interval' => $interval, 'display' => round($interval / 60, 1).' minutes' ); $schedules['wpo_use_cache_lifespan'] = array( 'interval' => WPO_Cache_Config::instance()->get_option('page_cache_length'), 'display' => 'Same as cache lifespan: '.WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit') ); return $schedules; } /** * Get the interval to continuing a preload task * * @return integer */ private function get_continue_preload_cron_interval() { /** * Filters the interval between each preload attempt, in seconds. */ return (int) apply_filters('wpo_page_cache_preload_continue_interval', 600); } /** * Schedule action for continuously preload. */ public function schedule_preload_continue_action() { $continue_in = wp_next_scheduled('wpo_page_cache_preload_continue'); // Action is still scheduled if ($continue_in && $continue_in > 0) return; // Action is overdue, delete it and re schedule it if ($continue_in && $continue_in < 0) $this->delete_preload_continue_action(); wp_schedule_event(time() + $this->get_schedule_interval('wpo_page_cache_preload_continue_interval'), 'wpo_page_cache_preload_continue_interval', 'wpo_page_cache_preload_continue'); } /** * Delete scheduled action for continuously preload. */ public function delete_preload_continue_action() { wp_clear_scheduled_hook('wpo_page_cache_preload_continue'); } /** * Run cache preload. If task queue is empty it creates tasks for site urls. * * @param string $type - The preload type (schedule | manual) * @param array $response - Specific response for echo into output thread when browser connection closing. * @return array|void - Void when closing the browser connection */ public function run($type = 'scheduled', $response = null) { if (!$this->is_cache_active()) { return array( 'success' => false, 'error' => __('Page cache is disabled.', 'wp-optimize') ); } if (empty($response)) { $response = array('success' => true); } $this->delete_cancel_flag(); // trying to lock semaphore. $creating_tasks_semaphore = new Updraft_Semaphore_3_0('wpo_cache_preloader_creating_tasks'); $lock = $creating_tasks_semaphore->lock(); // if semaphore haven't locked then just return response. if (!$lock) { return array( 'success' => false, 'error' => __('Probably page cache preload is running already.', 'wp-optimize') ); } $is_wp_cli = defined('WP_CLI') && WP_CLI; // close browser connection and continue work. // don't close connection for WP-CLI if (false == $is_wp_cli) { WP_Optimize()->close_browser_connection(json_encode($response)); } // trying to change time limit. WP_Optimize()->change_time_limit(); $status = $this->get_status($this->task_type); if (0 == $status['all_tasks'] && $lock) { if (is_multisite()) { $sites = WP_Optimize()->get_sites(); foreach ($sites as $site) { switch_to_blog($site->blog_id); $this->create_tasks_for_preload_site_urls($type); restore_current_blog(); } } else { $this->create_tasks_for_preload_site_urls($type); } } if ($lock) $creating_tasks_semaphore->release(); $this->process_tasks_queue(); // return $response in WP-CLI mode if ($is_wp_cli) { return $response; } } /** * Check if we need run cache preload and run it. */ public function run_scheduled_cache_preload() { $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); if (!$schedule_type) return; // Don't run preload if cache lifespan option enabled and cache not expired yet. if ('wpo_use_cache_lifespan' == $schedule_type) { /** * Filters the allowed time difference between the cache exiry and the current time, in seconds. * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it. * * @param integer $allowed_time_difference The time difference, in seconds (default = 600) */ $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', 600); $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0); $time_since_last_preload = time() - $last_preload_time; $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference; // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return; } $this->run(); } /** * Process tasks queue. */ public function process_tasks_queue() { // schedule continue preload action. $this->schedule_preload_continue_action(); if (!$this->process_queue($this->task_type)) { return; } // delete scheduled continue preload action. $this->delete_preload_continue_action(); // update last cache preload time only if processing any tasks, else process was cancelled. if ($this->is_running()) { $this->options->update_option('wpo_last_page_cache_preload', time()); } $this->clean_up_old_tasks($this->task_type); } /** * Find out if the current queue should be interrupted * * @param boolean $interrupt * @return boolean */ public function maybe_interrupt_queue($interrupt) { if ($interrupt) return $interrupt; static $memory_threshold = null; if (null == $memory_threshold) { /** * Filters the minimum memory required before stopping a queue. Default: 10MB */ $memory_threshold = apply_filters('wpo_page_cache_preload_memory_threshold', 10485760); } return WP_Optimize()->get_free_memory() < $memory_threshold; } /** * Delete all preload tasks from queue. */ public function cancel_preload() { $this->set_cancel_flag(); $this->delete_tasks($this->task_type); $this->delete_preload_continue_action(); } /** * Set 'cancel' option to true. */ public function set_cancel_flag() { $this->options->update_option('last_page_cache_preload_cancel', true); } /** * Delete 'cancel' option. */ public function delete_cancel_flag() { $this->options->delete_option('last_page_cache_preload_cancel'); } /** * Check if the last preload is cancelled. * * @return bool */ public function is_cancelled() { return $this->options->get_option('last_page_cache_preload_cancel', false); } /** * Check if preloading queue is processing. * * @return bool */ public function is_busy() { return $this->is_semaphore_locked($this->task_type) || $this->is_semaphore_locked('wpo_cache_preloader_creating_tasks'); } /** * Get current status of preloading urls. * * @return array */ public function get_status_info() { $status = $this->get_status($this->task_type); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); if ($this->is_semaphore_locked('wpo_cache_preloader_creating_tasks') && !$this->is_cancelled()) { // we are still creating tasks. return array( 'done' => false, 'message' => __('Loading URLs...', 'wp-optimize'), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } elseif ($status['complete_tasks'] == $status['all_tasks']) { $gmt_offset = (int) (3600 * get_option('gmt_offset')); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload'); if ($last_preload_time) { $last_preload_time_str = date_i18n(get_option('time_format').', '.get_option('date_format'), $last_preload_time + $gmt_offset); return array( 'done' => true, 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } else { return array( 'done' => true, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } } else { $preload_resuming_time = wp_next_scheduled('wpo_page_cache_preload_continue'); $preload_resuming_in = $preload_resuming_time ? $preload_resuming_time - time() : 0; $preloaded_message = sprintf(_n('%1$s out of %2$s URL preloaded', '%1$s out of %2$s URLs preloaded', $status['all_tasks'], 'wp-optimize'), $status['complete_tasks'], $status['all_tasks']); if ('sitemap' == $this->options->get_option('wpo_last_page_cache_preload_type', '')) { $preloaded_message = __('Preloading posts found in sitemap:', 'wp-optimize') .' '. $preloaded_message; } $return = array( 'done' => false, 'message' => $preloaded_message, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], 'resume_in' => $preload_resuming_in ); if (defined('DOING_AJAX') && DOING_AJAX) { // if no cron was found or cron is overdue more than 20s, trigger it if (!$preload_resuming_time || $preload_resuming_in < -20) { $this->run($return); } } return $return; } } /** * Check if preload action in process. * * @return bool */ public function is_running() { $status = $this->get_status($this->task_type); if ($status['all_tasks'] > 0) return true; } /** * Get cache config option value. * * @return mixed */ public function get_cache_config($option) { static $config = null; if (null === $config) $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists($option, $config)) { return $config[$option]; } return false; } /** * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site. * * @param string $type The preload type (currently: scheduled, manual) * @return void */ public function create_tasks_for_preload_site_urls($type) { $urls = $this->get_site_urls(); if (!empty($urls)) { $this->log(__('Creating tasks for preload site urls.', 'wp-optimize')); foreach ($urls as $url) { if (wpo_url_in_exceptions($url)) continue; if ($this->url_is_already_cached($url, $type)) { continue; } // this description is being used for internal purposes. $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->log(__('Tasks for preload site urls created.', 'wp-optimize')); } } /** * Preload desktop version from url. * * @param string $url * * @return void */ public function preload_desktop($url) { $desktop_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, 'headers' => array( 'X-WP-Optimize-Cache-Preload' => 'Yes', ), ); $desktop_args = apply_filters('wpo_page_cache_preloader_desktop_args', $desktop_args, $url); $this->log('preload_desktop - '. $url); wp_remote_get($url, $desktop_args); } /** * Preload mobile version from $url. * * @param string $url * * @return void */ public function preload_mobile($url) { static $is_mobile_caching_enabled; if (!isset($is_mobile_caching_enabled)) { $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching'); } // Only run if option is active if (!$is_mobile_caching_enabled) return; $mobile_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', 'timeout' => 10, 'headers' => array( 'X-WP-Optimize-Cache-Preload' => 'Yes', ), ); $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url); $this->log('preload_mobile - ' . $url); wp_remote_get($url, $mobile_args); } /** * Preload amp version from $url. * * @param string $url * * @return void */ public function preload_amp($url) { if (!apply_filters('wpo_should_preload_amp', false, $url)) return; $amp_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, 'headers' => array( 'X-WP-Optimize-Cache-Preload' => 'Yes', ), ); $url = untrailingslashit($url) . '/amp/'; $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url); $this->log('preload_amp - ' . $url); wp_remote_get($url, $amp_args); } /** * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls. * * @return array */ public function get_site_urls() { $urls = $this->get_sitemap_urls(); if (!empty($urls)) { $this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap'); } else { $urls = $this->get_post_urls(); $this->options->update_option('wpo_last_page_cache_preload_type', 'posts'); } $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls))); /** * Filter the URLs which will be preloaded * * @param array $urls * @return array */ return apply_filters('wpo_preload_get_site_urls', $urls); } /** * Loads sitemap file and returns list of urls. * * @param string $sitemap_url * * @return array|bool */ public function get_sitemap_urls($sitemap_url = '') { $urls = array(); // if sitemap url is empty then use main sitemap file name. $sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url; // if simplexml_load_string not available then we don't load sitemap. if (!function_exists('simplexml_load_string')) { return $urls; } // load sitemap file. $response = wp_remote_get($sitemap_url, array('timeout' => 30)); // if we get error then if (is_wp_error($response)) { $response = file_get_contents($sitemap_url); // if response is empty then try load from file. if (empty($response) && '' == $sitemap_url) { $sitemap_file = $this->get_local_sitemap_file(); $response = file_get_contents($sitemap_file); } if (empty($response)) return $urls; $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } else { // parse xml answer. $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // xml file has not valid xml content then return false. if (false === $xml) return false; // if exists urls then return them. if (isset($xml->url)) { foreach ($xml->url as $element) { if (!isset($element->loc)) continue; $urls[] = (string) $element->loc; } } elseif (isset($xml->sitemap)) { // if has links to other sitemap files then get urls from them. foreach ($xml->sitemap as $element) { if (!isset($element->loc)) continue; $sitemap_urls = $this->get_sitemap_urls($element->loc); if (is_array($sitemap_urls)) { $urls = array_merge($urls, $sitemap_urls); } } } return $urls; } /** * Get the path to a local sitemap file * * @return string */ private function get_local_sitemap_file() { if (!function_exists('get_home_path')) { include_once ABSPATH . '/wp-admin/includes/file.php'; } return trailingslashit(get_home_path()) . $this->get_sitemap_filename(); } /** * Get all posts of any post type and returns urls for them. * * @return array */ public function get_post_urls() { global $post; $offset = 0; $posts_per_page = 1000; $urls = array(); $urls[] = site_url('/'); do { $query = new WP_Query(array( 'post_type' => 'any', 'post_status' => 'publish', 'posts_per_page' => $posts_per_page, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'cache_results' => false, // disable cache to avoid memory error. )); $posts_loaded = $query->post_count; while ($query->have_posts()) { $query->the_post(); $permalink = get_permalink(); $urls[] = $permalink; // check page separators in the post content preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches); // if there any separators add urls for each page if (count($matches[0])) { $prefix = strpos($permalink, '?') ? '&page=' : ''; for ($page = 0; $page < count($matches[0]); $page++) { if ('' != $prefix) { $urls[] = $permalink . $prefix . ($page+2); } else { $urls[] = trailingslashit($permalink) . ($page+2); } } } } $offset += $posts_loaded; } while ($posts_loaded > 0); /** * If domain mapping enabled then replace domains in urls. */ if ($this->is_domain_mapping_enabled()) { $blog_id = get_current_blog_id(); $mapped_domain = $this->get_mapped_domain($blog_id); $blog_details = get_blog_details($blog_id); if ($mapped_domain) { foreach ($urls as $i => $url) { $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1); } } } wp_reset_postdata(); return $urls; } /** * Check if domain mapping enabled. * * @return bool */ public function is_domain_mapping_enabled() { // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin. $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE); /** * Filters if Multisite Domain mapping is enabled. * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use. * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option. */ return apply_filters('wpo_is_domain_mapping_enabled', $enabled); } /** * Return mapped domain by $blog_id. * * @param int $blog_id * * @return string */ public function get_mapped_domain($blog_id) { global $wpdb; $domain = ''; $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) { // This table created in WordPress MU Domain Mapping plugin. $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A); if (!empty($row)) { $domain = $row['domain']; } } else { // When using the WP Core method, the site url option contains the mapped domain. $domain = get_site_url($blog_id); } /** * Filters the mapped domain name * * @param string $domain The domain name * @param integer $blog_id The blog ID */ return apply_filters('wpo_get_mapped_domain', $domain, $blog_id); } /** * Captures and logs any interesting messages * * @param String $message - the error message * @param String $error_type - the error type */ public function log($message, $error_type = 'info') { if (isset($this->loggers)) { foreach ($this->loggers as $logger) { $logger->log($message, $error_type); } } } /** * Instance of WP_Optimize_Page_Cache_Preloader. * * @return WP_Optimize_Page_Cache_Preloader */ public static function instance() { if (empty(self::$_instance)) { self::$_instance = new WP_Optimize_Page_Cache_Preloader(); } return self::$_instance; } /** * Get sitemap filename. * * @return string */ private function get_sitemap_filename() { /** * Filter the sitemap file used to collect the URLs to preload * * @param string $filename - The sitemap name * @default sitemap.xml */ return apply_filters('wpo_cache_preload_sitemap_filename', 'sitemap.xml'); } /** * Check if semaphore is locked. * * @param string $semaphore * @return bool */ private function is_semaphore_locked($semaphore) { $semaphore = new Updraft_Semaphore_3_0($semaphore); if ($semaphore->lock()) { $semaphore->release(); return false; } return true; } /** * Check if the URL is already cached, or needs to be preloaded * * @param string $url The preloaded url * @param string $preload_type The preload type (manual | scheduled) * @return boolean */ private function url_is_already_cached($url, $preload_type) { static $files = array(); $regenerate_count = 0; $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url); // If the folder does not exist, consider the URL as cleared if (!is_dir($folder)) return false; if (empty($files)) { // Check only the base files $files[] = 'index.html'; if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) { $files[] = 'mobile.index.html'; } $files = apply_filters('wpo_maybe_clear_files_list', $files); } foreach ($files as $file) { $file_path = trailingslashit($folder).$file; if (!file_exists($file_path)) { // The file does not exist, count it as "deleted" $regenerate_count++; continue; } if ($this->should_regenerate_file($file_path, $preload_type)) { // delefe the expired cache file unlink($file_path); $regenerate_count++; } } // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted. return 0 == $regenerate_count; } /** * Determine if a file should be regenerated * * @param string $path The file to check * @param string $preload_type The preload type (manual | scheduled) * * @return boolean */ private function should_regenerate_file($path, $preload_type) { // Store the variables, as they'll be used for each file and each file static $is_preloader_scheduled = null; static $lifespan = null; static $schedule_type = null; static $schedule_interval = null; static $lifespan_expiry_threshold = null; static $always_regenerate_file_if_preload_is_manual = null; static $always_regenerate_file_if_preload_is_scheduled = null; static $regenerate_file_when_no_expiry_date = null; // Sets the variables once per request: if (null === $is_preloader_scheduled) { $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload'); $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length'); $schedule_interval = $this->get_schedule_interval($schedule_type); /** * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min) */ $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600); /** * Filters if a cache should systematically be regenerated when running a manual preload. Default: false */ $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false); /** * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false */ $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false); /** * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true */ $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true); } if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) { $result = true; } else { $modified_time = (int) filemtime($path); // cache lifespan is set. if (0 != $lifespan) { $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold; $result = time() > $expiry_time; } elseif ($is_preloader_scheduled) { $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold; $result = time() > $expiry_time; } else { $result = $regenerate_file_when_no_expiry_date; } } return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type); } } WP_Optimize_Page_Cache_Preloader::instance(); cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-cache-config.php 000644 000000 000000 00000016267 13730076454 033347 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->get_defaults()); } else { $config = get_option('wpo_cache_config', $this->get_defaults()); } return wp_parse_args($config, $this->get_defaults()); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return isset($options[$option_key]) ? $options[$option_key] : $default; } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved. * * @return bool */ public function update($config, $skip_disk_if_not_yet_present = false) { $config = wp_parse_args($config, $this->get_defaults()); $config['page_cache_length_value'] = intval($config['page_cache_length_value']); $config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']); /** * Filters the cookies used to set cache file names * * @param array $cookies - The cookies * @param array $config - The new config */ $wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config); sort($wpo_cache_cookies); /** * Filters the query variables used to set cache file names * * @param array $wpo_query_variables - The variables * @param array $config - The new config */ $wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; $config = apply_filters('wpo_cache_update_config', $config); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } do_action('wpo_cache_config_updated', $config); return $this->write($config, $skip_disk_if_not_yet_present); } /** * Calculate cache expiration value in seconds. * * @param int $value * @param string $unit ( hours | days | months ) * * @return int */ private function calculate_page_cache_length($value, $unit) { $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); return $value * $cache_length_units[$unit]; } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config - Configuration array. * @param boolean $only_if_present - only writes to the disk if the configuration file already exists * * @return boolean - returns false if an attempt to write failed */ private function write($config, $only_if_present = false) { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'-port'.$url['port'].'.php'; } else { $config_file = WPO_CACHE_CONFIG_DIR.'/config-'.$url['host'].'.php'; } $this->config = wp_parse_args($config, $this->get_defaults()); // from 3.0.17 we use more secure way to store cache config files. $advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version(); // if advanced-cache.php exists and has at least 3.0.17 version or // advanced-cache.php doesn't exist then // we write the cache config in a new format. if (($advanced_cache_version && (version_compare($advanced_cache_version, '3.0.17', '>='))) || !$advanced_cache_version) { $config_content = '<?php' . "\n" . 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n" . '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . json_encode($this->config) . '\', true);' . "\n"; } else { $config_content = json_encode($this->config); } if ((!$only_if_present || file_exists($config_file)) && !file_put_contents($config_file, $config_content)) { return new WP_Error('write_cache_config', sprintf(__('The cache configuration file could not be saved to the disk; please check the file/folder permissions of %s .', 'wp-optimize'), $config_file)); } return true; } /** * Verify we can write to the file system * * @since 1.0 * @return boolean */ public function verify_file_access() { if (function_exists('clearstatcache')) { clearstatcache(); } // First check wp-config.php. if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) { return false; } // Now check wp-content. We need to be able to create files of the same user as this file. if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) { return false; } // If the cache and config directories exist, make sure they're writeable if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) { if (file_exists(WPO_CACHE_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_DIR)) { return false; } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) { return false; } } } return true; } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => false, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => network_site_url('/'), 'enable_cache_per_country' => false, ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/php-5.3-functions.php 000644 000000 000000 00000000575 13614520640 032216 0 ustar 00root wheel 000000 000000 <?php /** * Get path to wp-config.php when called from WP-CLI. * * @return string */ function wpo_wp_cli_locate_wp_config() { $config_path = ''; if (is_callable('\WP_CLI\Utils\locate_wp_config')) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound $config_path = \WP_CLI\Utils\locate_wp_config(); } return $config_path; } wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-detect-cache-plugins.php 000644 000000 000000 00000004420 13665647440 034744 0 ustar 00root wheel 000000 000000 cms/wordpress <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ protected function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $active_cache_plugins = array(); foreach ($this->get_plugins() as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Get the plugins list * * @return array */ protected function get_plugins() { return array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { static $instance; if (empty($instance)) { $instance = new self(); } return $instance; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/file-based-page-cache.php 000644 000000 000000 00000011314 14057473210 033057 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); /** * Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded. */ if (function_exists('do_action')) { do_action('wpo_cache_extensions_loaded'); } $no_cache_because = array(); // check if we want to cache current page. if (function_exists('add_filter') && function_exists('apply_filters')) { add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); $restricted_cache_page_type = apply_filters('wpo_restricted_cache_page_type', false); } else { // On old WP versions, you can't filter the result $restricted_cache_page_type = wpo_restricted_cache_page_type(false); } if ($restricted_cache_page_type) { $no_cache_because[] = $restricted_cache_page_type; } // Don't cache non-GET requests. if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) { $no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')'; } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && !preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) { $no_cache_because[] = 'The request extension is not suitable for caching'; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (!wpo_cache_loggedin_users()) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { $no_cache_because[] = 'WordPress login cookies were detected'; break(2); } } } } if (!empty($_COOKIE['wpo_commented_post'])) { $no_cache_because[] = 'The user has commented on a post (comment cookie set)'; } // get cookie exceptions from options. $cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array(); // filter cookie exceptions, since WP 4.6 $cache_exception_cookies = function_exists('apply_filters') ? apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies) : $cache_exception_cookies; // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { $no_cache_because[] = 'An excepted cookie was set ('.$key.')'; break 2; } } } } } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) { $no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent"; } // Deal with optional cache exceptions. if (wpo_url_in_exceptions(wpo_current_url())) { $no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL'; } if (!empty($_GET)) { // get variables used for building filename. $get_variable_names = wpo_cache_query_variables(); $get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET)); // if GET variables include one or more undefined variable names then we don't cache. $get_variables_diff = array_diff($get_variables, $get_variable_names); if (!empty($get_variables_diff)) { $no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters"; } } if (!empty($no_cache_because)) { $no_cache_because_message = implode(', ', $no_cache_because); // Add http header if (!defined('DOING_CRON') || !DOING_CRON) { wpo_cache_add_nocache_http_header($no_cache_because_message); } // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON)) { wpo_cache_add_footer_output("Page not served from cache because: ".htmlspecialchars($no_cache_because_message)); } return; } wpo_serve_cache(); ob_start('wpo_cache'); cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-page-cache.php 000644 000000 000000 00000111473 14151417634 033006 0 ustar 00root wheel 000000 000000 <?php /** * Page caching functionality * * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specifc cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('WP_Optimize_Detect_Cache_Plugins')) require_once(dirname(__FILE__) . '/class-wpo-detect-cache-plugins.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php'); if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php'); if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-abstract-logger.php'); if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-php-logger.php'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (version_compare(PHP_VERSION, '5.3.0') >= 0) { require_once dirname(__FILE__) . '/php-5.3-functions.php'; } wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Store last advanced cache file writing status * If true then last writing finished with error * * @var bool */ public $advanced_cache_file_writing_error; /** * Store errors * * @var array */ private $_errors = array(); /** * Last advanced cache file content * * @var string */ public $advanced_cache_file_content; /** * Store the latest advanced-cache.php version required * * @var string */ private $_minimum_advanced_cache_file_version = '3.0.17'; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); $this->rules = WPO_Cache_Rules::instance(); $this->logger = new Updraft_PHP_Logger(); add_action('activate_plugin', array($this, 'activate_deactivate_plugin')); add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); /** * Regenerate config file on cache flush. */ add_action('wpo_cache_flush', array($this, 'update_cache_config')); add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); // Add purge cache link to admin bar. add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1); // Handle single page purge. add_action('wp_loaded', array($this, 'handle_purge_single_page_cache')); add_action('admin_init', array($this, 'admin_init')); $this->check_compatibility_issues(); } /** * Do required actions on activate/deactivate any plugin. */ public function activate_deactivate_plugin() { $this->update_cache_config(); /** * Filters whether activating / deactivating a plugin will purge the cache. */ if (apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true)) { $this->purge(); } } /** * Check if current user can purge cache. * * @return bool */ public function can_purge_cache() { if (is_multisite()) return $this->is_enabled() && current_user_can('manage_network_options'); return $this->is_enabled() && current_user_can('manage_options'); } /** * Add Purge from cache in admin bar. * * @param array $menu_items * @return array */ public function admin_bar_purge_cache($menu_items) { global $pagenow; if (!$this->can_purge_cache()) return $menu_items; $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); $cache_size = $this->get_cache_size(); $cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>'; $cache_size_info .= '<span>'.__('Cache size:', 'wp-optimize').' '. WP_Optimize()->format_size($cache_size['size']).' '.sprintf(__('(%d files)', 'wp-optimize'), $cache_size['file_count']).'</span>'; $menu_items[] = array( 'id' => 'wpo_cache_stats', 'title' => $cache_size_info, 'meta' => array( 'class' => 'wpo-cache-stats', ), 'parent' => 'wpo_purge_cache', ); $menu_items[] = array( 'id' => 'wpo_purge_all_pages_cache', 'title' => __('Purge cache for all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for all pages', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); if (!is_admin() || 'post.php' == $pagenow) { $menu_items[] = array( 'id' => 'wpo_purge_this_page_cache', 'title' => __('Purge cache for this page', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for this page', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); } return $menu_items; } /** * Check if purge single page action sent and purge cache. */ public function handle_purge_single_page_cache() { if (!$this->can_purge_cache()) return; if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { if (isset($_GET['wpo_single_page_cache_purged'])) { $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; } else { $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; } add_action('admin_notices', array($this, $notice_function)); return; } if (!isset($_GET['_wpo_purge'])) return; if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) { $success = false; if (is_admin()) { $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; if ($post > 0) { $success = self::delete_single_post_cache($post); } } else { $success = self::delete_cache_by_url(wpo_current_url()); } // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) { $success = self::purge(); // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } } /** * Show notification when page cache purged successfully. */ public function notice_purge_single_page_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when page cache wasn't purged. */ public function notice_purge_single_page_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification when all pages cache purged successfully. */ public function notice_purge_all_pages_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when all pages cache wasn't purged. */ public function notice_purge_all_pages_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification in WordPress admin. * * @param string $message HTML (no further escaping is performed) * @param string $type error, warning, success, or info */ public function show_notice($message, $type) { global $current_screen; if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?> <script> window.addEventListener('load', function() { (function(wp) { if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) { wp.data.dispatch('core/notices').createNotice( '<?php echo $type; ?>', '<?php echo $message; ?>', { isDismissible: true, } ); } })(window.wp); }); </script> <?php else : ?> <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible"> <p><?php echo $message; ?></p> </div> <?php endif; } /** * Enables page cache * * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings * * @return WP_Error|bool - true on success, error otherwise */ public function enable($force_enable = false) { static $already_ran_enable = false; if ($already_ran_enable) return $already_ran_enable; $folders_created = $this->create_folders(); if (is_wp_error($folders_created)) { $already_ran_enable = $folders_created; return $already_ran_enable; } // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) { $force_enable = true; } if (!$force_enable) { $already_ran_enable = true; return true; } if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) { $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); if (!defined('WP_CLI') || !WP_CLI) { $message .= "\n\n".sprintf(__('1. Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); $message .= "\n".__('2. Edit or create a file with the name advanced-cache.php', 'wp-optimize'); $message .= "\n".__('3. Copy and paste the following lines into the file:', 'wp-optimize'); } $already_ran_enable = new WP_Error("write_advanced_cache", $message); return $already_ran_enable; } if (!$this->write_wp_config(true)) { $already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions."); return $already_ran_enable; } if (!$this->verify_cache()) { $errors = $this->get_errors(); $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors)); return $already_ran_enable; } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { $ret = true; $advanced_cache_file = $this->get_advanced_cache_filename(); // N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem. $disabled_wp_config = $this->write_wp_config(false); if (!$disabled_wp_config) { $this->log("Could not turn off the WP_CACHE constant in wp-config.php"); $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize')); } $disabled_advanced_cache = true; // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { $disabled_advanced_cache = false; $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize')); } } // If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled. if (!$disabled_wp_config && !$disabled_advanced_cache) { $ret = new WP_Error('error_disabling_cache', __('The page caching could not be disabled: the WP_CACHE constant could not be removed from wp-config.php and the request to the filesystem to remove or empty advanced-cache.php failed.', 'wp-optimize')); } // Delete cache to avoid stale cache on next activation $this->purge(); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } /** * Fires after purging the cache */ do_action('wpo_cache_flush'); return true; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!defined('WP_CACHE') || !WP_CACHE) { return false; } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { return false; } if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { return false; } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ private function create_folders() { if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR))); } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR))); } if (!is_dir(WPO_CACHE_FILES_DIR)) { if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR))); } else { wpo_disable_cache_directories_viewing(); } } return true; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_advanced_cache_filename() { return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_cache_config_filename() { $url = parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { return 'config-'.$url['host'].'-port'.$url['port'].'.php'; } else { return 'config-'.$url['host'].'.php'; } } /** * Writes advanced-cache.php * * @param boolean $update_required - Whether the update is required or not. * @return bool */ private function write_advanced_cache($update_required = false) { $config_file_basename = $this->get_cache_config_filename(); $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__)); $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $cache_path = '/wpo-cache'; $cache_files_path = '/cache/wpo-cache'; $cache_extensions_path = WPO_CACHE_EXT_DIR; $wpo_version = WPO_VERSION; $wpo_home_url = trailingslashit(home_url()); // CS does not like heredoc // phpcs:disable $this->advanced_cache_file_content = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); // WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks) if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); \$possible_plugin_locations = array( defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false, defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false, dirname(__FILE__).'/plugins/$plugin_basename/cache', '$cache_file_basename', ); \$plugin_location = false; foreach (\$possible_plugin_locations as \$possible_location) { if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) { \$plugin_location = \$possible_location; break; } } if (false === \$plugin_location) { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', true); \$protocol = \$_SERVER['REQUEST_SCHEME']; \$host = \$_SERVER['HTTP_HOST']; \$request_uri = \$_SERVER['REQUEST_URI']; if (strcasecmp('$wpo_home_url', \$protocol . '://' . \$host . \$request_uri) === 0) { error_log('WP-Optimize: No caching took place, because the plugin location could not be found'); } } else { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', false); } if (is_admin()) { return; } if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path'); if (false !== \$plugin_location) { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions'); } else { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); } if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; } \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true); if (empty(\$GLOBALS['wpo_cache_config'])) { include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'); } if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); } EOF; // phpcs:enable $advanced_cache_filename = $this->get_advanced_cache_filename(); // If the file content is already up to date, success if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) { $this->advanced_cache_file_writing_error = false; return true; } // check if we can't write the advanced cache file // case 1: the directory is read-only and the file doesn't exist if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) { $this->advanced_cache_file_writing_error = true; return false; } // case 2: the file already exists but it's read-only if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) { if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) { $this->advanced_cache_file_writing_error = true; return false; } else { $this->advanced_cache_file_writing_error = false; return true; } } if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) { $this->advanced_cache_file_writing_error = true; return false; } $this->advanced_cache_file_writing_error = false; return true; } /** * Update advanced cache version if needed. */ public function maybe_update_advanced_cache() { if (!$this->is_enabled()) return; if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND') || (defined('WPO_PLUGIN_LOCATION_NOT_FOUND') && true === WPO_PLUGIN_LOCATION_NOT_FOUND)) { if (!$this->write_advanced_cache(true)) { add_action('admin_notices', array($this, 'show_admin_notice_advanced_cache')); } } // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php $advanced_cache_current_version = $this->get_advanced_cache_version(); if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return; if (!$this->write_advanced_cache()) { add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); } else { $this->update_cache_config(); } } /** * Show notification when advanced-cache.php could not be updated. */ public function notice_advanced_cache_autoupdate_error() { $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp-optimize'). ' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to disable and then re-enable the WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error'); } /** * Get WPO version number from advanced-cache.php file. * * @return bool|mixed */ public function get_advanced_cache_version() { if (!is_file($this->get_advanced_cache_filename())) return false; $version = false; $content = file_get_contents($this->get_advanced_cache_filename()); if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { $version = $match[1]; } return $version; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { // If we changed the value in wp-config, save it, in case we need to change it again in the same run. static $changed = false; if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r\n)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) { return false; } $changed = true; return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } $errors = 0; // First check wp-config.php. if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize')); } $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; // Now check wp-content. We need to be able to create files of the same user as this file. if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) { $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); $this->add_error('verify_cache', __("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions", 'wp-optimize')); $errors++; } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); $this->add_warning('verify_cache', sprintf(__("Unable to write inside the cache files folder (%s); please check file/folder permissions (no cache files will be able to be created otherwise)", 'wp-optimize'), WPO_CACHE_FILES_DIR)); } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); // If the config exists, only send a warning. Otherwise send an error. $type = 'warning'; if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) { $type = 'error'; $errors++; } $this->add_error('verify_cache', sprintf(__("Unable to write inside the cache configuration folder (%s); please check file/folder permissions", 'wp-optimize'), WPO_CACHE_CONFIG_DIR), $type); } } return !$errors; } /** * Update cache config. Used to support 3d party plugins. */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. $this->config->update($current_config, true); } /** * Delete information about cache size. */ public function delete_cache_size_information() { delete_transient('wpo_get_cache_size'); } /** * Get current cache size. * * @return array */ public function get_cache_size() { $cache_size = get_transient('wpo_get_cache_size'); if (!empty($cache_size)) return $cache_size; $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); $cache_size = array( 'size' => $infos['size'], 'file_count' => $infos['file_count'] ); set_transient('wpo_get_cache_size', $cache_size); return $cache_size; } /** * Fetch directory informations. * * @param string $dir * @return array */ private function get_dir_infos($dir) { $dir_size = 0; $file_count = 0; $handle = is_dir($dir) ? opendir($dir) : false; if (false === $handle) { return array('size' => 0, 'file_count' => 0); } $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { $current_file = $dir.'/'.$file; if (is_dir($current_file)) { $sub_dir_infos = $this->get_dir_infos($current_file); $dir_size += $sub_dir_infos['size']; $file_count += $sub_dir_infos['file_count']; } elseif (is_file($current_file)) { $dir_size += filesize($current_file); $file_count++; } } $file = readdir($handle); } return array('size' => $dir_size, 'file_count' => $file_count); } /** * Returns the path to wp-config * * @return string|boolean wp-config.php path. */ private function _get_wp_config() { $config_path = false; foreach (get_included_files() as $filename) { if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) { $config_path = $filename; break; } } // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file. if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) { $config_path = wpo_wp_cli_locate_wp_config(); } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Delete cached files for specific url. * * @param string $url * @param bool $recursive If true child elements will deleted too * * @return bool */ public static function delete_cache_by_url($url, $recursive = false) { if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; $path = self::get_full_path_from_url($url); do_action('wpo_delete_cache_by_url', $url, $recursive); return wpo_delete_files($path, $recursive); } /** * Delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function delete_single_post_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url); // for posts with pagination run purging cache recursively. $post = get_post($post_id); $recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false; do_action('wpo_delete_cache_by_url', $post_url, $recursive); return wpo_delete_files($path, $recursive); } /** * Delete cached home page files. */ public static function delete_homepage_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url); do_action('wpo_delete_cache_by_url', $homepage_url, false); wpo_delete_files($path, false); } /** * Delete sitemap cahche. */ public static function delete_sitemap_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($homepage_url)); if (!is_dir($path)) return; $handle = opendir($path); if (false !== $handle) { $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file && is_dir($path . $file) && preg_match('/.*sitemap.*\.xml/i', $file)) { do_action('wpo_delete_cache_by_url', $path . $file, false); wpo_delete_files($path . $file, true); } $file = readdir($handle); } } closedir($handle); } /** * Delete feed from cache. */ public static function delete_feed_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete post feed from cache. */ public static function delete_post_feed_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete comments feed from cache. */ public static function delete_comments_feed() { if (!defined('WPO_CACHE_FILES_DIR')) return; $comments_feed_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/feed/'; $path = self::get_full_path_from_url($comments_feed_url); do_action('wpo_delete_cache_by_url', $comments_feed_url, true); wpo_delete_files($path, true); // delete empty comments dir from the cache $comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/'; $path = self::get_full_path_from_url($comments_url); if (wpo_is_empty_dir($path)) { wpo_delete_files($path, true); } } /** * Returns full path to the cache folder by url. * * @param string $url * @return string */ private static function get_full_path_from_url($url) { return trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url)); } /** * Admin actions * * @return void */ public function admin_init() { // Maybe update the advanced cache. if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { $this->maybe_update_advanced_cache(); } } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log($message, 'error'); } else { error_log($message); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Adds an error to the error store * * @param string $code - The error code * @param string $message - The error's message * @param string $type - The error's type (error, warning) * @return void */ public function add_error($code, $message, $type = 'error') { if (!isset($this->_errors[$type])) { $this->_errors[$type] = new WP_Error($code, $message); } else { $this->_errors[$type]->add($code, $message); } } /** * Adds a warning to the error store * * @param string $code - The error code * @param string $message - The error's message * @return void */ public function add_warning($code, $message) { $this->add_error($code, $message, 'warning'); } /** * Get all recorded errors * * @param string $type - The error type * @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object * @return boolean|array|WP_Error */ public function get_errors($type = 'error', $get_messages_only = true) { if (!$this->has_errors($type)) return false; $errors = $this->_errors[$type]; if ($get_messages_only) { return $errors->get_error_messages(); } return $errors; } /** * Check if any errors were recorded * * @param string $type - The error type * @return boolean */ public function has_errors($type = 'error') { return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors(); } /** * Check if any warnings were recorded * * @return boolean */ public function has_warnings() { return $this->has_errors('warning'); } /** * Check the cache compatibility issues. */ public function check_compatibility_issues() { if (!$this->is_enabled()) return; if ($this->is_pagespeedninja_gzip_active()) add_action('admin_notices', array($this, 'show_pagespeedninja_gzip_notice')); if ($this->is_farfutureexpiration_gzip_active()) add_action('admin_notices', array($this, 'show_farfutureexpiration_gzip_notice')); } /** * Check if PageSpeed Ninja is active and GZIP compression option is enabled. * * @return bool */ public function is_pagespeedninja_gzip_active() { if (!class_exists('PagespeedNinja')) return false; $options = get_option('pagespeedninja_config'); $gzip = !empty($options) ? (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip'] : false; return $gzip; } /** * Output PageSpeed Ninja Gzip notice. */ public function show_pagespeedninja_gzip_notice() { echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in PageSpeed Ninja to prevent conflicts.', 'wp-optimize').'</p></div>'; } /** * Check if Far Future Expiration is active and GZIP compression option is enabled. * * @return bool */ public function is_farfutureexpiration_gzip_active() { if (!class_exists('farFutureExpiration')) return false; $options = get_option('far_future_expiration_settings'); $gzip = !empty($options) ? (bool) $options['enable_gzip'] : false; return $gzip; } /** * Output Far Future Expiration Gzip notice. */ public function show_farfutureexpiration_gzip_notice() { echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in Far Future Expiration to prevent conflicts.', 'wp-optimize').'</p></div>'; } /** * This is a notice to show users that writing `advanced-cache.php` failed */ public function show_admin_notice_advanced_cache() { $message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message)); } } endif; wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/file-based-page-cache-functions.php 000644 000000 000000 00000110221 14173760430 035005 0 ustar 00root wheel 000000 000000 cms/wordpress <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above. * * @param String $buffer Page HTML. * @param Int $flags OB flags to be passed through. * * @return String */ if (!function_exists('wpo_cache')) : function wpo_cache($buffer, $flags) { // This case appears to happen for unclear reasons without WP being fully loaded, e.g. https://wordpress.org/support/topic/fatal-error-since-wp-5-8-update/ . It is simplest just to short-circuit it. if ('' === $buffer) return ''; // This array records reasons why no cacheing took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately. $no_cache_because = array(); if (strlen($buffer) < 255) { $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth caching', 'wp-optimize'), 255); } // Don't cache pages for logged in users. if (empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && (!function_exists('wpo_we_cache_per_role') || !wpo_we_cache_per_role()) && (!function_exists('is_user_logged_in') || (function_exists('wp_get_current_user') && is_user_logged_in()))) { $no_cache_because[] = __('User is logged in', 'wp-optimize'); } $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_page_type_cache) { $no_cache_because[] = $restricted_page_type_cache; } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) { $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')'; } elseif (!file_exists(WPO_CACHE_FILES_DIR)) { // Try creating a folder for cached files, if it was flushed recently if (!mkdir(WPO_CACHE_FILES_DIR)) { $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')'; } else { wpo_disable_cache_directories_viewing(); } } // If comments are opened and the user has saved his information. if (function_exists('comments_open') && function_exists('get_post') && get_post() && comments_open()) { $commenter = wp_get_current_commenter(); // if any of the fields contain something, do not save to cache if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) { $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize'); } } $can_cache_page = true; if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { $can_cache_page = false; } /** * Defines if the page can be cached or not * * @param boolean $can_cache_page */ $can_cache_page_filter = apply_filters('wpo_can_cache_page', $can_cache_page); if (!$can_cache_page_filter) { if ($can_cache_page) { $can_cache_page = false; $no_cache_because[] = __('wpo_can_cache_page filter forbade it', 'wp-optimize'); } else { $no_cache_because[] = __('DONOTCACHEPAGE constant forbade it and wpo_can_cache_page filter did not over-ride it', 'wp-optimize'); } } if (defined('REST_REQUEST') && REST_REQUEST) { $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize'); } // Don't cache with fatal error pages. $last_error = error_get_last(); if (is_array($last_error) && E_ERROR == $last_error['type']) { $no_cache_because[] = __('This page has a fatal error', 'wp-optimize'); } if (http_response_code() >= 500) { $no_cache_because[] = sprintf(__('This page has a critical error (HTTP code %s)', 'wp-optimize'), http_response_code()); } elseif (http_response_code() >= 400) { $no_cache_because[] = sprintf(__('This page returned an HTTP unauthorised response code (%s)', 'wp-optimize'), http_response_code()); } if (empty($no_cache_because)) { $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)"; break; } } } } } if (!empty($no_cache_because)) { $message = implode(', ', $no_cache_because); // Add http headers wpo_cache_add_nocache_http_header($message); // Only output if the user has turned on debugging output if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) { $buffer .= "\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached because: ".htmlspecialchars($message)." -->\n"; } return $buffer; } else { // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } $modified_time = time(); // Take this as soon before writing as possible $add_to_footer = ''; /** * Filter wether to display the html comment <!-- Cached by WP-Optimize ... --> * * @param boolean $show - Wether to display the html comment * @return boolean */ if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } else { $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n"; } } // Create an empty index.php file in the cache directory for disable directory viewing. if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', ''); /** * Save $buffer into cache file. */ $file_ext = '.html'; if (wpo_feeds_caching_enabled()) { if (is_feed()) { $file_ext = '.rss-xml'; } } $cache_filename = wpo_cache_filename($file_ext); $cache_file = $path . '/' .$cache_filename; if (defined('WPO_CACHE_FILENAME_DEBUG') && WPO_CACHE_FILENAME_DEBUG) { $add_to_footer .= "\n<!-- WP Optimize page cache debug information -->\n"; if (!empty($GLOBALS['wpo_cache_filename_debug']) && is_array($GLOBALS['wpo_cache_filename_debug'])) { $add_to_footer .= "<!-- \n" . join("\n", array_map('htmlspecialchars', $GLOBALS['wpo_cache_filename_debug'])) . "\n --->"; } } // if we can then cache gzipped content in .gz file. if (function_exists('gzencode')) { // Only replace inside the addition, not inside the main buffer (e.g. post content) file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6))); } file_put_contents($cache_file, $buffer.$add_to_footer); if (is_callable('WP_Optimize')) { // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); } else { error_log('[WPO_CACHE] WP_Optimize() is not callable.'); $message = 'Please report this to WP-O support: '; if (function_exists('wp_debug_backtrace_summary')) { $message .= wp_debug_backtrace_summary(); } else { $message .= wpo_debug_backtrace_summary(); } error_log($message); } header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header('WPO-Cache-Status: saving to cache'); if (wpo_cache_can_output_gzip_content()) { if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) { header('Content-Encoding: gzip'); } // disable php gzip to avoid double compression. ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set return ob_gzhandler($buffer, $flags); } else { return $buffer; } } } endif; /** * Load files for support plugins. */ if (!function_exists('wpo_cache_load_extensions')) : function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); // Add external extensions if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) { $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php')); } if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } endif; if (!function_exists('wpo_restricted_cache_page_type')) { function wpo_restricted_cache_page_type($restricted) { global $post; // Don't cache search or password protected. if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) { $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize'); } // Don't cache the front page if option is set. if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) { $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize'); } // Don't cache htacesss. Remember to properly escape any output to prevent injection. if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')'; } // Don't cache feeds. if (function_exists('is_feed') && is_feed() && !wpo_feeds_caching_enabled()) { $restricted = __('We don\'t cache RSS feeds', 'wp-optimize'); } return $restricted; } } /** * Returns true if we need cache content for loggedin users. * * @return bool */ if (!function_exists('wpo_cache_loggedin_users')) : function wpo_cache_loggedin_users() { return !empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) || (function_exists('wpo_we_cache_per_role') && wpo_we_cache_per_role()); } endif; /** * Returns true if we need to cache content for loggedin users. * * @return bool */ if (!function_exists('wpo_user_specific_cache_enabled')) : function wpo_user_specific_cache_enabled() { return !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_auth']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_logged_in']); } endif; /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ if (!function_exists('wpo_cache_filename')) : function wpo_cache_filename($ext = '.html') { $wpo_cache_filename_debug = array(); $filename = 'index'; if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. * This section was inspired by things learned from WP-Rocket. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $key . '[' . $cookie_key . '], value: *** , cache_key:' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $cookie_name . ', value: *** , cache_key:' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'GET parameter: name: ' . $variable . ', value:' . htmlentities($_GET[$variable]) . ', cache_key:' . $_cache_key; } } } // add hash of queried cookies and variables to cache file name. if ('' !== $cache_key) { $hash = md5($cache_key); $filename .= '-'.$hash; $wpo_cache_filename_debug[] = 'Hash: ' . $hash; } $filename = apply_filters('wpo_cache_filename', $filename); $wpo_cache_filename_debug[] = 'Extension: ' . $ext; $wpo_cache_filename_debug[] = 'Filename: ' . $filename.$ext; $GLOBALS['wpo_cache_filename_debug'] = $wpo_cache_filename_debug; return $filename . $ext; } endif; /** * Returns site url from site_url() function or if it is not available from cache configuration. */ if (!function_exists('wpo_site_url')) : function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } endif; /** * Get cookie names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_cookies')) : function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } endif; /** * Get GET variable names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_query_variables')) : function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return wpo_cache_maybe_ignore_query_variables($variables); } endif; /** * Get list of all received HTTP headers. * * @return array */ if (!function_exists('wpo_get_http_headers')) : function wpo_get_http_headers() { static $headers; if (!empty($headers)) return $headers; $headers = array(); // if is apache server then use get allheaders() function. if (function_exists('getallheaders')) { $headers = getallheaders(); } else { // https://www.php.net/manual/en/function.getallheaders.php foreach ($_SERVER as $key => $value) { $key = strtolower($key); if ('HTTP_' == substr($key, 0, 5)) { $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value; } elseif ('content_type' == $key) { $headers["Content-Type"] = $value; } elseif ('content_length' == $key) { $headers["Content-Length"] = $value; } } } return $headers; } endif; /** * Check if requested Accept-Encoding headers has gzip value. * * @return bool */ if (!function_exists('wpo_cache_gzip_accepted')) : function wpo_cache_gzip_accepted() { $headers = wpo_get_http_headers(); if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true; return false; } endif; /** * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value * and function ob_gzhandler is available. * * @return bool */ if (!function_exists('wpo_cache_can_output_gzip_content')) : function wpo_cache_can_output_gzip_content() { return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler'); } endif; /** * Check if header with certain name exists in already prepared headers and has value comparable with $header_value. * * @param string $header_name header name * @param string $header_value header value as regexp. * * @return bool */ if (!function_exists('wpo_cache_is_in_response_headers_list')) : function wpo_cache_is_in_response_headers_list($header_name, $header_value) { $headers_list = headers_list(); if (!empty($headers_list)) { $header_name = strtolower($header_name); foreach ($headers_list as $value) { $value = explode(':', $value); if (strtolower($value[0]) == $header_name) { if (preg_match('/'.$header_value.'/', $value[1])) { return true; } else { return false; } } } } return false; } endif; /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ if (!function_exists('wpo_cache_mobile_caching_enabled')) : function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } endif; /** * Serves the cache and exits */ if (!function_exists('wpo_serve_cache')) : function wpo_serve_cache() { $file_name = wpo_cache_filename(); $file_name_rss_xml = wpo_cache_filename('.rss-xml'); $send_as_feed = false; $path_dir = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/'; $path = $path_dir . $file_name; if (wpo_feeds_caching_enabled()) { // check for .xml cache file if .html cache file doesn't exist if (!file_exists($path_dir . $file_name) && file_exists($path_dir . $file_name_rss_xml)) { $path = $path_dir . $file_name_rss_xml; $send_as_feed = true; } } $use_gzip = false; // if we can use gzip and gzipped file exist in cache we use it. // if headers already sent we don't use gzipped file content. if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) { $path .= '.gz'; $use_gzip = true; } $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } // disable zlib output compression to avoid double content compression. if ($use_gzip) { ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set } $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip'); header('Cache-Control: no-cache'); // Check back later if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } // send correct headers for xml and txt files $filename = basename(dirname($path)); if (preg_match('/\.xml$/i', $filename)) { header('Content-type: text/xml'); } if (preg_match('/\.txt$/i', $filename)) { header('Content-type: text/plain'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); if (!empty($modified_time)) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); } readfile($path); exit; } } endif; /** * Clears the cache */ if (!function_exists('wpo_cache_flush')) : function wpo_cache_flush() { if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } endif; /** * Get URL path for caching * * @since 1.0 * @return string */ if (!function_exists('wpo_get_url_path')) : function wpo_get_url_path($url = '') { $url = '' == $url ? wpo_current_url() : $url; $url_parts = parse_url($url); if (isset($url_parts['path']) && false !== stripos($url_parts['path'], '/index.php')) { $url_parts['path'] = preg_replace('/(.*?)index\.php(\/.+)/i', '$1index-php$2', $url_parts['path']); } if (!isset($url_parts['host'])) $url_parts['host'] = ''; if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].$url_parts['path']; } endif; /** * Get requested url. * * @return string */ if (!function_exists('wpo_current_url')) : function wpo_current_url() { // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot). // Otherwise this function would return a different URL at the begining and end of the cache process. static $url = ''; if ('' != $url) return $url; $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . $http_host.$_SERVER['REQUEST_URI'], '/'); return $url; } endif; /** * Return list of url exceptions. * * @return array */ if (!function_exists('wpo_get_url_exceptions')) : function wpo_get_url_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; // if called from file-based-page-cache.php when WP loading // and cache settings exists then use it otherwise get settings from database. if (isset($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = array(); } else { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); } } else { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_urls', $config)) { $exceptions = $config['cache_exception_urls']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } return apply_filters('wpo_get_url_exceptions', $exceptions); } endif; /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ if (!function_exists('wpo_current_url_exception_match')) : function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } endif; /** * Check if url in exceptions list. * * @param string $url * * @return bool */ if (!function_exists('wpo_url_in_exceptions')) : function wpo_url_in_exceptions($url) { $exceptions = wpo_get_url_exceptions(); if (!empty($exceptions)) { foreach ($exceptions as $exception) { // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type() if ('/' == $exception) continue; if (wpo_url_exception_match($url, $exception)) { // Exception match. return true; } } } return false; } endif; /** * Check if url string match with exception. * * @param string $url - complete url string i.e. http(s):://domain/path * @param string $exception - complete url or absolute path, can consist (.*) wildcards * * @return bool */ if (!function_exists('wpo_url_exception_match')) : function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // used to test websites placed in subdirectories. $sub_dir = ''; // if exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = rtrim($url, '/') . '/'; $exception = rtrim($exception, '/'); // if we have no wildcat in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = preg_quote($exception); // fix - unescape possible escaped mask .* $exception = str_replace('\\.\\*', '.*', $exception); return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url); } endif; /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ if (!function_exists('wpo_is_mobile')) : function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } endif; /** * Check if current browser agent is not disabled in options. * * @return bool */ if (!function_exists('wpo_is_accepted_user_agent')) : function wpo_is_accepted_user_agent($user_agent) { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } endif; /** * Delete function that deals with directories recursively * * @param string $src Path of the folder * @param boolean $recursive If $src is a folder, recursively delete the inner folders. If set to false, only the files will be deleted. * * @return bool */ if (!function_exists('wpo_delete_files')) : function wpo_delete_files($src, $recursive = true) { if (!file_exists($src) || '' == $src || '/' == $src) { return true; } if (is_file($src)) { return unlink($src); } $success = true; $has_dir = false; if ($recursive) { // N.B. If opendir() fails, then a false positive (i.e. true) will be returned if (false !== ($dir = opendir($src))) { $file = readdir($dir); while (false !== $file) { if ('.' == $file || '..' == $file) { $file = readdir($dir); continue; } if (is_dir($src . '/' . $file)) { if (!wpo_delete_files($src . '/' . $file)) { $success = false; } } else { if (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($dir); } closedir($dir); } } else { // Not recursive, so we only delete the files // scan directories recursively. $handle = opendir($src); if (false === $handle) return false; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { if (is_dir($src . '/' . $file)) { $has_dir = true; } elseif (!unlink($src . '/' . $file)) { $success = false; } } $file = readdir($handle); } } if ($success && !$has_dir) { // Success of this operation is not recorded; we only ultimately care about emptying, not removing entirely (empty folders in our context are harmless) rmdir($src); } // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); return $success; } endif; if (!function_exists('wpo_is_empty_dir')) : /** * Check if selected directory is empty or has only index.php which we added for security reasons. * * @param string $dir * * @return bool */ function wpo_is_empty_dir($dir) { if (!file_exists($dir) || !is_dir($dir)) return false; $handle = opendir($dir); if (false === $handle) return false; $is_empty = true; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file && 'index.php' != $file) { $is_empty = false; break; } $file = readdir($handle); } closedir($handle); return $is_empty; } endif; /** * Either store for later output, or output now. Only the most-recent call will be effective. * * @param String|Null $output - if not null, then the string to use when called by the shutdown action. */ if (!function_exists('wpo_cache_add_footer_output')) : function wpo_cache_add_footer_output($output = null) { static $buffered = null; if (function_exists('current_filter') && 'shutdown' == current_filter()) { // Only add the line if it was a page, not something else (e.g. REST response) if (function_exists('did_action') && did_action('wp_footer')) { echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".$buffered." -->\n"; } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG) { error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered); } } else { if (null == $buffered && function_exists('add_action')) add_action('shutdown', 'wpo_cache_add_footer_output', 11); $buffered = $output; } } endif; /** * Remove variable names that shouldn't influence cache. * * @param array $variables List of variable names. * * @return array */ if (!function_exists('wpo_cache_maybe_ignore_query_variables')) : function wpo_cache_maybe_ignore_query_variables($variables) { /** * Filters the current $_GET variables that will be used when caching or excluding from cache. * Currently: * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set) * - 'doing_wp_cron' (alternative cron) * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap) * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap) * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap) */ $exclude_variables = array( 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set 'doing_wp_cron', // alternative cron 'aiosp_sitemap_path', // All in one SEO sitemap 'aiosp_sitemap_page', 'xml_sitemap', // SEOPress sitemap 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged', 'sitemap', // YOAST SEO sitemap 'sitemap_n', ); $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables; if (empty($exclude_variables)) return $variables; foreach ($exclude_variables as $variable) { $exclude = array_search($variable, $variables); if (false !== $exclude) { array_splice($variables, $exclude, 1); } } return $variables; } endif; /** * Get cache config * * @param string $key - The config item * @param mixed $default - The default value * * @return mixed */ if (!function_exists('wpo_cache_config_get')) : function wpo_cache_config_get($key, $default = false) { $config = $GLOBALS['wpo_cache_config']; if (!$config) return false; if (isset($config[$key])) { return $config[$key]; } else { return $default; } } endif; if (!function_exists('wpo_disable_cache_directories_viewing')) : function wpo_disable_cache_directories_viewing() { global $is_apache, $is_IIS, $is_iis7; if (!is_dir(WPO_CACHE_FILES_DIR)) return; // Create .htaccess file for apache server. if ($is_apache) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // CS does not like heredoc // phpcs:disable $htaccess_content = <<<EOF # Disable directory browsing Options -Indexes # Disable access to any files <FilesMatch ".*"> Order allow,deny Deny from all </FilesMatch> EOF; // phpcs:enable if (!is_file($htaccess_filename)) @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create web.config file for IIS servers. if ($is_IIS || $is_iis7) { $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config'; $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n"; if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } // Create empty index.php file for all servers. if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', '');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } endif; /** * Add the headers indicating why the page is not cached or served from cache * * @param string $message - The headers * * @return void */ if (!function_exists('wpo_cache_add_nocache_http_header')) : function wpo_cache_add_nocache_http_header($message = '') { static $buffered_message = null; if (function_exists('current_filter') && 'send_headers' === current_filter() && $buffered_message && !headers_sent()) { header('WPO-Cache-Status: not cached'); header('WPO-Cache-Message: '. trim(str_replace(array("\r", "\n", ':'), ' ', strip_tags($buffered_message)))); } else { if (!$buffered_message && function_exists('add_action')) add_action('send_headers', 'wpo_cache_add_nocache_http_header', 11); $buffered_message = $message; } } endif; /** * Check if feeds caching enabled * * @return bool */ if (!function_exists('wpo_feeds_caching_enabled')) : function wpo_feeds_caching_enabled() { return apply_filters('wpo_feeds_caching_enabled', true); } endif; if (!function_exists('wpo_debug_backtrace_summary')) { function wpo_debug_backtrace_summary($ignore_class = null, $skip_frames = 0, $pretty = true) { static $truncate_paths; $trace = debug_backtrace(false); $caller = array(); $check_class = !is_null($ignore_class); $skip_frames++; // Skip this function. if (!isset($truncate_paths)) { $truncate_paths = array( wpo_normalize_path(WP_CONTENT_DIR), wpo_normalize_path(ABSPATH), ); } foreach ($trace as $call) { if ($skip_frames > 0) { $skip_frames--; } elseif (isset($call['class'])) { if ($check_class && $ignore_class == $call['class']) { continue; // Filter out calls. } $caller[] = "{$call['class']}{$call['type']}{$call['function']}"; } else { if (in_array($call['function'], array('do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array'), true)) { $caller[] = "{$call['function']}('{$call['args'][0]}')"; } elseif (in_array($call['function'], array('include', 'include_once', 'require', 'require_once'), true)) { $filename = isset($call['args'][0]) ? $call['args'][0] : ''; $caller[] = $call['function'] . "('" . str_replace($truncate_paths, '', wpo_normalize_path($filename)) . "')"; } else { $caller[] = $call['function']; } } } if ($pretty) { return implode(', ', array_reverse($caller)); } else { return $caller; } } } if (!function_exists('wpo_normalize_path')) { function wpo_normalize_path($path) { // Standardise all paths to use '/'. $path = str_replace('\\', '/', $path); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. $path = preg_replace('|(?<=.)/+|', '/', $path); // Windows paths should uppercase the drive letter. if (':' === substr($path, 1, 1)) { $path = ucfirst($path); } return $path; } } cms/wordpress/wp-optimize-versions/wp-optimize.3.2.2/wp-optimize/cache/class-wpo-load-url-task.php 000644 000000 000000 00000003024 14151417634 033500 0 ustar 00root wheel 000000 000000 <?php if (!defined('ABSPATH')) die('Access denied.'); if (!class_exists('Updraft_Task_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php'); if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php'); class WP_Optimize_Load_Url_Task extends Updraft_Task_1_2 { /** * Default options. */ public function get_default_options() { return array(); } /** * Run preload http requests with different user-agent values to cache pages for different devices. * * @return bool */ public function run() { $url = $this->get_option('url'); if (empty($url)) return; $cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); // load pages with different user-agents values. $cache_preloader->preload_desktop($url); $cache_preloader->preload_mobile($url); $cache_preloader->preload_amp($url); if (defined('WP_CLI') && WP_CLI) { WP_CLI::log($url); } /** * Action triggered after preloading a single url * * @param string $url The url to preload * @param object $cache_preloader Cache preloader instance */ do_action('wpoptimize_after_preload_url', $url, $cache_preloader); /** * Allows to change the delay between each URL preload, to reduce server load. * * @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second). */ usleep(apply_filters('wpoptimize_preload_delay', 500000)); return true; } } cms/webasyst/cache/ 000755 000000 000000 00000000000 14214665000 014641 5 ustar 00root wheel 000000 000000 cms/webasyst/cache/waConfigCache.class.php 000644 000000 000000 00000013517 14202631424 021146 0 ustar 00root wheel 000000 000000 <?php /** * Transparent memory cache for config files. * * To enable this caching strategy, set up default memory cache * (such as Memcache, XCache or Redis) via wa-config/cache.php, then set * 'config_cache_enable' => true in wa-config/config.php * * Note that file cache adapter makes no sense for this type of caching, * only in-memory cache should be used. */ class waConfigCache { protected static $instance; /** * @var $cache_adapter waMemcachedCacheAdapter */ protected static $cache_adapter = false; /** * @return waConfigCache singleton instance */ public static function getInstance() { if (!isset(self::$instance)) { self::$cache_adapter = false; $framework_is_ready = function_exists('wa') && class_exists('waConfig') && waConfig::has('wa_path_root'); // Do not use cache unless explicitly enabled if ($framework_is_ready && waSystemConfig::systemOption('config_cache_enable') === true) { try { self::$cache_adapter = wa('wa-system')->getCache(); } catch (Exception $e) { $framework_is_ready = false; } } if (!$framework_is_ready) { // Framework is not ready, called too early. // Return an instance of self but do not save it to self::$instance // so that we attempt to do that again later. return new self(); } else { self::$instance = new self(); } } return self::$instance; } /** * Drop-in replacement for include() that transparently uses cache if available. * @param string $file path to config file * @param bool $compare_filemtime false to return cache contents even if older than modification time of config file * @return mixed config file contents, as include() would return; usually PHP array */ public function includeFile($file, $compare_filemtime = true) { $normalized_key = false; if (self::$cache_adapter) { $normalized_key = $this->normalizeKey($file); } if (self::$cache_adapter && $normalized_key) { $cache = self::$cache_adapter->get($normalized_key); if (!empty($cache['value']) && (!$compare_filemtime || $cache['timestamp'] >= filemtime($file))) { // config_cache_debug option allows to compare cached value to actual config file. // It will write to wa-log when cache returns different value compared to what is in file. // Note that it does nothing to fix the difference even when found. // This option should not be normally enabled in live environments. if (waSystemConfig::systemOption('config_cache_debug')) { $value_from_file = include($file); if ($value_from_file != $cache['value']) { waLog::dump( 'Difference found between cached value and actual file config (compare_filemtime='.($compare_filemtime?'true':'false').').', "cached data (cache key `{$normalized_key}`):", $cache['value'], "read from config file (file path `{$file}`):", $value_from_file, 'config_cache_debug.log' ); } } return $cache['value']; } } $new_cache = include($file); if (self::$cache_adapter && $normalized_key) { self::setFileContents($normalized_key, $new_cache); } return $new_cache; } /** * Remove cache contents for a single config file, or clear all cache. * @param string $file path to config file; omit to clear the whole cache */ public function clearCache($file = null) { if (self::$cache_adapter) { if ($file === null) { self::$cache_adapter->deleteAll(); } else { $normalized_key = $this->normalizeKey($file); if ($normalized_key) { self::$cache_adapter->delete($normalized_key); } } } } /** * Write config contents to cache without reading file from disk. * @param string $file path to config file * @param mixed $data config contents (usually PHP array) */ public function setFileContents($file, $data) { if (self::$cache_adapter) { $normalized_key = $this->normalizeKey($file); if ($normalized_key) { self::$cache_adapter->set($normalized_key, array( 'value' => $data, 'timestamp' => time(), )); } } } /** * Normalize file path before using it as cache key * @param string $file path to config file * @return bool|string valid cache key to use for given file, or false if file is not cacheable */ protected function normalizeKey($file) { if (!function_exists('wa') || mb_strlen($file) <= 0) { return false; } $file = realpath($file); if (!$file) { return false; } try { $root_path = wa()->getConfig()->getRootPath().DIRECTORY_SEPARATOR; } catch (Exception $e) { // Framework is not ready, called too early return false; } if (mb_substr($file, 0, mb_strlen($root_path)) !== $root_path) { // do not cache anything outside of framework directory return false; } // remove root path from the begining of the key return mb_substr($file, mb_strlen($root_path)); } } cms/webasyst/cache/waCacheAdapter.class.php 000644 000000 000000 00000001521 14202631424 021311 0 ustar 00root wheel 000000 000000 <?php /** * Base class for an adapter to abstract away communication * to a key/value storage such as Memcached. */ abstract class waCacheAdapter { protected $options; public function __construct($options) { $this->options = $options; $this->init(); } protected function init() { } public function key($key, $app_id, $group = null) { $key = trim($key, '/'); if (!$group || $group === true) { return $app_id.'/'. $key; } else { return $app_id.'/'.$group.'/'.$key; } } abstract public function get($key); abstract public function set($key, $value, $expiration = null, $group = null); abstract public function delete($key); abstract public function deleteGroup($group); abstract public function deleteAll(); } cms/webasyst/cache/waSystemCache.class.php 000644 000000 000000 00000000636 14202631424 021223 0 ustar 00root wheel 000000 000000 <?php class waSystemCache extends waVarExportCache { protected function getFilePath() { $path = waConfig::get('wa_path_cache').'/'.$this->key.'.php'; waFiles::create($path); return $path; } public function getFilemtime() { $path = $this->getFilePath(); if (file_exists($path)) { return filemtime($path); } return 0; } } cms/webasyst/cache/adapters/ 000755 000000 000000 00000000000 14214665074 016457 5 ustar 00root wheel 000000 000000 cms/webasyst/cache/waFileCache.class.php 000644 000000 000000 00000006311 14202631424 020612 0 ustar 00root wheel 000000 000000 <?php /* * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Webasyst LLC * @copyright 2011 Webasyst LLC * @package wa-system * @subpackage cache */ abstract class waFileCache implements waiCache { /** * Key * * @var string */ protected $key; /** * Expire time in sec * * @var int */ protected $ttl; protected $app_id; protected $value = null; /** * If you are not sure that the recorded cache will clear itself - use this flag. * In this case, the Framework will definitely remove it when the $this->ttl time expires. * @important On $this->writeToFile and $this->delete makes database queries! * @var bool */ protected $hard_clean = false; public function __construct($key, $ttl = -1, $app_id = null, $hard_clean = false) { $this->key = trim($key, '/'); $this->ttl = $ttl; $this->app_id = $app_id; $this->hard_clean = $hard_clean; } protected function getFilePath() { return waSystem::getInstance()->getCachePath('cache/'.$this->key.'.php', $this->app_id); } public function get() { if ($this->value !== null) { return $this->value; } $t = func_num_args() ? func_get_arg(0) : null; $this->value = $this->readFromFile($this->getFilePath(), $t); return $this->value; } public function set($value) { $this->value = null; $result = $this->writeToFile($this->getFilePath(), $value); if ($this->hard_clean) { $this->getCacheModel()->add($this->getCacheName(), $this->ttl); } // Update the value so that you can continue working with the object. // But only if that makes sense. // This will eliminate the excessive reading of the cache file, if after set we need get. if ($result && $this->ttl !== 0) { $this->value = $value; } return $result; } public function delete() { $this->value = null; if ($this->hard_clean) { $this->getCacheModel()->deleteByField('name', $this->getCacheName()); } $file = $this->getFilePath(); if (file_exists($file)) { return @unlink($file); } return true; } public function isCached() { return $this->get() === null ? false : true; } abstract protected function writeToFile($file, $v); abstract protected function readFromFile($file); protected function getCacheName() { $file = $this->getFilePath(); $root_path = wa()->getConfig()->getRootPath(); $name = str_replace($root_path, '', $file); return $name; } /** * @return waCacheModel */ protected function getCacheModel() { static $model; if ($model === null) { $model = new waCacheModel(); } return $model; } } cms/webasyst/cache/waVarExportCache.class.php 000644 000000 000000 00000003066 14202631424 021671 0 ustar 00root wheel 000000 000000 <?php /* * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Webasyst LLC * @copyright 2011 Webasyst LLC * @package wa-system * @subpackage cache */ class waVarExportCache extends waFileCache { protected function writeToFile($file, $v) { if ($this->ttl == 0) { return true; } $result = waUtils::varExportToFile($v, $file); if (!$result && waSystemConfig::isDebug()) { throw new waException("Cannot write to cache file ".$file, 601); } return $result; } /** * @param $file * @return mixed|null */ protected function readFromFile($file) { if (file_exists($file)) { if ($this->ttl >= 0 && time() - @filemtime($file) >= $this->ttl) { $this->delete(); return null; } else { if (!@filesize($file)) { $this->delete(); return null; } try { $r = @include($file); } catch (Error $error) { $this->delete(); return null; } // check cache if ($r === false || $r === null) { $this->delete(); return null; } return $r; } } return null; } } cms/webasyst/cache/waRuntimeCache.class.php 000644 000000 000000 00000001521 14202631424 021354 0 ustar 00root wheel 000000 000000 <?php class waRuntimeCache implements waiCache { protected $key; protected static $cache = array(); public function __construct($key, $ttl = -1, $app_id = null) { if (!$app_id) { $app_id = wa()->getApp(); } $this->key = $app_id.'/'.$key; } public function get() { return isset(self::$cache[$this->key]) ? self::$cache[$this->key] : null; } public function set($value) { self::$cache[$this->key] = $value; } public function delete() { if (isset(self::$cache[$this->key])) { unset(self::$cache[$this->key]); } return true; } public function isCached() { return isset(self::$cache[$this->key]); } public static function clearAll() { self::$cache = array(); } } cms/webasyst/cache/waCache.class.php 000644 000000 000000 00000003351 14202631424 020013 0 ustar 00root wheel 000000 000000 <?php /** * Interface for a key/value storage such as Memcached. * See waSystem->getCache(), waSystemConfig->getCache() */ class waCache { /** * @var waCacheAdapter */ protected $adapter; protected $app_id; /** * @param waCacheAdapter $adapter * @param string $app_id */ public function __construct(waCacheAdapter $adapter, $app_id) { $this->adapter = $adapter; $this->app_id = $app_id; } /** * @param string $key * @param string|bool $group * @return string */ protected function key($key, $group = null) { return $this->adapter->key($key, $this->app_id, $group); } /** * @param string $key * @param string $group * @return mixed */ public function get($key, $group = null) { return $this->adapter->get($this->key($key, $group)); } /** * @param string $key * @param mixed $value * @param string|bool $group * @param int $expiration * @return mixed */ public function set($key, $value, $expiration = null, $group = null) { return $this->adapter->set($this->key($key, $group), $value, $expiration, $this->key($group, true)); } /** * @param string $key * @param string * @return mixed */ public function delete($key, $group = null) { return $this->adapter->delete($this->key($key, $group)); } /** * @param string $group * @return mixed */ public function deleteGroup($group) { return $this->adapter->deleteGroup($this->key($group, true)); } /** * @return mixed */ public function deleteAll() { return $this->adapter->deleteAll(); } } cms/webasyst/cache/waFunctionCache.class.php 000644 000000 000000 00000006544 14202631424 021530 0 ustar 00root wheel 000000 000000 <?php /** * @property-read int $call_limit If the execution time (in seconds) is less - the result will not be cached. * @property-read string $namespace Namespace, which will be passed to waVarExportCache as app_id. The default id of the current app. * @property-read int $ttl The maximum lifetime of the cache, which is considered relevant. * @property-read bool $hard_clean If you are not sure that the recorded cache will clear itself - use this flag. * In this case, the Framework will definitely remove it when the $this->ttl time expires. * @property-read string $hash_salt The salt that will be used to generate the hash. This could be the user locale or something else. */ class waFunctionCache { protected $function; protected $options = array( 'call_limit' => 1, 'namespace' => null, 'ttl' => 1800, // 30 mins 'hard_clean' => false, 'hash_salt' => '', ); /** * @var bool $disable_cache * Debug helper. Set to true to make all ->call()s ignore cache and never write there */ public $disable_cache = false; /** * @var string $last_call_cache_status * Debug helper. * after ->call() this is set to one of: 'from_cache', 'just_cached', * 'not_cached' (when call_limit option is not met), or 'error' (when callable throws exception) */ public $last_call_cache_status = false; /** * @param callable $function * @param array $options * @throws waException */ public function __construct($function, $options = array()) { if (!is_callable($function)) { throw new waException('Function or method not exists'); } $this->function = $function; if (!empty($options) && is_array($options)) { $this->options = array_merge($this->options, $options); } $this->disable_cache = defined('WA_DISABLE_FUNCTIONS_CACHE'); } public function __get($option) { return isset($this->options[$option]) ? $this->options[$option] : null; } public function __isset($option) { return isset($this->options[$option]); } public function call() { $args = func_get_args(); if ($this->disable_cache) { $this->last_call_cache_status = 'not_cached'; return call_user_func_array($this->function, $args); } $hash_data = var_export(array($this->function, $args), true).$this->hash_salt; $hash = md5($hash_data); //waLog::log($hash_data, 'wa_fun_cache/'.$hash.'.log'); unset($hash_data); $app_id = $this->namespace ? $this->namespace : wa()->getApp(); $cache = new waVarExportCache('fn_'.$hash, $this->ttl, $app_id, $this->hard_clean); $result = $cache->get(); if (!$result) { $t = microtime(true); $this->last_call_cache_status = 'error'; $result = call_user_func_array($this->function, $args); if ((microtime(true) - $t) > $this->call_limit) { $cache->set($result); $this->last_call_cache_status = 'just_cached'; } else { $this->last_call_cache_status = 'not_cached'; } } else { $this->last_call_cache_status = 'from_cache'; } return $result; } } cms/webasyst/cache/waiCache.interface.php 000644 000000 000000 00000001133 14202631424 021013 0 ustar 00root wheel 000000 000000 <?php /** * Interface for a simple cache. One object = one cached value. */ /* * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Webasyst LLC * @copyright 2011 Webasyst LLC * @package wa-system * @subpackage cache */ interface waiCache { public function __construct($key, $ttl = -1, $app_id = null); public function get(); public function set($value); public function delete(); public function isCached(); } cms/webasyst/cache/waSerializeCache.class.php 000644 000000 000000 00000002615 14202631424 021665 0 ustar 00root wheel 000000 000000 <?php /* * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Webasyst LLC * @copyright 2011 Webasyst LLC * @package wa-system * @subpackage cache */ class waSerializeCache extends waFileCache { protected function writeToFile($file, $v) { if ($this->ttl == 0) { return null; } if (!file_exists($file) || is_writable($file)) { $data = serialize(array('time' => time(), 'ttl' => $this->ttl, 'value' => $v)); $r = @file_put_contents($file, $data); if ($r) { @chmod($file, 0664); } return $r; } elseif (waSystemConfig::isDebug()) { throw new waException("Cannot write to cache file ".$file, 601); } } protected function readFromFile($file, $t = null) { if (file_exists($file) && is_writable($file)) { $info = unserialize(file_get_contents($file)); if ($t && $info['time'] < $t) { return null; } elseif (!empty($info['ttl']) && $info['ttl'] >= 0 && time() - $info['time'] >= $info['ttl']) { return null; } else { return $info['value']; } } return null; } } cms/webasyst/cache/adapters/waXcacheCacheAdapter.class.php 000644 000000 000000 00000005014 14202631424 024231 0 ustar 00root wheel 000000 000000 <?php /** * This file is part of Webasyst framework. * * Licensed under the terms of the GNU Lesser General Public License (LGPL). * http://www.webasyst.com/framework/license/ * * @link http://www.webasyst.com/ * @author Serge Rodovnichenko <sergerod@gmail.com> * @copyright 2014 Serge Rodovnichenko * @package wa-system * @subpackage cache */ /** * Cache adapter class to store data with XCache * * Required keys for $options * - 'prefix' - Unique prefix for variables stored in cache. This value * must be unique for the server! * */ class waXcacheCacheAdapter extends waCacheAdapter { protected function init() { parent::init(); if(!extension_loaded('XCache')) { throw new waException("XCache module not loaded"); } if(version_compare(phpversion("XCache"), "3.1.0", "<")) { throw new waException("XCache version 3.1.0 or newer required"); } if(!isset($this->options["prefix"])) { throw new waException("Prefix for XCache is not set"); } } /** * * @param string $key Key name * @param string $app_id Application ID * @param string|bool $group * @return string */ public function key($key, $app_id, $group = null) { $key = parent::key($key, $app_id, $group); return $this->options["prefix"] . $key; } /** * @param string $key * @return boolean */ public function delete($key) { if(!xcache_isset($key)) { return TRUE; } return xcache_unset($key); } /** * @return boolean */ public function deleteAll() { xcache_unset_by_prefix($this->options["prefix"]); return TRUE; } public function deleteGroup($group) { xcache_unset_by_prefix($group); return TRUE; } /** * Retrieves from cache * * @param string $key * @return mixed Cached value or NULL */ public function get($key) { $v = xcache_get($key); if($v) { return unserialize($v); } return NULL; } /** * Stores value in the cache * * @param string $key * @param mixed $value Value to store in the cache * @param int $expiration * @param string|bool $group * @return bool */ public function set($key, $value, $expiration = null, $group = null) { return xcache_set($key, serialize($value), ($expiration ? $expiration: 0)); } } cms/webasyst/cache/adapters/waMemcachedCacheAdapter.class.php 000644 000000 000000 00000004144 14202631424 024707 0 ustar 00root wheel 000000 000000 <?php class waMemcachedCacheAdapter extends waCacheAdapter { /** * @var Memcached */ protected static $memcached; protected function init() { if (!self::$memcached) { if (!empty($this->options['persistent'])) { self::$memcached = new Memcached($this->options['persistent']); // if servers already exists if (self::$memcached->getServerList()) { return; } } else { self::$memcached = new Memcached(); } if (empty($this->options['servers'])) { self::$memcached->addServer('127.0.0.1', 11211); } else { foreach ($this->options['servers'] as $s) { self::$memcached->addServer($s['host'], isset($s['port']) ? $s['port'] : 11211, isset($s['weight']) ? $s['weight'] : 0); } } } } public function key($key, $app_id, $group = null) { return (isset($this->options['namespace']) ? $this->options['namespace'].'/' : '').parent::key($key, $app_id. $group); } public function get($key, $group = null) { $r = self::$memcached->get($key); if ($r === false) { return null; } return $r; } public function set($key, $value, $expiration = null, $group = null) { if ($group) { $keys = $this->get($group); if (!$keys) { $keys = array(); } $keys[] = $key; $this->set($group, $keys); } return self::$memcached->set($key, $value, $expiration); } public function delete($key) { return self::$memcached->delete($key); } public function deleteGroup($group) { $keys = $this->get($group); if ($keys) { foreach ($keys as $k) { $this->delete($k); } } return $this->delete($group); } public function deleteAll() { return self::$memcached->flush(); } } cms/webasyst/cache/adapters/waFileCacheAdapter.class.php 000644 000000 000000 00000003413 14202631424 023716 0 ustar 00root wheel 000000 000000 <?php class waFileCacheAdapter extends waCacheAdapter { protected function init() { if (!isset($this->options['path'])) { $this->options['path'] = waConfig::get('wa_path_cache').'/apps'; } } public function key($key, $app_id, $group = null) { $key = trim($key, '/'); if ($group === true) { return $app_id.'/cache/g_'.$key; } elseif (!$group) { return $app_id.'/cache/k_'.$key.'.slz'; } return $app_id.'/cache/g_'.$group.'/'.$key.'.slz'; } public function get($key) { $file = $this->options['path'].'/'.$key; if (file_exists($file) && is_writable($file)) { $info = @unserialize(file_get_contents($file)); if (!empty($info['ttl']) && $info['ttl'] >= 0 && time() - $info['time'] >= $info['ttl']) { return null; } else { return $info['value']; } } return null; } public function set($key, $value, $expiration = null, $group = null) { $file = waFiles::create($this->options['path'].'/'.$key); $data = serialize(array('time' => time(), 'ttl' => $expiration, 'value' => $value)); if (!file_exists($file) || is_writable($file)) { $r = @file_put_contents($file, $data, LOCK_EX); if ($r) { @chmod($file, 0664); } return $r; } } public function delete($key) { return waFiles::delete($this->options['path'].'/'.$key); } public function deleteGroup($group) { return waFiles::delete($this->options['path'].'/'.$group); } public function deleteAll() { return waFiles::delete($this->options['path']); } } cms/opencart/cache/ 000755 000000 000000 00000000000 14214276054 014622 5 ustar 00root wheel 000000 000000 cms/opencart/cache/file.php 000644 000000 000000 00000002432 12440647730 016255 0 ustar 00root wheel 000000 000000 <?php namespace Cache; class File { private $expire; public function __construct($expire = 3600) { $this->expire = $expire; $files = glob(DIR_CACHE . 'cache.*'); if ($files) { foreach ($files as $file) { $time = substr(strrchr($file, '.'), 1); if ($time < time()) { if (file_exists($file)) { unlink($file); } } } } } public function get($key) { $files = glob(DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.*'); if ($files) { $handle = fopen($files[0], 'r'); flock($handle, LOCK_SH); $data = fread($handle, filesize($files[0])); flock($handle, LOCK_UN); fclose($handle); return unserialize($data); } return false; } public function set($key, $value) { $this->delete($key); $file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.' . (time() + $this->expire); $handle = fopen($file, 'w'); flock($handle, LOCK_EX); fwrite($handle, serialize($value)); fflush($handle); flock($handle, LOCK_UN); fclose($handle); } public function delete($key) { $files = glob(DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.*'); if ($files) { foreach ($files as $file) { if (file_exists($file)) { unlink($file); } } } } } cms/opencart/cache/mem.php 000644 000000 000000 00000001017 12462431030 016076 0 ustar 00root wheel 000000 000000 <?php namespace Cache; class Mem { private $expire; private $cache; public function __construct($expire) { $this->expire = $expire; $this->cache = new \Memcache(); $this->cache->pconnect(CACHE_HOSTNAME, CACHE_PORT); } public function get($key) { return $this->cache->get(CACHE_PREFIX . $key); } public function set($key,$value) { return $this->cache->set(CACHE_PREFIX . $key, $value, MEMCACHE_COMPRESSED, $this->expire); } public function delete($key) { $this->cache->delete(CACHE_PREFIX . $key); } } cms/opencart/cache/apc.php 000644 000000 000000 00000000610 12440647730 016075 0 ustar 00root wheel 000000 000000 <?php namespace Cache; class APC { private $expire; private $cache; public function __construct($expire) { $this->expire = $expire; } public function get($key) { return apc_fetch(CACHE_PREFIX . $key); } public function set($key, $value) { return apc_store(CACHE_PREFIX . $key, $value, $this->expire); } public function delete($key) { apc_delete(CACHE_PREFIX . $key); } } cms/joomla/cache1/ 000755 000000 000765 00000000000 14214403610 015412 5 ustar 00root novadesign 000000 000000 cms/joomla/cache/ 000755 000000 000765 00000000000 14213621611 015333 5 ustar 00root novadesign 000000 000000 cms/joomla/cache/storage.php 000644 001411 001411 00000017331 12750043556 016601 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Abstract cache storage handler * * @since 11.1 * @note As of 4.0 this class will be abstract */ class JCacheStorage { /** * The raw object name * * @var string * @since 11.1 */ protected $rawname; /** * Time that the cache storage handler was instantiated * * @var integer * @since 11.1 */ public $_now; /** * Cache lifetime * * @var integer * @since 11.1 */ public $_lifetime; /** * Flag if locking is enabled * * @var boolean * @since 11.1 */ public $_locking; /** * Language code * * @var string * @since 11.1 */ public $_language; /** * Application name * * @var string * @since 11.1 */ public $_application; /** * Object hash * * @var string * @since 11.1 */ public $_hash; /** * Constructor * * @param array $options Optional parameters * * @since 11.1 */ public function __construct($options = array()) { $config = JFactory::getConfig(); $this->_hash = md5($config->get('secret')); $this->_application = (isset($options['application'])) ? $options['application'] : null; $this->_language = (isset($options['language'])) ? $options['language'] : 'en-GB'; $this->_locking = (isset($options['locking'])) ? $options['locking'] : true; $this->_lifetime = (isset($options['lifetime'])) ? $options['lifetime'] * 60 : $config->get('cachetime') * 60; $this->_now = (isset($options['now'])) ? $options['now'] : time(); // Set time threshold value. If the lifetime is not set, default to 60 (0 is BAD) // _threshold is now available ONLY as a legacy (it's deprecated). It's no longer used in the core. if (empty($this->_lifetime)) { $this->_threshold = $this->_now - 60; $this->_lifetime = 60; } else { $this->_threshold = $this->_now - $this->_lifetime; } } /** * Returns a cache storage handler object. * * @param string $handler The cache storage handler to instantiate * @param array $options Array of handler options * * @return JCacheStorage * * @since 11.1 * @throws UnexpectedValueException * @throws RuntimeException */ public static function getInstance($handler = null, $options = array()) { static $now = null; // @deprecated 4.0 This class path is autoloaded, manual inclusion is no longer necessary self::addIncludePath(JPATH_PLATFORM . '/joomla/cache/storage'); if (!isset($handler)) { $handler = JFactory::getConfig()->get('cache_handler'); if (empty($handler)) { throw new UnexpectedValueException('Cache Storage Handler not set.'); } } if (is_null($now)) { $now = time(); } $options['now'] = $now; // We can't cache this since options may change... $handler = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $handler)); /** @var JCacheStorage $class */ $class = 'JCacheStorage' . ucfirst($handler); if (!class_exists($class)) { // Search for the class file in the JCacheStorage include paths. jimport('joomla.filesystem.path'); $path = JPath::find(self::addIncludePath(), strtolower($handler) . '.php'); if ($path === false) { throw new RuntimeException(sprintf('Unable to load Cache Storage: %s', $handler)); } include_once $path; // The class should now be loaded if (!class_exists($class)) { throw new RuntimeException(sprintf('Unable to load Cache Storage: %s', $handler)); } } // Validate the cache storage is supported on this platform if (!$class::isSupported()) { throw new RuntimeException(sprintf('The %s Cache Storage is not supported on this platform.', $handler)); } return new $class($options); } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { return false; } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { return false; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { return true; } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { return true; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { return true; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 11.1 * @deprecated 12.3 (Platform) & 4.0 (CMS) */ public static function test() { JLog::add(__METHOD__ . '() is deprecated. Use JCacheStorage::isSupported() instead.', JLog::WARNING, 'deprecated'); return static::isSupported(); } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 11.1 */ public function lock($id, $group, $locktime) { return false; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function unlock($id, $group = null) { return false; } /** * Get a cache ID string from an ID/group pair * * @param string $id The cache data ID * @param string $group The cache data group * * @return string * * @since 11.1 */ protected function _getCacheId($id, $group) { $name = md5($this->_application . '-' . $id . '-' . $this->_language); $this->rawname = $this->_hash . '-' . $name; return JCache::getPlatformPrefix() . $this->_hash . '-cache-' . $group . '-' . $name; } /** * Add a directory where JCacheStorage should search for handlers. You may either pass a string or an array of directories. * * @param array|string $path A path to search. * * @return array An array with directory elements * * @since 11.1 */ public static function addIncludePath($path = '') { static $paths; if (!isset($paths)) { $paths = array(); } if (!empty($path) && !in_array($path, $paths)) { jimport('joomla.filesystem.path'); array_unshift($paths, JPath::clean($path)); } return $paths; } } cms/joomla/cache/storage/ 000755 001411 001411 00000000000 12750043556 016063 5 ustar 00panel panel 000000 000000 cms/joomla/cache/cache.php 000644 001411 001411 00000043750 12750043556 016204 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; use Joomla\String\StringHelper; /** * Joomla! Cache base object * * @since 11.1 */ class JCache { /** * Storage handler * * @var JCacheStorage[] * @since 11.1 */ public static $_handler = array(); /** * Cache options * * @var array * @since 11.1 */ public $_options; /** * Constructor * * @param array $options Cache options * * @since 11.1 */ public function __construct($options) { $conf = JFactory::getConfig(); $this->_options = array( 'cachebase' => $conf->get('cache_path', JPATH_CACHE), 'lifetime' => (int) $conf->get('cachetime'), 'language' => $conf->get('language', 'en-GB'), 'storage' => $conf->get('cache_handler', ''), 'defaultgroup' => 'default', 'locking' => true, 'locktime' => 15, 'checkTime' => true, 'caching' => ($conf->get('caching') >= 1) ? true : false ); // Overwrite default options with given options foreach ($options as $option => $value) { if (isset($options[$option]) && $options[$option] !== '') { $this->_options[$option] = $options[$option]; } } if (empty($this->_options['storage'])) { $this->_options['caching'] = false; } } /** * Returns a reference to a cache adapter object, always creating it * * @param string $type The cache object type to instantiate * @param array $options The array of options * * @return JCacheController * * @since 11.1 */ public static function getInstance($type = 'output', $options = array()) { return JCacheController::getInstance($type, $options); } /** * Get the storage handlers * * @return array * * @since 11.1 */ public static function getStores() { $handlers = array(); // Get an iterator and loop trough the driver classes. $iterator = new DirectoryIterator(__DIR__ . '/storage'); /** @type $file DirectoryIterator */ foreach ($iterator as $file) { $fileName = $file->getFilename(); // Only load for php files. if (!$file->isFile() || $file->getExtension() != 'php' || $fileName == 'helper.php') { continue; } // Derive the class name from the type. $class = str_ireplace('.php', '', 'JCacheStorage' . ucfirst(trim($fileName))); // If the class doesn't exist we have nothing left to do but look at the next type. We did our best. if (!class_exists($class)) { continue; } // Sweet! Our class exists, so now we just need to know if it passes its test method. if ($class::isSupported()) { // Connector names should not have file extensions. $handlers[] = str_ireplace('.php', '', $fileName); } } return $handlers; } /** * Set caching enabled state * * @param boolean $enabled True to enable caching * * @return void * * @since 11.1 */ public function setCaching($enabled) { $this->_options['caching'] = $enabled; } /** * Get caching state * * @return boolean * * @since 11.1 */ public function getCaching() { return $this->_options['caching']; } /** * Set cache lifetime * * @param integer $lt Cache lifetime * * @return void * * @since 11.1 */ public function setLifeTime($lt) { $this->_options['lifetime'] = $lt; } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group = null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage $handler = $this->_getStorage(); if (!($handler instanceof Exception) && $this->_options['caching']) { return $handler->get($id, $group, $this->_options['checkTime']); } return false; } /** * Get a list of all cached data * * @return mixed Boolean false on failure or an object with a list of cache groups and data * * @since 11.1 */ public function getAll() { // Get the storage $handler = $this->_getStorage(); if (!($handler instanceof Exception) && $this->_options['caching']) { return $handler->getAll(); } return false; } /** * Store the cached data by ID and group * * @param mixed $data The data to store * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function store($data, $id, $group = null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage and store the cached data $handler = $this->_getStorage(); if (!($handler instanceof Exception) && $this->_options['caching']) { return $handler->store($id, $group, $data); } return false; } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group = null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage $handler = $this->_getStorage(); if (!($handler instanceof Exception)) { return $handler->remove($id, $group); } return false; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean True on success, false otherwise * * @since 11.1 */ public function clean($group = null, $mode = 'group') { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage handler $handler = $this->_getStorage(); if (!($handler instanceof Exception)) { return $handler->clean($group, $mode); } return false; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { // Get the storage handler $handler = $this->_getStorage(); if (!($handler instanceof Exception)) { return $handler->gc(); } return false; } /** * Set lock flag on cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param string $locktime The default locktime for locking the cache. * * @return stdClass Object with properties of lock and locklooped * * @since 11.1 */ public function lock($id, $group = null, $locktime = null) { $returning = new stdClass; $returning->locklooped = false; // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the default locktime $locktime = ($locktime) ? $locktime : $this->_options['locktime']; /* * Allow storage handlers to perform locking on their own * NOTE drivers with lock need also unlock or unlocking will fail because of false $id */ $handler = $this->_getStorage(); if (!($handler instanceof Exception) && $this->_options['locking'] == true && $this->_options['caching'] == true) { $locked = $handler->lock($id, $group, $locktime); if ($locked !== false) { return $locked; } } // Fallback $curentlifetime = $this->_options['lifetime']; // Set lifetime to locktime for storing in children $this->_options['lifetime'] = $locktime; $looptime = $locktime * 10; $id2 = $id . '_lock'; if ($this->_options['locking'] == true && $this->_options['caching'] == true) { $data_lock = $this->get($id2, $group); } else { $data_lock = false; $returning->locked = false; } if ($data_lock !== false) { $lock_counter = 0; // Loop until you find that the lock has been released. That implies that data get from other thread has finished while ($data_lock !== false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = $this->get($id2, $group); $lock_counter++; } } if ($this->_options['locking'] == true && $this->_options['caching'] == true) { $returning->locked = $this->store(1, $id2, $group); } // Revert lifetime to previous one $this->_options['lifetime'] = $curentlifetime; return $returning; } /** * Unset lock flag on cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function unlock($id, $group = null) { $unlock = false; // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Allow handlers to perform unlocking on their own $handler = $this->_getStorage(); if (!($handler instanceof Exception) && $this->_options['caching']) { $unlocked = $handler->unlock($id, $group); if ($unlocked !== false) { return $unlocked; } } // Fallback if ($this->_options['caching']) { $unlock = $this->remove($id . '_lock', $group); } return $unlock; } /** * Get the cache storage handler * * @return JCacheStorage * * @since 11.1 */ public function &_getStorage() { $hash = md5(serialize($this->_options)); if (isset(self::$_handler[$hash])) { return self::$_handler[$hash]; } self::$_handler[$hash] = JCacheStorage::getInstance($this->_options['storage'], $this->_options); return self::$_handler[$hash]; } /** * Perform workarounds on retrieved cached data * * @param string $data Cached data * @param array $options Array of options * * @return string Body of cached data * * @since 11.1 */ public static function getWorkarounds($data, $options = array()) { $app = JFactory::getApplication(); $document = JFactory::getDocument(); $body = null; // Get the document head out of the cache. if (isset($options['mergehead']) && $options['mergehead'] == 1 && isset($data['head']) && !empty($data['head']) && method_exists($document, 'mergeHeadData')) { $document->mergeHeadData($data['head']); } elseif (isset($data['head']) && method_exists($document, 'setHeadData')) { $document->setHeadData($data['head']); } // Get the document MIME encoding out of the cache if (isset($data['mime_encoding'])) { $document->setMimeEncoding($data['mime_encoding'], true); } // If the pathway buffer is set in the cache data, get it. if (isset($data['pathway']) && is_array($data['pathway'])) { // Push the pathway data into the pathway object. $app->getPathway()->setPathway($data['pathway']); } // @todo check if the following is needed, seems like it should be in page cache // If a module buffer is set in the cache data, get it. if (isset($data['module']) && is_array($data['module'])) { // Iterate through the module positions and push them into the document buffer. foreach ($data['module'] as $name => $contents) { $document->setBuffer($contents, 'module', $name); } } // Set cached headers. if (isset($data['headers']) && $data['headers']) { foreach ($data['headers'] as $header) { $app->setHeader($header['name'], $header['value']); } } // The following code searches for a token in the cached page and replaces it with the proper token. if (isset($data['body'])) { $token = JSession::getFormToken(); $search = '#<input type="hidden" name="[0-9a-f]{32}" value="1" />#'; $replacement = '<input type="hidden" name="' . $token . '" value="1" />'; $data['body'] = preg_replace($search, $replacement, $data['body']); $body = $data['body']; } // Get the document body out of the cache. return $body; } /** * Create workarounds for data to be cached * * @param string $data Cached data * @param array $options Array of options * * @return string Data to be cached * * @since 11.1 */ public static function setWorkarounds($data, $options = array()) { $loptions = array( 'nopathway' => 0, 'nohead' => 0, 'nomodules' => 0, 'modulemode' => 0, ); if (isset($options['nopathway'])) { $loptions['nopathway'] = $options['nopathway']; } if (isset($options['nohead'])) { $loptions['nohead'] = $options['nohead']; } if (isset($options['nomodules'])) { $loptions['nomodules'] = $options['nomodules']; } if (isset($options['modulemode'])) { $loptions['modulemode'] = $options['modulemode']; } $app = JFactory::getApplication(); $document = JFactory::getDocument(); if ($loptions['nomodules'] != 1) { // Get the modules buffer before component execution. $buffer1 = $document->getBuffer(); if (!is_array($buffer1)) { $buffer1 = array(); } // Make sure the module buffer is an array. if (!isset($buffer1['module']) || !is_array($buffer1['module'])) { $buffer1['module'] = array(); } } // View body data $cached['body'] = $data; // Document head data if ($loptions['nohead'] != 1 && method_exists($document, 'getHeadData')) { if ($loptions['modulemode'] == 1) { $headnow = $document->getHeadData(); $unset = array('title', 'description', 'link', 'links', 'metaTags'); foreach ($unset as $un) { unset($headnow[$un]); unset($options['headerbefore'][$un]); } $cached['head'] = array(); // Only store what this module has added foreach ($headnow as $now => $value) { if (isset($options['headerbefore'][$now])) { // We have to serialize the content of the arrays because the may contain other arrays which is a notice in PHP 5.4 and newer $nowvalue = array_map('serialize', $headnow[$now]); $beforevalue = array_map('serialize', $options['headerbefore'][$now]); $newvalue = array_diff_assoc($nowvalue, $beforevalue); $newvalue = array_map('unserialize', $newvalue); // Special treatment for script and style declarations. if (($now == 'script' || $now == 'style') && is_array($newvalue) && is_array($options['headerbefore'][$now])) { foreach ($newvalue as $type => $currentScriptStr) { if (isset($options['headerbefore'][$now][strtolower($type)])) { $oldScriptStr = $options['headerbefore'][$now][strtolower($type)]; if ($oldScriptStr != $currentScriptStr) { // Save only the appended declaration. $newvalue[strtolower($type)] = StringHelper::substr($currentScriptStr, StringHelper::strlen($oldScriptStr)); } } } } } else { $newvalue = $headnow[$now]; } if (!empty($newvalue)) { $cached['head'][$now] = $newvalue; } } } else { $cached['head'] = $document->getHeadData(); } } // Document MIME encoding $cached['mime_encoding'] = $document->getMimeEncoding(); // Pathway data if ($app->isSite() && $loptions['nopathway'] != 1) { $cached['pathway'] = is_array($data) && isset($data['pathway']) ? $data['pathway'] : $app->getPathway()->getPathway(); } if ($loptions['nomodules'] != 1) { // @todo Check if the following is needed, seems like it should be in page cache // Get the module buffer after component execution. $buffer2 = $document->getBuffer(); if (!is_array($buffer2)) { $buffer2 = array(); } // Make sure the module buffer is an array. if (!isset($buffer2['module']) || !is_array($buffer2['module'])) { $buffer2['module'] = array(); } // Compare the second module buffer against the first buffer. $cached['module'] = array_diff_assoc($buffer2['module'], $buffer1['module']); } // Headers data if (isset($options['headers']) && $options['headers']) { $cached['headers'] = $app->getHeaders(); } return $cached; } /** * Create a safe ID for cached data from URL parameters * * @return string MD5 encoded cache ID * * @since 11.1 */ public static function makeId() { $app = JFactory::getApplication(); $registeredurlparams = new stdClass; // Get url parameters set by plugins if (!empty($app->registeredurlparams)) { $registeredurlparams = $app->registeredurlparams; } // Platform defaults $defaulturlparams = array( 'format' => 'WORD', 'option' => 'WORD', 'view' => 'WORD', 'layout' => 'WORD', 'tpl' => 'CMD', 'id' => 'INT' ); // Use platform defaults if parameter doesn't already exist. foreach ($defaulturlparams as $param => $type) { if (!property_exists($registeredurlparams, $param)) { $registeredurlparams->$param = $type; } } $safeuriaddon = new stdClass; foreach ($registeredurlparams as $key => $value) { $safeuriaddon->$key = $app->input->get($key, null, $value); } return md5(serialize($safeuriaddon)); } /** * Set a prefix cache key if device calls for separate caching * * @return string * * @since 3.5 */ public static function getPlatformPrefix() { // No prefix when Global Config is set to no platfom specific prefix if (!JFactory::getConfig()->get('cache_platformprefix', '0')) { return ''; } $webclient = new JApplicationWebClient; if ($webclient->mobile) { return 'M-'; } return ''; } /** * Add a directory where JCache should search for handlers. You may either pass a string or an array of directories. * * @param array|string $path A path to search. * * @return array An array with directory elements * * @since 11.1 */ public static function addIncludePath($path = '') { static $paths; if (!isset($paths)) { $paths = array(); } if (!empty($path) && !in_array($path, $paths)) { jimport('joomla.filesystem.path'); array_unshift($paths, JPath::clean($path)); } return $paths; } } cms/joomla/cache/controller/ 000755 001411 001411 00000000000 12750043556 016602 5 ustar 00panel panel 000000 000000 cms/joomla/cache/controller.php 000644 001411 001411 00000011610 12750043556 017312 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Public cache handler * * @since 11.1 */ class JCacheController { /** * JCache object * * @var JCache * @since 11.1 */ public $cache; /** * Array of options * * @var array * @since 11.1 */ public $options; /** * Constructor * * @param array $options Array of options * * @since 11.1 */ public function __construct($options) { $this->cache = new JCache($options); $this->options = & $this->cache->_options; // Overwrite default options with given options foreach ($options as $option => $value) { if (isset($options[$option])) { $this->options[$option] = $options[$option]; } } } /** * Magic method to proxy JCacheController method calls to JCache * * @param string $name Name of the function * @param array $arguments Array of arguments for the function * * @return mixed * * @since 11.1 */ public function __call($name, $arguments) { $nazaj = call_user_func_array(array($this->cache, $name), $arguments); return $nazaj; } /** * Returns a reference to a cache adapter object, always creating it * * @param string $type The cache object type to instantiate; default is output. * @param array $options Array of options * * @return JCacheController * * @since 11.1 * @throws RuntimeException */ public static function getInstance($type = 'output', $options = array()) { self::addIncludePath(JPATH_PLATFORM . '/joomla/cache/controller'); $type = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $type)); $class = 'JCacheController' . ucfirst($type); if (!class_exists($class)) { // Search for the class file in the JCache include paths. jimport('joomla.filesystem.path'); $path = JPath::find(self::addIncludePath(), strtolower($type) . '.php'); if ($path === false) { throw new RuntimeException('Unable to load Cache Controller: ' . $type, 500); } include_once $path; // The class should now be loaded if (!class_exists($class)) { throw new RuntimeException('Unable to load Cache Controller: ' . $type, 500); } } return new $class($options); } /** * Set caching enabled state * * @param boolean $enabled True to enable caching * * @return void * * @since 11.1 */ public function setCaching($enabled) { $this->cache->setCaching($enabled); } /** * Set cache lifetime * * @param integer $lt Cache lifetime * * @return void * * @since 11.1 */ public function setLifeTime($lt) { $this->cache->setLifeTime($lt); } /** * Add a directory where JCache should search for controllers. You may either pass a string or an array of directories. * * @param array|string $path A path to search. * * @return array An array with directory elements * * @since 11.1 */ public static function addIncludePath($path = '') { static $paths; if (!isset($paths)) { $paths = array(); } if (!empty($path) && !in_array($path, $paths)) { jimport('joomla.filesystem.path'); array_unshift($paths, JPath::clean($path)); } return $paths; } /** * Get stored cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return mixed Boolean false on no result, cached object otherwise * * @since 11.1 */ public function get($id, $group = null) { $data = $this->cache->get($id, $group); if ($data === false) { $locktest = $this->cache->lock($id, $group); if ($locktest->locked == true && $locktest->locklooped == true) { $data = $this->cache->get($id, $group); } if ($locktest->locked == true) { $this->cache->unlock($id, $group); } } // Check again because we might get it from second attempt if ($data !== false) { // Trim to fix unserialize errors $data = unserialize(trim($data)); } return $data; } /** * Store data to cache by ID and group * * @param mixed $data The data to store * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $wrkarounds True to use wrkarounds * * @return boolean True if cache stored * * @since 11.1 */ public function store($data, $id, $group = null, $wrkarounds = true) { $locktest = $this->cache->lock($id, $group); if ($locktest->locked == false && $locktest->locklooped == true) { $locktest = $this->cache->lock($id, $group); } $success = $this->cache->store(serialize($data), $id, $group); if ($locktest->locked == true) { $this->cache->unlock($id, $group); } return $success; } } cms/joomla/cache/controller/view.php 000644 001411 001411 00000006320 12750043556 020266 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Joomla! Cache view type object * * @since 11.1 */ class JCacheControllerView extends JCacheController { /** * Get the cached view data * * @param object $view The view object to cache output for * @param string $method The method name of the view method to cache output for * @param mixed $id The cache data ID * @param boolean $wrkarounds True to enable workarounds. * * @return boolean True if the cache is hit (false else) * * @since 11.1 */ public function get($view, $method = 'display', $id = false, $wrkarounds = true) { // If an id is not given generate it from the request if ($id == false) { $id = $this->_makeId($view, $method); } $data = $this->cache->get($id); $locktest = new stdClass; $locktest->locked = null; $locktest->locklooped = null; if ($data === false) { $locktest = $this->cache->lock($id, null); /* * If the loop is completed and returned true it means the lock has been set. * If looped is true try to get the cached data again; it could exist now. */ if ($locktest->locked == true && $locktest->locklooped == true) { $data = $this->cache->get($id); } // False means that locking is either turned off or maxtime has been exceeded. Execute the view. } if ($data !== false) { $data = unserialize(trim($data)); if ($wrkarounds === true) { echo JCache::getWorkarounds($data); } else { // No workarounds, so all data is stored in one piece echo isset($data) ? $data : null; } if ($locktest->locked == true) { $this->cache->unlock($id); } return true; } // No hit so we have to execute the view if (method_exists($view, $method)) { // If previous lock failed try again if ($locktest->locked == false) { $locktest = $this->cache->lock($id); } // Capture and echo output ob_start(); ob_implicit_flush(false); $view->$method(); $data = ob_get_clean(); echo $data; /* * For a view we have a special case. We need to cache not only the output from the view, but the state * of the document head after the view has been rendered. This will allow us to properly cache any attached * scripts or stylesheets or links or any other modifications that the view has made to the document object */ $cached = $wrkarounds == true ? JCache::setWorkarounds($data) : $data; // Store the cache data $this->cache->store(serialize($cached), $id); if ($locktest->locked == true) { $this->cache->unlock($id); } } return false; } /** * Generate a view cache ID. * * @param object &$view The view object to cache output for * @param string $method The method name to cache for the view object * * @return string MD5 Hash * * @since 11.1 */ protected function _makeId(&$view, $method) { return md5(serialize(array(JCache::makeId(), get_class($view), $method))); } } cms/joomla/cache/controller/output.php 000644 001411 001411 00000004731 12750043556 020660 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Joomla Cache output type object * * @since 11.1 */ class JCacheControllerOutput extends JCacheController { /** * Cache data ID * * @var string * @since 11.1 */ protected $_id; /** * Cache data group * * @var string * @since 11.1 */ protected $_group; /** * Object to test locked state * * @var stdClass * @since 11.1 */ protected $_locktest = null; /** * Start the cache * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function start($id, $group = null) { // If we have data in cache use that. $data = $this->cache->get($id, $group); $this->_locktest = new stdClass; $this->_locktest->locked = null; $this->_locktest->locklooped = null; if ($data === false) { $this->_locktest = $this->cache->lock($id, $group); if ($this->_locktest->locked == true && $this->_locktest->locklooped == true) { $data = $this->cache->get($id, $group); } } if ($data !== false) { $data = unserialize(trim($data)); echo $data; if ($this->_locktest->locked == true) { $this->cache->unlock($id, $group); } return true; } // Nothing in cache... let's start the output buffer and start collecting data for next time. if ($this->_locktest->locked == false) { $this->_locktest = $this->cache->lock($id, $group); } ob_start(); ob_implicit_flush(false); // Set id and group placeholders $this->_id = $id; $this->_group = $group; return false; } /** * Stop the cache buffer and store the cached data * * @return boolean True if the cache data was stored * * @since 11.1 */ public function end() { // Get data from output buffer and echo it $data = ob_get_clean(); echo $data; // Get the ID and group and reset the placeholders $id = $this->_id; $group = $this->_group; $this->_id = null; $this->_group = null; // Get the storage handler and store the cached data $ret = $this->cache->store(serialize($data), $id, $group); if ($this->_locktest->locked == true) { $this->cache->unlock($id, $group); } return $ret; } } cms/joomla/cache/controller/page.php 000644 001411 001411 00000010565 12750043556 020236 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Joomla! Cache page type object * * @since 11.1 */ class JCacheControllerPage extends JCacheController { /** * ID property for the cache page object. * * @var integer * @since 11.1 */ protected $_id; /** * Cache group * * @var string * @since 11.1 */ protected $_group; /** * Cache lock test * * @var stdClass * @since 11.1 */ protected $_locktest = null; /** * Get the cached page data * * @param boolean $id The cache data ID * @param string $group The cache data group * * @return mixed Boolean false on no result, cached object otherwise * * @since 11.1 */ public function get($id = false, $group = 'page') { // If an id is not given, generate it from the request if ($id == false) { $id = $this->_makeId(); } // If the etag matches the page id ... set a no change header and exit : utilize browser cache if (!headers_sent() && isset($_SERVER['HTTP_IF_NONE_MATCH'])) { $etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']); if ($etag == $id) { $browserCache = isset($this->options['browsercache']) ? $this->options['browsercache'] : false; if ($browserCache) { $this->_noChange(); } } } // We got a cache hit... set the etag header and echo the page data $data = $this->cache->get($id, $group); $this->_locktest = new stdClass; $this->_locktest->locked = null; $this->_locktest->locklooped = null; if ($data === false) { $this->_locktest = $this->cache->lock($id, $group); if ($this->_locktest->locked == true && $this->_locktest->locklooped == true) { $data = $this->cache->get($id, $group); } } if ($data !== false) { $data = unserialize(trim($data)); $data = JCache::getWorkarounds($data); $this->_setEtag($id); if ($this->_locktest->locked == true) { $this->cache->unlock($id, $group); } return $data; } // Set ID and group placeholders $this->_id = $id; $this->_group = $group; return false; } /** * Stop the cache buffer and store the cached data * * @param mixed $data The data to store * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $wrkarounds True to use wrkarounds * * @return boolean * * @since 11.1 */ public function store($data, $id, $group = null, $wrkarounds = true) { // Get page data from the application object if (empty($data)) { $data = JFactory::getApplication()->getBody(); } // Get id and group and reset the placeholders if (empty($id)) { $id = $this->_id; } if (empty($group)) { $group = $this->_group; } // Only attempt to store if page data exists if ($data) { if ($wrkarounds) { $data = JCache::setWorkarounds( $data, array( 'nopathway' => 1, 'nohead' => 1, 'nomodules' => 1, 'headers' => true ) ); } if ($this->_locktest->locked == false) { $this->_locktest = $this->cache->lock($id, $group); } $sucess = $this->cache->store(serialize($data), $id, $group); if ($this->_locktest->locked == true) { $this->cache->unlock($id, $group); } return $sucess; } return false; } /** * Generate a page cache id * * @return string MD5 Hash * * @since 11.1 * @todo Discuss whether this should be coupled to a data hash or a request hash ... perhaps hashed with a serialized request */ protected function _makeId() { return JCache::makeId(); } /** * There is no change in page data so send an unmodified header and die gracefully * * @return void * * @since 11.1 */ protected function _noChange() { $app = JFactory::getApplication(); // Send not modified header and exit gracefully header('HTTP/1.x 304 Not Modified', true); $app->close(); } /** * Set the ETag header in the response * * @param string $etag The entity tag (etag) to set * * @return void * * @since 11.1 */ protected function _setEtag($etag) { JFactory::getApplication()->setHeader('ETag', $etag, true); } } cms/joomla/cache/controller/callback.php 000644 001411 001411 00000012456 12750043556 021057 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Joomla! Cache callback type object * * @since 11.1 */ class JCacheControllerCallback extends JCacheController { /** * Executes a cacheable callback if not found in cache else returns cached output and result * * Since arguments to this function are read with func_get_args you can pass any number of arguments to this method * as long as the first argument passed is the callback definition. * * The callback definition can be in several forms: * - Standard PHP Callback array see <https://secure.php.net/callback> [recommended] * - Function name as a string eg. 'foo' for function foo() * - Static method name as a string eg. 'MyClass::myMethod' for method myMethod() of class MyClass * * @return mixed Result of the callback * * @since 11.1 */ public function call() { // Get callback and arguments $args = func_get_args(); $callback = array_shift($args); return $this->get($callback, $args); } /** * Executes a cacheable callback if not found in cache else returns cached output and result * * @param mixed $callback Callback or string shorthand for a callback * @param array $args Callback arguments * @param mixed $id Cache ID * @param boolean $wrkarounds True to use wrkarounds * @param array $woptions Workaround options * * @return mixed Result of the callback * * @since 11.1 */ public function get($callback, $args = array(), $id = false, $wrkarounds = false, $woptions = array()) { // Normalize callback if (is_array($callback)) { // We have a standard php callback array -- do nothing } elseif (strstr($callback, '::')) { // This is shorthand for a static method callback classname::methodname list ($class, $method) = explode('::', $callback); $callback = array(trim($class), trim($method)); } elseif (strstr($callback, '->')) { /* * This is a really not so smart way of doing this... we provide this for backward compatability but this * WILL! disappear in a future version. If you are using this syntax change your code to use the standard * PHP callback array syntax: <https://secure.php.net/callback> * * We have to use some silly global notation to pull it off and this is very unreliable */ list ($object_123456789, $method) = explode('->', $callback); global $$object_123456789; $callback = array($$object_123456789, $method); } if (!$id) { // Generate an ID $id = $this->_makeId($callback, $args); } $data = $this->cache->get($id); $locktest = new stdClass; $locktest->locked = null; $locktest->locklooped = null; if ($data === false) { $locktest = $this->cache->lock($id); if ($locktest->locked == true && $locktest->locklooped == true) { $data = $this->cache->get($id); } } $coptions = array(); if ($data !== false) { $cached = unserialize(trim($data)); $coptions['mergehead'] = isset($woptions['mergehead']) ? $woptions['mergehead'] : 0; $output = ($wrkarounds == false) ? $cached['output'] : JCache::getWorkarounds($cached['output'], $coptions); $result = $cached['result']; if ($locktest->locked == true) { $this->cache->unlock($id); } } else { if (!is_array($args)) { $referenceArgs = !empty($args) ? array(&$args) : array(); } else { $referenceArgs = &$args; } if ($locktest->locked == false) { $locktest = $this->cache->lock($id); } if (isset($woptions['modulemode']) && $woptions['modulemode'] == 1) { $document = JFactory::getDocument(); $coptions['modulemode'] = 1; if (method_exists($document, 'getHeadData')) { $coptions['headerbefore'] = $document->getHeadData(); } } else { $coptions['modulemode'] = 0; } ob_start(); ob_implicit_flush(false); $result = call_user_func_array($callback, $referenceArgs); $output = ob_get_clean(); $coptions['nopathway'] = isset($woptions['nopathway']) ? $woptions['nopathway'] : 1; $coptions['nohead'] = isset($woptions['nohead']) ? $woptions['nohead'] : 1; $coptions['nomodules'] = isset($woptions['nomodules']) ? $woptions['nomodules'] : 1; $cached = array( 'output' => ($wrkarounds == false) ? $output : JCache::setWorkarounds($output, $coptions), 'result' => $result ); // Store the cache data $this->cache->store(serialize($cached), $id); if ($locktest->locked == true) { $this->cache->unlock($id); } } echo $output; return $result; } /** * Generate a callback cache ID * * @param callback $callback Callback to cache * @param array $args Arguments to the callback method to cache * * @return string MD5 Hash * * @since 11.1 */ protected function _makeId($callback, $args) { if (is_array($callback) && is_object($callback[0])) { $vars = get_object_vars($callback[0]); $vars[] = strtolower(get_class($callback[0])); $callback[0] = $vars; } return md5(serialize(array($callback, $args))); } } cms/joomla/cache/storage/apcu.php 000644 001411 001411 00000013265 12750043556 017533 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * APCu cache storage handler * * @see https://secure.php.net/manual/en/ref.apcu.php * @since 3.5 */ class JCacheStorageApcu extends JCacheStorage { /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 3.5 */ public function get($id, $group, $checkTime = true) { return apcu_fetch($this->_getCacheId($id, $group)); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 3.5 */ public function getAll() { $allinfo = apcu_cache_info(); $keys = $allinfo['cache_list']; $secret = $this->_hash; $data = array(); foreach ($keys as $key) { // The internal key name changed with APCu 4.0.7 from key to info $name = isset($key['info']) ? $key['info'] : $key['key']; $namearr = explode('-', $name); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize($key['mem_size'] / 1024); $data[$group] = $item; } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 3.5 */ public function store($id, $group, $data) { return apcu_store($this->_getCacheId($id, $group), $data, $this->_lifetime); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 3.5 */ public function remove($id, $group) { $cache_id = $this->_getCacheId($id, $group); // The apcu_delete function returns false if the ID does not exist if (apcu_exists($cache_id)) { return apcu_delete($cache_id); } return true; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 3.5 */ public function clean($group, $mode = null) { $allinfo = apcu_cache_info(); $keys = $allinfo['cache_list']; $secret = $this->_hash; foreach ($keys as $key) { // The internal key name changed with APCu 4.0.7 from key to info $internalKey = isset($key['info']) ? $key['info'] : $key['key']; if (strpos($internalKey, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { apcu_delete($internalKey); } } return true; } /** * Garbage collect expired cache data * * @return boolean * * @since 3.5 */ public function gc() { $allinfo = apcu_cache_info(); $keys = $allinfo['cache_list']; $secret = $this->_hash; foreach ($keys as $key) { // The internal key name changed with APCu 4.0.7 from key to info $internalKey = isset($key['info']) ? $key['info'] : $key['key']; if (strpos($internalKey, $secret . '-cache-')) { apcu_fetch($internalKey); } } return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 3.5 */ public static function isSupported() { $supported = extension_loaded('apcu') && ini_get('apc.enabled'); // If on the CLI interface, the `apc.enable_cli` option must also be enabled if ($supported && php_sapi_name() === 'cli') { $supported = ini_get('apc.enable_cli'); } return (bool) $supported; } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 3.5 */ public function lock($id, $group, $locktime) { $returning = new stdClass; $returning->locklooped = false; $looptime = $locktime * 10; $cache_id = $this->_getCacheId($id, $group) . '_lock'; $data_lock = apcu_add($cache_id, 1, $locktime); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. // That implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = apcu_add($cache_id, 1, $locktime); $lock_counter++; } } $returning->locked = $data_lock; return $returning; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 3.5 */ public function unlock($id, $group = null) { $cache_id = $this->_getCacheId($id, $group) . '_lock'; // The apcu_delete function returns false if the ID does not exist if (apcu_exists($cache_id)) { return apcu_delete($cache_id); } return true; } } cms/joomla/cache/storage/memcached.php 000644 001411 001411 00000022656 12750043556 020515 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Memcached cache storage handler * * @see https://secure.php.net/manual/en/book.memcached.php * @since 12.1 */ class JCacheStorageMemcached extends JCacheStorage { /** * Memcached connection object * * @var Memcached * @since 12.1 */ protected static $_db = null; /** * Persistent session flag * * @var boolean * @since 12.1 */ protected $_persistent = false; /** * Payload compression level * * @var integer * @since 12.1 */ protected $_compress = 0; /** * Constructor * * @param array $options Optional parameters. * * @since 12.1 */ public function __construct($options = array()) { parent::__construct($options); if (static::isSupported() && static::$_db === null) { $this->getConnection(); } } /** * Create the Memcached connection * * @return void * * @since 12.1 * @throws RuntimeException */ protected function getConnection() { $config = JFactory::getConfig(); $this->_persistent = $config->get('memcached_persist', true); $this->_compress = $config->get('memcached_compress', false) == false ? 0 : Memcached::OPT_COMPRESSION; // Create the memcache connection if ($this->_persistent) { static::$_db = new Memcached(JFactory::getSession()->getId()); } else { static::$_db = new Memcached; } $memcachedtest = static::$_db->addServer($config->get('memcached_server_host', 'localhost'), $config->get('memcached_server_port', 11211)); if ($memcachedtest == false) { throw new RuntimeException('Could not connect to memcached server', 404); } static::$_db->setOption(Memcached::OPT_COMPRESSION, $this->_compress); // Memcached has no list keys, we do our own accounting, initialise key index if (static::$_db->get($this->_hash . '-index') === false) { static::$_db->set($this->_hash . '-index', array(), 0); } } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 12.1 */ public function get($id, $group, $checkTime = true) { $cache_id = $this->_getCacheId($id, $group); return static::$_db->get($cache_id); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 12.1 */ public function getAll() { $keys = static::$_db->get($this->_hash . '-index'); $secret = $this->_hash; $data = array(); if (!empty($keys) && is_array($keys)) { foreach ($keys as $key) { if (empty($key)) { continue; } $namearr = explode('-', $key->name); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize($key->size / 1024); $data[$group] = $item; } } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 12.1 */ public function store($id, $group, $data) { $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $tmparr = new stdClass; $tmparr->name = $cache_id; $tmparr->size = strlen($data); $index[] = $tmparr; static::$_db->replace($this->_hash . '-index', $index, 0); $this->unlockindex(); // Prevent double writes, write only if it doesn't exist else replace if (!static::$_db->replace($cache_id, $data, $this->_lifetime)) { static::$_db->set($cache_id, $data, $this->_lifetime); } return true; } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 12.1 */ public function remove($id, $group) { $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } foreach ($index as $key => $value) { if ($value->name == $cache_id) { unset($index[$key]); } break; } static::$_db->replace($this->_hash . '-index', $index, 0); $this->unlockindex(); return static::$_db->delete($cache_id); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 12.1 */ public function clean($group, $mode = null) { if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $secret = $this->_hash; foreach ($index as $key => $value) { if (strpos($value->name, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { static::$_db->delete($value->name, 0); unset($index[$key]); } } static::$_db->replace($this->_hash . '-index', $index, 0); $this->unlockindex(); return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { /* * GAE and HHVM have both had instances where Memcached the class was defined but no extension was loaded. * If the class is there, we can assume support. */ if (!class_exists('Memcached')) { return false; } // Now check if we can connect to the specified Memcached server $config = JFactory::getConfig(); $memcached = new Memcached; return @$memcached->addServer($config->get('memcached_server_host', 'localhost'), $config->get('memcached_server_port', 11211)); } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 12.1 */ public function lock($id, $group, $locktime) { $returning = new stdClass; $returning->locklooped = false; $looptime = $locktime * 10; $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $tmparr = new stdClass; $tmparr->name = $cache_id; $tmparr->size = 1; $index[] = $tmparr; static::$_db->replace($this->_hash . '-index', $index, 0); $this->unlockindex(); $data_lock = static::$_db->add($cache_id . '_lock', 1, $locktime); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. // That implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = static::$_db->add($cache_id . '_lock', 1, $locktime); $lock_counter++; } } $returning->locked = $data_lock; return $returning; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 12.1 */ public function unlock($id, $group = null) { $cache_id = $this->_getCacheId($id, $group) . '_lock'; if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } foreach ($index as $key => $value) { if ($value->name == $cache_id) { unset($index[$key]); } break; } static::$_db->replace($this->_hash . '-index', $index, 0); $this->unlockindex(); return static::$_db->delete($cache_id); } /** * Lock cache index * * @return boolean * * @since 12.1 */ protected function lockindex() { $looptime = 300; $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, 30); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. that implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { return false; break; } usleep(100); $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, 30); $lock_counter++; } } return true; } /** * Unlock cache index * * @return boolean * * @since 12.1 */ protected function unlockindex() { return static::$_db->delete($this->_hash . '-index_lock'); } } cms/joomla/cache/storage/xcache.php 000644 001411 001411 00000011034 12750043556 020026 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * XCache cache storage handler * * @link http://xcache.lighttpd.net/ * @since 11.1 */ class JCacheStorageXcache extends JCacheStorage { /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { // Make sure XCache is configured properly if (static::isSupported() == false) { return false; } $cache_id = $this->_getCacheId($id, $group); $cache_content = xcache_get($cache_id); if ($cache_content === null) { return false; } return $cache_content; } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 * @note This requires the php.ini setting xcache.admin.enable_auth = Off. */ public function getAll() { // Make sure XCache is configured properly if (static::isSupported() == false) { return array(); } $allinfo = xcache_list(XC_TYPE_VAR, 0); $keys = $allinfo['cache_list']; $secret = $this->_hash; $data = array(); foreach ($keys as $key) { $namearr = explode('-', $key['name']); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize($key['size'] / 1024); $data[$group] = $item; } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { // Make sure XCache is configured properly if (static::isSupported() == false) { return false; } return xcache_set($this->_getCacheId($id, $group), $data, $this->_lifetime); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { // Make sure XCache is configured properly if (static::isSupported() == false) { return false; } $cache_id = $this->_getCacheId($id, $group); if (!xcache_isset($cache_id)) { return true; } return xcache_unset($cache_id); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { // Make sure XCache is configured properly if (static::isSupported() == false) { return true; } $allinfo = xcache_list(XC_TYPE_VAR, 0); $keys = $allinfo['cache_list']; $secret = $this->_hash; foreach ($keys as $key) { if (strpos($key['name'], $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { xcache_unset($key['name']); } } return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { if (extension_loaded('xcache')) { // XCache Admin must be disabled for Joomla to use XCache $xcache_admin_enable_auth = ini_get('xcache.admin.enable_auth'); // Some extensions ini variables are reported as strings if ($xcache_admin_enable_auth == 'Off') { return true; } // We require a string with contents 0, not a null value because it is not set since that then defaults to On/True if ($xcache_admin_enable_auth === '0') { return true; } // In some enviorments empty is equivalent to Off; See JC: #34044 && Github: #4083 if ($xcache_admin_enable_auth === '') { return true; } } // If the settings are not correct, give up return false; } } cms/joomla/cache/storage/redis.php 000644 001411 001411 00000014331 12750043556 017704 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Redis cache storage handler for PECL * * @since 3.4 */ class JCacheStorageRedis extends JCacheStorage { /** * Redis connection object * * @var Redis * @since 3.4 */ protected static $_redis = null; /** * Persistent session flag * * @var boolean * @since 3.4 */ protected $_persistent = false; /** * Constructor * * @param array $options Optional parameters. * * @since 3.4 */ public function __construct($options = array()) { parent::__construct($options); if (static::$_redis === null) { $this->getConnection(); } } /** * Create the Redis connection * * @return Redis|boolean Redis connection object on success, boolean on failure * * @since 3.4 */ protected function getConnection() { if (static::isSupported() == false) { return false; } $config = JFactory::getConfig(); $app = JFactory::getApplication(); $this->_persistent = $config->get('redis_persist', true); $server = array( 'host' => $config->get('redis_server_host', 'localhost'), 'port' => $config->get('redis_server_port', 6379), 'auth' => $config->get('redis_server_auth', null), 'db' => (int) $config->get('redis_server_db', null) ); static::$_redis = new Redis; if ($this->_persistent) { try { $connection = static::$_redis->pconnect($server['host'], $server['port']); $auth = (!empty($server['auth'])) ? static::$_redis->auth($server['auth']) : true; } catch (RedisException $e) { JLog::add($e->getMessage(), JLog::DEBUG); } } else { try { $connection = static::$_redis->connect($server['host'], $server['port']); $auth = (!empty($server['auth'])) ? static::$_redis->auth($server['auth']) : true; } catch (RedisException $e) { JLog::add($e->getMessage(), JLog::DEBUG); } } if ($connection == false) { static::$_redis = null; if ($app->isAdmin()) { JError::raiseWarning(500, 'Redis connection failed'); } return false; } if ($auth == false) { if ($app->isAdmin()) { JError::raiseWarning(500, 'Redis authentication failed'); } return false; } $select = static::$_redis->select($server['db']); if ($select == false) { static::$_redis = null; if ($app->isAdmin()) { JError::raiseWarning(500, 'Redis failed to select database'); } return false; } try { static::$_redis->ping(); } catch (RedisException $e) { static::$_redis = null; if ($app->isAdmin()) { JError::raiseWarning(500, 'Redis ping failed'); } return false; } return static::$_redis; } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 3.4 */ public function get($id, $group, $checkTime = true) { if (static::isConnected() == false) { return false; } return static::$_redis->get($this->_getCacheId($id, $group)); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 3.4 */ public function getAll() { if (static::isConnected() == false) { return false; } $allKeys = static::$_redis->keys('*'); $data = array(); $secret = $this->_hash; if (!empty($allKeys)) { foreach ($allKeys as $key) { $namearr = explode('-', $key); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize(strlen($key)*8/1024); $data[$group] = $item; } } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 3.4 */ public function store($id, $group, $data) { if (static::isConnected() == false) { return false; } static::$_redis->setex($this->_getCacheId($id, $group), $this->_lifetime, $data); return true; } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 3.4 */ public function remove($id, $group) { if (static::isConnected() == false) { return false; } return (bool) static::$_redis->delete($this->_getCacheId($id, $group)); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 3.4 */ public function clean($group, $mode = null) { if (static::isConnected() == false) { return false; } $allKeys = static::$_redis->keys('*'); if ($allKeys === false) { $allKeys = array(); } $secret = $this->_hash; foreach ($allKeys as $key) { if (strpos($key, $secret . '-cache-' . $group . '-') === 0 && $mode == 'group') { static::$_redis->delete($key); } if (strpos($key, $secret . '-cache-' . $group . '-') !== 0 && $mode != 'group') { static::$_redis->delete($key); } } return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 3.4 */ public static function isSupported() { return class_exists('Redis'); } /** * Test to see if the Redis connection is available. * * @return boolean * * @since 3.4 */ public static function isConnected() { return static::$_redis instanceof Redis; } } cms/joomla/cache/storage/memcache.php 000644 001411 001411 00000022455 12750043556 020346 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Memcache cache storage handler * * @see https://secure.php.net/manual/en/book.memcache.php * @since 11.1 */ class JCacheStorageMemcache extends JCacheStorage { /** * Memcache connection object * * @var Memcache * @since 11.1 */ protected static $_db = null; /** * Persistent session flag * * @var boolean * @since 11.1 */ protected $_persistent = false; /** * Payload compression level * * @var integer * @since 11.1 */ protected $_compress = 0; /** * Constructor * * @param array $options Optional parameters. * * @since 11.1 */ public function __construct($options = array()) { parent::__construct($options); if (static::isSupported() && static::$_db === null) { $this->getConnection(); } } /** * Create the Memcache connection * * @return void * * @since 11.1 * @throws RuntimeException */ protected function getConnection() { $config = JFactory::getConfig(); $this->_persistent = $config->get('memcache_persist', true); $this->_compress = $config->get('memcache_compress', false) == false ? 0 : MEMCACHE_COMPRESSED; // Create the memcache connection static::$_db = new Memcache; static::$_db->addserver($config->get('memcache_server_host', 'localhost'), $config->get('memcache_server_port', 11211), $this->_persistent); $memcachetest = @static::$_db->connect($server['host'], $server['port']); if ($memcachetest == false) { throw new RuntimeException('Could not connect to memcache server', 404); } // Memcahed has no list keys, we do our own accounting, initialise key index if (static::$_db->get($this->_hash . '-index') === false) { static::$_db->set($this->_hash . '-index', array(), $this->_compress, 0); } return; } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { return static::$_db->get($this->_getCacheId($id, $group)); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { $keys = static::$_db->get($this->_hash . '-index'); $secret = $this->_hash; $data = array(); if (!empty($keys)) { foreach ($keys as $key) { if (empty($key)) { continue; } $namearr = explode('-', $key->name); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize($key->size / 1024); $data[$group] = $item; } } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $tmparr = new stdClass; $tmparr->name = $cache_id; $tmparr->size = strlen($data); $index[] = $tmparr; static::$_db->replace($this->_hash . '-index', $index, 0, 0); $this->unlockindex(); // Prevent double writes, write only if it doesn't exist else replace if (!static::$_db->replace($cache_id, $data, $this->_compress, $this->_lifetime)) { static::$_db->set($cache_id, $data, $this->_compress, $this->_lifetime); } return true; } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } foreach ($index as $key => $value) { if ($value->name == $cache_id) { unset($index[$key]); } break; } static::$_db->replace($this->_hash . '-index', $index, 0, 0); $this->unlockindex(); return static::$_db->delete($cache_id); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $secret = $this->_hash; foreach ($index as $key => $value) { if (strpos($value->name, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { static::$_db->delete($value->name, 0); unset($index[$key]); } } static::$_db->replace($this->_hash . '-index', $index, 0, 0); $this->unlockindex(); return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { // First check if the PHP requirements are met $supported = extension_loaded('memcache') && class_exists('Memcache'); if (!$supported) { return false; } // Now check if we can connect to the specified Memcache server $config = JFactory::getConfig(); $memcache = new Memcache; return @$memcache->connect($config->get('memcache_server_host', 'localhost'), $config->get('memcache_server_port', 11211)); } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 11.1 */ public function lock($id, $group, $locktime) { $returning = new stdClass; $returning->locklooped = false; $looptime = $locktime * 10; $cache_id = $this->_getCacheId($id, $group); if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } $tmparr = new stdClass; $tmparr->name = $cache_id; $tmparr->size = 1; $index[] = $tmparr; static::$_db->replace($this->_hash . '-index', $index, 0, 0); $this->unlockindex(); $data_lock = static::$_db->add($cache_id . '_lock', 1, false, $locktime); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. That implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = static::$_db->add($cache_id . '_lock', 1, false, $locktime); $lock_counter++; } } $returning->locked = $data_lock; return $returning; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function unlock($id, $group = null) { $cache_id = $this->_getCacheId($id, $group) . '_lock'; if (!$this->lockindex()) { return false; } $index = static::$_db->get($this->_hash . '-index'); if ($index === false) { $index = array(); } foreach ($index as $key => $value) { if ($value->name == $cache_id) { unset($index[$key]); } break; } static::$_db->replace($this->_hash . '-index', $index, 0, 0); $this->unlockindex(); return static::$_db->delete($cache_id); } /** * Lock cache index * * @return boolean * * @since 11.1 */ protected function lockindex() { $looptime = 300; $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, false, 30); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. that implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { return false; break; } usleep(100); $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, false, 30); $lock_counter++; } } return true; } /** * Unlock cache index * * @return boolean * * @since 11.1 */ protected function unlockindex() { return static::$_db->delete($this->_hash . '-index_lock'); } } cms/joomla/cache/storage/cachelite.php 000644 001411 001411 00000016264 12750043556 020526 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Cache lite storage handler * * @see http://pear.php.net/package/Cache_Lite/ * @since 11.1 */ class JCacheStorageCachelite extends JCacheStorage { /** * Singleton Cache_Lite instance * * @var Cache_Lite * @since 11.1 */ protected static $CacheLiteInstance = null; /** * Root path * * @var string * @since 11.1 */ protected $_root; /** * Constructor * * @param array $options Optional parameters. * * @since 11.1 */ public function __construct($options = array()) { parent::__construct($options); $this->_root = $options['cachebase']; $cloptions = array( 'cacheDir' => $this->_root . '/', 'lifeTime' => $this->_lifetime, 'fileLocking' => $this->_locking, 'automaticCleaningFactor' => isset($options['autoclean']) ? $options['autoclean'] : 200, 'fileNameProtection' => false, 'hashedDirectoryLevel' => 0, 'caching' => $options['caching'] ); if (static::$CacheLiteInstance === null) { $this->initCache($cloptions); } } /** * Instantiates the Cache_Lite object. Only initializes the engine if it does not already exist. * * @param array $cloptions optional parameters * * @return Cache_Lite * * @since 11.1 */ protected function initCache($cloptions) { if (!class_exists('Cache_Lite')) { require_once 'Cache/Lite.php'; } static::$CacheLiteInstance = new Cache_Lite($cloptions); return static::$CacheLiteInstance; } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { static::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/'); // This call is needed to ensure $this->rawname is set $this->_getCacheId($id, $group); return static::$CacheLiteInstance->get($this->rawname, $group); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { $path = $this->_root; $folders = new DirectoryIterator($path); $data = array(); foreach ($folders as $folder) { if (!$folder->isDir() || $folder->isDot()) { continue; } $foldername = $folder->getFilename(); $files = new DirectoryIterator($path . '/' . $foldername); $item = new JCacheStorageHelper($foldername); foreach ($files as $file) { if (!$file->isFile()) { continue; } $filename = $file->getFilename(); $item->updateSize(filesize($path . '/' . $foldername . '/' . $filename) / 1024); } $data[$foldername] = $item; } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { $dir = $this->_root . '/' . $group; // If the folder doesn't exist try to create it if (!is_dir($dir)) { // Make sure the index file is there $indexFile = $dir . '/index.html'; @mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE html><title></title>'); } // Make sure the folder exists if (!is_dir($dir)) { return false; } static::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/'); // This call is needed to ensure $this->rawname is set $this->_getCacheId($id, $group); return static::$CacheLiteInstance->save($data, $this->rawname, $group); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { static::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/'); // This call is needed to ensure $this->rawname is set $this->_getCacheId($id, $group); return static::$CacheLiteInstance->remove($this->rawname, $group); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { jimport('joomla.filesystem.folder'); jimport('joomla.filesystem.file'); switch ($mode) { case 'notgroup': $clmode = 'notingroup'; $success = static::$CacheLiteInstance->clean($group, $clmode); break; case 'group': if (is_dir($this->_root . '/' . $group)) { $clmode = $group; static::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/'); $success = static::$CacheLiteInstance->clean($group, $clmode); // Remove sub-folders of folder; disable all filtering $folders = JFolder::folders($this->_root . '/' . $group, '.', false, true, array(), array()); foreach ($folders as $folder) { if (is_link($folder)) { if (JFile::delete($folder) !== true) { return false; } } elseif (JFolder::delete($folder) !== true) { return false; } } } else { $success = true; } break; default: if (is_dir($this->_root . '/' . $group)) { $clmode = $group; static::$CacheLiteInstance->setOption('cacheDir', $this->_root . '/' . $group . '/'); $success = static::$CacheLiteInstance->clean($group, $clmode); } else { $success = true; } break; } return $success; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { $result = true; static::$CacheLiteInstance->setOption('automaticCleaningFactor', 1); static::$CacheLiteInstance->setOption('hashedDirectoryLevel', 1); $success1 = static::$CacheLiteInstance->_cleanDir($this->_root . '/', false, 'old'); if (!($dh = opendir($this->_root . '/'))) { return false; } while ($file = readdir($dh)) { if (($file != '.') && ($file != '..') && ($file != '.svn')) { $file2 = $this->_root . '/' . $file; if (is_dir($file2)) { $result = ($result && (static::$CacheLiteInstance->_cleanDir($file2 . '/', false, 'old'))); } } } $success = ($success1 && $result); return $success; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { @include_once 'Cache/Lite.php'; return class_exists('Cache_Lite'); } } cms/joomla/cache/storage/file.php 000644 001411 001411 00000035774 12750043556 017533 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * File cache storage handler * * @since 11.1 * @note For performance reasons this class does not use the Filesystem package's API */ class JCacheStorageFile extends JCacheStorage { /** * Root path * * @var string * @since 11.1 */ protected $_root; /** * Constructor * * @param array $options Optional parameters * * @since 11.1 */ public function __construct($options = array()) { parent::__construct($options); $this->_root = $options['cachebase']; } /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { $data = false; $path = $this->_getFilePath($id, $group); if ($checkTime == false || ($checkTime == true && $this->_checkExpire($id, $group) === true)) { if (file_exists($path)) { $data = file_get_contents($path); if ($data) { // Remove the initial die() statement $data = str_replace('<?php die("Access Denied"); ?>#x#', '', $data); } } return $data; } return false; } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { $path = $this->_root; $folders = $this->_folders($path); $data = array(); foreach ($folders as $folder) { $files = $this->_filesInFolder($path . '/' . $folder); $item = new JCacheStorageHelper($folder); foreach ($files as $file) { $item->updateSize(filesize($path . '/' . $folder . '/' . $file) / 1024); } $data[$folder] = $item; } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { $written = false; $path = $this->_getFilePath($id, $group); $die = '<?php die("Access Denied"); ?>#x#'; // Prepend a die string $data = $die . $data; $_fileopen = @fopen($path, "wb"); if ($_fileopen) { $len = strlen($data); @fwrite($_fileopen, $data, $len); $written = true; } // Data integrity check return $written && ($data == file_get_contents($path)); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { $path = $this->_getFilePath($id, $group); if (!@unlink($path)) { return false; } return true; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { $return = true; $folder = $group; if (trim($folder) == '') { $mode = 'notgroup'; } switch ($mode) { case 'notgroup' : $folders = $this->_folders($this->_root); for ($i = 0, $n = count($folders); $i < $n; $i++) { if ($folders[$i] != $folder) { $return |= $this->_deleteFolder($this->_root . '/' . $folders[$i]); } } break; case 'group' : default : if (is_dir($this->_root . '/' . $folder)) { $return = $this->_deleteFolder($this->_root . '/' . $folder); } break; } return (bool) $return; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { $result = true; // Files older than lifeTime get deleted from cache $files = $this->_filesInFolder($this->_root, '', true, true, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html')); foreach ($files as $file) { $time = @filemtime($file); if (($time + $this->_lifetime) < $this->_now || empty($time)) { $result |= @unlink($file); } } return (bool) $result; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { return is_writable(JFactory::getConfig()->get('cache_path', JPATH_CACHE)); } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 11.1 */ public function lock($id, $group, $locktime) { $returning = new stdClass; $returning->locklooped = false; $looptime = $locktime * 10; $path = $this->_getFilePath($id, $group); $_fileopen = @fopen($path, "r+b"); if ($_fileopen) { $data_lock = @flock($_fileopen, LOCK_EX); } else { $data_lock = false; } if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. // That implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = @flock($_fileopen, LOCK_EX); $lock_counter++; } } $returning->locked = $data_lock; return $returning; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function unlock($id, $group = null) { $path = $this->_getFilePath($id, $group); $_fileopen = @fopen($path, "r+b"); if ($_fileopen) { $ret = @flock($_fileopen, LOCK_UN); @fclose($_fileopen); return $ret; } return true; } /** * Check if a cache object has expired * * @param string $id Cache ID to check * @param string $group The cache data group * * @return boolean True if the cache ID is valid * * @since 11.1 */ protected function _checkExpire($id, $group) { $path = $this->_getFilePath($id, $group); // Check prune period if (file_exists($path)) { $time = @filemtime($path); if (($time + $this->_lifetime) < $this->_now || empty($time)) { @unlink($path); return false; } return true; } return false; } /** * Get a cache file path from an ID/group pair * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean|string The path to the data object or boolean false if the cache directory does not exist * * @since 11.1 */ protected function _getFilePath($id, $group) { $name = $this->_getCacheId($id, $group); $dir = $this->_root . '/' . $group; // If the folder doesn't exist try to create it if (!is_dir($dir)) { // Make sure the index file is there $indexFile = $dir . '/index.html'; @mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE html><title></title>'); } // Make sure the folder exists if (!is_dir($dir)) { return false; } return $dir . '/' . $name . '.php'; } /** * Quickly delete a folder of files * * @param string $path The path to the folder to delete. * * @return boolean * * @since 11.1 */ protected function _deleteFolder($path) { // Sanity check if (!$path || !is_dir($path) || empty($this->_root)) { // Bad programmer! Bad, bad programmer! JLog::add(__METHOD__ . ' ' . JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'), JLog::WARNING, 'jerror'); return false; } $path = $this->_cleanPath($path); // Check to make sure path is inside cache folder, we do not want to delete Joomla root! $pos = strpos($path, $this->_cleanPath($this->_root)); if ($pos === false || $pos > 0) { JLog::add(__METHOD__ . ' ' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror'); return false; } // Remove all the files in folder if they exist; disable all filtering $files = $this->_filesInFolder($path, '.', false, true, array(), array()); if (!empty($files) && !is_array($files)) { if (@unlink($files) !== true) { return false; } } elseif (!empty($files) && is_array($files)) { foreach ($files as $file) { $file = $this->_cleanPath($file); // In case of restricted permissions we zap it one way or the other as long as the owner is either the webserver or the ftp if (@unlink($file) !== true) { JLog::add(__METHOD__ . ' ' . JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', basename($file)), JLog::WARNING, 'jerror'); return false; } } } // Remove sub-folders of folder; disable all filtering $folders = $this->_folders($path, '.', false, true, array(), array()); foreach ($folders as $folder) { if (is_link($folder)) { // Don't descend into linked directories, just delete the link. if (@unlink($folder) !== true) { return false; } } elseif ($this->_deleteFolder($folder) !== true) { return false; } } // In case of restricted permissions we zap it one way or the other as long as the owner is either the webserver or the ftp if (@rmdir($path)) { return true; } JLog::add(__METHOD__ . ' ' . JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path), JLog::WARNING, 'jerror'); return false; } /** * Function to strip additional / or \ in a path name * * @param string $path The path to clean * @param string $ds Directory separator (optional) * * @return string The cleaned path * * @since 11.1 */ protected function _cleanPath($path, $ds = DIRECTORY_SEPARATOR) { $path = trim($path); if (empty($path)) { return $this->_root; } // Remove double slashes and backslahses and convert all slashes and backslashes to DIRECTORY_SEPARATOR $path = preg_replace('#[/\\\\]+#', $ds, $path); return $path; } /** * Utility function to quickly read the files in a folder. * * @param string $path The path of the folder to read. * @param string $filter A filter for file names. * @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth. * @param boolean $fullpath True to return the full path to the file. * @param array $exclude Array with names of files which should not be shown in the result. * @param array $excludefilter Array of folder names to exclude * * @return array Files in the given folder. * * @since 11.1 */ protected function _filesInFolder($path, $filter = '.', $recurse = false, $fullpath = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'), $excludefilter = array('^\..*', '.*~')) { $arr = array(); // Check to make sure the path valid and clean $path = $this->_cleanPath($path); // Is the path a folder? if (!is_dir($path)) { JLog::add(__METHOD__ . ' ' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror'); return false; } // Read the source directory. if (!($handle = @opendir($path))) { return $arr; } if (count($excludefilter)) { $excludefilter = '/(' . implode('|', $excludefilter) . ')/'; } else { $excludefilter = ''; } while (($file = readdir($handle)) !== false) { if (($file != '.') && ($file != '..') && (!in_array($file, $exclude)) && (!$excludefilter || !preg_match($excludefilter, $file))) { $dir = $path . '/' . $file; $isDir = is_dir($dir); if ($isDir) { if ($recurse) { if (is_int($recurse)) { $arr2 = $this->_filesInFolder($dir, $filter, $recurse - 1, $fullpath); } else { $arr2 = $this->_filesInFolder($dir, $filter, $recurse, $fullpath); } $arr = array_merge($arr, $arr2); } } else { if (preg_match("/$filter/", $file)) { if ($fullpath) { $arr[] = $path . '/' . $file; } else { $arr[] = $file; } } } } } closedir($handle); return $arr; } /** * Utility function to read the folders in a folder. * * @param string $path The path of the folder to read. * @param string $filter A filter for folder names. * @param mixed $recurse True to recursively search into sub-folders, or an integer to specify the maximum depth. * @param boolean $fullpath True to return the full path to the folders. * @param array $exclude Array with names of folders which should not be shown in the result. * @param array $excludefilter Array with regular expressions matching folders which should not be shown in the result. * * @return array Folders in the given folder. * * @since 11.1 */ protected function _folders($path, $filter = '.', $recurse = false, $fullpath = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'), $excludefilter = array('^\..*')) { $arr = array(); // Check to make sure the path valid and clean $path = $this->_cleanPath($path); // Is the path a folder? if (!is_dir($path)) { JLog::add(__METHOD__ . ' ' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror'); return false; } // Read the source directory if (!($handle = @opendir($path))) { return $arr; } if (count($excludefilter)) { $excludefilter_string = '/(' . implode('|', $excludefilter) . ')/'; } else { $excludefilter_string = ''; } while (($file = readdir($handle)) !== false) { if (($file != '.') && ($file != '..') && (!in_array($file, $exclude)) && (empty($excludefilter_string) || !preg_match($excludefilter_string, $file))) { $dir = $path . '/' . $file; $isDir = is_dir($dir); if ($isDir) { // Removes filtered directories if (preg_match("/$filter/", $file)) { if ($fullpath) { $arr[] = $dir; } else { $arr[] = $file; } } if ($recurse) { if (is_int($recurse)) { $arr2 = $this->_folders($dir, $filter, $recurse - 1, $fullpath, $exclude, $excludefilter); } else { $arr2 = $this->_folders($dir, $filter, $recurse, $fullpath, $exclude, $excludefilter); } $arr = array_merge($arr, $arr2); } } } } closedir($handle); return $arr; } } cms/joomla/cache/storage/apc.php 000644 001411 001411 00000013011 12750043556 017333 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * APC cache storage handler * * @see https://secure.php.net/manual/en/book.apc.php * @since 11.1 */ class JCacheStorageApc extends JCacheStorage { /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { return apc_fetch($this->_getCacheId($id, $group)); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { $allinfo = apc_cache_info('user'); $keys = $allinfo['cache_list']; $secret = $this->_hash; $data = array(); foreach ($keys as $key) { // If APCu is being used for this adapter, the internal key name changed with APCu 4.0.7 from key to info $name = isset($key['info']) ? $key['info'] : $key['key']; $namearr = explode('-', $name); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } $item->updateSize($key['mem_size'] / 1024); $data[$group] = $item; } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { return apc_store($this->_getCacheId($id, $group), $data, $this->_lifetime); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { return apc_delete($this->_getCacheId($id, $group)); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { $allinfo = apc_cache_info('user'); $keys = $allinfo['cache_list']; $secret = $this->_hash; foreach ($keys as $key) { // If APCu is being used for this adapter, the internal key name changed with APCu 4.0.7 from key to info $internalKey = isset($key['info']) ? $key['info'] : $key['key']; if (strpos($internalKey, $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { apc_delete($internalKey); } } return true; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { $allinfo = apc_cache_info('user'); $keys = $allinfo['cache_list']; $secret = $this->_hash; foreach ($keys as $key) { // If APCu is being used for this adapter, the internal key name changed with APCu 4.0.7 from key to info $internalKey = isset($key['info']) ? $key['info'] : $key['key']; if (strpos($internalKey, $secret . '-cache-')) { apc_fetch($internalKey); } } } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { $supported = extension_loaded('apc') && ini_get('apc.enabled'); // If on the CLI interface, the `apc.enable_cli` option must also be enabled if ($supported && php_sapi_name() === 'cli') { $supported = ini_get('apc.enable_cli'); } return (bool) $supported; } /** * Lock cached item * * @param string $id The cache data ID * @param string $group The cache data group * @param integer $locktime Cached item max lock time * * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped * * @since 11.1 */ public function lock($id, $group, $locktime) { $returning = new stdClass; $returning->locklooped = false; $looptime = $locktime * 10; $cache_id = $this->_getCacheId($id, $group) . '_lock'; $data_lock = apc_add($cache_id, 1, $locktime); if ($data_lock === false) { $lock_counter = 0; // Loop until you find that the lock has been released. That implies that data get from other thread has finished while ($data_lock === false) { if ($lock_counter > $looptime) { $returning->locked = false; $returning->locklooped = true; break; } usleep(100); $data_lock = apc_add($cache_id, 1, $locktime); $lock_counter++; } } $returning->locked = $data_lock; return $returning; } /** * Unlock cached item * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function unlock($id, $group = null) { return apc_delete($this->_getCacheId($id, $group) . '_lock'); } } cms/joomla/cache/storage/helper.php 000644 001411 001411 00000002154 12750043556 020055 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * Cache storage helper functions. * * @since 11.1 */ class JCacheStorageHelper { /** * Cache data group * * @var string * @since 11.1 */ public $group = ''; /** * Cached item size * * @var string * @since 11.1 */ public $size = 0; /** * Counter * * @var integer * @since 11.1 */ public $count = 0; /** * Constructor * * @param string $group The cache data group * * @since 11.1 */ public function __construct($group) { $this->group = $group; } /** * Increase cache items count. * * @param string $size Cached item size * * @return void * * @since 11.1 */ public function updateSize($size) { $this->size = number_format((float) $this->size + (float) $size, 2, JText::_('DECIMALS_SEPARATOR'), JText::_('THOUSANDS_SEPARATOR')); $this->count++; } } cms/joomla/cache/storage/wincache.php 000644 001411 001411 00000007426 12750043556 020366 0 ustar 00panel panel 000000 000000 <?php /** * @package Joomla.Platform * @subpackage Cache * * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; /** * WinCache cache storage handler * * @see https://secure.php.net/manual/en/book.wincache.php * @since 11.1 */ class JCacheStorageWincache extends JCacheStorage { /** * Get cached data by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function get($id, $group, $checkTime = true) { return wincache_ucache_get($this->_getCacheId($id, $group)); } /** * Get all cached data * * @return mixed Boolean false on failure or a cached data object * * @since 11.1 */ public function getAll() { $allinfo = wincache_ucache_info(); $keys = $allinfo['ucache_entries']; $secret = $this->_hash; $data = array(); foreach ($keys as $key) { $name = $key['key_name']; $namearr = explode('-', $name); if ($namearr !== false && $namearr[0] == $secret && $namearr[1] == 'cache') { $group = $namearr[2]; if (!isset($data[$group])) { $item = new JCacheStorageHelper($group); } else { $item = $data[$group]; } if (isset($key['value_size'])) { $item->updateSize($key['value_size'] / 1024); } else { // Dummy, WINCACHE version is too low. $item->updateSize(1); } $data[$group] = $item; } } return $data; } /** * Store the data to cache by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * @param string $data The data to store in cache * * @return boolean * * @since 11.1 */ public function store($id, $group, $data) { return wincache_ucache_set($this->_getCacheId($id, $group), $data, $this->_lifetime); } /** * Remove a cached data entry by ID and group * * @param string $id The cache data ID * @param string $group The cache data group * * @return boolean * * @since 11.1 */ public function remove($id, $group) { return wincache_ucache_delete($this->_getCacheId($id, $group)); } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * * @return boolean * * @since 11.1 */ public function clean($group, $mode = null) { $allinfo = wincache_ucache_info(); $keys = $allinfo['ucache_entries']; $secret = $this->_hash; foreach ($keys as $key) { if (strpos($key['key_name'], $secret . '-cache-' . $group . '-') === 0 xor $mode != 'group') { wincache_ucache_delete($key['key_name']); } } return true; } /** * Garbage collect expired cache data * * @return boolean * * @since 11.1 */ public function gc() { $allinfo = wincache_ucache_info(); $keys = $allinfo['ucache_entries']; $secret = $this->_hash; foreach ($keys as $key) { if (strpos($key['key_name'], $secret . '-cache-')) { wincache_ucache_get($key['key_name']); } } return true; } /** * Test to see if the storage handler is available. * * @return boolean * * @since 12.1 */ public static function isSupported() { return extension_loaded('wincache') && function_exists('wincache_ucache_get') && !strcmp(ini_get('wincache.ucenabled'), '1'); } } cms/joomla/cache1/cache.php 000644 000000 000000 00000016075 11663435434 016142 0 ustar 00root wheel 000000 000000 <?php /** * @version $Id: cache.php 14401 2010-01-26 14:10:00Z louis $ * @package Joomla.Framework * @subpackage Cache * @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved. * @license GNU/GPL, see LICENSE.php * Joomla! is free software. This version may have been modified pursuant to the * GNU General Public License, and as distributed it includes or is derivative * of works licensed under the GNU General Public License or other free or open * source software licenses. See COPYRIGHT.php for copyright notices and * details. */ // Check to ensure this file is within the rest of the framework defined('JPATH_BASE') or die(); //Register the session storage class with the loader JLoader::register('JCacheStorage', dirname(__FILE__).DS.'storage.php'); /** * Joomla! Cache base object * * @abstract * @package Joomla.Framework * @subpackage Cache * @since 1.5 */ class JCache extends JObject { /** * Storage Handler * @access private * @var object */ var $_handler; /** * Cache Options * @access private * @var array */ var $_options; /** * Constructor * * @access protected * @param array $options options */ function __construct($options) { $this->_options =& $options; // Get the default group and caching if(isset($options['language'])) { $this->_options['language'] = $options['language']; } else { $options['language'] = 'en-GB'; } if(isset($options['cachebase'])) { $this->_options['cachebase'] = $options['cachebase']; } else { $this->_options['cachebase'] = JPATH_ROOT.DS.'cache'; } if(isset($options['defaultgroup'])) { $this->_options['defaultgroup'] = $options['defaultgroup']; } else { $this->_options['defaultgroup'] = 'default'; } if(isset($options['caching'])) { $this->_options['caching'] = $options['caching']; } else { $this->_options['caching'] = true; } if( isset($options['storage'])) { $this->_options['storage'] = $options['storage']; } else { $this->_options['storage'] = 'file'; } //Fix to detect if template positions are enabled... if(JRequest::getCMD('tpl',0)) { $this->_options['caching'] = false; } } /** * Returns a reference to a cache adapter object, always creating it * * @static * @param string $type The cache object type to instantiate * @return object A JCache object * @since 1.5 */ function &getInstance($type = 'output', $options = array()) { $type = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $type)); $class = 'JCache'.ucfirst($type); if(!class_exists($class)) { $path = dirname(__FILE__).DS.'handler'.DS.$type.'.php'; if (file_exists($path)) { require_once($path); } else { JError::raiseError(500, 'Unable to load Cache Handler: '.$type); } } $instance = new $class($options); return $instance; } /** * Get the storage handlers * * @access public * @return array An array of available storage handlers */ function getStores() { jimport('joomla.filesystem.folder'); $handlers = JFolder::files(dirname(__FILE__).DS.'storage', '.php$'); $names = array(); foreach($handlers as $handler) { $name = substr($handler, 0, strrpos($handler, '.')); $class = 'JCacheStorage'.$name; if(!class_exists($class)) { require_once(dirname(__FILE__).DS.'storage'.DS.$name.'.php'); } if(call_user_func_array( array( trim($class), 'test' ), array())) { $names[] = $name; } } return $names; } /** * Set caching enabled state * * @access public * @param boolean $enabled True to enable caching * @return void * @since 1.5 */ function setCaching($enabled) { $this->_options['caching'] = $enabled; } /** * Set cache lifetime * * @access public * @param int $lt Cache lifetime * @return void * @since 1.5 */ function setLifeTime($lt) { $this->_options['lifetime'] = $lt; } /** * Set cache validation * * @access public * @return void * @since 1.5 */ function setCacheValidation() { // Deprecated } /** * Get cached data by id and group * * @abstract * @access public * @param string $id The cache data id * @param string $group The cache data group * @return mixed Boolean false on failure or a cached data string * @since 1.5 */ function get($id, $group=null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage handler $handler =& $this->_getStorage(); if (!JError::isError($handler) && $this->_options['caching']) { return $handler->get($id, $group, (isset($this->_options['checkTime']))? $this->_options['checkTime'] : true); } return false; } /** * Store the cached data by id and group * * @access public * @param string $id The cache data id * @param string $group The cache data group * @param mixed $data The data to store * @return boolean True if cache stored * @since 1.5 */ function store($data, $id, $group=null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage handler and store the cached data $handler =& $this->_getStorage(); if (!JError::isError($handler) && $this->_options['caching']) { return $handler->store($id, $group, $data); } return false; } /** * Remove a cached data entry by id and group * * @abstract * @access public * @param string $id The cache data id * @param string $group The cache data group * @return boolean True on success, false otherwise * @since 1.5 */ function remove($id, $group=null) { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage handler $handler =& $this->_getStorage(); if (!JError::isError($handler)) { return $handler->remove($id, $group); } return false; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @access public * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * @return boolean True on success, false otherwise * @since 1.5 */ function clean($group=null, $mode='group') { // Get the default group $group = ($group) ? $group : $this->_options['defaultgroup']; // Get the storage handler $handler =& $this->_getStorage(); if (!JError::isError($handler)) { return $handler->clean($group, $mode); } return false; } /** * Garbage collect expired cache data * * @access public * @return boolean True on success, false otherwise. * @since 1.5 */ function gc() { // Get the storage handler $handler =& $this->_getStorage(); if (!JError::isError($handler)) { return $handler->gc(); } return false; } /** * Get the cache storage handler * * @access protected * @return object A JCacheStorage object * @since 1.5 */ function &_getStorage() { if (is_a($this->_handler, 'JCacheStorage')) { return $this->_handler; } $this->_handler =& JCacheStorage::getInstance($this->_options['storage'], $this->_options); return $this->_handler; } } cms/joomla/cache1/storage/ 000755 000000 000000 00000000000 11663435474 016025 5 ustar 00root wheel 000000 000000 cms/joomla/cache1/storage.php 000644 000000 000000 00000010617 11663435435 016540 0 ustar 00root wheel 000000 000000 <?php /** * @version $Id:storage.php 6961 2007-03-15 16:06:53Z tcp $ * @package Joomla.Framework * @subpackage Cache * @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved. * @license GNU/GPL, see LICENSE.php * Joomla! is free software. This version may have been modified pursuant * to the GNU General Public License, and as distributed it includes or * is derivative of works licensed under the GNU General Public License or * other free or open source software licenses. * See COPYRIGHT.php for copyright notices and details. */ // Check to ensure this file is within the rest of the framework defined('JPATH_BASE') or die(); /** * Abstract cache storage handler * * @abstract * @package Joomla.Framework * @subpackage Cache * @since 1.5 */ class JCacheStorage extends JObject { /** * Constructor * * @access protected * @param array $options optional parameters */ function __construct( $options = array() ) { $this->_application = (isset($options['application'])) ? $options['application'] : null; $this->_language = (isset($options['language'])) ? $options['language'] : 'en-GB'; $this->_locking = (isset($options['locking'])) ? $options['locking'] : true; $this->_lifetime = (isset($options['lifetime'])) ? $options['lifetime'] : null; $this->_now = (isset($options['now'])) ? $options['now'] : time(); // Set time threshold value. If the lifetime is not set, default to 60 (0 is BAD) // _threshold is now available ONLY as a legacy (it's deprecated). It's no longer used in the core. if (empty($this->_lifetime)) { $this->_threshold = $this->_now - 60; $this->_lifetime = 60; } else { $this->_threshold = $this->_now - $this->_lifetime; } } /** * Returns a reference to a cache storage hanlder object, only creating it * if it doesn't already exist. * * @static * @param string $handler The cache storage handler to instantiate * @return object A JCacheStorageHandler object * @since 1.5 */ function &getInstance($handler = 'file', $options = array()) { static $now = null; if(is_null($now)) { $now = time(); } $options['now'] = $now; //We can't cache this since options may change... $handler = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $handler)); $class = 'JCacheStorage'.ucfirst($handler); if(!class_exists($class)) { $path = dirname(__FILE__).DS.'storage'.DS.$handler.'.php'; if (file_exists($path) ) { require_once($path); } else { return JError::raiseWarning(500, 'Unable to load Cache Storage: '.$handler); } } $return = new $class($options); return $return; } /** * Get cached data by id and group * * @abstract * @access public * @param string $id The cache data id * @param string $group The cache data group * @param boolean $checkTime True to verify cache time expiration threshold * @return mixed Boolean false on failure or a cached data string * @since 1.5 */ function get($id, $group, $checkTime) { return; } /** * Store the data to cache by id and group * * @abstract * @access public * @param string $id The cache data id * @param string $group The cache data group * @param string $data The data to store in cache * @return boolean True on success, false otherwise * @since 1.5 */ function store($id, $group, $data) { return true; } /** * Remove a cached data entry by id and group * * @abstract * @access public * @param string $id The cache data id * @param string $group The cache data group * @return boolean True on success, false otherwise * @since 1.5 */ function remove($id, $group) { return true; } /** * Clean cache for a group given a mode. * * group mode : cleans all cache in the group * notgroup mode : cleans all cache not in the group * * @abstract * @access public * @param string $group The cache data group * @param string $mode The mode for cleaning cache [group|notgroup] * @return boolean True on success, false otherwise * @since 1.5 */ function clean($group, $mode) { return true; } /** * Garbage collect expired cache data * * @abstract * @access public * @return boolean True on success, false otherwise. */ function gc() { return true; } /** * Test to see if the storage handler is available. * * @abstract * @static * @access public * @return boolean True on success, false otherwise. */ function test() { return true; } } cms/joomla/cache1/handler/ 000755 000000 000000 00000000000 11663435473 015775 5 ustar 00root wheel 000000 000000 cms/joomla/cache1/index.html 000644 000000 000000 00000000054 11663435434 016351 0 ustar 00root wheel 000000 000000 <html><body bgcolor="#FFFFFF"></body></html>