[ 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.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 }
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 |