14

PHPを使用して画像のキャッシュを処理するためのベストプラクティスの方法は何でしょうか。

ファイル名は現在MySQLデータベースに保存されており、アップロード時に元のファイル名とaltタグとともにGUIDに名前が変更されます。

画像がHTMLページに配置されるときは、phpスクリプトに書き換えられた'/images/get/200x200/{guid}.jpgなどのURLを使用して配置されます。これにより、デザイナーはファイルサイズを指定できます(おおよそ-ソースイメージはもっと小さいかもしれません)。

次に、phpスクリプトは、サイズ(urlの200x200)とGUIDファイル名のハッシュを作成し、ファイルが以前に生成されている場合(ハッシュの名前のファイルがTMPディレクトリに存在する場合)、アプリケーションのTMPディレクトリからファイルを送信します。ハッシュされたファイル名が存在しない場合は、作成され、ディスクに書き込まれ、同じ方法で提供されます。

これは可能な限り効率的ですか?(画像の透かし入れもサポートしており、透かし入れの設定もハッシュに保存されますが、これは範囲外です。)

4

9 に答える 9

30

私は別の方法でそれを行います。

問題点: 1. PHP にファイルを提供させるのは、実際よりも効率が悪い。2. PHP は、画像が要求されるたびにファイルの存在をチェックする必要があります。 3. Apache は、PHP よりもはるかに優れています。

ここにはいくつかの解決策があります。

mod_rewriteアパッチで使えます。mod_rewrite を使用してファイルが存在するかどうかをテストし、存在する場合は代わりにそのファイルを提供することができます。これにより、PHP が完全にバイパスされ、処理が大幅に高速化されます。ただし、これを行う実際の方法は、常に存在する特定の URL スキーマを生成し、存在しない場合は PHP にリダイレクトすることです。

例えば:

RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]

そのため、クライアントが要求/images/cached/<something>し、そのファイルがまだ存在しない場合、Apache は要求を にリダイレクトし/images/generate.php?/images/cached/<something>ます。このスクリプトは、イメージを生成してキャッシュに書き込み、クライアントに送信できます。今後は、新しいイメージを除いて、PHP スクリプトが呼び出されることはありません。

キャッシングを使用します。別のポスターが言ったようmod_expiresに、Last-Modified ヘッダーなどを使用して、条件付き GET 要求に応答します。クライアントが画像を再リクエストする必要がなければ、ページの読み込みが大幅に高速化され、サーバーの負荷が減少します。

PHP から画像を送信する必要がある場合は、 を使用mod_xsendfileしてより少ないオーバーヘッドで送信できます。この問題については、Arnold Daniels による優れたブログ投稿を参照してください。ただし、彼の例はダウンロードに関するものであることに注意してください。画像をインラインで提供するには、Content-Disposition ヘッダーを取り出します (3 番目の header() 呼び出し)。

これがお役に立てば幸いです-片頭痛が治った後はもっと.

于 2008-09-26T19:17:48.357 に答える
10

Dan Udey の書き直しの例には 2 つのタイプミスがあります (コメントできません)。

RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]

よろしく。

于 2009-12-29T15:02:58.823 に答える
5

追加する価値のある1つの注意点は、コードがこれらの画像の「許可されていない」サイズを生成しないことを確認することです。

したがって、次のURLは、イメージ1234の200x200バージョンがまだ存在しない場合は作成します。リクエストされたURLに、サポートする画像のサイズが含まれていることを確認することを強くお勧めします。

/images/get/200x200/1234.jpg

悪意のある人物がランダムなURLを要求し始め、常に画像の高さと幅を変更する可能性があります。これにより、サーバーに深刻な問題が発生し、基本的に攻撃を受けて、サポートされていないサイズのイメージが生成されます。

/images/get/0x1/1234.jpg
/images/get/0x2/1234.jpg
...
/images/get/0x9999999/1234.jpg
/images/get/1x1/1234.jpg
...
etc

これを説明するコードのランダムな断片は次のとおりです。

<?php

    $pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']);

    if(file_exists($pathOnDisk)) {
        // send header with image mime type 
        echo file_get_contents($pathOnDisk);
        exit;
    } else {
        $matches = array();
        $ok = preg_match(
            '/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/', 
            $_SERVER['REQUEST_URI'], $matches);

        if(! $ok) {
            // invalid url
            handleInvalidRequest();
        } else {
            list(, $width, $height, $guid) = $matches;

            // you should do this!
            if(isSupportedSize($width, $height)) {
                // size is supported. all good
                // generate the resized image, save it & output it
            } else {
                // invalid size requested!!!
                handleInvalidRequest();
            }
        }
    }

    // snip
    function handleInvalidRequest() {
        // do something w/ invalid request          
        // show a default graphic, log it etc
    }
?>
于 2008-09-26T18:48:14.403 に答える
1

素晴らしい投稿のようですが、私の問題はまだ解決されていません。ホスト プロバイダーで htaccess にアクセスできないので、Apache の微調整に問題はありません。画像の cace-control ヘッダーを設定する方法は本当にありますか?

于 2009-03-01T23:51:23.893 に答える
0

データベースにファイルアドレスを保持する代わりに、ユーザーがログインするたびにファイル名に乱数を追加することをお勧めします。ユーザー1234の場合は次のようになります。image/ picture_1234.png?rnd = 6534122341

セッション中にユーザーが新しい写真を送信した場合は、乱数を更新するだけです。

GUIDはキャッシュの問題に100%取り組みます。ただし、画像ファイルを追跡するのが難しくなります。この方法では、ユーザーが将来のログイン時に同じ画像を再び表示する可能性があります。ただし、10億の数字から乱数を生成する場合、オッズは低くなります。

于 2010-04-04T00:18:37.180 に答える
0

あなたのアプローチは非常に合理的だと思います-キャッシュされたバージョンが生成された日付が元の(ソース)画像ファイルの最後に変更されたタイムスタンプの後であることを確認し、そうでない場合はキャッシュ/サイズ変更されたバージョンを再生成するためのメカニズムを導入する必要があることを追加します。これにより、デザイナーが画像を変更した場合でも、キャッシュが適切に更新されます。

于 2008-09-26T17:22:09.147 に答える
0

PHPでリダイレクトヘッダーを使用するだけで、これを行うことができました。

if (!file_exists($filename)) {  

    // *** Insert code that generates image ***

    // Content type
    header('Content-type: image/jpeg'); 

    // Output
    readfile($filename);    

} else {
    // Redirect
    $host  = $_SERVER['HTTP_HOST'];
    $uri   = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
    $extra = $filename;
    header("Location: http://$host$uri/$extra");
}
于 2009-03-05T17:01:28.170 に答える
0

それはそれを行うための堅実な方法のように聞こえます。次のステップは、PHP/MySQL を超えることかもしれません。

おそらく、ヘッダーを微調整してください:

PHP を使用して MIME タイプを送信している場合は、'Keep-alive' ヘッダーと 'Cache-control' ヘッダーを使用してサーバー上の画像の寿命を延ばし、PHP/MySQL の負荷を軽減することもできます。

また、キャッシュ用の apache プラグインも検討してください。mod_expiresのように

ああ、もう 1 つ、サーバーをどの程度制御できますか? この会話をPHP/MySQLだけに制限する必要がありますか?

于 2008-09-26T17:29:20.240 に答える
0

phpThumbは、サイズ変更された画像/サムネイルをオンザフライで生成するフレームワークです。また、キャッシングも実装しており、実装は非常に簡単です。

画像のサイズを変更するコードは次のとおりです。

<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&amp;h=200" alt="thumbnail"/>

200 x 200 のサムネイルが表示されます。

透かしもサポートしています。

http://phpthumb.sourceforge.net/で確認してください。

于 2008-09-26T18:34:26.043 に答える