如何使用 PHP 让浏览器缓存图像?

Posted

技术标签:

【中文标题】如何使用 PHP 让浏览器缓存图像?【英文标题】:How to get the browser to cache images, with PHP? 【发布时间】:2010-11-26 00:53:44 【问题描述】:

我完全不知道如何缓存图像。

我用 php 输出画廊中的所有图像,并希望已经显示的图像被浏览器缓存,因此 PHP 脚本不必再次输出相同的图像。我想要的只是图像显示得更快。

当调用图像时,我会这样做:

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

showImage.php-file 可以:

$id = (int) $_GET['id'];
$resultat = mysql_query("
    SELECT filename, id
    FROM Media 
    WHERE id = $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']."")); 

【问题讨论】:

我不确定您要完成什么,从您最初的问题来看,这听起来好像您正在动态生成图像并希望在第一次加载时缓存生成的图像并从磁盘上提供服务后续负载。您是在谈论浏览器缓存吗? 你为什么还要使用 PHP 脚本? 是的,我希望浏览器缓存图片。 为了安全起见,我使用php,脚本在输出图像之前检查用户是否登录 @Johan 如果您使用 php 在输出消息之前检查用户是否已登录,那么您不希望浏览器缓存图像。如果浏览器缓存了图片,它不会在后续运行时调用你的脚本,即使用户没有登录,图片也会显示。 【参考方案1】:

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

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

然后,您将.htaccess file 放在将调用 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标头

【讨论】:

【参考方案2】:

首先,如果您使用会话,则必须禁用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();

【讨论】:

是的,我正在使用sessions。嗯,看起来你说的是我需要的,但我不明白如何将它们整合到工作代码中。想让浏览器缓存图片一年怎么写? 非常感谢,它对我来说太棒了!谢谢谢谢谢谢! :) If-Modified-Since 位是“d'oh”或“eureka!”时刻,随你喜欢! 这应该是选中的答案【参考方案3】:

这是我用于 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;
  

【讨论】:

【参考方案4】:

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

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

【讨论】:

嗯,这很好。但是将图像存储一个小时就可以了。 即使一个小时也不安全,只是希望黑客不要在某个时间尝试入侵。但是,从我在 mnot.net/cache_docs/#SCRIPT 上看到的情况来看,您似乎可以通过在 HTTP 标头中使用 Cache-control: public, no-cache; 来强制使用缓存进行身份验证(no-cache 实际上并不意味着没有缓存;名称有点偏离)。 您仍然可以缓存并且让浏览器调用服务器。这称为缓存验证。您可以通过发送Cache-control: private, must-revalidate(私有,因为它不应该在用户之间共享)和Last-ModifiedETag 标头来做到这一点。然后,当浏览器发送 If-Modified-SinceIf-None-Match 时,如果自生成图像以来没有任何变化,则返回状态 304 这不是问题的答案!【参考方案5】:

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

另一种处理图像的巧妙方法是精灵,请查一下。它节省了大量的带宽和请求。

如果速度如此重要,您也可以使用直接位图加载。但是,对于大图像不建议这样做。如果您正在加载它的图标和小图像/GIF。您可以直接在页面上使用位图。

【讨论】:

以上是关于如何使用 PHP 让浏览器缓存图像?的主要内容,如果未能解决你的问题,请参考以下文章

用php输出图片,怎么让浏览器缓存

在 PHP 中缓存动态图像

如何使用控制缓存标头?

如何强制浏览器重新缓存图像[重复]

如何在angularjs中将图像存储到浏览器缓存中

如何强制浏览器使用 php 刷新缓存?