File Manager

Current Directory: /home/astoriaah/www/plugins/sh404sefcore/sh404sefsimilarurls
Viewing File: /home/astoriaah/www/plugins/sh404sefcore/sh404sefsimilarurls/sh404sefsimilarurls.php
<?php /** * sh404SEF - SEO extension for Joomla! * * @author Yannick Gaultier * @copyright (c) Yannick Gaultier - Weeblr llc - 2022 * @package sh404SEF * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 4.24.1.4308 * @date 2022-05-31 */ defined('_JEXEC') or die('Direct Access to this location is not allowed.'); jimport('joomla.utilities.string'); $app = JFactory::getApplication(); if (!$app->isAdmin()) { $app->registerEvent('onContentPrepare', 'plgSh404sefsimilarurls'); } function plgSh404sefsimilarurls($context, &$rowContent, &$params, $page = 0) { if (!defined('SH404SEF_IS_RUNNING')) { // only do something if sh404sef is up and running return true; } if ($context == 'com_finder.indexer') { return true; } if (empty($rowContent->text)) { return true; } // a little hack on the side : optionnally display the requested url // replace marker $url = JURI::getInstance()->toString(); $rowContent->text = str_replace('{%sh404SEF_404_URL%}', htmlspecialchars(urldecode($url), ENT_COMPAT, 'UTF-8'), $rowContent->text); // now the similar urls $marker = 'sh404sefSimilarUrls'; // quick check for our marker: if (JString::strpos($rowContent->text, $marker) === false) { return true; } // get plugin params $plugin = JPluginHelper::getPlugin('sh404sefcore', 'sh404sefsimilarurls'); // init params from plugin $pluginParams = new JRegistry; $pluginParams->loadString($plugin->params); $matches = array(); // regexp to catch plugin requests $regExp = "#{" . $marker . "}#Uus"; // search for our marker} if (preg_match_all($regExp, $rowContent->text, $matches, PREG_SET_ORDER) > 0) { // we have at least one match, we can search for similar urls $target = str_replace(JURI::base(true), '', JURI::getInstance()->getPath()); $html = shGetSimilarUrls($target, $pluginParams); // remove comment, so that nothing shows if (empty($html)) { $rowContent->text = ShlSystem_Strings::pr('/{sh404sefSimilarUrlsCommentStart}.*{sh404sefSimilarUrlsCommentEnd}/iUus', '', $rowContent->text); } else { // remove the comment markers themselves $rowContent->text = str_replace('{sh404sefSimilarUrlsCommentStart}', '', $rowContent->text); $rowContent->text = str_replace('{sh404sefSimilarUrlsCommentEnd}', '', $rowContent->text); } // now replace instances of the marker by similar urls list $rowContent->text = str_replace($matches[0], $html, $rowContent->text); } return true; } /** * @params object parameters set by user for the plugin * @return string a list of sef urls similar to that of the current page */ function shGetSimilarUrls($path, $params) { // init result $urls = ''; // current path $path = JString::trim($path); $path = JString::trim($path, '.'); // if empty, we may be on a non-sef urls if (empty($path)) { return $urls; } $urlList = shFindSimilarUrls($path, $params); $urls = shFormatSimilarUrls($urlList); return $urls; } /** * @params object parameters set by user for the plugin * @return string a list of sef urls similar to that of the current page */ function shFindSimilarUrls($path, $params) { // init result $urls = array(); // if empty, we may be on a non-sef urls if (empty($path)) { return $urls; } // actually do the search // minimum segment to use $minLength = $params->get('min_segment_length', 3); // break down path into segments, and check them $bits = explode('/', $path); // discard elements that are too short // and prepare for db query $segments = array(); $originalSegments = array(); foreach ($bits as $bit) { // for soundex, we keep the whole url if (JString::strlen($bit) >= $minLength) { $originalSegments[] = $bit; } // try break down the request further, based on common replacement character values $bit = str_replace('-', ' ', $bit); $bit = str_replace('_', ' ', $bit); $bit = str_replace('.', ' ', $bit); // now we can break down based on spaces $subBits = explode(' ', $bit); // keep only the good ones foreach ($subBits as $subBit) { if ((JString::strlen($subBit) >= $minLength) && JString::strtolower($subBit) != 'html' && JString::strtolower($subBit) != 'htm' && JString::strtolower($subBit) != 'php' ) { $segments[] = $subBit; } } } // call search function $urls = shSearchSimilarUrls($segments, $originalSegments, $path, $params); // return whatever we found return $urls; } /** * Search the sef url and aliases tables for * urls similar to the current one * * @param $bits segment of the requested url, borken down to each individual words in the url * @param $originalBits segment of the urls, broken down by only by slashes * @param $limit * @return unknown_type */ function shSearchSimilarUrls($bits, $originalBits, $searchedPath, $params) { // init result $urls = array(); // do we have data to work with ? if (empty($bits)) { return $urls; } // get params we need // how many urls to display, max ? $limit = $params->get('max_number_of_urls', 5); // include pdf ? $includePdf = $params->get('include_pdf', 0); // include printable ? $includePrint = $params->get('include_print', 0); // get db instance $db = ShlDbHelper::getDb(); // search the redirection table for similar urls $sql = 'SELECT `oldurl`, `newurl`, `id`, `rank`, `dateadd`, soundex(`oldurl`) AS soundex_value FROM `#__sh404sef_urls` where `newurl` <> "" and `rank` = 0 '; // virtuemart hack $sql .= ' AND `oldurl` not like ' . $db->Quote('%vmchk%'); // additional conditions : never include feed results $sql .= ' AND `newurl` not like ' . $db->Quote('%format=feed%'); // additional user-set conditions if (!$includePdf) { $sql .= ' AND `newurl` not like ' . $db->Quote('%format=pdf%'); } if (!$includePrint) { $sql .= ' AND `newurl` not like ' . $db->Quote('%print=1%'); } // apply exclusion list $excludedWords = $params->get('excluded_words_sef', ''); if (!empty($excludedWords)) { $words = explode("\n", $excludedWords); foreach ($words as $word) { $word = trim($word); if (!empty($word)) { $sql .= ' AND `oldurl` not like ' . shEscapeLike('%' . $word . '%', $db); } } } $excludedWords = $params->get('excluded_words_non_sef', ''); if (!empty($excludedWords)) { $words = explode("\n", $excludedWords); foreach ($words as $word) { $word = trim($word); if (!empty($word)) { $sql .= ' AND `newurl` not like ' . shEscapeLike('%' . $word . '%', $db); } } } // search the redirection table for similar urls $sql .= ' AND ( '; $sql .= ' soundex(oldurl) = soundex(' . $db->Quote(implode('/', $originalBits)) . ')'; $subSql = array(); foreach ($bits as $bit) { $subSql[] = ' `oldurl` like ' . shEscapeLike('%' . $bit . '%', $db); } $sql .= ' OR '; $sql .= implode(' OR ', $subSql); $sql .= ')'; // group and limit result set $sql .= ' GROUP BY `oldurl`'; $sql .= ' limit 500'; // perform query $db->setQuery($sql); $urlList = $db->loadObjectList(); $urlList = empty($urlList) ? array() : $urlList; // rank them, trying to have the best one near the top of the list $urlList = shRankSimilarUrlsSimilarText($urlList, $searchedPath); // only keep a limited number $urlList = array_slice($urlList, 0, $limit); // now build an unordered list with the remaining solutions reset($urlList); // return whatever we found return $urlList; } function shEscapeLike($string, $db) { $escaped = str_replace('_', '\_', $db->Quote($string)); return $escaped; } function shFormatSimilarUrls($urlList) { $urls = ''; if (!empty($urlList)) { foreach ($urlList as $url) { $urls .= '<li><a href="' . JRoute::_($url->newurl) . '">' . $url->oldurl . '</a></li>'; } $urls = '<ul>' . $urls . '</ul>'; } return $urls; } /** * Call back function for usort * Compares distance between requested url lenght and * candidate url length * * @param $a * @param $b * @return unknown_type */ function shSortByReverseDistance($a, $b) { if ($a['distance'] == $b['distance']) { return 0; } return ($a['distance'] >= $b['distance']) ? -1 : 1; } /** * Apply a method to put the most appropriate urls * at top of list * * @param array $urls an array of retrieved urls * @return array same array, sorted to have most relevant url at offset 0, 1, etc */ function shRankSimilarUrlsSimilarText($urls, $searchedPath) { if (empty($urls)) { return $urls; } // sort by distance // current path $path = JString::trim($searchedPath); $path = JString::trim($path, '.'); // create a temporary array indexed on distance // between the length of the request and the current similar url $tmp = array(); foreach ($urls as $url) { $r = null; $distance = similar_text($url->oldurl, $path, $r); $t = array('distance' => $r, 'url' => $url); $tmp[] = $t; } // sort this array according to text similarity usort($tmp, 'shSortByReverseDistance'); // recreate the array we want $rankedUrls = array(); foreach ($tmp as $u) { $rankedUrls[] = $u['url']; } return $rankedUrls; }