OXID eShop CE  4.10.2
 All Classes Namespaces Files Functions Variables Pages
oxutilsobject.php
Go to the documentation of this file.
1 <?php
2 
10 {
11 
15  const CACHE_FILE_PREFIX = "config";
16 
22  protected $_aClassNameCache = array();
23 
29  protected static $_aLoadedArticles = array();
30 
36  protected static $_aInstanceCache = array();
37 
43  protected static $_aModuleVars = array();
44 
50  protected static $_aClassInstances = array();
51 
57  private static $_instance = null;
58 
64  public static function getInstance()
65  {
66  // disable caching for test modules
67  if (defined('OXID_PHP_UNIT')) {
68  self::$_instance = null;
69  }
70 
71  if (!self::$_instance instanceof oxUtilsObject) {
72 
73  // allow modules
74  $oUtilsObject = new oxUtilsObject();
75  self::$_instance = $oUtilsObject->oxNew('oxUtilsObject');
76  }
77 
78  return self::$_instance;
79  }
80 
88  public static function setClassInstance($sClassName, $oInstance)
89  {
90  $sClassName = strtolower($sClassName);
91  self::$_aClassInstances[$sClassName] = $oInstance;
92  }
93 
97  public static function resetClassInstances()
98  {
99  self::$_aClassInstances = array();
100  }
101 
107  public static function resetModuleVars()
108  {
109  self::$_aModuleVars = array();
110 
111  $sMask = oxRegistry::get("oxConfigFile")->getVar("sCompileDir") . "/" . self::CACHE_FILE_PREFIX . ".*.txt";
112  $aFiles = glob($sMask);
113  if (is_array($aFiles)) {
114  foreach ($aFiles as $sFile) {
115  if (is_file($sFile)) {
116  @unlink($sFile);
117  }
118  }
119  }
120  }
121 
132  public function oxNew($sClassName)
133  {
134  $aArgs = func_get_args();
135  array_shift($aArgs);
136  $iArgCnt = count($aArgs);
137  $blCacheObj = $iArgCnt < 2;
138  $sClassName = strtolower($sClassName);
139 
140  if (isset(self::$_aClassInstances[$sClassName])) {
141  return self::$_aClassInstances[$sClassName];
142  }
143  if (!defined('OXID_PHP_UNIT') && $blCacheObj) {
144  $sCacheKey = ($iArgCnt) ? $sClassName . md5(serialize($aArgs)) : $sClassName;
145  if (isset(self::$_aInstanceCache[$sCacheKey])) {
146  return clone self::$_aInstanceCache[$sCacheKey];
147  }
148  }
149 
150  // performance
151  if (!defined('OXID_PHP_UNIT') && isset($this->_aClassNameCache[$sClassName])) {
152  $sActionClassName = $this->_aClassNameCache[$sClassName];
153  } else {
154  $sActionClassName = $this->getClassName($sClassName);
155  //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
156  if (!class_exists($sActionClassName)) {
158  $oEx = oxNew("oxSystemComponentException");
159  $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
160  $oEx->setComponent($sClassName);
161  $oEx->debugOut();
162  throw $oEx;
163  }
164  // performance
165  $this->_aClassNameCache[$sClassName] = $sActionClassName;
166  }
167 
168  $oActionObject = $this->_getObject($sActionClassName, $iArgCnt, $aArgs);
169  if ($blCacheObj && $oActionObject instanceof oxBase) {
170  self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
171  }
172 
173  return $oActionObject;
174  }
175 
188  protected function _getObject($sClassName, $iArgCnt, $aParams)
189  {
190  // dynamic creation (if parameter count < 4) gives more performance for regular objects
191  switch ($iArgCnt) {
192  case 0:
193  $oObj = new $sClassName();
194  break;
195  case 1:
196  $oObj = new $sClassName($aParams[0]);
197  break;
198  case 2:
199  $oObj = new $sClassName($aParams[0], $aParams[1]);
200  break;
201  case 3:
202  $oObj = new $sClassName($aParams[0], $aParams[1], $aParams[2]);
203  break;
204  default:
205  try {
206  // unlimited constructor arguments support
207  $oRo = new ReflectionClass($sClassName);
208  $oObj = $oRo->newInstanceArgs($aParams);
209  } catch (ReflectionException $oRefExcp) {
210  // something went wrong?
212  $oEx = oxNew("oxSystemComponentException");
213  $oEx->setMessage($oRefExcp->getMessage());
214  $oEx->setComponent($sClassName);
215  $oEx->debugOut();
216  throw $oEx;
217  }
218  }
219 
220  return $oObj;
221  }
222 
230  public function resetInstanceCache($sClassName = null)
231  {
232  if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
233  unset(self::$_aInstanceCache[$sClassName]);
234 
235  return;
236  }
237 
238  //looping due to possible memory "leak".
239  if (is_array(self::$_aInstanceCache)) {
240  foreach (self::$_aInstanceCache as $sKey => $oInstance) {
241  unset(self::$_aInstanceCache[$sKey]);
242  }
243  }
244 
245  self::$_aInstanceCache = array();
246  }
247 
253  public function generateUId()
254  {
255  return /*substr( $this->getSession()->getId(), 0, 3 ) . */
256  substr(md5(uniqid('', true) . '|' . microtime()), 0, 32);
257  }
258 
259 
260 
268  public function getClassName($sClassName)
269  {
270  //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
271  $aModules = $this->getModuleVar('aModules');
272  $aClassChain = array();
273 
274 
275  if (is_array($aModules)) {
276 
277  $aModules = array_change_key_case($aModules);
278 
279  if (array_key_exists($sClassName, $aModules)) {
280  //multiple inheritance implementation
281  //in case we have multiple modules:
282  //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
283  $aClassChain = explode("&", $aModules[$sClassName]);
284  $aClassChain = $this->_getActiveModuleChain($aClassChain);
285  }
286 
287  if (count($aClassChain)) {
288  $sParent = $sClassName;
289 
290  //security: just preventing string termination
291  $sParent = str_replace(chr(0), '', $sParent);
292 
293  //building middle classes if needed
294  $sClassName = $this->_makeSafeModuleClassParents($aClassChain, $sParent);
295  }
296  }
297 
298  // check if there is a path, if yes, remove it
299  $sClassName = basename($sClassName);
300 
301  return $sClassName;
302  }
303 
311  protected function _getActiveModuleChain($aClassChain)
312  {
313  $aDisabledModules = $this->getModuleVar('aDisabledModules');
314  $aModulePaths = $this->getModuleVar('aModulePaths');
315 
316  if (is_array($aDisabledModules) && count($aDisabledModules) > 0) {
317  foreach ($aDisabledModules as $sId) {
318  $sPath = $sId;
319  if (is_array($aModulePaths) && array_key_exists($sId, $aModulePaths)) {
320  $sPath = $aModulePaths[$sId];
321  if (!isset($sPath)) {
322  $sPath = $sId;
323  }
324  }
325  foreach ($aClassChain as $sKey => $sModuleClass) {
326  if (strpos($sModuleClass, $sPath . "/") === 0) {
327  unset($aClassChain[$sKey]);
328  } elseif (strpos($sPath, ".")) {
329  // If module consists of one file without own dir (getting module.php as id, instead of module)
330  if (strpos($sPath, strtolower($sModuleClass)) === 0) {
331  unset($aClassChain[$sKey]);
332  }
333  }
334  }
335  }
336  }
337 
338  return $aClassChain;
339  }
340 
346  protected function _disableModule($sModule)
347  {
349  $oModule = oxNew("oxModule");
350  $sModuleId = $oModule->getIdByPath($sModule);
351  $oModule->load($sModuleId);
352 
354  $oModuleCache = oxNew('oxModuleCache', $oModule);
356  $oModuleInstaller = oxNew('oxModuleInstaller', $oModuleCache);
357 
358  $oModuleInstaller->deactivate($oModule);
359 
360  }
361 
372  protected function _makeSafeModuleClassParents($aClassChain, $sBaseModule)
373  {
374  $sParent = $sBaseModule;
375  $sClassName = $sBaseModule;
376 
377  //building middle classes if needed
378  foreach ($aClassChain as $sModule) {
379  //creating middle classes
380  //e.g. class suboutput1_parent extends oxoutput {}
381  // class suboutput2_parent extends suboutput1 {}
382  //$sModuleClass = $this->getClassName($sModule);
383 
384  //security: just preventing string termination
385  $sModule = str_replace(chr(0), '', $sModule);
386 
387  //get parent and module class names from sub/suboutput2
388  $sModuleClass = basename($sModule);
389 
390  if (!class_exists($sModuleClass, false)) {
391  $sParentClass = basename($sParent);
392  $sModuleParentClass = $sModuleClass . "_parent";
393 
394  //initializing middle class
395  if (!class_exists($sModuleParentClass, false)) {
396  // If possible using alias instead if eval (since php 5.3).
397  if (function_exists('class_alias')) {
398  class_alias($sParentClass, $sModuleParentClass);
399  } else {
400  eval("abstract class $sModuleParentClass extends $sParentClass {}");
401  }
402  }
403  $sParentPath = oxRegistry::get("oxConfigFile")->getVar("sShopDir") . "/modules/" . $sModule . ".php";
404 
405  //including original file
406  if (file_exists($sParentPath)) {
407  include_once $sParentPath;
408  } elseif (!class_exists($sModuleClass)) {
409  // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
410  // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
411  if ($sParentClass == "oxconfig") {
412  $oConfig = $this->_getObject("oxconfig", 0, null);
413  oxRegistry::set("oxconfig", $oConfig);
414  }
415 
416  // disable module if extended class is not found
417  $blDisableModuleOnError = !oxRegistry::get("oxConfigFile")->getVar("blDoNotDisableModuleOnError");
418  if ($blDisableModuleOnError) {
419  $this->_disableModule($sModule);
420  } else {
421  //to avoid problems with unitest and only throw a exception if class does not exists MAFI
423  $oEx = oxNew("oxSystemComponentException");
424  $oEx->setMessage("EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND");
425  $oEx->setComponent($sModuleClass);
426  throw $oEx;
427  }
428  continue;
429  }
430  }
431  $sParent = $sModule;
432  $sClassName = $sModule;
433  }
434 
435  //returning the last module from the chain
436  return $sClassName;
437  }
438 
444  public function getShopId()
445  {
446  return 'oxbaseshop';
447  }
448 
458  public function getModuleVar($sModuleVarName)
459  {
460  //static cache
461  if (isset(self::$_aModuleVars[$sModuleVarName])) {
462  return self::$_aModuleVars[$sModuleVarName];
463  }
464 
465  //first try to get it from cache
466  //we do not use any of our cache APIs, as we want to prevent any class dependencies here
467  $aValue = $this->_getFromCache($sModuleVarName);
468 
469  if (is_null($aValue)) {
470  $aValue = $this->_getModuleVarFromDB($sModuleVarName);
471  $this->_setToCache($sModuleVarName, $aValue);
472  }
473 
474  //static cache
475  self::$_aModuleVars[$sModuleVarName] = $aValue;
476 
477  return $aValue;
478  }
479 
486  public function setModuleVar($sModuleVarName, $aValues)
487  {
488  if (is_null($aValues)) {
489  self::$_aModuleVars = null;
490  } else {
491  self::$_aModuleVars[$sModuleVarName] = $aValues;
492  }
493 
494  $this->_setToCache($sModuleVarName, $aValues);
495  }
496 
502  protected function _getConfKey()
503  {
504  $sFileName = dirname(__FILE__) . "/oxconfk.php";
505  $sCfgFile = new oxConfigFile($sFileName);
506 
507  return $sCfgFile->getVar("sConfigKey");
508  }
509 
515  protected function _getShopUrlMap()
516  {
517 
518  //get from static cache
519  if (isset(self::$_aModuleVars["urlMap"])) {
520  return self::$_aModuleVars["urlMap"];
521  }
522 
523  //get from file cache
524  $aMap = $this->_getFromCache("urlMap", false);
525  if (!is_null($aMap)) {
526  self::$_aModuleVars["urlMap"] = $aMap;
527 
528  return $aMap;
529  }
530 
531  $aMap = array();
532 
533  $oDb = oxDb::getDb();
534  $sConfKey = $this->_getConfKey();
535 
536  $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , " . $oDb->quote($sConfKey) . " ) as oxvarvalue " .
537  "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
538 
539  $oRs = $oDb->select($sSelect, false, false);
540 
541  if ($oRs && $oRs->recordCount() > 0) {
542  while (!$oRs->EOF) {
543  $iShp = (int) $oRs->fields[0];
544  $sVar = $oRs->fields[1];
545  $sURL = $oRs->fields[2];
546 
547  if ($sVar == 'aLanguageURLs') {
548  $aUrls = unserialize($sURL);
549  if (is_array($aUrls) && count($aUrls)) {
550  $aUrls = array_filter($aUrls);
551  $aUrls = array_fill_keys($aUrls, $iShp);
552  $aMap = array_merge($aMap, $aUrls);
553  }
554  } elseif ($sURL) {
555  $aMap[$sURL] = $iShp;
556  }
557 
558  $oRs->moveNext();
559  }
560  }
561 
562  //save to cache
563  $this->_setToCache("urlMap", $aMap, false);
564  self::$_aModuleVars["urlMap"] = $aMap;
565 
566  return $aMap;
567  }
568 
574  protected function _getCacheDir()
575  {
576  $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
577 
578  return $sDir;
579  }
580 
589  protected function _getCacheFileName($sModuleVarName, $sShopId = null)
590  {
591  if (is_null($sShopId)) {
592  $sShopId = $this->getShopId();
593  }
594 
595  $sDir = $this->_getCacheDir();
596  $sVar = strtolower(basename($sModuleVarName));
597  $sShop = strtolower(basename($sShopId));
598 
599  $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
600 
601  return $sFileName;
602  }
603 
611  protected function _getModuleVarFromDB($sModuleVarName)
612  {
613  $oDb = oxDb::getDb();
614 
615  $sShopId = $this->getShopId();
616  $sConfKey = $this->_getConfKey();
617 
618  $sSelect = "SELECT DECODE( oxvarvalue , " . $oDb->quote($sConfKey) . " ) FROM oxconfig " .
619  "WHERE oxvarname = " . $oDb->quote($sModuleVarName) . " AND oxshopid = " . $oDb->quote($sShopId);
620 
621  $sModuleVarName = $oDb->getOne($sSelect, false, false);
622 
623  $sModuleVarName = unserialize($sModuleVarName);
624 
625  return $sModuleVarName;
626  }
627 
637  protected function _getFromCache($sModuleVarName, $blSubshopSpecific = true)
638  {
639  $sShopId = null;
640  if (!$blSubshopSpecific) {
641  $sShopId = "all";
642  }
643 
644  $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
645  $sValue = null;
646  if (is_readable($sFileName)) {
647  $sValue = file_get_contents($sFileName);
648  if ($sValue == serialize(false)) {
649  return false;
650  }
651 
652  $sValue = unserialize($sValue);
653  if ($sValue === false) {
654  $sValue = null;
655  }
656  }
657 
658  return $sValue;
659  }
660 
668  protected function _setToCache($sVarName, $sValue, $blSubshopSpecific = true)
669  {
670  $sShopId = null;
671  if (!$blSubshopSpecific) {
672  $sShopId = "all";
673  }
674 
675  $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
676  file_put_contents($sFileName, serialize($sValue), LOCK_EX);
677  }
678 }