diff --git a/system/compatibility/Polyfill/Mbstring.php b/system/compatibility/Polyfill/Mbstring.php new file mode 100644 index 0000000..9198cca --- /dev/null +++ b/system/compatibility/Polyfill/Mbstring.php @@ -0,0 +1,29 @@ + + * + * Only for old versions of PHP that not support variable-length argument lists (...) + */ + + +namespace Phacil\Framework\Compatibility\Polyfill { + + class Mbstring { + static function load() { + return true; + } + } +} + +namespace { + if (!function_exists('mb_convert_variables')) { + function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) + { + return \Symfony\Polyfill\Mbstring\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $v0, $a, $b, $c, $d, $e, $f); + } + } +} diff --git a/system/engine/autoload.php b/system/engine/autoload.php index 26fba9c..9d6c88c 100644 --- a/system/engine/autoload.php +++ b/system/engine/autoload.php @@ -6,55 +6,40 @@ * Phacil PHP Framework - https://github.com/exacti/phacil-framework */ + namespace Phacil\Framework; -/** @autoload class */ -spl_autoload_register(function ($class) { - $namespace = explode("\\", $class); - $namespaceWithoutPrefix = (defined('NAMESPACE_PREFIX')) ? explode("\\", str_replace(NAMESPACE_PREFIX."\\" , "", $class)) : $namespace; + /** + * Autoload class for Phacil Framework + * + * @package Phacil\Framework + * @since 2.0.0 + */ + class AutoLoad { - $legacy = [ - 'Controller', - 'Model', - 'Document', - 'Captcha', - 'Caches', - 'Pagination', - 'Request', - 'Mail', - 'Translate'. - 'Encryption' - ]; - - if(in_array($class, $legacy)){ - try { - class_alias("\\Phacil\\Framework\\".$class, $class); - } catch (\Exception $th) { - throw new \Phacil\Framework\Exception ($th->getMessage()); - } - - return; - } - - $classNative = ($namespace[0] == "Phacil") ? str_replace('phacil\\framework\\', '', strtolower( $class)) : $class; - - if($namespace[0] == 'Phacil' && isset($namespace[2]) && $namespace[2] == 'Databases'){ + /** + * + * @var array|null + */ + private static $namespace = null; + private static $namespaceWithoutPrefix; + private static $class = null; + private static $classNative; - $fileDB = \Phacil\Framework\Config::DIR_DATABASE(\Phacil\Framework\Config::DIR_SYSTEM() . "database/") . str_replace("\\", "/", $classNative).'.php'; + const CONFIG_CLASS = "Phacil\Framework\Config"; - try { - if (!file_exists($fileDB)){ - throw new \Phacil\Framework\Exception($fileDB.' does not exist', 2); - }else{ - require_once($fileDB); + /** + * + * @var \Phacil\Framework\AutoLoad + */ + private static $instance = null; - return; - } - } catch (Exception $th) { - throw new \Phacil\Framework\Exception($th->getMessage(), $th->getCode(), $th); - } - } + protected $loadedClasses = array(); - $allowed = [ + /** + * + * @var array + */ + private static $allowed = [ 'log', 'front', 'controller', @@ -77,133 +62,405 @@ spl_autoload_register(function ($class) { 'restful' ]; - if($namespace[0] == "Phacil" && in_array($classNative, $allowed)){ - $file = DIR_SYSTEM . 'engine/'. str_replace("\\", "/", $classNative).'.php'; + /** + * + * @var string[] + */ + private static $legacy = [ + 'Controller', + 'Model', + 'Document', + 'Captcha', + 'Caches', + 'Pagination', + 'Request', + 'Mail', + 'Translate', + 'Encryption' + ]; + function __construct() { + } + + /** + * Load SPL Autoloader + * + * @return bool + * @throws \TypeError + */ + static public function run() { + return spl_autoload_register(['self', 'load']); + } + + static protected function fileResolver($file) { + $splFile = new \SplFileInfo($file); + if(!$splFile->isReadable()) return false; + + return $splFile; + } + + static protected function loadClassFile($file){ + $file = ($file instanceof \SplFileInfo) ? $file : self::fileResolver($file); + + if($file){ + if(self::required($file)) { + self::getInstance()->loadedClasses[] = self::$class; + return true; + } + } else { + return false; + } + } + + static public function required(\SplFileInfo $file) { + return require_once($file->getPathname()); + } + + /** + * + * @return string[] + */ + static public function getAllowedSystemClasses() { + return self::$allowed; + } + + /** + * + * @return \Phacil\Framework\AutoLoad + */ + static public function getInstance() { + + if(!self::$instance) + self::$instance = new self(); + + return self::$instance; + } + + /** + * + * @return bool + */ + private function loadConfigClass(){ + if(self::$class != self::CONFIG_CLASS) return false; + + $classNative = str_replace('phacil\\framework\\', '', strtolower(self::$class)); + + $value = DIR_SYSTEM . str_replace('\\', "/", $classNative) . '/autoload.php'; + + $value = self::fileResolver($value); + + if (file_exists($value)) { + try { + if (($value)) { + self::loadClassFile($value); + + return true; + } else { + throw new \Exception("I can't load '$value' file! Please check system permissions."); + } + } catch (\Exception $e) { + $log = new \Phacil\Framework\Log("exception.log"); + $log->write($class . ' not loaded!'); + exit($e->getMessage()); + } + } + + return false; + } + + /** @return bool */ + public function checkConfigLoaded(){ + return isset($this->loadedClasses[0]) && $this->loadedClasses[0] == self::CONFIG_CLASS; + } + + /** + * @return true|void + * @throws \Exception + */ + public function configIsFirst(){ try { - if(is_readable($file)){ - require_once($file); - return; - } else { - throw new \Exception("Class '$class' not loaded."); + if(!$this->checkConfigLoaded()) throw new \Exception("Config need to be a first class loaded!"); + + return true; + } catch (\Exception $th) { + throw $th; + } + } + + private function prepareNamespaces() { + self::$namespace = explode("\\", self::$class); + self::$namespaceWithoutPrefix = (\Phacil\Framework\Config::NAMESPACE_PREFIX()) ? explode("\\", str_replace(\Phacil\Framework\Config::NAMESPACE_PREFIX() . "\\", "", self::$class)) : self::$namespace; + + self::$classNative = (isset(self::$namespace[0]) && self::$namespace[0] == "Phacil") ? str_replace('phacil\\framework\\', '', strtolower(self::$class)) : self::$class; + } + + /** + * + * @return bool + * @throws \Phacil\Framework\Exception + */ + private function legacyLoad() { + if (in_array(self::$class, self::$legacy)) { + try { + class_alias("\\Phacil\\Framework\\" . self::$class, self::$class); + return true; + } catch (\Exception $th) { + throw new \Phacil\Framework\Exception($th->getMessage()); + } + return false; + } + + return false; + } + + /** + * + * @return bool + */ + static private function isPhacil() { + return isset(self::$namespace[0]) && self::$namespace[0] == 'Phacil'; + } + + /** + * + * @return bool + */ + private function loadEngineClasses() { + if (!self::isPhacil()) return false; + + if (in_array(self::$classNative, self::$allowed)) { + $file = \Phacil\Framework\Config::DIR_SYSTEM() . 'engine/' . str_replace("\\", "/", self::$classNative) . '.php'; + + try { + if (!self::loadClassFile($file)) { + throw new \Exception("Class ".self::$class." not loaded."); + } + return true; + } catch (\Exception $th) { + $log = new \Phacil\Framework\Log("exception.log"); + $log->write($th->getMessage()); + } + } + + return false; + } + + private function loadActionClasses() { + if (!self::isPhacil()) return false; + + if(self::$class != 'Phacil\Framework\Action' && self::$class != 'Phacil\Framework\ActionSystem') return false; + + $file = (\Phacil\Framework\Config::DIR_SYSTEM() . 'engine/action.php'); + + try { + if (!self::loadClassFile($file)) { + throw new \Exception("Action classes is not loaded."); } + return true; } catch (\Exception $th) { - $log = new \Phacil\Framework\Log("exception.log"); $log->write($th->getMessage()); - } + + return false; } - $value = DIR_SYSTEM . str_replace('\\', "/", $classNative) .'/autoload.php'; + /** + * + * @return bool|void + * @throws \Phacil\Framework\Exception + */ + private function loadDatabase() { + if(!self::isPhacil()) return false; + + if (isset(self::$namespace[2]) && self::$namespace[2] == 'Databases') { - if($namespace[0] == "Phacil" && file_exists($value)){ - try { - if(is_readable($value)) { - require_once $value; - return; - } else { - throw new \Exception("I can't load '$value' file! Please check system permissions."); + $fileDB = \Phacil\Framework\Config::DIR_DATABASE(\Phacil\Framework\Config::DIR_SYSTEM() . "database/") . str_replace("\\", "/", self::$classNative) . '.php'; + + //$fileDB = self::fileResolver($fileDB); + + try { + if (!self::loadClassFile($fileDB)) { + throw new \Phacil\Framework\Exception($fileDB . ' does not exist', 2); + } + + return true; + } catch (Exception $th) { + throw new \Phacil\Framework\Exception($th->getMessage(), $th->getCode(), $th); } + + return false; + } + } + + /** + * + * @return bool + */ + private function loadEngineAutload() { + if (!self::isPhacil()) return false; + + $value = \Phacil\Framework\Config::DIR_SYSTEM() . str_replace('\\', "/", self::$classNative) . '/autoload.php'; + + try { + if (self::loadClassFile($value)) { + return true; + } } catch (\Exception $e) { $log = new \Phacil\Framework\Log("exception.log"); - $log->write($class.' not loaded!'); + $log->write(self::$class . ' not loaded!'); exit($e->getMessage()); } + + return false; + } - $value = DIR_SYSTEM . str_replace('\\', "/", $classNative) . '.php'; + private function loadEngineAutload2() { + if (!self::isPhacil()) return false; + + $value = \Phacil\Framework\Config::DIR_SYSTEM() . str_replace('\\', "/", self::$classNative) . '.php'; - if ($namespace[0] == "Phacil" && file_exists($value) ) { try { - if (is_readable($value)) { - require_once $value; - return; - } else { - throw new \Exception("I can't load '$value' file! Please check system permissions."); + if (self::loadClassFile($value)) { + return true; } } catch (\Exception $e) { $log = new \Phacil\Framework\Log("exception.log"); - $log->write($class . ' not loaded!'); + $log->write(self::$class . ' not loaded!'); exit($e->getMessage()); } + + return false; } - - if(file_exists($tryMagicOne = DIR_APP_MODULAR. implode("/", $namespace).".php")){ + + /** + * + * @return bool + */ + private function loadModularFiles() { + $tryMagicOne = \Phacil\Framework\Config::DIR_APP_MODULAR() . implode("/", self::$namespace) . ".php"; + try { - if(is_readable($tryMagicOne)) { - require_once $tryMagicOne; - return; - } else { - throw new \Exception("I can't load '$tryMagicOne' file! Please check system permissions."); - } + if (self::loadClassFile($tryMagicOne)) { + return true; + } } catch (\Exception $e) { $log = new \Phacil\Framework\Log("exception.log"); $log->write($e->getMessage()); exit($e->getMessage()); } - } - - if(file_exists($tryMagicOne = DIR_APP_MODULAR. implode("/", $namespaceWithoutPrefix).".php")){ + return false; + } + + /** + * + * @return bool + */ + private function loadModularWithoutNamespacesPrefix() { + $tryMagicOne = \Phacil\Framework\Config::DIR_APP_MODULAR() . implode("/", self::$namespaceWithoutPrefix) . ".php"; try { - if(is_readable($tryMagicOne)) { - require_once $tryMagicOne; - return; - } else { - throw new \Exception("I can't load '$tryMagicOne' file! Please check system permissions."); - } + if (self::loadClassFile($tryMagicOne)) { + return true; + } } catch (\Exception $e) { $log = new \Phacil\Framework\Log("exception.log"); $log->write($e->getMessage()); exit($e->getMessage()); } - } - $prefix = array_shift($namespace); - - if(file_exists($tryMagicOne = DIR_APP_MODULAR. implode("/", $namespace).".php")){ + return false; + } + + private function loadModularNamespaceShift() { + $namespace = self::$namespace; + $prefix = array_shift($namespace); + + $tryMagicOne = \Phacil\Framework\Config::DIR_APP_MODULAR() . implode("/", $namespace) . ".php" ; try { - if(is_readable($tryMagicOne)) { - require_once $tryMagicOne; - return; - } else { - throw new \Exception("I can't load '$tryMagicOne' file! Please check system permissions."); - } + if (self::loadClassFile($tryMagicOne)) { + return true; + } } catch (\Exception $e) { $log = new \Phacil\Framework\Log("exception.log"); $log->write($e->getMessage()); exit($e->getMessage()); } - } - - - return; + return false; -}); + } -require_once(\Phacil\Framework\Config::DIR_SYSTEM() . 'engine/action.php'); + static public function loadComposer() { + if (self::isPhacil()) return false; -$composer = \Phacil\Framework\Config::DIR_VENDOR() ?: \Phacil\Framework\Config::DIR_VENDOR(\Phacil\Framework\Config::DIR_SYSTEM() . 'vendor/autoload.php'); + $composer = \Phacil\Framework\Config::DIR_VENDOR() ?: \Phacil\Framework\Config::DIR_VENDOR(\Phacil\Framework\Config::DIR_SYSTEM() . 'vendor/autoload.php'); -if (file_exists($composer)) { - /** - * fix for Polyfill Mbstring in older PHP versions - */ - if (!function_exists('mb_convert_variables')) { - function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) - { - return Symfony\Polyfill\Mbstring\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $v0, $a, $b, $c, $d, $e, $f); + /** + * fix for Polyfill Mbstring in older PHP versions + */ + + $cMbstring = false; + + if (version_compare(phpversion(), '7.0.0', '>') == false || extension_loaded('mbstring')) { + $cMbstring = \Phacil\Framework\Compatibility\Polyfill\Mbstring::load(); + + $GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a'] = 'noLoad'; + } + /** + * End fix + */ + + if ($autoloadComposer = self::loadClassFile($composer)) { + //$autoloadComposer = (include_once $composer); + return true; + } else { + $log = new \Phacil\Framework\Log("exception.log"); + $m = 'Composer load not found.'; + $log->write($m); + throw new Exception($m); } + } - if (extension_loaded('mbstring')) { - $GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a'] = 'noLoad'; + + static public function load($class) { + self::$class = $class; + + $autoload = self::getInstance(); + + if($autoload->loadConfigClass()) return; + + $autoload->configIsFirst(); + + $autoload->prepareNamespaces(); + + if($autoload->legacyLoad()) return; + + if($autoload->loadActionClasses()) return; + + if($autoload->loadDatabase()) return; + + if($autoload->loadEngineClasses()) return; + + if($autoload->loadEngineAutload()) return; + + if($autoload->loadEngineAutload2()) return; + + if($autoload->loadModularFiles()) return; + + if($autoload->loadModularWithoutNamespacesPrefix()) return; + + if($autoload->loadModularNamespaceShift()) return; + + //if($autoload->loadComposer()) return; + + return; } - /** - * End fix - */ + } + +AutoLoad::run(); + +$config = \Phacil\Framework\Config::INIT(); - $autoloadComposer = (include_once $composer); - //return; -} \ No newline at end of file +AutoLoad::loadComposer(); \ No newline at end of file