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

时间:2022-10-07 01:23:46

I couldn't find a succinct way to summarise the question in the title, allow me to elaborate:

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

I have a website that uses a PHP script "getImg.php" that takes an image binary object from my database and display it when called by the HTML img tag on a separate page.

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

I would like to log the number of times people view images so I added a simple line to increment the 'views' property for the appropriate image.

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

I thought this would be simple, but it turns out that it increments twice. My bodgy way around this was to make the 'views' column a float and increment by 0.5 to result with a 1 increment. However, I viewed my database today to find 0.5 in some images!

我认为这很简单,但事实证明它增加了两倍。我的方法是将“视图”列设为浮点数并增加0.5,结果为1。但是,我今天查看了我的数据库,在某些图像中找到了0.5!

When I comment out the end print it works properly. I assumed the call from the HTML tag plus the script itself counts for two calls? But this doesn't seem to be the case with other people.

当我注释掉最终打印时,它可以正常工作。我假设来自HTML标签的调用加上脚本本身计入两次调用?但其他人似乎并非如此。

Is this just my set up?

这只是我的设置吗?

<?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;

?>

Thanks for any help.

谢谢你的帮助。

2 个解决方案

#1


3  

This seems to be a brwoser issue. Browsers like Chrome could prefetch the images so it is loaded once and if the user clicks on a link to a image - it is loaded twice.

这似乎是一个更加粗糙的问题。像Chrome这样的浏览器可以预取图像,使其加载一次,如果用户点击指向图像的链接,则会加载两次。

Check:

Load a image with your browser and then check your apache access.log and if you see 2 request at the same time it is a browser issue.

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

#2


2  

Here's your problem:

这是你的问题:

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

You're starting this if...else branch as a 1-line deal, but in the else case you're executing a code block. php starts executes that 1 line below if, skips else and the first subsequent line and carries on as if the closing barcket weren't there. It's somewhat of a bug I reckon. I've been hearing a lot of people complaining about this lately. (since 5.3.7 or something). Set your ini to E_STRICT error reporting and check if that makes any difference

如果... else分支作为1行交易,你就开始这个,但在其他情况下你正在执行代码块。 php开始执行下面的1行if,跳过else和第一个后续行并继续进行,好像关闭barcket不在那里。这有点像我估计的错误。我听到很多人最近抱怨这个。 (自5.3.7起)。将您的ini设置为E_STRICT错误报告,并检查是否有任何区别


Looks like Besnik found it before I started to even look into it (well done and +1). @Lee: Here's how to avoid this issue:

看起来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]

Found this 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 either of the branches are missing curly braces that could cause issues. Again: if the if statement isn't contained in a code block, only the first statement (all code up to the first semi-colon) following the else statement will be interpreted as a branch. This is the assignment to the $img variable in your case. The database insert will be called in both cases.

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

You could check to see weather or not the db query is executed using the __halt_compiler:

你可以检查天气是否使用__halt_compiler执行db查询:

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
        }
    }
}

the __halt_compiler() function cannot be used in any other scope but the global namespace, and only affects the current script being executed, if this script is an include of -for example- the index.php, the index.php will carry on as is, but the include script will halt. Read the docs for a more comprehensive explanation (I suck at explaining things).

__halt_compiler()函数不能在除全局命名空间之外的任何其他范围内使用,并且只影响正在执行的当前脚本,如果此脚本包含 - 例如index.php,则index.php将继续执行是,但包含脚本将停止。阅读文档以获得更全面的解释(我很难解释事情)。


All this won't help you avoid this issue while figuring this one out, so I'd suggest this fugly work around for now:

所有这些都无法帮助你避免这个问题同时解决这个问题,所以我建议现在这个非常好的工作:

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

Let me know which of the above works, or if you're still encountering the same problem. I find this a very curious and therefore interesting case :)

让我知道上面的哪些作品,或者你是否仍然遇到同样的问题。我发现这是一个非常好奇,因此有趣的情况:)

#1


3  

This seems to be a brwoser issue. Browsers like Chrome could prefetch the images so it is loaded once and if the user clicks on a link to a image - it is loaded twice.

这似乎是一个更加粗糙的问题。像Chrome这样的浏览器可以预取图像,使其加载一次,如果用户点击指向图像的链接,则会加载两次。

Check:

Load a image with your browser and then check your apache access.log and if you see 2 request at the same time it is a browser issue.

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

#2


2  

Here's your problem:

这是你的问题:

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

You're starting this if...else branch as a 1-line deal, but in the else case you're executing a code block. php starts executes that 1 line below if, skips else and the first subsequent line and carries on as if the closing barcket weren't there. It's somewhat of a bug I reckon. I've been hearing a lot of people complaining about this lately. (since 5.3.7 or something). Set your ini to E_STRICT error reporting and check if that makes any difference

如果... else分支作为1行交易,你就开始这个,但在其他情况下你正在执行代码块。 php开始执行下面的1行if,跳过else和第一个后续行并继续进行,好像关闭barcket不在那里。这有点像我估计的错误。我听到很多人最近抱怨这个。 (自5.3.7起)。将您的ini设置为E_STRICT错误报告,并检查是否有任何区别


Looks like Besnik found it before I started to even look into it (well done and +1). @Lee: Here's how to avoid this issue:

看起来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]

Found this 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 either of the branches are missing curly braces that could cause issues. Again: if the if statement isn't contained in a code block, only the first statement (all code up to the first semi-colon) following the else statement will be interpreted as a branch. This is the assignment to the $img variable in your case. The database insert will be called in both cases.

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

You could check to see weather or not the db query is executed using the __halt_compiler:

你可以检查天气是否使用__halt_compiler执行db查询:

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
        }
    }
}

the __halt_compiler() function cannot be used in any other scope but the global namespace, and only affects the current script being executed, if this script is an include of -for example- the index.php, the index.php will carry on as is, but the include script will halt. Read the docs for a more comprehensive explanation (I suck at explaining things).

__halt_compiler()函数不能在除全局命名空间之外的任何其他范围内使用,并且只影响正在执行的当前脚本,如果此脚本包含 - 例如index.php,则index.php将继续执行是,但包含脚本将停止。阅读文档以获得更全面的解释(我很难解释事情)。


All this won't help you avoid this issue while figuring this one out, so I'd suggest this fugly work around for now:

所有这些都无法帮助你避免这个问题同时解决这个问题,所以我建议现在这个非常好的工作:

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

Let me know which of the above works, or if you're still encountering the same problem. I find this a very curious and therefore interesting case :)

让我知道上面的哪些作品,或者你是否仍然遇到同样的问题。我发现这是一个非常好奇,因此有趣的情况:)