修改 httpd.conf 后 PHP require/include 失效
结论
这组错误与 httpd.conf 是否导致 PHP 的 require_once 或 include 失效无关。错误中最值得注意的是:
Failed opening required '1'
PHP 尝试加载的文件名是 1,并非 constants.php。也就是说,传给 require_once 的表达式在运行时成了布尔值 true 或整数 1。
如果实际执行的是:
require_once('constants.php');
错误信息中应该出现 constants.php。现在的结果说明,当前执行的代码、实际访问的站点目录或第 17 行的表达式,至少有一项与预期不同。
DocumentRoot 负责将 HTTP 请求映射到磁盘目录,不会把 PHP 文件名改成 1。Options Includes 控制 Apache SSI,也不影响 PHP 的 include。
检查 require_once 收到的值
打开报错指向的文件:
C:\Program Files (x86)\Zend\Apache2\htdocs\index.php
直接查看第 17 行,不要只对照另一台机器上的副本。可以在调用前输出参数:
<?php
$path = 'constants.php';
var_dump($path, gettype($path));
require_once $path;
正常情况下应显示:
string(13) "constants.php"
如果显示:
bool(true)
或:
int(1)
需要向前追查 $path 的赋值过程。例如,下面的代码误把检测结果传给了 require_once:
<?php
// 错误:file_exists() 返回布尔值
require_once file_exists('constants.php');
文件存在时,file_exists() 返回的 true 会在错误信息中显示为 1。可以改成:
<?php
$path = __DIR__ . DIRECTORY_SEPARATOR . 'constants.php';
if (!is_file($path)) {
throw new RuntimeException('Configuration file not found: ' . $path);
}
require_once $path;
同时检查变量有没有被覆盖、函数是否返回了布尔值,以及条件表达式的括号是否正确。
用脚本目录构造绝对路径
相对路径不一定以当前 PHP 文件所在的目录为基准。PHP 会结合当前工作目录和 include_path 查找文件。如果代码调用过 chdir(),或者入口脚本、任务脚本发生变化,相对路径的解析结果也会随之变化。
如果 constants.php 和 index.php 在同一目录,可以写成:
<?php
require_once __DIR__ . DIRECTORY_SEPARATOR . 'constants.php';
如果当前 PHP 版本不支持 __DIR__,则使用:
<?php
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'constants.php';
如果配置文件放在网站根目录之外,应按真实位置构造路径。例如:
<?php
$configFile = 'C:/private-config/constants.php';
if (!is_readable($configFile)) {
throw new RuntimeException('Cannot read configuration file: ' . $configFile);
}
require_once $configFile;
Windows 下的 PHP 通常能够识别正斜杠,也可以借此减少反斜杠转义问题。
确认 Apache 实际加载的代码
结合“相同文件放在同一目录仍然找不到”和错误中的 '1' 来看,实际请求可能没有运行正在编辑的文件。可以临时建立一个诊断页面:
<?php
header('Content-Type: text/plain; charset=utf-8');
echo '__FILE__: ', __FILE__, PHP_EOL;
echo '__DIR__: ', __DIR__, PHP_EOL;
echo 'getcwd(): ', getcwd(), PHP_EOL;
echo 'DOCUMENT_ROOT: ', $_SERVER['DOCUMENT_ROOT'] ?? '(undefined)', PHP_EOL;
echo 'include_path: ', get_include_path(), PHP_EOL;
echo 'open_basedir: ', ini_get('open_basedir'), PHP_EOL;
echo 'php.ini: ', php_ini_loaded_file() ?: '(none)', PHP_EOL;
核对以下信息:
__FILE__是否指向正在编辑的文件。DOCUMENT_ROOT是否为预期目录。- 是否有另一个 VirtualHost 将同一域名映射到其他目录。
- 浏览器访问的端口是否属于这套 Zend Server。
- 系统中是否还有另一套 Apache、IIS 或其他 Web 服务正在运行。
也可以在目标文件中加入一段容易辨认的临时输出:
<?php
exit('Loaded from: ' . __FILE__);
如果浏览器没有显示这段内容,请检查请求是否进入了其他文件、其他站点实例或缓存层。
确认 Apache 已应用恢复后的配置
恢复 httpd.conf 后必须重启 Apache。如果新配置有语法错误,服务可能启动失败,原来的进程也可能仍在响应请求。
进入 Zend Server 的 Apache bin 目录执行配置检查,具体路径以本机安装位置为准:
httpd.exe -t
httpd.exe -V
httpd.exe -S
这三个命令分别检查配置语法、显示服务器根目录和主配置文件,以及列出 VirtualHost 映射。需要核对:
HTTPD_ROOT和SERVER_CONFIG_FILE是否指向修改过的配置。- 是否通过
Include或IncludeOptional加载了其他配置文件。 - VirtualHost 中是否另外设置了
DocumentRoot。 - Windows 服务实际启动的是哪个
httpd.exe。 - Apache 的重启时间是否与配置修改时间一致。
如果问题描述中的英文说明确实写在 httpd.conf 里,只是在展示时省略了注释符,那么每行说明前都要保留 #。否则 Apache 会把这些文字当成指令并报告语法错误。
检查 PHP 实际加载的配置
错误中显示的搜索路径是:
.;C:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\library
其中的 . 代表当前工作目录,不一定是 index.php 所在目录,因此不应依赖它加载重要配置文件。
建议通过 Web 请求执行 phpinfo(),因为命令行 PHP 和 Apache 使用的配置可能不同,仅运行 php --ini 无法确认 Web 环境的实际配置:
<?php
phpinfo();
检查以下项目:
Loaded Configuration FileScan this dir for additional .ini filesAdditional .ini files parsedinclude_pathopen_basedirauto_prepend_fileauto_append_file
还要在项目和附加配置中搜索:
set_include_path(...)
ini_set('include_path', ...)
chdir(...)
并检查 Apache 或 VirtualHost 配置里是否有:
php_value include_path ...
php_admin_value open_basedir ...
php_value auto_prepend_file ...
AllowOverride None 只表示该目录中的 .htaccess 无法覆盖配置。其他 VirtualHost、Zend Server 管理配置或额外加载的配置文件仍然可能生效。
排查 Windows 权限和链接
确认参数已经是正确的完整路径后,再检查文件系统:
<?php
$path = __DIR__ . DIRECTORY_SEPARATOR . 'constants.php';
var_dump([
'path' => $path,
'realpath' => realpath($path),
'exists' => file_exists($path),
'is_file' => is_file($path),
'is_readable'=> is_readable($path),
]);
根据结果继续判断:
realpath()返回false:路径不存在、链接目标失效,或当前进程无法解析该路径。file_exists()返回false:检查文件名、扩展名、目录和链接目标。is_readable()返回false:检查运行 Apache 服务的 Windows 账户及其 NTFS 权限。- 普通文件可读,但链接目录不可读:检查 junction/symlink 的目标和服务账户权限。
Dropbox 目录可能位于某个特定用户的配置文件下,而 Apache 服务通常由另一个账户运行。登录用户能够访问该目录,不代表服务账户也有权限。网络盘符往往也只对登录用户可见,服务应使用其能够访问的本地路径或 UNC 路径,并配置相应权限。
如果触发了 open_basedir,PHP 通常会明确报告 open_basedir restriction in effect。NTFS 权限不足时,通常会出现 Permission denied。当前错误直接指向文件名 1,应先解决参数值异常,再继续排查权限。
重新安装没有解决问题的原因
重新安装 Zend Server 不一定会删除以下内容:
- 原有站点代码及第 17 行的错误。
- Zend Server 保存的 PHP 配置。
- VirtualHost 或附加
.conf文件。 - Windows 服务注册信息。
- Dropbox 目录、symlink、junction 和 NTFS 权限。
- 仍在运行的另一套 Apache 或 PHP 环境。
继续替换 httpd.conf 很难解决当前问题。应先确认实际执行的文件、PHP 实际加载的配置,以及 require_once 参数的类型和值。
针对现有错误,可以先把调用参数改为可验证的绝对文件路径:
<?php
$configFile = __DIR__ . DIRECTORY_SEPARATOR . 'constants.php';
if (!is_readable($configFile)) {
throw new RuntimeException(
sprintf('Required file is not readable: %s; cwd=%s', $configFile, getcwd())
);
}
require_once $configFile;
如果运行这段代码后仍然报告加载 '1',说明浏览器执行的并非刚才修改的代码。此时应继续检查 Apache 实例、VirtualHost、端口和缓存。
备注:内容仅供参考。
