OXID eShop CE  4.8.12
 All Classes Files Functions Variables Pages
oxutilsobject.php
Go to the documentation of this file.
1 <?php
2 
7 {
8 
12  const CACHE_FILE_PREFIX = "config";
13 
19  protected $_aClassNameCache = array();
20 
26  protected static $_aLoadedArticles = array();
27 
33  protected static $_aInstanceCache = array();
34 
40  protected static $_aModuleVars = array();
41 
47  protected static $_aClassInstances = array();
48 
54  private static $_instance = null;
55 
61  public static function getInstance()
62  {
63  // disable caching for test modules
64  if ( defined( 'OXID_PHP_UNIT' ) ) {
65  self::$_instance = null;
66  }
67 
68  if ( !self::$_instance instanceof oxUtilsObject ) {
69 
70  // allow modules
71  $oUtilsObject = new oxUtilsObject();
72  self::$_instance = $oUtilsObject->oxNew( 'oxUtilsObject' );
73  }
74  return self::$_instance;
75  }
76 
86  public static function setClassInstance( $sClassName, $oInstance )
87  {
88  $sClassName = strtolower( $sClassName );
89  self::$_aClassInstances[$sClassName] = $oInstance;
90  }
91 
97  public static function resetClassInstances()
98  {
99  self::$_aClassInstances = array();
100  }
101 
109  public static function resetModuleVars()
110  {
111  self::$_aModuleVars = array();
112 
113  $sMask = oxRegistry::get("oxConfigFile")->getVar("sCompileDir") . "/" . self::CACHE_FILE_PREFIX . ".*.txt" ;
114  $aFiles = glob( $sMask );
115  if ( is_array( $aFiles ) ) {
116  foreach ( $aFiles as $sFile ) {
117  if (is_file($sFile)) {
118  @unlink($sFile);
119  }
120  }
121  }
122  }
123 
134  public function oxNew( $sClassName )
135  {
136  $aArgs = func_get_args();
137  array_shift( $aArgs );
138  $iArgCnt = count( $aArgs );
139  $blCacheObj = $iArgCnt < 2;
140  $sClassName = strtolower( $sClassName );
141 
142  if ( isset( self::$_aClassInstances[$sClassName] ) ) {
143  return self::$_aClassInstances[$sClassName];
144  }
145  if ( !defined( 'OXID_PHP_UNIT' ) && $blCacheObj ) {
146  $sCacheKey = ( $iArgCnt )?$sClassName.md5( serialize( $aArgs ) ):$sClassName;
147  if ( isset( self::$_aInstanceCache[$sCacheKey] ) ) {
148  return clone self::$_aInstanceCache[$sCacheKey];
149  }
150  }
151 
152  // performance
153  if ( !defined( 'OXID_PHP_UNIT' ) && isset( $this->_aClassNameCache[$sClassName] ) ) {
154  $sActionClassName = $this->_aClassNameCache[$sClassName];
155  } else {
156  $sActionClassName = $this->getClassName( $sClassName );
157  //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
158  if ( !class_exists( $sActionClassName ) ) {
162  $oEx = oxNew( "oxSystemComponentException" );
163  $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
164  $oEx->setComponent($sClassName);
165  $oEx->debugOut();
166  throw $oEx;
167  }
168  // performance
169  $this->_aClassNameCache[$sClassName] = $sActionClassName;
170  }
171 
172  $oActionObject = $this->_getObject( $sActionClassName, $iArgCnt, $aArgs );
173  if ( $blCacheObj && $oActionObject instanceof oxBase ) {
174  self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
175  }
176 
177  return $oActionObject;
178  }
179 
192  protected function _getObject( $sClassName, $iArgCnt, $aParams )
193  {
194  // dynamic creation (if parameter count < 4) gives more performance for regular objects
195  switch( $iArgCnt ) {
196  case 0:
197  $oObj = new $sClassName();
198  break;
199  case 1:
200  $oObj = new $sClassName( $aParams[0] );
201  break;
202  case 2:
203  $oObj = new $sClassName( $aParams[0], $aParams[1] );
204  break;
205  case 3:
206  $oObj = new $sClassName( $aParams[0], $aParams[1], $aParams[2] );
207  break;
208  default:
209  try {
210  // unlimited constructor arguments support
211  $oRo = new ReflectionClass( $sClassName );
212  $oObj = $oRo->newInstanceArgs( $aParams );
213  } catch ( ReflectionException $oRefExcp ) {
214  // something went wrong?
218  $oEx = oxNew( "oxSystemComponentException" );
219  $oEx->setMessage( $oRefExcp->getMessage() );
220  $oEx->setComponent( $sClassName );
221  $oEx->debugOut();
222  throw $oEx;
223  }
224  }
225 
226  return $oObj;
227  }
228 
239  public function oxNewArticle( $sOxID, $aProperties = array())
240  {
241  if ( $sOxID && isset( self::$_aLoadedArticles[$sOxID] ) ) {
242  return self::$_aLoadedArticles[$sOxID];
243  }
244 
245  $oActionObject = $this->oxNew( 'oxarticle' );
246 
247  // adding object prioperties
248  foreach ( $aProperties as $sPropertyName => $sPropertyVal ) {
249  $oActionObject->$sPropertyName = $sPropertyVal;
250  }
251 
252  $oActionObject->load( $sOxID );
253 
254  self::$_aLoadedArticles[$sOxID] = $oActionObject;
255  return $oActionObject;
256  }
257 
265  public function resetInstanceCache($sClassName = null)
266  {
267  if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
268  unset(self::$_aInstanceCache[$sClassName]);
269  return;
270  }
271 
272  //looping due to possible memory "leak".
273  if (is_array(self::$_aInstanceCache)) {
274  foreach (self::$_aInstanceCache as $sKey => $oInstance) {
275  unset(self::$_aInstanceCache[$sKey]);
276  }
277  }
278 
279  self::$_aInstanceCache = array();
280  }
281 
287  public function generateUId()
288  {
289  return /*substr( $this->getSession()->getId(), 0, 3 ) . */ substr( md5( uniqid( '', true ).'|'.microtime() ), 0, 32 );
290  }
291 
292 
293 
301  public function getClassName( $sClassName )
302  {
303  //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
304  $aModules = $this->getModuleVar('aModules');
305  $aClassChain = array();
306 
307 
308  if (is_array( $aModules )) {
309 
310  $aModules = array_change_key_case( $aModules );
311 
312  if ( array_key_exists( $sClassName, $aModules ) ) {
313  //multiple inheritance implementation
314  //in case we have multiple modules:
315  //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
316  $aClassChain = explode( "&", $aModules[$sClassName] );
317  $aClassChain = $this->_getActiveModuleChain( $aClassChain );
318  }
319 
320  if (count($aClassChain)) {
321  $sParent = $sClassName;
322 
323  //security: just preventing string termination
324  $sParent = str_replace(chr(0), '', $sParent);
325 
326  //building middle classes if needed
327  $sClassName = $this->_makeSafeModuleClassParents( $aClassChain, $sParent );
328  }
329  }
330 
331  // check if there is a path, if yes, remove it
332  $sClassName = basename( $sClassName );
333 
334  return $sClassName;
335  }
336 
344  protected function _getActiveModuleChain( $aClassChain )
345  {
346  $aDisabledModules = $this->getModuleVar( 'aDisabledModules' );
347  $aModulePaths = $this->getModuleVar( 'aModulePaths' );
348 
349  if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
350  foreach ($aDisabledModules as $sId) {
351  $sPath = $aModulePaths[$sId];
352  if (!isset($sPath)) {
353  $sPath = $sId;
354  }
355  foreach ( $aClassChain as $sKey => $sModuleClass ) {
356  if ( strpos($sModuleClass, $sPath."/" ) === 0 ) {
357  unset( $aClassChain[$sKey] );
358  }
359  // If module consists of one file without own dir (getting module.php as id, instead of module)
360  elseif ( strpos( $sPath, "." ) ) {
361  if ( strpos( $sPath, strtolower( $sModuleClass ) ) === 0 ) {
362  unset( $aClassChain[$sKey] );
363  }
364  }
365  }
366  }
367  }
368 
369  return $aClassChain;
370  }
371 
379  protected function _disableModule( $sModule )
380  {
384  $oModule = oxNew("oxModule");
385  $sModuleId = $oModule->getIdByPath($sModule);
386  $oModule->deactivate($sModuleId);
387  }
388 
399  protected function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
400  {
401  $sParent = $sBaseModule;
402  $sClassName = $sBaseModule;
403 
404  //building middle classes if needed
405  foreach ($aClassChain as $sModule) {
406  //creating middle classes
407  //e.g. class suboutput1_parent extends oxoutput {}
408  // class suboutput2_parent extends suboutput1 {}
409  //$sModuleClass = $this->getClassName($sModule);
410 
411  //security: just preventing string termination
412  $sModule = str_replace(chr(0), '', $sModule);
413 
414  //get parent and module class names from sub/suboutput2
415  $sModuleClass = basename($sModule);
416 
417  if ( !class_exists( $sModuleClass, false ) ) {
418  $sParentClass = basename($sParent);
419  $sModuleParentClass = $sModuleClass."_parent";
420 
421  //initializing middle class
422  if (!class_exists($sModuleParentClass, false)) {
423  // If possible using alias instead if eval (since php 5.3).
424  if (function_exists('class_alias')) {
425  class_alias($sParentClass, $sModuleParentClass);
426  } else {
427  eval("abstract class $sModuleParentClass extends $sParentClass {}");
428  }
429  }
430  $sParentPath = oxRegistry::get( "oxConfigFile" )->getVar( "sShopDir" ) . "/modules/".$sModule.".php";
431 
432  //including original file
433  if ( file_exists( $sParentPath ) ) {
434  include_once $sParentPath;
435  } elseif ( !class_exists( $sModuleClass ) ) {
436  // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
437  // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
438  if ( $sParentClass == "oxconfig" ) {
439  $oConfig = $this->_getObject( "oxconfig", 0, null );
440  oxRegistry::set( "oxconfig", $oConfig );
441  }
442 
443  // disable module if extended class is not found
444  $blDisableModuleOnError = !oxRegistry::get( "oxConfigFile" )->getVar( "blDoNotDisableModuleOnError" );
445  if ( $blDisableModuleOnError ) {
446  $this->_disableModule( $sModule );
447  } else {
448  //to avoid problems with unitest and only throw a exception if class does not exists MAFI
449  $oEx = oxNew( "oxSystemComponentException" );
450  $oEx->setMessage("EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND");
451  $oEx->setComponent( $sModuleClass );
452  throw $oEx;
453  }
454  continue;
455  }
456  }
457  $sParent = $sModule;
458  $sClassName = $sModule;
459  }
460 
461  //returning the last module from the chain
462  return $sClassName;
463  }
464 
470  public function getShopId()
471  {
472  return 'oxbaseshop';
473  }
474 
484  public function getModuleVar( $sModuleVarName )
485  {
486  //static cache
487  if ( isset(self::$_aModuleVars[$sModuleVarName]) ) {
488  return self::$_aModuleVars[$sModuleVarName];
489  }
490 
491  //first try to get it from cache
492  //we do not use any of our cache APIs, as we want to prevent any class dependencies here
493  $aValue = $this->_getFromCache( $sModuleVarName );
494 
495  if ( is_null( $aValue ) ) {
496  $aValue = $this->_getModuleVarFromDB($sModuleVarName);
497  $this->_setToCache( $sModuleVarName, $aValue);
498  }
499 
500  //static cache
501  self::$_aModuleVars[$sModuleVarName] = $aValue;
502 
503  return $aValue;
504  }
505 
514  public function setModuleVar( $sModuleVarName, $aValues )
515  {
516  if ( is_null( $aValues) ) {
517  self::$_aModuleVars = null;
518  } else {
519  self::$_aModuleVars[$sModuleVarName] = $aValues;
520  }
521 
522  $this->_setToCache($sModuleVarName, $aValues);
523  }
524 
530  protected function _getConfKey()
531  {
532  $sFileName = dirname( __FILE__ ) . "/oxconfk.php";
533  $sCfgFile = new oxConfigFile( $sFileName );
534  return $sCfgFile->getVar("sConfigKey");
535  }
536 
542  protected function _getShopUrlMap( )
543  {
544 
545  //get from static cache
546  if (isset( self::$_aModuleVars["urlMap"] )) {
547  return self::$_aModuleVars["urlMap"];
548  }
549 
550  //get from file cache
551  $aMap = $this->_getFromCache("urlMap", false);
552  if (!is_null($aMap)) {
553  self::$_aModuleVars["urlMap"] = $aMap;
554  return $aMap;
555  }
556 
557  $aMap = array();
558 
559  $oDb = oxDb::getDb();
560  $sConfKey = $this->_getConfKey();
561 
562  $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) as oxvarvalue ".
563  "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
564 
565  $oRs = $oDb->select($sSelect, false, false);
566 
567  if ( $oRs && $oRs->recordCount() > 0) {
568  while ( !$oRs->EOF ) {
569  $iShp = (int) $oRs->fields[0];
570  $sVar = $oRs->fields[1];
571  $sURL = $oRs->fields[2];
572 
573  if ($sVar == 'aLanguageURLs') {
574  $aUrls = unserialize($sURL);
575  if (is_array($aUrls) && count($aUrls)) {
576  $aUrls = array_filter($aUrls);
577  $aUrls = array_fill_keys($aUrls, $iShp);
578  $aMap = array_merge($aMap, $aUrls);
579  }
580  } elseif ($sURL) {
581  $aMap[$sURL] = $iShp;
582  }
583 
584  $oRs->moveNext();
585  }
586  }
587 
588  //save to cache
589  $this->_setToCache("urlMap", $aMap, false);
590  self::$_aModuleVars["urlMap"] = $aMap;
591 
592  return $aMap;
593  }
594 
600  protected function _getCacheDir()
601  {
602  $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
603  return $sDir;
604  }
605 
614  protected function _getCacheFileName($sModuleVarName, $sShopId = null)
615  {
616  if (is_null($sShopId)) {
617  $sShopId = $this->getShopId();
618  }
619 
620  $sDir = $this->_getCacheDir();
621  $sVar = strtolower( basename ($sModuleVarName) );
622  $sShop = strtolower( basename ($sShopId) );
623 
624  $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
625 
626  return $sFileName;
627  }
628 
636  protected function _getModuleVarFromDB( $sModuleVarName )
637  {
638  $oDb = oxDb::getDb();
639 
640  $sShopId = $this->getShopId();
641  $sConfKey = $this->_getConfKey();
642 
643  $sSelect = "SELECT DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) FROM oxconfig ".
644  "WHERE oxvarname = ".$oDb->quote( $sModuleVarName )." AND oxshopid = ".$oDb->quote($sShopId);
645 
646  $sModuleVarName = $oDb->getOne($sSelect, false, false);
647 
648  $sModuleVarName = unserialize( $sModuleVarName );
649 
650  return $sModuleVarName;
651  }
652 
662  protected function _getFromCache( $sModuleVarName, $blSubshopSpecific = true )
663  {
664  $sShopId = null;
665  if ( !$blSubshopSpecific ) {
666  $sShopId = "all";
667  }
668 
669  $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
670  $sValue = null;
671  if ( is_readable( $sFileName ) ) {
672  $sValue = file_get_contents( $sFileName );
673  if ( $sValue == serialize( false ) ) {
674  return false;
675  }
676 
677  $sValue = unserialize( $sValue );
678  if ( $sValue === false ) {
679  $sValue = null;
680  }
681  }
682 
683  return $sValue ;
684  }
685 
695  protected function _setToCache( $sVarName, $sValue, $blSubshopSpecific = true )
696  {
697  $sShopId = null;
698  if ( !$blSubshopSpecific ) {
699  $sShopId = "all";
700  }
701 
702  $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
703  file_put_contents( $sFileName, serialize($sValue), LOCK_EX );
704  }
705 
706 }