← Все статьи

SiteGuard11 мин чтения

Браузер скачивает PHP-файл вместо открытия сайта: как исправить обработчик

Если браузер скачивает PHP-файл вместо открытия сайта, сначала установите, что находится в ответе. Это может быть намеренная загрузка документа, неверный заголовок готовой страницы или выдача исходного кода приложения. В последнем случае нужно сразу ограничить публичную выдачу затронутого сайта, затем восстановить обработчик PHP и проверить, какие сведения могли раскрыться.

Причину ищут по пути конкретного запроса: адрес пользователя, CDN или прокси, выбранный виртуальный хост, правило обработки и исполнитель PHP. Установка новой версии PHP сама по себе не связывает эти звенья. Ниже — порядок диагностики для владельца сайта и администратора, с отдельными замечаниями для Nginx, Apache и виртуального хостинга.

1. Отличите исходный PHP от корректной загрузки файла

Имя скачанного файла не доказывает, что интерпретатор не работает. Скрипт download.php может успешно сформировать PDF и вернуть его как вложение. По RFC 6266, значение attachment в заголовке Content-Disposition предлагает сохранить ответ локально. Такой ответ может быть правильным результатом работы приложения.

Разработчик проверяет статус, заголовки и фактическое содержимое ответа на известном проблемном адресе. Если вместо готового HTML видны PHP-инструкции, комментарии и серверная логика, это признак выдачи исходника. Исследуйте полученный материал в контролируемой среде; не загружайте его в публичный онлайн-анализатор и не пересылайте целиком в общий чат.

Что вернулосьНаправление проверки
Ожидаемый документ с заголовком attachmentСценарий скачивания и предлагаемое имя файла
Готовый HTML, который браузер сохраняетContent-Type, Content-Disposition и промежуточные слои
Исходный PHP-кодПубличная выдача файлов и маршрут к обработчику
Страница ошибки шлюзаДоступность выбранного backend и его журнал

HTTP 200, имя файла и наличие либо отсутствие заголовка о версии PHP недостаточны для вывода. Подмена типа ответа на text/html не заставит сервер исполнить уже выдаваемый исходник: она изменит представление ответа, сохранив саму проблему.

2. Ограничьте выдачу исходников до ремонта

При подтверждённой выдаче исходного кода временно закройте публичный доступ к затронутому хосту на том слое, который реально обслуживает посетителей. Используйте предусмотренное инфраструктурой ограничение или статическую страницу обслуживания. Она должна работать независимо от неисправного PHP, иначе защитный экран может оказаться ещё одним неисполняемым скриптом.

Не ограничивайтесь удалением скачанного файла у себя. Не меняйте расширение входного скрипта в надежде скрыть его адрес. Если маршрутизация нарушена для всего сайта, другие PHP-файлы могут остаться доступны по прежним путям. Область ограничения определяют по конфигурации и устройству проекта.

Сохраните время обнаружения, проблемный URL без секретных параметров, версию публикации и сведения о выбранном сервере. Журналы доступа и ошибок пригодятся для расследования; не уничтожайте их вместе с очисткой кеша. Если сайт поддерживает подрядчик, передайте ему эти признаки и необходимость прекратить выдачу исходников.

На хостинге без доступа к конфигурации используйте доступные средства ограничения и официальную поддержку. Сообщение «домен отдаёт исходный PHP вместо результата выполнения» точнее, чем «браузер неправильно открывает сайт»: оно направляет проверку к серверному обработчику.

3. Зафиксируйте путь одного запроса

Возьмите адрес, на котором проблема воспроизводится, и проследите его целиком. Укажите протокол, доменное имя, порт, путь, перенаправления и время проверки. Варианты с www и без него, HTTP и HTTPS могут попадать в разные конфигурации. Успех одного адреса не подтверждает исправность остальных.

Выясните, участвуют ли CDN, обратный прокси, балансировщик и несколько серверов приложения. Один узел может уже выполнять PHP, а другой — продолжать отдавать файлы. Сопоставляйте ответ с журналом того экземпляра, который обработал запрос, используя безопасный идентификатор обращения или предусмотренную служебную диагностику.

Проверка origin выполняется администратором с сохранением правильного доменного контекста, включая Host и SNI для HTTPS, и штатной проверкой TLS. Прямое открытие IP-адреса может выбрать другой виртуальный хост и дать ложное подтверждение исправления. Не отключайте проверку сертификата ради удобного результата.

Сравните свежую выдачу origin и ответ через публичный маршрут. Если сервер уже исправлен, а CDN возвращает старый исходник из кеша, дальнейшая перестановка обработчиков на origin не решит оставшуюся проблему. Для каждой попытки нужно понимать, какой слой сформировал или повторно отдал ответ.

4. Проверьте выбранный виртуальный хост Nginx

В описании обработки запросов Nginx выбор виртуального сервера связан с адресом и портом прослушивания, затем с именем хоста. Если подходящее имя не найдено, запрос может обработать сервер по умолчанию для этого адреса и порта. Поэтому наличие правильного блока где-то в конфигурации ещё не означает, что запрос попал в него.

Сопоставьте listen, server_name и действительный адрес запроса. Затем проверьте корневой каталог публикации. После переноса проекта домен иногда указывает на каталог исходников вместо предусмотренного публичного каталога. Это меняет не только запуск PHP, но и набор файлов, потенциально доступных посетителю.

Проверьте включаемые файлы конфигурации и фактически запущенный экземпляр Nginx. Исправление отключённого шаблона, старого контейнера или другого сервера не влияет на текущую выдачу. Зафиксируйте, какой файл входит в активную конфигурацию и каким процессом он используется.

Не переносите рабочие настройки соседнего сайта целиком. У него могут отличаться корневой каталог, способ выполнения PHP и ограничения доступа. Для рассматриваемого проекта нужно восстановить согласованное соответствие домена, публичного каталога и обработчика, сохранив изоляцию других сайтов.

5. Найдите правило, которое перехватывает PHP как статику

Следующий вопрос — какой location выбран для конкретного URI. В документации location описаны точные совпадения, префиксы и регулярные выражения. В обычной схеме с префиксами и регулярными выражениями учитываются наиболее длинный подходящий префикс и порядок регулярных правил; модификатор ^~ у выбранного префикса исключает последующую проверку регулярных выражений.

Например, отдельный префикс для каталога приложения может обслуживаться как статика и не попадать в общее регулярное правило PHP. В такой ситуации добавление ещё одного похожего PHP-блока в конец файла ничего не гарантирует. Нужно объяснить фактический выбор правила, включая вложенные блоки и внутренние перенаправления.

Проверьте try_files, обработку ошибок и запасные маршруты. Существование файла на диске не означает, что его разрешено отправить посетителю как статический ресурс. Для серверных скриптов должен действовать предусмотренный маршрут исполнения или отказ, а не случайный путь выдачи содержимого.

При исправлении не разрешайте выполнение любого файла в каталогах загрузок. Если приложение принимает пользовательские вложения, эти каталоги должны сохранять свои ограничения. Исправная обработка входного скрипта не требует превращать все доступные файлы в потенциально исполняемые.

Проверяйте адрес без расширения и прямой входной PHP-адрес отдельно, если оба предусмотрены приложением. Первый может проходить через внутреннее перенаправление, а второй — через другой блок. Успешная главная страница не раскрывает весь путь обработки остальных маршрутов.

6. Сверьте передачу запроса в FastCGI

Nginx передаёт PHP-запрос исполнителю через FastCGI. В документации FastCGI-модуля параметр SCRIPT_FILENAME определяет имя скрипта для PHP, а QUERY_STRING передаёт параметры запроса. Для POST важны также метод, тип и длина содержимого. Проверьте полный набор, который реально получает backend.

ЭлементЧто сопоставить
fastcgi_passВыбранный сокет или адрес нужного PHP-FPM
SCRIPT_FILENAMEПуть к разрешённому скрипту в файловой системе исполнителя
Параметры запросаМетод, query string и необходимые сведения о теле
Публичный каталогСоответствие URI, файлов и схемы маршрутизации приложения

Формула пути из чужого примера может оказаться неверной при alias, контейнерах или другой структуре публикации. Установите, какой путь доступен внутри среды PHP-FPM, а не только на хосте Nginx. Не добавляйте второй конфликтующий SCRIPT_FILENAME поверх существующего без разбора включаемых настроек.

Если запрос уже передан FastCGI, но backend сообщает, что скрипт не найден, это другой этап отказа. Он не исправляется изменением MIME-типа. Запишите конкретный ответ и путь, затем корректируйте соответствие файловой системы и разрешённой точки входа.

7. Подтвердите работу нужного пула PHP-FPM

Проверьте, запущен ли нужный PHP-FPM, совпадает ли его адрес прослушивания с настройкой веб-сервера и может ли сервер установить соединение. На машине могут существовать несколько версий PHP и несколько пулов для разных сайтов. Успешный запуск CLI-команды php -v не подтверждает состояние выбранного веб-пула.

В конфигурации PHP-FPM предусмотрены параметры сокета и ограничения подключений. Проверяйте их для своей системы, сохраняя минимально необходимые права. Не открывайте порт FPM всему интернету и не выдавайте всем пользователям доступ к сокету ради устранения ошибки соединения.

Сопоставьте журнал FPM, журнал веб-сервера и время одной попытки. Пустой журнал исполнителя не является окончательным доказательством отсутствия вызова: нужные события могли не записываться. Ищите подтверждённый путь обработки, включая сообщения о соединении и фактический результат безопасной проверки.

Недоступность FPM и статическая выдача PHP — разные неисправности. Если веб-сервер пытается обратиться к исполнителю и получает ошибку, не добавляйте запасной маршрут, который отдаёт тот же скрипт как файл. После ремонта соединения убедитесь, что разрешены только необходимые точки входа и сохранены ограничения исполняемых расширений.

8. Для Apache и панели хостинга проверьте назначенный обработчик

В Apache способ подключения PHP зависит от установленной схемы. Для варианта с PHP-FPM документация mod_proxy_fcgi описывает передачу запросов через proxy/FastCGI и назначение обработчика. Сам этот модуль не запускает процесс приложения: работу FPM организуют отдельно.

Администратор проверяет загруженные модули, назначение обработчика нужным файлам, виртуальный хост и доступность backend. Настройка, рассчитанная на встроенный модуль PHP, может не соответствовать системе с FPM. Не смешивайте инструкции для этих вариантов и не считайте добавление произвольной строки в .htaccess универсальным исправлением.

Если перед Apache стоит Nginx, установите, доходит ли проблемный запрос до Apache вообще. Исправление внутреннего обработчика не поможет файлу, который внешний сервер выдаёт самостоятельно. Оба слоя должны согласованно определять публичные ресурсы и серверные скрипты.

На виртуальном хостинге проверьте выбор обработчика для конкретного домена, а не наличие PHP в списке услуг. После смены параметра подтвердите результат запроса. Поддержке передайте домен, время, ожидаемую точку входа и наблюдение об исходном коде без прикрепления конфигурационных файлов с секретами.

9. Проверьте конфигурацию и выполнение без вывода секретов

Перед применением изменения сохраните прежнюю конфигурацию и убедитесь, что она не будет случайно возвращена следующим развёртыванием. Для Nginx параметр -t, согласно официальному описанию команд, проверяет синтаксис и возможность открыть указанные в конфигурации файлы. Успешная проверка не доказывает правильность маршрутизации или выполнения PHP.

Применяйте настройки штатным механизмом своего окружения и подтвердите, что нужный экземпляр их принял. Затем выполните проверку запроса. В закрытом тестовом контуре можно использовать временный скрипт, который выводит только безвредный маркер, без phpinfo, переменных окружения и конфигурации приложения:

<?php
echo 'PHP_HANDLER_OK';

При корректном выполнении тело ответа равно PHP_HANDLER_OK. Недостаточно найти эту подстроку в ответе: она содержится и в исходнике. Если возвращаются PHP-инструкции, проверка провалена. После диагностики временный файл удаляют предусмотренным способом.

Маркер проверяет только собственный маршрут. Отдельно проверьте штатные входные адреса приложения, перенаправления и необходимые POST-запросы на тестовых данных. Не выкладывайте публичную страницу со всеми настройками сервера ради выяснения одного признака работы обработчика.

10. Разберите пример с отдельным каталогом приложения

Представим учебный сайт: главная страница работает, но после переноса раздела по адресу /portal/index.php браузер сохраняет файл с исходным кодом. В конфигурации есть общее правило PHP, поэтому первая догадка команды — проблема версии интерпретатора. Проверка пути запроса показывает другую причину.

Для /portal/ добавили префиксное правило с ^~, рассчитанное на статическую выдачу. Из-за выбранного правила запрос не попал в обычный PHP-обработчик. Наличие рабочего FPM и корректная главная страница не могли исправить этот маршрут.

ЭтапНаблюдениеВывод
Виртуальный хостВыбран ожидаемый сайтПроверка продолжается на уровне location
Маршрут разделаПрименена статическая конфигурацияНужно исправить назначение обработчика
После измененияРазрешённый входной скрипт выполняетсяПроверяется ответ через публичный маршрут
Другие файлыСерверные материалы недоступны как статикаСохранена граница публичной публикации

Команда сначала ограничивает выдачу раздела, затем корректирует маршрутизацию, проверяет конфигурацию и повторяет контрольный запрос. Дополнительно проверяются вложения и ресурсы раздела: ремонт одного скрипта не должен разрешить исполнение загруженных файлов.

Это модель диагностики, а не готовый конфигурационный шаблон. В реальном проекте результат зависит от вложенных location, корня публикации и правил приложения. Для приёмки нужна объяснённая цепочка обработки конкретного адреса.

11. Разберите раскрытые данные и оставшиеся копии

Восстановление выполнения PHP прекращает неправильную выдачу новых ответов, но не удаляет ранее скачанные копии. Определите доступный период раскрытия по публикациям и журналам, перечень затронутых файлов и содержащиеся в них сведения. Исходный код может раскрывать структуру приложения даже без встроенных паролей.

Если в доступных файлах находились действующие секреты, отзовите и замените соответствующие реквизиты у их провайдеров. В рекомендациях OWASP по управлению секретами отзыв предусмотрен для потенциально скомпрометированных значений. Удаление исходника из публичной выдачи не делает уже раскрытый ключ закрытым.

Проверьте, не осталось ли ошибочных ответов в CDN, reverse proxy и предусмотренных кешах. Очистку выполняйте для установленной области, после исправления origin, и подтверждайте новой сетевой проверкой. Приватный браузер помогает отделить локальное сохранение, но сам по себе не очищает серверный кеш.

Отсутствие подозрительных строк в доступном журнале не доказывает, что никто не получил файл. В отчёте укажите период, просмотренные источники и ограничения сведений. Если код не содержал секретов, не приписывайте инциденту неподтверждённую утечку всех данных сайта; оценивайте реально доступные материалы.

12. Подтвердите восстановление по нескольким признакам

Закрывайте задачу после проверки исполнения, маршрутизации и публичной выдачи. Одного изменения MIME-типа, успешной проверки синтаксиса или отсутствия окна скачивания недостаточно. Пользователь должен получать ожидаемый результат приложения, а серверные исходники должны оставаться вне статической публикации.

  • Проверены нужные домены, протоколы и действующие серверные экземпляры.
  • Каждая разрешённая точка входа передаётся ожидаемому обработчику.
  • Контрольный ответ содержит результат выполнения, а не текст скрипта.
  • Основные GET- и POST-сценарии проходят на безопасных тестовых данных.
  • Конфигурационные файлы, резервные копии и загрузки сохраняют предусмотренные ограничения.
  • Ошибочный исходник не возвращается из промежуточного кеша.
  • Временная диагностика убрана, раскрытые секреты обработаны, причина записана.

Сохраните краткое объяснение: какой адрес выбирал неправильный хост или правило, что изменено и чем подтверждён результат. Добавьте эту проверку в процедуру переноса сайта и смены обработчика. Это полезнее постоянного ручного контроля только главной страницы, которая может работать при неисправном отдельном разделе.

Подключите SiteGuard для внешнего наблюдения за HTTP-доступностью сайта после восстановления. Корректность выполнения PHP подтверждайте контрольными ответами приложения и проверками его маршрутов: одного доступного HTTP-ответа для этого недостаточно.