Как обнаружить поддержку X-Accel-Redirect (Nginx) / X-Sendfile (Apache) в PHP? - PullRequest
12 голосов
/ 26 октября 2010

О приложении

Я работаю над приложением электронной коммерции на PHP.Чтобы обеспечить безопасность URL-адресов, ссылки на загрузку продуктов сохраняются за PHP.Существует файл, скажем download.php, который принимает несколько параметров через GET и проверяет их по базе данных.Если все идет хорошо, он обрабатывает файл с помощью функции readfile () в PHP.

О проблеме

Теперь возникает проблема, когда файл для передачи в readfile () больше, чем ограничение памяти, установленное в php.ini Поскольку это приложение будет использоваться многими пользователями на разделяемом хостинге, мы не можем ретранслировать изменения настроек php.ini.

В наших попытках найти обходные пути я сначала подумал, что мы можем пойти на вызовы fread () вцикл while, но кажется, что это создаст проблемы, а также выделено здесь Надежная загрузка больших файлов в PHP

Поэтому мой лучший вариант - определить / проверить, поддерживает ли сервер X-Accel-Redirect (в случае Nginx) / X-Sendfile (в случае Apache)

Если сервер поддерживает X-Accel-Redirect / X-Sendfile, я могу использовать их, а в блоке else я могузаставить системного администратора знать об ограничении памяти, установленном php.ini

В идеале я хочу использовать поддержку на стороне сервера, такую ​​как X-Accel-Redirect / X-Sendfile, где это возможно, и если это не сработает - я былайк иметь запасной код для чтения файлов без readfile ().

Я пока не уверен, насколько readfile () и fread () в цикле while отличаются, но кажется, что цикл создаст проблему, опять же, как это было предложено в Надежная загрузка больших файлов в PHP

Надеюсь получить помощь, предложения, коды, руководство.

Спасибо за чтение.

Ответы [ 3 ]

12 голосов
/ 28 октября 2010

Чтобы определить, установлен ли модуль apache mod_xsendfile, вы можете попробовать этот код:

if function_exists('apache_get_modules') 
      && in_array('mod_xsendfile', apache_get_modules()) { 
  header("X-Sendfile"); 
}

Но этот код просто проверяет, установлен ли только модуль, что может привести к ошибкам, если он установлен, но настроен неправильно

другой возможный способ сделать это для настройки общесерверной переменной через Apache .htaccess:

<IfModule mod_xsendfile.c>
  <Files *.php>
    XSendFile On
    XSendFileAllowAbove On
    SetEnv MOD_X_SENDFILE_ENABLED 1
  </Files>
</IfModule>

и проверьте его с помощью php-кода:

if ($_SERVER['MOD_X_SENDFILE_ENABLED']) {
  Header(...)
}

Общая идея для nginx та же - просто передать значение переменной состояния бэкэнду через HTTP-заголовок или переменную CGI / FastCGI.

4 голосов
/ 26 октября 2010

readfile не занимает большой объем памяти. Он открывает файл, читает небольшую часть, записывает эту часть в браузер и затем повторно использует память для следующего чтения. Это то же самое, что использовать fread + echo в цикле while. Вы не будете ограничены пределами памяти, но вы будете ограничены max_execution_time и т. Д.

Если вы хотите использовать поддержку X-Accel-Redirect (или аналогичную), предоставляемую вашим веб-сервером, отправьте такой заголовок (для Nginx):

header('X-Accel-Redirect: /path/to/file');

Ваше приложение не может знать, поддерживает ли сервер это. Вам нужно будет указать параметр конфигурации, чтобы администратор / установщик вашего программного обеспечения мог предоставить такую ​​информацию вручную.

0 голосов
/ 04 февраля 2017

Вы можете установить переменную среды на сервере, которая контролирует правильное имя заголовка сервера (возможно, это установит команда ops или кто-то, кто отвечает за создание сценариев / определение среды сервера).Это пригодится любому стеку, поддерживающему обслуживание файлов на основе заголовка, потому что люди, контролирующие этот стек, могут принимать решения, а вы просто читаете из среды заголовок.

<?php

/**
 * Method to delegate sending file to webserver
 *
 * Uses environment variable `SERVER_ACCEL_HEADER` to define the specific
 * server header to use to send files from server layer rather than 
 * application layer
 *
 * @param  string $path path to file that should exist
 * @param  bool $die if script should terminate after setting header
 * @return void returns nothing
 */
function sendPathAccel($path, $die=true) {
    $accelHeader = getenv('SERVER_ACCEL_HEADER');
    header("{$accelHeader}: {$path}");
    if($die) { die(); }
}

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

...