4

タイトルの質問を簡潔に要約する方法が見つかりませんでした。詳しく説明させてください。

データベースから画像バイナリ オブジェクトを取得し、HTML img タグによって呼び出されたときに別のページに表示する PHP スクリプト "getImg.php" を使用する Web サイトがあります。

人々が画像を表示した回数を記録したいので、適切な画像の「views」プロパティをインクリメントする単純な行を追加しました。

これは簡単だと思っていましたが、2 倍になっていることがわかりました。これを回避する私の厄介な方法は、「ビュー」列をフロートにし、0.5ずつインクリメントして1インクリメントすることでした。ただし、今日データベースを表示して、いくつかの画像で 0.5 を見つけました!

エンドプリントをコメントアウトすると、正しく機能します。HTML タグからの呼び出しとスクリプト自体が 2 つの呼び出しとしてカウントされると仮定しましたか? しかし、これは他の人には当てはまらないようです。

これは私だけの設定ですか?

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

?>

助けてくれてありがとう。

4

2 に答える 2

3

これはブラウザの問題のようです。Chrome などのブラウザは画像をプリフェッチできるため、画像は 1 回読み込まれ、ユーザーが画像へのリンクをクリックすると、画像は 2 回読み込まれます。

チェック:

ブラウザで画像をロードし、Apache の access.log を確認します。同時に 2 つのリクエストが表示される場合は、ブラウザの問題です。

于 2012-08-03T14:00:35.613 に答える
2

これがあなたの問題です:

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

このif...elseブランチは1行の取引として開始していますが、それ以外の場合はコードブロックを実行しています。php startは、ifの場合、その1行下を実行し、elseとそれに続く最初の行をスキップして、終了バーケットがないかのように続行します。それは私が考えるバグのようなものです。最近、これについて多くの人が不満を言っているのを聞いています。(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]

ここでこれを見つけました


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:を使用して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
        }
    }
}

この__halt_compiler()関数は、グローバル名前空間以外のスコープでは使用できず、実行中の現在のスクリプトにのみ影響します。このスクリプトがインクルードである場合、たとえばindex.php、index.phpはそのまま続行されますが、インクルードスクリプトは停止します。より包括的な説明については、ドキュメントを読んでください(私は物事を説明するのが苦手です)。


これはすべて、これを理解しているときにこの問題を回避するのに役立ちません。そのため、今のところ、この厄介な回避策をお勧めします。

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

上記のどれが機能するか、または同じ問題が引き続き発生するかどうかをお知らせください。私はこれが非常に好奇心が強く、したがって興味深いケースだと思います:)

于 2012-08-03T13:49:22.893 に答える