00001 <?php
00002
00007 class oxSeoEncoder extends oxSuperCfg
00008 {
00015 protected static $_aReservedWords = array( 'admin' );
00016
00022 protected static $_aReservedEntryKeys = null;
00023
00029 protected static $_sSeparator = null;
00030
00036 protected $_iIdLength = 255;
00037
00043 protected static $_sPrefix = null;
00044
00050 protected $_sAddParams = null;
00051
00057 protected static $_instance = null;
00058
00064 protected static $_aFixedCache = array();
00065
00070 protected static $_sCacheKey = null;
00071
00076 protected static $_aCache = null;
00077
00083 public static function getInstance()
00084 {
00085 if ( defined( 'OXID_PHP_UNIT' ) ) {
00086 self::$_instance = modInstances::getMod( __CLASS__ );
00087 }
00088
00089 if (!self::$_instance) {
00090 self::$_instance = oxNew("oxSeoEncoder");
00091 if ( defined( 'OXID_PHP_UNIT' ) ) {
00092 modInstances::addMod( __CLASS__, self::$_instance);
00093 }
00094 }
00095
00096 return self::$_instance;
00097
00098 }
00099
00108 public function addLanguageParam( $sSeoUrl, $iLang )
00109 {
00110 $iLang = (int) $iLang;
00111 $iDefLang = (int) $this->getConfig()->getConfigParam( 'iDefSeoLang' );
00112 $aLangIds = oxLang::getInstance()->getLanguageIds();
00113
00114 if ( $iLang != $iDefLang && isset( $aLangIds[$iLang] ) && getStr()->strpos( $sSeoUrl, $aLangIds[$iLang] . '/' ) !== 0 ) {
00115 $sSeoUrl = $aLangIds[$iLang] . '/'.$sSeoUrl;
00116 }
00117
00118 return $sSeoUrl;
00119 }
00120
00133 protected function _processSeoUrl( $sSeoUrl, $sObjectId = null, $iLang = null, $blExclude = false )
00134 {
00135 if (!$blExclude) {
00136 $sSeoUrl = $this->addLanguageParam( $sSeoUrl, $iLang );
00137 }
00138 return $this->_getUniqueSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00139 }
00140
00144 public function __construct()
00145 {
00146 $myConfig = $this->getConfig();
00147 if (!self::$_sSeparator) {
00148 $this->setSeparator( $myConfig->getConfigParam( 'sSEOSeparator' ) );
00149 }
00150 if (!self::$_sPrefix) {
00151 $this->setPrefix( $myConfig->getConfigParam( 'sSEOuprefix' ) );
00152 }
00153 $this->setReservedWords( $myConfig->getConfigParam( 'aSEOReservedWords' ) );
00154 }
00155
00167 protected function _copyToHistory( $sId, $iShopId, $iLang, $sType = null, $sNewId = null )
00168 {
00169 $oDb = oxDb::getDb();
00170 $sObjectid = $sNewId?$oDb->quote( $sNewId ):'oxobjectid';
00171 $sType = $sType?"oxtype =".$oDb->quote( $sType )." and":'';
00172 $iLang = (int) $iLang;
00173
00174
00175 $sSub = "select $sObjectid, MD5( LOWER( oxseourl ) ), oxshopid, oxlang, now() from oxseo
00176 where {$sType} oxobjectid = ".$oDb->quote( $sId )." and oxshopid = ".$oDb->quote( $iShopId )." and
00177 oxlang = {$iLang} and oxexpired = '1'";
00178 $sQ = "replace oxseohistory ( oxobjectid, oxident, oxshopid, oxlang, oxinsert ) {$sSub}";
00179 $oDb->execute( $sQ );
00180 }
00181
00190 public function getDynamicObjectId( $iShopId, $sStdUrl )
00191 {
00192 return $this->_getStaticObjectId( $iShopId, $sStdUrl );
00193 }
00194
00204 protected function _getDynamicUri( $sStdUrl, $sSeoUrl, $iLang )
00205 {
00206 $iShopId = $this->getConfig()->getShopId();
00207
00208 $sStdUrl = $this->_trimUrl( $sStdUrl );
00209 $sObjectId = $this->getDynamicObjectId( $iShopId, $sStdUrl );
00210 $sSeoUrl = $this->_prepareUri( $this->addLanguageParam( $sSeoUrl, $iLang ) );
00211
00212
00213 $sOldSeoUrl = $this->_loadFromDb( 'dynamic', $sObjectId, $iLang );
00214 if ( $sOldSeoUrl === $sSeoUrl ) {
00215 $sSeoUrl = $sOldSeoUrl;
00216 } else {
00217
00218 if ( $sOldSeoUrl ) {
00219
00220 $this->_copyToHistory( $sObjectId, $iShopId, $iLang, 'dynamic' );
00221 }
00222
00223
00224 $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00225
00226
00227 $this->_saveToDb( 'dynamic', $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId );
00228 }
00229
00230 return $sSeoUrl;
00231 }
00232
00242 protected function _getFullUrl( $sSeoUrl, $iLang = null, $blSsl = false )
00243 {
00244 if ( $sSeoUrl ) {
00245 $sFullUrl = ( $blSsl ? $this->getConfig()->getSslShopUrl( $iLang ) : $this->getConfig()->getShopUrl( $iLang, false ) ) . $sSeoUrl;
00246 return oxUtilsUrl::getInstance()->processSeoUrl( $sFullUrl );
00247 }
00248 return false;
00249 }
00250
00260 protected function _getSeoIdent( $sSeoUrl )
00261 {
00262 return md5( strtolower( $sSeoUrl ) );
00263 }
00264
00274 protected function _getStaticUri( $sStdUrl, $iShopId, $iLang )
00275 {
00276 $sStdUrl = $this->_trimUrl( $sStdUrl, $iLang );
00277 return $this->_loadFromDb( 'static', $this->_getStaticObjectId( $iShopId, $sStdUrl ), $iLang );
00278 }
00279
00285 protected function _getUrlExtension()
00286 {
00287 return;
00288 }
00289
00302 protected function _getUniqueSeoUrl( $sSeoUrl, $sObjectId = null, $iObjectLang = null )
00303 {
00304 $sSeoUrl = $this->_prepareUri( $sSeoUrl );
00305 $oStr = getStr();
00306 $sExt = '';
00307 if ( $oStr->preg_match( '/(\.html?|\/)$/i', $sSeoUrl, $aMatched ) ) {
00308 $sExt = $aMatched[0];
00309 }
00310 $sBaseSeoUrl = $sSeoUrl;
00311 if ( $sExt && $oStr->substr( $sSeoUrl, 0 - $oStr->strlen( $sExt ) ) == $sExt ) {
00312 $sBaseSeoUrl = $oStr->substr( $sSeoUrl, 0, $oStr->strlen( $sSeoUrl ) - $oStr->strlen( $sExt ) );
00313 }
00314
00315 $oDb = oxDb::getDb();
00316 $iShopId = $this->getConfig()->getShopId();
00317 $iCnt = 0;
00318 $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl );
00319 $sQ = "select 1 from oxseo where oxshopid = '{$iShopId}'";
00320
00321
00322 if ( $sObjectId && isset($iObjectLang) ) {
00323 $iObjectLang = (int) $iObjectLang;
00324 $sQ .= " and not (oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxlang = $iObjectLang)";
00325 }
00326
00327 while ( $oDb->getOne( $sQ ." and oxident= " . $oDb->quote( $this->_getSeoIdent( $sCheckSeoUrl ) ) ) ) {
00328 $sAdd = '';
00329 if ( self::$_sPrefix ) {
00330 $sAdd = self::$_sSeparator . self::$_sPrefix;
00331 }
00332 if ( $iCnt ) {
00333 $sAdd .= self::$_sSeparator . $iCnt;
00334 }
00335 ++$iCnt;
00336
00337 $sSeoUrl = $sBaseSeoUrl . $sAdd . $sExt;
00338 $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl );
00339 }
00340 return $sSeoUrl;
00341 }
00342
00357 protected function _isFixed( $sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00358 {
00359 if ( $iShopId === null ) {
00360 $iShopId = $this->getConfig()->getShopId();
00361 }
00362 $iLang = (int) $iLang;
00363
00364 if ( !isset( self::$_aFixedCache[$sType][$sShopId][$sId][$iLang] ) ) {
00365 $oDb = oxDb::getDb( true );
00366
00367 $sQ = "select oxfixed from oxseo where oxtype = ".$oDb->quote( $sType )."
00368 and oxobjectid = ".$oDb->quote( $sId ) ." and oxshopid = ".$oDb->quote( $iShopId )." and oxlang = '{$iLang}'";
00369
00370 $sParams = $sParams ? $oDb->quote( $sParams ) : "''";
00371 if ( $sParams && $blStrictParamsCheck ) {
00372 $sQ .= " and oxparams = {$sParams}";
00373 } else {
00374 $sQ .= " order by oxparams = {$sParams} desc";
00375 }
00376 $sQ .= " limit 1";
00377
00378 self::$_aFixedCache[$sType][$sShopId][$sId][$iLang] = (bool) $oDb->getOne( $sQ );
00379 }
00380 return self::$_aFixedCache[$sType][$sShopId][$sId][$iLang];
00381 }
00382
00388 protected function _getCacheKey()
00389 {
00390
00391 if ( self::$_sCacheKey === null ) {
00392 self::$_sCacheKey = false;
00393 if ( !$this->isAdmin() && ( $oView = $this->getConfig()->getActiveView() ) ) {
00394 self::$_sCacheKey = md5( $oView->getViewId() ) . "seo";
00395 }
00396 }
00397 return self::$_sCacheKey;
00398 }
00399
00407 protected function _loadFromCache( $sCacheIdent )
00408 {
00409 startProfile( "seoencoder_loadFromCache" );
00410
00411 $sCache = false;
00412 if ( self::$_aCache === null ) {
00413 self::$_aCache = false;
00414 if ( ( $sCacheKey = $this->_getCacheKey() ) !== false ) {
00415 self::$_aCache = oxUtils::getInstance()->fromFileCache( $sCacheKey );
00416 }
00417 }
00418
00419 if ( self::$_aCache && isset( self::$_aCache[$sCacheIdent] ) ) {
00420 $sCache = self::$_aCache[$sCacheIdent];
00421 }
00422
00423 stopProfile( "seoencoder_loadFromCache" );
00424 return $sCache;
00425 }
00426
00435 protected function _saveInCache( $sCacheIdent, $sCache )
00436 {
00437 startProfile( "seoencoder_saveInCache" );
00438
00439 $blSaved = false;
00440 if ( $sCache && ( $sCacheKey = $this->_getCacheKey() ) !== false ) {
00441 self::$_aCache[$sCacheIdent] = $sCache;
00442 $blSaved = oxUtils::getInstance()->toFileCache( $sCacheKey, self::$_aCache );
00443 }
00444
00445 stopProfile( "seoencoder_saveInCache" );
00446 return $blSaved;
00447 }
00448
00464 protected function _loadFromDb( $sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00465 {
00466 if ( $iShopId === null ) {
00467 $iShopId = $this->getConfig()->getShopId();
00468 }
00469
00470 $iLang = (int) $iLang;
00471
00472 $oDb = oxDb::getDb( true );
00473 $sQ = "select oxfixed, oxseourl, oxexpired, oxtype from oxseo where oxtype = ".$oDb->quote( $sType )."
00474 and oxobjectid = ".$oDb->quote( $sId ) ." and oxshopid = ".$oDb->quote( $iShopId )." and oxlang = '{$iLang}'";
00475
00476 $sParams = $sParams ? $sParams : '';
00477 if ( $sParams && $blStrictParamsCheck ) {
00478 $sQ .= " and oxparams = '{$sParams}'";
00479 } else {
00480 $sQ .= " order by oxparams = '{$sParams}' desc";
00481 }
00482 $sQ .= " limit 1";
00483
00484
00485 $sIdent = md5( $sQ );
00486
00487
00488 if ( ( $sSeoUrl = $this->_loadFromCache( $sIdent ) ) === false ) {
00489
00490 $oRs = $oDb->execute( $sQ );
00491 if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00492
00493 if ( $oRs->fields['oxexpired'] && ( $oRs->fields['oxtype'] == 'static' || $oRs->fields['oxtype'] == 'dynamic' ) ) {
00494
00495 $this->_copyToHistory( $sId, $iShopId, $iLang );
00496 $oDb->execute( "update oxseo set oxexpired = 0 where oxobjectid = ".$oDb->quote( $sId )." and oxlang = '{$iLang}'" );
00497 $sSeoUrl = $oRs->fields['oxseourl'];
00498 } elseif ( !$oRs->fields['oxexpired'] || $oRs->fields['oxfixed'] ) {
00499
00500 $sSeoUrl = $oRs->fields['oxseourl'];
00501 }
00502
00503
00504 $this->_saveInCache( $sIdent, $sSeoUrl );
00505 }
00506 }
00507 return $sSeoUrl;
00508 }
00509
00516 protected function _getReservedEntryKeys()
00517 {
00518 if ( !isset( self::$_aReservedEntryKeys ) || !is_array( self::$_aReservedEntryKeys ) ) {
00519 $sDir = getShopBasePath();
00520 self::$_aReservedEntryKeys = array_map('preg_quote', self::$_aReservedWords, array('#'));
00521 $oStr = getStr();
00522 foreach ( glob( "$sDir/*" ) as $sFile ) {
00523 if ( $oStr->preg_match( '/^(.+)\.php[0-9]*$/i', basename( $sFile ), $aMatches ) ) {
00524 self::$_aReservedEntryKeys[] = preg_quote( $aMatches[0], '#' );
00525 self::$_aReservedEntryKeys[] = preg_quote( $aMatches[1], '#' );
00526 } elseif ( is_dir( $sFile ) ) {
00527 self::$_aReservedEntryKeys[] = preg_quote( basename( $sFile ), '#' );
00528 }
00529 }
00530 self::$_aReservedEntryKeys = array_unique(self::$_aReservedEntryKeys);
00531 }
00532 return self::$_aReservedEntryKeys;
00533 }
00534
00542 protected function _prepareUri( $sUri )
00543 {
00544
00545 $sUri = $this->encodeString( $sUri );
00546
00547
00548 $sUri = strip_tags( $sUri );
00549 $oStr = getStr();
00550
00551
00552
00553 $oStr = getStr();
00554 $sExt = $this->_getUrlExtension();
00555 if ($sExt === null) {
00556 $aMatched = array();
00557 if ( $oStr->preg_match( '/(\.html?|\/)$/i', $sUri, $aMatched ) ) {
00558 $sExt = $aMatched[0];
00559 } else {
00560 $sExt = '/';
00561 }
00562 }
00563 if ( $sExt && $oStr->substr( $sUri, 0 - $oStr->strlen( $sExt ) ) == $sExt ) {
00564 $sUri = $oStr->substr( $sUri, 0, $oStr->strlen( $sUri ) - $oStr->strlen( $sExt ) );
00565 }
00566
00567
00568 $sRegExp = '/[^A-Za-z0-9'.preg_quote( self::$_sSeparator, '/').preg_quote( self::$_sPrefix, '/').'\/]+/';
00569 $sUri = $oStr->preg_replace( array( "/\W*\/\W*/", $sRegExp ), array( "/", self::$_sSeparator ), $sUri );
00570
00571
00572 if ( !$sUri && self::$_sPrefix ) {
00573 $sUri = $this->_prepareUri( self::$_sPrefix );
00574 }
00575
00576 $sAdd = '';
00577 if ('/' != self::$_sSeparator) {
00578 $sAdd = self::$_sSeparator . self::$_sPrefix;
00579 $sUri = trim($sUri, self::$_sSeparator);
00580 } else {
00581 $sAdd = '_' . self::$_sPrefix;
00582 }
00583
00584
00585 $sUri .= $sExt;
00586
00587
00588 $sUri = $oStr->preg_replace( "#^(/*)(".implode('|', $this->_getReservedEntryKeys()).")(/|$)#i", "\$1\$2$sAdd\$3", $sUri );
00589
00590
00591 return $oStr->preg_replace( array( '|//+|', '/' . preg_quote( self::$_sSeparator . self::$_sSeparator, '/' ) .'+/' ),
00592 array( '/', self::$_sSeparator ), $sUri );
00593 }
00594
00595
00604 protected function _prepareTitle( $sTitle, $blSkipTruncate = false )
00605 {
00606 $sTitle = $this->encodeString( $sTitle );
00607 $sSep = self::$_sSeparator;
00608 if (!$sSep || ('/' == $sSep)) {
00609 $sSep = '_';
00610 }
00611
00612 $sRegExp = '/[^A-Za-z0-9\/'.preg_quote( self::$_sPrefix, '/').preg_quote($sSep, '/').']+/';
00613 $sTitle = preg_replace( array("#/+#", $sRegExp, "# +#", "#(".preg_quote($sSep, '/').")+#"), $sSep, $sTitle );
00614
00615 $oStr = getStr();
00616
00617 if ( !$blSkipTruncate && $oStr->strlen( $sTitle ) > $this->_iIdLength ) {
00618 $iFirstSpace = $oStr->strpos( $sTitle, $sSep, $this->_iIdLength);
00619 if ( $iFirstSpace !== false ) {
00620 $sTitle = $oStr->substr( $sTitle, 0, $iFirstSpace );
00621 }
00622 }
00623
00624 $sTitle = trim( $sTitle, $sSep );
00625
00626 if (!$sTitle) {
00627 return self::$_sPrefix;
00628 }
00629
00630 return $sTitle;
00631 }
00632
00633
00650 protected function _saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId = null, $blFixed = null, $sParams = null )
00651 {
00652 $oDb = oxDb::getDb( true );
00653 if ( $iShopId === null ) {
00654 $iShopId = $this->getConfig()->getShopId();
00655 }
00656
00657 $iLang = (int) $iLang;
00658
00659 $sStdUrl = $this->_trimUrl( $sStdUrl );
00660 $sSeoUrl = $this->_trimUrl( $sSeoUrl );
00661 $sIdent = $this->_getSeoIdent( $sSeoUrl );
00662
00663
00664 $sQtedObjectId = $oDb->quote( $sObjectId );
00665 $iQtedShopId = $oDb->quote( $iShopId );
00666 $sQtedType = $oDb->quote( $sType );
00667 $sQtedSeoUrl = $oDb->quote( $sSeoUrl );
00668 $sQtedStdUrl = $oDb->quote( $sStdUrl );
00669 $sQtedParams = $oDb->quote( $sParams );
00670 $sQtedIdent = $oDb->quote( $sIdent );
00671
00672
00673 $sQ = "select oxfixed, oxexpired, ( oxstdurl like {$sQtedStdUrl} ) as samestdurl,
00674 oxseourl like {$sQtedSeoUrl} as sameseourl from oxseo where oxtype = {$sQtedType} and
00675 oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId} and oxlang = {$iLang} ";
00676
00677 $sQ .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00678
00679 $sQ .= "limit 1";
00680
00681 $oRs = $oDb->execute( $sQ );
00682 if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00683 if ( $oRs->fields['samestdurl'] && $oRs->fields['sameseourl'] && $oRs->fields['oxexpired'] ) {
00684
00685 $sFixed = isset( $blFixed ) ? ", oxfixed = " . ( (int) $blFixed ) . " " : '';
00686
00687 $sSql = "update oxseo set oxexpired = 0 {$sFixed} where oxtype = {$sQtedType} and
00688 oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId} and oxlang = {$iLang} ";
00689 $sSql .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00690 $sSql .= " limit 1";
00691
00692 return $oDb->execute( $sSql );
00693 } elseif ( $oRs->fields['oxexpired'] ) {
00694
00695 $this->_copyToHistory( $sObjectId, $iShopId, $iLang, $sType );
00696 }
00697 }
00698
00699
00700 $sParams = $sParams ? $oDb->quote( $sParams ) :'""';
00701 $blFixed = (int) $blFixed;
00702
00703 $sQ = "insert into oxseo
00704 (oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype, oxfixed, oxexpired, oxparams)
00705 values
00706 ( {$sQtedObjectId}, {$sQtedIdent}, {$iQtedShopId}, {$iLang}, {$sQtedStdUrl}, {$sQtedSeoUrl}, {$sQtedType}, '$blFixed', '0', {$sParams} )
00707 on duplicate key update
00708 oxident = {$sQtedIdent}, oxstdurl = {$sQtedStdUrl}, oxseourl = {$sQtedSeoUrl}, oxfixed = '$blFixed', oxexpired = '0'";
00709
00710 return $oDb->execute( $sQ );
00711 }
00712
00723 protected function _trimUrl( $sUrl, $iLang = null )
00724 {
00725 $myConfig = $this->getConfig();
00726 $oStr = getStr();
00727 $sUrl = str_replace( array( $myConfig->getShopUrl( $iLang, false ), $myConfig->getSslShopUrl( $iLang ) ), '', $sUrl );
00728 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)(force_)?(admin_)?sid=[a-z0-9\.]+&?(amp;)?/i', '\1', $sUrl );
00729 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)shp=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00730 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)lang=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00731 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)cur=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00732 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)stoken=[a-z0-9]+&?(amp;)?/i', '\1', $sUrl );
00733 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)&(amp;)?/i', '\1', $sUrl );
00734 $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)+$/i', '', $sUrl );
00735 return trim($sUrl);
00736 }
00737
00746 public function encodeString( $sString, $blReplaceChars = true )
00747 {
00748
00749 $sString = getStr()->html_entity_decode( $sString );
00750
00751 if ( $blReplaceChars ) {
00752 if ( $aReplaceChars = $this->getConfig()->getConfigParam( 'aSeoReplaceChars' ) ) {
00753 $sString = str_replace( array_keys( $aReplaceChars ), array_values( $aReplaceChars ), $sString );
00754 }
00755 }
00756
00757
00758 $aReplaceWhat = array( '&', '"', ''', '<', '>' );
00759 return str_replace( $aReplaceWhat, '', $sString );
00760 }
00761
00769 public function setSeparator( $sSeparator = null )
00770 {
00771 self::$_sSeparator = $sSeparator;
00772 if ( !self::$_sSeparator ) {
00773 self::$_sSeparator = '-';
00774 }
00775 }
00776
00784 public function setPrefix( $sPrefix )
00785 {
00786 if ($sPrefix) {
00787 self::$_sPrefix = $sPrefix;
00788 } else {
00789 self::$_sPrefix = 'oxid';
00790 }
00791 }
00792
00800 public function setIdLength( $iIdlength = null )
00801 {
00802 if ( isset( $iIdlength ) ) {
00803 $this->_iIdLength = $iIdlength;
00804 }
00805 }
00806
00815 public function setReservedWords( $aReservedWords )
00816 {
00817 self::$_aReservedWords = array_merge( self::$_aReservedWords, $aReservedWords );
00818 }
00819
00820
00832 public function markAsExpired( $sId, $iShopId = null, $iExpStat = 1, $iLang = null, $sParams = null )
00833 {
00834 $oDb = oxDb::getDb();
00835 $sWhere = $sId ? "where oxobjectid = " . $oDb->quote( $sId ) : '';
00836 $sWhere .= isset( $iShopId ) ? ( $sWhere ? " and oxshopid = ". $oDb->quote( $iShopId ) : "where oxshopid = ". $oDb->quote( $iShopId ) ) : '';
00837 $sWhere .= $iLang ? ( $sWhere ? " and oxlang = '{$iLang}'" : "where oxlang = '{$iLang}'" ) : '';
00838 $sWhere .= $sParams ? ( $sWhere ? " and {$sParams}" : "where {$sParams}" ) : '';
00839
00840 $sQ = "update oxseo set oxexpired = " . $oDb->quote( $iExpStat ) . " $sWhere ";
00841 $oDb->execute( $sQ );
00842 }
00843
00857 protected function _getPageUri( $oObject, $sType, $sStdUrl, $sSeoUrl, $sParams, $iLang = null, $blFixed = false )
00858 {
00859 if ( !isset( $iLang ) ) {
00860 $iLang = $oObject->getLanguage();
00861 }
00862 $iShopId = $this->getConfig()->getShopId();
00863
00864
00865 $sOldSeoUrl = $this->_loadFromDb( $sType, $oObject->getId(), $iLang, $iShopId, $sParams );
00866 if ( !$sOldSeoUrl ) {
00867
00868 $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $oObject->getId(), $iLang );
00869 $this->_saveToDb( $sType, $oObject->getId(), $sStdUrl, $sSeoUrl, $iLang, $iShopId, (int) $blFixed, $sParams );
00870 } else {
00871
00872 $sSeoUrl = $sOldSeoUrl;
00873 }
00874 return $sSeoUrl;
00875 }
00876
00885 protected function _getStaticObjectId( $iShopId, $sStdUrl )
00886 {
00887 return md5( strtolower ( $iShopId . $this->_trimUrl( $sStdUrl ) ) );
00888 }
00889
00899 public function encodeStaticUrls( $aStaticUrl, $iShopId, $iLang )
00900 {
00901 $oDb = oxDb::getDb();
00902 $sValues = '';
00903 $sOldObjectId = null;
00904
00905
00906 $sStdUrl = $this->_trimUrl( trim( $aStaticUrl['oxseo__oxstdurl'] ) );
00907 $sObjectId = $aStaticUrl['oxseo__oxobjectid'];
00908
00909 if ( !$sObjectId || $sObjectId == '-1' ) {
00910 $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00911 } else {
00912
00913 $sOldObjectId = $sObjectId;
00914
00915
00916 if ( $this->_getStaticObjectId( $iShopId, $sStdUrl ) != $sObjectId ) {
00917 $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00918 }
00919 }
00920
00921 foreach ( $aStaticUrl['oxseo__oxseourl'] as $iLang => $sSeoUrl ) {
00922
00923 $iLang = (int) $iLang;
00924
00925
00926 $sSeoUrl = $this->_trimUrl( $sSeoUrl );
00927 if ( $sSeoUrl ) {
00928 $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00929 }
00930
00931
00932 if ( $sOldObjectId ) {
00933
00934 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}' " ) ) {
00935 $this->_copyToHistory( $sOldObjectId, $iShopId, $iLang, 'static', $sObjectId );
00936 }
00937 }
00938
00939 if ( !$sSeoUrl || !$sStdUrl ) {
00940 continue;
00941 }
00942
00943 $sIdent = $this->_getSeoIdent( $sSeoUrl );
00944
00945 if ( $sValues ) {
00946 $sValues .= ', ';
00947 }
00948
00949 $sValues .= "( " . $oDb->quote( $sObjectId ) . ", " . $oDb->quote( $sIdent ) . ", " . $oDb->quote( $iShopId ).", '{$iLang}', " . $oDb->quote( $sStdUrl ) . ", " . $oDb->quote( $sSeoUrl ) . ", 'static' )";
00950 }
00951
00952
00953 if ( $sOldObjectId ) {
00954 $oDb->execute( "delete from oxseo where oxobjectid in ( " . $oDb->quote( $sOldObjectId ) . ", " . $oDb->quote( $sObjectId ) . " )" );
00955 }
00956
00957
00958 if ( $sValues ) {
00959
00960 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype ) values {$sValues} ";
00961 $oDb->execute( $sQ );
00962 }
00963
00964 return $sObjectId;
00965 }
00966
00974 public function copyStaticUrls( $iShopId )
00975 {
00976 $iBaseShopId = $this->getConfig()->getBaseShopId();
00977 if ( $iShopId != $iBaseShopId ) {
00978 $oDb = oxDb::getDb();
00979 foreach (array_keys(oxLang::getInstance()->getLanguageIds()) as $iLang) {
00980 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype )
00981 select MD5( LOWER( CONCAT( " . $oDb->quote( $iShopId ) . ", oxstdurl ) ) ), MD5( LOWER( oxseourl ) ),
00982 " . $oDb->quote( $iShopId ) . ", oxlang, oxstdurl, oxseourl, oxtype from oxseo where oxshopid = '{$iBaseShopId}' and oxtype = 'static' and oxlang='$iLang' ";
00983 $oDb->execute( $sQ );
00984 }
00985 }
00986 }
00987
00997 public function getStaticUrl( $sStdUrl, $iLang = null, $iShopId = null )
00998 {
00999 if (!isset($iShopId)) {
01000 $iShopId = $this->getConfig()->getShopId();
01001 }
01002 if (!isset($iLang)) {
01003 $iLang = oxLang::getInstance()->getEditLanguage();
01004 }
01005
01006 if ( isset($this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId])) {
01007 return $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId];
01008 }
01009
01010 $sFullUrl = '';
01011 if ( ( $sSeoUrl = $this->_getStaticUri( $sStdUrl, $iShopId, $iLang ) ) ) {
01012 $sFullUrl = $this->_getFullUrl( $sSeoUrl, $iLang, strpos( $sStdUrl, "https:" ) === 0 );
01013 }
01014
01015
01016 $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId] = $sFullUrl;
01017
01018 return $sFullUrl;
01019 }
01020
01039 public function addSeoEntry( $sObjectId, $iShopId, $iLang, $sStdUrl, $sSeoUrl, $sType, $blFixed = 1, $sKeywords = '', $sDescription = '', $sParams = '', $blExclude = false, $sAltObjectId = null )
01040 {
01041 $sSeoUrl = $this->_processSeoUrl( $this->_trimUrl( $sSeoUrl ? $sSeoUrl : $this->_getAltUri( $sAltObjectId ? $sAltObjectId : $sObjectId, $iLang ) ), $sObjectId, $iLang, $blExclude );
01042 if ( $this->_saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId, $blFixed, $sParams ) ) {
01043
01044 $oDb = oxDb::getDb( true );
01045
01046
01047 $sQtedObjectId = $oDb->quote( $sAltObjectId ? $sAltObjectId : $sObjectId );
01048 $iQtedShopId = $oDb->quote( $iShopId );
01049
01050 $oStr = getStr();
01051 if ( $sKeywords !== false ) {
01052 $sKeywords = $oDb->quote( $oStr->htmlspecialchars( $this->encodeString( strip_tags( $sKeywords ), false ) ) );
01053 }
01054
01055 if ( $sDescription !== false ) {
01056 $sDescription = $oDb->quote( $oStr->htmlspecialchars( strip_tags( $sDescription ) ) );
01057 }
01058
01059 $sQ = "insert into oxobject2seodata
01060 ( oxobjectid, oxshopid, oxlang, oxkeywords, oxdescription )
01061 values
01062 ( {$sQtedObjectId}, {$iQtedShopId}, {$iLang}, ".( $sKeywords ? $sKeywords : "''" ).", ".( $sDescription ? $sDescription : "''" )." )
01063 on duplicate key update
01064 oxkeywords = ".( $sKeywords ? $sKeywords : "oxkeywords" ).", oxdescription = ".( $sDescription ? $sDescription : "oxdescription" );
01065 $oDb->execute( $sQ );
01066 }
01067 }
01068
01077 protected function _getAltUri( $sObjectId, $iLang )
01078 {
01079 }
01080
01091 public function deleteSeoEntry( $sObjectId, $iShopId, $iLang, $sType )
01092 {
01093 $oDb = oxDb::getDb();
01094 $sQ = "delete from oxseo where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId ) . " and oxlang = " . $oDb->quote( $iLang ) . " and oxtype = " . $oDb->quote( $sType ) . " ";
01095 oxDb::getDb()->execute( $sQ );
01096 }
01097
01108 public function getMetaData( $sObjectId, $sMetaType, $iShopId = null, $iLang = null )
01109 {
01110 $oDb = oxDb::getDb();
01111
01112 $iShopId = ( !isset( $iShopId ) ) ? $this->getConfig()->getShopId():$iShopId;
01113 $iLang = ( !isset( $iLang ) ) ? oxLang::getInstance()->getObjectTplLanguage():((int) $iLang);
01114 return $oDb->getOne( "select {$sMetaType} from oxobject2seodata where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId )." and oxlang = '{$iLang}'" );
01115 }
01116
01130 public function getDynamicUrl( $sStdUrl, $sSeoUrl, $iLang )
01131 {
01132 startProfile("getDynamicUrl");
01133 $sDynUrl = $this->_getFullUrl( $this->_getDynamicUri( $sStdUrl, $sSeoUrl, $iLang ), strpos( $sStdUrl, "https:" ) === 0 );
01134 stopProfile("getDynamicUrl");
01135 return $sDynUrl;
01136 }
01137
01146 public function fetchSeoUrl( $sStdUrl, $iLanguage = null )
01147 {
01148 $oDb = oxDb::getDb( true );
01149 $iLanguage = isset( $iLanguage ) ? ( (int) $iLanguage ) : oxLang::getInstance()->getBaseLanguage();
01150 $sSeoUrl = false;
01151
01152 $sShopId = $this->getConfig()->getShopId();
01153
01154 $sQ = "select oxseourl, oxlang from oxseo where oxstdurl = ".$oDb->quote( $sStdUrl )." and oxlang = '$iLanguage' and oxshopid = '$sShopId' limit 1";
01155 $oRs = $oDb->execute( $sQ );
01156 if ( !$oRs->EOF ) {
01157 $sSeoUrl = $oRs->fields['oxseourl'];
01158 }
01159
01160 return $sSeoUrl;
01161 }
01162 }