2009-09-06 99 views
20

我对如何缓存图像完全陌生。如何让浏览器缓存图片,用PHP?

我用php输出图库中的所有图像,并希望已经显示的图像被浏览器缓存,所以php-script不必再输出相同的图像。我想要的是图像显示更快。

调用一个图像,当我这样做:

<img src="showImage.php?id=601"> 

showImage.php -file做:

$resultat = mysql_query(" 
    SELECT filename, id 
    FROM Media 
    WHERE id = '".$_GET['id']."' 
"); 
$data = mysql_fetch_assoc($resultat); 

... 

//Only if the user are logged in 
if(isset($_SESSION['user'])){ 
    header("Content-Type: image/jpeg"); 

    //$data['filename'] can be = dsSGKLMsgKkD3325J.jpg 
    echo(file_get_contents("images/".$data['filename']."")); 
} 
+0

我不知道你想什么来完成,从原来的问题,听起来就好像你生成的飞行图像和希望在第一次加载时缓存生成的图像,并在后续加载时从磁盘提供服务。你在谈论浏览器缓存吗? – 2009-09-06 15:50:06

+1

为什么你使用PHP脚本呢? – Gumbo 2009-09-06 15:50:42

+0

是的,我希望浏览器缓存图像。 – Johan 2009-09-06 15:51:20

回答

4

如果您在输出消息之前使用php来检查用户是否已登录,那么您不希望浏览器缓存图像。

缓存的全部重点是调用服务器一次,然后再不再调用它。如果浏览器缓存图像,它将不会调用服务器,脚本也不会运行。相反,即使用户不再登录,浏览器也会将您的映像从缓存中取出并显示出来。这可能是一个非常大的安全漏洞。

+0

嗯,这是一个很好的观点。但是,将图像存储一个小时就可以了。 – Johan 2009-09-06 16:43:52

+1

即使一个小时也不安全,所有这一切都是希望黑客在某个时间不会尝试破解。但是,从我在http://www.mnot.net/cache_docs/#SCRIPT中看到的内容看起来,您可以在HTTP标头中使用“Cache-control:public,no-cache;”强制进行身份验证('no-cache'实际上并不意味着没有缓存;名字有点不对)。 – Imagist 2009-09-06 16:59:48

+3

您仍然可以缓存*和*让浏览器调用服务器。它被称为缓存验证。你可以通过发送'Cache-control:private,must-revalidate'(private,因为它不应该在用户之间共享)和'Last-Modified'或者'ETag'头文件来做到这一点。然后当浏览器发送'If-Modified-Since'或'If-None-Match'时,如果由于图像已经生成而没有任何变化,则以状态“304”响应。 – Kornel 2013-02-15 10:36:00

48

首先,如果你使用的会话,必须禁用session_cache_limiter(通过将其设置为nonepublic)。它发送的头对缓存来说是相当糟糕的。

session_cache_limiter('none'); 

然后发送Cache-Control: max-age=number_of_seconds和任选的等效Expires:报头。

header('Cache-control: max-age='.(60*60*24*365)); 
header('Expires: '.gmdate(DATE_RFC1123,time()+60*60*24*365)); 

为了获得最佳的高速缓存能力,发送Last-Modified头以及如果所述浏览器发送一个匹配If-Modified-Since头用状态304和空体回复。

header('Last-Modified: '.gmdate(DATE_RFC1123,filemtime($path_to_image))); 

为了简便起见,我在这里作弊位(该示例不验证日期),但你不介意的浏览器保持缓存的文件永远是只要有效:

if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 
    header('HTTP/1.1 304 Not Modified'); 
    die(); 
} 
+0

是的,我正在使用'sessions'。嗯,看起来你说的是我所需要的,但我不明白如何将它们合并到工作代码中。如果我希望浏览器将图像缓存一年,该如何编写? – Johan 2009-09-06 16:01:12

+0

非常感谢,它对我来说非常适合这么棒!谢谢thnaks! :) – ParisNakitaKejser 2014-05-12 06:55:20

+0

'If-Modified-Since''位是“d'oh”或“eureka!”时刻,无论你喜欢什么! – Agamemnus 2015-01-17 09:06:07

3

您可以存储生成的图像在一个名为“showImage”目录中,这样,你会嵌入他们这样

<img src="showimage/601.jpg" /> 

然后你把.htaccess文件中,将调用showImage.php非常相同的目录? ID =的情况下,该文件不存在,如:

<IfModule mod_rewrite.c> 
    RewriteEngine On 
    RewriteCond %{REQUEST_FILENAME} !-f 
    RewriteRule ^(.*)\.jpg$ showImage.php?id=$1 [QSA,L] 
</IfModule> 

在您的评论刚看完,你想要做的客户端缓存:只要根据http://www.mnot.net/cache_docs/

设置缓存相关的HTTP头

请注意,您的查询很容易受到SQL注入,因为你不消毒/逃避$ _GET [ '身份证']:http://php.net/mysql_real_escape_string

0

请不要地址图片是一些id'ed资源。为图片使用绝对网址,最好在子网域中使用,最好使用Cookie。浏览器将对图像执行缓存。在网站上更快加载图像的巧妙方法是将其放置在某个CDN或其他网站上。这是因为浏览器将并行请求线程的数量限制为一个域。

另一种处理图像的方法很简单,就是查看图像。它节省了大量的带宽和请求。

如果速度如此重要,您也可以使用直接位图加载。尽管这并不建议用于大图像。如果它的图标和小图片/你正在加载的gif。您可以直接在页面上使用位图。

7

下面是一些代码,我使用304头支持:

/** 
    * @return false if not cached or modified, true otherwise. 
    * @param bool check_request set this to true if you want to check the client's request headers and "return" 304 if it makes sense. will only output the cache response headers otherwise. 
    **/  
    protected function sendHTTPCacheHeaders($cache_file_name, $check_request = false) 
    { 
    $mtime = @filemtime($cache_file_name); 

    if($mtime > 0) 
    { 
     $gmt_mtime = gmdate('D, d M Y H:i:s', $mtime) . ' GMT'; 
     $etag = sprintf('%08x-%08x', crc32($cache_file_name), $mtime); 

     header('ETag: "' . $etag . '"'); 
     header('Last-Modified: ' . $gmt_mtime); 
     header('Cache-Control: private'); 
     // we don't send an "Expires:" header to make clients/browsers use if-modified-since and/or if-none-match 

     if($check_request) 
     { 
     if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && !empty($_SERVER['HTTP_IF_NONE_MATCH'])) 
     { 
      $tmp = explode(';', $_SERVER['HTTP_IF_NONE_MATCH']); // IE fix! 
      if(!empty($tmp[0]) && strtotime($tmp[0]) == strtotime($gmt_mtime)) 
      { 
      header('HTTP/1.1 304 Not Modified'); 
      return false; 
      } 
     } 

     if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) 
     { 
      if(str_replace(array('\"', '"'), '', $_SERVER['HTTP_IF_NONE_MATCH']) == $etag) 
      { 
      header('HTTP/1.1 304 Not Modified'); 
      return false; 
      } 
     } 
     } 
    } 

    return true; 
    }