file_get_contents или readfile для отображения образа файловой системы - PullRequest
12 голосов
/ 26 мая 2009

Может кто-нибудь посоветовать, какая функция PHP лучше всего подходит для отображения изображения, хранящегося в файловой системе - file_get_contents или readfile. Мы переключаемся с отображения изображений, хранящихся в базе данных, поэтому нам по-прежнему необходимо вызывать изображения через файл PHP, и мы не можем напрямую связываться с файловой системой. Я видел людей, которые рекомендуют обе функции, но я склонен использовать readfile. Буду признателен за любую информацию по этому вопросу.

Ответы [ 5 ]

26 голосов
/ 26 мая 2009

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

9 голосов
/ 27 мая 2009

Обязательно учитывайте кэширование при написании таких скриптов!

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

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

Для этого есть три механизма. Я не могу сказать вам точно, как написать оптимальный сценарий, поскольку мне никогда не приходилось делать это раньше, и я не уверен, как взаимодействуют различные заголовки кэширования и на какой версии HTTP, но я призываю вас изучить эту проблему. в дальнейшем.

Три механизма, которые я знаю:

Истекает (HTTP / 1.0)

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

То, как вы должны установить это, полностью зависит от вашего приложения; Ваши изображения меняются быстро или редко? Если изображение изменяется до истечения времени, которое вы отправили клиенту, клиент не увидит новое изображение.

Пример:

header("Expires: " . gmdate('D, d-M-Y H:i:s \G\M\T', time() + 60)); // Valid for a minute

(Примечание: срок действия, похоже, был заменен Cache-Control в HTTP / 1.1)

If-Modified-Since (HTTP / 1.1)

Клиент HTTP / 1.1 может отправить этот заголовок, если у него уже есть копия изображения, и отмечает, с какого времени копия копируется. Затем вы можете определить в своей базе данных, была ли текущая версия изображения изменена ранее или позже. Если версия клиента по-прежнему правильная, просто отправьте ответ «304 Not Modified» и выйдите из системы (тем самым, исключив необходимость переноса изображения).

Пример: * 1 034 *

$cache_time   = parse_browsers_date_time_format($_SERVER["IF-MODIFIED-SINCE"]);
$actual_time  = get_current_resource_time_from_db();

if ($actual_time <= $cache_time) {
    header("HTTP/1.1 304 Not Modified");
    die;
}

// ... Produce and output resource here

(Примечание: клиенты могут фактически отправлять If-Modified-Since , если вы также отправляете Last-Modified в исходном ответе. Я не уверен в этом, исследование для себя.)

ETag / If-None-Match (HTTP / 1.1)

Этот метод аналогичен согласованию If-Modified-Since , но вместо этого он использует хэш изображения, чтобы увидеть, изменился ли контент. Он работает следующим образом: сервер вычисляет некоторый хэш для изображения и отправляет этот хэш при первом запросе изображения в заголовке ETag .

При последующих запросах сервер отправит хэш обратно в поле запроса If-None-Match . Если хэш клиента совпадает с текущим хешем изображения, изображение между ними не изменилось, и сценария может быть достаточно, просто отправив «304 Not Modified».

Поскольку ETag, похоже, фактически предназначен для предотвращения проблем параллелизма в клиентских запросах с побочными эффектами (т. Е. POST и PUT), а также потому, что вычисление хэша является дорогостоящей операцией, я думаю, что подход If-Modified-Since будет лучше подходить для большинства файловых приложений.

4 голосов
/ 26 мая 2009

Я бы сделал что-то вроде:

header('Content-type: image/jpeg');
readfile('something.jpg');

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

0 голосов
/ 22 января 2014

file_get_contents() является предпочтительным способом чтения содержимого файла в строку. Он будет использовать методы отображения памяти, если они поддерживаются вашей ОС, для повышения производительности. Но кроме этого, я не знаю, что лучше. Вы могли бы попытаться определить, дают ли большие файлы более высокую производительность при file_get_contents(), но я ожидаю, что сетевой трафик гораздо более важен, чем файловый ввод-вывод серверов. и readfile() используется для загрузки файла, передавая content-type в header().

0 голосов
/ 26 мая 2009

Я должен использовать fpassthru Используя fopen, вы можете обрабатывать ошибки более точно.

PS: убедитесь, что ваш прямой вывод из файловой системы не уязвим!

...