Вернуть страницу PHP в виде изображения

Я пытаюсь прочитать файл изображения (точнее, .jpeg) и "отобразить" его обратно на вывод страницы, но отображаю изображение...

мой index.php имеет ссылку на изображение, подобную этой:

<img src='test.php?image=1234.jpeg' />

и мой php-скрипт делает в основном это:

1) прочитать 1234.jpeg 2) эхо-содержимое файла... 3) у меня такое чувство, что мне нужно вернуть вывод обратно с мим-типом, но здесь я теряюсь

Как только я это выясню, я полностью удалю ввод имени файла и заменю его идентификатором изображения.

Если я неясен, или вам нужна дополнительная информация, пожалуйста, ответьте.


person MichaelICE    schedule 22.05.2009    source источник
comment
Просто добавьте немного безопасности, чтобы можно было избежать таких атак, как <img src='test.php?image=../config.php' />   -  person mixdev    schedule 29.11.2015


Ответы (6)


В руководстве по PHP есть этот пример:

<?php
// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');

// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

// dump the picture and stop the script
fpassthru($fp);
exit;
?>

Важным моментом является то, что вы должны отправить заголовок Content-Type. Кроме того, вы должны следить за тем, чтобы в вашем файле не было лишних пробелов (например, новых строк) до или после тегов <?php ... ?>.

Как было предложено в комментариях, вы можете избежать опасности появления лишних пробелов в конце вашего скрипта, опустив тег ?>:

<?php
$name = './img/ok.png';
$fp = fopen($name, 'rb');

header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

fpassthru($fp);

Вам по-прежнему нужно тщательно избегать пробелов в верхней части скрипта. Одной из особенно сложных форм пробелов является спецификация UTF-8. Чтобы избежать этого, обязательно сохраните свой сценарий как "ANSI" (Блокнот), или "ASCII", или "UTF-8 без подписи" (Emacs) или подобное.

person Martin Geisler    schedule 22.05.2009
comment
С этой целью некоторые (в том числе Zend, PEAR или оба - я забыл) рекомендуют опускать закрытие ?›. Это совершенно синтаксически допустимо и гарантирует отсутствие проблем с конечными пробелами. - person Frank Farmer; 23.05.2009
comment
Но, но... странно не закрывать то, что открыто :-) - person Martin Geisler; 23.05.2009
comment
Не опускайте ?›. Легче не значит лучше. - person Jared Farrish; 23.05.2009
comment
Полностью согласен с Фрэнком Фармером, код без окончания ?› будет легче отлаживать. Это просто очень полезный совет. И, чтобы ответить Джареду Фарришу, проще здесь значит лучше, это правильно, и это нужно использовать везде, так как ваш код не должен быть забагованным или что-то в этом роде, если вы его не поместите, он будет предупреждать вас, если будут какие-то ошибки. . Это экономит много времени на отладку. - person Boris Guéry; 23.05.2009
comment
согласен, опустим. Технически это более правильно, потому что мы не хотим, чтобы анализ PHP когда-либо заканчивался на рассматриваемом скрипте. - person William Denniss; 30.05.2010
comment
вместо жесткого кодирования заголовка вы можете просто добавить: $size = getimagesize($filename); заголовок (тип контента: {$ size ['mime']}); - person Sauleil; 09.04.2011
comment
Согласен, опускаем закрывающую ?>. @Джаред Фарриш; почему вы думаете, что лучше не делать? - person MikeSchinkel; 15.05.2011
comment
Я просто считаю, что это лучшая практика, закрыть свои теги. У меня нет причудливого ответа, но это две буквы и семантически, я просто думаю, что это более полно. Это только мое мнение. :) - person Jared Farrish; 16.05.2011
comment
Устранение ошибок и потенциальных ошибок на сегодняшний день является лучшей практикой. Этот случай является явным контрпримером для закрытия ваших тегов. Встряхните головой. - person DaveWalley; 03.10.2013
comment
ВНИМАНИЕ: filesize($name) сломает скрипт, если ваше $name является URL-адресом. - person Ulad Kasach; 20.09.2015
comment
Хороший пример из документов, но на странице написано: «Если вы просто хотите сбросить содержимое файла в выходной буфер, не изменяя его предварительно и не ища определенного смещения, вы можете использовать readfile(), что спасет вас». вызов fopen(). поэтому readfile в этом случае лучше и эффективнее. - person Edward; 08.05.2016
comment
Спасибо за предупреждение о пробелах. - person Tim Seed; 08.09.2017

Я чувствую, что мы можем сделать этот код немного проще, просто получив MIME-тип из $image_info:

$file_out = "myDirectory/myImage.gif"; // The image to return

if (file_exists($file_out)) {

   $image_info = getimagesize($file_out);

   //Set the content-type header as appropriate
   header('Content-Type: ' . $image_info['mime']);

   //Set the content-length header
   header('Content-Length: ' . filesize($file_out));

   //Write the image bytes to the client
   readfile($file_out);
}
else { // Image file not found

    header($_SERVER["SERVER_PROTOCOL"] . " 404 Not Found");

}

С помощью этого решения можно обрабатывать изображения любого типа, но это всего лишь еще один вариант. Спасибо ban-geoengineering за ваш вклад.

person ban-geoengineering    schedule 07.11.2014
comment
На странице fpassthru docs говорится, что если вы просто хотите сбросить содержимое файла в выходной буфер, не изменяя его предварительно и не ища определенного смещения, вы можете использовать readfile(), который избавит вас от вызова fopen() . поэтому readfile лучше, чем fpassthru, поскольку в этом случае он более эффективен. - person Edward; 08.05.2016
comment
Код header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); можно использовать, если файл не существует и требуется уведомление об этом в ответе. - person Edward; 08.05.2016
comment
Переменная $fileOut должна содержать имя файла: $fileOut = "your_file_name.png"; - person metatron; 29.11.2017
comment
@ Эдвард и метатрон, спасибо за ваши ответы. Теперь я обновил свой ответ и код соответственно. - person ban-geoengineering; 11.05.2018
comment
Обратите внимание, что для этого требуется, чтобы PHP был скомпилирован с GD (из-за getimagesize()). - person Gwyneth Llewelyn; 01.01.2019
comment
@GwynethLlewelyn Знаете ли вы альтернативу getimagesize(), которая не требует GD? - person ban-geoengineering; 04.05.2020
comment
@ban-geoengineering — нет, не знаю, и кажется, что в сети нет жизнеспособных альтернатив (или, если они есть, Google не может их найти...). Заметьте, это была не «жалоба», а просто замечание — хотя в наши дни я предполагаю, что большинство инсталляций PHP будут иметь встроенный GD, а некоторые — нет, поэтому мое примечание. - person Gwyneth Llewelyn; 01.06.2020

Это должно работать. Это может быть медленнее.

$img = imagecreatefromjpeg($filename);
header("Content-Type: image/jpg");
imagejpeg($img);
imagedestroy($img);
person Drew LeSueur    schedule 30.09.2013
comment
Для этого требуется, чтобы в PHP был скомпилирован GD. - person Gwyneth Llewelyn; 01.01.2019

Я работал без Content-Length . возможно, причина работы с удаленными файлами изображений

// open the file in a binary mode
$name = 'https://www.example.com/image_file.jpg';
$fp = fopen($name, 'rb');

// send the right headers
header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
header('Expires: January 01, 2013'); // Date in the past
header('Pragma: no-cache');
header("Content-Type: image/jpg");
/* header("Content-Length: " . filesize($name)); */

// dump the picture and stop the script
fpassthru($fp);
exit;
person Berk    schedule 02.03.2018

Очень, очень легко.

<?php

//could be image/jpeg or image/gif or whatever
header('Content-Type: image/png')
readfile('image.png')
?>
person Blaze612 YT    schedule 16.05.2021

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

<?php
  Function insertImage( $fileName ) {
    echo '<img src="path/to/your/images/',$fileName,'">';    
  }
?>

<html>
  <body>
    This is my awesome website.<br>
    <?php insertImage( '1234.jpg' ); ?><br>
    Like my nice picture above?
  </body>
</html>
person Joe Bubna    schedule 22.05.2009
comment
Этот ответ будет работать, но не отвечает на вопрос этой страницы, указанный выше. Ответы всегда должны отвечать на исходный вопрос. - person Edward; 08.05.2016
comment
Imho, если вы хотите скрыть местоположение изображения, поместите зашифрованный источник base64 в тег img. Но он спросил не об этом. src="data:image/png;base64,[...]" - person 3ED; 16.02.2019