diff --git a/plugins/system/redirect/redirect.php b/plugins/system/redirect/redirect.php index 9403a261e11ad..856be90135efc 100644 --- a/plugins/system/redirect/redirect.php +++ b/plugins/system/redirect/redirect.php @@ -101,11 +101,9 @@ public static function handleException($exception) */ private static function doErrorHandling($error) { - // Get the application object. $app = JFactory::getApplication(); - // Make sure the error is a 404 and we are not in the administrator. - if ($app->isAdmin() || $error->getCode() != 404) + if ($app->isAdmin() || ((int) $error->getCode() !== 404)) { // Proxy to the previous exception handler if available, otherwise just render the error page if (self::$previousExceptionHandler) @@ -118,125 +116,135 @@ private static function doErrorHandling($error) } } - // Get the full current URI. - $uri = JUri::getInstance(); - $current = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment'))); + $uri = JUri::getInstance(); - // Attempt to ignore idiots. - if ((strpos($current, 'mosConfig_') !== false) || (strpos($current, '=http://') !== false)) + $url = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment'))); + $urlRel = rawurldecode($uri->toString(array('path', 'query', 'fragment'))); + + $urlWithoutQuery = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'fragment'))); + $urlRelWithoutQuery = rawurldecode($uri->toString(array('path', 'fragment'))); + + // Why is this (still) here? + if ((strpos($url, 'mosConfig_') !== false) || (strpos($url, '=http://') !== false)) { - // Render the error page. JErrorPage::render($error); } - // See if the current url exists in the database as a redirect. - $db = JFactory::getDbo(); - $query = $db->getQuery(true) - ->select($db->quoteName(array('new_url', 'header'))) - ->select($db->quoteName('published')) + $db = JFactory::getDbo(); + + $query = $db->getQuery(true); + + $query->select('*') ->from($db->quoteName('#__redirect_links')) - ->where($db->quoteName('old_url') . ' = ' . $db->quote($current)); - $db->setQuery($query, 0, 1); - $link = $db->loadObject(); + ->where( + '(' + . $db->quoteName('old_url') . ' = ' . $db->quote($url) + . ' OR ' + . $db->quoteName('old_url') . ' = ' . $db->quote($urlRel) + . ' OR ' + . $db->quoteName('old_url') . ' = ' . $db->quote($urlWithoutQuery) + . ' OR ' + . $db->quoteName('old_url') . ' = ' . $db->quote($urlRelWithoutQuery) + . ')' + ); - // If no published redirect was found try with the server-relative URL - if (!$link || ($link->published != 1)) + $db->setQuery($query); + + $redirect = null; + + try { - $currRel = rawurldecode($uri->toString(array('path', 'query', 'fragment'))); - $query = $db->getQuery(true) - ->select($db->quoteName(array('new_url', 'header'))) - ->select($db->quoteName('published')) - ->from($db->quoteName('#__redirect_links')) - ->where($db->quoteName('old_url') . ' = ' . $db->quote($currRel)); - $db->setQuery($query, 0, 1); - $link = $db->loadObject(); + $redirects = $db->loadAssocList(); } - - // If a redirect exists and is published, permanently redirect. - if ($link && ($link->published == 1)) + catch (Exception $e) { - // If no header is set use a 301 permanent redirect - if (!$link->header || JComponentHelper::getParams('com_redirect')->get('mode', 0) == false) - { - $link->header = 301; - } + JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e)); + } + + $possibleMatches = array_unique( + array($url, $urlRel, $urlWithoutQuery, $urlRelWithoutQuery) + ); - // If we have a redirect in the 300 range use JApplicationWeb::redirect(). - if ($link->header < 400 && $link->header >= 300) + foreach ($possibleMatches as $match) + { + if (($index = array_search($match, array_column($redirects, 'old_url'))) !== false) { - $new_link = JUri::isInternal($link->new_url) ? JRoute::_($link->new_url) : $link->new_url; + $redirect = (object) $redirects[$index]; - $app->redirect($new_link, intval($link->header)); + if ((int) $redirect->published === 1) + { + break; + } } - - // Else rethrow the exeception with the new header and return - JErrorPage::render(new RuntimeException($error->getMessage(), $link->header, $error)); } - try + // A redirect object was found and, if published, will be used + if (!is_null($redirect) && ((int) $redirect->published === 1)) { - $referer = $app->input->server->getString('HTTP_REFERER', ''); - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from($db->quoteName('#__redirect_links')) - ->where($db->quoteName('old_url') . ' = ' . $db->quote($current)); - $db->setQuery($query); - $res = $db->loadResult(); - - if (!$res) + if (!$redirect->header || (bool) JComponentHelper::getParams('com_redirect')->get('mode', false) === false) + { + $redirect->header = 301; + } + + if ($redirect->header < 400 && $redirect->header >= 300) { - // If not, add the new url to the database but only if option is enabled - $params = new Registry(JPluginHelper::getPlugin('system', 'redirect')->params); - $collect_urls = $params->get('collect_urls', 1); + $urlQuery = $uri->getQuery(); + + $oldUrlParts = parse_url($redirect->old_url); - if ($collect_urls == true) + if (empty($oldUrlParts['query']) && $urlQuery !== '') { - $columns = array( - $db->quoteName('old_url'), - $db->quoteName('new_url'), - $db->quoteName('referer'), - $db->quoteName('comment'), - $db->quoteName('hits'), - $db->quoteName('published'), - $db->quoteName('created_date') - ); - - $values = array( - $db->quote($current), - $db->quote(''), - $db->quote($referer), - $db->quote(''), - 1, - 0, - $db->quote(JFactory::getDate()->toSql()) - ); - - $query->clear() - ->insert($db->quoteName('#__redirect_links'), false) - ->columns($columns) - ->values(implode(', ', $values)); - - $db->setQuery($query); - $db->execute(); + $redirect->new_url .= '?' . $urlQuery; } + + $destination = JUri::isInternal($redirect->new_url) ? JRoute::_($redirect->new_url) : $redirect->new_url; + + $app->redirect($destination, (int) $redirect->header); } - else + + JErrorPage::render(new RuntimeException($error->getMessage(), $redirect->header, $error)); + } + // No redirect object was found so we create an entry in the redirect table + elseif (is_null($redirect)) + { + $params = new Registry(JPluginHelper::getPlugin('system', 'redirect')->params); + + if ((bool) $params->get('collect_urls', true)) { - // Existing error url, increase hit counter. - $query->clear() - ->update($db->quoteName('#__redirect_links')) - ->set($db->quoteName('hits') . ' = ' . $db->quoteName('hits') . ' + 1') - ->where('id = ' . (int) $res); - $db->setQuery($query); - $db->execute(); + $data = (object) array( + 'id' => 0, + 'old_url' => $url, + 'referer' => $app->input->server->getString('HTTP_REFERER', ''), + 'hits' => 1, + 'published' => 0, + 'created_date' => JFactory::getDate()->toSql() + ); + + try + { + $db->insertObject('#__redirect_links', $data, 'id'); + } + catch (Exception $e) + { + JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e)); + } } } - catch (RuntimeException $exception) + // We have an unpublished redirect object, increment the hit counter + else { - JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 404, $exception)); + $redirect->hits += 1; + + try + { + $db->updateObject('#__redirect_links', $redirect, 'id'); + } + catch (Exception $e) + { + JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e)); + } } - // Render the error page. JErrorPage::render($error); } }