frdl / remote-psr4
一个从远程服务器自动加载的php psr4 自动加载器。
v1.2.0
2023-09-17 16:48 UTC
Requires
- php: >=7.2 | >=8.0
Suggests
- frdl/codebase: More autoloading strategy...
- frdlweb/webfat: An Implementation wich is wrapping this package.
This package is auto-updated.
Last update: 2024-10-01 20:55:56 UTC
README
一个从一个或多个远程服务器自动加载的php PSR-4[?] 自动加载器 Client
。带有远程 Classmap 和 别名。
服务器?
如果您想为这个客户端构建一个 API Server
,您可以安装我的包 frdl/codebase
。
这适用于更大的项目,请只使用 我的API服务器 进行测试,如果想要在生产中使用或者需要更大的负载量,请与我联系! 如果您需要关于我的包的帮助,或者需要托管计划,您也可以与我联系!
可选地,您可以配置客户端,例如从githubs 没有中央服务器 加载。
用法
$loader = \frdl\implementation\psr4\RemoteAutoloader::getInstance('03.webfan.de', true, 'latest', true);
...或者...
带有(自定义)配置
- Classmap(带有PSR4和别名)
- 缓存设置
$config = [ 'FRDL_UPDATE_CHANNEL' => 'latest', // stable | latest 'FRDL_REMOTE_PSR4_CACHE_DIR'=> \sys_get_temp_dir().\DIRECTORY_SEPARATOR. \get_current_user() .\DIRECTORY_SEPARATOR.'.frdl'.\DIRECTORY_SEPARATOR.'runtime'.\DIRECTORY_SEPARATOR.'cache'.\DIRECTORY_SEPARATOR .'classes'.\DIRECTORY_SEPARATOR.'psr4'.\DIRECTORY_SEPARATOR, 'FRDL_REMOTE_PSR4_CACHE_LIMIT'=> 24 * 60 * 60, ]; // $workspace is the DEFAULT Psr4 Server // e.g.: $workspace = 'https://webfan.de/install/'. $config['FRDL_UPDATE_CHANNEL'].'/?source=${class}&salt=${salt}&source-encoding=b64' $loader = call_user_func(function($config,$workspace){ return \frdl\implementation\psr4\RemoteAutoloaderApiClient::getInstance($workspace, false, $config['FRDL_UPDATE_CHANNEL'], false, false, /*Classmap (with PSR4 and Alias)*/ [ // (CLASSMAP) Concrete Classes: \frdlweb\Thread\ShutdownTasks::class => 'https://raw.githubusercontent.com/frdl/shutdown-helper/master/src/ShutdownTasks.php', \Webfan\Webfat\Jeytill::class => 'https://raw.githubusercontent.com/frdl/webfat-jeytill/main/src/Jeytill.php', // (PSR4) NAMESPACES = \\ at the end: 'frdl\\Proxy\\' => 'https://raw.githubusercontent.com/frdl/proxy/master/src/${class}.php?cache_bust=${salt}', // ALIAS = @ as first char: '@Webfan\\Autoloader\\Remote' => __CLASS__, // ALIAS works with PSR4-Namespace too: '@BetterReflection\\'=>'Roave\BetterReflection\\', //Versions at Webfan: // Default/Fallback Versions Server: \webfan\hps\Format\DataUri::class => 'https://webfan.de/install/?salt=${salt}&source=webfan\hps\Format\DataUri', // Stable/Current Versions Server: //\webfan\hps\Format\DataUri::class => 'https://webfan.de/install/stable/?salt=${salt}&source=webfan\hps\Format\DataUri', // Latest/Beta Versions Server: // \webfan\hps\Format\DataUri::class => 'https://webfan.de/install/latest/?salt=${salt}&source=webfan\hps\Format\DataUri', ], $config['FRDL_REMOTE_PSR4_CACHE_DIR'], $config['FRDL_REMOTE_PSR4_CACHE_LIMIT'] ); }, $config,'https://webfan.de/install/'. $config['FRDL_UPDATE_CHANNEL'].'/?source=${class}&salt=${salt}&source-encoding=b64');
更多示例...
/** More Examples: */ $loader->withClassmap([ //Alias: '@'.\BetterReflection\Reflection\ReflectionFunction::class => \Roave\BetterReflection\BetterReflection::class, '@'.\BetterReflection\SourceLocator\Exception\TwoClosuresOneLine::class => \Roave\BetterReflection\SourceLocator\Exception\TwoClosuresOnSameLine::class, \Webfan\Webfat\MainModule::class => 'https://raw.githubusercontent.com/frdl/recommendations/master/src/Webfan/Webfat/MainModule.php?cache_bust=${salt}', //Conrete class AND namespace: ORDER matters! //Classmaps SHOULD be sorted DESC in most cases, CLASS should be listed BEFORE namespace if equal FQN. \Webfan\Webfat\Module::class => 'https://raw.githubusercontent.com/frdl/recommendations/master/src/Webfan/Webfat/Module.php?cache_bust=${salt}', 'Webfan\Webfat\Module\\' => 'https://raw.githubusercontent.com/frdl/recommendations/master/src/Webfan/Webfat/Module/${class}.php?cache_bust=${salt}', 'Webfan\Webfat\Intent\\' => 'https://raw.githubusercontent.com/frdl/recommendations/master/src/Webfan/Webfat/Intent/${class}.php?cache_bust=${salt}', \Pimple::class => 'https://raw.githubusercontent.com/silexphp/Pimple/1.1/lib/Pimple.php', 'Task\Plugin\Console\\' => 'https://github.com/taskphp/console/blob/00bfa982c4502938ca0110d2f23c5cd04ffcbcc3/src/${class}.php?cache_bust=${salt}', 'Task\\' => 'https://raw.githubusercontent.com/taskphp/task/7618739308ba484b5f90a83d5e1a44e1d90968d2/src/${class}.php?cache_bust=${salt}', '@BetterReflection\\'=>'Roave\BetterReflection\\', ]);
注册自动加载器
$loader->register(false); // Prepend autoloader to autoloader-stack: // $loader->register(true);
预置自动加载器:如果您想预置自动加载器,您必须在注册自动加载器之前将公共静态变量 allwaysAppendAutoloader 设置为 false!
public static $alwaysAppendLoader = true;
\frdl\implementation\psr4\RemoteAutoloader::$alwaysAppendLoader = $loader::$alwaysAppendLoader = false; $loader->register(true);
这不推荐使用,因为这个加载器从远程加载,为了性能,您应该优先考虑本地类(在生产环境中例如)。
带有(自定义)验证器
- ->withBeforeMiddleware()
- ->withAfterMiddleware()
- ->withWebfanWebfatDefaultSettings()
//... $publicKeyChanged = false; $increaseTimelimit = true; $setPublicKey = function($baseUrl,$expFile, $pubKeyFile){ if(file_exists($expFile)){ $expires = intval(file_get_contents($expFile)); }else{ $expires = 0; } if($expires > 0 && ($expires === time() || ($expires > time() - 3 && $expires < time() + 3))){ sleep(3); } if($expires <= time() || !file_exists($pubKeyFile) ){ $opts =[ 'http'=>[ 'method'=>'GET', //'header'=>"Accept-Encoding: deflate, gzip\r\n", ], ]; $context = stream_context_create($opts); $key = file_get_contents($baseUrl.'source=@server.key', false, $context); foreach($http_response_header as $i => $header){ $h = explode(':', $header); if('x-frdlweb-source-expires' === strtolower(trim($h[0]))){ file_put_contents($expFile, trim($h[1]) ); break; } } file_put_contents($pubKeyFile, $key); } }; $getDefaultValidatorForUrl = function($baseUrl, $cacheDir, $increaseTimelimit = true) use($setPublicKey, &$publicKeyChanged) { $expFile = rtrim($cacheDir, '\\/ ') . \DIRECTORY_SEPARATOR.'validator-'.sha1($baseUrl).strlen($baseUrl).'.expires.txt'; $pubKeyFile = rtrim($cacheDir, '\\/ ') . \DIRECTORY_SEPARATOR.'validator-'.sha1($baseUrl).strlen($baseUrl).'.public-key.txt'; $setPublicKey($baseUrl,$expFile, $pubKeyFile); $condition = function($url, &$loader, $class) use($baseUrl, $increaseTimelimit){ if($increaseTimelimit){ set_time_limit(min(180, intval(ini_get('max_execution_time')) + 90)); } if($baseUrl === substr($url, 0, strlen($baseUrl) ) ){ return true; }else{ return false; } }; $cb = null; $filter = function($code, &$loader, $class, $c = 0) use(&$cb, $baseUrl, $expFile, $pubKeyFile, $setPublicKey, &$publicKeyChanged) { $c++; $sep = 'X19oYWx0X2NvbXBpbGVyKCk7'; $my_signed_data=$code; $public_key = file_get_contents($pubKeyFile); list($plain_data,$sigdata) = explode(base64_decode($sep), $my_signed_data, 2); list($nullVoid,$old_sig_1) = explode("----SIGNATURE:----", $sigdata, 2); list($old_sig,$ATTACHMENT) = explode("----ATTACHMENT:----", $old_sig_1, 2); $old_sig = base64_decode($old_sig); $ATTACHMENT = base64_decode($ATTACHMENT); if(empty($old_sig)){ return new \Exception("ERROR -- unsigned data"); } \openssl_public_decrypt($old_sig, $decrypted_sig, $public_key); $data_hash = sha1($plain_data.$ATTACHMENT).substr(str_pad(strlen($plain_data.$ATTACHMENT).'', 128, strlen($plain_data.$ATTACHMENT) % 10, \STR_PAD_LEFT), 0, 128); if($decrypted_sig === $data_hash && strlen($data_hash)>0){ return $plain_data; }else{ if(!$publicKeyChanged && $c <= 1){ $publicKeyChanged = true; unlink($pubKeyFile); unlink($expFile); $setPublicKey($baseUrl, $expFile, $pubKeyFile); return $cb($code, $loader, $class, $c); } return new \Exception("ERROR -- untrusted signature"); } }; $cb = $filter; return [$condition, $filter]; }; $getDefaultValidators = function($cacheDir, $increaseTimelimit = true) use($getDefaultValidatorForUrl) { return [ $getDefaultValidatorForUrl('https://webfan.de/install/stable/?', $cacheDir, $increaseTimelimit), $getDefaultValidatorForUrl('https://webfan.de/install/latest/?', $cacheDir, $increaseTimelimit), $getDefaultValidatorForUrl('https://webfan.de/install/?', $cacheDir, $increaseTimelimit), ]; }; foreach($getDefaultValidators($cacheDir, $increaseTimelimit) as $validator){ $loader->withAfterMiddleware($validator[0], $validator[1]); } $loader->withBeforeMiddleware(function($class, &$loader){ switch($class){ case \DI\Compiler\Compiler::class : $aDir = dirname($loader->file($class)); if(!is_dir($aDir)){ mkdir($aDir, 0755, true); } $aFile = $aDir.\DIRECTORY_SEPARATOR.'Template.php'; if(!file_exists($aFile)){ file_put_contents($aFile, file_get_contents('https://raw.githubusercontent.com/PHP-DI/PHP-DI/master/src/Compiler/Template.php')); } return true; break; default: return true; break; } /* return true; return false to skip this autoloader, return any/VOID to continue */ }); //...
应用程序和PHP版本预设
为了捆绑预设并将其缓存,以便在下一个请求中更快地加载,您可以使用以下方法
- ->getClassmapFor Webfan API提供一个端点,用于获取包含应用程序/组的类的捆绑类映射以及特定的
PHP版本
。目前,Frdlweb可能会废弃PHP 7对新产品的支持,但可能会支持 >=7+ 和 >=8+。$version参数应该是latest
、stable
和legacy
的枚举。$app参数default
或*
捆绑了大多数框架类,您还可以指定当前的应用程序
- io4
- frdl/codebase | codebase
- webfan | webfat | webfan-website | webfan-webfat
public function getClassmapFor(string $app, string $version, string $phpVersion = \PHP_VERSION, int | bool $cache = true) : array | bool
请求以下API端点:` curl -X 'GET'
'https://api.webfan.de/v1/install/generate/default/latest/autoloading/remote-mapping/8.2/classmap'
-H 'accept: /'
`
成功的响应看起来像(类映射在结果成员中)
{ "code": 200, "message": "Your (remote-fetcher-) classmap was generated in the result property.", "for": { "app": "default", "version": "latest", "php_version": "8.2" }, "result": { "@frdl\\Facades": "Webfan\\FacadesManager", "Webfan\\ComposerAdapter\\": "https://raw.githubusercontent.com/frdl/composer-adapter/master/src/${class}.php?cache_bust=${salt}", "Webfan\\Codebase\\Server\\BundleExportHelper": "https://webfan.de/install/?source=Webfan\\Codebase\\Server\\BundleExportHelper&salt=${salt}", "WMDE\\VueJsTemplating\\": "https://raw.githubusercontent.com/wmde/php-vuejs-templating/2.0.0/src/${class}.php?cache_bust=${salt}", " ... ": " ... " } }
要加载与您正在运行的PHP版本相对应的类映射,从缓存或API加载,并立即将类映射自动加载定义附加到$loader,您可以使用以下方法
- ->withClassmapFor
withClassmapFor(string $app, string $version, string $phpVersion = \PHP_VERSION, int | bool $cache = true)