Melhor maneira de cache do redimensionada imagens usando PHP e MySQL
Pergunta
Qual seria a melhor maneira prática de lidar com o cache de imagens usando PHP.
O nome do arquivo está armazenado em um banco de dados MySQL, que é renomeado para um GUID no upload, juntamente com a tag nome do arquivo e alt originais.
Quando a imagem é colocada em páginas HTML é feito usando um url como '/images/get/200x200/{guid}.jpg que é reescrito para um script php. Isso permite que os meus designers para especificar (aproximadamente - a imagem de origem talvez menor) o tamanho do arquivo.
O script php, em seguida, cria um hash do tamanho (200x200 na url) e o nome do arquivo GUID e se o arquivo foi gerado antes (arquivo com o nome do hash existe no diretório TMP) envia o arquivo da aplicação tmp. Se o nome do arquivo hash não existe, então ele é criado, gravado em disco e serviu-se da mesma maneira,
Este é eficiente quanto poderia ser? (Ele também suporta marca d'água nas imagens e as configurações de marca d'água são armazenadas no hash, bem como, mas isso é fora do escopo para isso.)
Solução
Há dois erros no exemplo de reescrita de Dan Udey (e eu não posso comentar sobre isso), ele deve sim ser:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
Cumprimentos.
Outras dicas
Eu faria isso de uma maneira diferente.
Problemas: 1. Tendo PHP servir os arquivos para fora é menos eficiente do que poderia ser. 2. PHP tem de verificar a existência de arquivos a cada vez que uma imagem é solicitada 3. Apache é muito melhor nisso do que PHP nunca vai ser.
Existem algumas soluções aqui.
Você pode usar mod_rewrite
no Apache. É possível usar o mod_rewrite para teste para ver se existe um arquivo, e se assim, servir a esse arquivo em vez. Isso ignora PHP inteiramente, e torna as coisas muito mais rápido. A forma real de fazer isso, porém, seria a de gerar um esquema URL específica que deve sempre existir, e depois redirecionar para PHP se não.
Por exemplo:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
Portanto, se um cliente solicita /images/cached/<something>
e esse arquivo não existir, o Apache irá redirecionar o pedido para /images/generate.php?/images/cached/<something>
. Este script pode gerar a imagem, escrevê-lo para o cache, e depois enviá-lo para o cliente. No futuro, o script PHP nunca é chamado, exceto para as novas imagens.
Use cache. Como outra com dossel disse, usar coisas como mod_expires
, cabeçalhos Last-Modified, etc. Para responder a solicitações GET condicionais. Se o cliente não tem de imagens re-pedido, carrega a página irá acelerar drasticamente, e carga sobre o servidor irá diminuir.
Para casos em que você tem que enviar uma imagem do PHP, você pode usar mod_xsendfile
fazê-lo com menos sobrecarga. Consulte o excelente blog de Arnold Daniels sobre a questão, mas note que o seu exemplo é para downloads. Para servir imagens em linha, tirar o cabeçalho Content-Disposition (o terceiro header () chamada).
Espero que isso ajude -. Mais depois da minha enxaqueca apura-se
Uma pena nota adicionando é ter certeza de que você está código não gera tamanhos "não autorizadas" dessas imagens.
Então, o seguinte URL criará uma versão 200x200 de imagem 1234 se ainda não existir. Eu tinha altamente sugiro que você se certificar de que o URL solicitado contém dimensões da imagem que você suporta.
/images/get/200x200/1234.jpg
Uma pessoa mal intencionada poderia começar a pedir URLs aleatórias, sempre alterando a altura e largura da imagem. Isso faria com que o servidor alguns problemas sérios b / c ele vai estar sentado lá, essencialmente sob ataque, gerando imagens de tamanhos que não suportam.
/images/get/0x1/1234.jpg
/images/get/0x2/1234.jpg
...
/images/get/0x9999999/1234.jpg
/images/get/1x1/1234.jpg
...
etc
Aqui está um recorte aleatória de código ilustrando esta:
<?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
}
?>
Parece ótimo post, mas o meu problema ainda permanece sem solução. Eu não tenho acesso a htaccess no meu provedor de hospedagem, então não há dúvida de apache ajustes. Existe realmente uma maneira de definir cabeçalho de controle de cace para imagens?
A sua abordagem parece bastante razoável - Gostaria de acrescentar que algum mecanismo deve ser posta em prática para verificar se a data em que a versão em cache foi gerado foi após o último timestamp modificada do arquivo de imagem original (fonte) e se não regenerar o cache / versão redimensionada. Isso irá garantir que, se uma imagem é alterada pelos designers do cache será atualizado de forma adequada.
Isso soa como um caminho sólido para fazê-lo. O próximo passo pode ser a de ir além de PHP / MySQL.
Talvez, ajustar seus cabeçalhos :
Se você estiver usando PHP para enviar tipos MIME, você também pode usar cabeçalhos 'keep-alive' e 'Cache-control' para prolongar a vida de suas imagens no servidor e tirar um pouco da carga fora de PHP / MySQL.
Além disso, considere apache plug-in (s) para armazenamento em cache também. Como mod_expires .
Oh, mais uma coisa, quanto controle você tem sobre o seu servidor? Devemos limitar essa conversa para apenas PHP / MySQL?
Eu consegui fazer isso simplesmente usando um cabeçalho de redirecionamento no 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");
}
Em vez de manter o endereço do arquivo no db Eu prefiro adicionando um número aleatório para o nome do arquivo sempre que o usuário fizer logon em algo assim para o usuário 1234:.? Image / picture_1234.png rnd = 6534122341
Se os submete usuário uma nova imagem durante a sessão eu apenas atualizar o número aleatório.
tackles GUID o problema de cache de 100%. No entanto, espécie de faz com que seja mais difícil de manter o controle dos arquivos de imagem. Com este método há uma chance de que o usuário pode ver a mesma imagem novamente a um login futuro. No entanto as probabilidades são baixas se você gerar o número aleatório de um bilhão de números.
phpThumb é uma estrutura que gera imagens redimensionadas / miniaturas na mosca. Ele também implementa cache e é muito fácil de implementar.
O código para redimensionar uma imagem é:
<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&h=200" alt="thumbnail"/>
lhe dará uma miniatura de 200 x 200;
Ele também suporta marca d'água.
Confira em: http://phpthumb.sourceforge.net/