2008-09-26 10 views
14

¿Cuál sería la mejor manera de manejar el almacenamiento en caché de imágenes usando PHP?La mejor manera de almacenar en caché las imágenes redimensionadas usando PHP y MySQL

El nombre de archivo se almacena actualmente en una base de datos MySQL que se renombra a un GUID al cargarse, junto con el nombre de archivo original y la etiqueta alt.

Cuando la imagen se coloca en las páginas HTML, se hace utilizando una URL como '/images/get/200x200/{guid}.jpg que se reescribe a un script php. Esto permite a mis diseñadores especificar (aproximadamente - la imagen de origen puede ser más pequeña) el tamaño del archivo.

El script php crea un hash del tamaño (200x200 en la url) y el nombre del archivo GUID y si el archivo se ha generado antes (el archivo con el nombre existe en el directorio TMP) envía el archivo desde aplicación de directorio TMP. Si el nombre de archivo hash no existe, entonces se crea, se escribe en el disco y se sirve de la misma manera,

¿Es esto eficiente como podría ser? (También admite la marca de agua de las imágenes y las configuraciones de marca de agua también se almacenan en el hash, pero eso está fuera del alcance de esto.)

Respuesta

10

Hay dos errores tipográficos en ejemplo de reescritura de Dan Udey (y no puedo opinar sobre ellos), que más bien debería haber :

RewriteCond %{REQUEST_URI} ^/images/cached/ 
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f 
RewriteRule (.*) /images/generate.php?$1 [L] 

Saludos.

+2

Gracias, he actualizado el código en el mío por si acaso lo usan en lugar de su versión fija. –

0

Su enfoque parece bastante razonable: agregaría que se debe implementar algún mecanismo para compruebe que la fecha en que se generó la versión en caché fue después de la última marca de tiempo modificada del archivo de imagen original (fuente) y, si no se vuelve a generar, la versión almacenada en caché/redimensionada. Esto asegurará que si los diseñadores modifican una imagen, la memoria caché se actualizará adecuadamente.

+0

Buen consejo, pero ... Si la fuente se cambia por una nueva imagen que se carga (a través de la interfaz de administración), se genera un nuevo GUID y el nombre del archivo en caché ya no coincidirá. Las imágenes no se deben cargar con (s) FTP, pero todos sabemos acerca de las suposiciones. ;) Se verá la implementación de todos modos. –

+0

También compruebo si la imagen fue almacenada en caché _después_ de cualquier modificación realizada en el script de almacenamiento en caché, es decir 'if (filemtime ($ cached_image)> filemtime ($ _ SERVER ['SCRIPT_FILENAME'])) {...}' –

0

Eso suena como una forma sólida de hacerlo. El siguiente paso puede ser ir más allá de PHP/MySQL.

Tal vez, ajustar sus cabeceras:

Si está usando PHP para enviar los tipos MIME, también puede utilizar 'keep-alive' y 'Cache-Control' cabeceras de extender la vida de sus imágenes en el servidor y quita parte de la carga de PHP/MySQL.

Además, considere los plugins de apache para el almacenamiento en caché también. Me gusta mod_expires.

Oh, una cosa más, ¿cuánto control tiene sobre su servidor? ¿Deberíamos limitar esta conversación a solo PHP/MySQL?

+0

La aplicación está alojada en un VPS, entonces tengo acceso de root. mod_expires está instalado, por lo que parece un simple .htaccess tweak podría reducir un poco la carga del servidor. Buen consejo, gracias. –

0

phpThumb es un marco que genera imágenes/miniaturas redimensionadas sobre la marcha. También implementa el almacenamiento en caché y es muy fácil de implementar.

El código para cambiar el tamaño de una imagen es:

<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&amp;h=200" alt="thumbnail"/> 

le dará una miniatura de 200 x 200;

También es compatible con marcas de agua.

echarle un vistazo en: http://phpthumb.sourceforge.net/

5

Una nota vale la pena añadir es asegurarse de que estás código no genera tamaños "no autorizadas" de estas imágenes.

De modo que la siguiente URL creará una versión 200x200 de la imagen 1234 si aún no existe.Me gustaría altamente sugiero que se asegure de que la URL solicitada contiene las dimensiones de la imagen que admite.

/images/get/200x200/1234.jpg 

Una persona con malas intenciones podría comenzar a solicitar direcciones URL al azar, siempre alterando el ancho altura & de la imagen. Esto causaría a su servidor algunos problemas serios b/c estará allí, esencialmente bajo ataque, generando imágenes de tamaños que no admite.

/images/get/0x1/1234.jpg 
/images/get/0x2/1234.jpg 
... 
/images/get/0x9999999/1234.jpg 
/images/get/1x1/1234.jpg 
... 
etc 

Aquí está un recorte aleatoria de código que ilustra esto:

<?php 

    $pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']); 

    if(file_exists($pathOnDisk)) { 
     // send header with image mime type 
     echo file_get_contents($pathOnDisk); 
     exit; 
    } else { 
     $matches = array(); 
     $ok = preg_match(
      '/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/', 
      $_SERVER['REQUEST_URI'], $matches); 

     if(! $ok) { 
      // invalid url 
      handleInvalidRequest(); 
     } else { 
      list(, $width, $height, $guid) = $matches; 

      // you should do this! 
      if(isSupportedSize($width, $height)) { 
       // size is supported. all good 
       // generate the resized image, save it & output it 
      } else { 
       // invalid size requested!!! 
       handleInvalidRequest(); 
      } 
     } 
    } 

    // snip 
    function handleInvalidRequest() { 
     // do something w/ invalid request   
     // show a default graphic, log it etc 
    } 
?> 
+0

Usar die() es un código horrible. Básicamente rescatas, tirando una sola línea de texto al cliente, sin hacer ninguna corrección de error. Si este ejemplo se usa en producción, reemplace las llamadas a morir() por imágenes de reemplazo o errores útiles. –

+0

estoy de acuerdo con usted. es solo un código de muestra para obtener el mensaje – phatduckk

+0

Esto ya está implementado en mi código (tamaños de imagen máximos y mínimos con una imagen de marcador de posición si algo sale mal). ¡Votificado porque pensar en la seguridad de PHP siempre es bueno! –

30

lo haría de manera diferente.

Problemas: 1. Tener PHP para servir los archivos es menos eficiente de lo que podría ser. 2. PHP tiene que verificar la existencia de archivos cada vez que se solicita una imagen 3. Apache es mucho mejor en esto que PHP.

Aquí hay algunas soluciones.

Puede usar mod_rewrite en Apache. Es posible usar mod_rewrite para probar para ver si existe un archivo, y si es así, servir ese archivo en su lugar. Esto evita el PHP por completo y hace que las cosas sean mucho más rápidas. La forma real de hacer esto, sin embargo, sería generar un esquema de URL específico que siempre debería existir, y luego redireccionar a PHP si no es así.

Por ejemplo:

RewriteCond %{REQUEST_URI} ^/images/cached/ 
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f 
RewriteRule (.*) /images/generate.php?$1 [L] 

lo tanto, si un cliente solicita /images/cached/<something> y que el archivo no existe ya, Apache redirigir la solicitud a /images/generate.php?/images/cached/<something>. Este script puede generar la imagen, escribirla en el caché y luego enviarla al cliente. En el futuro, el script PHP nunca se llama, excepto para las nuevas imágenes.

Utilice el almacenamiento en caché. Como dijo otro cartel, use cosas como mod_expires, encabezados Last-Modified, etc. para responder a las solicitudes GET condicionales. Si el cliente no tiene que volver a solicitar imágenes, la carga de la página se acelerará drásticamente y la carga en el servidor disminuirá.

Para los casos en que debe enviar una imagen de PHP, puede usar mod_xsendfile para hacerlo con menos sobrecarga. Consulte the excellent blog post from Arnold Daniels sobre el problema, pero tenga en cuenta que su ejemplo es para descargas. Para mostrar imágenes en línea, saque el encabezado Content-Disposition (la tercera llamada a header()).

Espero que esto ayude, más después de que desaparezca mi migraña.

+0

Excelente método gracias. Combinado con las rutas CakePHP, una solución muy elegante. –

+1

Excelente método y exactamente lo que necesito en este momento. Ojalá pudiera votar esto dos veces. –

+0

Dude - NICE !!! +1 por el momento de Heureka –

1

Parece una gran publicación, pero mi problema sigue sin resolverse. No tengo acceso a htaccess en mi proveedor de host, por lo que no hay dudas sobre el ajuste de apache. ¿Hay realmente una manera de establecer el encabezado de control de cace para las imágenes?

0

He conseguido hacer esto simplemente utilizando una cabecera de redirección en PHP:

if (!file_exists($filename)) { 

    // *** Insert code that generates image *** 

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

    // Output 
    readfile($filename);  

} else { 
    // Redirect 
    $host = $_SERVER['HTTP_HOST']; 
    $uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\'); 
    $extra = $filename; 
    header("Location: http://$host$uri/$extra"); 
} 
0

En lugar de mantener la dirección del archivo en el PP Yo prefiero la adición de un número aleatorio al nombre de archivo cada vez que el usuario inicia sesión en algo como esto para el usuario 1234:.? Imagen/picture_1234.png rnd = 6534122341

Si el usuario envía una nueva imagen durante la sesión. Solo actualizo el número aleatorio.

GUID aborda el problema de caché 100%. Sin embargo, hace que sea más difícil hacer un seguimiento de los archivos de imagen. Con este método, existe la posibilidad de que el usuario vuelva a ver la misma imagen en un inicio de sesión futuro. Sin embargo, las probabilidades son bajas si genera su número aleatorio de mil millones de números.

Cuestiones relacionadas