Когда запрашивается файл с сервера Apache, я хочу, чтобы он создавался, сохранялся на диске, а затем этот созданный файл обслуживался так, как будто он уже был файлом на сервере. Клиенты не будут веб-браузерами и могут быть очень простыми; файлы могут быть довольно большими.
Я пытался добиться этого с помощью PHP и правил перенаправления, а также с помощью mod_xsendfile. Но X-SENDFILE не добавляет все заголовки ответа к файлу, как это сделала бы прямая ссылка. Особенно согласно документации (https://tn123.org/mod_xsendfile/) заголовок “Content-Encoding” отбрасывается, поэтому файлы не могут быть отправлены с кодировкой gzip (если клиент это поддерживает), что важно, так как это значительно уменьшает размер файла. Но я также не могу создавать и обслуживать .gz файлы, так как клиенты ожидают файлы в определённом формате.
Я не хочу устанавливать перенаправления или заголовок обновления и тому подобное, так как клиенты могут это не поддерживать. Я хотел бы иметь решение, которое будет работать точно так, как если бы файл просто скачивался с диска.
Ответ
Для решения вашей задачи, состоящей в создании файла на диске при запросе к Apache, а затем его предоставлении в качестве ответа на этот запрос, мы можем использовать PHP и несколько настроек конфигурации Apache.
Общая схема решения:
- Создание файла на диске при первом запросе.
- Отправка созданного файла клиенту с правильными заголовками ответа.
Шаги по реализации:
- Настройка Apache:
Убедитесь, что в конфигурации Apache включены модули mod_rewrite
и mod_headers
. Это можно сделать, добавив в конфигурационный файл Apache (например, httpd.conf
или .htaccess
):
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
- PHP скрипт для создания и сервировки файла:
Создайте файл serve_file.php
, который будет обрабатывать запросы, создавать файл (если он не существует) и отправлять его клиенту.
<?php
// Задайте путь к файлу и имя файла
$filename = 'path/to/your/file.txt';
// Если файл не существует, создайте его
if (!file_exists($filename)) {
// Логика для создания файла
// Например, записываем содержимое "Hello, world!" в созданный файл
file_put_contents($filename, 'Hello, world!');
}
// Убедитесь, что файл существует
if (file_exists($filename)) {
// Получаем информацию о файле
$filesize = filesize($filename);
// Устанавливаем соответствующие заголовки
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $filesize);
// Очищаем буфер
ob_clean();
flush();
// Читаем и выводим файл
readfile($filename);
exit;
} else {
// Обработка ошибки, если файл не найден (не должно происходить)
http_response_code(404);
echo "Файл не найден.";
}
?>
- Настройка правила переписывания (Rewrite Rule):
Если вы используете .htaccess
, добавьте в него следующее правило:
RewriteEngine On
# Если клиент запрашивает файл, направьте запрос на скрипт PHP
RewriteRule ^file\.txt$ serve_file.php [L]
- Тестирование:
Теперь, когда вы запрашиваете http://example.com/file.txt
, Apache будет направлять запрос на serve_file.php
, которое создаст файл (если он еще не существует) и отправит его клиенту с правильными заголовками.
Заключение:
Таким образом, данный подход позволяет создать файл на диске по запросу, а затем скорректировать заголовки ответа для правильного предоставления файла клиенту. Рекомендуется протестировать ваше решение, чтобы убедиться, что все работает должным образом с клиентами, которые не поддерживают браузеры.