PHP脚本显示图像BLOB执行两次


PHP script display image BLOB executed twice?

我找不到一种简洁的方式来总结标题中的问题,请允许我详细说明:

我有一个网站,它使用了一个PHP脚本"getImg.PHP",该脚本从我的数据库中获取一个图像二进制对象,并在被HTML img标记调用时在单独的页面上显示它。

我想记录人们查看图像的次数,所以我添加了一行简单的代码来增加相应图像的"views"属性。

我原以为这会很简单,但结果是它增加了两倍。我解决这个问题的方法是将"视图"列设为浮动列,然后增加0.5,得到1的增量。然而,我今天查看了我的数据库,在一些图像中发现了0.5!

当我评论结束打印时,它工作正常。我假设来自HTML标记的调用加上脚本本身算两个调用?但其他人的情况似乎并非如此。

这只是我的安排吗?

<?php
# Connect to db
include('db.php');
# Get ID
$id = $_GET['id'];
if(!is_numeric($id)) exit;
$q = $db->prepare("SELECT tNail,image,format FROM gallery WHERE id = '$id'");
$q->execute();
$row = $q->fetch(PDO::FETCH_ASSOC);
if(array_key_exists("thumb", $_GET))
    $img = base64_decode($row["tNail"]);
else
{
    $img = base64_decode($row["image"]);
    # Add to views if not thumb
    // 0.5 because script called twice due to print?
    $db->query("UPDATE gallery SET views = (views + 0.5) WHERE id = '$id'");
}
switch($row["format"])
{
    case ".jpg":
        header("Content-type: image/jpeg");
        break;
    case ".png":
        header("Content-type: image/png");
        break;
}
print $img;
?>

谢谢你的帮助。

这似乎是一个brwoser问题。像Chrome这样的浏览器可以预取图像,这样它就会加载一次,如果用户点击图像链接,它就会加载两次。

检查

用浏览器加载一个图像,然后检查你的apacheaccess.log,如果你同时看到2个请求,那就是浏览器问题。

这是您的问题:

if(array_key_exists("thumb", $_GET))
    $img = base64_decode($row["tNail"]);
else
{$img = base64_decode($row["image"]);//<==

您将这个if...else分支作为一个单行交易来启动,但在其他情况下,您将执行一个代码块。php开始执行if下面的那一行,跳过else和后面的第一行,继续执行,就好像没有结束符一样。我觉得这有点像虫子。我最近听到很多人抱怨这件事。(从5.3.7开始)。将您的ini设置为E_STRICT错误报告,并检查这是否会对产生任何影响


看起来Besnik在我开始研究之前就发现了它(做得很好,+1)@李:以下是如何避免这个问题:

RewriteEngine On
SetEnvIfNoCase X-Forwarded-For .+ proxy=yes
SetEnvIfNoCase X-moz prefetch no_access=yes
# block pre-fetch requests with X-moz headers
RewriteCond %{ENV:no_access} yes
RewriteRule .* - [F,L]

在这里找到这个


if(array_key_exists("thumb", $_GET))
{
    $img = base64_decode($row["tNail"]);
}
else
{
    $img = base64_decode($row["image"]);
    $db->query("UPDATE gallery SET views = (views + 0.5) WHERE id = '$id'");
}

如果其中一个分支缺少大括号,则可能会导致问题。同样:如果if语句不包含在代码块中,那么只有else语句后面的第一个语句(所有代码直到第一个分号)将被解释为分支。在您的案例中,这是对$img变量的赋值。在这两种情况下都将调用数据库插入。

您可以使用__halt_compiler:查看数据库查询是否执行

if(array_key_exists("thumb", $_GET))
{
    $img = base64_decode($row["tNail"]);
}
else
{
    $img = base64_decode($row["image"]);
    if ($db->query("UPDATE gallery SET views = (views + 0.5) WHERE id = '$id'"))
    {
        if (array_key_exists("thumb", $_GET))
        {//this should be an impossible branch
            __halt_compiler();//or exit || throw if this is a (member) function
        }
    }
}

__halt_compiler()函数不能用于除全局命名空间之外的任何其他范围,并且只影响正在执行的当前脚本,如果该脚本是index.php的include,则index.php将按原样进行,但include脚本将停止。阅读文档以获得更全面的解释(我很难解释)。


所有这些都不能帮助你在解决这个问题的同时避免这个问题,所以我建议暂时解决这个问题:

if(array_key_exists("thumb", $_GET))
{
    $img = base64_decode($row["tNail"]);
    $db = null;//disconnect
}
else
{
    $img = base64_decode($row["image"]);
    if ($db !== null)
    {//or $db instanceof PDO (or whatever object you're using)
     //or try{$db->query('UPDATE...');}catch(Exception $e){}//<- suppress exception
        $db->query("UPDATE gallery SET views = (views + 0.5) WHERE id = '$id'");
    }
}

让我知道上面哪一个有效,或者你是否仍然遇到同样的问题。我发现这是一个非常奇怪的,因此也很有趣的案例:)