=5.3") */ class FooClass { / ** @Persistent * / public $foo; / ** @User(loggedIn, role=Admin) * / public function bar() {} } $fooReflection = new Nette\Reflection\ClassType('FooClass'); $fooReflection->hasAnnotation('author'); // returns true $fooReflection->hasAnnotation('copyright'); // returns false $fooReflection->getAnnotation('author'); // returns string 'Tomas Marny' $fooReflection->getMethod('bar')->getAnnotation('User'); // returns array('loggedIn', 'role' => 'Admin') */ namespace Webfan\Traits { trait WithContextDirectories { protected $cacheRootDir=null; protected $cacheDir=null; public function cacheRoot(string $name = null){ if(is_string($name)){ $this->cacheRootDir=$this->tempDir($name, 'local'); } if(null === $this->cacheRootDir){ $this->cacheRootDir= $this->tempDir(null, 'local'); } return $this->cacheRootDir; } public function homedir(){ $user = \posix_getpwuid(\posix_getuid()); /* Array ( [name] => username [passwd] => ******** [uid] => 501 [gid] => 20 [gecos] => Full Name [dir] => /home/username [shell] => /bin/bash ) */ return $user['dir']; } public function tmpdir($context = 'global'){ $method=[$this, $context.'_'.__FUNCTION__]; if(is_callable($method)){ return call_user_func($method); } return $this->sys_tmpdir(); } public function usr_tmpdir(){ $dir = $this->homedir().\DIRECTORY_SEPARATOR.'tmp'; if(!is_dir($dir)){ @mkdir($dir, 0777, true); } if(!is_writable($dir)){ throw new \Exception(sprintf('The directory "%s" is not writable', $dir)); } return $dir; } public function local_tmpdir(){ return $this->usr_tmpdir(); } public function global_tmpdir(){ return $this->sys_tmpdir(); } public function sys_tmpdir(){ return \sys_get_temp_dir(); } public function tempDir( $name = null, $context = 'global'){ $tmpdir = $this->tmpdir($context); if(is_string($name)){ return $tmpdir . \DIRECTORY_SEPARATOR .$name . \DIRECTORY_SEPARATOR ; }elseif(false === $name){ return $tmpdir . \DIRECTORY_SEPARATOR; }elseif(true === $name){ return $tmpdir . \DIRECTORY_SEPARATOR .get_current_user() . \DIRECTORY_SEPARATOR ; }elseif(null === $name){ return $tmpdir. \DIRECTORY_SEPARATOR; } } public function getCacheDir(string $name = null){ $base = $this->cacheRoot($name); if(null === $name){ $name = ''; } $name = \preg_replace("/[^A-Za-z0-9\.\-\_\:\@]/", "", $name); return (empty($name)) ? $base : $base. \DIRECTORY_SEPARATOR.$name. \DIRECTORY_SEPARATOR ; } } } namespace Webfan\Traits { trait WithOnShutdown { public function onShutdown(){ return call_user_func_array($this->_getShutdowner(), func_get_args()); } public function _getShutdowner(){ $load = $this->_currentClassToAutoload !== \frdlweb\Thread\ShutdownTasks::class; return (class_exists(\frdlweb\Thread\ShutdownTasks::class, $load )) ? \frdlweb\Thread\ShutdownTasks::mutex() : function(){ call_user_func_array('register_shutdown_function', func_get_args()); register_shutdown_function(function($load){ $t = class_exists(\frdlweb\Thread\ShutdownTasks::class, $load); }, $load); }; } } } namespace webfan\hps\patch{ use Webfan\Traits\WithContextDirectories as DirectoriesTrait; use DirectoryIterator; use SplFileInfo; class Fs { use DirectoriesTrait; /* by https://www.php.net/manual/de/function.chmod.php#105570 */ public static function chmod($path, $filemode, $dirmode, $r = true, &$log = null){ if(null === $log){ $log = []; } if (is_dir($path) ) { if (!chmod($path, $dirmode)) { $dirmode_str=decoct($dirmode); $e =[\E_USER_ERROR, new \Exception("Failed applying filemode '$dirmode_str' on directory '$path'\n" . " `-> the directory '$path' will be skipped from recursive chmod\n")]; $log[] = $e; return $e; } if(true === $r){ $dh = opendir($path); while (($file = readdir($dh)) !== false) { if($file != '.' && $file != '..') { $fullpath = $path.'/'.$file; self::chmod($fullpath, $filemode,$dirmode, true, $log); } } closedir($dh); } $dirmode_str=decoct($dirmode); $e =[\E_USER_NOTICE, "Done applying filemode '$dirmode_str' on directory '$path'\n"]; $log[] = $e; return $e; } else { if (is_link($path)) { $e = [\E_USER_NOTICE, new \Exception("link '$path' is skipped\n")]; $log[] = $e; return $e; } if (!chmod($path, $filemode)) { $filemode_str=decoct($filemode); $e = [\E_USER_ERROR, new \Exception("Failed applying filemode '$filemode_str' on file '$path'\n")]; $log[] = $e; return $e; } $filemode_str=decoct($filemode); $e =[\E_USER_NOTICE, "Done applying filemode '$filemode_str' on file '$path'\n"]; $log[] = $e; return $e; } } public static function mostRecentModified(string $dirName,bool $doRecursive=null, array $extensions = null, array $excludeExtensions = null) { $d = dir($dirName); if(null === $extensions){ $extensions=['*']; } if(null === $excludeExtensions){ $excludeExtensions=[]; } if(null===$doRecursive){ $doRecursive=true; } $lastModified = [0, null,null]; while($entry = $d->read()) { if ($entry != "." && $entry != "..") { if (!is_dir($dirName."/".$entry)) { $fileInfo = new SplFileInfo($dirName."/".$entry); $currentModified = ['filemtime'=>$fileInfo->getMTime(), 'path'=>$fileInfo->getPathname(), 'extension'=>$fileInfo->getExtension()]; } else if (true===$doRecursive && is_dir($dirName."/".$entry)) { $currentModified = self::mostRecentModified($dirName."/".$entry,true,$extensions,$excludeExtensions); } if ($currentModified['filemtime'] > $lastModified['filemtime'] && (in_array('*', $extensions) || in_array($currentModified['extension'], $extensions)) && !in_array($currentModified['extension'], $excludeExtensions)){ $lastModified = $currentModified; } } } $d->close(); return $lastModified; } /*https://www.startutorial.com/articles/view/deployment-script-in-php*/ public static function recursiveCopyDir($srcDir, $destDir){ foreach (new DirectoryIterator($srcDir) as $fileInfo) { if ($fileInfo->isDot()) { continue; } if (!file_exists($destDir)) { shell_exec('mkdir -p '.$destDir); } $copyTo = $destDir . '/' . $fileInfo->getFilename(); copy($fileInfo->getRealPath(), $copyTo); } } public static function copyFileToDir($src, $desDir){ if (!file_exists($desDir)) { shell_exec('mkdir -p '.$desDir); } $fileInfo = new SplFileInfo($src); $copyTo = $desDir . '/' . $fileInfo->getFilename(); copy($fileInfo->getRealPath(), $copyTo); } public static function copy($src, $desDir){ if(is_dir($src)){ self::copy($src, $desDir); }elseif(is_file($src)){ self::copyFileToDir($src, $desDir); } } public static function remove($dir){ shell_exec('rm -rf '.$dir); } public static function compress($buffer) { /* remove comments */ $buffer = preg_replace("/((?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/)|(?:\/\/.*))/", "", $buffer); /* remove tabs, spaces, newlines, etc. */ $buffer = str_replace(array("\r\n","\r","\t","\n",' ',' ',' '), '', $buffer); /* remove other spaces before/after ) */ $buffer = preg_replace(array('(( )+\))','(\)( )+)'), ')', $buffer); return $buffer; } public static function filePrune($filename,$maxfilesize = 4096, $pruneStart = true){ if(filesize($filename) < $maxfilesize){ return; } $maxfilesize = min($maxfilesize, filesize($filename)); $maxfilesize = max($maxfilesize, 0); if(true!==$pruneStart){ $fp = fopen($filename, "r+"); ftruncate($fp, $maxfilesize); fclose($fp); return; } $size=filesize($filename); if ($size<$maxfilesize*1.0) return; $maxfilesize=$maxfilesize*0.5; //we don't want to do it too often... $fh=fopen($filename,"r+"); $start=ftell($fh); fseek($fh,-$maxfilesize,SEEK_END); $drop=fgets($fh); $offset=ftell($fh); for ($x=0;$x<$maxfilesize;$x++){ fseek($fh,$x+$offset); $c=fgetc($fh); fseek($fh,$x); fwrite($fh,$c); } ftruncate($fh,$maxfilesize-strlen($drop)); fclose($fh); } public static function getRootDir($path = null){ if(null===$path){ $path = $_SERVER['DOCUMENT_ROOT']; } if(''!==dirname($path) && '/'!==dirname($path) //&& @chmod(dirname($path), 0755) && true===@is_writable(dirname($path)) ){ return self::getRootDir(dirname($path)); }else{ return $path; } } public static function getPathUrl($dir = null, $absolute = true){ if(null===$dir){ // $dir = dirname($_SERVER['PHP_SELF']); $dir = getcwd(); }elseif(is_file($dir)){ $dir = dirname($dir); } $root = ""; $dir = str_replace('\\', '/', realpath($dir)); //HTTPS or HTTP $root .= ($absolute) ? (!empty($_SERVER['HTTPS']) ? 'https' : 'http') : ''; //HOST $root .= ($absolute) ? '://' . $_SERVER['HTTP_HOST'] : ''; //ALIAS if(!empty($_SERVER['CONTEXT_PREFIX'])) { $root .= $_SERVER['CONTEXT_PREFIX']; $root .= substr($dir, strlen($_SERVER[ 'CONTEXT_DOCUMENT_ROOT' ])); } else { $root .= substr($dir, strlen($_SERVER[ 'DOCUMENT_ROOT' ])); } $root .= '/'; return $root; } public static function getRelativePath($from, $to){ // some compatibility fixes for Windows paths // $from = is_dir($from) ? rtrim($from, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR : $from; // $to = is_dir($to) ? rtrim($to, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR : $to; $from = str_replace('\\', \DIRECTORY_SEPARATOR, $from); $to = str_replace('\\', \DIRECTORY_SEPARATOR, $to); $from = explode( \DIRECTORY_SEPARATOR, $from); $to = explode( \DIRECTORY_SEPARATOR, $to); $relPath = $to; foreach($from as $depth => $dir) { // find first non-matching dir if($dir === $to[$depth]) { // ignore this directory array_shift($relPath); } else { // get number of remaining dirs to $from $remaining = count($from) - $depth; if($remaining > 1) { // add traversals up to first matching dir $padLength = (count($relPath) + $remaining - 1) * -1; $relPath = array_pad($relPath, $padLength, '..'); break; } else { $relPath[0] = '.'. \DIRECTORY_SEPARATOR . $relPath[0]; } } } return implode( \DIRECTORY_SEPARATOR, $relPath); } public static function pruneDir($dir, $limit, $skipDotFiles = true, $remove = false){ $iterator = new \DirectoryIterator($dir); $c = 0; $all = 0; foreach ($iterator as $fileinfo) { if ($fileinfo->isFile()) { $c++; if(true===$skipDotFiles && '.'===substr($fileinfo->getFilename(),0,1))continue; // if($fileinfo->getMTime() < time() - $limit){ if(filemtime($fileinfo->getPathname()) < time() - $limit){ if(file_exists($fileinfo->getPathname()) && is_file($fileinfo->getPathname()) && strlen(realpath($fileinfo->getPathname())) > strlen(realpath($dir)) ){ // echo $fileinfo->getPathname(); // @chmod(dirname($fileinfo->getPathname()), 0775); // @chmod($fileinfo->getPathname(), 0775); unlink($fileinfo->getPathname()); $c=$c-1; } } }elseif ($fileinfo->isDir()){ $firstToken = substr(basename($fileinfo->getPathname()),0,1); if('.'===$firstToken)continue; $subdir = rtrim($fileinfo->getPathname(),'/ ') . DIRECTORY_SEPARATOR; $all += self::pruneDir($subdir, $limit, $skipDotFiles, true); } }//foreach ($iterator as $fileinfo) if(true === $remove && 0 === max($c, $all)){ @rmdir($dir); } return $c; } public static function rglob($pattern, $flags = 0, $traversePostOrder = false) { // Keep away the hassles of the rest if we don't use the wildcard anyway if (strpos($pattern, '/**/') === false) { $files = glob($pattern, $flags); return (!is_array($files)) ? [] : $files; } $patternParts = explode('/**/', $pattern); // Get sub dirs $dirs = glob(array_shift($patternParts) . '/*', \GLOB_ONLYDIR | \GLOB_NOSORT); // Get files for current dir $files = glob($pattern, $flags); $files = (!is_array($files)) ? [] : $files; foreach ($dirs as $dir) { $subDirContent = self::rglob($dir . '/**/' . implode('/**/', $patternParts), $flags, $traversePostOrder); if (!$traversePostOrder) { $files = array_merge($files, $subDirContent); } else { $files = array_merge($subDirContent, $files); } } return (!is_array($files)) ? [] : $files; } public static function rglob2($root, $pattern = "*"){ $fname=$pattern; $result=[]; foreach(self::globdirs($root) as $dir) { $match=glob($dir.'/'.$fname,GLOB_NOSORT); if(!$match) continue; $result=array_merge($result,$match); } return $result; } public static function globdirs($start) { $dirStack=[$start]; while($dir=array_shift($dirStack)) { $ar=glob($dir.'/*',\GLOB_ONLYDIR|\GLOB_NOSORT); if(!$ar) continue; $dirStack=array_merge($dirStack,$ar); foreach($ar as $DIR) yield $DIR; } } } } namespace Webfan\Autoupdate { if (!interface_exists(SVLClassInterface::class)) { ///Single Version Line interface SVLClassInterface { public static function __FRDL_SVLC_INTERVAL(int $interval = null) :int; public static function __FRDL_SVLC_RACE(array $race = null):array; public static function __FRDL_SVLC_UPDATE(); } } if ( !trait_exists( SVLClassTrait::class ) ) { trait SVLClassTrait// implements SVLClassInterface { // public static $__SVLCCLASS_UPDATE_INTERVAL__ = 86400; // public static $__SVLCCLASS_UPDATE_RACE__ = null; public static function __FRDL_SVLC_INTERVAL(int $interval = null) :int{ if(is_int($interval)){ static::$__SVLCCLASS_UPDATE_INTERVAL__= $interval; } return static::$__SVLCCLASS_UPDATE_INTERVAL__; } public static function __FRDL_SVLC_RACE( $race = null):array{ if(!is_array(static::$__SVLCCLASS_UPDATE_RACE__)){ static::$__SVLCCLASS_UPDATE_RACE__= [ 'https://cdn.frdl.io/@webfan3/stubs-and-fixtures/classes/${class}?salt=${salt}&version=${version}', 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=${class}', ]; array_unshift(static::$__SVLCCLASS_UPDATE_RACE__, \frdl\implementation\psr4\RemoteAutoloader::getInstance()->resolve(static::class) ); } if(is_string($race)){ array_unshift(static::$__SVLCCLASS_UPDATE_RACE__, $race ); }elseif(is_array($race)){ static::$__SVLCCLASS_UPDATE_RACE__= array_merge(static::$__SVLCCLASS_UPDATE_RACE__,$race); } return static::$__SVLCCLASS_UPDATE_RACE__; } public static function __FRDL_SVLC_UPDATE($force = false){ if(true!==$force && file_exists(\frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class) ) && filemtime(\frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class) ) > time() - static::__FRDL_SVLC_INTERVAL() ){ return false; } $SourcesRaces=static::__FRDL_SVLC_RACE(); $loader = \frdl\implementation\psr4\RemoteAutoloader::getInstance(); $loader->withClassmap($SourcesRaces); $oldc = \frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class); $links_hint=[]; $trys=[]; $code=false; while(($code===false || empty($code) ) && count($SourcesRaces) > 0){ array_push($trys, array_shift($SourcesRaces) ); $current=$trys[count($trys)-1]; try{ $code = @file_get_contents($current); }catch(\Exception $e){ $code=false; } if($code === false && $current!==__FILE__){ array_push($links_hint, $current ); } } try{ if(false === $code){ throw new \Exception(sprintf('Could not load %s from %s', \frdl\implementation\psr4\RemoteAutoloader::class, print_r($links_hint,true))); }else{ file_put_contents( \frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class), $code); // return require \frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class); } // return require __FILE__; }catch(\Exception $e){ file_put_contents(\frdl\implementation\psr4\RemoteAutoloader::getInstance()->file(static::class), $oldc); throw $e; } } } } } namespace frdl\implementation\psr4{ use Psr\Container\ContainerInterface; use Webfan\Autoupdate\SVLClassTrait as SVLClassTrait; use Webfan\Autoupdate\SVLClassInterface; /* $loader = \frdl\implementation\psr4\RemoteAutoloader::getInstance('frdl.webfan.de', true, 'latest', true); \frdl\implementation\psr4\RemoteAutoloader::getInstance($server = '03.webfan.de', $register = true, $version = 'latest', $allowFromSelfOrigin = false, $salted = false, $classMap = null, $cacheDirOrAccessLevel = self::ACCESS_LEVEL_SHARED, $cacheLimit = null, $password = null) \frdl\implementation\psr4\RemoteAutoloader::getInstance()->url(\frdl\Proxy\Proxy::class, false, false) https://raw.githubusercontent.com/frdl/proxy/master/src/frdl\Proxy\Proxy.php?cache_bust=123 \frdl\implementation\psr4\RemoteAutoloader::getInstance()->urlTemplate(\frdl\Proxy\Proxy::class) https://03.webfan.de/install/?salt=${salt}&source=${class}&version=${version} \frdl\implementation\psr4\RemoteAutoloader::getInstance()->url(\WeidDnsConverter::class) https://raw.githubusercontent.com/frdl/oid2weid/master/src/WeidDnsConverter.php?cache_bust=123 \frdl\implementation\psr4\RemoteAutoloader::getInstance()->urlTemplate(\WeidDnsConverter::class) https://raw.githubusercontent.com/frdl/oid2weid/master/src/WeidDnsConverter.php?cache_bust=${salt} \frdl\implementation\psr4\RemoteAutoloader::getInstance()->resolve(\frdl\Proxy\Proxy::class, 123) https://raw.githubusercontent.com/frdl/proxy/master/src/frdl\Proxy\Proxy.php?cache_bust=123 */ class RemoteAutoloader implements /*ContainerInterface,*/SVLClassInterface { use SVLClassTrait; public static $__SVLCCLASS_UPDATE_RACE__= [ 'https://cdn.frdl.io/@webfan3/stubs-and-fixtures/classes/frdl/implementation/psr4/RemoteAutoloader', 'https://raw.githubusercontent.com/frdl/remote-psr4/master/src/implementations/autoloading/RemoteAutoloader.php', 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=${class}', 'https://cdn.frdl.io/@webfan3/stubs-and-fixtures/classes/${class}?salt=${salt}&version=${version}', ]; const HASH_ALGO = 'sha1'; const ACCESS_LEVEL_SHARED = 0; const ACCESS_LEVEL_PUBLIC = 1; const ACCESS_LEVEL_OWNER = 2; const ACCESS_LEVEL_PROJECT = 4; const ACCESS_LEVEL_BUCKET = 8; const ACCESS_LEVEL_CONTEXT = 16; const CLASSMAP_DEFAULTS = [ 'GuzzleHttp\\uri_template' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\describe_type' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\headers_from_lines' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\debug_resource' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\choose_handler' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\default_user_agent' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\default_ca_bundle' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\normalize_header_keys' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\is_host_in_noproxy' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\json_decode' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', 'GuzzleHttp\\json_encode' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\choose_handler', \GuzzleHttp\LoadGuzzleFunctionsForFrdl::class => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\LoadGuzzleFunctionsForFrdl', // 'GuzzleHttp\\Psr7\\uri_for' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\Psr7\uri_for', 'GuzzleHttp\\Psr7\\uri_for' => 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=GuzzleHttp\Psr7\uri_for', \Wehowski\Gist\Http\Response\Helper::class => 'https://gist.githubusercontent.com/wehowski/d762cc34d5aa2b388f3ebbfe7c87d822/raw/5c3acdab92e9c149082caee3714f0cf6a7a9fe0b/Wehowski%255CGist%255CHttp%255CResponse%255CHelper.php?cache_bust=${salt}', \webfan\hps\Format\DataUri::class => 'https://03.webfan.de/install/?salt=${salt}&source=webfan\hps\Format\DataUri', 'frdl\\Proxy\\' => 'https://raw.githubusercontent.com/frdl/proxy/master/src/${class}.php?cache_bust=${salt}', \frdlweb\Thread\ShutdownTasks::class => 'https://raw.githubusercontent.com/frdl/shutdown-helper/master/src/ShutdownTasks.php?cache_bust=${salt}', 'Fusio\\Adapter\\Webfantize\\' => 'https://raw.githubusercontent.com/frdl/fusio-adapter-webfantize/master/src/${class}.php?cache_bust=${salt}', //frdl\implementation\psr4 //Nette\Loaders\FrdlRobotLoader '@frdl\\implementation\\Load\\ClassMap' => 'Nette\\Loaders\\FrdlRobotLoader', '@frdl\\implementation\\Load\\RemoteClass' => __CLASS__, // NAMESPACES // Zend Framework components '@Zend\\AuraDi\\Config' => 'Laminas\\AuraDi\\Config', '@Zend\\Authentication' => 'Laminas\\Authentication', '@Zend\\Barcode' => 'Laminas\\Barcode', '@Zend\\Cache' => 'Laminas\\Cache', '@Zend\\Captcha' => 'Laminas\\Captcha', '@Zend\\Code' => 'Laminas\\Code', '@ZendCodingStandard\\Sniffs' => 'LaminasCodingStandard\\Sniffs', '@ZendCodingStandard\\Utils' => 'LaminasCodingStandard\\Utils', '@Zend\\ComponentInstaller' => 'Laminas\\ComponentInstaller', '@Zend\\Config' => 'Laminas\\Config', '@Zend\\ConfigAggregator' => 'Laminas\\ConfigAggregator', '@Zend\\ConfigAggregatorModuleManager' => 'Laminas\\ConfigAggregatorModuleManager', '@Zend\\ConfigAggregatorParameters' => 'Laminas\\ConfigAggregatorParameters', '@Zend\\Console' => 'Laminas\\Console', '@Zend\\ContainerConfigTest' => 'Laminas\\ContainerConfigTest', '@Zend\\Crypt' => 'Laminas\\Crypt', '@Zend\\Db' => 'Laminas\\Db', '@ZendDeveloperTools' => 'Laminas\\DeveloperTools', '@Zend\\Di' => 'Laminas\\Di', '@Zend\\Diactoros' => 'Laminas\\Diactoros', '@ZendDiagnostics\\Check' => 'Laminas\\Diagnostics\\Check', '@ZendDiagnostics\\Result' => 'Laminas\\Diagnostics\\Result', '@ZendDiagnostics\\Runner' => 'Laminas\\Diagnostics\\Runner', '@Zend\\Dom' => 'Laminas\\Dom', '@Zend\\Escaper' => 'Laminas\\Escaper', '@Zend\\EventManager' => 'Laminas\\EventManager', '@Zend\\Feed' => 'Laminas\\Feed', '@Zend\\File' => 'Laminas\\File', '@Zend\\Filter' => 'Laminas\\Filter', '@Zend\\Form' => 'Laminas\\Form', '@Zend\\Http' => 'Laminas\\Http', '@Zend\\HttpHandlerRunner' => 'Laminas\\HttpHandlerRunner', '@Zend\\Hydrator' => 'Laminas\\Hydrator', '@Zend\\I18n' => 'Laminas\\I18n', '@Zend\\InputFilter' => 'Laminas\\InputFilter', '@Zend\\Json' => 'Laminas\\Json', '@Zend\\Ldap' => 'Laminas\\Ldap', '@Zend\\Loader' => 'Laminas\\Loader', '@Zend\\Log' => 'Laminas\\Log', '@Zend\\Mail' => 'Laminas\\Mail', '@Zend\\Math' => 'Laminas\\Math', '@Zend\\Memory' => 'Laminas\\Memory', '@Zend\\Mime' => 'Laminas\\Mime', '@Zend\\ModuleManager' => 'Laminas\\ModuleManager', '@Zend\\Mvc' => 'Laminas\\Mvc', '@Zend\\Navigation' => 'Laminas\\Navigation', '@Zend\\Paginator' => 'Laminas\\Paginator', '@Zend\\Permissions' => 'Laminas\\Permissions', '@Zend\\Pimple\\Config' => 'Laminas\\Pimple\\Config', '@Zend\\ProblemDetails' => 'Mezzio\\ProblemDetails', '@Zend\\ProgressBar' => 'Laminas\\ProgressBar', '@Zend\\Psr7Bridge' => 'Laminas\\Psr7Bridge', '@Zend\\Router' => 'Laminas\\Router', '@Zend\\Serializer' => 'Laminas\\Serializer', '@Zend\\Server' => 'Laminas\\Server', '@Zend\\ServiceManager' => 'Laminas\\ServiceManager', '@ZendService\\ReCaptcha' => 'Laminas\\ReCaptcha', '@ZendService\\Twitter' => 'Laminas\\Twitter', '@Zend\\Session' => 'Laminas\\Session', '@Zend\\SkeletonInstaller' => 'Laminas\\SkeletonInstaller', '@Zend\\Soap' => 'Laminas\\Soap', '@Zend\\Stdlib' => 'Laminas\\Stdlib', '@Zend\\Stratigility' => 'Laminas\\Stratigility', '@Zend\\Tag' => 'Laminas\\Tag', '@Zend\\Test' => 'Laminas\\Test', '@Zend\\Text' => 'Laminas\\Text', '@Zend\\Uri' => 'Laminas\\Uri', '@Zend\\Validator' => 'Laminas\\Validator', '@Zend\\View' => 'Laminas\\View', '@ZendXml' => 'Laminas\\Xml', '@Zend\\Xml2Json' => 'Laminas\\Xml2Json', '@Zend\\XmlRpc' => 'Laminas\\XmlRpc', '@ZendOAuth' => 'Laminas\\OAuth', //https://raw.githubusercontent.com/elastic/elasticsearch-php/v7.12.0/src/autoload.php 'Elasticsearch\\' => 'https://raw.githubusercontent.com/elastic/elasticsearch-php/v7.12.0/src/${class}.php?cache_bust=${salt}', \WeidDnsConverter::class => 'https://raw.githubusercontent.com/frdl/oid2weid/master/src/WeidDnsConverter.php?cache_bust=${salt}', \WeidHelper::class => 'https://raw.githubusercontent.com/frdl/oid2weid/master/src/WeidHelper.php?cache_bust=${salt}', \WeidOidConverter::class => 'https://raw.githubusercontent.com/frdl/oid2weid/master/src/WeidOidConverter.php?cache_bust=${salt}', ]; protected $salted = false; protected $selfDomain; protected $server; protected $domain; protected $version; protected $allowFromSelfOrigin = false; protected $prefixes = []; protected $cacheDir; protected $cacheLimit = 0; protected static $instances = []; protected $alias = []; protected static $classmap = []; protected $_currentClassToAutoload = null; public static function getInstance($server = 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=${class}', $register = true, $version = 'latest', $allowFromSelfOrigin = false, $salted = false, $classMap = null, $cacheDirOrAccessLevel = self::ACCESS_LEVEL_SHARED, $cacheLimit = null, $password = null){ if(!is_array($classMap)){ $classMap = self::CLASSMAP_DEFAULTS; }else{ $classMap = array_merge(self::CLASSMAP_DEFAULTS, $classMap); } $classMap = array_merge([ '@frdl\\implementation\\Load\\ClassMap' => 'Nette\\Loaders\\FrdlRobotLoader', '@frdl\\implementation\\Load\\RemoteClass' => static::class, \Webfan\Autoupdate\SVLClassInterface::class=> 'https://cdn.frdl.io/@webfan3/stubs-and-fixtures/classes/frdl/implementation/psr4/RemoteAutoloader', \Webfan\Autoupdate\SVLClassTrait::class => 'https://cdn.frdl.io/@webfan3/stubs-and-fixtures/classes/frdl/implementation/psr4/RemoteAutoloader', ], $classMap); if(is_array($server)){ $instance = []; foreach($server as $indexOrServer => $_s){ $s=array_merge($_s, [ 'server' => (is_string($indexOrServer))?$indexOrServer:$server, 'register'=>$register, 'version'=>$version, 'allowFromSelfOrigin'=>$allowFromSelfOrigin, 'salted'=>$salted, 'classmap'=>(is_string($indexOrServer)&&is_string($_s))?[$indexOrServer=>$_s]:$classmap, 'cacheDirOrAccessLevel'=>$cacheDirOrAccessLevel, 'cacheLimit'=>$cacheLimit, 'password'=>$password, ]); $instance[(is_string($indexOrServer))?$indexOrServer:$_s] = self::getInstance( $s['server'], $s['register'], $s['version'], $s['allowFromSelfOrigin'], $s['salted'], $s['classmap'], $s['cacheDirOrAccessLevel'], $s['cacheLimit'], $s['password']); } //$server = 'file://'.getcwd().\DIRECTORY_SEPARATOR; }elseif(is_string($server)){ $key = static::ik($server, $classMap); if(!isset(self::$instances[$key])){ self::$instances[$key] = new self($server, $register, $version, $allowFromSelfOrigin, $salted, $classMap, $cacheDirOrAccessLevel, $cacheLimit, $password); } $instance = self::$instances[$key]; //$instance::__FRDL_SVLC_UPDATE(); }elseif(0===count(func_get_args())){ return self::$instances; } return $instance; } public function onShutdown(){ return call_user_func_array($this->_getShutdowner(), func_get_args()); } public function pruneCache(){ if($this->cacheLimit !== 0 && $this->cacheLimit !== -1){ $this->onShutdown(function($CacheDir, $maxCacheTime){ \webfan\hps\patch\Fs::pruneDir($CacheDir, $maxCacheTime, true, 'tmp' !== basename($CacheDir)); }, $this->cacheDir, $this->cacheLimit); } } public function get(string $class){ $that = &$this; $r = new \stdclass; $r->name = $class; $r->class = [ 'aliasOf'=>isset($this->alias[$class]) ? $this->alias[$class] : null, 'loaded'=>class_exists($class, false), ]; $r->remote = (isset($that->alias[$class]) ) ? false :[ 'link' => $that->resolve($class), 'exists' => $that->exists($this->resolve($class)), ]; $r->local = (isset($that->alias[$class]) ) ? false :[ 'link' =>$that->file($class), 'cache' => (object)[ 'hit'=> file_exists($this->file($class)), 'expired'=> !file_exists($this->file($class)) || ($interval >= 0 && (false === filemtime($this->file($class)) > time() - $interval)), 'filemtime' => (!file_exists($this->file($class))) ? 0 : filemtime($this->file($class)), ] ]; $make = function(array $options = null) use (&$that, &$make, &$r, $class){ if(!is_array($options))$options=[]; $options['class']=$class; if(!isset($options['interval'])){ $options['interval']=-1; } extract($options); if(isset($classMap)){ $that->withClassmap($classMap); } $r->class = array_merge($r->class, [ 'autoload' => $that->Autoload($class), 'aliasOf'=>isset($that->alias[$class]) ? $that->alias[$class] : null, 'loaded'=>class_exists($class, true), ]); $r->remote = (isset($that->alias[$class]) ) ? false : [ 'link' => $that->resolve($class), 'exists' => $that->exists($this->resolve($class)), ]; $r->local = (isset($that->alias[$class]) ) ? false :[ 'link' =>$that->file($class), 'cache' => (object)[ 'hit'=> file_exists($this->file($class)), 'expired'=> !file_exists($this->file($class)) || ($interval >= 0 && (false === filemtime($this->file($class)) > time() - $interval)), 'filemtime' => (!file_exists($this->file($class))) ? 0 : filemtime($this->file($class)), ], ]; return $r; }; $r->load = $make; $r->__construct = function() use (&$r){ return call_user_func_array($r->name().'::__construct', func_get_args()); }; return $r; } public function has(string $class):bool{ return isset($this->alias[$class]) || file_exists($this->file($class)) || is_string($this->urlTemplate($class)); } public function getCacheDir(){ return $this->cacheDir; } public function file($class){ return rtrim($this->getCacheDir(),\DIRECTORY_SEPARATOR.'/\\ '). \DIRECTORY_SEPARATOR . str_replace('\\', \DIRECTORY_SEPARATOR, $class). '.php'; } public function str_contains($haystack, $needle, $ignoreCase = false) { if ($ignoreCase) { $haystack = strtolower($haystack); $needle = strtolower($needle); } $needlePos = strpos($haystack, $needle); return ($needlePos === false ? false : ($needlePos+1)); } public function str_parse_vars($string,$start = '[',$end = '/]', $variableDelimiter = '='){ preg_match_all('/' . preg_quote($start, '/') . '(.*?)'. preg_quote($end, '/').'/i', $string, $m); $out = []; foreach($m[1] as $key => $value){ $type = explode($variableDelimiter,$value); if(sizeof($type)>1){ if(!is_array($out[$type[0]])) $out[$type[0]] = []; $out[$type[0]][] = $type[1]; } else { $out[] = $value; } } return $out; } public function resolve($class, $salt = null){ return $this->url($class, $salt, false); } public function url($class, $salt = null, $skipCheck = true){ if(true===$salt){ $salt = sha1(mt_rand(1000,99999999).time()); } $url = $this->replaceUrlVars($this->urlTemplate($class, null, $skipCheck), $salt, $class, $this->version); return $url; } public function urlTemplate($class, $salt = null, $skipCheck = true){ return $this->loadClass($class, $salt, $skipCheck); } public function Autoload($class){ $this->_currentClassToAutoload=$class; $cacheFile =$this->file($class); //$cacheFile = realpath($cacheFile); if(file_exists($cacheFile) && ($this->cacheLimit !== 0 && $this->cacheLimit !== -1 && (filemtime($cacheFile) < time() - $this->cacheLimit) )){ if($class!==\frdlweb\Thread\ShutdownTasks::class){ $this->onShutdown(function($cacheFile){ if(file_exists($cacheFile)){ unlink($cacheFile); clearstatcache(true, $cacheFile); } }, $cacheFile); }else{ unlink($cacheFile); clearstatcache(true, $cacheFile); } } if(!file_exists($cacheFile) || ( $this->cacheLimit !== 0 && $this->cacheLimit !== -1 && (filemtime($cacheFile) < time() - $this->cacheLimit) ) ){ $code = $this->fetchCode($class, null); if(true === $code){ return true; }elseif(false !==$code){ if(!is_dir(dirname($cacheFile))){ mkdir(dirname($cacheFile), 0775, true); } if(!file_put_contents($cacheFile, $code)){ throw new \Exception('Cannot write source for class '.$class.' to '.$cacheFile); } }else/*if(false ===$code || !file_exists($cacheFile))*/{ // die($cacheFile); return false; } } if(file_exists($cacheFile) ){ try{ if(false === ($this->requireFile($cacheFile)) ){ if(file_exists($cacheFile)){ unlink($cacheFile); } return false; } }catch(\Exception $e){ unlink($cacheFile); throw new \Exception($e->getMessage()); } //return true; return class_exists($class, false); }elseif(isset($code) && is_string($code)){ /* $code =ltrim($code, ''); eval($code); */ //$tmpfile = tmpfile(); $tmpfile = tempnam($this->cacheDir, 'autoloaded-file.'.sha1($code)); file_put_contents($tmpfile, $code); if($class!==\frdlweb\Thread\ShutdownTasks::class){ $this->onShutdown(function($tmpfile){ if(file_exists($tmpfile)){ unlink($tmpfile); } }, $tmpfile); } if(false === ($this->requireFile($tmpfile)) ){ return false; }else{ return class_exists($class, false); } }else{ throw new \Exception('Cannot write/load source for class '.$class.' in '.$cacheFile); } } public static function ik($server, $classMap){ if(is_array($classMap)){ ksort($classMap); } $hashingData=[$server, $classMap]; return sha1(var_export( $hashingData , true)); } protected function __construct($server = 'https://03.webfan.de/install/?salt=${salt}&version=${version}&source=${class}', $register = true, $version = 'latest', $allowFromSelfOrigin = false, $salted = false, $classMap = null, $cacheDirOrAccessLevel = self::ACCESS_LEVEL_SHARED, $cacheLimit = null, $password = null){ $defauoltcacheLimit = -1; $bucketHash = $this->generateHash([ self::class//, // $version ], '', self::HASH_ALGO, '-'); switch($cacheDirOrAccessLevel){ case self::ACCESS_LEVEL_PUBLIC : $bucket = \get_current_user().\DIRECTORY_SEPARATOR.'shared'; break; case self::ACCESS_LEVEL_OWNER : $bucket = \get_current_user().\DIRECTORY_SEPARATOR .$this->generateHash([ $bucketHash, $version, \get_current_user ( ), //$_SERVER['SERVER_NAME'] // $_SERVER['SERVER_ADDR'] ], $password, self::HASH_ALGO, '-'); break; case self::ACCESS_LEVEL_PROJECT : $bucket = \get_current_user ( ).\DIRECTORY_SEPARATOR .$this->generateHash([ $bucketHash, $version, \get_current_user ( ), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_ADDR'], basename(getcwd()), realpath(getcwd()), ], $password, self::HASH_ALGO, '-'); break; case self::ACCESS_LEVEL_BUCKET : $bucket = \get_current_user ( ).\DIRECTORY_SEPARATOR .$this->generateHash([ $bucketHash, $version ], $password, self::HASH_ALGO, '-'); break; case self::ACCESS_LEVEL_CONTEXT : $bucket = \get_current_user ( ).\DIRECTORY_SEPARATOR .$this->generateHash([ $bucketHash, $version, \get_current_user ( ), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_ADDR'], $_SERVER['REMOTE_ADDR'], basename(getcwd()), realpath(getcwd()) ], $password, self::HASH_ALGO, '-'); break; case self::ACCESS_LEVEL_SHARED : default: $bucket = '_'.\DIRECTORY_SEPARATOR.'shared'; break; } $this->cacheLimit = (is_int($cacheLimit)) ? $cacheLimit : ((isset($_ENV['FRDL_HPS_PSR4_CACHE_LIMIT']))? $_ENV['FRDL_HPS_PSR4_CACHE_LIMIT'] : $defauoltcacheLimit); $this->cacheDir = (is_string($cacheDirOrAccessLevel) && is_dir($cacheDirOrAccessLevel) && is_readable($cacheDirOrAccessLevel) && is_writeable($cacheDirOrAccessLevel) ) ? $cacheDirOrAccessLevel : \sys_get_temp_dir().\DIRECTORY_SEPARATOR // .'.frdl'.\DIRECTORY_SEPARATOR .$bucket.\DIRECTORY_SEPARATOR .'lib'.\DIRECTORY_SEPARATOR .'php'.\DIRECTORY_SEPARATOR .'src'.\DIRECTORY_SEPARATOR .'psr4'.\DIRECTORY_SEPARATOR; /* */ $valCacheDir; $valCacheDir = (function($CacheDir, $checkAccessable = true, $checkNotIsSysTemp = true, $r = null) use(&$valCacheDir){ if(null ===$r)$r=dirname($CacheDir); $checkRoot = substr($r, 0, strlen($CacheDir) ); $checkSame = $r === $CacheDir; $checked = false === $checkNotIsSysTemp || false === $checkSame || ( ( rtrim($CacheDir, \DIRECTORY_SEPARATOR.'/\\ ') !== rtrim(\sys_get_temp_dir(),\DIRECTORY_SEPARATOR.'/\\ ') && 'tmp' !== basename($CacheDir) // && 'tmp' !== basename(dirname($CacheDir)) ) ); return ( $checkAccessable === false || ( // (//is_dir($CacheDir) // || is_dir(dirname($CacheDir)) //|| is_dir(dirname(dirname($CacheDir))) // || // $valCacheDir($r, false, false, $CacheDir) // ) //&& is_writable($CacheDir) && is_readable($CacheDir) ) ) && true === $checked ? true : false ; }); if(!$valCacheDir($this->cacheDir,false,false) ){ throw new \Exception('Bootstrap error in '.basename(__FILE__).' '.__LINE__.' for '.$this->cacheDir); } if(!is_dir($this->cacheDir)){ mkdir($this->cacheDir, 0777,true); } //die($this->cacheDir); if(!is_array($classMap)){ $classMap = self::CLASSMAP_DEFAULTS; } $this->withSalt($salted); $this->withClassmap($classMap); $this->allowFromSelfOrigin = $allowFromSelfOrigin; $this->version=$version; $this->server = $server; $_self = (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']; $h = explode('.', $_self); $dns = array_reverse($h); $this->selfDomain = $dns[1].'.'.$dns[0]; $h = explode('.', $this->server); $dns = array_reverse($h); $this->domain = $dns[1].'.'.$dns[0]; if(!$this->allowFromSelfOrigin && $this->domain === $this->selfDomain){ $register = false; } if(true === $register){ $this->register(); } } public function generateHash( array $chunks = [], $key = null, $algo = 'sha1', $delimiter = '-', &$ctx = null ){ $size = count($chunks); $initial = null === $ctx; $asString = serialize($chunks);//implode($delimiter, $chunks); $buffer = ''; $l = 0; $c = $size + ($initial); if(null===$key || empty($key)){ $c++; $key = \hash( $algo , serialize([$delimiter, [$algo,$size, $delimiter, $c, $asString]]) ); } $MetaCtx = \hash_init ( $algo , \HASH_HMAC, $key ) ; \hash_update($MetaCtx, $key); if( true === $initial || null === $ctx){ $ctx = \hash_init ( $algo , \HASH_HMAC, $key ) ; } while(count($chunks) > 0 && $data = array_shift($chunks)){ $buffer .=$data; $l += strlen($data); $c += count($chunks); \hash_update($ctx, $data); \hash_update($MetaCtx, $buffer); \hash_update($MetaCtx, $l); \hash_update($MetaCtx, $c); } $c++; //$h2 = $this->generateHash([$algo,count($chunks),$l,$asString, $delimiter, $key, $c], $key, 'sha1', $delimiter, $ctx); $h2 = \hash( $algo , $size .'.'. $l. '.' . $c. '.' . strlen($buffer.$asString) ); \hash_update($ctx, $h2); \hash_update($MetaCtx, $h2); $c++; $h3 = hash_final($MetaCtx); \hash_update($ctx, $h3); $hash = hash_final($ctx); return implode($delimiter, [$size .'.'. $l. '.' . $c. '.' . (strlen($h2.$buffer.$asString) * $c) % 20, $h3, $hash, $h2]); } public function withNamespace($prefix, $server, $prepend = false) { // normalize namespace prefix $prefix = trim($prefix, '\\') . '\\'; // normalize the base directory with a trailing separator // $base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/'; // initialize the namespace prefix array if (isset($this->prefixes[$prefix]) === false) { $this->prefixes[$prefix] = []; } // retain the base directory for the namespace prefix if ($prepend) { array_unshift($this->prefixes[$prefix], $server); } else { array_push($this->prefixes[$prefix], $server); } } public function getUrl($class, $server, $salt = null, $parseVars = false){ if(!is_string($salt))$salt=mt_rand(1000,9999); $url = false; if(is_string($server) ){ if(substr($server, 0, strlen('http://')) === 'http://' || substr($server, 0, strlen('https://')) === 'https://'){ // $url = str_replace(['${salt}', '${class}', '${version}'], [$salt, $class, $this->version], $server); $url = $server; }elseif('~' === substr($server, 0, 1) || is_string($server) && '.' === substr($server, 0, 1) || substr($server, 0, strlen('file://')) === 'file://'){ $url = \DIRECTORY_SEPARATOR.str_replace('\\', \DIRECTORY_SEPARATOR, getcwd() .str_replace(['file://', '~'/*, '${salt}', '${class}', '${version}'*/], ['', (!empty(getenv('FRDL_HOME'))) ? getenv('FRDL_HOME') : getenv('HOME')/*, $salt, $class, $this->version*/], $server). '.php'); }elseif(preg_match("/^([a-z0-9]+)\.webfan\.de$/", $server, $m) && false === strpos($server, '/') ){ $url = 'https://'.$m[1].'.webfan.de/install/?salt=${salt}&source=${class}&version=${version}'; }elseif(preg_match("/^([\w\.^\/]+)(\/[.*]+)?$/", $server, $m) && false !== strpos($server, '.') ){ $url = 'https://'.$m[1].((isset($m[2])) ? $m[2] : '/'); }//else{ // $url = 'https://'.$server.'/install/?salt='.$salt.'&source='. $class.'&version='.$this->version; //$url = 'https://'.$server.'/install/?salt=${salt}&source=${class}&version=${version}'; // } if(!$this->str_contains($url, '${class}', false) && '.php' !== substr(explode('?', $url)[0], -4)){ $url = rtrim($url, '/').'/${class}'; } if(!$this->str_contains($url, '${salt}', false)){ $url .= (( $this->str_contains($url, '?', false) ) ? '&' : '?').'salt=${salt}'; } }elseif(is_callable($server)){ $url = call_user_func_array($server, [$class, $this->version, $salt]); }elseif(is_object($server) && is_callable([$server, 'has']) && is_callable([$server, 'get']) && true === call_user_func_array([$server, 'has'], [$class]) ){ $url = call_user_func_array([$server, 'get'], [$class, $this->version, $salt]); }elseif(is_object($server) && is_callable([$server, 'get']) ){ $url = call_user_func_array([$server, 'get'], [$class, $this->version, $salt]); } return (true === $parseVars && is_string($url)) ? $this->replaceUrlVars($url, $salt, $class, $version) : $url; } public function replaceUrlVars($_url, $salt, $class, $version){ $url = str_replace(['${salt}', '${class}', '${version}'], [$salt, $class, $version], $_url); if(substr($_url,0, strlen('http'))==='http' && ( !$this->str_contains($_url, '=${class}', false) || !preg_match("/".preg_quote('=${class}')."/",$_url) ) ){ $url = preg_replace('/\\\\/', '/', $url); } return $url; } /** * Loads the class file for a given class name. * * @param string $class The fully-qualified class name. * @return mixed The mapped file name on success, or boolean false on * failure. */ public function loadClass($class, $salt = null, $skipCheck = false) { // the current namespace prefix $prefix = $class; // work backwards through the namespace names of the fully-qualified // class name to find a mapped file name while (false !== $pos = strrpos($prefix, '\\')) { // retain the trailing namespace separator in the prefix $prefix = substr($class, 0, $pos + 1); // the rest is the relative class name $relative_class = substr($class, $pos + 1); // try to load a mapped file for the prefix and relative class $mapped_file = $this->loadMappedSource($prefix, $relative_class, $salt, $skipCheck); if ($mapped_file) { return $mapped_file; } // remove the trailing namespace separator for the next iteration // of strrpos() $prefix = rtrim($prefix, '\\'); } // never found a mapped file return $this->loadMappedSource('', $class, $salt, $skipCheck); } /** * Load the mapped file for a namespace prefix and relative class. * * @param string $prefix The namespace prefix. * @param string $relative_class The relative class name. * @return mixed Boolean false if no mapped file can be loaded, or the * name of the mapped file that was loaded. */ protected function loadMappedSource($prefix, $relative_class, $salt = null, $skipCheck = false) { $url = false; $class = $prefix.$relative_class; //if(isset($this->alias[$class]) ){ // \webfan\hps\Format\DataUri // die(__LINE__.$class.' Alias: '.$this->alias[$class]); // } $pfx = !isset($this->alias[$prefix]) && substr($prefix,-1) === '\\' ? substr($prefix, 0, -1) : $prefix; if(isset($this->alias[$pfx]) ){ // \webfan\hps\Format\DataUri $originalClass = substr($this->alias[$pfx],-1) === '\\' ? substr($this->alias[$pfx], 0, -1) : $this->alias[$pfx]; $originalClass .= '\\'.$relative_class; $alias = $class; // die($classOrInterfaceExists.'
'.$alias.'
rc: '.$originalClass.'
'.$datUri); $classOrInterfaceExistsAndNotEqualsAlias =( class_exists($originalClass, $originalClass !== $alias) || interface_exists($originalClass, $originalClass !== $alias) || (function_exists('trait_exists') && trait_exists($originalClass, $originalClass !== $alias)) ) && $originalClass !== $alias; if($classOrInterfaceExistsAndNotEqualsAlias){ \class_alias($originalClass, $alias); } return true; //return $classOrInterfaceExistsAndNotEqualsAlias; } if (isset($this->prefixes[$prefix]) ) { // look through base directories for this namespace prefix foreach ($this->prefixes[$prefix] as $server) { $url = $this->getUrl($relative_class, $server, $salt); if(is_string($url) && (false === $skipCheck || $this->exists($url) ) // && '\\' !== substr($class, -1) && '\\' !== substr(self::$classmap[$class], -1) ){ $url = $this->replaceUrlVars($url, $salt, $relative_class, $this->version); return $url; } } } if( isset(self::$classmap[$class]) && is_string(self::$classmap[$class]) // && '\\' !== substr($class, -1) && '\\' !== substr(self::$classmap[$class], -1) ){ return $this->getUrl($class, self::$classmap[$class], $salt); // return self::$classmap[$class]; } // never found it return $this->getUrl($class, $this->server, $salt); } /** * If a file exists, require it from the file system. * * @param string $file The file to require. * @return bool True if the file exists, false if not. */ protected function requireFile($file){ if (file_exists($file)) { try{ require $file; }catch(\Exception $e){ trigger_error($e->getMessage(), \E_USER_ERROR); return false; } return true; } return false; } public function withClassmap(array $classMap = null){ if(null !== $classMap){ foreach($classMap as $class => $server){ if('@' === substr($class, 0, 1) && is_string($server)){ $this->withAlias($class, $server); }elseif('\\' === substr($class, -1)){ $this->withNamespace($class, $server, is_string($server)); }else{ self::$classmap[$class] = $server; } } } return self::$classmap; } public function withAlias(string $alias, string $rewrite){ $this->alias[ltrim($alias, '@')] = $rewrite; } public function withSalt(bool $salted = null){ if(null !== $salted){ $this->salted = $salted; } return $this->salted; } public static function __callStatic($name, $arguments){ $me = (count(self::$instances)) ? self::$instances[0] : self::getInstance(); return call_user_func_array([$me, $name], $arguments); } public function __call($name, $arguments){ if(!in_array($name, ['fetch', 'fetchCode', '__invoke', 'register', 'getLoader', 'Autoload'])){ throw new \Exception('Method '.$name.' not allowed in '.__METHOD__); } return call_user_func_array([$this, $name], $arguments); } protected function fetch(){ return call_user_func_array([$this, 'fetchCode'], func_get_args()); } protected function exists($source){ if('http://'!==substr($source, 0, strlen('http://')) && 'https://'!==substr($source, 0, strlen('https://')) && is_file($source) && file_exists($source) && is_readable($source)){ return true; } $options = [ 'https' => [ 'method' => 'HEAD', 'ignore_errors' => true, ] ]; $context = stream_context_create($options); $res = @file_get_contents($source, false, $context); return false !== $res; } protected function fetchCode($class, $salt = null){ /* $server = (isset(self::$classmap[$class])) ? self::$classmap[$class] : $this->server; */ if(!is_string($salt) //&& true === $this->withSalt() ){ $salt = mt_rand(10000000,99999999); } // $url = $this->loadClass($class, $salt, false); $url = $this->resolve($class, $salt); if(is_bool($url)){ return $url; } $withSaltedUrl = (true === $this->str_contains($url, '${salt}', false)) ? true : false; // $url = $this->replaceUrlVars($url, $salt, $class, $this->version); // print_r($url.'
'); $options = [ 'https' => [ 'method' => 'GET', 'ignore_errors' => true, ] ]; $context = stream_context_create($options); $code = @file_get_contents($url, false, $context); $statusCode = 0; //$code = file_get_contents($url); if(isset($http_response_header) && is_array($http_response_header)){ foreach($http_response_header as $i => $header){ if(0===$i){ preg_match('{HTTP\/\S*\s(\d{3})}', $header, $match); $statusCode = intval($match[1]); } $h = explode(':', $header); if('x-content-hash' === strtolower(trim($h[0]))){ $hash = trim($h[1]); } if('x-user-hash' === strtolower(trim($h[0]))){ $userHash = trim($h[1]); } } } else{ } if( 200!==$statusCode || false===$code || !is_string($code) || (true === $withSaltedUrl && true === $this->withSalt() && (!isset($hash) || !isset($userHash))) ){ // throw new \Exception('Missing checksums while fetching source code for '.$class.' from '.$url); return false; } $oCode =$code; if(is_string($salt) && true === $withSaltedUrl && true === $this->withSalt() ){ $hash_check = strlen($oCode).'.'.sha1($oCode); $userHash_check = sha1($salt .$hash_check); if($hash_check !== $hash || $userHash_check !== $userHash){ throw new \Exception('Invalid checksums while fetching source code for '.$class.' from '.$url); } } $code = trim($code); if(!$this->str_contains($code, ' '); $codeWithStartTags = "getLoader(), func_get_args()); } public function register($throw = true, $prepend = false){ $res = false; if(!$this->allowFromSelfOrigin && $this->domain === $this->selfDomain){ throw new \Exception('You should not autoload from remote where you have local access to the source (remote server = host)'); } $aFuncs = \spl_autoload_functions(); if(!is_array($aFuncs) || !in_array($this->getLoader(), $aFuncs) ){ $res = \spl_autoload_register($this->getLoader(), $throw, $prepend); } if( false !== $res ){ $this->pruneCache(); }else{ throw new \Exception(sprintf('Cannot register Autoloader of "%s" with cachedir "%s"', __METHOD__, $this->cacheDir)); } return $res; } protected function getLoader(){ return [$this, 'Autoload']; } protected function _getShutdowner(){ $load = $this->_currentClassToAutoload !== \frdlweb\Thread\ShutdownTasks::class; return (class_exists(\frdlweb\Thread\ShutdownTasks::class, $load )) ? \frdlweb\Thread\ShutdownTasks::mutex() : function(){ call_user_func_array('register_shutdown_function', func_get_args()); register_shutdown_function(function(){ $t = class_exists(\frdlweb\Thread\ShutdownTasks::class, $load); }); }; } } }