OXID eShop CE  4.8.12
 All Classes Files Functions Variables Pages
oxnavigationtree.php
Go to the documentation of this file.
1 <?php
2 
7 {
11  protected $_oDom = null;
12 
16  protected $_oInitialDom = null;
17 
23  protected $_sDynIncludeUrl = null;
24 
29  protected $_aSupportedExpathXmlEncodings = array( 'utf-8', 'utf-16', 'iso-8859-1', 'us-ascii' );
30 
40  protected function _cleanEmptyParents($oDom, $sParentXPath, $sChildXPath)
41  {
42  $oXPath = new DomXPath( $oDom );
43  $oNodeList = $oXPath->query( $sParentXPath );
44 
45  foreach ( $oNodeList as $oNode ) {
46  $sId = $oNode->getAttribute( 'id' );
47  $oChildList = $oXPath->query( "{$sParentXPath}[@id='$sId']/$sChildXPath" );
48  if (!$oChildList->length) {
49  $oNode->parentNode->removeChild( $oNode );
50  }
51  }
52  }
53 
61  protected function _addLinks( $oDom )
62  {
63  $sURL = 'index.php?'; // session parameters will be included later (after cache processor)
64  $oXPath = new DomXPath( $oDom );
65 
66  // building
67  $oNodeList = $oXPath->query( "//SUBMENU[@cl]" );
68  foreach ( $oNodeList as $oNode ) {
69  // fetching class
70  $sCl = $oNode->getAttribute( 'cl' );
71  $sCl = $sCl?"cl=$sCl":'';
72 
73  // fetching params
74  $sParam = $oNode->getAttribute( 'clparam' );
75  $sParam = $sParam?"&$sParam":'';
76 
77  // setting link
78  $oNode->setAttribute( 'link', "{$sURL}{$sCl}{$sParam}" );
79  }
80  }
81 
90  protected function _loadFromFile( $sMenuFile, $oDom )
91  {
92  $blMerge = false;
93  $oDomFile = new DomDocument();
94  $oDomFile->preserveWhiteSpace = false;
95  if ( !@$oDomFile->load( $sMenuFile ) ) {
96  $blMerge = true;
97  } elseif ( is_readable( $sMenuFile ) && ( $sXml = @file_get_contents( $sMenuFile ) ) ) {
98 
99  // looking for non supported character encoding
100  if ( getStr()->preg_match( "/encoding\=(.*)\?>/", $sXml, $aMatches ) !== 0 ) {
101  if ( isset( $aMatches[1] ) ) {
102  $sCurrEncoding = trim( $aMatches[1], "\"" );
103  if ( !in_array( strtolower( $sCurrEncoding ), $this->_aSupportedExpathXmlEncodings ) ) {
104  $sXml = str_replace( $aMatches[1], "\"UTF-8\"", $sXml );
105  $sXml = iconv( $sCurrEncoding, "UTF-8", $sXml );
106  }
107  }
108  }
109 
110  // load XML as string
111  if ( @$oDomFile->loadXml( $sXml ) ) {
112  $blMerge = true;
113  }
114  }
115 
116  if ( $blMerge ) {
117  $this->_merge( $oDomFile, $oDom );
118  }
119  }
120 
128  protected function _addDynLinks( $oDom )
129  {
130  $myConfig = $this->getConfig();
131  $myUtilsFile = oxRegistry::get("oxUtilsFile");
132 
133  $sURL = 'index.php?'; // session parameters will be included later (after cache processor)
134 
135  $oXPath = new DomXPath( $oDom );
136  $oNodeList = $oXPath->query( "//OXMENU[@type='dyn']/MAINMENU/SUBMENU" );
137 
138  foreach ( $oNodeList as $oNode ) {
139 
140  // fetching class
141  $sCl = $oNode->getAttribute( 'cl' );
142  $sCl = "cl=dynscreen&menu=$sCl";
143 
144  // fetching params
145  $sParam = $oNode->getAttribute( 'clparam' );
146  $sParam = $sParam?"&$sParam":'';
147 
148  // setting list node if its is not set yet
149  if ( !$oNode->getAttribute( 'list' ) ) {
150  $oNode->setAttribute( 'list', 'dynscreen_list' );
151  $oNode->setAttribute( 'listparam', 'menu='.$oNode->getAttribute( 'cl' ) );
152  }
153 
154  // setting link
155  $oNode->setAttribute( 'link', "{$sURL}{$sCl}{$sParam}" );
156 
157  // setting id
158  $oNode->parentNode->setAttribute( 'id', 'dyn_menu' );
159 
160  // setting id to its parent
161 
162  // fetching class
163  $sFile = $oNode->getAttribute( 'cl' );
164 
165  // always display the "about" tab no matter what licence
166 
167  if ( $myUtilsFile->checkFile( "{$this->_sDynIncludeUrl}pages/{$sFile}_about.php" ) ) {
168  $oTabElem = new DOMElement( 'TAB' );
169  $oNode->appendChild( $oTabElem );
170  $oTabElem->setAttribute( 'external', 'true' );
171  $oTabElem->setAttribute( 'location', "{$this->_sDynIncludeUrl}pages/{$sFile}_about.php" );
172  $oTabElem->setAttribute( 'id', 'dyn_about' );
173  }
174 
175  // checking for technics page
176  if ( $myUtilsFile->checkFile( "{$this->_sDynIncludeUrl}pages/{$sFile}_technics.php" ) ) {
177  $oTabElem = new DOMElement( 'TAB' );
178  $oNode->appendChild( $oTabElem );
179  $oTabElem->setAttribute( 'external', 'true' );
180  $oTabElem->setAttribute( 'location', "{$this->_sDynIncludeUrl}pages/{$sFile}_technics.php" );
181  $oTabElem->setAttribute( 'id', 'dyn_interface' );
182  }
183 
184  // checking for setup page
185  if ( file_exists( $myConfig->getConfigParam( 'sShopDir' )."/application/controllers/admin/{$sFile}.php" ) ) {
186  $oTabElem = new DOMElement( 'TAB' );
187  $oNode->appendChild( $oTabElem );
188  $oTabElem->setAttribute( 'id', 'dyn_interface' );
189  $oTabElem->setAttribute( 'cl', $sFile );
190  }
191  }
192  }
193 
201  protected function _sessionizeLocalUrls( $oDom )
202  {
203  $sURL = $this->_getAdminUrl();
204  $oXPath = new DomXPath( $oDom );
205  $oStr = getStr();
206  foreach (array('url', 'link') as $sAttrType) {
207  foreach ( $oXPath->query( "//OXMENU//*[@$sAttrType]" ) as $oNode ) {
208  $sLocalUrl = $oNode->getAttribute( $sAttrType );
209  if (strpos($sLocalUrl, 'index.php?') === 0) {
210  $sLocalUrl = $oStr->preg_replace('#^index.php\?#', $sURL, $sLocalUrl);
211  $oNode->setAttribute( $sAttrType, $sLocalUrl );
212  }
213  }
214  }
215  }
216 
224  protected function _checkRights( $oDom )
225  {
226  $oXPath = new DomXPath( $oDom );
227  $oNodeList = $oXPath->query( '//*[@rights or @norights]' );
228 
229  foreach ( $oNodeList as $oNode ) {
230  // only allowed modules/user rights or so
231  if ( ( $sReq = $oNode->getAttribute( 'rights' ) ) ) {
232  $aPerm = explode( ',', $sReq );
233  foreach ( $aPerm as $sPerm ) {
234  if ( $sPerm && !$this->_hasRights( $sPerm ) ) {
235  $oNode->parentNode->removeChild( $oNode );
236  }
237  }
238  // not allowed modules/user rights or so
239  } elseif ( ( $sNoReq = $oNode->getAttribute( 'norights' ) ) ) {
240  $aPerm = explode( ',', $sNoReq );
241  foreach ( $aPerm as $sPerm ) {
242  if ( $sPerm && $this->_hasRights( $sPerm ) ) {
243  $oNode->parentNode->removeChild( $oNode );
244  }
245  }
246  }
247  }
248  }
249 
257  protected function _checkGroups( $oDom )
258  {
259  $oXPath = new DomXPath( $oDom );
260  $oNodeList = $oXPath->query( "//*[@nogroup or @group]" );
261 
262  foreach ( $oNodeList as $oNode ) {
263  // allowed only for groups
264  if ( ( $sReq = $oNode->getAttribute('group') ) ) {
265  $aPerm = explode( ',', $sReq );
266  foreach ( $aPerm as $sPerm ) {
267  if ( $sPerm && !$this->_hasGroup( $sPerm ) ) {
268  $oNode->parentNode->removeChild($oNode);
269  }
270  }
271  // not allowed for groups
272  } elseif ( ( $sNoReq = $oNode->getAttribute('nogroup') ) ) {
273  $aPerm = explode( ',', $sNoReq );
274  foreach ( $aPerm as $sPerm ) {
275  if ( $sPerm && $this->_hasGroup( $sPerm ) ) {
276  $oNode->parentNode->removeChild($oNode);
277  }
278  }
279  }
280  }
281  }
282 
290  protected function _checkDemoShopDenials( $oDom )
291  {
292  if (!$this->getConfig()->isDemoShop()) {
293  // nothing to check for non demo shop
294  return;
295  }
296 
297  $oXPath = new DomXPath( $oDom );
298  $oNodeList = $oXPath->query( "//*[@disableForDemoShop]" );
299  foreach ( $oNodeList as $oNode ) {
300  if ( $oNode->getAttribute('disableForDemoShop') ) {
301  $oNode->parentNode->removeChild($oNode);
302  }
303  }
304  }
305 
314  protected function _copyAttributes( $oDomElemTo, $oDomElemFrom )
315  {
316  foreach ( $oDomElemFrom->attributes as $oAttr ) {
317  $oDomElemTo->setAttribute( $oAttr->nodeName, $oAttr->nodeValue );
318  }
319  }
320 
332  protected function _mergeNodes( $oDomElemTo, $oDomElemFrom, $oXPathTo, $oDomDocTo, $sQueryStart )
333  {
334  foreach ( $oDomElemFrom->childNodes as $oFromNode ) {
335  if ( $oFromNode->nodeType === XML_ELEMENT_NODE ) {
336 
337  $sFromAttrName = $oFromNode->getAttribute( 'id' );
338  $sFromNodeName = $oFromNode->tagName;
339 
340  // find current item
341  $sQuery = "{$sQueryStart}/{$sFromNodeName}[@id='{$sFromAttrName}']";
342  $oCurNode = $oXPathTo->query( $sQuery );
343 
344  // if not found - append
345  if ( $oCurNode->length == 0 ) {
346  $oDomElemTo->appendChild( $oDomDocTo->importNode( $oFromNode, true ) );
347  } else {
348 
349  $oCurNode = $oCurNode->item( 0 );
350 
351  // if found copy all attributes and check childnodes
352  $this->_copyAttributes( $oCurNode, $oFromNode );
353 
354  if ( $oFromNode->childNodes->length ) {
355  $this->_mergeNodes( $oCurNode, $oFromNode, $oXPathTo, $oDomDocTo, $sQuery );
356  }
357  }
358  }
359  }
360  }
361 
370  protected function _merge( $oDomNew, $oDom )
371  {
372  $oXPath = new DOMXPath( $oDom );
373  $this->_mergeNodes( $oDom->documentElement, $oDomNew->documentElement, $oXPath, $oDom, '/OX' );
374  }
375 
385  public function getTabs( $sId, $iAct, $blSetActive = true )
386  {
387  $oXPath = new DOMXPath( $this->getDomXml() );
388  //$oNodeList = $oXPath->query( "//SUBMENU[@cl='$sId' or @list='$sId']/TAB | //SUBMENU/../TAB[@cl='$sId']" );
389  $oNodeList = $oXPath->query( "//SUBMENU[@cl='$sId']/TAB | //SUBMENU[@list='$sId']/TAB | //SUBMENU/../TAB[@cl='$sId']" );
390 
391  $iAct = ( $iAct > $oNodeList->length )?( $oNodeList->length - 1 ):$iAct;
392 
393  if ( $blSetActive ) {
394  foreach ( $oNodeList as $iPos => $oNode ) {
395  if ( $iPos == $iAct ) {
396  // marking active node
397  $oNode->setAttribute( 'active', 1 );
398  }
399  }
400  }
401 
402  return $oNodeList;
403  }
404 
413  public function getActiveTab( $sId, $iAct )
414  {
415  $sTab = null;
416  $oNodeList = $this->getTabs( $sId, $iAct, false );
417  $iAct = ( $iAct > $oNodeList->length )?( $oNodeList->length - 1 ):$iAct;
418  if ( $oNodeList->length && ( $oNode = $oNodeList->item( $iAct ) ) ) {
419  $sTab = $oNode->getAttribute( 'cl' );
420  }
421 
422  return $sTab;
423  }
424 
432  public function getBtn( $sClass )
433  {
434  $oButtons = null;
435  $oXPath = new DOMXPath($this->getDomXml());
436  $oNodeList = $oXPath->query("//TAB[@cl='$sClass']/../BTN");
437  if ($oNodeList->length) {
438  $oButtons = new stdClass();
439  foreach ($oNodeList as $oNode) {
440  $sBtnID = $oNode->getAttribute('id');
441  $oButtons->$sBtnID = 1;
442  }
443  }
444  return $oButtons;
445  }
446 
452  protected function _getMenuFiles()
453  {
454  $myConfig = $this->getConfig();
455  $myOxUtlis = oxRegistry::getUtils();
456 
457  $sFullAdminDir = getShopBasePath() . 'application/views/admin';
458  $sMenuFile = "/menu.xml";
459 
460  $sTmpDir = $myConfig->getConfigParam( 'sCompileDir' );
461  $sDynLang = $this->_getDynMenuLang();
462  $sLocalDynPath = "{$sTmpDir}{$sDynLang}_dynscreen.xml";
463 
464 
465  // including std file
466  if ( file_exists( $sFullAdminDir.$sMenuFile ) ) {
467  $aFilesToLoad[] = $sFullAdminDir.$sMenuFile;
468  }
469 
470  // including custom file
471  if ( file_exists( "$sFullAdminDir/user.xml" ) ) {
472  $aFilesToLoad[] = "$sFullAdminDir/user.xml";
473  }
474 
475  // including module menu files
476  $sPath = getShopBasePath();
477  $oModulelist = oxNew('oxmodulelist');
478  $aActiveModuleInfo = $oModulelist->getActiveModuleInfo();
479  if (is_array($aActiveModuleInfo)) {
480  foreach ( $aActiveModuleInfo as $sModulePath ) {
481  $sFullPath = $sPath. "modules/" . $sModulePath;
482  // missing file/folder?
483  if ( is_dir( $sFullPath ) ) {
484  // including menu file
485  $sMenuFile = $sFullPath . "/menu.xml";
486  if ( file_exists( $sMenuFile ) && is_readable( $sMenuFile ) ) {
487  $aFilesToLoad[] = $sMenuFile;
488  }
489  }
490  }
491  }
492 
493  $blLoadDynContents = $myConfig->getConfigParam( 'blLoadDynContents' );
494  $sShopCountry = $myConfig->getConfigParam( 'sShopCountry' );
495 
496  // including dyn menu file
497  $sDynPath = null;
498 
499  if ( $blLoadDynContents ) {
500  if ( $sShopCountry ) {
501  $sRemoteDynUrl = $this->_getDynMenuUrl( $sDynLang, $blLoadDynContents );
502 
503  // loading remote file from server only once
504  $blLoadRemote = oxSession::getVar( "loadedremotexml" );
505 
506  // very basic check if its valid xml file
507  if ( ( !isset( $blLoadRemote ) || $blLoadRemote ) && ( $sDynPath = $myOxUtlis->getRemoteCachePath( $sRemoteDynUrl, $sLocalDynPath ) ) ) {
508  $sDynPath = $this->_checkDynFile( $sDynPath );
509  }
510 
511  // caching last load state
512  oxSession::setVar( "loadedremotexml", $sDynPath ? true : false );
513  }
514  } else {
515  if ( $sShopCountry ) {
516  //non international country
517  }
518  }
519 
520  // loading dynpages
521  if ( $sDynPath ) {
522  $aFilesToLoad[] = $sDynPath;
523  }
524  return $aFilesToLoad;
525  }
526 
534  protected function _checkDynFile( $sDynFilePath )
535  {
536  $sDynFile = null;
537  if ( file_exists( $sDynFilePath ) ) {
538  $sLine = null;
539  if ( ( $rHandle = @fopen($sDynFilePath, 'r' ) ) ) {
540  $sLine = stream_get_line( $rHandle, 100, "?>");
541  fclose( $rHandle );
542 
543  // checking xml file header
544  if ( $sLine && stripos( $sLine, '<?xml' ) !== false ) {
545  $sDynFile = $sDynFilePath;
546  }
547  }
548 
549  // cleanup ..
550  if ( !$sDynFile ) {
551  @unlink( $sDynFilePath );
552  }
553  }
554 
555  return $sDynFile;
556  }
557 
569  protected function _processCachedFile( $sCacheContents )
570  {
571  return $sCacheContents;
572  }
573 
579  protected function _getInitialDom()
580  {
581  if ( $this->_oInitialDom === null ) {
582  $myOxUtlis = oxRegistry::getUtils();
583 
584  if ( is_array( $aFilesToLoad = $this->_getMenuFiles() ) ) {
585 
586  // now checking if xml files are newer than cached file
587  $blReload = false;
588  $sDynLang = $this->_getDynMenuLang();
589 
590  $sShopId = $this->getConfig()->getActiveShop()->getShopId();
591  $sCacheName = 'menu_' . $sDynLang . $sShopId . '_xml';
592  $sCacheFile = $myOxUtlis->getCacheFilePath( $sCacheName );
593  $sCacheContents = $myOxUtlis->fromFileCache( $sCacheName );
594  if ( $sCacheContents && file_exists( $sCacheFile ) && ( $iCacheModTime = filemtime( $sCacheFile ) ) ) {
595  foreach ( $aFilesToLoad as $sDynPath ) {
596  if ( $iCacheModTime < filemtime( $sDynPath ) ) {
597  $blReload = true;
598  }
599  }
600  } else {
601  $blReload = true;
602  }
603 
604  $this->_oInitialDom = new DOMDocument();
605  if ( $blReload ) {
606  // fully reloading and building pathes
607  $this->_oInitialDom->appendChild( new DOMElement( 'OX' ) );
608 
609  foreach ( $aFilesToLoad as $sDynPath ) {
610  $this->_loadFromFile( $sDynPath, $this->_oInitialDom );
611  }
612 
613  // adds links to menu items
614  $this->_addLinks( $this->_oInitialDom );
615 
616  // adds links to dynamic parts
617  $this->_addDynLinks( $this->_oInitialDom );
618 
619  // writing to cache
620  $myOxUtlis->toFileCache( $sCacheName, $this->_oInitialDom->saveXML() );
621  } else {
622  $sCacheContents = $this->_processCachedFile($sCacheContents);
623  // loading from cached file
624  $this->_oInitialDom->preserveWhiteSpace = false;
625  $this->_oInitialDom->loadXML( $sCacheContents );
626  }
627 
628  // add session params
629  $this->_sessionizeLocalUrls( $this->_oInitialDom );
630  }
631  }
632  return $this->_oInitialDom;
633  }
634 
640  public function getDomXml()
641  {
642  if ( $this->_oDom === null ) {
643  $this->_oDom = clone $this->_getInitialDom();
644 
645  // removes items denied by user group
646  $this->_checkGroups( $this->_oDom );
647 
648  // removes items denied by user rights
649  $this->_checkRights( $this->_oDom );
650 
651  // check config params
652  $this->_checkDemoShopDenials( $this->_oDom );
653 
654 
655  $this->_cleanEmptyParents( $this->_oDom, '//SUBMENU[@id][@list]', 'TAB');
656  $this->_cleanEmptyParents( $this->_oDom, '//MAINMENU[@id]', 'SUBMENU');
657  }
658 
659  return $this->_oDom;
660  }
661 
669  public function getListNodes( $aNodes )
670  {
671  $oXPath = new DOMXPath( $this->getDomXml() );
672  $oNodeList = $oXPath->query( "//SUBMENU[@cl='".implode("' or @cl='", $aNodes)."']" );
673 
674  return ( $oNodeList->length ) ? $oNodeList : null;
675  }
676 
684  public function markNodeActive( $sNodeId )
685  {
686  $oXPath = new DOMXPath( $this->getDomXml() );
687  $oNodeList = $oXPath->query( "//*[@cl='{$sNodeId}' or @list='{$sNodeId}']" );
688 
689  if ( $oNodeList->length ) {
690  foreach ( $oNodeList as $oNode ) {
691  // special case for external resources
692  $oNode->setAttribute( 'active', 1 );
693  $oNode->parentNode->setAttribute( 'active', 1 );
694  }
695  }
696 
697  }
698 
706  public function getListUrl( $sId )
707  {
708  $sUrl = null;
709  $oXPath = new DOMXPath( $this->getDomXml() );
710  $oNodeList = $oXPath->query( "//SUBMENU[@cl='{$sId}']" );
711  if ( $oNodeList->length && ( $oNode = $oNodeList->item( 0 ) ) ) {
712  $sCl = $oNode->getAttribute('list');
713  $sCl = $sCl?"cl=$sCl":'';
714 
715  $sParams = $oNode->getAttribute('listparam');
716  $sParams = $sParams?"&$sParams":'';
717 
718  $sUrl = "{$sCl}{$sParams}";
719  }
720  return $sUrl;
721  }
722 
731  public function getEditUrl( $sId, $iActTab )
732  {
733  $sUrl = null;
734  $oXPath = new DOMXPath( $this->getDomXml() );
735  $oNodeList = $oXPath->query( "//SUBMENU[@cl='{$sId}']/TAB" );
736 
737  $iActTab = ( $iActTab > $oNodeList->length )?( $oNodeList->length - 1 ) : $iActTab;
738  if ( $oNodeList->length && ( $oActTab = $oNodeList->item( $iActTab ) ) ) {
739  // special case for external resources
740  if ( $oActTab->getAttribute( 'external' ) ) {
741  $sUrl = $oActTab->getAttribute( 'location' );
742  } else {
743  $sCl = $oActTab->getAttribute( 'cl' );
744  $sCl = $sCl?"cl={$sCl}":'';
745 
746  $sParams = $oActTab->getAttribute( 'clparam' );
747  $sParams = $sParams?"&{$sParams}":'';
748 
749  $sUrl = "{$sCl}{$sParams}";
750  }
751  }
752  return $sUrl;
753  }
754 
760  protected function _getAdminUrl()
761  {
762  $myConfig = $this->getConfig();
763 
764  if ( ( $sAdminSslUrl = $myConfig->getConfigParam( 'sAdminSSLURL' ) ) ) {
765  $sURL = trim( $sAdminSslUrl, '/' );
766  } else {
767  $sURL = trim( $myConfig->getConfigParam( 'sShopURL' ), '/' ).'/admin';
768  }
769  return oxRegistry::get("oxUtilsUrl")->processUrl("{$sURL}/index.php", false);
770  }
771 
779  protected function _hasRights( $sRights )
780  {
781  return $this->getUser()->oxuser__oxrights->value == $sRights;
782  }
783 
791  protected function _hasGroup( $sGroupId )
792  {
793  return $this->getUser()->inGroup( $sGroupId );
794  }
795 
803  public function getClassId( $sClassName )
804  {
805  $sClassId = null;
806 
807  $oXPath = new DOMXPath( $this->_getInitialDom() );
808  $oNodeList = $oXPath->query( "//*[@cl='{$sClassName}' or @list='{$sClassName}']" );
809  if ( $oNodeList->length && ( $oFirstItem = $oNodeList->item( 0 ) ) ) {
810  $sClassId = $oFirstItem->getAttribute( 'id' );
811  }
812 
813  return $sClassId;
814  }
815 
816 
825  protected function _getDynMenuUrl( $iLang, $blLoadDynContents )
826  {
827  if ( !$blLoadDynContents ) {
828  // getting dyn info from oxid server is off, so getting local menu path
829  $sFullAdminDir = getShopBasePath() . 'application/views/admin';
830  $sUrl = $sFullAdminDir . "/dynscreen_local.xml";
831  } else {
832  $oAdminView = oxNew( 'oxadminview' );
833  $this->_sDynIncludeUrl = $oAdminView->getServiceUrl( $iLang );
834  $sUrl .= $this->_sDynIncludeUrl . "menue/dynscreen.xml";
835  }
836 
837  return $sUrl;
838  }
839 
845  protected function _getDynMenuLang()
846  {
847  $myConfig = $this->getConfig();
848  $oLang = oxRegistry::getLang();
849 
850  $iDynLang = $myConfig->getConfigParam( 'iDynInterfaceLanguage' );
851  $iDynLang = isset( $iDynLang )?$iDynLang:( $oLang->getTplLanguage() );
852 
853  $aLanguages = $oLang->getLanguageArray();
854  $sLangAbr = $aLanguages[$iDynLang]->abbr;
855 
856  return $sLangAbr;
857  }
858 }