[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Plugin
   5   * @subpackage  System.redirect
   6   *
   7   * @copyright   (C) 2009 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\Component\ComponentHelper;
  14  use Joomla\CMS\Event\ErrorEvent;
  15  use Joomla\CMS\Factory;
  16  use Joomla\CMS\Language\Text;
  17  use Joomla\CMS\Plugin\CMSPlugin;
  18  use Joomla\CMS\Router\Route;
  19  use Joomla\CMS\Uri\Uri;
  20  use Joomla\Database\DatabaseInterface;
  21  use Joomla\Database\ParameterType;
  22  use Joomla\Event\SubscriberInterface;
  23  use Joomla\String\StringHelper;
  24  
  25  // phpcs:disable PSR1.Files.SideEffects
  26  \defined('_JEXEC') or die;
  27  // phpcs:enable PSR1.Files.SideEffects
  28  
  29  /**
  30   * Plugin class for redirect handling.
  31   *
  32   * @since  1.6
  33   */
  34  class PlgSystemRedirect extends CMSPlugin implements SubscriberInterface
  35  {
  36      /**
  37       * Affects constructor behavior. If true, language files will be loaded automatically.
  38       *
  39       * @var    boolean
  40       * @since  3.4
  41       */
  42      protected $autoloadLanguage = false;
  43  
  44      /**
  45       * Database object.
  46       *
  47       * @var    DatabaseInterface
  48       * @since  4.0.0
  49       */
  50      protected $db;
  51  
  52      /**
  53       * Returns an array of events this subscriber will listen to.
  54       *
  55       * @return  array
  56       *
  57       * @since   4.0.0
  58       */
  59      public static function getSubscribedEvents(): array
  60      {
  61          return [
  62              'onError' => 'handleError',
  63          ];
  64      }
  65  
  66      /**
  67       * Internal processor for all error handlers
  68       *
  69       * @param   ErrorEvent  $event  The event object
  70       *
  71       * @return  void
  72       *
  73       * @since   3.5
  74       */
  75      public function handleError(ErrorEvent $event)
  76      {
  77          /** @var \Joomla\CMS\Application\CMSApplication $app */
  78          $app = $event->getApplication();
  79  
  80          if ($app->isClient('administrator') || ((int) $event->getError()->getCode() !== 404)) {
  81              return;
  82          }
  83  
  84          $uri = Uri::getInstance();
  85  
  86          // These are the original URLs
  87          $orgurl                = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment')));
  88          $orgurlRel             = rawurldecode($uri->toString(array('path', 'query', 'fragment')));
  89  
  90          // The above doesn't work for sub directories, so do this
  91          $orgurlRootRel         = str_replace(Uri::root(), '', $orgurl);
  92  
  93          // For when users have added / to the url
  94          $orgurlRootRelSlash    = str_replace(Uri::root(), '/', $orgurl);
  95          $orgurlWithoutQuery    = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'fragment')));
  96          $orgurlRelWithoutQuery = rawurldecode($uri->toString(array('path', 'fragment')));
  97  
  98          // These are the URLs we save and use
  99          $url                = StringHelper::strtolower(rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment'))));
 100          $urlRel             = StringHelper::strtolower(rawurldecode($uri->toString(array('path', 'query', 'fragment'))));
 101  
 102          // The above doesn't work for sub directories, so do this
 103          $urlRootRel         = str_replace(Uri::root(), '', $url);
 104  
 105          // For when users have added / to the url
 106          $urlRootRelSlash    = str_replace(Uri::root(), '/', $url);
 107          $urlWithoutQuery    = StringHelper::strtolower(rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'fragment'))));
 108          $urlRelWithoutQuery = StringHelper::strtolower(rawurldecode($uri->toString(array('path', 'fragment'))));
 109  
 110          $excludes = (array) $this->params->get('exclude_urls');
 111  
 112          $skipUrl = false;
 113  
 114          foreach ($excludes as $exclude) {
 115              if (empty($exclude->term)) {
 116                  continue;
 117              }
 118  
 119              if (!empty($exclude->regexp)) {
 120                  // Only check $url, because it includes all other sub urls
 121                  if (preg_match('/' . $exclude->term . '/i', $orgurlRel)) {
 122                      $skipUrl = true;
 123                      break;
 124                  }
 125              } else {
 126                  if (StringHelper::strpos($orgurlRel, $exclude->term) !== false) {
 127                      $skipUrl = true;
 128                      break;
 129                  }
 130              }
 131          }
 132  
 133          /**
 134           * Why is this (still) here?
 135           * Because hackers still try urls with mosConfig_* and Url Injection with =http[s]:// and we dont want to log/redirect these requests
 136           */
 137          if ($skipUrl || (strpos($url, 'mosConfig_') !== false) || (strpos($url, '=http') !== false)) {
 138              return;
 139          }
 140  
 141          $query = $this->db->getQuery(true);
 142  
 143          $query->select('*')
 144              ->from($this->db->quoteName('#__redirect_links'))
 145              ->whereIn(
 146                  $this->db->quoteName('old_url'),
 147                  [
 148                      $url,
 149                      $urlRel,
 150                      $urlRootRel,
 151                      $urlRootRelSlash,
 152                      $urlWithoutQuery,
 153                      $urlRelWithoutQuery,
 154                      $orgurl,
 155                      $orgurlRel,
 156                      $orgurlRootRel,
 157                      $orgurlRootRelSlash,
 158                      $orgurlWithoutQuery,
 159                      $orgurlRelWithoutQuery,
 160                  ],
 161                  ParameterType::STRING
 162              );
 163  
 164          $this->db->setQuery($query);
 165  
 166          $redirect = null;
 167  
 168          try {
 169              $redirects = $this->db->loadAssocList();
 170          } catch (Exception $e) {
 171              $event->setError(new Exception(Text::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
 172  
 173              return;
 174          }
 175  
 176          $possibleMatches = array_unique(
 177              array(
 178                  $url,
 179                  $urlRel,
 180                  $urlRootRel,
 181                  $urlRootRelSlash,
 182                  $urlWithoutQuery,
 183                  $urlRelWithoutQuery,
 184                  $orgurl,
 185                  $orgurlRel,
 186                  $orgurlRootRel,
 187                  $orgurlRootRelSlash,
 188                  $orgurlWithoutQuery,
 189                  $orgurlRelWithoutQuery,
 190              )
 191          );
 192  
 193          foreach ($possibleMatches as $match) {
 194              if (($index = array_search($match, array_column($redirects, 'old_url'))) !== false) {
 195                  $redirect = (object) $redirects[$index];
 196  
 197                  if ((int) $redirect->published === 1) {
 198                      break;
 199                  }
 200              }
 201          }
 202  
 203          // A redirect object was found and, if published, will be used
 204          if ($redirect !== null && ((int) $redirect->published === 1)) {
 205              if (!$redirect->header || (bool) ComponentHelper::getParams('com_redirect')->get('mode', false) === false) {
 206                  $redirect->header = 301;
 207              }
 208  
 209              if ($redirect->header < 400 && $redirect->header >= 300) {
 210                  $urlQuery = $uri->getQuery();
 211  
 212                  $oldUrlParts = parse_url($redirect->old_url);
 213  
 214                  $newUrl = $redirect->new_url;
 215  
 216                  if ($urlQuery !== '' && empty($oldUrlParts['query'])) {
 217                      $newUrl .= '?' . $urlQuery;
 218                  }
 219  
 220                  $dest = Uri::isInternal($newUrl) || strpos($newUrl, 'http') === false ?
 221                      Route::_($newUrl) : $newUrl;
 222  
 223                  // In case the url contains double // lets remove it
 224                  $destination = str_replace(Uri::root() . '/', Uri::root(), $dest);
 225  
 226                  // Always count redirect hits
 227                  $redirect->hits++;
 228  
 229                  try {
 230                      $this->db->updateObject('#__redirect_links', $redirect, 'id');
 231                  } catch (Exception $e) {
 232                      // We don't log issues for now
 233                  }
 234  
 235                  $app->redirect($destination, (int) $redirect->header);
 236              }
 237  
 238              $event->setError(new RuntimeException($event->getError()->getMessage(), $redirect->header, $event->getError()));
 239          } elseif ($redirect === null) {
 240              // No redirect object was found so we create an entry in the redirect table
 241              if ((bool) $this->params->get('collect_urls', 1)) {
 242                  if (!$this->params->get('includeUrl', 1)) {
 243                      $url = $urlRel;
 244                  }
 245  
 246                  $nowDate = Factory::getDate()->toSql();
 247  
 248                  $data = (object) array(
 249                      'id' => 0,
 250                      'old_url' => $url,
 251                      'referer' => $app->input->server->getString('HTTP_REFERER', ''),
 252                      'hits' => 1,
 253                      'published' => 0,
 254                      'created_date' => $nowDate,
 255                      'modified_date' => $nowDate,
 256                  );
 257  
 258                  try {
 259                      $this->db->insertObject('#__redirect_links', $data, 'id');
 260                  } catch (Exception $e) {
 261                      $event->setError(new Exception(Text::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
 262  
 263                      return;
 264                  }
 265              }
 266          } else {
 267              // We have an unpublished redirect object, increment the hit counter
 268              $redirect->hits++;
 269  
 270              try {
 271                  $this->db->updateObject('#__redirect_links', $redirect, ['id']);
 272              } catch (Exception $e) {
 273                  $event->setError(new Exception(Text::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
 274  
 275                  return;
 276              }
 277          }
 278      }
 279  }


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