0

わかりました、これがシナリオです:ログを解析して、「大きな画像」ページを実際に見ずに画像のサムネイルがダウンロードされた回数を見つける必要があります...これは基本的に、「親指」の比率に基づくホットリンク保護システムです。 「フル」画像ビューへ

サーバーがサムネイルへのリクエストによって絶えず攻撃されていることを考えると、最も効率的なソリューションは、たとえば 1Mb ごとに 1 回ディスクに書き込み、ログを定期的に解析するバッファリングされた apache ログを使用するようです。

私の質問は次のとおりです。PHPでApacheログを解析してデータを保存するにはどうすればよいですか。次のことが当てはまります。

  • ログはリアルタイムで使用および更新されます。これが行われている間、ログを読み取ることができるように PHP スクリプトが必要です。
  • php スクリプトは、ログのどの部分を読み取ったかを「覚えておく」必要があります。これにより、同じ部分を 2 回読み取ってデータを歪めないようにします。
  • ログは数時間で 10Gb のデータに簡単に到達するため、メモリ消費は最小限に抑える必要があります。

PHP ロガー スクリプトは 60 秒ごとに 1 回呼び出され、その間に処理できるログ行の量に関係なく処理されます。

いくつかのコードを一緒にハックしようとしましたが、最小量のメモリを使用するのに問題があり、「移動する」ファイルサイズでポインターを追跡する方法を見つけました

ログの一部を次に示します。

212.180.168.244 - - [18/Jan/2012:20:06:57 +0100] "GET /t/0/11/11441/11441268.jpg HTTP/1.1" 200 3072 "-" "Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.10.229 Version/11.60" "-"
122.53.168.123 - - [18/Jan/2012:20:06:57 +0100] "GET /t/0/11/11441/11441276.jpg HTTP/1.1" 200 3007 "-" "Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.10.229 Version/11.60" "-"
143.22.203.211 - - [18/Jan/2012:20:06:57 +0100] "GET /t/0/11/11441/11441282.jpg HTTP/1.1" 200 4670 "-" "Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.10.229 Version/11.60" "-"

ここにレビュー用のコードを添付します。

<?php
//limit for running it every minute
error_reporting(E_ALL);
ini_set('display_errors',1);
set_time_limit(0);
include(dirname(__FILE__).'/../kframework/kcore.class.php');
$aj = new kajaxpage;
$aj->use_db=1;
$aj->init();
$db=kdbhandler::getInstance();
$d=kdebug::getInstance();
$d->debug=TRUE;
$d->verbose=TRUE;

$log_file = "/var/log/nginx/access.log"; //full path to log file when run by cron
$pid_file = dirname(__FILE__)."/../kframework/cron/cron_log.pid";
//$images_id = array("8308086", "7485151", "6666231", "8343336");

if (file_exists($pid_file)) {
    $pid = file_get_contents($pid_file);
    $temp = explode(" ", $pid);
    $pid_timestamp = $temp[0];
    $now_timestamp = strtotime("now");
    //if (($now_timestamp - $pid_timestamp) < 90) return;
    $pointer = $temp[1];
    if ($pointer > filesize($log_file)) $pointer = 0;
}
else $pointer = 0;

$pattern = "/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[^\[]*\[([^\]]*)\][^\"]*\"([^\"]*)\"\s([0-9]*)\s([0-9]*)(.*)/";
$last_time = 0;
$lines_processed=0;

if ($fp = fopen($log_file, "r+")) {
    fseek($fp, $pointer);
    while (!feof($fp)) {
        //if ($lines_processed>100) exit;
        $lines_processed++;
        $log_line = trim(fgets($fp));
        if (!empty($log_line)) {
            preg_match_all($pattern, $log_line, $matches);
            //print_r($matches);
            $size = $matches[5][0];
            $matches[3][0] = str_replace("GET ", "", $matches[3][0]);
            $matches[3][0] = str_replace("HTTP/1.1", "", $matches[3][0]);
            $matches[3][0] = str_replace(".jpg/", ".jpg", $matches[3][0]);
            if (substr($matches[3][0],0,3) == "/t/") {
                $get = explode("-",end(explode("/",$matches[3][0])));
                $imgid = $get[0];
                $type='thumb';
            }
            elseif (substr($matches[3][0], 0, 5) == "/img/") {
                $get1 = explode("/", $matches[3][0]);
                $get2 = explode("-", $get1[2]);
                $imgid = $get2[0];
                $type='raw';
            }
            echo $matches[3][0];
            // put here your sql insert or update
            $imgid=(int) $imgid;
            if (isset($type) && $imgid!=1) {
                switch ($type) {
                    case 'thumb':
                        //use the second slave in the registry
                        $sql=$db->slave_query("INSERT INTO hotlink SET thumbviews=1, imageid=".$imgid." ON DUPLICATE KEY UPDATE thumbviews=thumbviews+1 ",2);
                        echo "INSERT INTO hotlink SET thumbviews=1, imageid=".$imgid." ON DUPLICATE KEY UPDATE thumbviews=thumbviews+1";
                    break;
                    case 'raw':
                        //use the second slave in the registry
                        $sql=$db->slave_query("INSERT INTO hotlink SET rawviews=1, imageid=".$imgid." ON DUPLICATE KEY UPDATE rawviews=rawviews+1",2);
                        echo "INSERT INTO hotlink SET rawviews=1, imageid=".$imgid." ON DUPLICATE KEY UPDATE rawviews=rawviews+1";
                    break;
                }
            }

            // $imgid - image ID
            // $size - image size

            $timestamp = strtotime("now");
            if (($timestamp - $last_time) > 30) {
                file_put_contents($pid_file, $timestamp . " " . ftell($fp));
                $last_time = $timestamp;
            }
        }
    }
    file_put_contents($pid_file, (strtotime("now") - 95) . " " . ftell($fp));
    fclose($fp);
}

?>
4

4 に答える 4

1

私の PHP バージョンの tail を微調整して、行を数えてからその時点から行を読み取り、1 つずつ処理するのではなく、最後のタイムスタンプを検索することができますか?

少し興味があるので自分で試してみますが、残念ながら今はできません:(

于 2012-01-19T12:24:32.920 に答える
0

代わりに、実行中のスクリプトにログ エントリを個人的に送信します。Apache は、パイプ (|) でログのファイル名を開始することにより、これを許可します。これが機能しない場合は、FIFO も作成できます (mkfifo を参照)。

実行中のスクリプト (それが何であれ) は x 行をバッファリングし、それに基づいて必要なことを実行できます。データを読み取ることはそれほど難しいことではなく、ボトルネックになる場所であってはなりません。

データベースでの INSERT ステートメントで問題が発生すると思われます。

于 2012-01-19T11:33:55.997 に答える
0

解決策は、ログを mysql データベースに保存することです。おそらく、ログ ファイルを mysql に保存した後、ログ ファイルを解析する C 言語プログラムを作成できます。はるかに高速で、それほど難しくありません。別のオプションはフィトンを使用することですが、データベースを使用する必要があると思います。全文索引を使用して文字列を照合できます。Python はバイナリにコンパイルすることもできます。これにより、より効率的になります。リクエストに応じて: ログ ファイルは増分的にスタックされます。一度に 10GB を与えるということではありません。

于 2012-01-18T19:13:26.843 に答える
0

この回答が遅れていることは知っていますが、それでも役立つ可能性があります (コードは常に改善できます)。

10Gb のファイル サイズと必要なメモリは、主な問題のように聞こえます。Apache は複数のログ ファイルをサポートしており、複数のログ ファイルの真の力は、さまざまな形式のログ ファイルを作成できることにありますhttp://httpd.apache.org/docs/1.3/multilogs.html

リアルタイムのログ監視に必要な最小限のデータのみを含む 2 つ目のログ ファイルを作成します。この場合、最初にユーザーエージェント文字列などをログから削除できる場合があります。

ログ行の例に基づいて、これにより、PHP がロードする必要があるデータの量が半分になる可能性があります。

于 2013-01-07T22:09:08.357 に答える