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

Posted

技术标签:

【中文标题】PHP脚本显示图像BLOB执行了两次?【英文标题】:PHP script display image BLOB executed twice? 【发布时间】:2012-08-01 13:11:36 【问题描述】:

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

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

我想记录人们查看图像的次数,因此我添加了一个简单的行来增加相应图像的“视图”属性。

我以为这很简单,但事实证明它增加了两次。我解决这个问题的方法是使“视图”列浮动并增加 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;

?>

感谢您的帮助。

【问题讨论】:

为什么要将一整列专门用于文件扩展名?为什么不直接阅读加载时苍蝇的 mime 类型?此外,缩略图不需要存储为单独的列,您应该让 php 生成调整大小的图像。以上所有方法都将在您的数据库中节省 大量 空间并且效率更高。 我使用生成器来处理大量图像,因此在生成器和数据库上施加尽可能多的负载似乎是一种更有效的方法,因为它只需要查询即可找到它。以你的方式去做会有很大的不同吗?唯一的好处是节省存储空间,对吧?生成器脚本会调整图像大小。我宁愿减轻预处理器的负担。我更喜欢访问者加载时间而不是数据库空间。 这样可以节省空间并且不会在服务器上留下任何明显的污点。与许多人的看法相反,图像处理是服务器完成的一项简单任务。如果有的话,它给服务器带来的压力可以忽略不计。我看看能不能找到好的文案。大多数大型网络服务都使用这种方法。 好的,谢谢。你知道是什么导致了我的双倍增量吗? 为什么不回显而不是打印? 【参考方案1】:

这是你的问题:

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

您将这个 if...else 分支作为 1 行交易开始,但在 else 情况下,您正在执行代码块。 php 开始执行 if 下面的 1 行,跳过 else 和后续的第一行,并继续执行,就好像关闭 barcket 不存在一样。我认为这是一个错误。我最近听到很多人抱怨这件事。 (从 5.3.7 或其他版本开始)。将您的 ini 设置为 E_STRICT 错误报告并检查是否有任何不同


看起来 Besnik 在我开始研究之前就找到了它(做得好,+1)。 @Lee:以下是避免此问题的方法:

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]

找到这个here


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,则 index.php 将按原样继续,但包含脚本将停止。 Read the docs 以获得更全面的解释(我不擅长解释事情)。


所有这些都不能帮助你在解决这个问题时避免这个问题,所以我建议现在这个丑陋的解决方法:

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'");
    

如果您仍然遇到同样的问题,请告诉我以上哪些方法有效。我发现这是一个非常好奇且因此很有趣的案例:)

【讨论】:

hm,我更改了错误报告,甚至为 if 语句添加了通常的大括号,但没有任何改变。当我注释掉打印构造时,它会正确递增,非常奇怪。 确实很好奇,等我完成工作再看看。很难理解这里发生了什么......解决它总是很有趣! @Lee:让我知道重写规则是否有效,它可能有一天会派上用场 谢谢。 mod_rewrite.so 已经启用,但是当我创建 .htaccess 并将其放在站点的 HTML 文件夹中时,似乎没有任何改变。我没有使用 .htaccess 的经验。将其粘贴到空白 .htaccess 文件中就足够了吗? 并在您的网络服务器上启用mod_rewrite,并且可能最好设置您的 RewriteEngine,并可能声明一个重写基础等... 一切正常:阅读链接,开始有点棘手关闭,但非常值得【参考方案2】:

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

检查

使用浏览器加载图像,然后检查 apache access.log,如果您同时看到 2 个请求,则说明是浏览器问题。

【讨论】:

你是对的。这在 FF 14.0.1 中表现不正确,但在 K-meleon 中表现良好。这是我无法避免的事情吗? 谢谢,是的,它要求两个请求

以上是关于PHP脚本显示图像BLOB执行了两次?的主要内容,如果未能解决你的问题,请参考以下文章

php mysqli_query 函数似乎运行了两次

如何在 php 中显示 blob 类型的图像?

无法使用 PHP 显示数据库中的 blob 图像

PHP / MySQL - 显示来自blob的图像[重复]

RequestImage 的结果处理程序调用了两次

PHP 文件执行了两次,但只在 Firefox 中执行