简而言之,Composer 为我制作的自动生成的 autoload.php 实际上并未加载任何内容。
我以前用过Composer安装过别人的项目,但这是我第一次用它来管理自己项目中的依赖关系。
这是我的
composer.json
。为了保护无辜者,名字已更改:
{
"name": "MyWorkplace/MyApp",
"description": "A very cool doohickey.",
"authors": [
{
"name": "wdmartin",
"email": "[email protected]"
}
],
"require": {
"onelogin/php-saml": "4.1.*"
}
}
输入该要求行后,我运行了
composer update
。它下载了 php-saml 库及其依赖项 xmlseclibs,并生成了一个 autoload.php 文件。
所以我开始处理项目中的第一个文件,如下所示:
<?php
require_once('vendor/autoload.php');
use OneLogin\Saml2\Settings;
// settings.php just creates the $settingsInfo array.
require_once('settings.php');
$settings = new Settings($settingsInfo, true);
运行代码会产生错误:
Fatal error: Uncaught Error: Class "OneLogin\Saml2\Settings" not found
自动加载器显然没有自动加载类定义。
我尝试将
autoload.php
的输出保存到变量中并将其转储,这给了我这样的结果:
object(Composer\Autoload\ClassLoader)#1 (11) {
["vendorDir":"Composer\Autoload\ClassLoader":private]=>
string(24) "/var/www/html/vendor"
["prefixLengthsPsr4":"Composer\Autoload\ClassLoader":private]=>
array(2) {
["R"]=>
array(1) {
["RobRichards\XMLSecLibs\"]=>
int(23)
}
["O"]=>
array(1) {
["OneLogin\"]=>
int(9)
}
}
["prefixDirsPsr4":"Composer\Autoload\ClassLoader":private]=>
array(2) {
["RobRichards\XMLSecLibs\"]=>
array(1) {
[0]=>
string(63) "/var/www/html/vendor/composer/../robrichards/xmlseclibs/src"
}
["OneLogin\"]=>
array(1) {
[0]=>
string(58) "/var/www/html/vendor/composer/../onelogin/php-saml/src"
}
}
["fallbackDirsPsr4":"Composer\Autoload\ClassLoader":private]=>
array(0) {
}
["prefixesPsr0":"Composer\Autoload\ClassLoader":private]=>
array(0) {
}
["fallbackDirsPsr0":"Composer\Autoload\ClassLoader":private]=>
array(0) {
}
["useIncludePath":"Composer\Autoload\ClassLoader":private]=>
bool(false)
["classMap":"Composer\Autoload\ClassLoader":private]=>
array(1) {
["Composer\InstalledVersions"]=>
string(67) "/var/www/html/vendor/composer/../composer/InstalledVersions.php"
}
["classMapAuthoritative":"Composer\Autoload\ClassLoader":private]=>
bool(false)
["missingClasses":"Composer\Autoload\ClassLoader":private]=>
array(0) {
}
["apcuPrefix":"Composer\Autoload\ClassLoader":private]=>
NULL
}
我可以看到应该加载的类,但它们不存在。我尝试跑步
get_declared_classes()
;在总是加载的原生 PHP 类的巨大列表的末尾,我发现了以下三个条目:
[215]=>
string(54) "ComposerAutoloaderInita5339d1e68f4fc243101898f7cd6b2b7"
[216]=>
string(29) "Composer\Autoload\ClassLoader"
[217]=>
string(68) "Composer\Autoload\ComposerStaticInita5339d1e68f4fc243101898f7cd6b2b7"
所以自动加载器肯定是自动加载本身。但 OneLogin\Saml2 类不在列表中,它的依赖项 XMLSecLibs 也不在列表中。
我尝试手动编辑自动加载文件,让它们通过沿途转储一堆信息来告诉我它们在做什么,但是除了验证自动加载器代码实际上是否具有正确的路径之外,没有产生任何可用的信息库的文件夹。
这是我对此进行猛烈抨击的第二天。这可能是非常明显的事情,但我没有看到。我当然可以直接将代码与
require_once('vendor/onelogin/php-saml/src/Saml2/Settings.php');
之类的东西链接起来,但这首先就违背了使用 Composer 的目的。任何建议将不胜感激。
编辑:
composer show
的输出
onelogin/php-saml 4.1.0 OneLogin PHP SAML Toolkit
robrichards/xmlseclibs 3.1.1 A PHP library for XML Security
编辑2: AlexHowansky 请求的一些调试输出。我运行了这段代码:
header('Content-Type: text/plain');
require_once('vendor/autoload.php');
print "Class exists?:\n";
var_dump(class_exists(\OneLogin\Saml2\Settings::class));
print "\n\nIs it in the array of declared classes?\n";
var_dump(in_array(\OneLogin\Saml2\Settings::class, get_declared_classes()));
它生成以下输出:
Class exists?:
bool(false)
Is it in the array of declared classes?
bool(false)
此外,我还检查了所有文件权限,以防网络服务器无权读取它,它们看起来没问题。
您的配置和代码看起来不错,并且在 RHEL 9 docker 映像上可以正常工作。如果你跑步:
require_once('vendor/autoload.php');
var_dump(class_exists(\OneLogin\Saml2\Settings::class));
var_dump(in_array(\OneLogin\Saml2\Settings::class, get_declared_classes()));
并得到:
bool(false)
bool(false)
然后看起来要求工作正常,否则脚本将在此时中止并且永远不会运行 var_dump() 调用。这将得出两个结论:1) 您的 Web 服务器进程无法读取文件,2) 您已禁用错误报告。
您可以运行类似
chmod -R 775 vendor
的递归权限更改,但这可能过于宽松。理想情况下,您希望这些文件由运行 Web 服务器进程的用户以外的用户拥有,然后将权限最低限度设置为仅允许读取。 chmod -R 755 vendor
更可取。
要启用错误报告,请加载运行
phpinfo()
函数的页面。这将告诉您网络服务器进程正在使用哪个 INI 文件。请参阅其内容以了解以下值:
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
注意,如果这只是一个开发服务器,我不确定我是否会费心使用 Apache,它(显然)增加的麻烦超过了它的价值。查看内置 Web 服务器,它对于本地开发来说已经足够了。我通常只是将这样的内容添加到我的
composer.json
文件中:
"scripts": {
"go": [
"Composer\\Config::disableProcessTimeout",
"php -S localhost:8000 -t public/"
]
},
然后我可以使用
composer go
从 CLI 启动本地服务器。