Подавать изображение с помощью PHP-скрипта против прямой загрузки изображения - PullRequest
17 голосов
/ 30 августа 2009

Я хочу отслеживать, как часто загружаются внешние изображения. Так что моя идея состоит в том, чтобы вместо того, чтобы давать URI прямо так:

www.site.com/image1.jpg

Я могу создать скрипт PHP, который читает изображение, поэтому я построил файл PHP, и мой HTML выглядел бы так:

<img src="www.site.com/serveImage.php?img=image1.jpg">

но я не знаю, как прочитать образ с диска и вернуть его. Я бы вернул байтовый массив или установил тип контента?

С уважением, Michel

Ответы [ 8 ]

34 голосов
/ 30 августа 2009

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

Как ответил Паскаль МАРТИН, функция readfile и эти заголовки являются требованиями:

  • Content-Type
    • MIME-тип этого контента
    • Пример: header('Content-Type: image/gif');
    • См. Функцию mime_content_type
    • Типы
      • image/gif
      • image/jpeg
      • image/png

Но помимо очевидного типа контента вы также должны обратить внимание на другие заголовки, такие как:

  • Content-Length
    • Длина тела ответа в октетах (8-битных байтов)
    • Пример: header('Content-Length: 348');
    • См. Функцию filesize
    • Позволяет лучше использовать соединение.
  • Last-Modified
    • Дата последнего изменения запрошенного объекта в формате RFC 2822
    • Пример: header('Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT');
    • См. Функции filemtime и date для форматирования в требуемый формат RFC 2822
      • Пример: header('Last-Modified: '.date(DATE_RFC2822, filemtime($filename)));
    • Вы можете выйти из сценария после отправки 304, если время изменения файла совпадает.
  • код статуса
    • Пример: header("HTTP/1.1 304 Not Modified");
    • Вы можете выйти сейчас и не отправлять изображение еще раз

Для последнего измененного времени ищите это в $_SERVER

  • If-Modified-Since
    • Позволяет возвращать 304 Not Modified, если содержимое не изменяется
    • Пример: If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
    • Находится в $_SERVER с ключом http_if_modified_since

Список ответов HTTP-заголовков

20 голосов
/ 30 августа 2009

Чтобы достичь чего-то подобного, вашему сценарию потребуется:

  • отправьте нужные заголовки, которые зависят от типа изображения: image / gif, image / png, image / jpeg, ...
  • отправить данные изображения
  • убедившись, что ничего еще отправлено (без пробелов, нет ничего)

Это делается с помощью функции header, с некоторым кодом, подобным этому:

header("Content-type: image/gif");

Или

header("Content-type: image/jpeg");

или что-то еще, в зависимости от типа изображения.


Для отправки данных изображения вы можете использовать функцию readfile:

Читает файл и записывает его в выходной буфер.

Таким образом, в одной функции вы одновременно читаете файл и выводите его содержимое.


В качестве обозначения:

  • Вы должны обеспечить некоторую безопасность, чтобы пользователи не могли запрашивать все, что им нужно, через ваш скрипт: вы должны убедиться, что он обслуживает только изображения из ожидаемой директории; например, serveImage.php?file=/etc/passwd не должно быть в порядке.
  • Если вы просто хотите узнать, сколько раз файл загружался каждый день, неплохо было бы проанализировать файл журнала Apache (через пакет, запускаемый cron каждый день в 00:05, который анализирует журнал например, накануне); у вас не будет статистики в реальном времени, но для этого потребуется меньше ресурсов на вашем сервере (без PHP для обслуживания статических файлов)
12 голосов
/ 28 апреля 2011

Я использую функцию "passthru" для вызова команды "cat", например:

header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');

Работает в Linux. Экономит ресурсы.

9 голосов
/ 30 августа 2009

Вы должны установить тип контента:

header("Content-type: image/jpeg");

Затем вы загружаете изображение и выводите его так:

$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
6 голосов
/ 26 февраля 2012

Вместо изменения прямого URL-адреса изображения в HTML вы можете поместить строку в конфигурации Apache или .htaccess, чтобы переписать все запросы изображений в каталоге в скрипт php.Затем в этом сценарии вы можете использовать заголовки запроса и массив $_server для обработки запроса и обслуживания файла.

Сначала в вашем .htaccess:

RewriteRule ^(.*)\.jpg$ serve.php [NC]
RewriteRule ^(.*)\.jpeg$ serve.php [NC]
RewriteRule ^(.*)\.png$ serve.php [NC]
RewriteRule ^(.*)\.gif$ serve.php [NC]
RewriteRule ^(.*)\.bmp$ serve.php [NC]

Сценарийserve.php должен находиться в том же каталоге, что и .htaccess.Вы, вероятно, напишите что-то вроде этого:

<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>

(Этот скрипт можно улучшить!)

3 голосов
/ 30 августа 2009

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

2 голосов
/ 11 июня 2010

Кроме того, если вы хотите, чтобы пользователь видел реальное имя файла вместо вашего имени сценария, когда пользователь RMC на изображении и выбирает «Сохранить как», вам также необходимо установить этот заголовок:

header('Content-Disposition: filename=$filename');
0 голосов
/ 07 октября 2016

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

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

Он также очень хорошо справляется с тем, что вы можете запрашивать только изображения.

Таким образом, для обслуживания упрощенный рабочий процесс будет выглядеть следующим образом (здесь невозможно опубликовать производственный код):

1) получить идентификатор запрошенного изображения

2) Поиск в базе данных

3) Бросать заголовки, основанные на расширении («jpg» будет преобразован в «jpeg» при загрузке)

4) readfile("/images/$id.$extension");

5) При желании защитите / images / dir, чтобы его нельзя было проиндексировать (в моей собственной системе это не проблема, поскольку он сопоставляет URL-адреса, такие как / image / view / 11 , с чем-то вроде / index .php? модуль = изображения и действие = вид & ID = 11 * 1 021 *) * * тысяча двадцать-дв

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...