【问题标题】:Cache manipulated images in PHP在 PHP 中缓存处理过的图像
【发布时间】:2012-02-23 10:16:51
【问题描述】:

效果很好。

但是,问题是图像更改但名​​称相同时。我的缓存系统识别出图像已更改并删除旧的缓存文件并创建新文件,然后从我自己的缓存中提供新的调整大小的缓存文件。但是我的系统或网络浏览器缓存有问题。

当图像更改时,我的脚本会发送 200 OK 标头(用于更改的文件)...但图像预览不会更改并且响应为 200 OK,直到我在浏览器中手动按 F5。然后它再次发送 200 OK 并更改图像,从那时起它发送 304 Not changed(应该如此)。但问题是我必须按 F5 才能更改浏览器缓存的图像...我不知道为什么 200 OK 不会更改浏览器缓存的文件...

代码:

<?php

// Image manipulation script

include("../../../Init.php");

if(!isset($_GET["File"]))
    return;

$sFullFile = urldecode($_GET["File"]);

$pData = pathinfo($sFullFile);

// Options
$sActions = isset($_GET["Actions"]) ? $_GET["Actions"] : "";
$iMaxWidth = isset($_GET["MaxWidth"]) ? (int)$_GET["MaxWidth"] : 0;
$iMaxHeight = isset($_GET["MaxHeight"]) ? (int)$_GET["MaxHeight"] : 0;
$bSaveAspect = isset($_GET["SaveAspect"]) & $_GET["SaveAspect"] == "0" ? false : true;

// Cache control
$sPathCacheString = md5($pData["dirname"]);
$sFileCacheString = md5($pData["basename"]);
$pLastModTime = filemtime($sFullFile);
$sOptCacheString = md5($sActions . $iMaxWidth . $iMaxHeight . $bSaveAspect);

$sCacheFile = ImageCache::GetImageManipulatorCacheFileName($sFullFile, $sActions, $iMaxWidth, $iMaxHeight, $bSaveAspect);

header("Cache-Control: private, max-age=2592000, pre-check=2592000, must-revalidate");
header("Pragma: private");
header("Expires: " . date(DATE_RFC822, strtotime(" 30 day")));

$sLastModString = gmdate("D, d M Y H:i:s \G\M\T", $pLastModTime);
if(isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) >= $pLastModTime)
{
    header("HTTP/1.0 304 Not Modified");
    return;
}
else
{
    $pImage = new Image($sFullFile);

    @unlink($sCacheFile);

    if(GetFlag("ResizeMax", $sActions))
    {
        if($pImage->GetWidth() > $iMaxWidth || $pImage->GetHeight() > $iMaxHeight)
            $pImage->ResizeImage($iMaxWidth, $iMaxHeight, $bSaveAspect);
    }

    Cache::WriteFile($sCacheFile, $pImage->GetOutput());    

    header("Last-Modified: $sLastModString");
    header("Content-type: " . $pImage->GetMIMEType());
    $pImage->Destroy();

    Cache::StreamOut($sCacheFile);
}


/*

    Copyright (C) 2010. Determinanta
    http://www.determinanta.hr
    Part of WebSuite aplication platform. All rights reserved.

*/


?>

编辑:已解决

我解决了...问题是检查 $_SERVER["HTTP_IF_MODIFIED_SINCE"]...如果没有更改,我现在只是提供缓存文件。我花了整个上午才解决这个问题...感谢您的所有投入。干杯。

<?php

// Image manipulation script

include("../../../Init.php");

if(!isset($_GET["File"]))
    return;

$sFullFile = urldecode($_GET["File"]);

$pData = pathinfo($sFullFile);

// Options
$sActions = isset($_GET["Actions"]) ? $_GET["Actions"] : "";
$iMaxWidth = isset($_GET["MaxWidth"]) ? (int)$_GET["MaxWidth"] : 0;
$iMaxHeight = isset($_GET["MaxHeight"]) ? (int)$_GET["MaxHeight"] : 0;
$bSaveAspect = isset($_GET["SaveAspect"]) & $_GET["SaveAspect"] == "0" ? false : true;

// Cache control
$sPathCacheString = md5($pData["dirname"]);
$sFileCacheString = md5($pData["basename"]);
$pLastModTime = filemtime($sFullFile);
$sOptCacheString = md5($sActions . $iMaxWidth . $iMaxHeight . $bSaveAspect);

$sCacheFile = ImageCache::GetImageManipulatorCacheFileName($sFullFile, $sActions, $iMaxWidth, $iMaxHeight, $bSaveAspect);
$sFullCacheFile = CACHE_PATH . "/" . $sCacheFile;

$bCacheNotModified = true;
if(!is_file($sFullCacheFile))
    $bCacheNotModified = false;
else
{
    if(filemtime($sFullCacheFile) != $pLastModTime)
        $bCacheNotModified = false;
}

$sLastModString = gmdate("D, d M Y H:i:s \G\M\T", $pLastModTime);
if($bCacheNotModified)
{
    header("HTTP/1.0 304 Not Modified");
    return;
}
else
{               
    $pImage = new Image($sFullFile);

    @unlink($sCacheFile);

    if(GetFlag("ResizeMax", $sActions))
    {
        if($pImage->GetWidth() > $iMaxWidth || $pImage->GetHeight() > $iMaxHeight)
            $pImage->ResizeImage($iMaxWidth, $iMaxHeight, $bSaveAspect);
    }

    Cache::WriteFile($sCacheFile, $pImage->GetOutput());
    touch($sFullCacheFile, $pLastModTime);

    header("Cache-Control: private, max-age=2592000, pre-check=2592000, must-revalidate");
    header("Pragma: private");
    header("Expires: " . date(DATE_RFC822, 0));
    header("Last-Modified: $sLastModString");
    header("ETag: \"" . $sImageMD5 . "\"");
    header("Content-type: " . $pImage->GetMIMEType());

    $pImage->Destroy();

    Cache::StreamOut($sCacheFile);
}


/*

    Copyright (C) 2010. Determinanta
    http://www.determinanta.hr
    Part of WebSuite aplication platform. All rights reserved.

*/


?>

【问题讨论】:

    标签: php caching browser-cache


    【解决方案1】:

    您面临的问题是浏览器。我也尝试过使用响应代码和标头来解决它,但最终让浏览器获取新图像的唯一可靠方法是将唯一的字符串附加到 url,例如时间戳。一种简单的解决方案是,当图像更改时,将当前时间戳附加到您的 html 源代码中,如下所示:

    <img src="path/to/your/php/script.php?<?= time(); ?>"/>
    

    【讨论】:

    • 是的,我知道这种解决方法,但是这种方法的问题是文件永远不会缓存,因为它将此 src 路径视为新图像(因为不断更改 time() 编号)...
    • 同意,这就是为什么你必须有逻辑来决定是否附加 time() 函数。在您的代码中,您已经在 PHP 端知道图像是否已更改,因此请使用相同的逻辑来决定是否附加时间戳。
    【解决方案2】:

    您是否尝试在图像的标题中设置 ETag(实体标签)?

    将图像MD5转换成变量,然后设置ETag如下:

    header("ETag: \"".$img_md5."\");
    

    【讨论】:

    • 抱歉,不知道你将如何解决这个问题。最近我一直在告诉 Chrome 在开发时不要缓存任何东西,一旦我部署,我会使用 cache.manifest 来强制删除客户端缓存,每当我发布新版本时。
    • 是的...... Chrome 的缓存非常糟糕......我正在使用 Firefox 进行测试和开发。不知道怎么办……有什么办法可以删除本地浏览器缓存文件吗?
    • 在 Chrome 检查器中,您可以点击右下角的 cog 并获得关闭所有缓存的选项。另一种方法是使用新的隐身窗口打开。希望这会有所帮助
    • 问题是如何强制任何浏览器理解文件已更改。
    猜你喜欢
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2021-03-27
    • 2012-02-15
    • 1970-01-01
    相关资源
    最近更新 更多