oxseoencoder.php

Go to the documentation of this file.
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 $_aSeoCache = array();
00065 
00071     protected $_aFixedCache = array();
00072 
00078     public static function getInstance()
00079     {
00080         if ( defined( 'OXID_PHP_UNIT' ) ) {
00081             self::$_instance = modInstances::getMod( __CLASS__ );
00082         }
00083 
00084         if (!self::$_instance) {
00085             self::$_instance = oxNew("oxSeoEncoder");
00086             if ( defined( 'OXID_PHP_UNIT' ) ) {
00087                 modInstances::addMod( __CLASS__, self::$_instance);
00088             }
00089         }
00090 
00091         if ( defined( 'OXID_PHP_UNIT' ) ) {
00092             // resetting cache
00093             self::$_instance->_aSeoCache = array();
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 
00146     public function resetCache()
00147     {
00148         $this->_aSeoCache = array();
00149     }
00150 
00154     public function __construct()
00155     {
00156         $myConfig = $this->getConfig();
00157         if (!self::$_sSeparator) {
00158             $this->setSeparator( $myConfig->getConfigParam( 'sSEOSeparator' ) );
00159         }
00160         if (!self::$_sPrefix) {
00161             $this->setPrefix( $myConfig->getConfigParam( 'sSEOuprefix' ) );
00162         }
00163         $this->setReservedWords( $myConfig->getConfigParam( 'aSEOReservedWords' ) );
00164     }
00165 
00177     protected function _copyToHistory( $sId, $iShopId, $iLang, $sType = null, $sNewId = null )
00178     {
00179         $oDb = oxDb::getDb();
00180         $sObjectid = $sNewId?$oDb->quote( $sNewId ):'oxobjectid';
00181         $sType     = $sType?"oxtype =".$oDb->quote( $sType )." and":'';
00182         $iLang     = (int) $iLang;
00183 
00184         // moving
00185         $sSub = "select $sObjectid, MD5( LOWER( oxseourl ) ), oxshopid, oxlang, now() from oxseo
00186                  where {$sType} oxobjectid = ".$oDb->quote( $sId )." and oxshopid = ".$oDb->quote( $iShopId )." and
00187                  oxlang = {$iLang} and oxexpired = '1'";
00188         $sQ   = "replace oxseohistory ( oxobjectid, oxident, oxshopid, oxlang, oxinsert ) {$sSub}";
00189         $oDb->execute( $sQ );
00190     }
00191 
00200     public function getDynamicObjectId( $iShopId, $sStdUrl )
00201     {
00202         return $this->_getStaticObjectId( $iShopId, $sStdUrl );
00203     }
00204 
00214     protected function _getDynamicUri( $sStdUrl, $sSeoUrl, $iLang )
00215     {
00216         $iShopId = $this->getConfig()->getShopId();
00217 
00218         $sStdUrl   = $this->_trimUrl( $sStdUrl );
00219         $sObjectId = $this->getDynamicObjectId( $iShopId, $sStdUrl );
00220         $sSeoUrl   = $this->_prepareUri( $sSeoUrl );
00221 
00222         //load details link from DB
00223         $sOldSeoUrl = $this->_loadFromDb( 'dynamic', $sObjectId, $iLang );
00224         if ( $sOldSeoUrl === $sSeoUrl ) {
00225             $sSeoUrl = $sOldSeoUrl;
00226         } else {
00227 
00228             if ( $sOldSeoUrl ) {
00229                 // old must be transferred to history
00230                 $this->_copyToHistory( $sObjectId, $iShopId, $iLang, 'dynamic' );
00231             }
00232 
00233             // creating unique
00234             $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00235 
00236             // inserting
00237             $this->_saveToDb( 'dynamic', $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId );
00238         }
00239 
00240         return $sSeoUrl;
00241     }
00242 
00252     protected function _getFullUrl( $sSeoUrl, $iLang = null, $blSsl = false )
00253     {
00254         if ( $sSeoUrl ) {
00255             $sFullUrl = ( $blSsl ? $this->getConfig()->getSslShopUrl( $iLang ) : $this->getConfig()->getShopUrl( $iLang ) ) . $sSeoUrl;
00256             return oxUtilsUrl::getInstance()->processSeoUrl( $sFullUrl );
00257         }
00258         return false;
00259     }
00260 
00270     protected function _getSeoIdent( $sSeoUrl )
00271     {
00272         return md5( strtolower( $sSeoUrl ) );
00273     }
00274 
00284     protected function _getStaticUri( $sStdUrl, $iShopId, $iLang )
00285     {
00286         $sStdUrl = $this->_trimUrl( $sStdUrl, $iLang );
00287         return $this->_loadFromDb( 'static', $this->_getStaticObjectId( $iShopId, $sStdUrl ), $iLang );
00288     }
00289 
00295     protected function _getUrlExtension()
00296     {
00297         return;
00298     }
00299 
00312     protected function _getUniqueSeoUrl( $sSeoUrl, $sObjectId = null, $iObjectLang = null )
00313     {
00314         $sSeoUrl = $this->_prepareUri( $sSeoUrl );
00315         $oStr = getStr();
00316         $sExt = '';
00317         if ( $oStr->preg_match( '/(\.html?|\/)$/i', $sSeoUrl, $aMatched ) ) {
00318             $sExt = $aMatched[0];
00319         }
00320         $sBaseSeoUrl = $sSeoUrl;
00321         if ( $sExt && $oStr->substr( $sSeoUrl, 0 - $oStr->strlen( $sExt ) ) == $sExt ) {
00322             $sBaseSeoUrl = $oStr->substr( $sSeoUrl, 0, $oStr->strlen( $sSeoUrl ) - $oStr->strlen( $sExt ) );
00323         }
00324 
00325         $oDb = oxDb::getDb();
00326         $iShopId = $this->getConfig()->getShopId();
00327         $iCnt = 0;
00328         $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl );
00329         $sQ = "select 1 from oxseo where oxshopid = '{$iShopId}'";
00330 
00331         // skipping self
00332         if ( $sObjectId && isset($iObjectLang) ) {
00333             $iObjectLang = (int) $iObjectLang;
00334             $sQ .= " and not (oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxlang = $iObjectLang)";
00335         }
00336 
00337         while ( $oDb->getOne( $sQ ." and oxident= " . $oDb->quote( $this->_getSeoIdent( $sCheckSeoUrl ) ) ) ) {
00338             $sAdd = '';
00339             if ( self::$_sPrefix ) {
00340                 $sAdd = self::$_sSeparator . self::$_sPrefix;
00341             }
00342             if ( $iCnt ) {
00343                 $sAdd .= self::$_sSeparator . $iCnt;
00344             }
00345             ++$iCnt;
00346 
00347             $sSeoUrl = $sBaseSeoUrl . $sAdd . $sExt;
00348             $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl );
00349         }
00350         return $sSeoUrl;
00351     }
00352 
00367     protected function _isFixed( $sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00368     {
00369         if ( $iShopId === null ) {
00370             $iShopId = $this->getConfig()->getShopId();
00371         }
00372         $iLang = (int) $iLang;
00373 
00374         if ( !isset( $this->_aFixedCache[$sType][$sShopId][$sId][$iLang] ) ) {
00375             $oDb = oxDb::getDb( true );
00376 
00377             $sQ = "select oxfixed from oxseo where oxtype = ".$oDb->quote( $sType )."
00378                    and oxobjectid = ".$oDb->quote( $sId ) ." and oxshopid = ".$oDb->quote( $iShopId )." and oxlang = '{$iLang}'";
00379 
00380             $sParams = $sParams ? $oDb->quote( $sParams ) : "''";
00381             if ( $sParams && $blStrictParamsCheck ) {
00382                 $sQ .= " and oxparams = {$sParams}";
00383             } else {
00384                 $sQ .= " order by oxparams = {$sParams} desc";
00385             }
00386             $sQ .= " limit 1";
00387 
00388             $this->_aFixedCache[$sType][$sShopId][$sId][$iLang] = (bool) $oDb->getOne( $sQ );
00389         }
00390         return $this->_aFixedCache[$sType][$sShopId][$sId][$iLang];
00391     }
00392 
00408     protected function _loadFromDb( $sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00409     {
00410         $oDb = oxDb::getDb( true );
00411         if ( $iShopId === null ) {
00412             $iShopId = $this->getConfig()->getShopId();
00413         }
00414 
00415         $iLang = (int) $iLang;
00416 
00417         $sQ = "select oxfixed, oxseourl, oxexpired, oxtype from oxseo where oxtype = ".$oDb->quote( $sType )."
00418                and oxobjectid = ".$oDb->quote( $sId ) ." and oxshopid = ".$oDb->quote( $iShopId )." and oxlang = '{$iLang}'";
00419 
00420         $sParams = $sParams ? $sParams : '';
00421         if ( $sParams && $blStrictParamsCheck ) {
00422             $sQ .= " and oxparams = '{$sParams}'";
00423         } else {
00424             $sQ .= " order by oxparams = '{$sParams}' desc";
00425         }
00426         $sQ .= " limit 1";
00427 
00428         // caching to avoid same queries..
00429         $sIdent = md5($sQ);
00430         if ( isset( $this->_aSeoCache[$sIdent] ) ) {
00431             return $this->_aSeoCache[$sIdent];
00432         }
00433 
00434         $sSeoUrl = false;
00435         $oRs = $oDb->execute( $sQ );
00436         if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00437             // moving expired static urls to history ..
00438             if ( $oRs->fields['oxexpired'] && ( $oRs->fields['oxtype'] == 'static' || $oRs->fields['oxtype'] == 'dynamic' ) ) {
00439                 // if expired - copying to history, marking as not expired
00440                 $this->_copyToHistory( $sId, $iShopId, $iLang );
00441                 $oDb->execute( "update oxseo set oxexpired = 0 where oxobjectid = ".$oDb->quote( $sId )." and oxlang = '{$iLang}'" );
00442                 $sSeoUrl = $oRs->fields['oxseourl'];
00443             } elseif ( !$oRs->fields['oxexpired'] || $oRs->fields['oxfixed'] ) {
00444                 // if seo url is available and is valid
00445                 $sSeoUrl = $oRs->fields['oxseourl'];
00446             }
00447 
00448             // store cache
00449             $this->_aSeoCache[$sIdent] = $sSeoUrl;
00450         }
00451         return $sSeoUrl;
00452     }
00453 
00460     protected function _getReservedEntryKeys()
00461     {
00462         if ( !isset( self::$_aReservedEntryKeys ) || !is_array( self::$_aReservedEntryKeys ) ) {
00463             $sDir = getShopBasePath();
00464             self::$_aReservedEntryKeys = array_map('preg_quote', self::$_aReservedWords, array('#'));
00465             $oStr = getStr();
00466             foreach ( glob( "$sDir/*" ) as $sFile ) {
00467                 if ( $oStr->preg_match( '/^(.+)\.php[0-9]*$/i', basename( $sFile ), $aMatches ) ) {
00468                     self::$_aReservedEntryKeys[] = preg_quote( $aMatches[0], '#' );
00469                     self::$_aReservedEntryKeys[] = preg_quote( $aMatches[1], '#' );
00470                 } elseif ( is_dir( $sFile ) ) {
00471                     self::$_aReservedEntryKeys[] = preg_quote( basename( $sFile ), '#' );
00472                 }
00473             }
00474             self::$_aReservedEntryKeys = array_unique(self::$_aReservedEntryKeys);
00475         }
00476         return self::$_aReservedEntryKeys;
00477     }
00478 
00486     protected function _prepareUri( $sUri )
00487     {
00488         // decoding entities
00489         $sUri = $this->encodeString( $sUri );
00490 
00491         // basic string preparation
00492         $sUri = strip_tags( $sUri );
00493         $oStr = getStr();
00494 
00495 
00496         // if found ".html" or "/" at the end - removing it temporary
00497         $oStr = getStr();
00498         $sExt = $this->_getUrlExtension();
00499         if ($sExt === null) {
00500             $aMatched = array();
00501             if ( $oStr->preg_match( '/(\.html?|\/)$/i', $sUri, $aMatched ) ) {
00502                 $sExt = $aMatched[0];
00503             } else {
00504                 $sExt = '/';
00505             }
00506         }
00507         if ( $sExt && $oStr->substr( $sUri, 0 - $oStr->strlen( $sExt ) ) == $sExt ) {
00508             $sUri = $oStr->substr( $sUri, 0, $oStr->strlen( $sUri ) - $oStr->strlen( $sExt ) );
00509         }
00510 
00511         // removing any special characters
00512         $sRegExp = '/[^A-Za-z0-9'.preg_quote( self::$_sSeparator, '/').preg_quote( self::$_sPrefix, '/').'\/]+/';
00513         $sUri  = $oStr->preg_replace( array( "/\W*\/\W*/", $sRegExp ), array( "/", self::$_sSeparator ), $sUri );
00514 
00515         // SEO id is empty ?
00516         if ( !$sUri && self::$_sPrefix ) {
00517             $sUri = $this->_prepareUri( self::$_sPrefix );
00518         }
00519 
00520         $sAdd = '';
00521         if ('/' != self::$_sSeparator) {
00522             $sAdd = self::$_sSeparator . self::$_sPrefix;
00523             $sUri = trim($sUri, self::$_sSeparator);
00524         } else {
00525             $sAdd = '_' . self::$_sPrefix;
00526         }
00527 
00528         // binding the ending back
00529         $sUri .= $sExt;
00530 
00531         // fix for not having url, which executes through /other/ script then seo decoder
00532         $sUri = $oStr->preg_replace( "#^(/*)(".implode('|', $this->_getReservedEntryKeys()).")(/|$)#i", "\$1\$2$sAdd\$3", $sUri );
00533 
00534         // cleaning
00535         return $oStr->preg_replace( array( '|//+|', '/' . preg_quote( self::$_sSeparator . self::$_sSeparator, '/' ) .'+/' ),
00536                              array( '/', self::$_sSeparator ), $sUri );
00537     }
00538 
00539 
00548     protected function _prepareTitle( $sTitle, $blSkipTruncate = false )
00549     {
00550         $sTitle = $this->encodeString( $sTitle );
00551         $sSep = self::$_sSeparator;
00552         if (!$sSep || ('/' == $sSep)) {
00553             $sSep = '_';
00554         }
00555 
00556         $sRegExp = '/[^A-Za-z0-9\/'.preg_quote( self::$_sPrefix, '/').preg_quote($sSep, '/').']+/';
00557         $sTitle = preg_replace( array("#/+#", $sRegExp, "# +#", "#(".preg_quote($sSep, '/').")+#"), $sSep, $sTitle );
00558 
00559         $oStr = getStr();
00560         // smart truncate
00561         if ( !$blSkipTruncate && $oStr->strlen( $sTitle ) > $this->_iIdLength ) {
00562             $iFirstSpace = $oStr->strpos( $sTitle, $sSep, $this->_iIdLength);
00563             if ( $iFirstSpace !== false ) {
00564                 $sTitle = $oStr->substr( $sTitle, 0, $iFirstSpace );
00565             }
00566         }
00567 
00568         $sTitle = trim( $sTitle, $sSep );
00569 
00570         if (!$sTitle) {
00571             return self::$_sPrefix;
00572         }
00573         // cleaning
00574         return $sTitle;
00575     }
00576 
00577 
00594     protected function _saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId = null, $blFixed = null, $sParams = null )
00595     {
00596         $oDb = oxDb::getDb( true );
00597         if ( $iShopId === null ) {
00598             $iShopId = $this->getConfig()->getShopId();
00599         }
00600 
00601         $iLang = (int) $iLang;
00602 
00603         $sStdUrl = $this->_trimUrl( $sStdUrl );
00604         $sSeoUrl = $this->_trimUrl( $sSeoUrl );
00605         $sIdent  = $this->_getSeoIdent( $sSeoUrl );
00606 
00607         // transferring old url, thus current url will be regenerated
00608         $sQtedObjectId = $oDb->quote( $sObjectId );
00609         $iQtedShopId   = $oDb->quote( $iShopId );
00610         $sQtedType     = $oDb->quote( $sType );
00611         $sQtedSeoUrl   = $oDb->quote( $sSeoUrl );
00612         $sQtedStdUrl   = $oDb->quote( $sStdUrl );
00613         $sQtedParams   = $oDb->quote( $sParams );
00614         $sQtedIdent    = $oDb->quote( $sIdent );
00615 
00616         // transferring old url, thus current url will be regenerated
00617         $sQ  = "select oxfixed, oxexpired, ( oxstdurl like {$sQtedStdUrl} ) as samestdurl,
00618                 oxseourl like {$sQtedSeoUrl} as sameseourl from oxseo where oxtype = {$sQtedType} and
00619                 oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId}  and oxlang = {$iLang} ";
00620 
00621         $sQ .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00622         //$sQ .= isset( $blFixed ) ? " and oxfixed = " . ( (int) $blFixed ) . " " : '';
00623         $sQ .= "limit 1";
00624 
00625         $oRs = $oDb->execute( $sQ );
00626         if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00627             if ( $oRs->fields['samestdurl'] && $oRs->fields['sameseourl'] && $oRs->fields['oxexpired'] ) {
00628                 // fixed state change
00629                 $sFixed = isset( $blFixed ) ? ", oxfixed = " . ( (int) $blFixed ) . " " : '';
00630                 // nothing was changed - setting expired status back to 0
00631                 $sSql  = "update oxseo set oxexpired = 0 {$sFixed} where oxtype = {$sQtedType} and
00632                           oxobjectid = {$sQtedObjectId} and oxshopid = {$iQtedShopId} and oxlang = {$iLang} ";
00633                 $sSql .= $sParams ? " and oxparams = {$sQtedParams} " : '';
00634                 $sSql .= " limit 1";
00635 
00636                 return $oDb->execute( $sSql );
00637             } elseif ( $oRs->fields['oxexpired'] ) {
00638                 // copy to history
00639                 $this->_copyToHistory( $sObjectId, $iShopId, $iLang, $sType );
00640             }
00641         }
00642 
00643         // inserting new or updating
00644         $sParams = $sParams ? $oDb->quote( $sParams ) :'""';
00645         $blFixed = (int) $blFixed;
00646 
00647         $sQ  = "insert into oxseo
00648                     (oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype, oxfixed, oxexpired, oxparams)
00649                 values
00650                     ( {$sQtedObjectId}, {$sQtedIdent}, {$iQtedShopId}, {$iLang}, {$sQtedStdUrl}, {$sQtedSeoUrl}, {$sQtedType}, '$blFixed', '0', {$sParams} )
00651                 on duplicate key update
00652                     oxident = {$sQtedIdent}, oxstdurl = {$sQtedStdUrl}, oxseourl = {$sQtedSeoUrl}, oxfixed = '$blFixed', oxexpired = '0'";
00653 
00654         return $oDb->execute( $sQ );
00655     }
00656 
00667     protected function _trimUrl( $sUrl, $iLang = null )
00668     {
00669         $myConfig = $this->getConfig();
00670         $oStr = getStr();
00671         $sUrl = str_replace( array( $myConfig->getShopUrl( $iLang ), $myConfig->getSslShopUrl( $iLang ) ), '', $sUrl );
00672         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)(force_)?(admin_)?sid=[a-z0-9\.]+&?(amp;)?/i', '\1', $sUrl );
00673         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)shp=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00674         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)lang=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00675         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)cur=[0-9]+&?(amp;)?/i', '\1', $sUrl );
00676         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)stoken=[a-z0-9]+&?(amp;)?/i', '\1', $sUrl );
00677         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)&(amp;)?/i', '\1', $sUrl );
00678         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)+$/i', '', $sUrl );
00679         return trim($sUrl);
00680     }
00681 
00690     public function encodeString( $sString, $blReplaceChars = true )
00691     {
00692         // decoding entities
00693         $sString = getStr()->html_entity_decode( $sString );
00694 
00695         if ( $blReplaceChars ) {
00696             $aReplaceChars = $this->getConfig()->getConfigParam( 'aSeoReplaceChars' );
00697             $sString = str_replace( array_keys( $aReplaceChars ), array_values( $aReplaceChars ), $sString );
00698         }
00699 
00700         // special chars
00701         $aReplaceWhat = array( '&amp;', '&quot;', '&#039;', '&lt;', '&gt;' );
00702         return str_replace( $aReplaceWhat, '', $sString );
00703     }
00704 
00712     public function setSeparator( $sSeparator = null )
00713     {
00714         self::$_sSeparator = $sSeparator;
00715         if ( !self::$_sSeparator ) {
00716             self::$_sSeparator = '-';
00717         }
00718     }
00719 
00727     public function setPrefix( $sPrefix )
00728     {
00729         if ($sPrefix) {
00730             self::$_sPrefix = $sPrefix;
00731         } else {
00732             self::$_sPrefix = 'oxid';
00733         }
00734     }
00735 
00743     public function setIdLength( $iIdlength = null )
00744     {
00745         if ( isset( $iIdlength ) ) {
00746             $this->_iIdLength = $iIdlength;
00747         }
00748     }
00749 
00758     public function setReservedWords( $aReservedWords )
00759     {
00760         self::$_aReservedWords = array_merge( self::$_aReservedWords, $aReservedWords );
00761     }
00762 
00763 
00775     public function markAsExpired( $sId, $iShopId = null, $iExpStat = 1, $iLang = null, $sParams = null )
00776     {
00777         $oDb = oxDb::getDb();
00778         $sWhere  = $sId ? "where oxobjectid =  " . $oDb->quote( $sId ) : '';
00779         $sWhere .= isset( $iShopId ) ? ( $sWhere ? " and oxshopid = ". $oDb->quote( $iShopId ) : "where oxshopid = ". $oDb->quote( $iShopId ) ) : '';
00780         $sWhere .= $iLang ? ( $sWhere ? " and oxlang = '{$iLang}'" : "where oxlang = '{$iLang}'" ) : '';
00781         $sWhere .= $sParams ? ( $sWhere ? " and {$sParams}" : "where {$sParams}" ) : '';
00782 
00783         $sQ = "update oxseo set oxexpired =  " . $oDb->quote( $iExpStat ) . " $sWhere ";
00784         $oDb->execute( $sQ );
00785     }
00786 
00800     protected function _getPageUri( $oObject, $sType, $sStdUrl, $sSeoUrl, $sParams, $iLang = null, $blFixed = false )
00801     {
00802         if ( !isset( $iLang ) ) {
00803             $iLang = $oObject->getLanguage();
00804         }
00805         $iShopId = $this->getConfig()->getShopId();
00806 
00807         //load page link from DB
00808         $sOldSeoUrl = $this->_loadFromDb( $sType, $oObject->getId(), $iLang, $iShopId, $sParams );
00809         if ( !$sOldSeoUrl ) {
00810             // generating new..
00811             $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $oObject->getId(), $iLang );
00812             $this->_saveToDb( $sType, $oObject->getId(), $sStdUrl, $sSeoUrl, $iLang, $iShopId, (int) $blFixed, $sParams );
00813         } else {
00814             // using old
00815             $sSeoUrl = $sOldSeoUrl;
00816         }
00817         return $sSeoUrl;
00818     }
00819 
00828     protected function _getStaticObjectId( $iShopId, $sStdUrl )
00829     {
00830         return md5( strtolower ( $iShopId . $this->_trimUrl( $sStdUrl ) ) );
00831     }
00832 
00842     public function encodeStaticUrls( $aStaticUrl, $iShopId, $iLang )
00843     {
00844         $oDb = oxDb::getDb();
00845         $sValues = '';
00846         $sOldObjectId = null;
00847 
00848         // standard url
00849         $sStdUrl = $this->_trimUrl( trim( $aStaticUrl['oxseo__oxstdurl'] ) );
00850         $sObjectId = $aStaticUrl['oxseo__oxobjectid'];
00851 
00852         if ( !$sObjectId || $sObjectId == '-1' ) {
00853             $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00854         } else {
00855             // marking entry as needs to move to history
00856             $sOldObjectId = $sObjectId;
00857 
00858             // if std url does not match old
00859             if ( $this->_getStaticObjectId( $iShopId, $sStdUrl ) != $sObjectId ) {
00860                 $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00861             }
00862         }
00863 
00864         foreach ( $aStaticUrl['oxseo__oxseourl'] as $iLang => $sSeoUrl ) {
00865 
00866             $iLang = (int) $iLang;
00867 
00868             // generating seo url
00869             $sSeoUrl = $this->_trimUrl( $sSeoUrl );
00870             if ( $sSeoUrl ) {
00871                 $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00872             }
00873 
00874 
00875             if ( $sOldObjectId ) {
00876                 // move changed records to history
00877                 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}' " ) ) {
00878                     $this->_copyToHistory( $sOldObjectId, $iShopId, $iLang, 'static', $sObjectId );
00879                 }
00880             }
00881 
00882             if ( !$sSeoUrl || !$sStdUrl ) {
00883                 continue;
00884             }
00885 
00886             $sIdent = $this->_getSeoIdent( $sSeoUrl );
00887 
00888             if ( $sValues ) {
00889                 $sValues .= ', ';
00890             }
00891 
00892             $sValues .= "( " . $oDb->quote( $sObjectId ) . ", " . $oDb->quote( $sIdent ) . ", " . $oDb->quote( $iShopId ).", '{$iLang}', " . $oDb->quote( $sStdUrl ) . ", " . $oDb->quote( $sSeoUrl ) . ", 'static' )";
00893         }
00894 
00895         // must delete old before insert/update
00896         if ( $sOldObjectId ) {
00897             $oDb->execute( "delete from oxseo where oxobjectid in ( " . $oDb->quote( $sOldObjectId ) . ", " . $oDb->quote( $sObjectId ) . " )" );
00898         }
00899 
00900         // (re)inserting
00901         if ( $sValues ) {
00902 
00903             $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype ) values {$sValues} ";
00904             $oDb->execute( $sQ );
00905         }
00906 
00907         return $sObjectId;
00908     }
00909 
00917     public function copyStaticUrls( $iShopId )
00918     {
00919         $iBaseShopId = $this->getConfig()->getBaseShopId();
00920         if ( $iShopId != $iBaseShopId ) {
00921             $oDb = oxDb::getDb();
00922             foreach (array_keys(oxLang::getInstance()->getLanguageIds()) as $iLang) {
00923                 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype )
00924                        select MD5( LOWER( CONCAT( " . $oDb->quote( $iShopId ) . ", oxstdurl ) ) ), MD5( LOWER( oxseourl ) ),
00925                        " . $oDb->quote( $iShopId ) . ", oxlang, oxstdurl, oxseourl, oxtype from oxseo where oxshopid = '{$iBaseShopId}' and oxtype = 'static' and oxlang='$iLang' ";
00926                 $oDb->execute( $sQ );
00927             }
00928         }
00929     }
00930 
00940     public function getStaticUrl( $sStdUrl, $iLang = null, $iShopId = null )
00941     {
00942         if (!isset($iShopId)) {
00943             $iShopId = $this->getConfig()->getShopId();
00944         }
00945         if (!isset($iLang)) {
00946             $iLang   = oxLang::getInstance()->getEditLanguage();
00947         }
00948 
00949         if ( isset($this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId])) {
00950             return $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId];
00951         }
00952 
00953         $sFullUrl = '';
00954         if ( ( $sSeoUrl = $this->_getStaticUri( $sStdUrl, $iShopId, $iLang ) ) ) {
00955             $sFullUrl = $this->_getFullUrl( $sSeoUrl, $iLang, strpos( $sStdUrl, "https:" ) === 0 );
00956         }
00957 
00958 
00959         $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId] = $sFullUrl;
00960 
00961         return $sFullUrl;
00962     }
00963 
00982     public function addSeoEntry( $sObjectId, $iShopId, $iLang, $sStdUrl, $sSeoUrl, $sType, $blFixed = 1, $sKeywords = '', $sDescription = '', $sParams = '', $blExclude = false, $sAltObjectId = null )
00983     {
00984         $sSeoUrl = $this->_processSeoUrl( $this->_trimUrl( $sSeoUrl ? $sSeoUrl : $this->_getAltUri( $sAltObjectId ? $sAltObjectId : $sObjectId, $iLang ) ), $sObjectId, $iLang, $blExclude );
00985         if ( $this->_saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId, $blFixed, $sParams ) ) {
00986 
00987             $oDb = oxDb::getDb( true );
00988 
00989             //
00990             $sQtedObjectId = $oDb->quote( $sAltObjectId ? $sAltObjectId : $sObjectId );
00991             $iQtedShopId   = $oDb->quote( $iShopId );
00992 
00993             $oStr = getStr();
00994             if ( $sKeywords !== false ) {
00995                 $sKeywords = $oDb->quote( $oStr->htmlspecialchars( $this->encodeString( strip_tags( $sKeywords ), false ) ) );
00996             }
00997 
00998             if ( $sDescription !== false ) {
00999                 $sDescription = $oDb->quote( $oStr->htmlspecialchars( strip_tags( $sDescription ) ) );
01000             }
01001 
01002             $sQ = "insert into oxobject2seodata
01003                        ( oxobjectid, oxshopid, oxlang, oxkeywords, oxdescription )
01004                    values
01005                        ( {$sQtedObjectId}, {$iQtedShopId}, {$iLang}, ".( $sKeywords ? $sKeywords : "''" ).", ".( $sDescription ? $sDescription : "''" )." )
01006                    on duplicate key update
01007                        oxkeywords = ".( $sKeywords ? $sKeywords : "oxkeywords" ).", oxdescription = ".( $sDescription ? $sDescription : "oxdescription" );
01008             $oDb->execute( $sQ );
01009         }
01010     }
01011 
01020     protected function _getAltUri( $sObjectId, $iLang )
01021     {
01022     }
01023 
01034     public function deleteSeoEntry( $sObjectId, $iShopId, $iLang, $sType )
01035     {
01036         $oDb = oxDb::getDb();
01037         $sQ = "delete from oxseo where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId ) . " and oxlang = " . $oDb->quote( $iLang ) . " and oxtype = " . $oDb->quote( $sType ) . " ";
01038         oxDb::getDb()->execute( $sQ );
01039     }
01040 
01051     public function getMetaData( $sObjectId, $sMetaType, $iShopId = null, $iLang = null )
01052     {
01053         $oDb = oxDb::getDb();
01054 
01055         $iShopId = ( !isset( $iShopId ) ) ? $this->getConfig()->getShopId():$iShopId;
01056         $iLang   = ( !isset( $iLang ) ) ? oxLang::getInstance()->getObjectTplLanguage():((int) $iLang);
01057         return $oDb->getOne( "select {$sMetaType} from oxobject2seodata where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId )." and oxlang = '{$iLang}'" );
01058     }
01059 
01073     public function getDynamicUrl( $sStdUrl, $sSeoUrl, $iLang )
01074     {
01075         startProfile("getDynamicUrl");
01076         $sDynUrl = $this->_getFullUrl( $this->_getDynamicUri( $sStdUrl, $sSeoUrl, $iLang ), strpos( $sStdUrl, "https:" ) === 0 );
01077         stopProfile("getDynamicUrl");
01078         return $sDynUrl;
01079     }
01080 
01089     public function fetchSeoUrl( $sStdUrl, $iLanguage = null )
01090     {
01091         $oDb = oxDb::getDb( true );
01092         $iLanguage = isset( $iLanguage ) ? ( (int) $iLanguage ) : oxLang::getInstance()->getBaseLanguage();
01093         $sSeoUrl   = false;
01094 
01095         $sShopId = $this->getConfig()->getShopId();
01096 
01097         $sQ = "select oxseourl, oxlang from oxseo where oxstdurl = ".$oDb->quote( $sStdUrl )." and oxlang = '$iLanguage' and oxshopid = '$sShopId' limit 1";
01098         $oRs = $oDb->execute( $sQ );
01099         if ( !$oRs->EOF ) {
01100             $sSeoUrl = $oRs->fields['oxseourl'];
01101         }
01102 
01103         return $sSeoUrl;
01104     }
01105 }