Skip to content

Commit

Permalink
unacms#1091 User friendly URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Trofimov committed Dec 7, 2021
1 parent 705af0e commit 9f48c30
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 20 deletions.
109 changes: 109 additions & 0 deletions inc/classes/BxDolPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,115 @@ static public function processPageTrigger ($sPageTriggerName)
return true;
}

/**
* Process SEO links. It takes request part from SEO link and process it
* to make it work as regular page link
* @param $sRequest request URI with SEO link
* @return true - if page was found and processed correctly, false - if page wasn't found
*/
static public function processSeoLink ($sRequest)
{
$a = explode('/', trim($sRequest, '/'));
if (!$a || empty($a[0]))
return false;

$sPageName = BxDolPageQuery::getPageObjectNameByURI($a[0]);
$aPage = $sPageName ? BxDolPageQuery::getPageObject($sPageName) : false;
if (!$aPage)
return false;

if (!empty($a[1])) { // page with params
$r = BxDolPageQuery::getSeoLink($aPage['module'], $a[0], ['uri' => $a[1]]);
if ($r)
$_GET[$r['param_name']] = $_REQUEST[$r['param_name']] = $r['param_value'];
}

$_REQUEST['i'] = $_GET['i'] = $a[0];
$oPage = BxDolPage::getObjectInstanceByURI($a[0], false, true);
$oPage->displayPage();

return true;
}

/**
* Transform regular link to SEO link. It takes regular list as param and return SEO link.
* @param $sLink regular link
* @param $sPrefix prefix to add to the final URL, usually BX_DOL_URL_ROOT
* @param $aParams additional GET params
* @return SEO link string on success, false if transform failed
*/
static public function transformSeoLink ($sLink, $sPrefix, $aParams = array())
{
if (0 !== strncmp('page.php', $sLink, 8)) // only page.php links are supported
return false;

$sQuery = parse_url($sLink, PHP_URL_QUERY);
if (false === $sQuery)
return false;

parse_str($sQuery, $aQueryParams);

$sPageUri = !empty($aQueryParams['i']) ? $aQueryParams['i'] : false;
unset($aQueryParams['i']);

if (!$sPageUri) // page URI wasn't found
return false;

$aSeoParams = array('id', 'profile_id'); // supported SEO params which are transformed to SEO strings
$sSeoParamName = '';
$sSeoParamValue = '';
foreach ($aSeoParams as $k) {
if (empty($k) || empty($aQueryParams[$k]))
continue;
$sSeoParamName = $k;
$sSeoParamValue = $aQueryParams[$k];
unset($aQueryParams[$k]);
break; // only 1 SEO param will be transformed
}

$sSeoPageUri = $sPageUri;

if ($sSeoParamName && $sSeoParamValue) { // process page with SEO param
$sPageName = BxDolPageQuery::getPageObjectNameByURI($sPageUri);
$aPage = $sPageName ? BxDolPageQuery::getPageObject($sPageName) : false;
if ($aPage) {
$sModule = $aPage['module'];
if ('id' == $sSeoParamName) {
$oContentInfo = BxDolContentInfo::getObjectInstance($sModule);
$sSeoTitle = $oContentInfo ? $oContentInfo->getContentTitle($sSeoParamValue) : '';
if (!$sSeoTitle)
$sSeoTitle = base_convert(substr(md5($sSeoParamValue), -8), 16, 36);
}
elseif ('profile_id' == $sSeoParamName) {
$oProfile = BxDolProfile::getInstance($sSeoParamValue);
$sSeoTitle = $oProfile ? $oProfile->getDisplayName() : '';
}

$r = BxDolPageQuery::getSeoLink($sModule, $sPageUri, ['param_value' => $sSeoParamValue]);
if (!$r) {
$sUri = uriGenerate ($sSeoTitle, 'sys_seo_links', 'uri', '-', '-', ['module' => $sModule, 'page_uri' => $sPageUri]);
BxDolPageQuery::insertSeoLink($sModule, $sPageUri, $sSeoParamName, $sSeoParamValue, $sUri);
}
elseif ($r['param_name'] == $sSeoParamName) {
$sUri = $r['uri'];
}
else {
$sUri = false;
}

if ($sUri)
$sSeoPageUri .= '/' . $sUri;
else
$sSeoPageUri = false;
}
}

if (!$sSeoPageUri)
return false;

return $sPrefix . bx_append_url_params($sSeoPageUri, array_merge($aQueryParams, $aParams));
}

/**
* Display complete page
*/
Expand Down
24 changes: 24 additions & 0 deletions inc/classes/BxDolPageQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,30 @@ public function getPageBlockContentPlaceholder($iId)
$sQuery = $this->prepare("SELECT `id`, `module`, `template` FROM `sys_pages_content_placeholders` WHERE `id` = ?", $iId);
return $this->getRow($sQuery);
}

static public function getSeoLink($sModule, $sPageUri, $aCond = [])
{
$oDb = BxDolDb::getInstance();
$sWhere = " 1 ";
if ($aCond)
$sWhere = $oDb->arrayToSQL($aCond, " AND ");
return $oDb->getRow("SELECT `uri`, `param_name`, `param_value` FROM `sys_seo_links` WHERE " . $sWhere . " AND `module` = :module AND `page_uri` = :page_uri", [
'module' => $sModule,
'page_uri' => $sPageUri,
]);
}

static public function insertSeoLink($sModule, $sPageUri, $sSeoParamName, $sSeoParamValue, $sUri)
{
return BxDolDb::getInstance()->query("INSERT INTO `sys_seo_links` SET `module` = :module, `page_uri` = :page_uri, `param_name` = :param_name, `param_value` = :param_value, `uri` = :uri, `added` = :ts", [
'module' => $sModule,
'page_uri' => $sPageUri,
'param_name' => $sSeoParamName,
'param_value' => $sSeoParamValue,
'uri' => $sUri,
'ts' => time(),
]);
}
}

/** @} */
3 changes: 3 additions & 0 deletions inc/classes/BxDolPermalinks.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ function permalink($sLink, $aParams = array())

$sLink = $this->_fixUrl($sLink);

if ($sSeoLink = BxDolPage::transformSeoLink ($sLink, $sPrefix, $aParams))
return $sSeoLink;

foreach ($this->aPrefixesStandard as $sKey => $iLength) {

if (strncmp($sLink, $sKey, $iLength) !== 0)
Expand Down
34 changes: 16 additions & 18 deletions inc/utils.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -638,27 +638,24 @@ function clear_xss($val)

//--------------------------------------- friendly permalinks --------------------------------------//
//------------------------------------------- main functions ---------------------------------------//
function uriGenerate ($s, $sTable, $sField, $sEmpty = '-', $sDivider = '-')
function uriGenerate ($sValue, $sTable, $sField, $sEmpty = '-', $sDivider = '-', $aCond = [])
{
$s = uriFilter($s, $sEmpty, $sDivider);
if(uriCheckUniq($s, $sTable, $sField))
return $s;
$sValue = uriFilter($sValue, $sEmpty, $sDivider);
if(uriCheckUniq($sValue, $sTable, $sField, $aCond))
return $sValue;

// cut off redundant part
if(get_mb_len($s) > 240)
$s = get_mb_substr($s, 0, 240);

// try to add date
$s .= $sDivider . date('Y-m-d');
if(uriCheckUniq($s, $sTable, $sField))
return $s;
if(get_mb_len($sValue) > 240)
$sValue = get_mb_substr($sValue, 0, 240);

// try to add number
for($i = 0 ; $i < 999 ; ++$i)
if(uriCheckUniq($s . $sDivider . $i, $sTable, $sField))
return ($s . $sDivider . $i);
for($i = 0 ; $i < 999 ; ++$i) {
$iRnd = mt_rand(1000, 9999);
if(uriCheckUniq($sValue . $sDivider . $iRnd, $sTable, $sField, $aCond))
return ($sValue . $sDivider . $iRnd);
}

return rand(0, 999999999);
return rand(0, PHP_INT_MAX);
}

function uriFilter ($s, $sEmpty = '-', $sDivider = '-')
Expand All @@ -671,14 +668,15 @@ function uriFilter ($s, $sEmpty = '-', $sDivider = '-')
$s = get_mb_replace ('/([' . $sDivider . '^]+)/', $sDivider, $s);
$s = get_mb_replace ('/([' . $sDivider . ']+)$/', '', $s); // remove trailing dash
if (!$s) $s = $sEmpty;
return $s;
return mb_strtolower($s);
}

function uriCheckUniq ($s, $sTable, $sField)
function uriCheckUniq ($sValue, $sTable, $sField, $aCond = [])
{
$oDb = BxDolDb::getInstance();

$sSql = $oDb->prepare("SELECT 1 FROM `$sTable` WHERE `$sField`=? LIMIT 1", $s);
$sWhere = $aCond ? $oDb->arrayToSQL($aCond, ' AND ') : '1';
$sSql = $oDb->prepare("SELECT 1 FROM `$sTable` WHERE $sWhere AND `$sField`=? LIMIT 1", $sValue);
return !$oDb->query($sSql);
}

Expand Down
18 changes: 18 additions & 0 deletions install/sql/system.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5495,6 +5495,24 @@ INSERT INTO `sys_rewrite_rules` (`preg`, `service`, `active`) VALUES

-- --------------------------------------------------------

--
-- SEO Links
--
CREATE TABLE `sys_seo_links` (
`id` int(11) NOT NULL,
`module` varchar(32) NOT NULL,
`page_uri` varchar(255) NOT NULL,
`param_name` varchar(32) NOT NULL,
`param_value` varchar(32) NOT NULL,
`uri` varchar(255) NOT NULL,
`added` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `module_page_param` (`module`,`page_uri`,`param_value`),
UNIQUE KEY `module_page_uri` (`module`,`page_uri`,`uri`)
);

-- --------------------------------------------------------

--
-- Table structure for table `sys_preloader`
--
Expand Down
4 changes: 3 additions & 1 deletion r.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
}
}

BxDolTemplate::getInstance()->displayPageNotFound();
if (!BxDolPage::processSeoLink($sRequest)) {
BxDolTemplate::getInstance()->displayPageNotFound();
}

/** @} */
2 changes: 1 addition & 1 deletion template/scripts/BxBaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
class BxBaseConfig extends BxDol implements iBxDolSingleton
{
protected $_aConfig = array (
'bAllowUnicodeInPreg' => false, ///< allow unicode in regular expressions
'bAllowUnicodeInPreg' => true, ///< allow unicode in regular expressions
'aLessConfig' => array (
'bx-page-width' => '1000px',

Expand Down

0 comments on commit 9f48c30

Please sign in to comment.