00001 <?php
00002
00008 class oxSeoEncoder extends oxSuperCfg
00009 {
00016 protected static $_aReservedWords = array( 'admin' );
00017
00023 protected static $_sSeparator = null;
00024
00030 protected $_iIdLength = 255;
00031
00037 protected static $_sPrefix = null;
00038
00044 protected $_sAddParams = null;
00045
00049 protected static $_instance = null;
00050
00056 public static function getInstance()
00057 {
00058 if (!self::$_instance) {
00059 self::$_instance = oxNew("oxSeoEncoder");
00060 }
00061 return self::$_instance;
00062 }
00063
00067 public function __construct()
00068 {
00069 $myConfig = $this->getConfig();
00070 if (!self::$_sSeparator) {
00071 $this->setSeparator( $myConfig->getConfigParam( 'sSEOSeparator' ) );
00072 }
00073 if (!self::$_sPrefix) {
00074 $this->setPrefix( $myConfig->getConfigParam( 'sSEOuprefix' ) );
00075 }
00076 $this->setReservedWords( $myConfig->getConfigParam( 'aSEOReservedWords' ) );
00077 }
00078
00090 protected function _copyToHistory( $sId, $iShopId, $iLang, $sType = null, $sNewId = null )
00091 {
00092 $sObjectid = $sNewId?"'$sNewId'":'oxobjectid';
00093 $sType = $sType?"oxtype = {$sType} and":'';
00094
00095
00096 $sSub = "select {$sObjectid}, MD5( LOWER( oxseourl ) ), oxshopid, oxlang, now() from oxseo where {$sType} oxobjectid = {$sId} and oxshopid = {$iShopId} and oxlang = {$iLang} limit 1";
00097 $sQ = "replace oxseohistory ( oxobjectid, oxident, oxshopid, oxlang, oxinsert ) {$sSub}";
00098 oxDb::getDb()->execute( $sQ );
00099 }
00100
00107 protected function _getAddParams()
00108 {
00109
00110 if ( $this->_sAddParams === null ) {
00111 $this->_sAddParams = $this->_getAddParamsFnc( oxConfig::getParameter('currency'), $this->getConfig()->getShopId() );
00112 }
00113 return $this->_sAddParams;
00114 }
00115
00125 protected function _getAddParamsFnc( $iCur, $iActShop )
00126 {
00127
00128 $this->_sAddParams = '';
00129 $sSep = '?';
00130 if ( $iCur ) {
00131 $this->_sAddParams .= $sSep . 'cur=' . $iCur;
00132 $sSep = '&';
00133 }
00134
00135
00136 return $this->_sAddParams;
00137 }
00138
00148 protected function _getDynamicUri( $sStdUrl, $sSeoUrl, $iLang )
00149 {
00150 $iShopId = $this->getConfig()->getShopId();
00151
00152 $sStdUrl = $this->_trimUrl( $sStdUrl, $iLang );
00153 $sObjectId = md5( strtolower( $iShopId . $sStdUrl ) );
00154 $sSeoUrl = $this->_prepareTitle( $sSeoUrl );
00155
00156
00157 $sOldSeoUrl = $this->_loadFromDb( 'dynamic', $sObjectId, $iLang );
00158 if ( $sOldSeoUrl === $sSeoUrl ) {
00159 $sSeoUrl = $sOldSeoUrl;
00160 } else {
00161
00162 if ( $sOldSeoUrl ) {
00163 $oDb = oxDb::getDb();
00164 $this->_copyToHistory( $oDb->quote( $sObjectId ), $oDb->quote( $iShopId ), $iLang, $oDb->quote( 'dynamic' ) );
00165 }
00166
00167
00168 $sSeoUrl = $this->_getUniqueSeoUrl( $sSeoUrl, null, $sObjectId );
00169
00170
00171 $this->_saveToDb( 'dynamic', $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId );
00172 }
00173
00174 return $sSeoUrl;
00175 }
00176
00184 public function getLanguageParam( $iObjectLang, $blForce = false )
00185 {
00186 $iDefLang = (int) $this->getConfig()->getConfigParam( 'iDefSeoLang' );
00187 $aLangIds = oxLang::getInstance()->getLanguageIds();
00188 $sLang = '';
00189
00190 if ( $blForce || ( $iObjectLang != $iDefLang && isset( $aLangIds[$iObjectLang] ) ) ) {
00191
00192 $sLang = $aLangIds[$iObjectLang] . '/';
00193 }
00194 return $sLang;
00195 }
00196
00205 protected function _getFullUrl( $sSeoUrl, $iLang )
00206 {
00207 return $this->getConfig()->getShopURL() . $this->getLanguageParam( (int) $iLang ) . $sSeoUrl . $this->_getAddParams();
00208 }
00209
00220 protected function _getSeoIdent( $sSeoUrl, $iLang )
00221 {
00222 return md5( strtolower( $this->getLanguageParam( $iLang, true ) . $sSeoUrl ) );
00223 }
00224
00234 protected function _getStaticUri( $sStdUrl, $iShopId, $iLang )
00235 {
00236 $sIdent = md5( strtolower( $iShopId . $this->_trimUrl( $sStdUrl, $iLang ) ) );
00237 return $this->_loadFromDb( 'static', $sIdent, $iLang );
00238 }
00239
00252 protected function _getUniqueSeoUrl( $sSeoUrl, $sConstEnd = null, $sObjectId = null )
00253 {
00254 if ($sConstEnd === null) {
00255 $aMatched = array();
00256 if ( preg_match('/\.html?$/i', $sSeoUrl, $aMatched ) ) {
00257 $sConstEnd = $aMatched[0];
00258 } else {
00259 if ($sSeoUrl{strlen($sSeoUrl)-1} != '/') {
00260 $sSeoUrl .= '/';
00261 }
00262 $sConstEnd = '/';
00263 }
00264 }
00265
00266 $sBaseSeoUrl = $sSeoUrl;
00267 if ( $sConstEnd && substr( $sSeoUrl, 0 - strlen( $sConstEnd ) ) == $sConstEnd ) {
00268 $sBaseSeoUrl = substr( $sSeoUrl, 0, strlen( $sSeoUrl ) - strlen( $sConstEnd ) );
00269 }
00270
00271 $oDb = oxDb::getDb();
00272 $iShopId = $this->getConfig()->getShopId();
00273 $iCnt = 0;
00274 $iLang = oxLang::getInstance()->getBaseLanguage();
00275 $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl, $iLang );
00276 $sQ = "select 1 from oxseo where oxshopid = '{$iShopId}'";
00277
00278
00279 if ( $sObjectId ) {
00280 $sQ .= " and oxobjectid != '{$sObjectId}'";
00281 }
00282
00283 while ( $oDb->getOne( $sQ ." and oxident='".$this->_getSeoIdent( $sCheckSeoUrl, $iLang )."' " ) ) {
00284
00285 $sAdd = self::$_sSeparator . self::$_sPrefix;
00286 if ( $iCnt ) {
00287 $sAdd .= self::$_sSeparator . $iCnt;
00288 }
00289 ++$iCnt;
00290
00291 $sSeoUrl = $sBaseSeoUrl . $sAdd . $sConstEnd;
00292 $sCheckSeoUrl = $this->_trimUrl( $sSeoUrl, $iLang );
00293 }
00294 return $sSeoUrl;
00295 }
00296
00312 protected function _loadFromDb( $sType, $sId, $iLang, $iShopId = null, $sParams = null, $blStrictParamsCheck = true)
00313 {
00314 $oDb = oxDb::getDb( true );
00315 if ( $iShopId === null ) {
00316 $iShopId = $this->getConfig()->getShopId();
00317 }
00318
00319 $iShopId = $oDb->quote( $iShopId );
00320 $sId = $oDb->quote( $sId );
00321 $sType = $oDb->quote( $sType );
00322 $iLang = (int) $iLang;
00323
00324 $sQ = "select oxfixed, oxseourl, oxexpired, oxtype from oxseo where oxtype = {$sType}
00325 and oxobjectid = {$sId} and oxshopid = {$iShopId} and oxlang = {$iLang}";
00326
00327 if ($sParams) {
00328 if ($blStrictParamsCheck) {
00329 $sQ .= " and oxparams = '{$sParams}'";
00330 } else {
00331 $sQ .= " order by oxparams = '{$sParams}' desc";
00332 }
00333 }
00334 $sQ .= " limit 1";
00335
00336 $sSeoUrl = false;
00337 $oRs = $oDb->execute( $sQ );
00338 if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00339
00340 if ( $oRs->fields['oxexpired'] && ( $oRs->fields['oxtype'] == 'static' || $oRs->fields['oxtype'] == 'dynamic' ) ) {
00341
00342 $this->_copyToHistory( $sId, $iShopId, $iLang );
00343 $oDb->execute( "update oxseo set oxexpired = 0 where oxobjectid = {$sId} and oxlang = '{$iLang}' " );
00344 $sSeoUrl = $oRs->fields['oxseourl'];
00345 } elseif ( !$oRs->fields['oxexpired'] || $oRs->fields['oxfixed'] ) {
00346
00347 $sSeoUrl = $oRs->fields['oxseourl'];
00348 }
00349 }
00350 return $sSeoUrl;
00351 }
00352
00361 protected function _prepareTitle( $sTitle, $blSkipTruncate = false )
00362 {
00363
00364 $sTitle = $this->encodeString( $sTitle );
00365
00366
00367 $sTitle = strip_tags( $sTitle );
00368 $sSeparator = self::$_sSeparator;
00369 $sPrefix = self::$_sPrefix;
00370
00371 foreach ( self::$_aReservedWords as $sWord ) {
00372
00373 $sTitle = preg_replace( array( "/(\s$sWord)$/i", "/^($sWord\s)/i", "/(\s$sWord\s)/i", "/^($sWord)$/i",
00374 "/(\/$sWord)$/i", "/^($sWord\/)/i", "/(\/$sWord\/)/i"),
00375 " $1{$sSeparator}{$sPrefix}{$sSeparator} ", $sTitle );
00376 }
00377
00378
00379 $sExt = '';
00380 $aMatched = array();
00381 if ( preg_match( '/\.html?$/i', $sTitle, $aMatched ) ) {
00382 $sExt = substr( $sTitle, 0 - strlen( $aMatched[0] ) );
00383 $sTitle = substr( $sTitle, 0, strlen( $sTitle ) - strlen( $aMatched[0] ) );
00384 }
00385
00386
00387 if ( !$blSkipTruncate && strlen( $sTitle ) > $this->_iIdLength ) {
00388
00389 if ( ( $iFirstSpace = strstr( substr( $sTitle, $this->_iIdLength ), ' ' ) ) ) {
00390 $sTitle = substr( $sTitle, 0, $this->_iIdLength + $iFirstSpace );
00391 }
00392 }
00393
00394
00395 $sRegExp = '/[^A-Za-z0-9'.preg_quote( self::$_sSeparator, '/').'\/]+/';
00396 $sTitle = trim( preg_replace( $sRegExp, self::$_sSeparator, $sTitle ), self::$_sSeparator );
00397
00398
00399 $sTitle .= $sExt;
00400
00401
00402 if ( !$sTitle ) {
00403 $sTitle = $this->_prepareTitle( self::$_sPrefix );
00404 }
00405
00406
00407 return preg_replace( array( '|//+|', '/' . preg_quote( self::$_sSeparator . self::$_sSeparator, '/' ) .'+/' ),
00408 array( '/', self::$_sSeparator ), $sTitle );
00409 }
00410
00411
00430 protected function _saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId = null, $blFixed = 0, $sKeywords = '', $sDescription = '', $sParams = null )
00431 {
00432 $oDb = oxDb::getDb( true );
00433 if ( $iShopId === null ) {
00434 $iShopId = $this->getConfig()->getShopId();
00435 }
00436
00437 $iShopId = $oDb->quote( $iShopId );
00438
00439 $sObjectId = $oDb->quote( $sObjectId );
00440 $sType = $oDb->quote( $sType );
00441
00442 $iLang = (int) $iLang;
00443
00444 $sStdUrl = $this->_trimUrl( $sStdUrl, $iLang );
00445 $sSeoUrl = $this->_trimUrl( $sSeoUrl, $iLang );
00446
00447 $sIdent = $this->_getSeoIdent( $sSeoUrl, $iLang );
00448
00449 $sStdUrl = $oDb->quote( $sStdUrl );
00450 $sSeoUrl = $oDb->quote( $sSeoUrl );
00451
00452 $blFixed = (int) $blFixed;
00453
00454 $sQ = "select oxfixed, oxexpired, ( oxstdurl like {$sStdUrl} and oxexpired != 2 ) as samestdurl, oxseourl like {$sSeoUrl} as sameseourl from oxseo where oxtype = {$sType} and oxobjectid = {$sObjectId} and oxshopid = {$iShopId} and oxlang = {$iLang} ";
00455 $sQ .= $sParams?" and oxparams = '{$sParams}' " : '';
00456 $sQ .= "limit 1";
00457
00458 $oRs = $oDb->execute( $sQ );
00459 if ( $oRs && $oRs->recordCount() > 0 && !$oRs->EOF ) {
00460
00461 if ( $oRs->fields['samestdurl'] && $oRs->fields['sameseourl'] && $oRs->fields['oxexpired'] ) {
00462
00463 return $oDb->execute( "update oxseo set oxexpired = 0 where oxtype = {$sType} and oxobjectid = {$sObjectId} and oxshopid = {$iShopId} and oxlang = {$iLang} limit 1" );
00464 } elseif ( $oRs->fields['oxexpired'] && !$oRs->fields['oxfixed'] ) {
00465
00466 $this->_copyToHistory( $sObjectId, $iShopId, $iLang, $sType );
00467 }
00468 }
00469
00470 $sKeywords = $sKeywords?$oDb->quote( htmlentities( $this->encodeString( strip_tags( $sKeywords ) ) ) ):"''";
00471 $sDescription = $sDescription?$oDb->quote( htmlentities( strip_tags( $sDescription ) ) ):"''";
00472
00473
00474 $sParams = $sParams ? $oDb->quote( $sParams ) :'""';
00475 $sQ = "replace into oxseo
00476 (oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype, oxfixed, oxexpired, oxkeywords, oxdescription, oxparams)
00477 values
00478 ( {$sObjectId}, '$sIdent', {$iShopId}, {$iLang}, {$sStdUrl}, {$sSeoUrl}, {$sType}, '$blFixed', '0', {$sKeywords}, {$sDescription}, $sParams )";
00479 return $oDb->execute( $sQ );
00480 }
00481
00492 protected function _trimUrl( $sUrl, $iLang )
00493 {
00494 $sUrl = str_replace( $this->getConfig()->getShopURL(), '', $sUrl );
00495
00496 if ( ( $sLangParam = $this->getLanguageParam( $iLang ) ) ) {
00497 $sUrl = preg_replace( "'^".preg_quote( $sLangParam, "'")."'", '', $sUrl );
00498 }
00499
00500 return preg_replace( '/(force_)?sid=[a-z0-9\.]+&?(amp;)?/i', '', $sUrl );
00501 }
00502
00510 public function encodeString( $sString )
00511 {
00512
00513 $sString = html_entity_decode( $sString );
00514
00515 $aReplaceChars = $this->getConfig()->getConfigParam( 'aSeoReplaceChars' );
00516 $sString = str_replace( array_keys( $aReplaceChars ), array_values( $aReplaceChars ), $sString );
00517
00518
00519 $aReplaceWhat = array( '/&/', '/"/', '/'/', '/</', '/>/' );
00520 return str_replace( $aReplaceWhat, '', $sString );
00521 }
00522
00530 public function setSeparator( $sSeparator = null )
00531 {
00532 self::$_sSeparator = $sSeparator;
00533 if ( !self::$_sSeparator ) {
00534 self::$_sSeparator = '-';
00535 }
00536 }
00537
00545 public function setPrefix( $sPrefix )
00546 {
00547 if ($sPrefix) {
00548 self::$_sPrefix = $sPrefix;
00549 } else {
00550 self::$_sPrefix = 'oxid';
00551 }
00552 }
00553
00561 public function setIdLength( $iIdlength = null )
00562 {
00563 if ( isset( $iIdlength ) ) {
00564 $this->_iIdLength = $iIdlength;
00565 }
00566 }
00567
00575 public function setReservedWords( $aReservedWords )
00576 {
00577 self::$_aReservedWords = array_merge( self::$_aReservedWords, $aReservedWords );
00578 }
00579
00580
00592 public function markAsExpired( $sId, $iShopId = null, $iExpStat = 1, $iLang = null, $sParams = null )
00593 {
00594 $sWhere = $sId ? "where oxobjectid = '{$sId}'" : '';
00595 $sWhere .= isset( $iShopId ) ? ( $sWhere ? " and oxshopid = '{$iShopId}'" : "where oxshopid = '{$iShopId}'" ) : '';
00596 $sWhere .= $iLang ? ( $sWhere ? " and oxlang = '{$iLang}'" : "where oxlang = '{$iLang}'" ) : '';
00597 $sWhere .= $sParams ? ( $sWhere ? " and {$sParams}" : "where {$sParams}" ) : '';
00598
00599 $sQ = "update oxseo set oxexpired = '{$iExpStat}' $sWhere ";
00600 oxDb::getDb()->execute( $sQ );
00601 }
00602
00616 protected function _getPageUri( $oObject, $sType, $sStdUrl, $sSeoUrl, $sParams, $iLang = null, $blFixed = false )
00617 {
00618 if (!isset($iLang)) {
00619 $iLang = $oObject->getLanguage();
00620 }
00621 $iShopId = $this->getConfig()->getShopId();
00622
00623
00624 if ( ( $sOldSeoUrl = $this->_loadFromDb( $sType, $oObject->getId(), $iLang, $iShopId, $sParams ) ) ) {
00625 if ( $sOldSeoUrl === $sSeoUrl ) {
00626 return $sSeoUrl;
00627 } else {
00628 $oDb = oxDb::getDb();
00629 $this->_copyToHistory( $oDb->quote( $oObject->getId() ), $oDb->quote( $iShopId ), $iLang, $oDb->quote( $sType ) );
00630 }
00631 }
00632
00633 $this->_saveToDb( $sType, $oObject->getId(), $sStdUrl, $sSeoUrl, $iLang, $iShopId, (int) $blFixed, '', '', $sParams );
00634
00635 return $sSeoUrl;
00636 }
00637
00647 public function encodeStaticUrls( $aStaticUrl, $iShopId, $iLang )
00648 {
00649 $oDb = oxDb::getDb();
00650 $sValues = '';
00651 $sOldObjectId = null;
00652
00653
00654 $sStdUrl = $this->_trimUrl( trim( $aStaticUrl['oxseo__oxstdurl'] ), $iLang );
00655 $sObjectId = $aStaticUrl['oxseo__oxobjectid'];
00656
00657 if ( !$sObjectId || $sObjectId == '-1' ) {
00658 $sObjectId = md5( strtolower ( $iShopId.$sStdUrl ) );
00659 } else {
00660
00661 $sOldObjectId = $sObjectId;
00662
00663
00664 if ( md5( strtolower ( $iShopId.$sStdUrl ) ) != $sObjectId ) {
00665 $sObjectId = md5( strtolower ( $iShopId.$sStdUrl ) );
00666 }
00667 }
00668
00669 foreach ( $aStaticUrl['oxseo__oxseourl'] as $iLang => $sSeoUrl ) {
00670
00671
00672 if ( ( $sSeoUrl = trim( $sSeoUrl ) ) ) {
00673 $sSeoUrl = $this->_prepareTitle( $this->_trimUrl( $sSeoUrl, $iLang ) );
00674 $sSeoUrl = $this->_getUniqueSeoUrl( $sSeoUrl, null, $sObjectId );
00675 }
00676
00677 if ( $sOldObjectId ) {
00678
00679 if ( !$oDb->getOne( "select ('{$sSeoUrl}' like oxseourl) & ('{$sStdUrl}' like oxstdurl) from oxseo where oxobjectid = '{$sOldObjectId}' and oxshopid = '{$iShopId}' and oxlang = '{$iLang}' " ) ) {
00680 $this->_copyToHistory( $oDb->quote( $sOldObjectId ), $oDb->quote( $iShopId ), $iLang, $oDb->quote( 'static' ), $sObjectId );
00681 }
00682 }
00683
00684 if ( !$sSeoUrl || !$sStdUrl ) {
00685 continue;
00686 }
00687
00688 $sIdent = $this->_getSeoIdent( $sSeoUrl, $iLang );
00689
00690 if ( $sValues ) {
00691 $sValues .= ', ';
00692 }
00693
00694 $sValues .= "( '{$sObjectId}', '{$sIdent}', '{$iShopId}', '{$iLang}', '$sStdUrl', '$sSeoUrl', 'static' )";
00695 }
00696
00697
00698 if ( $sOldObjectId ) {
00699 $oDb->execute( "delete from oxseo where oxobjectid in ( '{$sOldObjectId}', '{$sObjectId}' )" );
00700 }
00701
00702
00703 if ( $sValues ) {
00704
00705 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype ) values {$sValues} ";
00706 $oDb->execute( $sQ );
00707 }
00708
00709 return $sObjectId;
00710 }
00711
00719 public function copyStaticUrls( $iShopId )
00720 {
00721 $iBaseShopId = $this->getConfig()->getBaseShopId();
00722 if ( $iShopId != $iBaseShopId ) {
00723 foreach (array_keys(oxLang::getInstance()->getLanguageIds()) as $iLang) {
00724 $iLang = (int) $iLang;
00725 $sPrfx = $this->getLanguageParam($iLang, true);
00726 $sQ = "insert into oxseo ( oxobjectid, oxident, oxshopid, oxlang, oxstdurl, oxseourl, oxtype )
00727 select MD5( LOWER( CONCAT( '{$iShopId}', oxstdurl ) ) ), MD5( LOWER( CONCAT( '{$sPrfx}', oxseourl ) ) ),
00728 '$iShopId', oxlang, oxstdurl, oxseourl, oxtype from oxseo where oxshopid = '{$iBaseShopId}' and oxtype = 'static' and oxlang='$iLang' ";
00729 oxDb::getDb()->execute( $sQ );
00730 }
00731 }
00732 }
00733
00743 public function getStaticUrl( $sStdUrl, $iLang = null, $iShopId = null )
00744 {
00745 if (!isset($iShopId)) {
00746 $iShopId = oxConfig::getInstance()->getShopId();
00747 }
00748 if (!isset($iLang)) {
00749 $iLang = oxLang::getInstance()->getEditLanguage();
00750 }
00751
00752 $sFullUrl = '';
00753 if ( ( $sSeoUrl = $this->_getStaticUri( $sStdUrl, $iShopId, $iLang ) ) ) {
00754 $sFullUrl = $this->_getFullUrl( $sSeoUrl, $iLang );
00755 }
00756 return $sFullUrl;
00757 }
00758
00775 public function addSeoEntry( $sObjectId, $iShopId, $iLang, $sStdUrl, $sSeoUrl, $sType, $blFixed = 1, $sKeywords = '', $sDescription = '', $sParams = '' )
00776 {
00777 $sSeoUrl = $this->_getUniqueSeoUrl( $this->_prepareTitle( $this->_trimUrl( $sSeoUrl, $iLang ) ), null, $sObjectId );
00778 $this->_saveToDb( $sType, $sObjectId, $sStdUrl, $sSeoUrl, $iLang, $iShopId, $blFixed, $sKeywords, $sDescription, $sParams );
00779 }
00780
00791 public function deleteSeoEntry( $sObjectId, $iShopId, $iLang, $sType )
00792 {
00793 $sQ = "delete from oxseo where oxobjectid = '{$sObjectId}' and oxshopid = '{$iShopId}' and oxlang = '{$iLang}' and oxtype = '{$sType}' ";
00794 oxDb::getDb()->execute( $sQ );
00795 }
00796
00807 public function getMetaData( $sObjectId, $sMetaType, $iShopId = null, $iLang = null )
00808 {
00809 $iShopId = ( !isset( $iShopId ) ) ? oxConfig::getInstance()->getShopId():$iShopId;
00810 $iLang = ( !isset( $iLang ) ) ? oxLang::getInstance()->getTplLanguage():$iLang;
00811
00812 return oxDb::getDb()->getOne( "select {$sMetaType} from oxseo where oxobjectid = '{$sObjectId}' and oxshopid = '{$iShopId}' and oxlang = '{$iLang}' order by oxparams" );
00813 }
00814
00828 public function getDynamicUrl( $sStdUrl, $sSeoUrl, $iLang )
00829 {
00830 return $this->_getFullUrl( $this->_getDynamicUri( $sStdUrl, $sSeoUrl, $iLang ), $iLang );
00831 }
00832
00861 }