Completed
Push — 6.0 ( cb8a0b...bb9f45 )
by yun
06:00
created

Socket::getClientArg()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 14
c 1
b 0
f 0
nc 12
nop 1
dl 0
loc 27
ccs 0
cts 15
cp 0
crap 42
rs 9.2222
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: luofei614 <weibo.com/luofei614>
10
// +----------------------------------------------------------------------
11
12
namespace think\log\driver;
13
14
use think\contract\LogHandlerInterface;
15
16
/**
17
 * github: https://github.com/luofei614/SocketLog
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
18
 * @author luofei614<weibo.com/luofei614>
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
19
 */
20
class Socket implements LogHandlerInterface
21
{
22
    public $port = 1116; //SocketLog 服务的http的端口号
23
24
    protected $config = [
25
        // socket服务器地址
26
        'host'                => 'localhost',
27
        // 是否显示加载的文件列表
28
        'show_included_files' => false,
29
        // 日志强制记录到配置的client_id
30
        'force_client_ids'    => [],
31
        // 限制允许读取日志的client_id
32
        'allow_client_ids'    => [],
33
        // 调试开关
34
        'debug'               => false,
35
    ];
36
37
    protected $css = [
38
        'sql'      => 'color:#009bb4;',
39
        'sql_warn' => 'color:#009bb4;font-size:14px;',
40
        'error'    => 'color:#f4006b;font-size:14px;',
41
        'page'     => 'color:#40e2ff;background:#171717;',
42
        'big'      => 'font-size:20px;color:red;',
43
    ];
44
45
    protected $allowForceClientIds = []; //配置强制推送且被授权的client_id
46
47
    /**
48
     * 架构函数
49
     * @access public
50
     * @param array $config 缓存参数
51
     */
52
    public function __construct(array $config = [])
53
    {
54
        if (!empty($config)) {
55
            $this->config = array_merge($this->config, $config);
56
        }
57
    }
58
59
    /**
60
     * 调试输出接口
61
     * @access public
62
     * @param array $log 日志信息
63
     * @return bool
64
     */
65
    public function save(array $log = []): bool
66
    {
67
        if (!$this->check()) {
68
            return false;
69
        }
70
71
        $trace = [];
72
73
        if ($this->config['debug']) {
74
75
            if (isset($_SERVER['HTTP_HOST'])) {
76
                $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
77
            } else {
78
                $current_uri = 'cmd:' . implode(' ', $_SERVER['argv']);
79
            }
80
81
            // 基本信息
82
            $trace[] = [
83
                'type' => 'group',
84
                'msg'  => $current_uri,
85
                'css'  => $this->css['page'],
86
            ];
87
        }
88
89
        foreach ($log as $type => $val) {
90
            $trace[] = [
91
                'type' => 'groupCollapsed',
92
                'msg'  => '[ ' . $type . ' ]',
93
                'css'  => isset($this->css[$type]) ? $this->css[$type] : '',
94
            ];
95
96
            foreach ($val as $msg) {
97
                if (!is_string($msg)) {
98
                    $msg = var_export($msg, true);
99
                }
100
                $trace[] = [
101
                    'type' => 'log',
102
                    'msg'  => $msg,
103
                    'css'  => '',
104
                ];
105
            }
106
107
            $trace[] = [
108
                'type' => 'groupEnd',
109
                'msg'  => '',
110
                'css'  => '',
111
            ];
112
        }
113
114
        if ($this->config['show_included_files']) {
115
            $trace[] = [
116
                'type' => 'groupCollapsed',
117
                'msg'  => '[ file ]',
118
                'css'  => '',
119
            ];
120
121
            $trace[] = [
122
                'type' => 'log',
123
                'msg'  => implode("\n", get_included_files()),
124
                'css'  => '',
125
            ];
126
127
            $trace[] = [
128
                'type' => 'groupEnd',
129
                'msg'  => '',
130
                'css'  => '',
131
            ];
132
        }
133
134
        $trace[] = [
135
            'type' => 'groupEnd',
136
            'msg'  => '',
137
            'css'  => '',
138
        ];
139
140
        $tabid = $this->getClientArg('tabid');
141
142
        if (!$client_id = $this->getClientArg('client_id')) {
143
            $client_id = '';
144
        }
145
146
        if (!empty($this->allowForceClientIds)) {
147
            //强制推送到多个client_id
148
            foreach ($this->allowForceClientIds as $force_client_id) {
149
                $client_id = $force_client_id;
150
                $this->sendToClient($tabid, $client_id, $trace, $force_client_id);
151
            }
152
        } else {
153
            $this->sendToClient($tabid, $client_id, $trace, '');
154
        }
155
156
        return true;
157
    }
158
159
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $tabid should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $client_id should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $logs should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $force_client_id should have a doc-comment as per coding-style.
Loading history...
160
     * 发送给指定客户端
161
     * @access protected
162
     * @param  $tabid
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
163
     * @param  $client_id
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
164
     * @param  $logs
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
165
     * @param  $force_client_id
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
166
     * @author Zjmainstay
167
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
168
    protected function sendToClient($tabid, $client_id, $logs, $force_client_id)
169
    {
170
        $logs = [
171
            'tabid'           => $tabid,
172
            'client_id'       => $client_id,
173
            'logs'            => $logs,
174
            'force_client_id' => $force_client_id,
175
        ];
176
177
        $msg     = @json_encode($logs);
178
        $address = '/' . $client_id; //将client_id作为地址, server端通过地址判断将日志发布给谁
179
180
        $this->send($this->config['host'], $msg, $address);
181
    }
182
183
    protected function check()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function check()
Loading history...
184
    {
185
        $tabid = $this->getClientArg('tabid');
186
187
        //是否记录日志的检查
188
        if (!$tabid && !$this->config['force_client_ids']) {
189
            return false;
190
        }
191
192
        //用户认证
193
        $allow_client_ids = $this->config['allow_client_ids'];
194
195
        if (!empty($allow_client_ids)) {
196
            //通过数组交集得出授权强制推送的client_id
197
            $this->allowForceClientIds = array_intersect($allow_client_ids, $this->config['force_client_ids']);
198
            if (!$tabid && count($this->allowForceClientIds)) {
199
                return true;
200
            }
201
202
            $client_id = $this->getClientArg('client_id');
203
            if (!in_array($client_id, $allow_client_ids)) {
204
                return false;
205
            }
206
        } else {
207
            $this->allowForceClientIds = $this->config['force_client_ids'];
208
        }
209
210
        return true;
211
    }
212
213
    protected function getClientArg($name)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getClientArg()
Loading history...
214
    {
215
        static $args = [];
216
217
        $key = 'HTTP_USER_AGENT';
218
219
        if (isset($_SERVER['HTTP_SOCKETLOG'])) {
220
            $key = 'HTTP_SOCKETLOG';
221
        }
222
223
        if (!isset($_SERVER[$key])) {
224
            return;
225
        }
226
227
        if (empty($args)) {
228
            if (!preg_match('/SocketLog\((.*?)\)/', $_SERVER[$key], $match)) {
229
                $args = ['tabid' => null];
230
                return;
231
            }
232
            parse_str($match[1], $args);
233
        }
234
235
        if (isset($args[$name])) {
236
            return $args[$name];
237
        }
238
239
        return;
240
    }
241
242
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
243
     * @access protected
244
     * @param string $host    - $host of socket server
245
     * @param string $message - 发送的消息
246
     * @param string $address - 地址
247
     * @return bool
248
     */
249
    protected function send($host, $message = '', $address = '/')
250
    {
251
        $url = 'http://' . $host . ':' . $this->port . $address;
252
        $ch  = curl_init();
253
254
        curl_setopt($ch, CURLOPT_URL, $url);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, $url);
Loading history...
255
        curl_setopt($ch, CURLOPT_POST, true);
256
        curl_setopt($ch, CURLOPT_POSTFIELDS, $message);
257
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
258
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
259
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
260
261
        $headers = [
262
            "Content-Type: application/json;charset=UTF-8",
263
        ];
264
265
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); //设置header
266
267
        return curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

267
        return curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
Bug Best Practice introduced by
The expression return curl_exec($ch) also could return the type string which is incompatible with the documented return type boolean.
Loading history...
268
    }
269
270
}
271