[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Plugin 5 * @subpackage System.logrotation 6 * 7 * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 10 * @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace 11 */ 12 13 use Joomla\CMS\Cache\Cache; 14 use Joomla\CMS\Factory; 15 use Joomla\CMS\Filesystem\File; 16 use Joomla\CMS\Filesystem\Folder; 17 use Joomla\CMS\Plugin\CMSPlugin; 18 use Joomla\Filesystem\Path; 19 20 // phpcs:disable PSR1.Files.SideEffects 21 \defined('_JEXEC') or die; 22 // phpcs:enable PSR1.Files.SideEffects 23 24 /** 25 * Joomla! Log Rotation plugin 26 * 27 * Rotate the log files created by Joomla core 28 * 29 * @since 3.9.0 30 */ 31 class PlgSystemLogrotation extends CMSPlugin 32 { 33 /** 34 * Load the language file on instantiation. 35 * 36 * @var boolean 37 * 38 * @since 3.9.0 39 */ 40 protected $autoloadLanguage = true; 41 42 /** 43 * @var \Joomla\CMS\Application\CMSApplication 44 * 45 * @since 3.9.0 46 */ 47 protected $app; 48 49 /** 50 * @var \Joomla\Database\DatabaseDriver 51 * 52 * @since 3.9.0 53 */ 54 protected $db; 55 56 /** 57 * The log check and rotation code is triggered after the page has fully rendered. 58 * 59 * @return void 60 * 61 * @since 3.9.0 62 */ 63 public function onAfterRender() 64 { 65 // Get the timeout as configured in plugin parameters 66 67 /** @var \Joomla\Registry\Registry $params */ 68 $cache_timeout = (int) $this->params->get('cachetimeout', 30); 69 $cache_timeout = 24 * 3600 * $cache_timeout; 70 $logsToKeep = (int) $this->params->get('logstokeep', 1); 71 72 // Do we need to run? Compare the last run timestamp stored in the plugin's options with the current 73 // timestamp. If the difference is greater than the cache timeout we shall not execute again. 74 $now = time(); 75 $last = (int) $this->params->get('lastrun', 0); 76 77 if ((abs($now - $last) < $cache_timeout)) { 78 return; 79 } 80 81 // Update last run status 82 $this->params->set('lastrun', $now); 83 84 $paramsJson = $this->params->toString('JSON'); 85 $db = $this->db; 86 $query = $db->getQuery(true) 87 ->update($db->quoteName('#__extensions')) 88 ->set($db->quoteName('params') . ' = :params') 89 ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) 90 ->where($db->quoteName('folder') . ' = ' . $db->quote('system')) 91 ->where($db->quoteName('element') . ' = ' . $db->quote('logrotation')) 92 ->bind(':params', $paramsJson); 93 94 try { 95 // Lock the tables to prevent multiple plugin executions causing a race condition 96 $db->lockTable('#__extensions'); 97 } catch (Exception $e) { 98 // If we can't lock the tables it's too risky to continue execution 99 return; 100 } 101 102 try { 103 // Update the plugin parameters 104 $result = $db->setQuery($query)->execute(); 105 106 $this->clearCacheGroups(array('com_plugins'), array(0, 1)); 107 } catch (Exception $exc) { 108 // If we failed to execute 109 $db->unlockTables(); 110 $result = false; 111 } 112 113 try { 114 // Unlock the tables after writing 115 $db->unlockTables(); 116 } catch (Exception $e) { 117 // If we can't lock the tables assume we have somehow failed 118 $result = false; 119 } 120 121 // Abort on failure 122 if (!$result) { 123 return; 124 } 125 126 // Get the log path 127 $logPath = Path::clean($this->app->get('log_path')); 128 129 // Invalid path, stop processing further 130 if (!is_dir($logPath)) { 131 return; 132 } 133 134 $logFiles = $this->getLogFiles($logPath); 135 136 // Sort log files by version number in reserve order 137 krsort($logFiles, SORT_NUMERIC); 138 139 foreach ($logFiles as $version => $files) { 140 if ($version >= $logsToKeep) { 141 // Delete files which has version greater than or equals $logsToKeep 142 foreach ($files as $file) { 143 File::delete($logPath . '/' . $file); 144 } 145 } else { 146 // For files which has version smaller than $logsToKeep, rotate (increase version number) 147 foreach ($files as $file) { 148 $this->rotate($logPath, $file, $version); 149 } 150 } 151 } 152 } 153 154 /** 155 * Get log files from log folder 156 * 157 * @param string $path The folder to get log files 158 * 159 * @return array The log files in the given path grouped by version number (not rotated files has number 0) 160 * 161 * @since 3.9.0 162 */ 163 private function getLogFiles($path) 164 { 165 $logFiles = array(); 166 $files = Folder::files($path, '\.php$'); 167 168 foreach ($files as $file) { 169 $parts = explode('.', $file); 170 171 /* 172 * Rotated log file has this filename format [VERSION].[FILENAME].php. So if $parts has at least 3 elements 173 * and the first element is a number, we know that it's a rotated file and can get it's current version 174 */ 175 if (count($parts) >= 3 && is_numeric($parts[0])) { 176 $version = (int) $parts[0]; 177 } else { 178 $version = 0; 179 } 180 181 if (!isset($logFiles[$version])) { 182 $logFiles[$version] = array(); 183 } 184 185 $logFiles[$version][] = $file; 186 } 187 188 return $logFiles; 189 } 190 191 /** 192 * Method to rotate (increase version) of a log file 193 * 194 * @param string $path Path to file to rotate 195 * @param string $filename Name of file to rotate 196 * @param int $currentVersion The current version number 197 * 198 * @return void 199 * 200 * @since 3.9.0 201 */ 202 private function rotate($path, $filename, $currentVersion) 203 { 204 if ($currentVersion === 0) { 205 $rotatedFile = $path . '/1.' . $filename; 206 } else { 207 /* 208 * Rotated log file has this filename format [VERSION].[FILENAME].php. To rotate it, we just need to explode 209 * the filename into an array, increase value of first element (keep version) and implode it back to get the 210 * rotated file name 211 */ 212 $parts = explode('.', $filename); 213 $parts[0] = $currentVersion + 1; 214 215 $rotatedFile = $path . '/' . implode('.', $parts); 216 } 217 218 File::move($path . '/' . $filename, $rotatedFile); 219 } 220 221 /** 222 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp. 223 * 224 * @param array $clearGroups The cache groups to clean 225 * @param array $cacheClients The cache clients (site, admin) to clean 226 * 227 * @return void 228 * 229 * @since 3.9.0 230 */ 231 private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1)) 232 { 233 foreach ($clearGroups as $group) { 234 foreach ($cacheClients as $client_id) { 235 try { 236 $options = array( 237 'defaultgroup' => $group, 238 'cachebase' => $client_id ? JPATH_ADMINISTRATOR . '/cache' : 239 Factory::getApplication()->get('cache_path', JPATH_SITE . '/cache'), 240 ); 241 242 $cache = Cache::getInstance('callback', $options); 243 $cache->clean(); 244 } catch (Exception $e) { 245 // Ignore it 246 } 247 } 248 } 249 } 250 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |