У меня есть сайт, размещенный у провайдера виртуального хостинга. Это Apache с FPM / FastCGI и PHP 7.2.
Поскольку у меня есть общий хостинг, единственная конфигурация, к которой у меня есть доступ, - это htaccess, но, очевидно, не какой-либо из файлов конфигурации Apache.
У меня есть настраиваемая страница ошибок, настроенная в моем htaccess, например: ErrorDocument 404 /error404.php
. Сегодня я заметил, что моя пользовательская страница с ошибкой 404 не отображается. Вместо обычного текста File not found.
возвращается в браузер с кодом состояния 404 в заголовке. Дальнейшее расследование показало, что это происходит только в том случае, если запрашивается файл. Если вы запрашиваете несуществующий каталог тогда вы получите настраиваемую страницу ошибки! Например, запрос mydomain.info/dummy.htm
выдает ошибку, но запрашивает mydomain.info/dummy/
возвращает настраиваемую страницу ошибки.
Сервер регистрирует ошибку AH01071
который Primary script unknown
для каждого File not found.
ошибка.
Похоже, что ModSecurity включен на сервере, потому что журналы регистрируют отклоненные вредоносные запросы, например [client xxx.xxx.xxx.xxx] ModSecurity: Access denied with code 403 (phase 2). ... etc
Кроме того, я недавно перешел на PHP 7.2, как рекомендовал хостинг-провайдер. Однако возврат к версии 5.6 не меняет симптомов.
Есть идеи, что вызывает это? Я видел информацию, которая предполагает, возможно, ProxyPass
или ProxyErrorOverride
может решить проблему, но я не знаю, где это настроить.
Для протокола, вот полный htaccess, бородавки и все такое:
RewriteEngine on
# AddType TYPE/SUBTYPE EXTENSION
AddType audio/mpeg mp3
AddType video/mp4 mp4 m4v
# Add WWW
RewriteCond %{HTTP_HOST} ^mydomain\.info [NC]
RewriteRule ^(.*) https://www.mydomain.info/$1 [R=301,L,NE]
# Redirect for .COM
RewriteCond %{HTTP_HOST} mydomain\.com$ [NC]
RewriteRule ^/?(.*) https://www.mydomain.info/$1 [R=301,L,NE]
# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# Home page canonicalization
RewriteCond %{THE_REQUEST} ^.*\/index\.htm\ HTTP/
RewriteRule ^(.*)index\.htm$ /$1 [R=301,L,NE]
# Removed page_missing.htm
Redirect 301 /page_missing.htm /new_page.htm#section_b
# Some content moved to sub-folder
Redirect 301 /extra_content.htm /extra/extra_content.htm
# Internally redirect all HTM & HTML URLs to PHP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.(htm|html)$ /$1\.php
# Error 404 page
ErrorDocument 404 /error404.php
<IfModule mod_expires.c>
# Activate mod_expires for this directory
ExpiresActive on
# Default
ExpiresDefault "access plus 7 days"
# Default for actual documents
ExpiresByType text/html "access plus 15 minutes"
# cache CSS files for 7 days
ExpiresByType text/css "access plus 7 days"
# locally cache common resource types for 7 days
ExpiresByType image/jpg "access plus 7 days"
ExpiresByType image/jpeg "access plus 7 days"
ExpiresByType image/gif "access plus 7 days"
ExpiresByType image/png "access plus 7 days"
ExpiresByType application/pdf "access plus 7 days"
ExpiresByType audio/mpeg "access plus 7 days"
</IfModule>
# Internally redirect all HTM & HTML URLs to PHP RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)\.(htm|html)$ /$1\.php
Я бы не ожидал, что это вызовет проблему, с которой вы столкнулись, однако у вас есть директивы, которые «вслепую» перезаписывают любые несуществующие .htm
(или .html
) запрос к эквивалентному .php
файл, будь то .php
файл существует или нет. (В этом случае документ об ошибке должен улавливать отсутствующие .php
файл, а не пропавший .htm
файл, который был запрошен изначально.)
Это также может объяснить разницу в поведении, которую вы наблюдаете при запросе несуществующего «каталога» (т. Е. Запрос формы /dummy/
), который не будет переписан вышеуказанной директивой и, похоже, «работает», как задумано (т. е. вызывается настраиваемый документ об ошибке).
Вы можете изменить приведенное выше правило, чтобы переписать его только на .php
если файл существует. Например:
# Internally redirect all HTM & HTML URLs to PHP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*)\.(htm|html)$ /$1.php [L]
Нет необходимости избегать буквальной точки в RewriteRule
замена. Вы должны включить L
flag (хотя в настоящее время это последняя директива mod_rewrite, поэтому не имеет особого значения).
ОБНОВИТЬ: Если вы запросите несуществующую страницу php, вы все равно получите ответ «Файл не найден».
Это похоже на проблему конфигурации сервера. Вы можете «обойти» эту проблему, вручную переписав документ об ошибке:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.php$ /error404.php [L]
Хотя вам, вероятно, потребуется изменить error404.php
чтобы учесть это.
ИЛИ ... Мне также было бы любопытно, изменит ли запуск 404 из Apache (который, на первый взгляд, не имеет большого смысла) это поведение. Например, вместо приведенного выше перепишите:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.php$ - [R=404]
Идея этого подхода заключается в том, что он, надеюсь, вызовет внутренний подзапрос для документа об ошибке до того, как запрос будет передан обработчику PHP (который, по-видимому, противоречит документу об ошибке). Затем обработчик PHP вызывается только для обслуживания документа об ошибке.