[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/plugins/system/logrotation/ -> logrotation.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer