2009-08-30 3 views
16

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

www.site.com/image1.jpg 

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

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

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

С наилучшими пожеланиями, Michel

ответ

9

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

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

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

$image=imagecreatefromjpeg($_GET['img']); 
imagejpeg($image); 
+2

imagecreatefromjpeg + imagejpeg может быть немного избыточным (anc CPU-consumming), если вы просто хотите отправить данные из файла - преимущество, которое я вижу, это убедиться, что вы действительно загружаете изображение; но, вероятно, есть другие способы убедиться в этом (например, разрешить только один каталог, содержащий только изображения). –

+15

readfile лучше, если вы просто собираетесь отправить изображение как есть. – OIS

20

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

  • послать правильные заголовки, которые зависят от типа изображения: изображение/GIF, изображение/PNG, изображение/JPEG, ...
  • отправить данные изображения
  • убедившись, что ничего остальное послал (без пробелов, нет ничего)

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

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

Или

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

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


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

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

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


В: заметка на полях

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

спасибо за оповещение: • вы должны установить определенную систему безопасности, чтобы пользователи не могли запрашивать что-то, что им нужно, через ваш скрипт: вы должны убедиться, что он служит только для изображений из ожидаемого каталога; например, файл serveImage.php? file =/etc/passwd должен быть в порядке. – Michel

3

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

+0

Хмм, это наверняка сделает трюк. я сохраню это, когда загрузка станет проблемой. – Michel

+0

Кроме того, запуск их через PHP-скрипт повлияет на кэширование на стороне клиента, что фактически может увеличить нагрузку на чтение. – Rob

+2

@rob: это не имеет никакого отношения к запуску через скрипт, но забывает отправить правильные заголовки. У меня есть 2 лучших в моем ответе. – OIS

33

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

Как ответил Паскаль MARTIN функцию readfile и эти заголовки являются требования:

  • Content-Type
    • Тип мим этого содержания
    • Пример: header('Content-Type: image/gif');
    • увидеть функции mime_content_type
    • Виды
      • image/gif
      • image/jpeg
      • image/png

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

  • контент- Длина
    • Длина тела ответа в октетах (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

List of HTTP header responses

+0

Вот хороший код, который поможет реализовать все тезисы заголовков: [link] (http://css-tricks.com/snippets/php/intelligent-php-cache-control/) –

2

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

header('Content-Disposition: filename=$filename'); 
+1

это также можно решить с помощью перенаправления в apache (виртуальный хост или .htaccess) в файл сценария. so /img/somefile_small.jpg получить внутреннее перенаправление на showimage.php – OIS

11

Я использую функцию «PassThru» для вызова команды «кошки», как это:

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

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

6

Вместо того, чтобы изменять 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 
*/ 
?> 

0

Я служу мои изображения с ReadFile, а также, но я пошел лишнюю милю, как для безопасности и дополнительной функциональности.

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

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

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

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

2) Посмотрите на него в базе данных

3) Бросьте заголовки на основе расширения ("JPG" получает переназначен на "JPEG" при загрузке)

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

5) Необязательно, защищать/images/dir, чтобы он не мог быть проиндексирован (не проблема в моей собственной системе, так как он отображает URL-адреса, например, /image/view/11 примерно на /index.php?module=image & action = вид & id = 11)

Смежные вопросы