0

簡単な統計情報を取得するために、テーマに含まれるこの php トラッカー コードを作成しました。多くのリクエストを処理するため、堅牢で高速である必要があります。私の PHP レベルはあまり良くないので、この悪人を最適化するためのヘルプ/ベスト プラクティスを探しています。

すべてのリクエストを index.php にリダイレクトする単純な .htaccess ファイルを作成して、リクエスト uri を php で処理できるようにしました。$_SERVER['REQUEST_URI'], /this-is-the-theme-slug /user-name

<?php
/** MySQL Database Settings */
require dirname(__FILE__) . '/inc/database.php';

/** Klogger Log Framework*/
require dirname(__FILE__) . '/lib/KLogger.php';
$log = KLogger::instance(dirname(__FILE__).'/log/', KLogger::DEBUG);

/** Process Request String **/
$request = $_SERVER['REQUEST_URI'];
$ipaddr = $_SERVER['REMOTE_ADDR'];

$uri = explode('/',$request);
$slug = $uri[1];
$user = $uri[2];

/** Global Variables **/
$theme_id = NULL;
$account_id = NULL;


function process_request(){
    global $log, $slug, $user;
    if(!empty($slug) && !empty($user)){

        $the_slug = validate_slug($slug);
        $the_user = account_exists($user);

        if($the_slug){  // if the slug is valid
            if($the_user){  // and the user exists
                // update entry
                update_entry($user);
            }else{
                // create new entry
                create_entry($user);
            }
        }

        return true;
    }else{
        $log->logError('process_request:: Bad request');
        return false;
    }
}

function validate_slug($slug){
    global $log, $theme_id;

    $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
    if(!$con){
        $log->logError('validate_slug:: Database connection failed');
        return false;   
    }else{
        $select = mysql_select_db(DB_NAME, $con);   
        $query = sprintf("SELECT id FROM ".DB_PREFIX."themes WHERE slug='%s'", mysql_real_escape_string($slug));
        $result = mysql_query($query);
        if(mysql_num_rows($result)==0){
            $log->logNotice('validate_slug:: Slug not found');
            return false;
        }else{
            $theme_id = mysql_result($result,0);
            return true;
        }   
        mysql_close($con);
    }
}

function account_exists($user){
    global $log, $account_id;

    $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
    if(!$con){
        $log->logError('account_exists:: Database connection failed');
        return false;   
    }else{
        $select = mysql_select_db(DB_NAME, $con);   
        $query = sprintf("SELECT id FROM ".DB_PREFIX."stats WHERE account='%s'", mysql_real_escape_string($user));
        $result = mysql_query($query);
        if(mysql_num_rows($result)==0){
            $log->logNotice('account_exists:: Account not found');
            return false;
        }else{
            $account_id = mysql_result($result,0);
            return true;
        }   
        mysql_close($con);
    }
}

function create_entry($user){
    global $log, $ipaddr, $theme_id;

    $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
    if(!$con){
        $log->logError('create_entry:: Database connection failed');
        return false;   
    }else{
        $select = mysql_select_db(DB_NAME, $con);
        $query = sprintf("INSERT INTO ".DB_PREFIX."stats (id,active,account,date,ip,hits,theme) VALUES ('','1','%s',NOW(),'".$ipaddr."','1','".$theme_id."')", mysql_real_escape_string($user));
        $result = mysql_query($query);

        $log->logNotice('create_entry:: Account created with id '.mysql_insert_id() );
        return true;
    }
    mysql_close($con);
}


function update_entry($user){
    global $log, $ipaddr, $account_id;  
    $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
    if (!$con) {
        $log->logError('update_entry:: Database connection failed');
        return false;
    } else {
        $select = mysql_select_db(DB_NAME, $con);
        $query = sprintf("UPDATE ".DB_PREFIX."stats SET date=NOW(),ip='".$ipaddr."',hits=hits+1 WHERE id='".$account_id."'");
        $result = mysql_query($query);

        $log->logNotice('update_entry:: Entry with id '.$account_id.' is updated.' );
        return true;
    }
    mysql_close($con);
}


process_request();

編集 トラッカー用の作業クラスを正常に作成しました。以下のコードを参照してください。速度の改善点があれば教えてください。mysqlli と pdo で接続しようとしましたが、うまくいきませんでした。どうやら私のホスティングがサポートしていないのでしょうか?

    <?php 
    require_once(__DIR__ . '/inc/database.php');
    require_once(__DIR__ . '/lib/KLogger.php');

    Class ThemeStatsTracker
    {
        public $log;

        private $theme_name;
        private $theme_user;
        private $theme_name_db_id;
        private $theme_user_db_id;

        public function __construct()
        {
            // Setup Log 
            $this->log = KLogger::instance(dirname(__FILE__).'/log/', KLogger::DEBUG);

            // Process URI variables
            $uri = explode('/',$_SERVER['REQUEST_URI']);    
            $this->theme_name = (!empty($uri[1])) ? $uri[1] : NULL;
            $this->theme_user = (!empty($uri[2])) ? $uri[2] : NULL;

            // Handle the Request
            $this->database_connect();
            if($this->validate_theme()){
                if($this->user_entry_exists()){
                    $this->user_entry_update(); 
                }else{
                    $this->user_entry_create();
                }   
            }

            // Always serve an image as response
            $this->serve_image();
        }

        private function validate_theme()
        {
            $query  = sprintf("SELECT id FROM ".DB_PREFIX."themes WHERE slug='%s' LIMIT 1", mysql_real_escape_string($this->theme_name));
            $result = mysql_query($query);
            if (!$result){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
            if(mysql_num_rows($result)==0){
                $this->log->logError(__FUNCTION__ . ' Theme name ' . $this->theme_name . ' NOT found');
                return FALSE;
            }else{
                $this->log->logInfo(__FUNCTION__ . ' Theme name ' . $this->theme_name . ' found');
                $this->theme_name_db_id = mysql_result($result,0);
                return TRUE;
            }
        }

        private function user_entry_exists()
        {
            $query  = sprintf("SELECT id FROM ".DB_PREFIX."stats WHERE account='%s' LIMIT 1", mysql_real_escape_string($this->theme_user));
            $result = mysql_query($query);
            if (!$result){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
            if(mysql_num_rows($result)==0){
                $this->log->logInfo(__FUNCTION__ . ' New user ' . $this->theme_user);
                return FALSE;
            }else{
                $this->log->logInfo(__FUNCTION__ . ' Existing user ' . $this->theme_user);
                $this->theme_user_db_id = mysql_result($result,0);
                return TRUE;
            }   
        }

        private function user_entry_create()
        {
            $query  = sprintf("INSERT INTO ".DB_PREFIX."stats (id,active,account,date,ip,hits,theme) VALUES ('','1','%s',NOW(),'".$_SERVER['REMOTE_ADDR']."','1','".$this->theme_name_db_id."')", mysql_real_escape_string($this->theme_user));
            $result = mysql_query($query);
            if (!$result){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
            $this->log->logNotice(__FUNCTION__ . ' New user created with id ' . mysql_insert_id());
            return TRUE;
        }

        private function user_entry_update()
        {
            $query  = sprintf("UPDATE ".DB_PREFIX."stats SET date=NOW(),ip='".$_SERVER['REMOTE_ADDR']."',hits=hits+1 WHERE id='".$this->theme_user_db_id."' LIMIT 1");
            $result = mysql_query($query);
            if (!$result){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
            $this->log->logNotice(__FUNCTION__ . ' User with id ' . $this->theme_user_db_id . 'updated');
            return TRUE;
        }

        private function serve_image()
        {
            header("Content-type: image/gif");
            header("Content-length: 43");
            $fp = fopen("php://output","wb");
            fwrite($fp,"GIF89a\x01\x00\x01\x00\x80\x00\x00\xFF\xFF",15);
            fwrite($fp,"\xFF\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00",12);
            fwrite($fp,"\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02",12);
            fwrite($fp,"\x44\x01\x00\x3B",4);
            fclose($fp);
        }

        private function database_connect()
        {
            $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
            if(!$con){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
            $select = mysql_select_db(DB_NAME, $con);
            if (!$select){
                $this->log->logError(__FUNCTION__ . ' FAIL: ' . $query . ' BECAUSE: ' . mysql_error());
                return FALSE;
            }
        }       
    }

    $stats = new ThemeStatsTracker();
4

3 に答える 3

1

潜在的なパフォーマンスの問題があるときはいつでも、それがI / Oサブシステムと、通常はデータベースを意味する最新のWebアプリケーションにあることは間違いありません。そのため、パフォーマンスの問題を見つけて修正することができます。これが私の簡単な経験則です。

  1. SELECT *を避け、代わりに実際に必要な列のみをSELECTします。
  2. すべての複雑なクエリでEXPLAINSELECTを使用します。「複雑」とは、1つまたは2つ以上のWHERE句要素を持つクエリ、または複数のテーブルを使用するクエリを意味します。
  3. WHERE、JOIN、ORDER、またはGROUPで使用されるすべての列にインデックスを付ける
  4. 全表スキャンを絶対に必要とせず、UPDATEクエリを含むすべてのクエリでLIMIT句を使用します。

これらは、クエリステートメントに適用できる一般的な原則です。

上記のコードの詳細については、スクリプトの開始時にサーバーを接続してdbを1回選択します。接続と選択は、事実上グローバルな範囲です。close-connectionステートメントを削除します。PHPガベージコレクターがそれを行います。

query()関数を読みたいと思うかもしれません。ほとんどのデータベース関数は値を返します。通常はリソースであるか、失敗するとFALSEを返します。スクリプトはこれらの値をテストし、動作を処理する必要があります。MySQLはブラックボックスではありません。それはあなたのコントロールの及ばない理由で失敗する可能性があり、失敗するでしょう。その場合は、エラーをログに記録してアラートを発生させます。

$slugや$logなどの保護されたクラスプロパティを使用して、これをオブジェクト指向表記で書き直すことを検討してください。これは、カプセル化を破壊するため、混乱への確実なパスであるグローバルステートメントの使用を回避するのに役立ちます。

HTH、〜レイ

于 2012-12-27T20:04:10.730 に答える
0

最適化クラブのルール:

  1. 最適化クラブの最初のルールは、最適化しないことです
  2. 最適化クラブの2番目のルールは、測定せずに最適化しないことです。
  3. アプリが基盤となるトランスポートプロトコルよりも高速に実行されている場合、最適化は終了しています。
  4. 一度に1つの要因。
  5. マーケットロイドもマーケットロイドスケジュールもありません。
  6. テストは必要な限り続行されます。
  7. これがOptimizationClubでの最初の夜である場合は、テストケースを作成する必要があります。

最も重要なルールは#1です。コードが遅いことがわからない場合は、スピードを上げようとしないでください。次に、#2の場合、速度を上げる必要があると思われる場合は、速度が遅いことを測定する必要があります。print microtime()これは、コード全体に呼び出しを入れてコードの個々のチャンクの実行にかかる時間を確認するようなローテクな場合もあれば、 XDebugなどのプロファイリングツールを使用して、コードのどの行の実行にかかる時間を正確に検出する場合もあります。

何をするにしても、動作するコードを使用せずに、コードを高速化するためにコードを叩き始めてください。

(そして、あなたの質問とは関係なく、安全性と使いやすさのためにパラメーター化されたクエリを使用する必要があります:http: //bobby-tables.com/php.htmlに例があります)

于 2012-12-29T17:51:36.703 に答える
0

比較のために、OOP 表記を使用してトラッカーを次のように記述します。これをテストしたことはありませんが、かなり正しいようです。また、PHP には、エラーや通知をログに記録する組み込み関数があります。http://php.net/manual/en/function.error-log.php

<?php // RAY_temp_ckdt.php
error_reporting(E_ALL);

/** MySQL Database CONSTANT DEFINITIONS */
require_once( __DIR__ . '/inc/database.php');

/** Klogger Log Framework*/
require_once( __DIR__ . '/lib/KLogger.php');
$log = KLogger::instance(dirname(__FILE__).'/log/', KLogger::DEBUG);



Class Tracker
{
    protected $return, $slug, $user, $theme_id, $account_id;
    public function __construct($log)
    {
        $this->return = TRUE;
        $this->log    = $log;
        $con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
        if(!$con){
            $this->log->logError('DB FAIL: ' . mysql_error());
        }
        $select = mysql_select_db(DB_NAME, $con);
        if (!$select){
            $this->log->logError('DB FAIL: ' . mysql_error());
            return FALSE;
        }
        $uri = explode(DIRECTORY_SEPARATOR, $_SERVER['REQUEST_URI']);
        $this->slug = (!empty($uri[1])) ? $uri[1] : NULL;
        $this->user = (!empty($uri[2])) ? $uri[2] : NULL;

        if(empty($this->slug) || !empty($this->user)){
            $this->log->logError(__FUNCTION__ . ": Bad request");
            return FALSE;
        }
        $the_slug = validate_slug($this->slug);
        $the_user = account_exists($this->user);

        if($the_slug){
            if($the_user){
                update_entry();
            }else{
                create_entry();
            }
        }
        return $this->return;
    }

    protected function validate_slug(){
        $query  = sprintf("SELECT id FROM ".DB_PREFIX."themes WHERE slug='%s' LIMIT 1", mysql_real_escape_string($this->slug));
        $result = mysql_query($query);
        if (!$result){
            $this->log->logError(__FUNCTION__ . "FAIL: $query BECAUSE: " . mysql_error());
            $this->return = FALSE;
            return FALSE;
        }
        if(mysql_num_rows($result)==0){
            $this->log->logNotice(__FUNCTION__ . ": Slug $this->slug not found");
            $this->return = FALSE;
            return FALSE;
        }else{
            $this->theme_id = mysql_result($result,0);
            $this->return = TRUE;
            return TRUE;
        }
    }

    protected function account_exists(){
        $query  = sprintf("SELECT id FROM ".DB_PREFIX."stats WHERE account='%s' LIMIT 1", mysql_real_escape_string($this->user));
        $result = mysql_query($query);
        if (!$result){
            $this->log->logError(__FUNCTION__ . "FAIL: $query BECAUSE: " . mysql_error());
            $this->return = FALSE;
            return FALSE;
        }
        if(mysql_num_rows($result)==0){
            $this->log->logNotice(__FUNCTION__ . ": Account $this->user not found");
            $this->return = FALSE;
            return FALSE;
        }else{
            $this->account_id = mysql_result($result,0);
            $this->return = TRUE;
            return TRUE;
        }
    }

    protected function create_entry(){
        $query  = sprintf("INSERT INTO ".DB_PREFIX."stats (id,active,account,date,ip,hits,theme) VALUES ('','1','%s',NOW(),'".$_SERVER['REMOTE_ADDR']."','1','".$theme_id."')", mysql_real_escape_string($this->user));
        $result = mysql_query($query);
        if (!$result){
            $this->log->logError(__FUNCTION__ . "FAIL: $query BECAUSE: " . mysql_error());
            $this->return = FALSE;
            return FALSE;
        }

        $this->log->logNotice(__FUNCTION__ . ': Account created with id '.mysql_insert_id() );
        $this->return = TRUE;
        return TRUE;
    }

    public function update_entry(){
        $query  = sprintf("UPDATE ".DB_PREFIX."stats SET date=NOW(),ip='".$_SERVER['REMOTE_ADDR']."',hits=hits+1 WHERE id='".$this->account_id."' LIMIT 1");
        $result = mysql_query($query);
        if (!$result){
            $this->log->logError(__FUNCTION__ . "FAIL: $query BECAUSE: " . mysql_error());
            $this->return = FALSE;
            return FALSE;
        }

        $this->log->logNotice(__FUNCTION__ . ': Entry with id '.$account_id.' is updated.' );
        $this->return = TRUE;
        return TRUE;
    }
} // END CLASS TRACKER

// TRACK THIS REQUEST
$x = new Tracker($log);
于 2012-12-27T20:58:08.313 に答える