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;)?)&(amp;)?/i', '\1', $sUrl );
00677         $sUrl = $oStr->preg_replace( '/(\?|&(amp;)?)+$/i', '', $sUrl );
00678         return trim($sUrl);
00679     }
00680 
00689     public function encodeString( $sString, $blReplaceChars = true )
00690     {
00691         // decoding entities
00692         $sString = getStr()->html_entity_decode( $sString );
00693 
00694         if ( $blReplaceChars ) {
00695             $aReplaceChars = $this->getConfig()->getConfigParam( 'aSeoReplaceChars' );
00696             $sString = str_replace( array_keys( $aReplaceChars ), array_values( $aReplaceChars ), $sString );
00697         }
00698 
00699         // special chars
00700         $aReplaceWhat = array( '&amp;', '&quot;', '&#039;', '&lt;', '&gt;' );
00701         return str_replace( $aReplaceWhat, '', $sString );
00702     }
00703 
00711     public function setSeparator( $sSeparator = null )
00712     {
00713         self::$_sSeparator = $sSeparator;
00714         if ( !self::$_sSeparator ) {
00715             self::$_sSeparator = '-';
00716         }
00717     }
00718 
00726     public function setPrefix( $sPrefix )
00727     {
00728         if ($sPrefix) {
00729             self::$_sPrefix = $sPrefix;
00730         } else {
00731             self::$_sPrefix = 'oxid';
00732         }
00733     }
00734 
00742     public function setIdLength( $iIdlength = null )
00743     {
00744         if ( isset( $iIdlength ) ) {
00745             $this->_iIdLength = $iIdlength;
00746         }
00747     }
00748 
00757     public function setReservedWords( $aReservedWords )
00758     {
00759         self::$_aReservedWords = array_merge( self::$_aReservedWords, $aReservedWords );
00760     }
00761 
00762 
00774     public function markAsExpired( $sId, $iShopId = null, $iExpStat = 1, $iLang = null, $sParams = null )
00775     {
00776         $oDb = oxDb::getDb();
00777         $sWhere  = $sId ? "where oxobjectid =  " . $oDb->quote( $sId ) : '';
00778         $sWhere .= isset( $iShopId ) ? ( $sWhere ? " and oxshopid = ". $oDb->quote( $iShopId ) : "where oxshopid = ". $oDb->quote( $iShopId ) ) : '';
00779         $sWhere .= $iLang ? ( $sWhere ? " and oxlang = '{$iLang}'" : "where oxlang = '{$iLang}'" ) : '';
00780         $sWhere .= $sParams ? ( $sWhere ? " and {$sParams}" : "where {$sParams}" ) : '';
00781 
00782         $sQ = "update oxseo set oxexpired =  " . $oDb->quote( $iExpStat ) . " $sWhere ";
00783         $oDb->execute( $sQ );
00784     }
00785 
00799     protected function _getPageUri( $oObject, $sType, $sStdUrl, $sSeoUrl, $sParams, $iLang = null, $blFixed = false )
00800     {
00801         if ( !isset( $iLang ) ) {
00802             $iLang = $oObject->getLanguage();
00803         }
00804         $iShopId = $this->getConfig()->getShopId();
00805 
00806         //load page link from DB
00807         $sOldSeoUrl = $this->_loadFromDb( $sType, $oObject->getId(), $iLang, $iShopId, $sParams );
00808         if ( !$sOldSeoUrl ) {
00809             // generating new..
00810             $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $oObject->getId(), $iLang );
00811             $this->_saveToDb( $sType, $oObject->getId(), $sStdUrl, $sSeoUrl, $iLang, $iShopId, (int) $blFixed, $sParams );
00812         } else {
00813             // using old
00814             $sSeoUrl = $sOldSeoUrl;
00815         }
00816         return $sSeoUrl;
00817     }
00818 
00827     protected function _getStaticObjectId( $iShopId, $sStdUrl )
00828     {
00829         return md5( strtolower ( $iShopId . $this->_trimUrl( $sStdUrl ) ) );
00830     }
00831 
00841     public function encodeStaticUrls( $aStaticUrl, $iShopId, $iLang )
00842     {
00843         $oDb = oxDb::getDb();
00844         $sValues = '';
00845         $sOldObjectId = null;
00846 
00847         // standard url
00848         $sStdUrl = $this->_trimUrl( trim( $aStaticUrl['oxseo__oxstdurl'] ) );
00849         $sObjectId = $aStaticUrl['oxseo__oxobjectid'];
00850 
00851         if ( !$sObjectId || $sObjectId == '-1' ) {
00852             $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00853         } else {
00854             // marking entry as needs to move to history
00855             $sOldObjectId = $sObjectId;
00856 
00857             // if std url does not match old
00858             if ( $this->_getStaticObjectId( $iShopId, $sStdUrl ) != $sObjectId ) {
00859                 $sObjectId = $this->_getStaticObjectId( $iShopId, $sStdUrl );
00860             }
00861         }
00862 
00863         foreach ( $aStaticUrl['oxseo__oxseourl'] as $iLang => $sSeoUrl ) {
00864 
00865             $iLang = (int) $iLang;
00866 
00867             // generating seo url
00868             $sSeoUrl = $this->_trimUrl( $sSeoUrl );
00869             if ( $sSeoUrl ) {
00870                 $sSeoUrl = $this->_processSeoUrl( $sSeoUrl, $sObjectId, $iLang );
00871             }
00872 
00873 
00874             if ( $sOldObjectId ) {
00875                 // move changed records to history
00876                 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}' " ) ) {
00877                     $this->_copyToHistory( $sOldObjectId, $iShopId, $iLang, 'static', $sObjectId );
00878                 }
00879             }
00880 
00881             if ( !$sSeoUrl || !$sStdUrl ) {
00882                 continue;
00883             }
00884 
00885             $sIdent = $this->_getSeoIdent( $sSeoUrl );
00886 
00887             if ( $sValues ) {
00888                 $sValues .= ', ';
00889             }
00890 
00891             $sValues .= "( " . $oDb->quote( $sObjectId ) . ", " . $oDb->quote( $sIdent ) . ", " . $oDb->quote( $iShopId ).", '{$iLang}', " . $oDb->quote( $sStdUrl ) . ", " . $oDb->quote( $sSeoUrl ) . ", 'static' )";
00892         }
00893 
00894         // must delete old before insert/update
00895         if ( $sOldObjectId ) {
00896             $oDb->execute( "delete from oxseo where oxobjectid in ( " . $oDb->quote( $sOldObjectId ) . ", " . $oDb->quote( $sObjectId ) . " )" );
00897         }
00898 
00899         // (re)inserting
00900         if ( $sValues ) {
00901 
00902             $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype ) values {$sValues} ";
00903             $oDb->execute( $sQ );
00904         }
00905 
00906         return $sObjectId;
00907     }
00908 
00916     public function copyStaticUrls( $iShopId )
00917     {
00918         $iBaseShopId = $this->getConfig()->getBaseShopId();
00919         if ( $iShopId != $iBaseShopId ) {
00920             $oDb = oxDb::getDb();
00921             foreach (array_keys(oxLang::getInstance()->getLanguageIds()) as $iLang) {
00922                 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype )
00923                        select MD5( LOWER( CONCAT( " . $oDb->quote( $iShopId ) . ", oxstdurl ) ) ), MD5( LOWER( oxseourl ) ),
00924                        " . $oDb->quote( $iShopId ) . ", oxlang, oxstdurl, oxseourl, oxtype from oxseo where oxshopid = '{$iBaseShopId}' and oxtype = 'static' and oxlang='$iLang' ";
00925                 $oDb->execute( $sQ );
00926             }
00927         }
00928     }
00929 
00939     public function getStaticUrl( $sStdUrl, $iLang = null, $iShopId = null )
00940     {
00941         if (!isset($iShopId)) {
00942             $iShopId = $this->getConfig()->getShopId();
00943         }
00944         if (!isset($iLang)) {
00945             $iLang   = oxLang::getInstance()->getEditLanguage();
00946         }
00947 
00948         if ( isset($this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId])) {
00949             return $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId];
00950         }
00951 
00952         $sFullUrl = '';
00953         if ( ( $sSeoUrl = $this->_getStaticUri( $sStdUrl, $iShopId, $iLang ) ) ) {
00954             $sFullUrl = $this->_getFullUrl( $sSeoUrl, $iLang, strpos( $sStdUrl, "https:" ) === 0 );
00955         }
00956 
00957 
00958         $this->_aStaticUrlCache[$sStdUrl][$iLang][$iShopId] = $sFullUrl;
00959 
00960         return $sFullUrl;
00961     }
00962 
00981     public function addSeoEntry( $sObjectId, $iShopId, $iLang, $sStdUrl, $sSeoUrl, $sType, $blFixed = 1, $sKeywords = '', $sDescription = '', $sParams = '', $blExclude = false, $sAltObjectId = null )
00982     {
00983         $sSeoUrl = $this->_processSeoUrl( $this->_trimUrl( $sSeoUrl ? $sSeoUrl : $this->_getAltUri( $sAltObjectId ? $sAltObjectId : $sObjectId, $iLang ) ), $sObjectId, $iLang, $blExclude );
00984         if ( $this->_saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId, $blFixed, $sParams ) ) {
00985 
00986             $oDb = oxDb::getDb( true );
00987 
00988             //
00989             $sQtedObjectId = $oDb->quote( $sAltObjectId ? $sAltObjectId : $sObjectId );
00990             $iQtedShopId   = $oDb->quote( $iShopId );
00991 
00992             $oStr = getStr();
00993             if ( $sKeywords !== false ) {
00994                 $sKeywords = $oDb->quote( $oStr->htmlspecialchars( $this->encodeString( strip_tags( $sKeywords ), false ) ) );
00995             }
00996 
00997             if ( $sDescription !== false ) {
00998                 $sDescription = $oDb->quote( $oStr->htmlspecialchars( strip_tags( $sDescription ) ) );
00999             }
01000 
01001             $sQ = "insert into oxobject2seodata
01002                        ( oxobjectid, oxshopid, oxlang, oxkeywords, oxdescription )
01003                    values
01004                        ( {$sQtedObjectId}, {$iQtedShopId}, {$iLang}, ".( $sKeywords ? $sKeywords : "''" ).", ".( $sDescription ? $sDescription : "''" )." )
01005                    on duplicate key update
01006                        oxkeywords = ".( $sKeywords ? $sKeywords : "oxkeywords" ).", oxdescription = ".( $sDescription ? $sDescription : "oxdescription" );
01007             $oDb->execute( $sQ );
01008         }
01009     }
01010 
01019     protected function _getAltUri( $sObjectId, $iLang )
01020     {
01021     }
01022 
01033     public function deleteSeoEntry( $sObjectId, $iShopId, $iLang, $sType )
01034     {
01035         $oDb = oxDb::getDb();
01036         $sQ = "delete from oxseo where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId ) . " and oxlang = " . $oDb->quote( $iLang ) . " and oxtype = " . $oDb->quote( $sType ) . " ";
01037         oxDb::getDb()->execute( $sQ );
01038     }
01039 
01050     public function getMetaData( $sObjectId, $sMetaType, $iShopId = null, $iLang = null )
01051     {
01052         $oDb = oxDb::getDb();
01053 
01054         $iShopId = ( !isset( $iShopId ) ) ? $this->getConfig()->getShopId():$iShopId;
01055         $iLang   = ( !isset( $iLang ) ) ? oxLang::getInstance()->getObjectTplLanguage():((int) $iLang);
01056         return $oDb->getOne( "select {$sMetaType} from oxobject2seodata where oxobjectid = " . $oDb->quote( $sObjectId ) . " and oxshopid = " . $oDb->quote( $iShopId )." and oxlang = '{$iLang}'" );
01057     }
01058 
01072     public function getDynamicUrl( $sStdUrl, $sSeoUrl, $iLang )
01073     {
01074         startProfile("getDynamicUrl");
01075         $sDynUrl = $this->_getFullUrl( $this->_getDynamicUri( $sStdUrl, $sSeoUrl, $iLang ), strpos( $sStdUrl, "https:" ) === 0 );
01076         stopProfile("getDynamicUrl");
01077         return $sDynUrl;
01078     }
01079 
01088     public function fetchSeoUrl( $sStdUrl, $iLanguage = null )
01089     {
01090         $oDb = oxDb::getDb( true );
01091         $iLanguage = isset( $iLanguage ) ? ( (int) $iLanguage ) : oxLang::getInstance()->getBaseLanguage();
01092         $sSeoUrl   = false;
01093 
01094         $sShopId = $this->getConfig()->getShopId();
01095 
01096         $sQ = "select oxseourl, oxlang from oxseo where oxstdurl = ".$oDb->quote( $sStdUrl )." and oxlang = '$iLanguage' and oxshopid = '$sShopId' limit 1";
01097         $oRs = $oDb->execute( $sQ );
01098         if ( !$oRs->EOF ) {
01099             $sSeoUrl = $oRs->fields['oxseourl'];
01100         }
01101 
01102         return $sSeoUrl;
01103     }
01104 }