Current Directory: /home/astoriaah/www/administrator/components/com_sh404sef/models
Viewing File: /home/astoriaah/www/administrator/components/com_sh404sef/models/pageids.full.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
*/
// Security check to ensure this file is being included by a parent file.
if (!defined('_JEXEC'))
{
die('Direct Access to this location is not allowed.');
}
class Sh404sefModelPageids extends Sh404sefClassBaselistModel
{
protected $_context = 'sh404sef.pageids';
protected $_defaultTable = 'pageids';
// base char set for creating shurls
protected static $_regular = 'pk3ax9wu68d4hqrfyc';
protected static $_alternate = '7bzeg';
// these words will not be accepted as shURL
// note that
// i, j, l, m, n, o, s, t, v and 0, 1 and 5
// are not used either in regular or alternate
// character set, so ass, sex, cul, pet and many more
// need not be listed here
protected static $_badWords = array('fuck');
protected static $_mustCreate = false;
/**
* Returns true if current sef url being created can have a shURL
* Can be set from within a plugin, otherwise default to false
* Reset to false upon each creation of a new sef url in shInitializePlugin()
*
* @param unknown_type $action
* @param unknown_type $value
*
* @return unknown
*/
public function mustCreatePageId($action = 'get', $value = false)
{
if ($action == 'set')
{
self::$_mustCreate = (boolean) $value;
}
return self::$_mustCreate;
}
/**
* Create a shurl either for an internal URL, or an external URL.
* If external, a fully qualified URL must be supplied, and non non-sef is needed.
*
* @param string $targetUrl
* @param string $targetUrl
*
* @return mixed|string
*/
public function createPageId($sefUrl, $targetUrl)
{
$shURL = '';
$isInternal = wbStartsWith($targetUrl, 'index.php?option');
if ($isInternal && !$this->_mustCreatePageid($targetUrl))
{
return $shURL;
}
jimport('joomla.utilities.string');
$targetUrl = JString::ltrim($targetUrl, '/');
try
{
if ($isInternal && !empty($targetUrl))
{
// check that we don't already have a shURL for the same SEF url, even if non-sef differ
$result = (int) ShlDbHelper::count(
'#__sh404sef_urls',
'*',
$this->_db->quoteName('oldurl') . ' = ? and ' . $this->_db->quoteName('newurl') . ' <> ?',
array(
$targetUrl,
''
)
);
if (!empty($result) && $result > 1)
{
// we already have a SEF URL, so we must already have a shURL as well
return $shURL;
}
}
// check this nonsef url does not already have a shURL
$existingShurl = ShlDbHelper::selectResult(
'#__sh404sef_pageids',
'pageid',
array(
'newurl' => $targetUrl
)
);
// there already is a shurl for the same non-sef
if (!empty($existingShurl))
{
return $existingShurl;
}
// if we don't already have a shURL, create the new one
$shURL = $this->_buildPageId();
if (!empty($shURL))
{
// insert in db
ShlDbHelper::insert(
'#__sh404sef_pageids',
array(
'newurl' => $targetUrl,
'pageid' => $shURL,
'type' => $isInternal ? Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_PAGEID : Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_PAGEID_EXTERNAL,
'hits' => 0
)
);
}
}
catch (\Exception $e)
{
ShlSystem_Log::error('sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
$shURL = '';
}
// don't need to add the pageid to cache, won't be needed when building up the page,
//only when decoding incoming url
return $shURL;
}
public function checkRedirect($shurl)
{
}
/**
* Count pageids record
* either all of them or the currently selected set
* as per user filter settings in meta manager
*
* @param string $type either 'all' or 'selected'
*/
public function getPageIdsCount($type)
{
switch (strtolower($type))
{
// we want to read all automatic urls (include duplicates)
case 'all':
$numberOfPageids = 0;
try
{
$numberOfPageids = ShlDbHelper::count($this->_getTableName(), '*');
}
catch (\Exception $e)
{
}
break;
// we want to read urls as per current selection input fields
// ie : component, language, custom, ...
case 'selected':
// get model and update context with current
$model = ShlMvcModel_Base::getInstance('urls', 'Sh404sefModel');
// use current filters for default layout of metas manager
$context = $model->setContext($this->_context . '.' . 'default');
// display type: simple for very large sites/slow slq servers
$sefConfig = &Sh404sefFactory::getConfig();
// read url data from model
$list = $model->getList((object) array('layout' => 'default', 'getPageId' => true, 'simpleUrlList' => true, 'slowServer' => $sefConfig->slowServer));
$numberOfPageids = 0;
// just count urls with some pageids
if (!empty($list))
{
foreach ($list as $urlRecord)
{
if (!empty($urlRecord->pageid))
{
$numberOfPageids++;
}
}
}
break;
default:
$numberOfPageids = 0;
break;
}
return intval($numberOfPageids);
}
/**
* Delete a list of pagesids from their ids,
* passed as params
*
* @param array of integer $ids the list of shURL id to delete
*/
public function deleteByIds($ids = array())
{
if (empty($ids))
{
return false;
}
// perform deletion
try
{
// delete detailed stats
$shurls = ShlDbHelper::selectColumn(
$this->_getTableName(), 'pageid',
$this->_db->qn('id') . ' in (' . ShlDbHelper::arrayToIntValList($ids) . ')'
);
ShlDbHelper::deleteIn('#__sh404sef_hits_shurls', 'url', $shurls);
ShlDbHelper::deleteIn($this->_getTableName(), 'id', $ids, ShlDbHelper::INTEGER);
}
catch (\Exception $e)
{
$this->setError('Internal database error # ' . $e->getMessage());
return false;
}
return true;
}
/**
* Purge shURL records from the database
* either all of them or the currently selected set
* as per user filter settings in meta manager
*
* @param string $type either 'all' or 'selected'
*/
public function purgePageids($type)
{
// make sure we use latest user state
$this->_updateContextData();
// call the appropriate sub-method to get the db query
$methodName = '_getPurgeQuery' . ucfirst($type);
if (is_callable(array($this, $methodName)))
{
$deleteQuery = $this->$methodName();
}
else
{
$this->setError('Invalid method call _purge' . $type);
return;
}
// then run the query
if (!empty($deleteQuery))
{
// perform deletion
try
{
ShlDbHelper::query($deleteQuery);
}
catch (\Exception $e)
{
$this->setError('Internal database error # ' . $e->getMessage());
}
// reset limit and limitstart variables, to avoid
// issue when displaying again results
$this->_setState('limitstart', 0);
$this->_setState('limit', 0);
}
else
{
$this->setError(JText::_('COM_SH404SEF_NORECORDS'));
}
}
/**
* Delete all automatically generated url records
* from database and cache
*/
private function _getPurgeQueryAll()
{
// delete from database
$query = 'truncate ' . $this->_db->quoteName($this->_getTableName());
return $query;
}
private function _getPurgeQuerySelected()
{
// get model and update context with current
$model = ShlMvcModel_Base::getInstance('urls', 'Sh404sefModel');
// use current filters for default layout of shURLs manager
$context = $model->updateContext($this->_context . '.' . 'default');
// read url data from model
$list = $model->getList((object) array('layout' => 'default', 'getPageId' => true));
$shURLs = array();
// store meta data records ids for urls with some metat data
if (!empty($list))
{
foreach ($list as $urlRecord)
{
$shURLs[] = $this->_db->Quote($urlRecord->pageid, true);
}
}
// if no urls with shURL data, return empty query
if (empty($shURLs))
{
return '';
}
// start delete query
$query = 'delete from ' . $this->_db->quoteName($this->_getTableName());
// call method to build where clause in accordance to current settings and user selection
$where = implode(', ', $shURLs);
// stitch where clause
$query = $query . ' where pageid in (' . $where . ')';
return $query;
}
protected function _buildListWhere($options)
{
// array to hold where clause parts
$where = array();
// are we reading pageids for one specific url ?
$newurl = $this->_getOption('newurl', $options);
if (!is_null($newurl))
{
$where[] = 'newurl = ' . $this->_db->Quote($newurl);
$where[] = 'type = ' . $this->_db->Quote(Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_PAGEID);
}
$filters = $this->getDisplayOptions();
if (!empty($filters->filter_requested_urls))
{
switch ($filters->filter_requested_urls)
{
case Sh404sefHelperGeneral::SHOW_REQUESTED:
$where[] = 'hits > 0';
break;
case Sh404sefHelperGeneral::SHOW_NOT_REQUESTED:
$where[] = 'hits = 0';
break;
}
}
// aggregate clauses
$where = (count($where) ? ' WHERE ' . implode(' AND ', $where) : '');
return $where;
}
protected function _buildListOrderBy($options)
{
// get set of filters applied to the current view
$filters = $this->getDisplayOptions();
// build query fragment
$orderBy = ' order by ' . $this->_db->quoteName('newurl');
$orderBy .= ' ' . $filters->filter_order_Dir;
return $orderBy;
}
protected function _getTableName()
{
return '#__sh404sef_pageids';
}
private function _buildPageId()
{
$shURL = '';
$nextId = $this->_getNextDBId($this->_db->getPrefix() . 'sh404sef_pageids');
if ($nextId !== false)
{
$nextId = base_convert(18 + $nextId, 10, 18);
for ($c = 0; $c < strlen($nextId); ++$c)
{
$char = base_convert($nextId[$c], 18, 10);
$shURL .= self::$_regular[$char];
}
}
// now check if this shurl is not an existing
// SEF or alias. If so, use the alternate char set
// to create a new shurl, and try again.
// using alternate char set (instead of simply increasing nextId)
// makes sure that next time we try to create a shurl (for next URL)
// we won't try something we've already used, making the number of attempts
// for each shurl creation grows each time there is a collision
try
{
$attempts = 0;
$maxAttempts = 8;
// don't need to check for collisions with existing shurls
// as we use the next insert id, and code that using a unique char set
//however, if we need to modify the shurl because it collides with
// an existing SEF url or an alias, we will do so using the alternate
// character set, so the new shurl don't risk collision with a regular
// shurl but it may then collide with another, previously modified shurl
// and so we need to check for shurl collisions when this happens
$doneShurl = true;
// however, need to check for collisions with regular sef urls and aliases
$doneSef = false;
$doneAlias = false;
// and for bad language
$doneClean = false;
// and for actual language codes
$doneLangCode = false;
// prepare user set bad language/exclusion list
$sefConfig = Sh404sefFactory::getConfig();
$countryCodes = Sh404sefFactory::getPConfig()->countryCodes;
$sefConfig->shurlBlackList = JString::trim($sefConfig->shurlBlackList);
if (empty($sefConfig->shurlBlackList))
{
$blackList = array();
}
else
{
if (strpos($sefConfig->shurlBlackList, '|') !== false)
{
$blackList = explode('|', $sefConfig->shurlBlackList);
}
else
{
$blackList = array($sefConfig->shurlBlackList);
}
}
$doneBlackList = false;
do
{
// language code collision
if (!$doneLangCode)
{
if (in_array(strtoupper($shURL), $countryCodes))
{
// language code collision
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate shurl and alias check flag, to check again with this new shurl
$doneShurl = false;
$doneAlias = false;
$doneSef = false;
$doneBlackList = false;
$doneLangCode = false;
}
else
{
$doneLangCode = true;
}
}
// clean word check
if (!$doneClean)
{
if (in_array($shURL, self::$_badWords))
{
// bad language
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate shurl and alias check flag, to check again with this new shurl
$doneShurl = false;
$doneAlias = false;
$doneSef = false;
$doneBlackList = false;
$doneLangCode = false;
}
else
{
$doneClean = true;
}
}
// user word black list
if (!$doneBlackList)
{
if (in_array($shURL, $blackList))
{
// bad language
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate shurl and alias check flag, to check again with this new shurl
$doneShurl = false;
$doneAlias = false;
$doneSef = false;
$doneClean = false;
$doneLangCode = false;
}
else
{
$doneBlackList = true;
}
}
// regular SEF url collision check
if (!$doneSef)
{
$isSEF = (int) ShlDbHelper::count('#__sh404sef_urls', '*', $this->_db->quoteName('oldurl') . ' = ? and ' . $this->_db->quoteName('newurl') . ' <> ?', array($shURL, ''));
if (!empty($isSEF))
{
// there is already a SEF url like that
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate shurl and alias check flag, to check again with this new shurl
$doneShurl = false;
$doneAlias = false;
$doneClean = false;
$doneBlackList = false;
}
else
{
$doneSef = true;
}
}
// previous shurl check
if (!$doneShurl)
{
$isShurl = (int) ShlDbHelper::count(
'#__sh404sef_pageids',
'*',
$this->_db->quoteName('pageid') . ' = ? and (' . $this->_db->quoteName('type') . ' = ? or ' . $this->_db->quoteName('type') . ' = ?)',
array(
$shURL,
Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_PAGEID,
Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_PAGEID_EXTERNAL
)
);
if (!empty($isShurl))
{
// there is already a shurl like that
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate regular sef and alias check flag, to check again with this new shurl
$doneSef = false;
$doneAlias = false;
$doneClean = false;
$doneBlackList = false;
}
else
{
$doneShurl = true;
}
}
// alias collision check
if (!$doneAlias)
{
$isAlias = (int) ShlDbHelper::count(
'#__sh404sef_aliases',
'*',
'alias = ? and (type = ? or type = ?)',
array(Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_ALIAS, Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_ALIAS_WILDCARD)
//array('alias' => $shURL, 'type' => Sh404sefHelperGeneral::COM_SH404SEF_URLTYPE_ALIAS)
);
if (!empty($isAlias))
{
// there is already an alias like that
$attempts++;
// build a new shurl, by changing a character
// with one from the alternate set
$shURL = $this->_getModifiedShurl($shURL);
// invalidate regular sef and shurl check flag, to check again with this new shurl
$doneSef = false;
$doneShurl = false;
$doneClean = false;
$doneBlackList = false;
}
else
{
$doneAlias = true;
}
}
} while ((!$doneSef || !$doneAlias || !$doneShurl || !$doneClean || !$doneBlackList || !$doneLangCode) && ($attempts < $maxAttempts));
}
catch (\Exception $e)
{
}
return $shURL;
}
private function _getModifiedShurl($shurl)
{
static $charIndex = 0;
static $altCharIndex = 0;
$altCharSize = strlen(self::$_alternate);
$shurl[$charIndex] = self::$_alternate[$altCharIndex];
$altCharIndex++;
if ($altCharIndex >= $altCharSize)
{
$altCharIndex = 0;
$charIndex++;
}
return $shurl;
}
private function _getNextDBId($table)
{
if (empty($table))
{
return false;
}
try
{
// need to force replace prefix
$query = 'show table status like ' . $this->_db->Quote($table);
$this->_db->setQuery($query);
$status = $this->_db->loadAssoc();
}
catch (\Exception $e)
{
ShlSystem_Log::error('sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
}
if (empty($status) || empty($status['Auto_increment']))
{
return false;
}
else
{
return (int) $status['Auto_increment'];
}
}
private function _mustCreatePageid($nonSefUrl)
{
// currently disabled by sef url plugin
if (!self::$_mustCreate)
{
return false;
}
// if enabled at sef url plugin level, check configuration
$sefConfig = &Sh404sefFactory::getConfig();
// check global flags
if (!$sefConfig->enablePageId || $sefConfig->stopCreatingShurls)
{
return false;
}
// make sure we have a language
$pageInfo = &Sh404sefFactory::getPageInfo();
$nonSefUrl = Sh404sefHelperUrl::setUrlVar($nonSefUrl, 'lang', $pageInfo->currentLanguageShortTag);
// not on homepage
if (shIsAnyHomepage($nonSefUrl))
{
return '';
}
// check at component level
$option = Sh404sefHelperUrl::getUrlVar($nonSefUrl, 'option');
$option = str_replace('com_', '', $option);
$enable = !empty($option) && in_array($option, $sefConfig->compEnablePageId);
// check non sef url content black list
$sefConfig->shurlNonSefBlackList = JString::trim($sefConfig->shurlNonSefBlackList);
if (empty($sefConfig->shurlNonSefBlackList))
{
$blackList = array();
}
else
{
if (strpos($sefConfig->shurlNonSefBlackList, '|') !== false)
{
$blackList = explode('|', $sefConfig->shurlNonSefBlackList);
}
else
{
$blackList = array($sefConfig->shurlNonSefBlackList);
}
}
if (!empty($blackList))
{
foreach ($blackList as $bit)
{
if (!empty($bit) && strpos($nonSefUrl, $bit) !== false)
{
// match, don't create a shurl for this non sef url
$enable = false;
break;
}
}
}
return $enable;
}
/**
* Gets alist of current filters and sort options which have
* been applied when building up the data
*
* @override
* @return object the list ov values as object properties
*/
public function getDisplayOptions()
{
$options = parent::getDisplayOptions();
// get additional options vs base class
// requested/not requested
$options->filter_requested_urls = $this->_getState('filter_requested_urls');
// return cached instance
return $options;
}
/**
* Provides context data definition, to be used by context handler
* Should be overriden by descendant
*/
protected function _getContextDataDef()
{
$contextData = parent::_getContextDataDef();
// define context data to be retrieved. Cannot be done at class level,
// as some default values are dynamic
$addedContextData = array(
// requested/not requested
array('name' => 'filter_requested_urls', 'html_name' => 'filter_requested_urls', 'default' => '', 'type' => 'string')
);
return array_merge($contextData, $addedContextData);
}
}