Может ли кто-нибудь посоветовать, какая лучшая функция PHP для отображения изображения, хранящегося в файловой системе – file_get_contents
или readfile
. Мы переключаемся с отображения изображений, хранящихся в базе данных, поэтому нам все равно нужно вызывать изображения через файл PHP и не может напрямую ссылаться на файловую систему. Я видел людей, рекомендующих обе функции, но я склонен к использованию readfile
. Был бы признателен за любой вклад в это.
Если вам не нужно манипулировать изображениями (изменение размера, добавление водяных знаков, …) readfile()
будет лучшим выбором, так как он записывает файл непосредственно в выходной буфер. file_get_contents()
вместо этого будет читать файл в памяти – требуется большая память с большими файлами.
Обязательно учитывайте кэширование при написании таких скриптов!
Веб-сервер, обслуживающий статическое изображение, будет вести переговоры с клиентом, когда изображение будет повторно запрошено при посещении следующей страницы, и если сервер определит, что кешированная копия изображения на стороне клиента все еще действительна, изображение не будет передаются повторно.
Поскольку наивный скрипт не выполняет эти переговоры, изображение будет повторно передано клиенту при каждом запросе страницы, что потребует вам большей пропускной способности, чем это необходимо.
Для этого есть три механизма. Я не могу точно сказать, как написать оптимальный скрипт, поскольку мне никогда не приходилось делать это раньше, и я не уверен, как разные заголовки кеширования взаимодействуют и на какой версии HTTP, но я призываю вас исследовать этот в дальнейшем.
Три механизма, о которых я знаю:
Истекает (HTTP / 1.0)
Самый простой. Этот заголовок сообщает клиенту, что изображение определенно будет действительным до заданного момента времени. Клиент даже не выполнит запрос к скрипту до тех пор, пока это время не пройдет, поэтому установка этого параметра может сэкономить вам (некоторые) циклы процессора на сервере и задержку загрузки изображений в вашем веб-приложении.
Как вы должны это установить, это полностью зависит от вашего приложения; Ваши изображения меняются быстро или редко? Если изображение меняется до истечения времени, которое вы отправили клиенту, клиент не увидит новое изображение.
Пример:
header("Expires: " . gmdate('D, dMY 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» и закройте (тем самым не позволяя перенести изображение).
Пример:
$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
(Примечание: клиенты могут отправлять только сообщение « Идет-Модифицировано», если вы также отправляете Last-Modified в исходном ответе. Я не уверен в этом, исследуйте для себя.)
ETag / If-None-Match (HTTP / 1.1)
Этот метод похож на согласование If-Modified-Since , но вместо него он использует хэш изображения, чтобы увидеть, изменилось ли содержимое. Он работает следующим образом: сервер вычисляет некоторый хэш для изображения и отправляет этот хеш при первом запросе изображения в заголовке ETag .
При последующих запросах сервер отправит хэш обратно в поле запроса If-None-Match . Если хеш клиента совпадает с текущим хешем изображения, изображение не было изменено между ними, и сценарий может быть достаточно, просто отправив «304 Not Modified».
Поскольку ETags, по-видимому, на самом деле предназначены для предотвращения проблем параллелизма в клиентских запросах с побочными эффектами (то есть POST и PUT), и поскольку вычисление хэша является дорогостоящей операцией, я думаю, что подход If-Modified-Since будет лучше подходит для большинства приложений, обслуживающих файлы.
Я бы сделал что-то вроде:
header('Content-type: image/jpeg'); readfile('something.jpg');
readfile () кажется более полезным для этой цели, когда он читает файл и записывает его в выходной буфер, возвращая количество байтов, считанных из файла, или false при ошибке.
Я должен использовать fpassthru. Используя fopen, вы можете более точно обрабатывать ошибки.
PS: убедитесь, что ваш прямой выход из файловой системы не уязвим!
file_get_contents()
является предпочтительным способом чтения содержимого файла в строку. Он будет использовать методы сопоставления памяти, если их поддерживает ваша ОС для повышения производительности. Но в стороне, я не знаю, что лучше. Вы могли бы попытаться понять, дает ли огромный файл лучшую производительность с помощью file_get_contents()
, но я ожидаю, что сетевой трафик будет гораздо более серьезным, чем файл-IO серверов. и readfile()
используется для загрузки файла путем передачи content-type
в header()
.