經過SocketLog快速分析php程序

轉載自http://www.thinkphp.cn/topic/10846.htmlphp

 

正在運行的API有bug,不能var_dump進行調試,由於會影響client的調用。這時候用SocketLog最好,SocketLog經過websocket將調試日誌打印到瀏覽器的console中。你還能夠用它來分析開源程序,分析SQL性能,結合taint分析程序漏洞。 

我將演示如何用SocketLog分析php程序, SocketLog的項目地址:https://github.com/luofei614/SocketLog 

#說明
* SocketLog方便API,AJAX的調試,能將日誌經過WebSocket輸出到Chrome瀏覽器的console中
* 它能代替ChromePHP、FirePHP等工具,ChromePHP等是經過header通訊,適合AJAX調試,但不適合API調試,並且它們是經過Header通訊,Chrome瀏覽器對傳遞Header大小有限制,日誌若是多了,Chrome瀏覽器就沒法支持。
* 目錄結構:
* chrome 目錄是 chrome插件的源代碼
* chrome.crx 文件是chrome插件的安裝包, 目前插件尚未上架到Chrome App Store, 你們須要手動安裝, 瀏覽器地址欄輸入並打開: chrome://extensions/ ,而後將chrome.crx拖入便可安裝。
* php 目錄是php相關腳本。 SocketLog.server.php 是一個 Websocket服務器, SocketLog.class.php是發送日誌的類庫,咱們在發送日誌的時候,須要載入這個類庫而後調用函數slog便可。
* 效果展現: 咱們在瀏覽網站的時候在瀏覽器console中就知道程序作了什麼,這對於二次開發產品十分有用。 下面效果圖在console中打印出瀏覽discuz程序時,執行了哪些sql語句, 以及執行sql語句的調用棧。程序的warning,notice等錯誤信息也能夠打到console中。



#使用方法
* 首先,請在chrome瀏覽器上安裝好插件。
* 而後,啓用Websocket服務, 在命令行中運行 `php php/SocketLog.server.php` , 將會在本地起一個websocket服務 ,監聽端口是1229 。 若是想服務後臺運行: `nohup php php/SocketLog.server.php > /dev/null &`
* 在本身的程序中發送日誌:css

  1.        <?php
  2.         include './php/SocketLog.class.php';
  3.         slog('hello world');
  4.         ?>
複製代碼

* 用slog函數發送日誌, 支持多種日誌類型:html

  1.         slog('msg','log');  //通常日誌
  2.         slog('msg','error'); //錯誤日誌
  3.         slog('msg','info'); //信息日誌
  4.         slog('msg','warn'); //警告日誌
  5.         slog('msg','trace');// 輸入日誌同時會打出調用棧
  6.         slog('msg','alert');//將日誌以alert方式彈出
  7.         slog('msg','log','color:red;font-size:20px;');//自定義日誌的樣式,第三個參數爲css樣式
複製代碼

* 經過上面例子能夠看出, slog函數支持三個參數:
* 第一個參數是日誌內容,日誌內容不光能支持字符串喲,你們若是傳遞數組,對象等同樣能夠打印到console中。
* 第二個參數是日誌類型,可選,若是沒有指定日誌類型默認類型爲log, 第三個參數是自定樣式,在這裏寫上你自定義css樣式便可。

##配置
* 在載入SocketLog.class.php文件後,還能夠對SocketLog進行一些配置。
* 例如:咱們若是想將程序的報錯信息頁輸出到console,能夠配置mysql

  1.         <?php
  2.         include './php/SocketLog.class.php';
  3.         slog(array(
  4.         'error_handler'=>true
  5.         ),'set_config');
  6.         echo notice;//製造一個notice報錯
  7.         slog('這裏是輸出的通常日誌');
  8.         ?>
複製代碼

* 配置SocketLog也是用slog函數, 第一個參數傳遞配置項的數組,第二個參數設置爲set_config
* 還支持其餘配置項git

  1.         <?php
  2.         include './php/SocketLog.class.php';
  3.         slog(array(
  4.         'host'=>'localhost',//websocket服務器地址,默認localhost
  5.         'port'=>'1229',//websocket服務器端口,默認端口是1229
  6.         'optimize'=>false,//是否顯示利於優化的參數,若是運行時間,消耗內存等,默認爲false
  7.         'show_included_files'=>false,//是否顯示本次程序運行加載了哪些文件,默認爲false
  8.         'error_handler'=>false,//是否接管程序錯誤,將程序錯誤顯示在console中,默認爲false
  9.         'force_client_id'=>'',//日誌強制記錄到配置的client_id,默認爲空
  10.         'allow_client_ids'=>array()////限制容許讀取日誌的client_id,默認爲空,表示全部人均可以得到日誌。
  11.         )
  12.         ,'set_config');
  13.         ?>
複製代碼

* optimize 參數若是設置爲true, 能夠在日誌中看見利於優化參數,如:`[運行時間:0.081346035003662s][吞吐率:12.29req/s][內存消耗:346,910.45kb]` 
* show_included_files 設置爲true,能顯示出程序運行時加載了哪些文件,好比咱們在分析開源程序時,若是不知道模板文件在那裏, 每每看一下加載文件列表就知道模板文件在哪裏了。
* error_handler 設置爲true,能接管報錯,將錯誤信息顯示到瀏覽器console, 在開發程序時notice報錯能讓咱們快速發現bug,可是有些notice報錯是不可避免的,若是讓他們顯示在頁面中會影響網頁的正常佈局,那麼就設置error_handler,讓它顯示在瀏覽器console中吧。 另外此功能結合php taint也是極佳的。 taint能自動檢測出xss,sql注入, 若是隻用php taint, 它warning報錯只告訴了變量輸出的地方,並不知道變量在那裏賦值、怎麼傳遞。經過SocketLog, 能看到調用棧,輕鬆對有問題變量進行跟蹤。 更多taint的信息:http://www.laruence.com/2012/02/14/2544.html 
* 設置client_id: 在chrome瀏覽器中,能夠設置插件的Client_ID ,Client_ID是你任意指定的字符串。

* 設置client_id後能實現如下功能:

* 1,配置allow_client_ids 配置項,讓指定的瀏覽器才能得到日誌,這樣就能夠把調試代碼帶上線。 普通用戶訪問不會觸發調試,不會發送日誌。 開發人員訪問就能看的調試日誌, 這樣利於找線上bug。 Client_ID 建議設置爲姓名拼命加上隨機字符串,這樣若是有員工離職能夠將其對應的client_id從配置項allow_client_ids中移除。 client_id除了姓名拼音,加上隨機字符串的目的,以防別人根據你公司員工姓名猜想出client_id,獲取線上的調試日誌。
* 設置allow_client_ids示例代碼:github

  1.         slog(array(
  2.         'allow_client_ids'=>array('luofei_zfH5NbLn','easy_DJq0z80H')
  3.         ),'set_config')
複製代碼

* 2, 設置force_client_id配置項,讓後臺腳本也能輸出日誌到chrome。 網站有可能用了隊列,一些業務邏輯經過後臺腳本處理, 若是後臺腳本須要調試,你也能夠將日誌打印到瀏覽器的console中, 固然後臺腳本不和瀏覽器接觸,不知道當前觸發程序的是哪一個瀏覽器,因此咱們須要強制將日誌打印到指定client_id的瀏覽器上面。 咱們在後臺腳本中使用SocketLog時設置force_client_id 配置項指定要強制輸出瀏覽器的client_id 便可。
* 示例代碼:web

  1.         <?php
  2.         include './php/SocketLog.class.php';
  3.         slog(array(
  4.         'force_client_id'=>'luofei_zfH5NbLn'
  5.         ),'set_config');
  6.         slog('test'); `
複製代碼

##對數據庫進行調試
* SocketLog還能對sql語句進行調試,自動對sql語句進行explain分析,顯示出有性能問題的sql語句。 以下圖所示。 

* 圖中顯示出了三條sql語句 , 第一條sql語句字體較大,是由於它又性能問題, 在sql語句的後臺已經標註Using filesort。 咱們還能夠點擊某個sql語句看到sql執行的調用棧,清楚的知道sql語句是如何被執行的,方便咱們分析程序、方便作開源程序的二次開發。圖中第三條sql語句爲被點開的狀態。
* 用slog函數打印sql語句是,第二個參數傳遞爲mysql或mysqli的對象便可。 示例代碼:sql

  1.         $link=mysql_connect( 'localhost:3306' , 'root' , '123456' , true ) ;
  2.         mysql_select_db('kuaijianli',$link);
  3.         $sql="SELECT * FROM `user`";
  4.         slog($sql,$link);
複製代碼

後面會以OneThink爲實例再對數據庫調試進行演示。

* 注意,有時候在數據比較少的狀況下,mysql查詢不會使用索引,explain也會提示Using filesort等性能問題, 其實這時候並非真正有性能問題, 你須要自行進行判斷,或者增長更多的數據再測試。

##對API進行調試
網站調用了API ,如何將API程序的調試信息也打印到瀏覽器的console中? 前面咱們講了一個配置 force_client_id, 能將日誌強制記錄到指定的瀏覽器。 用這種方式也能夠將API的調試信息打印到console中,可是force_client_id 只能指定一個client_id, 若是咱們的開發環境是多人共用,這種方式就不方便了。
其實只要將瀏覽器傳遞給網站的User-Agent 再傳遞給API, API程序中不用配置force_client_id, 也能識別當前訪問程序的瀏覽器, 將日誌打印到當前訪問程序的瀏覽器, 咱們須要將SDK代碼稍微作一下修改。 調用API的SDK,通常是用curl寫的,增長下面代碼能夠將瀏覽器的User-Agent傳遞到API 。 chrome

  1.         $headers=array(
  2.                 'User-Agent: '.$_SERVER['HTTP_USER_AGENT']
  3.             );
  4.         curl_setopt($ch,CURLOPT_HTTPHEADER,$headers); 
複製代碼

##分析開源程序

有了SocketLog,咱們能很方便的分析開源程序,下面以OneThink爲例, 你們能夠在 http://www.onethink.cn/ 下載最新的OneThink程序。 安裝好OneThink後,按下面步驟增長SocketLog程序。 

* 將SocketLog.class.php複製到OneThink的程序目錄中,你若是沒有想好將文件放到哪一個子文件夾,暫且放到根目錄吧。 
* 編輯入口文件index.php, 再代碼的最前面加載SocketLog.class.php ,並設置SocketLog

thinkphp

  1.         <?php
  2.             include './SocketLog.class.php';
  3.             slog(array(
  4.              'error_handler'=>true,
  5.              'optimize'=>true,
  6.              'show_included_files'=>true
  7.             ),'set_config');
複製代碼

- 編輯ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php 文件, 若是你用的數據庫驅動類型不是mysqli,而是mysql,那麼請打開Mysql.class.php, 找到執行sql語句的地方, 這個類中得execute 方法爲一個執行sql語句的方法,大約在119行處,增長代碼:

  1.         slog($this->queryStr,$this->_linkID);
複製代碼

- 類中的query方法也是一個執行sql語句的地方, 一樣須要增長上面的代碼, 大約在92行增長slog($this->queryStr,$this->_linkID);

- 而後瀏覽網站看看效果: 
經過console的日誌,訪問每一頁咱們都知道程序幹了什麼,是一件很爽的事情。- 提示:另外一種更簡單的方法,由於OneThink每次執行完sql語句都會調用$this->debug, 因此咱們能夠把slog($this->queryStr,$this->_linkID); 直接寫在 Db.class.php文件的debug方法中。 這樣不論是mysqli仍是mysql驅動都有效。

相關文章
相關標籤/搜索