Apache 2.4 + несколько PHP на Windows XP с одноядерным API
Извиняюсь за долгое чтение, но я думаю, что имеет смысл включать как можно больше подробностей, вместо того, чтобы ждать, пока люди попросят различные конфиги, логи и т. Д.
У меня старый ПК под управлением XP с установленным One Core API.
Я использую это для тестирования Apache 2.4.38 с несколькими версиями PHP. Все работает отлично, за исключением того, что PHP 7.2 и 7.3 возвращают статус 404 для всех файлов php с сообщением "Входной файл не указан". Журналы Apache, если я правильно их читаю, показывают, что php-cgi.exe вызывается правильно и отвечает за возвращение этого статуса, даже если файлы существуют.
SysInternals Process Monitor показывает, что Apache "httpd.exe" не находит php-файлы без проблем. После этого все версии PHP до 7.1 проверяют как "user.ini", так и запрашиваемый файл php. Версии 7.2 и 7.3, однако, проверяют только "user.ini" и вообще не пытаются получить доступ к запрошенному файлу php. Несмотря на это, они возвращают ошибку 404 с сообщением "Входной файл не указан".
Теперь я все уменьшил до рабочей конфигурации, которая показана ниже, если кто-то хочет попробовать это для себя. Apache и все сборки PHP установлены в папке, названной в соответствии с их 5-значным идентификатором версии. Есть один тестовый сайт "test2.local", который содержит один индексный файл.
- Все 32-битные и все версии PHP не являются потокобезопасными (nts) версиями.
- Apache - это текущая сборка из Apache Lounge (по состоянию на 8 февраля 2019 года).
- PHP <= 5.5 - последние сборки для каждой версии.
- PHP> = 5.6 - все текущие сборки (по состоянию на 8 февраля 2019 г.).
- Все сборки PHP - это готовые двоичные файлы из php.net.
- Все среды выполнения VC установлены и работают (2008, 2012, 2017).
- Для простоты расширения PHP не загружаются.
- Все версии PHP имеют собственный файл php.ini в своей папке.
- Все двоичные файлы были проверены, и нет никаких отсутствующих зависимостей, за исключением обычных преступников (расширения PHP, которые полагаются на стороннее программное обеспечение, которое не установлено).
- Все версии "php.exe" и "php-cgi.exe" отлично работают из командной строки и без ошибок регистрируются в журнале ошибок PHP.
- Все версии "php-cgi.exe" до 7.1 отлично работают с Apache, также без каких-либо ошибок в журнале.
- Версии 7.2 и 7.3 программы "php-cgi.exe" показывают состояние 404 для всех файлов php в журнале ошибок Apache, но опять же, ничего не регистрируйте в журнале ошибок 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>
Все конфигурации PHP одинаковы, за исключением того, что версии 7.1 и выше включают директиву default_charset, которая, если она отсутствует, вызывает 500 внутренних ошибок сервера. Я нашел это решение для 7.1 (которое также изначально не работало, но работает сейчас) благодаря страницам миграции на php.net. Я не могу найти ничего, что указывает на то, что необходимы дальнейшие изменения для 7.2 или 7.3.
- http://php.net/manual/en/migration71.php
- http://php.net/manual/en/migration72.php
- http://php.net/manual/en/migration73.php
Полное содержимое файлов "php.ini" выглядит следующим образом (XXXXX = идентификатор версии):
[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", но я пытался это сделать безуспешно. На самом деле, включение этих настроек имело только эффект обе переменные "SCRIPT_NAME" и "PHP_SELF" были установлены на "D:/index.php" вместо "/index.php" во всех рабочих версиях 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
Журнал Apache для запроса " http://test2.local/index.php " (PHP 7.1):
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
Снимок экрана Process Monitor для " http://test2.local/index.php " (PHP 7.1):
Журнал Apache для запроса " http://test2.local/index.php " (PHP 7.2):
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
Снимок экрана Process Monitor для " http://test2.local/index.php " (PHP 7.2):
Любая помощь в разгадке этой тайны будет высоко оценена. Снова извиняюсь за длительное чтение.
1 ответ
Ну, для тех, кто заинтересован, я наконец-то разобрался с проблемой, и вы можете заставить ее работать, если вы захотите пересобрать PHP самостоятельно.
Виновником является вызов функции "FindFirstFileExW" в kernel32, которая завершается с ошибкой. Это один из файлов, который переименовывает One Core API и предоставляет оболочку, так что либо оболочка портит вызов (в чем я сомневаюсь), либо реальная функция просто возвращает INVALID_HANDLE_VALUE в XP по любой причине.
До PHP 7.2 функция "FindFirstFileW" использовалась вместо "FindFirstFileExW". Таким образом, исправление - это просто вопрос замены одной строки кода.
Итак, вот что вам нужно сделать, что в настоящее время применимо ко всем версиям PHP 7.2.x и 7.3.x.
Возьмите исходный код 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.