0

为长篇阅读道歉,但我认为在前期包含尽可能多的细节是有意义的,而不是等待人们询问各种配置、日志等。

我有一台运行 XP 并安装了 One Core API 的旧 PC。

我正在使用它来测试具有多个 PHP 版本的 Apache 2.4.38。一切正常,除了 PHP 7.2 和 7.3 为所有 php 文件返回 404 状态并显示“未指定输入文件”消息。Apache 日志,如果我正确阅读它们,表明 php-cgi.exe 被正确调用,并且即使文件存在也负责返回此状态。

SysInternals Process Monitor 显示 Apache 的“httpd.exe”发现 php 文件没有问题。在此之后,直到 7.1 的所有 PHP 版本都检查“user.ini”和请求的 php 文件。然而,版本 7.2 和 7.3 只检查“user.ini”,根本不尝试访问请求的 php 文件。尽管如此,它们还是返回 404 错误,并显示消息“未指定输入文件”。

我现在已经将所有东西缩小到一个简单的工作配置,如果有人想自己尝试一下,下面都会显示。Apache 和所有 PHP 版本都安装在一个根据其 5 位版本 ID 命名的文件夹中。有一个测试站点“test2.local”,其中包含一个索引文件。

  • 一切都是 32 位的,所有 PHP 版本都是非线程安全 (nts) 版本。
  • Apache 是 Apache Lounge 的当前版本(截至 2019 年 2 月 8 日)。
  • PHP <=5.5 是每个版本的最后构建。
  • PHP >=5.6 是所有当前版本(截至 2019 年 2 月 8 日)。
  • PHP 构建都是来自 php.net 的预构建二进制文件。
  • 所有 VC 运行时都已安装并正常工作(2008、2012、2017)。
  • 为了简单起见,没有加载任何 PHP 扩展。
  • 所有 PHP 版本在它们自己的文件夹中都有自己的“php.ini”文件。
  • 所有二进制文件都经过检查,除了通常的罪魁祸首(依赖于未安装的第三方软件的 PHP 扩展)外,没有缺少依赖项。
  • “php.exe”和“php-cgi.exe”的所有版本都可以在命令行中完美运行,并且不会在 PHP 错误日志中记录任何错误。
  • 最高 7.1 的所有“php-cgi.exe”版本都可以与 Apache 完美配合,也不会记录任何错误。
  • “php-cgi.exe”的 7.2 和 7.3 版本在 Apache 错误日志中显示所有 php 文件的 404 状态,但同样,不要在 PHP 错误日志中记录任何内容。

文件夹结构:

Apache (Logs folder contains both Apache and PHP logs):
    2.4.38 ....... D:\www\APACHE\20438
    Logs ......... D:\www\APACHE\logs
PHP:
    5.2.17 ....... D:\www\PHP\50217
    5.3.29 ....... D:\www\PHP\50329
    5.4.45 ....... D:\www\PHP\50445
    5.5.17 ....... D:\www\PHP\50538
    5.6.40 ....... D:\www\PHP\50640
    7.0.33 ....... D:\www\PHP\70033
    7.1.26 ....... D:\www\PHP\70126
    7.2.15 ....... D:\www\PHP\70215
    7.3.02 ....... D:\www\PHP\70302
Virtual Hosts:
    test2.local .. D:\www\sites\test2  (contains 1 file: index.php)

“D:\www\sites\test2\index.php”的内容:

<?php
echo <<<EOF
<!DOCTYPE html>
<html>
<head><meta charset="us-ascii"><title>test2.local</title></head>
<body><h1>test2.local</h1></body>
</html>
EOF;
?>

Apache 配置是我认为最小的:

# Apache 2.4.38 Configuration

Define SRVROOT "D:\www\APACHE\20438"
Define LOGPATH "D:\www\APACHE\logs"
Define DOCROOT "D:\www\sites"

# Here I simply uncomment the PHP version I want to test and then restart Apache.
#Define PHPVER 50217
#Define PHPVER 50329
#Define PHPVER 50445
#Define PHPVER 50538
#Define PHPVER 50640
#Define PHPVER 70033
Define PHPVER 70126
#Define PHPVER 70215
#Define PHPVER 70302

ErrorLog "${LOGPATH}\apache_20438.txt"
LogLevel trace8

ServerRoot "${SRVROOT}"
DocumentRoot "${DOCROOT}"
ServerName apache.local
Listen 192.168.0.1:80

LoadModule access_compat_module     modules/mod_access_compat.so
LoadModule authz_core_module        modules/mod_authz_core.so
LoadModule dir_module               modules/mod_dir.so
LoadModule mime_module              modules/mod_mime.so
LoadModule fcgid_module             modules/mod_fcgid.so

<Directory />
    Options Indexes ExecCGI FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

TypesConfig conf/mime.types
AddType application/x-httpd-php .php
DirectoryIndex index.php index.htm

FcgidInitialEnv SystemRoot "C:\Windows"
FcgidInitialEnv SystemDrive "C:"
FcgidInitialEnv TEMP "D:\www\PHP\${PHPVER}\tmp"
FcgidInitialEnv TMP "D:\www\PHP\${PHPVER}\tmp"
FcgidInitialEnv windir "C:\WINDOWS"
FcgidInitialEnv PHPRC "D:\www\PHP\${PHPVER}"
FcgidInitialEnv PATH "D:\www\PHP\${PHPVER};D:\www\PHP\${PHPVER}\ext;${PATH}"
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 1000
FcgidMaxRequestsPerProcess 10
FcgidMaxProcesses 15
FcgidIOTimeout 50
FcgidIdleTimeout 50
FcgidFixPathinfo 0
FcgidWrapper "D:/www/PHP/${PHPVER}/php-cgi.exe" .php
AddHandler fcgid-script .php

<VirtualHost *:80>
    # This forces unknown addresses to the default site.
    DocumentRoot "${DOCROOT}"
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "${DOCROOT}\test2"
    ServerName test2.local
</VirtualHost>

除了 7.1 及更高版本包含“default_charset”指令外,所有 PHP 配置都相同,如果不存在,则会导致 500 内部服务器错误。由于 php.net 的迁移页面,我找到了适用于 7.1 的解决方案(最初也不起作用,但现在可以)。我找不到任何表明 7.2 或 7.3 需要进一步更改的内容。

“php.ini”文件的完整内容如下(XXXXX = 版本 ID):

[PHP]
; Paths at the top for ease of copying configurations, which
; in this case you would only need to edit these two lines.
extension_dir="D:/www/PHP/XXXXX/ext"
error_log="D:/www/APACHE/logs/php_XXXXX.txt"

allow_url_fopen=On
allow_url_include=Off
asp_tags=Off
auto_globals_jit=On
cgi.fix_pathinfo=0
cgi.force_redirect=0

; default_charset must be set for PHP 7.1 onwards
default_charset="us-ascii"

default_mimetype="text/html"
default_socket_timeout=60
display_errors=On
display_startup_errors=On
engine=On
error_reporting=E_ALL
expose_php=On
html_errors=Off
ignore_repeated_errors=On
ignore_repeated_source=Off
implicit_flush=Off
log_errors=On
log_errors_max_len=1024
magic_quotes_gpc=Off
magic_quotes_runtime=Off
magic_quotes_sybase=Off
max_execution_time=0
max_input_time=60
memory_limit=128M
output_buffering=On
post_max_size=16M
precision=14
register_argc_argv=Off
register_globals=Off
register_long_arrays=Off
report_memleaks=On
request_order="GP"
serialize_precision=100
short_open_tag=On

; Default value for user_ini.filename is ".user.ini". I remove the first
; period here for ease. (In XP, creating files that begin with a period
; usually causes an error unless done from the command prompt.)
user_ini.filename="user.ini"

variables_order="EGPCS"
y2k_compliance=On
zlib.output_compression=Off

(我在很多地方读到修复路径信息设置应该是“FcgidFixPathinfo = 1”和“cgi.fix_pathinfo = 1”,但我尝试过没有成功。实际上,打开这些设置只有效果在所有工作的 PHP 版本中,“SCRIPT_NAME”和“PHP_SELF”变量都设置为“D:/index.php”而不是“/index.php”。换句话说,打开它会破坏东西而不是修复任何东西。 )

随着一切的启动和运行,测试就像在“ http://test2.local/index.php ”请求页面一样简单。PHP <=7.1 的结果都是一样的,所以我将使用 7.1 的日志。同样,7.2 和 7.3 的结果是相同的,所以我将使用 7.2 的日志。没有 PHP 版本记录任何错误或崩溃。每个版本都在第一次请求时成功加载并继续愉快地运行,直到重新启动 Apache。

Apache 启动日志(所有 PHP 版本)

Setting LogLevel for all modules to trace8
Setting LogLevel for all modules to trace8
AH00455: Apache/2.4.38 (Win32) mod_fcgid/2.3.9 configured -- resuming normal operations
AH00456: Apache Lounge VC15 Server built: Jan 18 2019 12:31:19
AH00094: Command line: 'D:\\www\\APACHE\\20438\\bin\\httpd.exe -d D:/www/APACHE/20438 -E D:/www/APACHE/logs/apache_20438.txt'
AH02639: Using SO_REUSEPORT: no (0)
AH00418: Parent: Created child process 3428
AH00402: Parent: Sent the scoreboard to the child
Setting LogLevel for all modules to trace8
Setting LogLevel for all modules to trace8
AH00453: Child process is running
AH00391: Child: Retrieved our scoreboard from the parent.
AH00403: Child: Waiting for data for listening socket 192.168.0.1:80
AH00408: Parent: Duplicating socket 324 (192.168.0.1:80) and sending it to child process 3428
AH00411: Parent: Sent 1 listeners to child 3428
AH00407: Child: retrieved 1 listeners from parent
AH00352: Child: Acquired the start mutex.
AH00354: Child: Starting 64 worker threads.
mpm child 3428 (gen 0/slot 0) started
AH00334: Child: Accept thread listening on 192.168.0.1:80 using AcceptFilter connect

用于请求“ http://test2.local/index.php ”(PHP 7.1)的 Apache 日志:

Request received from client: GET /index.php HTTP/1.1
Headers received from client:
  Host: test2.local
  User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Language: en-GB,en;q=0.5
  Accept-Encoding: gzip, deflate
  DNT: 1
  Connection: keep-alive
  Upgrade-Insecure-Requests: 1
AH01626: authorization result of Require all granted: granted
AH01626: authorization result of <RequireAny>: granted
request authorized without authentication by access_checker_ex hook: /index.php
mod_fcgid: server test2.local:D:/www/PHP/70126/php-cgi.exe(532) started
Headers from script 'index.php':
  X-Powered-By: PHP/7.1.26
  Content-type: text/html; charset=us-ascii
Response sent with status 200, headers:
  Date: Mon, 18 Feb 2019 01:31:39 GMT
  Server: Apache/2.4.38 (Win32) mod_fcgid/2.3.9
  X-Powered-By: PHP/7.1.26
  Keep-Alive: timeout=5, max=100
  Connection: Keep-Alive
  Transfer-Encoding: chunked
  Content-Type: text/html; charset=us-ascii
brigade contains: bytes: 256, non-file bytes: 256, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 395, non-file bytes: 395, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 400, non-file bytes: 400, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 400, non-file bytes: 400, eor buckets: 1, morphing buckets: 0
will flush because of FLUSH bucket
seen in brigade so far: bytes: 400, non-file bytes: 400, eor buckets: 1, morphing buckets: 0
flushing now
total bytes written: 400
brigade contains: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0
will flush because of FLUSH bucket
seen in brigade so far: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0
flushing now
total bytes written: 400
brigade contains: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0

“ http://test2.local/index.php ”(PHP 7.1)的进程监视器屏幕截图

进程监视器屏幕截图 (PHP 7.1)

用于请求“ http://test2.local/index.php ”(PHP 7.2)的 Apache 日志:

Request received from client: GET /index.php HTTP/1.1
Headers received from client:
  Host: test2.local
  User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Language: en-GB,en;q=0.5
  Accept-Encoding: gzip, deflate
  DNT: 1
  Connection: keep-alive
  Upgrade-Insecure-Requests: 1
AH01626: authorization result of Require all granted: granted
AH01626: authorization result of <RequireAny>: granted
request authorized without authentication by access_checker_ex hook: /index.php
mod_fcgid: server test2.local:D:/www/PHP/70215/php-cgi.exe(808) started
Headers from script 'index.php':
  Status: 404 Not Found
Status line from script 'index.php': 404 Not Found
  X-Powered-By: PHP/7.2.15
  Content-type: text/html; charset=us-ascii
Response sent with status 404, headers:
  Date: Mon, 18 Feb 2019 01:34:54 GMT
  Server: Apache/2.4.38 (Win32) mod_fcgid/2.3.9
  X-Powered-By: PHP/7.2.15
  Keep-Alive: timeout=5, max=100
  Connection: Keep-Alive
  Transfer-Encoding: chunked
  Content-Type: text/html; charset=us-ascii
brigade contains: bytes: 263, non-file bytes: 263, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 294, non-file bytes: 294, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 299, non-file bytes: 299, eor buckets: 0, morphing buckets: 0
brigade contains: bytes: 299, non-file bytes: 299, eor buckets: 1, morphing buckets: 0
will flush because of FLUSH bucket
seen in brigade so far: bytes: 299, non-file bytes: 299, eor buckets: 1, morphing buckets: 0
flushing now
total bytes written: 299
brigade contains: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0
will flush because of FLUSH bucket
seen in brigade so far: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0
flushing now
total bytes written: 299
brigade contains: bytes: 0, non-file bytes: 0, eor buckets: 0, morphing buckets: 0

“ http://test2.local/index.php ”(PHP 7.2)的进程监视器屏幕截图

进程监视器屏幕截图 (PHP 7.2)

任何帮助弄清楚这个谜团将不胜感激。再次为冗长的阅读道歉。

4

1 回答 1

1

好吧,对于任何有兴趣的人,我终于找到了问题所在,如果你愿意自己重新编译 PHP,你可以让它工作。

罪魁祸首是调用 kernel32 中的“FindFirstFileExW”函数失败。这是 One Core API 重命名并为其提供包装器的文件之一,因此无论出于何种原因,包装器都会弄乱调用(我对此表示怀疑),或者实际函数只是在 XP 上返回 INVALID_HANDLE_VALUE。

在 PHP 7.2 之前,使用“FindFirstFileW”函数代替“FindFirstFileExW”。所以修复只是替换一行代码的问题。

所以这是您需要做的,目前适用于所有 7.2.x 和 7.3.x 版本的 PHP。

获取 PHP 源代码并在 Zend 文件夹中打开文件“zend_virtual_cwd.c”。搜索文本“FindFirstFileExW”。文件中只会出现一次,对于 PHP 7.3.2,它位于第 843 行。

837
838     if (save) {
839         pathw = php_win32_ioutil_any_to_w(path);
840         if (!pathw) {
841             return (size_t)-1;
842         }
843         hFind = FindFirstFileExW(pathw, FindExInfoBasic, &dataw, FindExSearchNameMatch, NULL, 0);
844         if (INVALID_HANDLE_VALUE == hFind) {
845             if (use_realpath == CWD_REALPATH) {
846                 /* file not found */
847                 FREE_PATHW()
848                 return (size_t)-1;
849             }
850             /* continue resolution anyway but don't save result in the cache */
851             save = 0;
852         } else {
853             FindClose(hFind);
854         }
855     }
856

好消息是这两个函数都使用 WIN32_FIND_DATA 结构(“dataw”参数)。因此,要让这个在 XP 上运行,我们所要做的就是调用“FindFirstFileW”而不是“FindFirstFileExW”,记住“FindFirstFileW”只需要 2 个参数而不是 6 个。

837
838     if (save) {
839         pathw = php_win32_ioutil_any_to_w(path);
840         if (!pathw) {
841             return (size_t)-1;
842         }
843     //  hFind = FindFirstFileExW(pathw, FindExInfoBasic, &dataw, FindExSearchNameMatch, NULL, 0);
844         hFind = FindFirstFileW(pathw, &dataw);
845         if (INVALID_HANDLE_VALUE == hFind) {
846             if (use_realpath == CWD_REALPATH) {
847                 /* file not found */
848                 FREE_PATHW()
849                 return (size_t)-1;
850             }
851             /* continue resolution anyway but don't save result in the cache */
852             save = 0;
853         } else {
854             FindClose(hFind);
855         }
856     }
856

保存文件并重新构建 PHP。如果您像我一样使用来自 php.net 的预编译二进制文件,则使用原始构建中的相同配置选项构建,然后将原始“php7.dll”(或“php7ts.dll”)替换为新的刚刚建成。如果您没有与原始构建器相同的环境,则需要删除一些配置选项。例如,原始 7.3.2 nts x86 二进制文件的配置选项是:

configure --enable-snapshot-build --enable-debug-pack --disable-zts 
--with-pdo-oci=c:\php-snap-build\deps_aux\oracle\x86\instantclient_12_1\sdk,shared 
--with-oci8-12c=c:\php-snap-build\deps_aux\oracle\x86\instantclient_12_1\sdk,shared 
--enable-object-out-dir=../obj/ --enable-com-dotnet=shared --without-analyzer --with-pgo

由于我没有 Oracle 或 PGO(不管是什么),我只需放弃这些选项并使用

configure --enable-snapshot-build --enable-debug-pack --disable-zts
--enable-com-dotnet=shared --without-analyzer

就是这样 - PHP 7.2.x 和 7.3.x 在 Windows XP 上使用 One Core API。

在 Windows XP 上运行的 PHP 7.3.2

于 2019-02-25T01:35:12.963 回答