Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:php7.2 create_function deprecated #45

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 30 additions & 198 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,210 +1,42 @@

#说明
* readme: https://github.com/luofei614/SocketLog

SocketLog适合Ajax调试和API调试, 举一个常见的场景,用SocketLog来做微信调试, 我们在做微信API开发的时候,如果API有bug,微信只提示“改公众账号暂时无法提供服务,请稍候再试” ,我们根本不知道API出来什么问题。 有了SocketLog就不一样了, 我们可以知道微信给API传递了哪些参数, 程序有错误我们也能看见错误信息(下方有张图片,可能加载慢,请耐心等待一下)
* composer require "jason-gao/socketlog:v2.2.2"

![微信调试](https://raw.githubusercontent.com/luofei614/SocketLog/master/screenshots/weixin.png)
* 2种方法使用slog

```

* 正在运行的API有bug,不能var_dump进行调试,因为会影响client的调用。 将日志写到文件,查看也不方便,特别是带调用栈或大数据结构的文件日志,查看日志十分困难。 这时候用SocketLog最好,SocketLog通过websocket将调试日志打印到浏览器的console中。你还可以用它来分析开源程序,分析SQL性能,结合taint分析程序漏洞。
* Chrome插件安装: https://chrome.google.com/webstore/detail/socketlog/apkmbfpihjhongonfcgdagliaglghcod (如果不能正常访问这个页面,你可以用下面手动安装的方法进行安装)
* 目录结构:
* chrome 目录是 chrome插件的源代码
* chrome.crx 文件是chrome插件的安装包, 如果你无法从chrome应用商店安装,可进行手动安装, 浏览器地址栏输入并打开: chrome://extensions/ ,然后将chrome.crx拖入即可安装。
* php 目录下的SocketLog.class.php是发送日志的类库,我们在发送日志的时候,需要载入这个类库然后调用函数slog即可。
* 效果展示: 我们在浏览网站的时候在浏览器console中就知道程序做了什么,这对于二次开发产品十分有用。 下面效果图在console中打印出浏览discuz程序时,执行了哪些sql语句, 以及执行sql语句的调用栈。程序的warning,notice等错误信息也可以打到console中。
![enter image description here][1]
require __ROOT__.'/vendor/autoload.php';

#使用方法
* 首先,请在chrome浏览器上安装好插件。
* 安装服务端`npm install -g socketlog-server` , 运行命令 `socketlog-server` 即可启动服务。 将会在本地起一个websocket服务 ,监听端口是1229 。 如果想服务后台运行: `socketlog-server > /dev/null &` 我们提供公用的服务端,需要去申请client_id : http://slog.thinkphp.cn/
* 如果你的服务器有防火墙,请开启1229和1116两个端口,这两个端口是socketlog要使用的。
* 在自己的程序中发送日志:
\SocketLog\Slog::config(array(
'host'=>'192.168.5.188',//websocket服务器地址,默认localhost
'optimize'=>true,//是否显示利于优化的参数,如果运行时间,消耗内存等,默认为false
'show_included_files'=>true,//是否显示本次程序运行加载了哪些文件,默认为false
'error_handler'=>true,//是否接管程序错误,将程序错误显示在console中,默认为false
'force_client_id'=>'',//日志强制记录到配置的client_id,默认为空
'allow_client_ids'=>array(123)//限制允许读取日志的client_id,默认为空,表示所有人都可以获得日志。
));

<?php
include './php/slog.function.php';
slog('hello world');
?>
slog(array(
'host'=>'192.168.5.188',//websocket服务器地址,默认localhost
'optimize'=>true,//是否显示利于优化的参数,如果运行时间,消耗内存等,默认为false
'show_included_files'=>true,//是否显示本次程序运行加载了哪些文件,默认为false
'error_handler'=>true,//是否接管程序错误,将程序错误显示在console中,默认为false
'force_client_id'=>'',//日志强制记录到配置的client_id,默认为空
'allow_client_ids'=>array(123)//限制允许读取日志的client_id,默认为空,表示所有人都可以获得日志。
),'config');


```

* 启动服务端的node index.js服务
* 安装chrome插件配置ws连接到node服务

* 用slog函数发送日志, 支持多种日志类型:
* 可以开始进行调试了

slog('msg','log'); //一般日志
slog('msg','error'); //错误日志
slog('msg','info'); //信息日志
slog('msg','warn'); //警告日志
slog('msg','trace');// 输入日志同时会打出调用栈
slog('msg','alert');//将日志以alert方式弹出
slog('msg','log','color:red;font-size:20px;');//自定义日志的样式,第三个参数为css样式
* 20180212-添加错误级别控制
* 默认 define('__ERROR_HANDLE_LEVEL_SOCKETLOG__', E_ALL);
* 项目入口文件定义错误级别define('__ERROR_HANDLE_LEVEL_SOCKETLOG__', E_ALL ^ E_WARNING ^E_NOTICE);

* 通过上面例子可以看出, slog函数支持三个参数:
* 第一个参数是日志内容,日志内容不光能支持字符串哟,大家如果传递数组,对象等一样可以打印到console中。
* 第二个参数是日志类型,可选,如果没有指定日志类型默认类型为log, 第三个参数是自定样式,在这里写上你自定义css样式即可。

##配置
* 在载入slog.function.php文件后,还可以对SocketLog进行一些配置。
* 例如:我们如果想将程序的报错信息页输出到console,可以配置

<?php
include './php/slog.function.php';
slog(array(
'error_handler'=>true
),'config');
echo notice;//制造一个notice报错
slog('这里是输出的一般日志');
?>
* 配置SocketLog也是用slog函数, 第一个参数传递配置项的数组,第二个参数设置为config
* 还支持其他配置项

<?php
include './php/slog.function.php';
slog(array(
'enable'=>true,//是否打印日志的开关
'host'=>'localhost',//websocket服务器地址,默认localhost
'optimize'=>false,//是否显示利于优化的参数,如果运行时间,消耗内存等,默认为false
'show_included_files'=>false,//是否显示本次程序运行加载了哪些文件,默认为false
'error_handler'=>false,//是否接管程序错误,将程序错误显示在console中,默认为false
'force_client_id'=>'',//日志强制记录到配置的client_id,默认为空
'allow_client_ids'=>array()////限制允许读取日志的client_id,默认为空,表示所有人都可以获得日志。
)
,'config');
?>
* 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是你任意指定的字符串。
![enter image description here][2]
* 设置client_id后能实现以下功能:

* 1,配置allow_client_ids 配置项,让指定的浏览器才能获得日志,这样就可以把调试代码带上线。 普通用户访问不会触发调试,不会发送日志。 开发人员访问就能看的调试日志, 这样利于找线上bug。 Client_ID 建议设置为姓名拼命加上随机字符串,这样如果有员工离职可以将其对应的client_id从配置项allow_client_ids中移除。 client_id除了姓名拼音,加上随机字符串的目的,以防别人根据你公司员工姓名猜测出client_id,获取线上的调试日志。
* 设置allow_client_ids示例代码:

slog(array(
'allow_client_ids'=>array('luofei_zfH5NbLn','easy_DJq0z80H')
),'set_config')

* 2, 设置force_client_id配置项,让后台脚本也能输出日志到chrome。 网站有可能用了队列,一些业务逻辑通过后台脚本处理, 如果后台脚本需要调试,你也可以将日志打印到浏览器的console中, 当然后台脚本不和浏览器接触,不知道当前触发程序的是哪个浏览器,所以我们需要强制将日志打印到指定client_id的浏览器上面。 我们在后台脚本中使用SocketLog时设置force_client_id 配置项指定要强制输出浏览器的client_id 即可。
* 示例代码:

<?php
include './php/slog.function.php';
slog(array(
'force_client_id'=>'luofei_zfH5NbLn'
),'config');
slog('test'); `

##支持composer

* 使用composer安装命令 `composer require luofei614/socketlog`

* 直接调用静态方法

<?php
require './vendor/autoload.php';
use think\org\Slog
//配置socketlog
Slog::config(array(
'enable'=>true,//是否打印日志的开关
'host'=>'localhost',//websocket服务器地址,默认localhost
'optimize'=>false,//是否显示利于优化的参数,如果运行时间,消耗内存等,默认为false
'show_included_files'=>false,//是否显示本次程序运行加载了哪些文件,默认为false
'error_handler'=>false,//是否接管程序错误,将程序错误显示在console中,默认为false
'force_client_id'=>'',//日志强制记录到配置的client_id,默认为空
'allow_client_ids'=>array()////限制允许读取日志的client_id,默认为空,表示所有人都可以获得日志。
));
Slog::log('log'); //一般日志
Slog::error('msg'); //错误日志
Slog::info('msg'); //信息日志
Slog::warn('msg'); //警告日志
Slog::trace('msg');// 输入日志同时会打出调用栈
Slog::alert('msg');//将日志以alert方式弹出
Slog::log('msg','color:red;font-size:20px;');//自定义日志的样式,第三个参数为css样式

##支持ThinkPHP
ThinkPHP5后, 在框架层集成了SocketLog ,只需要设置配置即可用

##对数据库进行调试
* SocketLog还能对sql语句进行调试,自动对sql语句进行explain分析,显示出有性能问题的sql语句。 如下图所示。
![enter image description here][3]
* 图中显示出了三条sql语句 , 第一条sql语句字体较大,是因为它又性能问题, 在sql语句的后台已经标注Using filesort。 我们还可以点击某个sql语句看到sql执行的调用栈,清楚的知道sql语句是如何被执行的,方便我们分析程序、方便做开源程序的二次开发。图中第三条sql语句为被点开的状态。
* 用slog函数打印sql语句是,第二个参数传递为mysql或mysqli的对象即可。 示例代码:


$link=mysql_connect( 'localhost:3306' , 'root' , '123456' , true ) ;
mysql_select_db('kuaijianli',$link);
$sql="SELECT * FROM `user`";
slog($sql,$link);
后面会以OneThink为实例再对数据库调试进行演示。

通过上面的方法,socketlog还能自动为你检测没有where语句的sql操作,然后自动提示你。

* 注意,有时候在数据比较少的情况下,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 。


$headers=array();
if(isset($_SERVER['HTTP_USER_AGENT']))
{
$headers[]='User-Agent: '.$_SERVER['HTTP_USER_AGENT'];
}
if(isset($_SERVER['HTTP_SOCKETLOG']))
{
$headers[]='Socketlog: '.$_SERVER['HTTP_SOCKETLOG'];
}
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);

##区分正式和开发环境

进入chrome浏览器的“工具”-->“扩展程序” , 点击SocketLog的“选项”进行设置。


##分析开源程序

有了SocketLog,我们能很方便的分析开源程序,下面以OneThink为例, 大家可以在 http://www.topthink.com/topic/2228.html 下载最新的OneThink程序。 安装好OneThink后,按下面步骤增加SocketLog程序。

* 将SocketLog.class.php复制到OneThink的程序目录中,你如果没有想好将文件放到哪个子文件夹,暂且放到根目录吧。
* 编辑入口文件index.php, 再代码的最前面加载slog.function.php ,并设置SocketLog



<?php
include './slog.function.php';
slog(array(
'error_handler'=>true,
'optimize'=>true,
'show_included_files'=>true
),'config');


- 编辑ThinkPHP/Library/Think/Db/Driver.class.php 文件,在这个类中的execute 方法为一个执行sql语句的方法,增加代码:


slog($this->queryStr,$this->_linkID);

- 类中的query方法也是一个执行sql语句的地方, 同样需要增加上面的代码

- 然后浏览网站看看效果:

![enter image description here][4]

通过console的日志,访问每一页我们都知道程序干了什么,是一件很爽的事情。

- 提示:另一种更简单的方法,因为OneThink每次执行完sql语句都会调用$this->debug, 所以我们可以把slog($this->queryStr,$this->_linkID); 直接写在 Db.class.php文件的debug方法中。 这样不管是mysqli还是mysql驱动都有效。

## 视频教程
[http://edu.normalcoder.com/course/941](http://edu.normalcoder.com/course/941)

感谢猿团的张盛翔(诺墨)提供教程。

##About Me
* Author: @luofei614 新浪微博:http://weibo.com/luofei614
* 优伯立信创始人,ThinkPHP核心开发者之一,待过新浪云计算


[1]: https://github.com/luofei614/SocketLog/raw/master/screenshots/discuz.png
[2]: https://github.com/luofei614/SocketLog/raw/master/screenshots/socketlog.png
[3]: https://github.com/luofei614/SocketLog/raw/master/screenshots/sql.png
[4]: https://github.com/luofei614/SocketLog/raw/master/screenshots/onethink.png
27 changes: 18 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
{
"name": "luofei614/socketlog",
"name": "jason-gao/socketlog",
"description": "debug tool for api , ajax,wechat ,v2.2",
"keywords": ["SocketLog", "slog", "api"],
"keywords": [
"SocketLog",
"slog",
"api"
],
"license": "MIT",
"authors": [
{
"name": "luofei",
"email": "upfy@qq.com"
"name": "jason-gao",
"email": "3048789891@qq.com"
}
],
"require":{
"require": {
"php": ">=5.4.0"
},
"autoload": {
"files": [
"php/slog.function.php"
],
"psr-4": {
"think\\org\\": "php/"
"SocketLog\\": "php/"
}
},
"archive" : {
"exclude":["!/php"]
"archive": {
"exclude": [
"!/php"
]
},
"minimum-stability": "dev"
"minimum-stability": "dev"
}
2 changes: 2 additions & 0 deletions demo.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@
$sql="DELETE * FROM `uxxxser`";
slog($sql,$link);
*/


13 changes: 9 additions & 4 deletions php/slog.function.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
<?php
require 'slog.php';
use think\org\Slog;
use SocketLog\Slog;

function slog($log,$type='log',$css='')
{
if(is_string($type))
{
$type=preg_replace_callback('/_([a-zA-Z])/',create_function('$matches', 'return strtoupper($matches[1]);'),$type);
if(method_exists('\think\org\Slog',$type) || in_array($type,Slog::$log_types))
$type=preg_replace_callback('/_([a-zA-Z])/',
function ($matches){
return strtoupper($matches[1]);
},
$type);
if(method_exists('\SocketLog\Slog',$type) || in_array($type,Slog::$log_types))
{
return call_user_func(array('\think\org\Slog',$type),$log,$css);
return call_user_func(array('\SocketLog\Slog',$type),$log,$css);
}
}

Expand Down
6 changes: 5 additions & 1 deletion php/slog.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
* github: https://github.com/luofei614/SocketLog
* @author luofei614<weibo.com/luofei614>
*/
namespace think\org;
namespace SocketLog;

if(!defined('__ERROR_HANDLE_LEVEL_SOCKETLOG__')) define('__ERROR_HANDLE_LEVEL_SOCKETLOG__', E_ALL);

class Slog
{
public static $start_time=0;
Expand Down Expand Up @@ -209,6 +212,7 @@ public static function registerErrorHandler()

public static function error_handler($errno, $errstr, $errfile, $errline)
{
if ( ($errno & __ERROR_HANDLE_LEVEL_SOCKETLOG__) !== $errno) return;
switch($errno){
case E_WARNING: $severity = 'E_WARNING'; break;
case E_NOTICE: $severity = 'E_NOTICE'; break;
Expand Down