00001 <?php
00002
00007 class oxSeoEncoder extends oxSuperCfg
00008 {
00009
00016 protected static $_aReservedWords = array('admin');
00017
00023 protected static $_aReservedEntryKeys = null;
00024
00030 protected static $_sSeparator = null;
00031
00037 protected $_iIdLength = 255;
00038
00044 protected static $_sPrefix = null;
00045
00051 protected $_sAddParams = null;
00052
00058 protected static $_aFixedCache = array();
00059
00065 protected static $_sCacheKey = null;
00066
00072 protected static $_aCache = array();
00073
00079 protected $_iMaxUrlLength = null;
00080
00089 public function addLanguageParam($sSeoUrl, $iLang)
00090 {
00091 $iLang = (int) $iLang;
00092 $iDefLang = (int) $this->getConfig()->getConfigParam('iDefSeoLang');
00093 $aLangIds = oxRegistry::getLang()->getLanguageIds();
00094
00095 if ($iLang != $iDefLang && isset($aLangIds[$iLang]) && getStr()->strpos($sSeoUrl, $aLangIds[$iLang] . '/') !== 0) {
00096 $sSeoUrl = $aLangIds[$iLang] . '/' . $sSeoUrl;
00097 }
00098
00099 return $sSeoUrl;
00100 }
00101
00114 protected function _processSeoUrl($sSeoUrl, $sObjectId = null, $iLang = null, $blExclude = false)
00115 {
00116 if (!$blExclude) {
00117 $sSeoUrl = $this->addLanguageParam($sSeoUrl, $iLang);
00118 }
00119
00120 return $this->_getUniqueSeoUrl($sSeoUrl, $sObjectId, $iLang);
00121 }
00122
00126 public function __construct()
00127 {
00128 $myConfig = $this->getConfig();
00129 if (!self::$_sSeparator) {
00130 $this->setSeparator($myConfig->getConfigParam('sSEOSeparator'));
00131 }
00132 if (!self::$_sPrefix) {
00133 $this->setPrefix($myConfig->getConfigParam('sSEOuprefix'));
00134 }
00135 $this->setReservedWords($myConfig->getConfigParam('aSEOReservedWords'));
00136 }
00137
00147 protected function _copyToHistory($sId, $iShopId, $iLang, $sType = null, $sNewId = null)
00148 {
00149 $oDb = oxDb::getDb();
00150 $sObjectid = $sNewId ? $oDb->quote($sNewId) : 'oxobjectid';
00151 $sType = $sType ? "oxtype =" . $oDb->quote($sType) . " and" : '';
00152 $iLang = (int) $iLang;
00153
00154
00155 $sSub = "select $sObjectid, MD5( LOWER( oxseourl ) ), oxshopid, oxlang, now() from oxseo
00156 where {$sType} oxobjectid = " . $oDb->quote($sId) . " and oxshopid = " . $oDb->quote($iShopId) . " and
00157 oxlang = {$iLang} and oxexpired = '1'";
00158 $sQ = "replace oxseohistory ( oxobjectid, oxident, oxshopid, oxlang, oxinsert ) {$sSub}";
00159 $oDb->execute($sQ);
00160 }
00161
00170 public function getDynamicObjectId($iShopId, $sStdUrl)
00171 {
00172 return $this->_getStaticObjectId($iShopId, $sStdUrl);
00173 }
00174
00184 protected function _getDynamicUri($sStdUrl, $sSeoUrl, $iLang)
00185 {
00186 $iShopId = $this->getConfig()->getShopId();
00187
00188 $sStdUrl = $this->_trimUrl($sStdUrl);
00189 $sObjectId = $this->getDynamicObjectId($iShopId, $sStdUrl);
00190 $sSeoUrl = $this->_prepareUri($this->addLanguageParam($sSeoUrl, $iLang), $iLang);
00191
00192
00193 $sOldSeoUrl = $this->_loadFromDb('dynamic', $sObjectId, $iLang);
00194 if ($sOldSeoUrl === $sSeoUrl) {
00195 $sSeoUrl = $sOldSeoUrl;
00196 } else {
00197
00198 if ($sOldSeoUrl) {
00199
00200 $this->_copyToHistory($sObjectId, $iShopId, $iLang, 'dynamic');
00201 }
00202
00203
00204 $sSeoUrl = $this->_processSeoUrl($sSeoUrl, $sObjectId, $iLang);
00205
00206
00207 $this->_saveToDb('dynamic', $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId);
00208 }
00209
00210 return $sSeoUrl;
00211 }
00212
00222 protected function _getFullUrl($sSeoUrl, $iLang = null, $blSsl = false)
00223 {
00224 if ($sSeoUrl) {
00225 $sFullUrl = ($blSsl ? $this->getConfig()->getSslShopUrl($iLang) : $this->getConfig()->getShopUrl($iLang, false)) . $sSeoUrl;
00226
00227 return oxRegistry::get("oxUtilsUrl")->processSeoUrl($sFullUrl);
00228 }
00229
00230 return false;
00231 }
00232
00242 protected function _getSeoIdent($sSeoUrl)
00243 {
00244 return md5(strtolower($sSeoUrl));
00245 }
00246
00256 protected function _getStaticUri($sStdUrl, $iShopId, $iLang)
00257 {
00258 $sStdUrl = $this->_trimUrl($sStdUrl, $iLang);
00259
00260 return $this->_loadFromDb('static', $this->_getStaticObjectId($iShopId, $sStdUrl), $iLang);
00261 }
00262
00268 protected function _getUrlExtension()
00269 {
00270 return;
00271 }
00272
00285 protected function _getUniqueSeoUrl($sSeoUrl, $sObjectId = null, $iObjectLang = null)
00286 {
00287 $sSeoUrl = $this->_prepareUri($sSeoUrl, $iObjectLang);
00288 $oStr = getStr();
00289 $sExt = '';
00290 if ($oStr->preg_match('/(\.html?|\/)$/i', $sSeoUrl, $aMatched)) {
00291 $sExt = $aMatched[0];
00292 }
00293 $sBaseSeoUrl = $sSeoUrl;
00294 if ($sExt && $oStr->substr($sSeoUrl, 0 - $oStr->strlen($sExt)) == $sExt) {
00295 $sBaseSeoUrl = $oStr->substr($sSeoUrl, 0, $oStr->strlen($sSeoUrl) - $oStr->strlen($sExt));
00296 }
00297
00298 $iShopId = $this->getConfig()->getShopId();
00299 $iCnt = 0;
00300 $sCheckSeoUrl = $this->_trimUrl($sSeoUrl);
00301 $sQ = "select 1 from oxseo where oxshopid = '{$iShopId}'";
00302
00303 $oDb = oxDb::getDb();
00304
00305 if ($sObjectId && isset($iObjectLang)) {
00306 $iObjectLang = (int) $iObjectLang;
00307 $sQ .= " and not (oxobjectid = " . $oDb->quote($sObjectId) . " and oxlang = $iObjectLang)";
00308 }
00309
00310 while ($oDb->getOne($sQ . " and oxident= " . $oDb->quote($this->_getSeoIdent($sCheckSeoUrl)))) {
00311 $sAdd = '';
00312 if (self::$_sPrefix) {
00313 $sAdd = self::$_sSeparator . self::$_sPrefix;
00314 }
00315 if ($iCnt) {
00316 $sAdd .= self::$_sSeparator . $iCnt;
00317 }
00318 ++$iCnt;
00319
00320 $sSeoUrl = $sBaseSeoUrl . $sAdd . $sExt;
00321 $sCheckSeoUrl = $this->_trimUrl($sSeoUrl);
00322 }
00323
00324 return $sSeoUrl;
00325 }
00326
00341 protected function _isFixed($sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00342 {
00343 if ($iShopId === null) {
00344 $iShopId = $this->getConfig()->getShopId();
00345 }
00346 $iLang = (int) $iLang;
00347
00348 if (!isset(self::$_aFixedCache[$sType][$sShopId][$sId][$iLang])) {
00349 $oDb = oxDb::getDb();
00350
00351 $sQ = "SELECT `oxfixed`
00352 FROM `oxseo`
00353 WHERE `oxtype` = " . $oDb->quote($sType) . "
00354 AND `oxobjectid` = " . $oDb->quote($sId) . "
00355 AND `oxshopid` = " . $oDb->quote($iShopId) . "
00356 AND `oxlang` = '{$iLang}'";
00357
00358 $sParams = $sParams ? $oDb->quote($sParams) : "''";
00359 if ($sParams && $blStrictParamsCheck) {
00360 $sQ .= " AND `oxparams` = {$sParams}";
00361 } else {
00362 $sQ .= " ORDER BY `oxparams` ASC";
00363 }
00364 $sQ .= " LIMIT 1";
00365
00366 self::$_aFixedCache[$sType][$sShopId][$sId][$iLang] = (bool) $oDb->getOne($sQ);
00367 }
00368
00369 return self::$_aFixedCache[$sType][$sShopId][$sId][$iLang];
00370 }
00371
00382 protected function _getCacheKey($sType, $iLang = null, $iShopId = null, $sParams = null)
00383 {
00384 $blAdmin = $this->isAdmin();
00385 if (!$blAdmin && $sType !== "oxarticle") {
00386 return $sType . ((int) $iLang) . ((int) $iShopId) . "seo";
00387 }
00388
00389
00390 if (self::$_sCacheKey === null) {
00391 self::$_sCacheKey = false;
00392 if (!$blAdmin && ($oView = $this->getConfig()->getActiveView())) {
00393 self::$_sCacheKey = md5($oView->getViewId()) . "seo";
00394 }
00395 }
00396
00397 return self::$_sCacheKey;
00398 }
00399
00411 protected function _loadFromCache($sCacheIdent, $sType, $iLang = null, $iShopId = null, $sParams = null)
00412 {
00413 if (!$this->getConfig()->getConfigParam('blEnableSeoCache')) {
00414 return false;
00415 }
00416
00417 startProfile("seoencoder_loadFromCache");
00418
00419 $sCacheKey = $this->_getCacheKey($sType, $iLang, $iShopId, $sParams);
00420 $sCache = false;
00421
00422 if ($sCacheKey && !isset(self::$_aCache[$sCacheKey])) {
00423 self::$_aCache[$sCacheKey] = oxRegistry::getUtils()->fromFileCache($sCacheKey);
00424 }
00425
00426 if (isset(self::$_aCache[$sCacheKey]) && isset(self::$_aCache[$sCacheKey][$sCacheIdent])) {
00427 $sCache = self::$_aCache[$sCacheKey][$sCacheIdent];
00428 }
00429
00430 stopProfile("seoencoder_loadFromCache");
00431
00432 return $sCache;
00433 }
00434
00447 protected function _saveInCache($sCacheIdent, $sCache, $sType, $iLang = null, $iShopId = null, $sParams = null)
00448 {
00449 if (!$this->getConfig()->getConfigParam('blEnableSeoCache')) {
00450 return false;
00451 }
00452
00453 startProfile("seoencoder_saveInCache");
00454
00455 $blSaved = false;
00456 if ($sCache && ($sCacheKey = $this->_getCacheKey($sType, $iLang, $iShopId, $sParams)) !== false) {
00457 self::$_aCache[$sCacheKey][$sCacheIdent] = $sCache;
00458 $blSaved = oxRegistry::getUtils()->toFileCache($sCacheKey, self::$_aCache[$sCacheKey]);
00459 }
00460
00461 stopProfile("seoencoder_saveInCache");
00462
00463 return $blSaved;
00464 }
00465
00481 protected function _loadFromDb($sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00482 {
00483
00484 if ($iShopId === null) {
00485 $iShopId = $this->getConfig()->getShopId();
00486 }
00487
00488 $iLang = (int) $iLang;
00489 $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
00490
00491 $sQ = "
00492 SELECT
00493 `oxfixed`,
00494 `oxseourl`,
00495 `oxexpired`,
00496 `oxtype`
00497 FROM `oxseo`
00498 WHERE `oxtype` = " . $oDb->quote($sType) . "
00499 AND `oxobjectid` = " . $oDb->quote($sId) . "
00500 AND `oxshopid` = " . $oDb->quote($iShopId) . "
00501 AND `oxlang` = '{$iLang}'";
00502
00503 $sParams = $sParams ? $sParams : '';
00504 if ($sParams && $blStrictParamsCheck) {
00505 $sQ .= " AND `oxparams` = '{$sParams}'";
00506 } else {
00507 $sQ .= " ORDER BY `oxparams` ASC";
00508 }
00509 $sQ .= " LIMIT 1";
00510
00511
00512
00513 $sIdent = md5($sQ);
00514
00515
00516 if (($sSeoUrl = $this->_loadFromCache($sIdent, $sType, $iLang, $iShopId, $sParams)) === false) {
00517 $oRs = $oDb->select($sQ);
00518
00519 if ($oRs && $oRs->recordCount() > 0 && !$oRs->EOF) {
00520
00521 if ($oRs->fields['oxexpired'] && ($oRs->fields['oxtype'] == 'static' || $oRs->fields['oxtype'] == 'dynamic')) {
00522
00523 $this->_copyToHistory($sId, $iShopId, $iLang);
00524 $oDb->execute("update oxseo set oxexpired = 0 where oxobjectid = " . $oDb->quote($sId) . " and oxlang = '{$iLang}'");
00525 $sSeoUrl = $oRs->fields['oxseourl'];
00526 } elseif (!$oRs->fields['oxexpired'] || $oRs->fields['oxfixed']) {
00527
00528 $sSeoUrl = $oRs->fields['oxseourl'];
00529 }
00530
00531
00532 $this->_saveInCache($sIdent, $sSeoUrl, $sType, $iLang, $iShopId, $sParams);
00533 }
00534 }
00535
00536 return $sSeoUrl;
00537 }
00538
00545 protected function _getReservedEntryKeys()
00546 {
00547 if (!isset(self::$_aReservedEntryKeys) || !is_array(self::$_aReservedEntryKeys)) {
00548 $sDir = getShopBasePath();
00549 self::$_aReservedEntryKeys = array_map('preg_quote', self::$_aReservedWords, array('#'));
00550 $oStr = getStr();
00551 foreach (glob("$sDir/*") as $sFile) {
00552 if ($oStr->preg_match('/^(.+)\.php[0-9]*$/i', basename($sFile), $aMatches)) {
00553 self::$_aReservedEntryKeys[] = preg_quote($aMatches[0], '#');
00554 self::$_aReservedEntryKeys[] = preg_quote($aMatches[1], '#');
00555 } elseif (is_dir($sFile)) {
00556 self::$_aReservedEntryKeys[] = preg_quote(basename($sFile), '#');
00557 }
00558 }
00559 self::$_aReservedEntryKeys = array_unique(self::$_aReservedEntryKeys);
00560 }
00561
00562 return self::$_aReservedEntryKeys;
00563 }
00564
00573 protected function _prepareUri($sUri, $iLang = false)
00574 {
00575
00576 $sUri = $this->encodeString($sUri, true, $iLang);
00577
00578
00579 $oStr = getStr();
00580 $sUri = $oStr->strip_tags($sUri);
00581
00582
00583 $sExt = $this->_getUrlExtension();
00584 if ($sExt === null) {
00585 $aMatched = array();
00586 if ($oStr->preg_match('/(\.html?|\/)$/i', $sUri, $aMatched)) {
00587 $sExt = $aMatched[0];
00588 } else {
00589 $sExt = '/';
00590 }
00591 }
00592 if ($sExt && $oStr->substr($sUri, 0 - $oStr->strlen($sExt)) == $sExt) {
00593 $sUri = $oStr->substr($sUri, 0, $oStr->strlen($sUri) - $oStr->strlen($sExt));
00594 }
00595
00596
00597
00598 $sQuotedPrefix = preg_quote(self::$_sSeparator . self::$_sPrefix, '/');
00599 if (phpversion() < '5.3') {
00600 $sQuotedPrefix = str_replace('-', '\-', $sQuotedPrefix);
00601 }
00602 $sRegExp = '/[^A-Za-z0-9' . $sQuotedPrefix . '\/]+/';
00603 $sUri = $oStr->preg_replace(array("/\W*\/\W*/", $sRegExp), array("/", self::$_sSeparator), $sUri);
00604
00605
00606 if (!$sUri && self::$_sPrefix) {
00607 $sUri = $this->_prepareUri(self::$_sPrefix, $iLang);
00608 }
00609
00610 $sAdd = '';
00611 if ('/' != self::$_sSeparator) {
00612 $sAdd = self::$_sSeparator . self::$_sPrefix;
00613 $sUri = trim($sUri, self::$_sSeparator);
00614 } else {
00615 $sAdd = '_' . self::$_sPrefix;
00616 }
00617
00618
00619 $sUri .= $sExt;
00620
00621
00622 $sUri = $oStr->preg_replace("#^(/*)(" . implode('|', $this->_getReservedEntryKeys()) . ")(/|$)#i", "\$1\$2$sAdd\$3", $sUri);
00623
00624
00625
00626
00627 if (phpversion() < '5.3') {
00628 $sQuotedSeparator = str_replace('-', '\-', $sQuotedSeparator);
00629 }
00630
00631 return $oStr->preg_replace(
00632 array('|//+|', '/' . $sQuotedSeparator . $sQuotedSeparator . '+/'),
00633 array('/', self::$_sSeparator), $sUri
00634 );
00635 }
00636
00637
00647 protected function _prepareTitle($sTitle, $blSkipTruncate = false, $iLang = false)
00648 {
00649 $sTitle = $this->encodeString($sTitle, true, $iLang);
00650 $sSep = self::$_sSeparator;
00651 if (!$sSep || ('/' == $sSep)) {
00652 $sSep = '_';
00653 }
00654
00655 $sRegExp = '/[^A-Za-z0-9\/' . preg_quote(self::$_sPrefix, '/') . preg_quote($sSep, '/') . ']+/';
00656 $sTitle = preg_replace(array("#/+#", $sRegExp, "# +#", "#(" . preg_quote($sSep, '/') . ")+#"), $sSep, $sTitle);
00657
00658 $oStr = getStr();
00659
00660 if (!$blSkipTruncate && $oStr->strlen($sTitle) > $this->_iIdLength) {
00661 $iFirstSpace = $oStr->strpos($sTitle, $sSep, $this->_iIdLength);
00662 if ($iFirstSpace !== false) {
00663 $sTitle = $oStr->substr($sTitle, 0, $iFirstSpace);
00664 }
00665 }
00666
00667 $sTitle = trim($sTitle, $sSep);
00668
00669 if (!$sTitle) {
00670 return self::$_sPrefix;
00671 }
00672
00673
00674 return $sTitle;
00675 }
00676
00677
00694 protected function _saveToDb($sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId = null, $blFixed = null, $sParams = null)
00695 {
00696 $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
00697 if ($iShopId === null) {
00698 $iShopId = $this->getConfig()->getShopId();
00699 }
00700
00701 $iLang = (int) $iLang;
00702
00703 $sStdUrl = $this->_trimUrl($sStdUrl);
00704 $sSeoUrl = $this->_trimUrl($sSeoUrl);
00705 $sIdent = $this->_getSeoIdent($sSeoUrl);
00706
00707
00708 $sQtedObjectId = $oDb->quote($sObjectId);
00709 $iQtedShopId = $oDb->quote($iShopId);
00710 $sQtedType = $oDb->quote($sType);
00711 $sQtedSeoUrl = $oDb->quote($sSeoUrl);
00712 $sQtedStdUrl = $oDb->quote($sStdUrl);
00713 $sQtedParams = $oDb->quote($sParams);
00714 $sQtedIdent = $oDb->quote($sIdent);
00715
00716
00717 $sQ = "select oxfixed, oxexpired, ( oxstdurl like {$sQtedStdUrl} ) as samestdurl,
00718 oxseourl like {$sQtedSeoUrl} as sameseourl from oxseo where oxtype = {$sQtedType} and
00719 oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId} and oxlang = {$iLang} ";
00720
00721 $sQ .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00722 $sQ .= "limit 1";
00723 $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
00724 $oRs = $oDb->select($sQ);
00725 if ($oRs && $oRs->recordCount() > 0 && !$oRs->EOF) {
00726 if ($oRs->fields['samestdurl'] && $oRs->fields['sameseourl'] && $oRs->fields['oxexpired']) {
00727
00728 $sFixed = isset($blFixed) ? ", oxfixed = " . ((int) $blFixed) . " " : '';
00729
00730 $sSql = "update oxseo set oxexpired = 0 {$sFixed} where oxtype = {$sQtedType} and
00731 oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId} and oxlang = {$iLang} ";
00732 $sSql .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00733 $sSql .= " limit 1";
00734
00735 return $oDb->execute($sSql);
00736 } elseif ($oRs->fields['oxexpired']) {
00737
00738 $this->_copyToHistory($sObjectId, $iShopId, $iLang, $sType);
00739 }
00740 }
00741
00742
00743 $sParams = $sParams ? $oDb->quote($sParams) : '""';
00744 $blFixed = (int) $blFixed;
00745
00746 $sQ = "insert into oxseo
00747 (oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype, oxfixed, oxexpired, oxparams)
00748 values
00749 ( {$sQtedObjectId}, {$sQtedIdent}, {$iQtedShopId}, {$iLang}, {$sQtedStdUrl}, {$sQtedSeoUrl}, {$sQtedType}, '$blFixed', '0', {$sParams} )
00750 on duplicate key update
00751 oxident = {$sQtedIdent}, oxstdurl = {$sQtedStdUrl}, oxseourl = {$sQtedSeoUrl}, oxfixed = '$blFixed', oxexpired = '0'";
00752
00753 return $oDb->execute($sQ);
00754 }
00755
00766 protected function _trimUrl($sUrl, $iLang = null)
00767 {
00768 $myConfig = $this->getConfig();
00769 $oStr = getStr();
00770 $sUrl = str_replace(array($myConfig->getShopUrl($iLang, false), $myConfig->getSslShopUrl($iLang)), '', $sUrl);
00771 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)(force_)?(admin_)?sid=[a-z0-9\.]+&?(amp;)?/i', '\1', $sUrl);
00772 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)shp=[0-9]+&?(amp;)?/i', '\1', $sUrl);
00773 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)lang=[0-9]+&?(amp;)?/i', '\1', $sUrl);
00774 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)cur=[0-9]+&?(amp;)?/i', '\1', $sUrl);
00775 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)stoken=[a-z0-9]+&?(amp;)?/i', '\1', $sUrl);
00776 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)&(amp;)?/i', '\1', $sUrl);
00777 $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)+$/i', '', $sUrl);
00778 $sUrl = trim($sUrl);
00779
00780
00781 $iLength = $this->_getMaxUrlLength();
00782 if ($oStr->strlen($sUrl) > $iLength) {
00783 $sUrl = $oStr->substr($sUrl, 0, $iLength);
00784 }
00785
00786 return $sUrl;
00787 }
00788
00794 protected function _getMaxUrlLength()
00795 {
00796 if ($this->_iMaxUrlLength === null) {
00797
00798 $this->_iMaxUrlLength = $this->getConfig()->getConfigParam("iMaxSeoUrlLength");
00799 if (!$this->_iMaxUrlLength) {
00800 $this->_iMaxUrlLength = 2048;
00801 }
00802 }
00803
00804 return $this->_iMaxUrlLength;
00805 }
00806
00816 public function encodeString($sString, $blReplaceChars = true, $iLang = false)
00817 {
00818
00819 $sString = getStr()->html_entity_decode($sString);
00820
00821 if ($blReplaceChars) {
00822 if ($iLang === false || !is_numeric($iLang)) {
00823 $iLang = oxRegistry::getLang()->getEditLanguage();
00824 }
00825
00826 if ($aReplaceChars = oxRegistry::getLang()->getSeoReplaceChars($iLang)) {
00827 $sString = str_replace(array_keys($aReplaceChars), array_values($aReplaceChars), $sString);
00828 }
00829 }
00830
00831
00832
00833 $aReplaceWhat = array('&', '"', ''', '<', '>');
00834
00835 return str_replace($aReplaceWhat, '', $sString);
00836 }
00837
00843 public function setSeparator($sSeparator = null)
00844 {
00845 self::$_sSeparator = $sSeparator;
00846 if (!self::$_sSeparator) {
00847 self::$_sSeparator = '-';
00848 }
00849 }
00850
00856 public function setPrefix($sPrefix)
00857 {
00858 if ($sPrefix) {
00859 self::$_sPrefix = $sPrefix;
00860 } else {
00861 self::$_sPrefix = 'oxid';
00862 }
00863 }
00864
00870 public function setIdLength($iIdlength = null)
00871 {
00872 if (isset($iIdlength)) {
00873 $this->_iIdLength = $iIdlength;
00874 }
00875 }
00876
00883 public function setReservedWords($aReservedWords)
00884 {
00885 self::$_aReservedWords = array_merge(self::$_aReservedWords, $aReservedWords);
00886 }
00887
00888
00898 public function markAsExpired($sId, $iShopId = null, $iExpStat = 1, $iLang = null, $sParams = null)
00899 {
00900 $oDb = oxDb::getDb();
00901 $sWhere = $sId ? "where oxobjectid = " . $oDb->quote($sId) : '';
00902 $sWhere .= isset($iShopId) ? ($sWhere ? " and oxshopid = " . $oDb->quote($iShopId) : "where oxshopid = " . $oDb->quote($iShopId)) : '';
00903 $sWhere .= $iLang ? ($sWhere ? " and oxlang = '{$iLang}'" : "where oxlang = '{$iLang}'") : '';
00904 $sWhere .= $sParams ? ($sWhere ? " and {$sParams}" : "where {$sParams}") : '';
00905
00906 $sQ = "update oxseo set oxexpired = " . $oDb->quote($iExpStat) . " $sWhere ";
00907 $oDb->execute($sQ);
00908 }
00909
00923 protected function _getPageUri($oObject, $sType, $sStdUrl, $sSeoUrl, $sParams, $iLang = null, $blFixed = false)
00924 {
00925 if (!isset($iLang)) {
00926 $iLang = $oObject->getLanguage();
00927 }
00928 $iShopId = $this->getConfig()->getShopId();
00929
00930
00931 $sOldSeoUrl = $this->_loadFromDb($sType, $oObject->getId(), $iLang, $iShopId, $sParams);
00932 if (!$sOldSeoUrl) {
00933
00934 $sSeoUrl = $this->_processSeoUrl($sSeoUrl, $oObject->getId(), $iLang);
00935 $this->_saveToDb($sType, $oObject->getId(), $sStdUrl, $sSeoUrl, $iLang, $iShopId, (int) $blFixed, $sParams);
00936 } else {
00937
00938 $sSeoUrl = $sOldSeoUrl;
00939 }
00940
00941 return $sSeoUrl;
00942 }
00943
00952 protected function _getStaticObjectId($iShopId, $sStdUrl)
00953 {
00954 return md5(strtolower($iShopId . $this->_trimUrl($sStdUrl)));
00955 }
00956
00966 public function encodeStaticUrls($aStaticUrl, $iShopId, $iLang)
00967 {
00968 $oDb = oxDb::getDb();
00969 $sValues = '';
00970 $sOldObjectId = null;
00971
00972
00973 $sStdUrl = $this->_trimUrl(trim($aStaticUrl['oxseo__oxstdurl']));
00974 $sObjectId = $aStaticUrl['oxseo__oxobjectid'];
00975
00976 if (!$sObjectId || $sObjectId == '-1') {
00977 $sObjectId = $this->_getStaticObjectId($iShopId, $sStdUrl);
00978 } else {
00979
00980 $sOldObjectId = $sObjectId;
00981
00982
00983 if ($this->_getStaticObjectId($iShopId, $sStdUrl) != $sObjectId) {
00984 $sObjectId = $this->_getStaticObjectId($iShopId, $sStdUrl);
00985 }
00986 }
00987
00988 foreach ($aStaticUrl['oxseo__oxseourl'] as $iLang => $sSeoUrl) {
00989
00990 $iLang = (int) $iLang;
00991
00992
00993 $sSeoUrl = $this->_trimUrl($sSeoUrl);
00994 if ($sSeoUrl) {
00995 $sSeoUrl = $this->_processSeoUrl($sSeoUrl, $sObjectId, $iLang);
00996 }
00997
00998
00999 if ($sOldObjectId) {
01000
01001 if (!$oDb->getOne("select (" . $oDb->quote($sSeoUrl) . " like oxseourl) & (" . $oDb->quote($sStdUrl) . " like oxstdurl) from oxseo where oxobjectid = " . $oDb->quote($sOldObjectId) . " and oxshopid = '{$iShopId}' and oxlang = '{$iLang}' ", false, false)) {
01002 $this->_copyToHistory($sOldObjectId, $iShopId, $iLang, 'static', $sObjectId);
01003 }
01004 }
01005
01006 if (!$sSeoUrl || !$sStdUrl) {
01007 continue;
01008 }
01009
01010 $sIdent = $this->_getSeoIdent($sSeoUrl);
01011
01012 if ($sValues) {
01013 $sValues .= ', ';
01014 }
01015
01016 $sValues .= "( " . $oDb->quote($sObjectId) . ", " . $oDb->quote($sIdent) . ", " . $oDb->quote($iShopId) . ", '{$iLang}', " . $oDb->quote($sStdUrl) . ", " . $oDb->quote($sSeoUrl) . ", 'static' )";
01017 }
01018
01019
01020 if ($sOldObjectId) {
01021 $oDb->execute("delete from oxseo where oxobjectid in ( " . $oDb->quote($sOldObjectId) . ", " . $oDb->quote($sObjectId) . " )");
01022 }
01023
01024
01025 if ($sValues) {
01026
01027 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype ) values {$sValues} ";
01028 $oDb->execute($sQ);
01029 }
01030
01031 return $sObjectId;
01032 }
01033
01039 public function copyStaticUrls($iShopId)
01040 {
01041 $iBaseShopId = $this->getConfig()->getBaseShopId();
01042 if ($iShopId != $iBaseShopId) {
01043 $oDb = oxDb::getDb();
01044 foreach (array_keys(oxRegistry::getLang()->getLanguageIds()) as $iLang) {
01045 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype )
01046 select MD5( LOWER( CONCAT( " . $oDb->quote($iShopId) . ", oxstdurl ) ) ), MD5( LOWER( oxseourl ) ),
01047 " . $oDb->quote($iShopId) . ", oxlang, oxstdurl, oxseourl, oxtype from oxseo where oxshopid = '{$iBaseShopId}' and oxtype = 'static' and oxlang='$iLang' ";
01048 $oDb->execute($sQ);
01049 }
01050 }
01051 }
01052
01062 public function getStaticUrl($sStdUrl, $iLang = null, $iShopId = null)
01063 {
01064 if (!isset($iShopId)) {
01065 $iShopId = $this->getConfig()->getShopId();
01066 }
01067 if (!isset($iLang)) {
01068 $iLang = oxRegistry::getLang()->getEditLanguage();
01069 }
01070
01071 if (isset($this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId])) {
01072 return $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId];
01073 }
01074
01075 $sFullUrl = '';
01076 if (($sSeoUrl = $this->_getStaticUri($sStdUrl, $iShopId, $iLang))) {
01077 $sFullUrl = $this->_getFullUrl($sSeoUrl, $iLang, strpos($sStdUrl, "https:") === 0);
01078 }
01079
01080
01081 $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId] = $sFullUrl;
01082
01083 return $sFullUrl;
01084 }
01085
01102 public function addSeoEntry($sObjectId, $iShopId, $iLang, $sStdUrl, $sSeoUrl, $sType, $blFixed = 1, $sKeywords = '', $sDescription = '', $sParams = '', $blExclude = false, $sAltObjectId = null)
01103 {
01104 $sSeoUrl = $this->_processSeoUrl($this->_trimUrl($sSeoUrl ? $sSeoUrl : $this->_getAltUri($sAltObjectId ? $sAltObjectId : $sObjectId, $iLang)), $sObjectId, $iLang, $blExclude);
01105 if ($this->_saveToDb($sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId, $blFixed, $sParams)) {
01106
01107 $oDb = oxDb::getDb();
01108
01109
01110 $sQtedObjectId = $oDb->quote($sAltObjectId ? $sAltObjectId : $sObjectId);
01111 $iQtedShopId = $oDb->quote($iShopId);
01112
01113 $oStr = getStr();
01114 if ($sKeywords !== false) {
01115 $sKeywords = $oDb->quote($oStr->htmlspecialchars($this->encodeString($oStr->strip_tags($sKeywords), false, $iLang)));
01116 }
01117
01118 if ($sDescription !== false) {
01119 $sDescription = $oDb->quote($oStr->htmlspecialchars($oStr->strip_tags($sDescription)));
01120 }
01121
01122 $sQ = "insert into oxobject2seodata
01123 ( oxobjectid, oxshopid, oxlang, oxkeywords, oxdescription )
01124 values
01125 ( {$sQtedObjectId}, {$iQtedShopId}, {$iLang}, " . ($sKeywords ? $sKeywords : "''") . ", " . ($sDescription ? $sDescription : "''") . " )
01126 on duplicate key update
01127 oxkeywords = " . ($sKeywords ? $sKeywords : "oxkeywords") . ", oxdescription = " . ($sDescription ? $sDescription : "oxdescription");
01128 $oDb->execute($sQ);
01129 }
01130 }
01131
01138 protected function _getAltUri($sObjectId, $iLang)
01139 {
01140 }
01141
01150 public function deleteSeoEntry($sObjectId, $iShopId, $iLang, $sType)
01151 {
01152 $oDb = oxDb::getDb();
01153 $sQ = "delete from oxseo where oxobjectid = " . $oDb->quote($sObjectId) . " and oxshopid = " . $oDb->quote($iShopId) . " and oxlang = " . $oDb->quote($iLang) . " and oxtype = " . $oDb->quote($sType) . " ";
01154 $oDb->execute($sQ);
01155 }
01156
01167 public function getMetaData($sObjectId, $sMetaType, $iShopId = null, $iLang = null)
01168 {
01169 $oDb = oxDb::getDb();
01170
01171 $iShopId = (!isset($iShopId)) ? $this->getConfig()->getShopId() : $iShopId;
01172 $iLang = (!isset($iLang)) ? oxRegistry::getLang()->getObjectTplLanguage() : ((int) $iLang);
01173
01174 return $oDb->getOne("select {$sMetaType} from oxobject2seodata where oxobjectid = " . $oDb->quote($sObjectId) . " and oxshopid = " . $oDb->quote($iShopId) . " and oxlang = '{$iLang}'");
01175 }
01176
01190 public function getDynamicUrl($sStdUrl, $sSeoUrl, $iLang)
01191 {
01192 startProfile("getDynamicUrl");
01193 $sDynUrl = $this->_getFullUrl($this->_getDynamicUri($sStdUrl, $sSeoUrl, $iLang), $iLang, strpos($sStdUrl, "https:") === 0);
01194 stopProfile("getDynamicUrl");
01195
01196 return $sDynUrl;
01197 }
01198
01207 public function fetchSeoUrl($sStdUrl, $iLanguage = null)
01208 {
01209 $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
01210 $iLanguage = isset($iLanguage) ? ((int) $iLanguage) : oxRegistry::getLang()->getBaseLanguage();
01211 $sSeoUrl = false;
01212
01213 $sShopId = $this->getConfig()->getShopId();
01214
01215 $sQ = "SELECT `oxseourl`, `oxlang` FROM `oxseo` WHERE `oxstdurl` = " . $oDb->quote($sStdUrl) . " AND `oxlang` = '$iLanguage' AND `oxshopid` = '$sShopId' LIMIT 1";
01216
01217 $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
01218 $oRs = $oDb->select($sQ);
01219
01220 if (!$oRs->EOF) {
01221 $sSeoUrl = $oRs->fields['oxseourl'];
01222 }
01223
01224 return $sSeoUrl;
01225 }
01226 }