2009-08-30 16 views
16

Quiero controlar la frecuencia con la que se cargan algunas imágenes externas. Así que mi idea es en lugar de dar un URI directamente como esto:Servir imagen con script PHP frente a carga directa de una imagen

www.site.com/image1.jpg 

puedo crear un script PHP que lee la imagen, así que construyó un archivo PHP y mi HTML se vería así:

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

pero no sé cómo leer la imagen del disco y devolverla. ¿Devolvería una matriz de bytes o establecería el tipo de contenido?

Saludos cordiales, Michel

Respuesta

9

Debe establecer el tipo de contenido:

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

A continuación se carga la imagen y de salida así:

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

imagecreatefromjpeg + imagejpeg puede ser un poco exagerado (y consume CPU) si solo quiere enviar los datos de un archivo; la ventaja que veo es asegurarse de que realmente carga la imagen; pero probablemente haya otras formas de estar seguro (como permitir solo un directorio, que solo contenga imágenes) –

+15

readfile es mejor si solo vas a enviar la imagen como está. – OIS

20

Para lograr algo como esto , su script necesitará:

  • enviar las cabeceras correctas, que dependen del tipo de la imagen: image/gif, image/gif, image/jpeg, ...
  • enviar los datos de la imagen
  • asegurándose nada más es enviado (sin espacios en blanco, sin nada)

esto se hace con la función header, con algo de código como este:

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

O

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

o lo que sea, según el tipo de imagen.


Para enviar los datos de la imagen, puede utilizar la función readfile:

lee un archivo y lo escribe en el buffer de salida .

De esta manera, en una función, ambos leen el archivo y muestran su contenido.


Como comentario:

  • debe poner un poco de seguridad en el lugar, para asegurar que los usuarios no pueden pedir lo que quieran a través de la secuencia de comandos: debe asegurarse de que sólo sirve imágenes, desde el directorio tu esperas ; nada como serveImage.php?file=/etc/passwd debería estar bien, por ejemplo.
  • Si solo desea obtener la cantidad de veces que se cargó un archivo cada día, es una buena idea analizar el archivo de registro de Apache (a través de un lote ejecutado por cron cada día a las 00:05, que analiza el registro de el día anterior, por ejemplo); usted no tendrá estadísticas en tiempo real, sino que se requieren menos recursos en su servidor (sin PHP para servir archivos estáticos)
+1

gracias por la nota al margen: • debe poner algo de seguridad en su lugar, para garantizar que los usuarios no puedan solicitar lo que quieran a través de su script: debe asegurarse de que solo sirva imágenes, desde el directorio que espera; nada como serveImage.php? file =/etc/passwd debería estar bien, por ejemplo. – Michel

3

Usted es probablemente mejor de examinar los registros de acceso al servidor para esto. Ejecutar todas las imágenes a través de php puede poner un poco de carga en su servidor.

+0

hmm, eso seguramente sería el truco. Lo guardaré cuando la carga se convierta en un problema. – Michel

+0

Además, ejecutarlos a través de un script PHP afectará el almacenamiento en caché del lado del cliente, lo que de hecho podría aumentar la carga de lectura. – Rob

+2

@rob: eso no tiene nada que ver con ejecutarlo a través de un script, pero olvidando enviar los encabezados correctos. Tengo los 2 mejores en mi respuesta. – OIS

33

Enviar imágenes a través de una secuencia de comandos es bueno para otras cosas como el cambio de tamaño y el almacenamiento en caché a pedido.

Como contestada por Pascal MARTIN la función readfile y estas cabeceras son los requisitos:

  • Content-Type
    • El tipo mime de este contenido
    • Ejemplo: header('Content-Type: image/gif');
    • Ver el función mime_content_type
    • Tipos
      • image/gif
      • image/jpeg
      • image/png

Pero junto al tipo de contenido evidente que también debe mirar a otras cabeceras como:

  • Content Longitud
    • La longitud del cuerpo de la respuesta en octetos (bytes de 8 bits)
    • Ejemplo: header('Content-Length: 348');
    • Véase la función filesize
    • Le permite a la connectio a ser mejor utilizados.
  • -de la última actualización
    • La última fecha de modificación para el objeto solicitado, en el RFC 2822 formato de
    • Ejemplo: header('Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT');
    • Véase la función filemtime y date formatearlo en el RFC requerida 2822 formato
      • Ejemplo: header('Last-Modified: '.date(DATE_RFC2822, filemtime($filename)));
    • Puede salir de la secuencia de comandos después de enviar un 304 si la hora del archivo modificado es la misma.
  • código de estado
    • Ejemplo: header("HTTP/1.1 304 Not Modified");
    • puede salir ahora y no enviar la imagen una vez más

Por última vez modificado, busque este en $_SERVER

  • If-Modified-Since
    • Permite un 304 No modificado para ser devuelto si el contenido no se ha modificado
    • Ejemplo: If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
    • Está en $_SERVER con la tecla http_if_modified_since

List of HTTP header responses

+0

Aquí hay un buen código que ayuda a implementar todos los encabezados de tesis: [link] (http://css-tricks.com/snippets/php/intelligent-php-cache-control/) –

2

Además, si desea que el usuario vea un nombre de archivo real ins tead de su scriptname cuando el usuario RMC en la imagen y selecciona "Guardar como", que tendrá que establecer también esta cabecera:

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

esto también se puede resolver redirigiendo en apache (host virtual o .htaccess) al archivo de script. entonces /img/somefile_small.jpg obtiene una redirección interna a showimage.php – OIS

11

utilizo la función de "tránsito" para llamar comando "cat", como esto:

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

Funciona en Linux. Ahorra recursos.

6

En lugar de cambiar la URL de la imagen directa en el HTML, puede poner una línea en la configuración de Apache o .htaccess para reescribir todas las solicitudes de imágenes en un directorio a una secuencia de comandos php. Luego, en esa secuencia de comandos puede hacer uso de los encabezados de solicitud y la matriz $_server para procesar la solicitud y servir el archivo.

Primero en su .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] 

El guión serve.php deben estar en el mismo directorio que .htaccess. Es probable que escribir algo como esto: (! Este script se puede mejorar)

<?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

sirvo a mis imágenes con readfile así, pero me ha hecho un gran esfuerzo tanto para la seguridad y la funcionalidad adicional.

Tengo una configuración de base de datos que almacena la identificación de la imagen, sus dimensiones y la extensión de archivo. Esto también significa que las imágenes deben cargarse (permitiendo el cambio de tamaño opcional), así que solo uso el sistema para el contenido y no para las imágenes necesarias para el sitio web (como fondos o sprites).

También hace un muy buen trabajo para asegurarse de que solo puede solicitar imágenes.

lo tanto, para servir al flujo de trabajo simplificado sería como este (no se puede publicar el código de producción aquí):

1) obtener el ID de la imagen solicitada

2) Búscalo en la base de datos

3) encabezados Throw en base a la extensión ("jpg" recibe reasignan a "jpeg" en la carga)

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

5) Opcionalmente, proteger/images/dir para que no pueda ser indexado (no es un problema en mi propio sistema ya que mapea URLs como /image/view/11 a algo así como /index.php?module=image & acción = ver & id = 11)

Cuestiones relacionadas