├── .idea
├── .name
├── encodings.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── swoole-game.iml
├── vcs.xml
└── workspace.xml
├── README.md
├── applications
├── Game
│ ├── Chat.php
│ ├── Config
│ │ ├── Db.php
│ │ ├── Server.php
│ │ └── Store.php
│ ├── Game.php
│ ├── Lib
│ │ ├── Autoloader.php
│ │ ├── Context.php
│ │ ├── Db.php
│ │ ├── DbConnection.php
│ │ ├── Store.php
│ │ └── StoreDriver
│ │ │ └── File.php
│ ├── Login.php
│ ├── Pay.php
│ ├── Protocols
│ │ ├── JsonProtocol.php
│ │ ├── TextProtocol.php
│ │ └── WebSocket.php
│ ├── README.md
│ └── Server
│ │ ├── Member.php
│ │ └── Statistic.php
├── Http
│ ├── Config
│ │ ├── Db.php
│ │ ├── Server.php
│ │ └── Store.php
│ ├── Lib
│ │ ├── Autoloader.php
│ │ ├── Context.php
│ │ ├── Db.php
│ │ ├── DbConnection.php
│ │ ├── Store.php
│ │ └── StoreDriver
│ │ │ └── File.php
│ ├── Protocols
│ │ └── JsonProtocol.php
│ ├── Services
│ │ ├── Online.php
│ │ └── Zone.php
│ └── index.php
└── swoole-yaf
│ ├── README.md
│ ├── application
│ ├── Bootstrap.php
│ ├── controllers
│ │ ├── Error.php
│ │ ├── Form.php
│ │ └── Index.php
│ ├── favicon.ico.png
│ ├── library
│ │ └── readme.txt
│ ├── models
│ │ └── Sample.php
│ ├── plugins
│ │ └── Sample.php
│ └── views
│ │ ├── error
│ │ └── error.phtml
│ │ ├── form
│ │ ├── form.phtml
│ │ └── index.phtml
│ │ └── index
│ │ └── index.phtml
│ ├── conf
│ ├── application.ini
│ └── routes.ini
│ ├── server
│ └── server.php
│ └── yaf_classes.php
├── example
├── JsonProtocol.php
├── echo
│ ├── client.php
│ ├── eofClient.php
│ ├── eofServer.php
│ ├── event.php
│ └── server.php
├── http
│ └── index.php
├── member.php
├── mysql
│ ├── async_mysql.php
│ └── mysqlPool.php
├── process
│ └── server.php
├── table
│ ├── get.php
│ └── set.php
├── task
│ ├── client.php
│ └── server.php
├── timer
│ ├── basic.php
│ └── server.php
└── websocket
│ └── server.php
└── swoole-auto-complete-master
├── README.md
├── Swoole.php
└── phpstorm
└── php.jar
/.idea/.name:
--------------------------------------------------------------------------------
1 | swoole-game
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/swoole-game.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | swoole-framework
2 | ================
3 |
4 | swoole基础框架
5 |
--------------------------------------------------------------------------------
/applications/Game/Chat.php:
--------------------------------------------------------------------------------
1 | set(['worker_num' => 4, 'user'=>'www', 'group'=>'www', 'daemonize'=>0]);
14 |
15 | //handshake成功之后回调, 和js的onopen对应
16 | $http->on('open', function($response) {
17 | echo "handshake success" . PHP_EOL;
18 | //print_r($response);
19 | });
20 |
21 | //自定定握手规则,没有设置则用系统内置的(只支持version:13的)
22 | $http->on('handshake', function($request, $response) {
23 | print_r($request);
24 |
25 | if (!isset($request->header['sec-websocket-key'])) {
26 | //'Bad protocol implementation: it is not RFC6455.'
27 | $response->end();
28 | return false;
29 | }
30 |
31 | if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key']) || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))) {
32 | //Header Sec-WebSocket-Key is illegal;
33 | $response->end();
34 | return false;
35 | }
36 |
37 | $headers = array(
38 | 'Upgrade' => 'websocket',
39 | 'Connection' => 'Upgrade',
40 | 'Sec-WebSocket-Accept' => ''. base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)),
41 | 'Sec-WebSocket-Version' => '13',
42 | 'KeedpAlive' => 'off',
43 | );
44 |
45 | foreach($headers as $key => $val) {
46 | $response->header($key, $val);
47 | }
48 | $response->status(101);
49 | $response->end();
50 | });
51 |
52 | $http->on('message', function($response){
53 | var_dump($response);
54 |
55 | $response->message($response->data);
56 | });
57 |
58 | $http->on('request', function ($request, $response) {
59 | var_dump($request);
60 | $response->end("
Hello Swoole. #".rand(1000, 9999)."
");
61 | });
62 |
63 | $http->on('close', function(){
64 | echo "on close" . PHP_EOL;
65 | });
66 |
67 | $http->start();
--------------------------------------------------------------------------------
/applications/Game/Config/Db.php:
--------------------------------------------------------------------------------
1 | select('name,age')->from('user')->where('age>12')->query();
13 | * 等价于
14 | * $user_array = Db::instance('one_demo')->query('SELECT `name`,`age` FROM `one_demo` WHERE `age`>12');
15 | * @var array
16 | */
17 | public static $passport = array(
18 | 'host' => '127.0.0.1',
19 | 'port' => 3306,
20 | 'user' => 'root',
21 | 'password' => '622124',
22 | 'dbname' => 'passport',
23 | 'charset' => 'utf8',
24 | );
25 | }
--------------------------------------------------------------------------------
/applications/Game/Config/Server.php:
--------------------------------------------------------------------------------
1 | 4,
17 | //task worker进程数
18 | 'task_worker_num' => 8,
19 | //设置程序进入后台作为守护进程运行
20 | 'daemonize' => false,
21 | //每个worker进程允许处理的最大任务数
22 | 'max_request' => 10000,
23 | //'heartbeat_check_interval' => 60,
24 | 'dispatch_mode' => 2,
25 | 'debug_mode'=> 1
26 | );
27 |
28 | public static $chat = array(
29 | //Worker进程数
30 | 'worker_num' => 4,
31 | //设置程序进入后台作为守护进程运行
32 | 'daemonize' => false,
33 | //每个worker进程允许处理的最大任务数
34 | 'max_request' => 10000,
35 | //'heartbeat_check_interval' => 60,
36 | 'dispatch_mode' => 2,
37 | 'debug_mode'=> 1
38 | );
39 | }
--------------------------------------------------------------------------------
/applications/Game/Config/Store.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9500);
22 |
23 | //通过配置获取
24 | $this->serv->set(Server::$game);
25 |
26 | //注册Server的事件回调函数
27 | $this->serv->on('Start', array($this, 'onStart'));
28 | $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
29 | $this->serv->on('Connect', array($this, 'onConnect'));
30 | $this->serv->on('Receive', array($this, 'onReceive'));
31 | $this->serv->on('Close', array($this, 'onClose'));
32 |
33 | //绑定任务
34 | $this->serv->on('Task', array($this, 'onTask'));
35 | $this->serv->on('Finish', array($this, 'onFinish'));
36 | $this->serv->start();
37 | }
38 |
39 | //主进程启动
40 | public function onStart($serv) {
41 | echo "Server is Running" . PHP_EOL;
42 |
43 | //管理进程的PID,通过向管理进程发送SIGUSR1信号可实现柔性重启
44 | echo $serv->manager_pid . PHP_EOL;
45 |
46 | //主进程的PID,通过向主进程发送SIGTERM信号可安全关闭服务器
47 | echo $serv->master_pid . PHP_EOL;
48 |
49 | //print_r($serv->stats());
50 |
51 | }
52 |
53 | public function onWorkerStart($serv, $worker_id) {
54 |
55 | }
56 |
57 | public function onConnect($serv, $fd, $from_id ) {}
58 |
59 | /**
60 | * 服务端接收数据
61 | *
62 | * @param $serv swoole_server对象
63 | * @param $fd 连接的描述符
64 | * @param $from_id reactor的id,无用
65 | * @param $data 接收数据
66 | */
67 | public function onReceive(swoole_server $serv, $fd, $from_id, $data) {
68 | //检测数据完整性
69 | if(JsonProtocol::check($data) != 0) {
70 | return;
71 | }
72 |
73 | $data = JsonProtocol::decode($data);
74 |
75 | //接收参数
76 | $class = $data['class'];
77 | $method = $data['method'];
78 | $params = $data['params'];
79 | $startTime = $this->microtimeFloat();
80 |
81 | // 判断类对应文件是否载入
82 | if(!class_exists($class))
83 | {
84 | $include_file = ROOT_DIR . "Server/$class.php";
85 | if(is_file($include_file)) {
86 | require_once $include_file;
87 | }
88 |
89 | if(!class_exists($class)) {
90 | $code = 404;
91 | $msg = "class $class not found";
92 |
93 | $result = array('code'=>$code, 'msg'=>$msg, 'data'=>null);
94 |
95 | $serv->send($fd, JsonProtocol::encode($result));
96 | }
97 | }
98 |
99 | // 调用类的方法
100 | try {
101 | $ret = call_user_func_array(array(new $class, $method), $params);
102 | $code = $ret['code'];
103 | $msg = $ret['msg'];
104 |
105 | // 发送数据给客户端,调用成功,data下标对应的元素即为调用结果
106 | $serv->send($fd, JsonProtocol::encode($ret));
107 | } catch(Exception $e) {
108 | // 发送数据给客户端,发生异常,调用失败
109 | $code = $e->getCode() ? $e->getCode() : 500;
110 | $msg = $e->getMessage();
111 | $result = array('code'=>$code, 'msg'=>$msg, 'data'=>$e);
112 |
113 | $serv->send($fd, JsonProtocol::encode($result));
114 | }
115 |
116 | //请求数据统计,放在task执行
117 | $executionTime = $this->microtimeFloat() - $startTime;
118 | $report = array(
119 | 'class' => $class,
120 | 'method' => $method,
121 | 'params' => json_encode($params),
122 | 'code' => $code,
123 | 'msg' => $msg,
124 | 'execution' => $executionTime,
125 | 'time' => time()
126 | );
127 | $serv->task(json_encode($report));
128 | }
129 |
130 | /**
131 | * @param $serv swoole_server对象
132 | * @param $task_id 任务ID
133 | * @param $from_id 来自于哪个worker进程
134 | * @param $data 任务内容
135 | * @return int
136 | */
137 | public function onTask($serv, $task_id, $from_id, $data) {
138 | $data = json_decode($data, true);
139 | Statistic::report($data);
140 | return 1;
141 | }
142 |
143 | /**
144 | * @param $serv swoole_server对象
145 | * @param $task_id 任务ID
146 | * @param $data 任务结果
147 | */
148 | public function onFinish($serv, $task_id, $data) {
149 | echo "Task {$task_id} finish" . PHP_EOL;
150 | }
151 |
152 | public function onClose($serv, $fd, $from_id ) {
153 | echo "Client {$fd} close connection" . PHP_EOL;
154 | }
155 |
156 | private function microtimeFloat() {
157 | list($usec, $sec) = explode(" ", microtime());
158 | return ((float)$usec + (float)$sec);
159 | }
160 | }
161 |
162 | new Game();
--------------------------------------------------------------------------------
/applications/Game/Lib/Autoloader.php:
--------------------------------------------------------------------------------
1 |
6 | */
7 | class Db
8 | {
9 | /**
10 | * 实例数组
11 | * @var array
12 | */
13 | protected static $instance = array();
14 |
15 | /**
16 | * 获取实例
17 | * @param string $config_name
18 | * @throws \Exception
19 | */
20 | public static function instance($config_name)
21 | {
22 | if(!isset(\Config\Db::$$config_name))
23 | {
24 | echo "\\Config\\Db::$config_name not set\n";
25 | throw new \Exception("\\Config\\Db::$config_name not set\n");
26 | }
27 |
28 | if(empty(self::$instance[$config_name]))
29 | {
30 | $config = \Config\Db::$$config_name;
31 | self::$instance[$config_name] = new \Lib\DbConnection($config['host'], $config['port'], $config['user'], $config['password'], $config['dbname']);
32 | }
33 | return self::$instance[$config_name];
34 | }
35 |
36 | /**
37 | * 关闭数据库实例
38 | * @param string $config_name
39 | */
40 | public static function close($config_name)
41 | {
42 | if(isset(self::$instance[$config_name]))
43 | {
44 | self::$instance[$config_name]->closeConnection();
45 | self::$instance[$config_name] = null;
46 | }
47 | }
48 |
49 | /**
50 | * 关闭所有数据库实例
51 | */
52 | public static function closeAll()
53 | {
54 | foreach(self::$instance as $connection)
55 | {
56 | $connection->closeConnection();
57 | self::$instance = array();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/applications/Game/Lib/DbConnection.php:
--------------------------------------------------------------------------------
1 | type = 'SELECT';
173 | if(!is_array($cols))
174 | {
175 | $cols = array($cols);
176 | }
177 | $this->cols($cols);
178 | return $this;
179 | }
180 |
181 | /**
182 | * 从哪个表删除
183 | * @param string $table
184 | * @return self
185 | */
186 | public function delete($table)
187 | {
188 | $this->type = 'DELETE';
189 | $this->table = $this->quoteName($table);
190 | $this->fromRaw($this->quoteName($table));
191 | return $this;
192 | }
193 |
194 | /**
195 | * 更新哪个表
196 | * @param string $table
197 | */
198 | public function update($table)
199 | {
200 | $this->type = 'UPDATE';
201 | $this->table = $this->quoteName($table);
202 | return $this;
203 | }
204 |
205 | /**
206 | * 向哪个表插入
207 | * @param string $table
208 | */
209 | public function insert($table)
210 | {
211 | $this->type = 'INSERT';
212 | $this->table = $this->quoteName($table);
213 | return $this;
214 | }
215 |
216 | /**
217 | *
218 | * 设置 SQL_CALC_FOUND_ROWS 标记.
219 | * @param bool
220 | * @return self
221 | */
222 | public function calcFoundRows($enable = true)
223 | {
224 | $this->setFlag('SQL_CALC_FOUND_ROWS', $enable);
225 | return $this;
226 | }
227 |
228 | /**
229 | * 设置 SQL_CACHE 标记
230 | * @param bool
231 | * @return self
232 | */
233 | public function cache($enable = true)
234 | {
235 | $this->setFlag('SQL_CACHE', $enable);
236 | return $this;
237 | }
238 |
239 | /**
240 | * 设置 SQL_NO_CACHE 标记
241 | * @param bool
242 | * @return self
243 | */
244 | public function noCache($enable = true)
245 | {
246 | $this->setFlag('SQL_NO_CACHE', $enable);
247 | return $this;
248 | }
249 |
250 | /**
251 | * 设置 STRAIGHT_JOIN 标记.
252 | * @param bool
253 | * @return self
254 | */
255 | public function straightJoin($enable = true)
256 | {
257 | $this->setFlag('STRAIGHT_JOIN', $enable);
258 | return $this;
259 | }
260 |
261 | /**
262 | * 设置 HIGH_PRIORITY 标记
263 | * @param bool
264 | * @return self
265 | */
266 | public function highPriority($enable = true)
267 | {
268 | $this->setFlag('HIGH_PRIORITY', $enable);
269 | return $this;
270 | }
271 |
272 | /**
273 | * 设置 SQL_SMALL_RESULT 标记
274 | * @param bool
275 | * @return self
276 | */
277 | public function smallResult($enable = true)
278 | {
279 | $this->setFlag('SQL_SMALL_RESULT', $enable);
280 | return $this;
281 | }
282 |
283 | /**
284 | * 设置 SQL_BIG_RESULT 标记
285 | * @param bool
286 | * @return self
287 | */
288 | public function bigResult($enable = true)
289 | {
290 | $this->setFlag('SQL_BIG_RESULT', $enable);
291 | return $this;
292 | }
293 |
294 | /**
295 | * 设置 SQL_BUFFER_RESULT 标记
296 | * @param bool
297 | * @return self
298 | */
299 | public function bufferResult($enable = true)
300 | {
301 | $this->setFlag('SQL_BUFFER_RESULT', $enable);
302 | return $this;
303 | }
304 |
305 | /**
306 | * 设置 FOR UPDATE 标记
307 | * @param bool
308 | * @return self
309 | */
310 | public function forUpdate($enable = true)
311 | {
312 | $this->for_update = (bool) $enable;
313 | return $this;
314 | }
315 |
316 | /**
317 | * 设置 DISTINCT 标记
318 | * @param bool
319 | * @return self
320 | */
321 | public function distinct($enable = true)
322 | {
323 | $this->setFlag('DISTINCT', $enable);
324 | return $this;
325 | }
326 |
327 | /**
328 | * 设置 LOW_PRIORITY 标记
329 | * @param bool $enable
330 | * @return self
331 | */
332 | public function lowPriority($enable = true)
333 | {
334 | $this->setFlag('LOW_PRIORITY', $enable);
335 | return $this;
336 | }
337 |
338 | /**
339 | * 设置 IGNORE 标记
340 | * @param bool $enable
341 | * @return self
342 | */
343 | public function ignore($enable = true)
344 | {
345 | $this->setFlag('IGNORE', $enable);
346 | return $this;
347 | }
348 |
349 | /**
350 | * 设置 QUICK 标记
351 | * @param bool $enable
352 | * @return self
353 | */
354 | public function quick($enable = true)
355 | {
356 | $this->setFlag('QUICK', $enable);
357 | return $this;
358 | }
359 |
360 | /**
361 | * 设置 DELAYED 标记
362 | * @param bool $enable
363 | * @return self
364 | */
365 | public function delayed($enable = true)
366 | {
367 | $this->setFlag('DELAYED', $enable);
368 | return $this;
369 | }
370 |
371 | /**
372 | * 序列化
373 | * @return string
374 | */
375 | public function __toString()
376 | {
377 | $union = '';
378 | if ($this->union) {
379 | $union = implode(' ', $this->union) . ' ';
380 | }
381 | return $union . $this->build();
382 | }
383 |
384 | /**
385 | * 设置每页多少条记录
386 | * @param int
387 | * @return self
388 | */
389 | public function setPaging($paging)
390 | {
391 | $this->paging = (int) $paging;
392 | return $this;
393 | }
394 |
395 | /**
396 | * 获取每页多少条记录
397 | * @return int
398 | */
399 | public function getPaging()
400 | {
401 | return $this->paging;
402 | }
403 |
404 | /**
405 | * 获取绑定在占位符上的值
406 | */
407 | public function getBindValues()
408 | {
409 | switch($this->type)
410 | {
411 | case 'SELECT':
412 | return $this->getBindValuesSELECT();
413 | case 'DELETE':
414 | case 'UPDATE':
415 | case 'INSERT':
416 | return $this->getBindValuesCOMMON();
417 | default :
418 | throw new \Exception("type err");
419 | }
420 | }
421 |
422 | /**
423 | * 获取绑定在占位符上的值
424 | * @return array
425 | */
426 | public function getBindValuesSELECT()
427 | {
428 | $bind_values = $this->bind_values;
429 | $i = 1;
430 | foreach ($this->bind_where as $val) {
431 | $bind_values[$i] = $val;
432 | $i ++;
433 | }
434 | foreach ($this->bind_having as $val) {
435 | $bind_values[$i] = $val;
436 | $i ++;
437 | }
438 | return $bind_values;
439 | }
440 |
441 | /**
442 | *
443 | * SELECT选择哪些列
444 | * @param mixed
445 | * @return null
446 | */
447 | protected function addColSELECT($key, $val)
448 | {
449 | if (is_string($key)) {
450 | $this->cols[$val] = $key;
451 | } else {
452 | $this->addColWithAlias($val);
453 | }
454 | }
455 |
456 | /**
457 | * SELECT增加选择的列
458 | * @param string
459 | * @return null
460 | */
461 | protected function addColWithAlias($spec)
462 | {
463 | $parts = explode(' ', $spec);
464 | $count = count($parts);
465 | if ($count == 2) {
466 | $this->cols[$parts[1]] = $parts[0];
467 | } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
468 | $this->cols[$parts[2]] = $parts[0];
469 | } else {
470 | $this->cols[] = $spec;
471 | }
472 | }
473 |
474 | /**
475 | * from 哪个表
476 | * @param string $table
477 | * @return self
478 | */
479 | public function from($table)
480 | {
481 | return $this->fromRaw($this->quoteName($table));
482 | }
483 |
484 | /**
485 | * from的表
486 | * @param string $table
487 | * @return self
488 | */
489 | public function fromRaw($table)
490 | {
491 | $this->from[] = array($table);
492 | $this->from_key ++;
493 | return $this;
494 | }
495 | /**
496 | *
497 | * 子查询
498 | * @param string $table
499 | * @param string $name The alias name for the sub-select.
500 | * @return self
501 | */
502 | public function fromSubSelect($table, $name)
503 | {
504 | $this->from[] = array( "($table) AS " . $this->quoteName($name));
505 | $this->from_key ++;
506 | return $this;
507 | }
508 |
509 |
510 | /**
511 | * 增加join语句
512 | * @param string $join inner, left, natural
513 | * @param string $table
514 | * @param string $cond
515 | * @return self
516 | * @throws Exception
517 | */
518 | public function join($table, $cond = null, $type = '')
519 | {
520 | return $this->joinInternal($type, $table, $cond);
521 | }
522 |
523 | /**
524 | * 增加join语句
525 | * @param string $join inner, left, natural
526 | * @param string $table
527 | * @param string $cond
528 | * @return self
529 | * @throws Exception
530 | */
531 | protected function joinInternal($join, $table, $cond = null)
532 | {
533 | if (! $this->from) {
534 | throw new Exception('Cannot join() without from()');
535 | }
536 |
537 | $join = strtoupper(ltrim("$join JOIN"));
538 | $table = $this->quoteName($table);
539 | $cond = $this->fixJoinCondition($cond);
540 | $this->from[$this->from_key][] = rtrim("$join $table $cond");
541 | return $this;
542 | }
543 |
544 | /**
545 | * quote
546 | * @param string $cond
547 | * @return string
548 | *
549 | */
550 | protected function fixJoinCondition($cond)
551 | {
552 | if (! $cond) {
553 | return;
554 | }
555 |
556 | $cond = $this->quoteNamesIn($cond);
557 |
558 | if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
559 | return $cond;
560 | }
561 |
562 | if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
563 | return $cond;
564 | }
565 |
566 | return 'ON ' . $cond;
567 | }
568 |
569 | /**
570 | * inner join
571 | * @param string $spec
572 | * @param string $cond
573 | * @return self
574 | * @throws Exception
575 | */
576 | public function innerJoin($table, $cond = null)
577 | {
578 | return $this->joinInternal('INNER', $table, $cond);
579 | }
580 |
581 | /**
582 | * left join
583 | * @param string $table
584 | * @param string $cond
585 | * @return self
586 | * @throws Exception
587 | */
588 | public function leftJoin($table, $cond = null)
589 | {
590 | return $this->joinInternal('LEFT', $table, $cond);
591 | }
592 |
593 | /**
594 | * right join
595 | * @param string $table
596 | * @param string $cond
597 | * @return self
598 | * @throws Exception
599 | */
600 | public function rightJoin($table, $cond = null)
601 | {
602 | return $this->joinInternal('RIGHT', $table, $cond);
603 | }
604 |
605 | /**
606 | * joinSubSelect
607 | * @param string $join inner, left, natural
608 | * @param string $spec
609 | * @param string $name sub-select 的别名
610 | * @param string $cond
611 | * @return self
612 | * @throws Exception
613 | */
614 | public function joinSubSelect($join, $spec, $name, $cond = null)
615 | {
616 | if (! $this->from) {
617 | throw new Exception('Cannot join() without from() first.');
618 | }
619 |
620 | $join = strtoupper(ltrim("$join JOIN"));
621 | $name = $this->quoteName($name);
622 | $cond = $this->fixJoinCondition($cond);
623 | $this->from[$this->from_key][] = rtrim("$join ($spec) AS $name $cond");
624 | return $this;
625 | }
626 |
627 | /**
628 | * group by 语句
629 | * @param array $cols
630 | * @return self
631 | */
632 | public function groupBy(array $cols)
633 | {
634 | foreach ($cols as $col) {
635 | $this->group_by[] = $this->quoteNamesIn($col);
636 | }
637 | return $this;
638 | }
639 |
640 | /**
641 | * having 语句
642 | * @param string $cond
643 | * @return self
644 | */
645 | public function having($cond)
646 | {
647 | $this->addClauseCondWithBind('having', 'AND', func_get_args());
648 | return $this;
649 | }
650 |
651 | /**
652 | * or having 语句
653 | * @param string $cond The HAVING condition.
654 | * @return self
655 | */
656 | public function orHaving($cond)
657 | {
658 | $this->addClauseCondWithBind('having', 'OR', func_get_args());
659 | return $this;
660 | }
661 |
662 | /**
663 | * 设置每页的记录数量
664 | * @param int $page
665 | * @return self
666 | */
667 | public function page($page)
668 | {
669 | $this->limit = 0;
670 | $this->offset = 0;
671 |
672 | $page = (int) $page;
673 | if ($page > 0) {
674 | $this->limit = $this->paging;
675 | $this->offset = $this->paging * ($page - 1);
676 | }
677 | return $this;
678 | }
679 |
680 | /**
681 | * union
682 | * @return self
683 | */
684 | public function union()
685 | {
686 | $this->union[] = $this->build() . ' UNION';
687 | $this->reset();
688 | return $this;
689 | }
690 |
691 | /**
692 | * unionAll
693 | * @return self
694 | */
695 | public function unionAll()
696 | {
697 | $this->union[] = $this->build() . ' UNION ALL';
698 | $this->reset();
699 | return $this;
700 | }
701 |
702 | /**
703 | * 重置
704 | * @return null
705 | */
706 | protected function reset()
707 | {
708 | $this->resetFlags();
709 | $this->cols = array();
710 | $this->from = array();
711 | $this->from_key = -1;
712 | $this->where = array();
713 | $this->group_by = array();
714 | $this->having = array();
715 | $this->order_by = array();
716 | $this->limit = 0;
717 | $this->offset = 0;
718 | $this->for_update = false;
719 | }
720 |
721 | /**
722 | * 清除所有数据
723 | * @return void
724 | */
725 | protected function resetAll()
726 | {
727 | $this->union = array();
728 | $this->for_update = false;
729 | $this->cols = array();
730 | $this->from = array();
731 | $this->from_key = -1;
732 | $this->group_by = array();
733 | $this->having = array();
734 | $this->bind_having = array();
735 | $this->paging = 10;
736 | $this->bind_values = array();
737 | $this->where = array();
738 | $this->bind_where = array();
739 | $this->order_by = array();
740 | $this->limit = 0;
741 | $this->offset = 0;
742 | $this->flags = array();
743 | $this->table = '';
744 | $this->last_insert_id_names = array();
745 | $this->col_values = array();
746 | $this->returning = array();
747 | $this->parameters = array();
748 | }
749 |
750 | /**
751 | * 创建 SELECT SQL
752 | * @return string
753 | */
754 | protected function buildSELECT()
755 | {
756 | return 'SELECT'
757 | . $this->buildFlags()
758 | . $this->buildCols()
759 | . $this->buildFrom()
760 | . $this->buildWhere()
761 | . $this->buildGroupBy()
762 | . $this->buildHaving()
763 | . $this->buildOrderBy()
764 | . $this->buildLimit()
765 | . $this->buildForUpdate();
766 | }
767 |
768 | /**
769 | * 创建DELETE SQL
770 | */
771 | protected function buildDELETE()
772 | {
773 | return 'DELETE'
774 | . $this->buildFlags()
775 | . $this->buildFrom()
776 | . $this->buildWhere()
777 | . $this->buildOrderBy()
778 | . $this->buildLimit()
779 | . $this->buildReturning();
780 | }
781 |
782 | /**
783 | * 生成SELECT列语句
784 | * @return string
785 | * @throws Exception
786 | */
787 | protected function buildCols()
788 | {
789 | if (! $this->cols) {
790 | throw new Exception('No columns in the SELECT.');
791 | }
792 |
793 | $cols = array();
794 | foreach ($this->cols as $key => $val) {
795 | if (is_int($key)) {
796 | $cols[] = $this->quoteNamesIn($val);
797 | } else {
798 | $cols[] = $this->quoteNamesIn("$val AS $key");
799 | }
800 | }
801 |
802 | return $this->indentCsv($cols);
803 | }
804 |
805 | /**
806 | * 生成 FROM 语句.
807 | * @return string
808 | */
809 | protected function buildFrom()
810 | {
811 | if (! $this->from) {
812 | return '';
813 | }
814 |
815 | $refs = array();
816 | foreach ($this->from as $from) {
817 | $refs[] = implode(' ', $from);
818 | }
819 | return ' FROM' . $this->indentCsv($refs);
820 | }
821 |
822 | /**
823 | * 生成 GROUP BY 语句.
824 | * @return string
825 | */
826 | protected function buildGroupBy()
827 | {
828 | if (! $this->group_by) {
829 | return '';
830 | }
831 | return ' GROUP BY' . $this->indentCsv($this->group_by);
832 | }
833 |
834 | /**
835 | * 生成 HAVING 语句.
836 | * @return string
837 | */
838 | protected function buildHaving()
839 | {
840 | if (! $this->having) {
841 | return '';
842 | }
843 | return ' HAVING' . $this->indent($this->having);
844 | }
845 |
846 | /**
847 | * 生成 FOR UPDATE 语句
848 | * @return string
849 | */
850 | protected function buildForUpdate()
851 | {
852 | if (! $this->for_update) {
853 | return '';
854 | }
855 | return ' FOR UPDATE';
856 | }
857 |
858 | /**
859 | * where
860 | * @param string $cond
861 | * @param mixed ...$bind
862 | * @return self
863 | */
864 | public function where($cond)
865 | {
866 | if(is_array($cond))
867 | {
868 | foreach($cond as $key=>$val)
869 | {
870 | if(is_string($key))
871 | {
872 | $this->addWhere('AND', array($key, $val));
873 | }
874 | else
875 | {
876 | $this->addWhere('AND', array($val));
877 | }
878 | }
879 | }
880 | else
881 | {
882 | $this->addWhere('AND', func_get_args());
883 | }
884 | return $this;
885 | }
886 |
887 | /**
888 | * or where
889 | * @param string $cond
890 | * @param mixed ...$bind
891 | * @return self
892 | */
893 | public function orWhere($cond)
894 | {
895 | if(is_array($con))
896 | {
897 | foreach($con as $key=>$val)
898 | {
899 | if(is_string($key))
900 | {
901 | $this->addWhere('OR', array($key, $val));
902 | }
903 | else
904 | {
905 | $this->addWhere('OR', array($val));
906 | }
907 | }
908 | }
909 | else
910 | {
911 | $this->addWhere('OR', func_get_args());
912 | }
913 | return $this;
914 | }
915 |
916 | /**
917 | * limit
918 | * @param int $limit
919 | * @return self
920 | */
921 | public function limit($limit)
922 | {
923 | $this->limit = (int) $limit;
924 | return $this;
925 | }
926 |
927 | /**
928 | * limit offset
929 | * @param int $offset
930 | * @return self
931 | */
932 | public function offset($offset)
933 | {
934 | $this->offset = (int) $offset;
935 | return $this;
936 | }
937 |
938 | /**
939 | * orderby.
940 | * @param array $cols
941 | * @return self
942 | */
943 | public function orderBy(array $cols)
944 | {
945 | return $this->addOrderBy($cols);
946 | }
947 |
948 | // -------------abstractquery----------
949 | /**
950 | * 返回逗号分隔的字符串
951 | * @param array $list
952 | * @return string
953 | */
954 | protected function indentCsv(array $list)
955 | {
956 | return ' ' . implode(',', $list);
957 | }
958 |
959 | /**
960 | * 返回空格分隔的字符串
961 | * @param array $list
962 | * @return string
963 | */
964 | protected function indent(array $list)
965 | {
966 | return ' ' . implode(' ', $list);
967 | }
968 |
969 | /**
970 | * 批量为占位符绑定值
971 | * @param array $bind_values
972 | * @return self
973 | *
974 | */
975 | public function bindValues(array $bind_values)
976 | {
977 | foreach ($bind_values as $key => $val) {
978 | $this->bindValue($key, $val);
979 | }
980 | return $this;
981 | }
982 |
983 | /**
984 | * 单个为占位符绑定值
985 | * @param string $name
986 | * @param mixed $value
987 | * @return self
988 | */
989 | public function bindValue($name, $value)
990 | {
991 | $this->bind_values[$name] = $value;
992 | return $this;
993 | }
994 |
995 | /**
996 | * 生成flag
997 | * @return string
998 | */
999 | protected function buildFlags()
1000 | {
1001 | if (! $this->flags) {
1002 | return '';
1003 | }
1004 | return ' ' . implode(' ', array_keys($this->flags));
1005 | }
1006 |
1007 | /**
1008 | * 设置 flag.
1009 | * @param string $flag
1010 | * @param bool $enable
1011 | * @return null
1012 | */
1013 | protected function setFlag($flag, $enable = true)
1014 | {
1015 | if ($enable) {
1016 | $this->flags[$flag] = true;
1017 | } else {
1018 | unset($this->flags[$flag]);
1019 | }
1020 | }
1021 |
1022 | /**
1023 | * 重置flag
1024 | * @return null
1025 | */
1026 | protected function resetFlags()
1027 | {
1028 | $this->flags = array();
1029 | }
1030 |
1031 | /**
1032 | *
1033 | * 添加where语句
1034 | * @param string $andor 'AND' or 'OR
1035 | * @param array $conditions
1036 | * @return self
1037 | *
1038 | */
1039 | protected function addWhere($andor, $conditions)
1040 | {
1041 | $this->addClauseCondWithBind('where', $andor, $conditions);
1042 | return $this;
1043 | }
1044 |
1045 | /**
1046 | * 添加条件和绑定值
1047 | * @param string $clause where 、having等
1048 | * @param string $andor AND、OR等
1049 | * @param array $conditions
1050 | * @return null
1051 | */
1052 | protected function addClauseCondWithBind($clause, $andor, $conditions)
1053 | {
1054 | $cond = array_shift($conditions);
1055 | $cond = $this->quoteNamesIn($cond);
1056 |
1057 | $bind =& $this->{"bind_{$clause}"};
1058 | foreach ($conditions as $value) {
1059 | $bind[] = $value;
1060 | }
1061 |
1062 | $clause =& $this->$clause;
1063 | if ($clause) {
1064 | $clause[] = "$andor $cond";
1065 | } else {
1066 | $clause[] = $cond;
1067 | }
1068 | }
1069 |
1070 | /**
1071 | * 生成where语句
1072 | * @return string
1073 | */
1074 | protected function buildWhere()
1075 | {
1076 | if (! $this->where) {
1077 | return '';
1078 | }
1079 | return ' WHERE' . $this->indent($this->where);
1080 | }
1081 |
1082 | /**
1083 | * 增加order by
1084 | * @param array $spec The columns and direction to order by.
1085 | * @return self
1086 | */
1087 | protected function addOrderBy(array $spec)
1088 | {
1089 | foreach ($spec as $col) {
1090 | $this->order_by[] = $this->quoteNamesIn($col);
1091 | }
1092 | return $this;
1093 | }
1094 |
1095 | /**
1096 | * 生成order by 语句
1097 | * @return string
1098 | */
1099 | protected function buildOrderBy()
1100 | {
1101 | if (! $this->order_by) {
1102 | return '';
1103 | }
1104 | return ' ORDER BY' . $this->indentCsv($this->order_by);
1105 | }
1106 |
1107 | /**
1108 | * 生成limit语句
1109 | * @return string
1110 | */
1111 | protected function buildLimit()
1112 | {
1113 | $has_limit = $this->type == 'DELETE' || $this->type == 'UPDATE';
1114 | $has_offset = $this->type == 'SELECT';
1115 |
1116 | if ($has_offset && $this->limit) {
1117 | $clause = " LIMIT {$this->limit}";
1118 | if ($this->offset) {
1119 | $clause .= " OFFSET {$this->offset}";
1120 | }
1121 | return $clause;
1122 | } elseif ($has_limit && $this->limit) {
1123 | return " LIMIT {$this->limit}";
1124 | }
1125 | return '';
1126 | }
1127 |
1128 | /**
1129 | * Quotes
1130 | * @param string $spec
1131 | * @return string|array
1132 | */
1133 | public function quoteName($spec)
1134 | {
1135 | $spec = trim($spec);
1136 | $seps = array(' AS ', ' ', '.');
1137 | foreach ($seps as $sep) {
1138 | $pos = strripos($spec, $sep);
1139 | if ($pos) {
1140 | return $this->quoteNameWithSeparator($spec, $sep, $pos);
1141 | }
1142 | }
1143 | return $this->replaceName($spec);
1144 | }
1145 |
1146 | /**
1147 | * 指定分隔符的Quotes
1148 | * @param string $spec
1149 | * @param string $sep
1150 | * @param string $pos
1151 | * @return string
1152 | */
1153 | protected function quoteNameWithSeparator($spec, $sep, $pos)
1154 | {
1155 | $len = strlen($sep);
1156 | $part1 = $this->quoteName(substr($spec, 0, $pos));
1157 | $part2 = $this->replaceName(substr($spec, $pos + $len));
1158 | return "{$part1}{$sep}{$part2}";
1159 | }
1160 |
1161 | /**
1162 | * Quotes "table.col" 格式的字符串
1163 | * @param string $text
1164 | * @return string|array
1165 | */
1166 | public function quoteNamesIn($text)
1167 | {
1168 | $list = $this->getListForQuoteNamesIn($text);
1169 | $last = count($list) - 1;
1170 | $text = null;
1171 | foreach ($list as $key => $val) {
1172 | if (($key+1) % 3) {
1173 | $text .= $this->quoteNamesInLoop($val, $key == $last);
1174 | }
1175 | }
1176 | return $text;
1177 | }
1178 |
1179 | /**
1180 | * 返回quote元素列表
1181 | * @param string $text
1182 | * @return array
1183 | */
1184 | protected function getListForQuoteNamesIn($text)
1185 | {
1186 | $apos = "'";
1187 | $quot = '"';
1188 | return preg_split(
1189 | "/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/",
1190 | $text,
1191 | -1,
1192 | PREG_SPLIT_DELIM_CAPTURE
1193 | );
1194 | }
1195 |
1196 | /**
1197 | * 循环quote
1198 | * @param string $val
1199 | * @param bool $is_last
1200 | * @return string
1201 | */
1202 | protected function quoteNamesInLoop($val, $is_last)
1203 | {
1204 | if ($is_last) {
1205 | return $this->replaceNamesAndAliasIn($val);
1206 | }
1207 | return $this->replaceNamesIn($val);
1208 | }
1209 |
1210 | /**
1211 | *
1212 | * 替换成别名
1213 | * @param string $val
1214 | * @return string
1215 | */
1216 | protected function replaceNamesAndAliasIn($val)
1217 | {
1218 | $quoted = $this->replaceNamesIn($val);
1219 | $pos = strripos($quoted, ' AS ');
1220 | if ($pos) {
1221 | $alias = $this->replaceName(substr($quoted, $pos + 4));
1222 | $quoted = substr($quoted, 0, $pos) . " AS $alias";
1223 | }
1224 | return $quoted;
1225 | }
1226 |
1227 | /**
1228 | * Quotes name
1229 | * @param string $name
1230 | * @return string
1231 | */
1232 | protected function replaceName($name)
1233 | {
1234 | $name = trim($name);
1235 | if ($name == '*') {
1236 | return $name;
1237 | }
1238 | return '`'. $name.'`';
1239 | }
1240 |
1241 | /**
1242 | * Quotes
1243 | * @param string $text
1244 | * @return string|array
1245 | */
1246 | protected function replaceNamesIn($text)
1247 | {
1248 | $is_string_literal = strpos($text, "'") !== false
1249 | || strpos($text, '"') !== false;
1250 | if ($is_string_literal) {
1251 | return $text;
1252 | }
1253 |
1254 | $word = "[a-z_][a-z0-9_]+";
1255 |
1256 | $find = "/(\\b)($word)\\.($word)(\\b)/i";
1257 |
1258 | $repl = '$1`$2`.`$3`$4';
1259 |
1260 | $text = preg_replace($find, $repl, $text);
1261 |
1262 | return $text;
1263 | }
1264 |
1265 | // ---------- insert --------------
1266 | /**
1267 | * 设置 `table.column` 与 last-insert-id 的映射
1268 | * @param array $insert_id_names
1269 | */
1270 | public function setLastInsertIdNames(array $last_insert_id_names)
1271 | {
1272 | $this->last_insert_id_names = $last_insert_id_names;
1273 | }
1274 |
1275 | /**
1276 | * insert into.
1277 | * @param string $into
1278 | * @return self
1279 | */
1280 | public function into($table)
1281 | {
1282 | $this->table = $this->quoteName($table);
1283 | return $this;
1284 | }
1285 |
1286 | /**
1287 | * 生成INSERT 语句
1288 | * @return string
1289 | */
1290 | protected function buildINSERT()
1291 | {
1292 | return 'INSERT'
1293 | . $this->buildFlags()
1294 | . $this->buildInto()
1295 | . $this->buildValuesForInsert()
1296 | . $this->buildReturning();
1297 | }
1298 |
1299 | /**
1300 | * 生成 INTO 语句
1301 | * @return string
1302 | */
1303 | protected function buildInto()
1304 | {
1305 | return " INTO " . $this->table;
1306 | }
1307 |
1308 | /**
1309 | * PDO::lastInsertId()
1310 | * @param string $col
1311 | * @return mixed
1312 | */
1313 | public function getLastInsertIdName($col)
1314 | {
1315 | $key = str_replace('`', '', $this->table) . '.' . $col;
1316 | if (isset($this->last_insert_id_names[$key])) {
1317 | return $this->last_insert_id_names[$key];
1318 | }
1319 | }
1320 |
1321 | /**
1322 | *
1323 | * 设置一列,如果有第二各参数,则把第二个参数绑定在占位符上
1324 | * @param string $col
1325 | * @param mixed $val
1326 | * @return self
1327 | */
1328 | public function col($col)
1329 | {
1330 | return call_user_func_array(array($this, 'addCol'), func_get_args());
1331 | }
1332 |
1333 | /**
1334 | * 设置多列
1335 | * @param array $cols
1336 | * @return self
1337 | */
1338 | public function cols(array $cols)
1339 | {
1340 | if($this->type == 'SELECT')
1341 | {
1342 | foreach ($cols as $key => $val)
1343 | {
1344 | $this->addColSELECT($key, $val);
1345 | }
1346 | return $this;
1347 | }
1348 | return $this->addCols($cols);
1349 | }
1350 |
1351 | /**
1352 | * 直接设置列的值
1353 | * @param string $col
1354 | * @param string $value
1355 | * @return self
1356 | */
1357 | public function set($col, $value)
1358 | {
1359 | return $this->setCol($col, $value);
1360 | }
1361 |
1362 | /**
1363 | * 为INSERT语句绑定值
1364 | * @return string
1365 | */
1366 | protected function buildValuesForInsert()
1367 | {
1368 | return ' ('.$this->indentCsv(array_keys($this->col_values)).') VALUES (' . $this->indentCsv(array_values($this->col_values)) . ')';
1369 | }
1370 |
1371 | // ------update-------
1372 | /**
1373 | * 更新哪个表
1374 | * @param string $table
1375 | * @return self
1376 | */
1377 | public function table($table)
1378 | {
1379 | $this->table = $this->quoteName($table);
1380 | return $this;
1381 | }
1382 |
1383 | /**
1384 | * 生成完整SQL语句
1385 | * @return string
1386 | */
1387 | protected function build()
1388 | {
1389 | switch($this->type)
1390 | {
1391 | case 'DELETE':
1392 | return $this->buildDELETE();
1393 | case 'INSERT':
1394 | return $this->buildINSERT();
1395 | case 'UPDATE':
1396 | return $this->buildUPDATE();
1397 | case 'SELECT':
1398 | return $this->buildSELECT();
1399 | }
1400 | throw new \Exception("type empty");
1401 | }
1402 |
1403 | /**
1404 | * 生成更新的SQL语句
1405 | */
1406 | protected function buildUPDATE()
1407 | {
1408 | return 'UPDATE'
1409 | . $this->buildFlags()
1410 | . $this->buildTable()
1411 | . $this->buildValuesForUpdate()
1412 | . $this->buildWhere()
1413 | . $this->buildOrderBy()
1414 | . $this->buildLimit()
1415 | . $this->buildReturning();
1416 |
1417 | }
1418 |
1419 | /**
1420 | * 哪个表
1421 | * @return null
1422 | */
1423 | protected function buildTable()
1424 | {
1425 | return " {$this->table}";
1426 | }
1427 |
1428 | /**
1429 | * 为更新语句绑定值
1430 | * @return string
1431 | */
1432 | protected function buildValuesForUpdate()
1433 | {
1434 | $values = array();
1435 | foreach ($this->col_values as $col => $value) {
1436 | $values[] = "{$col} = {$value}";
1437 | }
1438 | return ' SET' . $this->indentCsv($values);
1439 | }
1440 |
1441 | // ----------Dml---------------
1442 | /**
1443 | * 获取绑定的值
1444 | * @return array
1445 | */
1446 | public function getBindValuesCOMMON()
1447 | {
1448 | $bind_values = $this->bind_values;
1449 | $i = 1;
1450 | foreach ($this->bind_where as $val) {
1451 | $bind_values[$i] = $val;
1452 | $i ++;
1453 | }
1454 | return $bind_values;
1455 | }
1456 |
1457 | /**
1458 | * 设置列
1459 | * @param string $col
1460 | * @param mixed $val
1461 | * @return self
1462 | */
1463 | protected function addCol($col)
1464 | {
1465 | $key = $this->quoteName($col);
1466 | $this->col_values[$key] = ":$col";
1467 | $args = func_get_args();
1468 | if (count($args) > 1) {
1469 | $this->bindValue($col, $args[1]);
1470 | }
1471 | return $this;
1472 | }
1473 |
1474 | /**
1475 | * 设置多个列
1476 | * @param array $cols
1477 | * @return self
1478 | */
1479 | protected function addCols(array $cols)
1480 | {
1481 | foreach ($cols as $key => $val) {
1482 | if (is_int($key)) {
1483 | $this->addCol($val);
1484 | } else {
1485 | $this->addCol($key, $val);
1486 | }
1487 | }
1488 | return $this;
1489 | }
1490 |
1491 | /**
1492 | * 设置单列的值
1493 | * @param string $col .
1494 | * @param string $value
1495 | * @return self
1496 | */
1497 | protected function setCol($col, $value)
1498 | {
1499 | if ($value === null) {
1500 | $value = 'NULL';
1501 | }
1502 |
1503 | $key = $this->quoteName($col);
1504 | $value = $this->quoteNamesIn($value);
1505 | $this->col_values[$key] = $value;
1506 | return $this;
1507 | }
1508 |
1509 | /**
1510 | * 增加返回的列
1511 | * @param array $cols
1512 | * @return self
1513 | *
1514 | */
1515 | protected function addReturning(array $cols)
1516 | {
1517 | foreach ($cols as $col) {
1518 | $this->returning[] = $this->quoteNamesIn($col);
1519 | }
1520 | return $this;
1521 | }
1522 |
1523 | /**
1524 | * 生成 RETURNING 语句
1525 | * @return string
1526 | */
1527 | protected function buildReturning()
1528 | {
1529 | if (! $this->returning) {
1530 | return '';
1531 | }
1532 | return ' RETURNING' . $this->indentCsv($this->returning);
1533 | }
1534 |
1535 | /**
1536 | * 构造函数
1537 | */
1538 | public function __construct($host, $port, $user, $password, $db_name, $charset = 'utf8')
1539 | {
1540 | $this->settings = array(
1541 | 'host' => $host,
1542 | 'port' => $port,
1543 | 'user' => $user,
1544 | 'password' => $password,
1545 | 'dbname' => $db_name,
1546 | 'charset' => $charset,
1547 | );
1548 | $this->connect();
1549 | }
1550 |
1551 | /**
1552 | * 创建pdo实例
1553 | */
1554 | protected function connect()
1555 | {
1556 | $dsn = 'mysql:dbname='.$this->settings["dbname"].';host='.$this->settings["host"].';port='.$this->settings['port'];
1557 | $this->pdo = new \PDO($dsn, $this->settings["user"], $this->settings["password"], array(\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . (!empty($this->settings['charset']) ? $this->settings['charset'] : 'utf8')));
1558 | $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
1559 | $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
1560 | }
1561 | /*
1562 | * 关闭连接
1563 | */
1564 | public function closeConnection()
1565 | {
1566 | $this->pdo = null;
1567 | }
1568 |
1569 | /**
1570 | * 执行
1571 | * @param string $query
1572 | * @param string $parameters
1573 | */
1574 | protected function execute($query,$parameters = "")
1575 | {
1576 | try {
1577 | $this->sQuery = $this->pdo->prepare($query);
1578 | $this->bindMore($parameters);
1579 | if(!empty($this->parameters)) {
1580 | foreach($this->parameters as $param)
1581 | {
1582 | $parameters = explode("\x7F",$param);
1583 | $this->sQuery->bindParam($parameters[0],$parameters[1]);
1584 | }
1585 | }
1586 | $this->succes = $this->sQuery->execute();
1587 | }
1588 | catch(\PDOException $e)
1589 | {
1590 | // 服务端断开时重连一次
1591 | if($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013)
1592 | {
1593 | $this->closeConnection();
1594 | $this->connect();
1595 | $this->sQuery = $this->pdo->prepare($query);
1596 | $this->bindMore($parameters);
1597 | if(!empty($this->parameters)) {
1598 | foreach($this->parameters as $param)
1599 | {
1600 | $parameters = explode("\x7F",$param);
1601 | $this->sQuery->bindParam($parameters[0],$parameters[1]);
1602 | }
1603 | }
1604 | $this->succes = $this->sQuery->execute();
1605 | }
1606 | else
1607 | {
1608 | throw $e;
1609 | }
1610 | }
1611 | $this->parameters = array();
1612 | }
1613 |
1614 | /**
1615 | * 绑定
1616 | * @param string $para
1617 | * @param string $value
1618 | */
1619 | public function bind($para, $value)
1620 | {
1621 | if(is_string($para))
1622 | {
1623 | $this->parameters[sizeof($this->parameters)] = ":" . $para . "\x7F" . $value;
1624 | }
1625 | else
1626 | {
1627 | $this->parameters[sizeof($this->parameters)] = $para . "\x7F" . $value;
1628 | }
1629 | }
1630 |
1631 | /**
1632 | * 绑定多个
1633 | * @param array $parray
1634 | */
1635 | public function bindMore($parray)
1636 | {
1637 | if(empty($this->parameters) && is_array($parray)) {
1638 | $columns = array_keys($parray);
1639 | foreach($columns as $i => &$column) {
1640 | $this->bind($column, $parray[$column]);
1641 | }
1642 | }
1643 | }
1644 |
1645 | /**
1646 | * 执行SQL
1647 | * @param string $query
1648 | * @param array $params
1649 | * @param int $fetchmode
1650 | * @return mixed
1651 | */
1652 | public function query($query = '',$params = null, $fetchmode = \PDO::FETCH_ASSOC)
1653 | {
1654 | $query = trim($query);
1655 | if(empty($query))
1656 | {
1657 | $query = $this->build();
1658 | if(!$params)
1659 | {
1660 | $params = $this->getBindValues();
1661 | }
1662 | }
1663 |
1664 | $this->resetAll();
1665 | $this->lastSql = $query;
1666 |
1667 | $this->execute($query,$params);
1668 |
1669 | $rawStatement = explode(" ", $query);
1670 |
1671 | $statement = strtolower(trim($rawStatement[0]));
1672 | if ($statement === 'select' || $statement === 'show') {
1673 | return $this->sQuery->fetchAll($fetchmode);
1674 | }
1675 | elseif ( $statement === 'insert' || $statement === 'update' || $statement === 'delete' ) {
1676 | return $this->sQuery->rowCount();
1677 | }
1678 | else {
1679 | return NULL;
1680 | }
1681 | }
1682 |
1683 | /**
1684 | * 返回一列
1685 | * @param string $query
1686 | * @param array $params
1687 | * @return array
1688 | */
1689 | public function column($query = '',$params = null)
1690 | {
1691 | $query = trim($query);
1692 | if(empty($query))
1693 | {
1694 | $query = $this->build();
1695 | if(!$params)
1696 | {
1697 | $params = $this->getBindValues();
1698 | }
1699 | }
1700 |
1701 | $this->resetAll();
1702 | $this->lastSql = $query;
1703 |
1704 | $this->execute($query,$params);
1705 | $columns = $this->sQuery->fetchAll(\PDO::FETCH_NUM);
1706 | $column = null;
1707 | foreach($columns as $cells) {
1708 | $column[] = $cells[0];
1709 | }
1710 | return $column;
1711 | }
1712 |
1713 | /**
1714 | * 返回一行
1715 | * @param string $query
1716 | * @param array $params
1717 | * @param int $fetchmode
1718 | * @return array
1719 | */
1720 | public function row($query = '',$params = null, $fetchmode = \PDO::FETCH_ASSOC)
1721 | {
1722 | $query = trim($query);
1723 | if(empty($query))
1724 | {
1725 | $query = $this->build();
1726 | if(!$params)
1727 | {
1728 | $params = $this->getBindValues();
1729 | }
1730 | }
1731 |
1732 | $this->resetAll();
1733 | $this->lastSql = $query;
1734 |
1735 | $this->execute($query,$params);
1736 | return $this->sQuery->fetch($fetchmode);
1737 | }
1738 |
1739 | /**
1740 | * 返回单个值
1741 | * @param string $query
1742 | * @param array $params
1743 | * @return string
1744 | */
1745 | public function single($query = '',$params = null)
1746 | {
1747 | $query = trim($query);
1748 | if(empty($query))
1749 | {
1750 | $query = $this->build();
1751 | if(!$params)
1752 | {
1753 | $params = $this->getBindValues();
1754 | }
1755 | }
1756 |
1757 | $this->resetAll();
1758 | $this->lastSql = $query;
1759 |
1760 | $this->execute($query,$params);
1761 | return $this->sQuery->fetchColumn();
1762 | }
1763 |
1764 | /**
1765 | * 返回lastInsertId
1766 | * @return string
1767 | */
1768 | public function lastInsertId() {
1769 | return $this->pdo->lastInsertId();
1770 | }
1771 |
1772 | /**
1773 | * 返回最后一条直行的sql
1774 | * @return string
1775 | */
1776 | public function lastSQL()
1777 | {
1778 | return $this->lastSql;
1779 | }
1780 | }
1781 |
--------------------------------------------------------------------------------
/applications/Game/Lib/Store.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | class Store
9 | {
10 | /**
11 | * 实例数组
12 | * @var array
13 | */
14 | protected static $instance = array();
15 |
16 | /**
17 | * 获取实例
18 | * @param string $config_name
19 | * @throws \Exception
20 | */
21 | public static function instance($config_name)
22 | {
23 | // memcache 驱动
24 | if(\Config\Store::$driver == \Config\Store::DRIVER_MC)
25 | {
26 | if(!isset(\Config\Store::$$config_name))
27 | {
28 | echo "\\Config\\Store::$config_name not set\n";
29 | throw new \Exception("\\Config\\Store::$config_name not set\n");
30 | }
31 |
32 | if(!isset(self::$instance[$config_name]))
33 | {
34 | if(extension_loaded('Memcached'))
35 | {
36 | self::$instance[$config_name] = new \Memcached;
37 | }
38 | elseif(extension_loaded('Memcache'))
39 | {
40 | self::$instance[$config_name] = new \Memcache;
41 | }
42 | else
43 | {
44 | sleep(2);
45 | exit("extension memcached is not installed\n");
46 | }
47 | foreach(\Config\Store::$$config_name as $address)
48 | {
49 | list($ip, $port) = explode(':', $address);
50 | self::$instance[$config_name] ->addServer($ip, $port);
51 | }
52 | }
53 | return self::$instance[$config_name];
54 | }
55 | // 文件驱动
56 | else
57 | {
58 | if(!isset(self::$instance[$config_name]))
59 | {
60 | self::$instance[$config_name] = new \Lib\StoreDriver\File($config_name);
61 | }
62 | return self::$instance[$config_name];
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/applications/Game/Lib/StoreDriver/File.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | */
11 |
12 | class File
13 | {
14 | // 为了避免频繁读取磁盘,增加了缓存机制
15 | protected $dataCache = array();
16 | // 上次缓存时间
17 | protected $lastCacheTime = 0;
18 | // 保存数据的文件
19 | protected $dataFile = '';
20 | // 打开文件的句柄
21 | protected $dataFileHandle = null;
22 |
23 | // 缓存过期时间
24 | const CACHE_EXP_TIME = 1;
25 |
26 | /**
27 | * 构造函数
28 | * @param 配置名 $config_name
29 | */
30 | public function __construct($config_name)
31 | {
32 | $this->dataFile = \Config\Store::$storePath . "/$config_name.store.cache.php";
33 | if(!is_dir(\Config\Store::$storePath) && !@mkdir(\Config\Store::$storePath, 0777, true))
34 | {
35 | // 可能目录已经被其它进程创建
36 | clearstatcache();
37 | if(!is_dir(\Config\Store::$storePath))
38 | {
39 | // 避免狂刷日志
40 | sleep(1);
41 | throw new \Exception('cant not mkdir('.\Config\Store::$storePath.')');
42 | }
43 | }
44 | if(!is_file($this->dataFile))
45 | {
46 | touch($this->dataFile);
47 | }
48 | $this->dataFileHandle = fopen(__FILE__, 'r');
49 | if(!$this->dataFileHandle)
50 | {
51 | throw new \Exception("can not fopen($this->dataFile, 'r')");
52 | }
53 | }
54 |
55 | /**
56 | * 设置
57 | * @param string $key
58 | * @param mixed $value
59 | * @param int $ttl
60 | * @return number
61 | */
62 | public function set($key, $value, $ttl = 0)
63 | {
64 | flock($this->dataFileHandle, LOCK_EX);
65 | $this->readDataFromDisk();
66 | $this->dataCache[$key] = $value;
67 | $ret = $this->writeToDisk();
68 | flock($this->dataFileHandle, LOCK_UN);
69 | return $ret;
70 | }
71 |
72 | /**
73 | * 读取
74 | * @param string $key
75 | * @param bool $use_cache
76 | * @return Ambigous
77 | */
78 | public function get($key, $use_cache = true)
79 | {
80 | if(!$use_cache || time() - $this->lastCacheTime > self::CACHE_EXP_TIME)
81 | {
82 | flock($this->dataFileHandle, LOCK_EX);
83 | $this->readDataFromDisk();
84 | flock($this->dataFileHandle, LOCK_UN);
85 | }
86 | return isset($this->dataCache[$key]) ? $this->dataCache[$key] : null;
87 | }
88 |
89 | /**
90 | * 删除
91 | * @param string $key
92 | * @return number
93 | */
94 | public function delete($key)
95 | {
96 | flock($this->dataFileHandle, LOCK_EX);
97 | $this->readDataFromDisk();
98 | unset($this->dataCache[$key]);
99 | $ret = $this->writeToDisk();
100 | flock($this->dataFileHandle, LOCK_UN);
101 | return $ret;
102 | }
103 |
104 | /**
105 | * 自增
106 | * @param string $key
107 | * @return boolean|multitype:
108 | */
109 | public function increment($key)
110 | {
111 | flock($this->dataFileHandle, LOCK_EX);
112 | $this->readDataFromDisk();
113 | if(!isset($this->dataCache[$key]))
114 | {
115 | flock($this->dataFileHandle, LOCK_UN);
116 | return false;
117 | }
118 | $this->dataCache[$key] ++;
119 | $this->writeToDisk();
120 | flock($this->dataFileHandle, LOCK_UN);
121 | return $this->dataCache[$key];
122 | }
123 |
124 | /**
125 | * 清零销毁存储数据
126 | */
127 | public function destroy()
128 | {
129 | @unlink($this->dataFile);
130 | }
131 |
132 | /**
133 | * 写入磁盘
134 | * @return number
135 | */
136 | protected function writeToDisk()
137 | {
138 | return file_put_contents($this->dataFile, "dataCache, true). ';');
139 | }
140 |
141 | /**
142 | * 从磁盘读
143 | */
144 | protected function readDataFromDisk()
145 | {
146 | $cache = include $this->dataFile;
147 | if(is_array($cache))
148 | {
149 | $this->dataCache = $cache;
150 | }
151 | $this->lastCacheTime = time();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/applications/Game/Login.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9500);
17 |
18 | //通过配置获取
19 | $this->serv->set(array(
20 | //Worker进程数
21 | 'worker_num' => 4,
22 | //设置程序进入后台作为守护进程运行
23 | 'daemonize' => false,
24 | //每个worker进程允许处理的最大任务数
25 | 'max_request' => 10000,
26 | 'heartbeat_check_interval' => 60,
27 | 'dispatch_mode' => 2,
28 | 'debug_mode'=> 1
29 | ));
30 |
31 | //注册Server的事件回调函数
32 | $this->serv->on('Start', array($this, 'onStart'));
33 | $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
34 | $this->serv->on('Connect', array($this, 'onConnect'));
35 | $this->serv->on('Receive', array($this, 'onReceive'));
36 | $this->serv->on('Close', array($this, 'onClose'));
37 |
38 | $this->serv->start();
39 | }
40 |
41 | //主进程启动
42 | public function onStart($serv) {
43 | echo "Server is Running" . PHP_EOL;
44 | }
45 |
46 | //进程组启动
47 | public function onWorkerStart( $serv , $worker_id) {
48 | //cli_set_process_title('GroupWorker');
49 | // 在Worker进程开启时绑定定时器
50 | //echo "进程组:$worker_id" . PHP_EOL;
51 | }
52 |
53 | public function onConnect($serv, $fd, $from_id ) {
54 |
55 | }
56 |
57 | /**
58 | * 服务端接收数据
59 | *
60 | * @param $serv swoole_server对象
61 | * @param $fd 连接的描述符
62 | * @param $from_id reactor的id,无用
63 | * @param $data 接收数据
64 | */
65 | public function onReceive(swoole_server $serv, $fd, $from_id, $data) {
66 | //检测数据完整性
67 | if(JsonProtocol::check($data) != 0) {
68 | return;
69 | }
70 |
71 | $data = JsonProtocol::decode($data);
72 |
73 | //接收参数
74 | $class = $data['class'];
75 | $method = $data['method'];
76 | $params = $data['params'];
77 |
78 | // 判断类对应文件是否载入
79 | if(!class_exists($class))
80 | {
81 | $include_file = ROOT_DIR . "Server/$class.php";
82 | if(is_file($include_file)) {
83 | require_once $include_file;
84 | }
85 |
86 | if(!class_exists($class)) {
87 | $code = 404;
88 | $msg = "class $class not found";
89 | $result = array('code'=>$code, 'msg'=>$msg, 'data'=>null);
90 |
91 | $serv->send($fd, JsonProtocol::encode($result));
92 | }
93 | }
94 |
95 | // 调用类的方法
96 | try {
97 | $ret = call_user_func_array(array(new $class, $method), $params);
98 |
99 | // 发送数据给客户端,调用成功,data下标对应的元素即为调用结果
100 | $serv->send($fd, JsonProtocol::encode($ret));
101 | } catch(Exception $e) {
102 | // 发送数据给客户端,发生异常,调用失败
103 | $code = $e->getCode() ? $e->getCode() : 500;
104 | $result = array('code'=>$code, 'msg'=>$e->getMessage(), 'data'=>$e);
105 |
106 | $serv->send($fd, JsonProtocol::encode($result));
107 | }
108 | }
109 |
110 | public function onClose($serv, $fd, $from_id) {
111 |
112 | }
113 | }
--------------------------------------------------------------------------------
/applications/Game/Pay.php:
--------------------------------------------------------------------------------
1 | $recv_length)
25 | {
26 | // 还有这么多字节要接收
27 | return $total_length - $recv_length;
28 | }
29 | // 接收完毕
30 | return 0;
31 | }
32 |
33 | // 打包
34 | public static function encode($data)
35 | {
36 | // 选用json格式化数据
37 | $buffer = json_encode($data);
38 | // 包的整体长度为json长度加首部四个字节(首部数据包长度存储占用空间)
39 | $total_length = 4 + strlen($buffer);
40 | return pack('N', $total_length) . $buffer;
41 | }
42 |
43 | // 解包
44 | public static function decode($buffer)
45 | {
46 | $buffer_data = unpack('Ntotal_length', $buffer);
47 | // 得到这次数据的整体长度(字节)
48 | $total_length = $buffer_data['total_length'];
49 | // json的数据
50 | $json_string = substr($buffer, 4);
51 | return json_decode($json_string, true);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/applications/Game/Protocols/TextProtocol.php:
--------------------------------------------------------------------------------
1 |
6 | */
7 |
8 | class WebSocket
9 | {
10 | /**
11 | * 检查包的完整性
12 | * @param unknown_type $buffer
13 | */
14 | public static function check($buffer)
15 | {
16 | // 数据长度
17 | $recv_len = strlen($buffer);
18 | // 长度不够
19 | if($recv_len < 6)
20 | {
21 | return 6-$recv_len;
22 | }
23 |
24 | // 握手阶段客户端发送HTTP协议
25 | if(0 === strpos($buffer, 'GET'))
26 | {
27 | // 判断\r\n\r\n边界
28 | if(strlen($buffer) - 4 === strpos($buffer, "\r\n\r\n"))
29 | {
30 | return 0;
31 | }
32 | return 1;
33 | }
34 | // 如果是flash的policy-file-request
35 | elseif(0 === strpos($buffer,'' != $buffer[strlen($buffer) - 1])
38 | {
39 | return 1;
40 | }
41 | return 0;
42 | }
43 |
44 | // websocket二进制数据
45 | $data_len = ord($buffer[1]) & 127;
46 | $head_len = 6;
47 | if ($data_len === 126) {
48 | $pack = unpack('ntotal_len', substr($buffer, 2, 2));
49 | $data_len = $pack['total_len'];
50 | $head_len = 8;
51 | } else if ($data_len === 127) {
52 | $arr = unpack('N2', substr($buffer, 2, 8));
53 | $data_len = $arr[1]*4294967296 + $arr[2];
54 | $head_len = 14;
55 | }
56 | $remain_len = $head_len + $data_len - $recv_len;
57 | if($remain_len < 0)
58 | {
59 | return false;
60 | }
61 | return $remain_len;
62 | }
63 |
64 | /**
65 | * 打包
66 | * @param string $buffer
67 | */
68 | public static function encode($buffer)
69 | {
70 | $len = strlen($buffer);
71 | if($len<=125)
72 | {
73 | return "\x81".chr($len).$buffer;
74 | }
75 | else if($len<=65535)
76 | {
77 | return "\x81".chr(126).pack("n", $len).$buffer;
78 | }
79 | else
80 | {
81 | return "\x81".chr(127).pack("xxxxN", $len).$buffer;
82 | }
83 | }
84 |
85 | /**
86 | * 解包
87 | * @param string $buffer
88 | * @return string
89 | */
90 | public static function decode($buffer)
91 | {
92 | $len = $masks = $data = $decoded = null;
93 | $len = ord($buffer[1]) & 127;
94 | if ($len === 126) {
95 | $masks = substr($buffer, 4, 4);
96 | $data = substr($buffer, 8);
97 | } else if ($len === 127) {
98 | $masks = substr($buffer, 10, 4);
99 | $data = substr($buffer, 14);
100 | } else {
101 | $masks = substr($buffer, 2, 4);
102 | $data = substr($buffer, 6);
103 | }
104 | for ($index = 0; $index < strlen($data); $index++) {
105 | $decoded .= $data[$index] ^ $masks[$index % 4];
106 | }
107 | return $decoded;
108 | }
109 |
110 | /**
111 | * 是否是websocket断开的数据包
112 | * @param string $buffer
113 | */
114 | public static function isClosePacket($buffer)
115 | {
116 | $opcode = self::getOpcode($buffer);
117 | return $opcode == 8;
118 | }
119 |
120 | /**
121 | * 是否是websocket ping的数据包
122 | * @param string $buffer
123 | */
124 | public static function isPingPacket($buffer)
125 | {
126 | $opcode = self::getOpcode($buffer);
127 | return $opcode == 9;
128 | }
129 |
130 | /**
131 | * 是否是websocket pong的数据包
132 | * @param string $buffer
133 | */
134 | public static function isPongPacket($buffer)
135 | {
136 | $opcode = self::getOpcode($buffer);
137 | return $opcode == 0xa;
138 | }
139 |
140 | /**
141 | * 获取wbsocket opcode
142 | * @param string $buffer
143 | */
144 | public static function getOpcode($buffer)
145 | {
146 | return ord($buffer[0]) & 0xf;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/applications/Game/README.md:
--------------------------------------------------------------------------------
1 | 游戏服务器
2 | ===================
3 |
4 | ## 项目介绍 ##
5 |
6 | 1. 框架模型:Gateway/Worker进程
7 | 2. 通讯协议: google protobuf
8 |
9 |
10 | ## 目录介绍 ##
11 | 1. Game.php 入口文件
12 | 2. Task.php 定时任务
13 | 3. Server目录下具体业务逻辑数据模型
14 | 4. Structure目录存放结构体数据
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/applications/Game/Server/Member.php:
--------------------------------------------------------------------------------
1 | array('code'=>1, 'msg' => 'successful', 'data' => null),
21 | 'NO_DATA_EXIST' => array('code'=>100, 'msg' => 'No data exist', 'data' => null),
22 | 'ERROR_USERNAME' => array('code'=>400, 'msg' => '用户名为空', 'data' => null),
23 | 'ERROR_PASSWORD' => array('code'=>401, 'msg' => '用户密码为空', 'data' => null),
24 | 'ERROR_USERNAME_PASSWORD' => array('code'=>402, 'msg' => '用户或者密码错误', 'data' => null),
25 | );
26 |
27 | public function __Construct() {
28 | $this->_store = Store::instance('game');
29 | $this->_db = Db::instance('passport');
30 | }
31 |
32 | /**
33 | * 验证用户登录
34 | *
35 | * @param array $params
36 | * @return mixed
37 | */
38 | public function authLogin($username, $password) {
39 | if(!isset($username)) {
40 | return $this->_result['ERROR_USERNAME'];
41 | }
42 |
43 | if(!isset($password)) {
44 | return $this->_result['ERROR_PASSWORD'];
45 | }
46 |
47 | $password = md5(md5($password));
48 |
49 | $sql = "SELECT m_id,m_nickname,m_email,m_regtime FROM `t_member`
50 | WHERE m_nickname='{$username}' and m_password = '{$password}'
51 | limit 1";
52 | $result = $this->_db->row($sql);
53 | if($result) {
54 | $this->_result['SUCCESS']['data'] = $result;
55 | return $this->_result['SUCCESS'];
56 | } else {
57 | return $this->_result['ERROR_USERNAME_PASSWORD'];
58 | }
59 | }
60 |
61 | /**
62 | * 注册用户
63 | * @param $username
64 | * @param $password
65 | * @return array
66 | */
67 | public function authReg($username, $password) {
68 | $password = md5(md5($password));
69 |
70 | $data = array(
71 | 'm_nickname' => $username,
72 | 'm_password' => $password,
73 | 'm_email' => 'tt@qq.com',
74 | 'm_ip' => '2147483647',
75 | 'm_regtime' => time()
76 | );
77 | $result = $this->_db->insert('t_member')->cols($data)->query();
78 | return $result;
79 | }
80 |
81 | /**
82 | * 获取用户信息
83 | *
84 | * @param $mid
85 | * @return mixed
86 | */
87 | public function userInfoByMid($mid) {
88 | $key = "GAME_USER_INFO_{$mid}";
89 |
90 | $userInfo = $this->_store->get($key);
91 | if($userInfo) {
92 | $this->_result['SUCCESS']['data'] = $userInfo;
93 | return $this->_result['SUCCESS'];
94 | }
95 |
96 | $sql = "SELECT m_id,m_nickname,m_email,m_regtime FROM `t_member`
97 | WHERE m_id='{$mid}'
98 | limit 1";
99 | $result = $this->_db->row($sql);
100 | if($result) {
101 | $this->_store->set($key, $result);
102 | }
103 |
104 | if($result) {
105 | $this->_result['SUCCESS']['data'] = $result;
106 | return $this->_result['SUCCESS'];
107 | } else {
108 | return $this->_result['NO_DATA_EXIST'];
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/applications/Game/Server/Statistic.php:
--------------------------------------------------------------------------------
1 | insert('t_statistic')->cols($data)->query();
20 | return $result;
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/applications/Http/Config/Db.php:
--------------------------------------------------------------------------------
1 | select('name,age')->from('user')->where('age>12')->query();
13 | * 等价于
14 | * $user_array = Db::instance('one_demo')->query('SELECT `name`,`age` FROM `one_demo` WHERE `age`>12');
15 | * @var array
16 | */
17 | public static $passport = array(
18 | 'host' => '127.0.0.1',
19 | 'port' => 3306,
20 | 'user' => 'root',
21 | 'password' => '622124',
22 | 'dbname' => 'passport',
23 | 'charset' => 'utf8',
24 | );
25 | }
--------------------------------------------------------------------------------
/applications/Http/Config/Server.php:
--------------------------------------------------------------------------------
1 |
6 | */
7 | class Db
8 | {
9 | /**
10 | * 实例数组
11 | * @var array
12 | */
13 | protected static $instance = array();
14 |
15 | /**
16 | * 获取实例
17 | * @param string $config_name
18 | * @throws \Exception
19 | */
20 | public static function instance($config_name)
21 | {
22 | if(!isset(\Config\Db::$$config_name))
23 | {
24 | echo "\\Config\\Db::$config_name not set\n";
25 | throw new \Exception("\\Config\\Db::$config_name not set\n");
26 | }
27 |
28 | if(empty(self::$instance[$config_name]))
29 | {
30 | $config = \Config\Db::$$config_name;
31 | self::$instance[$config_name] = new \Lib\DbConnection($config['host'], $config['port'], $config['user'], $config['password'], $config['dbname']);
32 | }
33 | return self::$instance[$config_name];
34 | }
35 |
36 | /**
37 | * 关闭数据库实例
38 | * @param string $config_name
39 | */
40 | public static function close($config_name)
41 | {
42 | if(isset(self::$instance[$config_name]))
43 | {
44 | self::$instance[$config_name]->closeConnection();
45 | self::$instance[$config_name] = null;
46 | }
47 | }
48 |
49 | /**
50 | * 关闭所有数据库实例
51 | */
52 | public static function closeAll()
53 | {
54 | foreach(self::$instance as $connection)
55 | {
56 | $connection->closeConnection();
57 | self::$instance = array();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/applications/Http/Lib/Store.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | class Store
9 | {
10 | /**
11 | * 实例数组
12 | * @var array
13 | */
14 | protected static $instance = array();
15 |
16 | /**
17 | * 获取实例
18 | * @param string $config_name
19 | * @throws \Exception
20 | */
21 | public static function instance($config_name)
22 | {
23 | // memcache 驱动
24 | if(\Config\Store::$driver == \Config\Store::DRIVER_MC)
25 | {
26 | if(!isset(\Config\Store::$$config_name))
27 | {
28 | echo "\\Config\\Store::$config_name not set\n";
29 | throw new \Exception("\\Config\\Store::$config_name not set\n");
30 | }
31 |
32 | if(!isset(self::$instance[$config_name]))
33 | {
34 | if(extension_loaded('Memcached'))
35 | {
36 | self::$instance[$config_name] = new \Memcached;
37 | }
38 | elseif(extension_loaded('Memcache'))
39 | {
40 | self::$instance[$config_name] = new \Memcache;
41 | }
42 | else
43 | {
44 | sleep(2);
45 | exit("extension memcached is not installed\n");
46 | }
47 | foreach(\Config\Store::$$config_name as $address)
48 | {
49 | list($ip, $port) = explode(':', $address);
50 | self::$instance[$config_name] ->addServer($ip, $port);
51 | }
52 | }
53 | return self::$instance[$config_name];
54 | }
55 | // 文件驱动
56 | else
57 | {
58 | if(!isset(self::$instance[$config_name]))
59 | {
60 | self::$instance[$config_name] = new \Lib\StoreDriver\File($config_name);
61 | }
62 | return self::$instance[$config_name];
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/applications/Http/Lib/StoreDriver/File.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | */
11 |
12 | class File
13 | {
14 | // 为了避免频繁读取磁盘,增加了缓存机制
15 | protected $dataCache = array();
16 | // 上次缓存时间
17 | protected $lastCacheTime = 0;
18 | // 保存数据的文件
19 | protected $dataFile = '';
20 | // 打开文件的句柄
21 | protected $dataFileHandle = null;
22 |
23 | // 缓存过期时间
24 | const CACHE_EXP_TIME = 1;
25 |
26 | /**
27 | * 构造函数
28 | * @param 配置名 $config_name
29 | */
30 | public function __construct($config_name)
31 | {
32 | $this->dataFile = \Config\Store::$storePath . "/$config_name.store.cache.php";
33 | if(!is_dir(\Config\Store::$storePath) && !@mkdir(\Config\Store::$storePath, 0777, true))
34 | {
35 | // 可能目录已经被其它进程创建
36 | clearstatcache();
37 | if(!is_dir(\Config\Store::$storePath))
38 | {
39 | // 避免狂刷日志
40 | sleep(1);
41 | throw new \Exception('cant not mkdir('.\Config\Store::$storePath.')');
42 | }
43 | }
44 | if(!is_file($this->dataFile))
45 | {
46 | touch($this->dataFile);
47 | }
48 | $this->dataFileHandle = fopen(__FILE__, 'r');
49 | if(!$this->dataFileHandle)
50 | {
51 | throw new \Exception("can not fopen($this->dataFile, 'r')");
52 | }
53 | }
54 |
55 | /**
56 | * 设置
57 | * @param string $key
58 | * @param mixed $value
59 | * @param int $ttl
60 | * @return number
61 | */
62 | public function set($key, $value, $ttl = 0)
63 | {
64 | flock($this->dataFileHandle, LOCK_EX);
65 | $this->readDataFromDisk();
66 | $this->dataCache[$key] = $value;
67 | $ret = $this->writeToDisk();
68 | flock($this->dataFileHandle, LOCK_UN);
69 | return $ret;
70 | }
71 |
72 | /**
73 | * 读取
74 | * @param string $key
75 | * @param bool $use_cache
76 | * @return Ambigous
77 | */
78 | public function get($key, $use_cache = true)
79 | {
80 | if(!$use_cache || time() - $this->lastCacheTime > self::CACHE_EXP_TIME)
81 | {
82 | flock($this->dataFileHandle, LOCK_EX);
83 | $this->readDataFromDisk();
84 | flock($this->dataFileHandle, LOCK_UN);
85 | }
86 | return isset($this->dataCache[$key]) ? $this->dataCache[$key] : null;
87 | }
88 |
89 | /**
90 | * 删除
91 | * @param string $key
92 | * @return number
93 | */
94 | public function delete($key)
95 | {
96 | flock($this->dataFileHandle, LOCK_EX);
97 | $this->readDataFromDisk();
98 | unset($this->dataCache[$key]);
99 | $ret = $this->writeToDisk();
100 | flock($this->dataFileHandle, LOCK_UN);
101 | return $ret;
102 | }
103 |
104 | /**
105 | * 自增
106 | * @param string $key
107 | * @return boolean|multitype:
108 | */
109 | public function increment($key)
110 | {
111 | flock($this->dataFileHandle, LOCK_EX);
112 | $this->readDataFromDisk();
113 | if(!isset($this->dataCache[$key]))
114 | {
115 | flock($this->dataFileHandle, LOCK_UN);
116 | return false;
117 | }
118 | $this->dataCache[$key] ++;
119 | $this->writeToDisk();
120 | flock($this->dataFileHandle, LOCK_UN);
121 | return $this->dataCache[$key];
122 | }
123 |
124 | /**
125 | * 清零销毁存储数据
126 | */
127 | public function destroy()
128 | {
129 | @unlink($this->dataFile);
130 | }
131 |
132 | /**
133 | * 写入磁盘
134 | * @return number
135 | */
136 | protected function writeToDisk()
137 | {
138 | return file_put_contents($this->dataFile, "dataCache, true). ';');
139 | }
140 |
141 | /**
142 | * 从磁盘读
143 | */
144 | protected function readDataFromDisk()
145 | {
146 | $cache = include $this->dataFile;
147 | if(is_array($cache))
148 | {
149 | $this->dataCache = $cache;
150 | }
151 | $this->lastCacheTime = time();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/applications/Http/Protocols/JsonProtocol.php:
--------------------------------------------------------------------------------
1 |
7 | * */
8 | class JsonProtocol
9 | {
10 | /**
11 | * 从socket缓冲区中预读长度
12 | * @var integer
13 | */
14 | const PRREAD_LENGTH = 87380;
15 |
16 | /**
17 | * 判断数据包是否接收完整
18 | * @param string $bin_data
19 | * @param mixed $data
20 | * @return integer 0代表接收完毕,大于0代表还要接收数据
21 | */
22 | public static function dealInput($bin_data)
23 | {
24 | $bin_data_length = strlen($bin_data);
25 | // 判断最后一个字符是否为\n,\n代表一个数据包的结束
26 | if($bin_data[$bin_data_length-1] !="\n")
27 | {
28 | // 再读
29 | return self::PRREAD_LENGTH;
30 | }
31 | return 0;
32 | }
33 |
34 | /**
35 | * 将数据打包成Rpc协议数据
36 | * @param mixed $data
37 | * @return string
38 | */
39 | public static function encode($data)
40 | {
41 | return json_encode($data)."\n";
42 | }
43 |
44 | /**
45 | * 解析Rpc协议数据
46 | * @param string $bin_data
47 | * @return mixed
48 | */
49 | public static function decode($bin_data)
50 | {
51 | return json_decode(trim($bin_data), true);
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/applications/Http/Services/Online.php:
--------------------------------------------------------------------------------
1 | single($sql);
29 | return $result;
30 | }
31 | }
--------------------------------------------------------------------------------
/applications/Http/Services/Zone.php:
--------------------------------------------------------------------------------
1 | get($key);
27 | if($serverList) {
28 | return $serverList;
29 | }
30 |
31 | $sql = "SELECT s_id,s_name,s_type,s_ip FROM `t_server`
32 | WHERE s_status=1
33 | ORDER BY s_id ASC";
34 | $result = $db->query($sql);
35 | if($result) {
36 | $store->set($key, $result);
37 | }
38 |
39 | return $result;
40 | }
41 |
42 | public static function getData($a, $b) {
43 | return $a+$b;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/applications/Http/index.php:
--------------------------------------------------------------------------------
1 | http = new swoole_http_server("0.0.0.0", 8080);
14 | $this->http->set(
15 | array(
16 | 'worker_num' => 16,
17 | 'daemonize' => false,
18 | 'max_request' => 10000,
19 | 'dispatch_mode' => 1
20 | )
21 | );
22 | $this->http->on('Start', array($this, 'onStart'));
23 | $this->http->on('request' , array( $this , 'onRequest'));
24 | $this->http->on('message' , array( $this , 'onMessage'));
25 | $this->http->start();
26 | }
27 |
28 | public function onStart( $serv ) {
29 | echo "Start\n";
30 | }
31 |
32 | public function onRequest($request, $response) {
33 | if( isset($request->server) ) {
34 | $server = $request->server;
35 |
36 | echo $server['request_uri'] . PHP_EOL;
37 | }
38 |
39 | if( isset($request->header) ) {
40 | $header = $request->header;
41 | }
42 |
43 | if( isset($request->get) ) {
44 | $get = $request->get;
45 | print_r($get);
46 | }
47 |
48 | if( isset($request->post) ) {
49 | $post = $request->post;
50 | }
51 |
52 | $response->end(1);
53 | }
54 |
55 | public function onMessage($request, $response) {
56 | //echo $request->message;
57 | //$response->message(json_encode(array("data1", "data2")));
58 | }
59 | }
60 | new Server();
--------------------------------------------------------------------------------
/applications/swoole-yaf/README.md:
--------------------------------------------------------------------------------
1 | ##**swoole-yaf**
2 | 结合PHP的Yaf框架和Swoole扩展的高性能PHP Web框架
3 |
4 | ##**描述**
5 | 底层使用Swoole内置的swoole_http_server提供服务
6 | 上层应用使用Yaf框架搭建
7 |
8 | ##**使用说明**
9 | 打开终端
10 | cd swoole-yaf
11 | php server/server.php
12 |
13 | 打开浏览器,输入http://ip:9501
14 | 1、路由:http://192.168.1.248:9501/test Index:模块 控制器:Index 方法:test
15 | 2、获取参数:http://192.168.1.248:9501/index/index/vote/mid/13392/status/1
16 | 参数:mid=13392 status=1
17 |
18 | ##**swoole版本**
19 | swoole-1.7.8+版本
20 |
21 | ##**yaf版本**
22 | 任意stable版本
23 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/Bootstrap.php:
--------------------------------------------------------------------------------
1 | getConfig();
15 | Yaf_Registry::set('config', $arrConfig);
16 | }
17 |
18 | public function _initPlugin(Yaf_Dispatcher $dispatcher) {
19 | //注册一个插件
20 | $objSamplePlugin = new SamplePlugin();
21 | $dispatcher->registerPlugin($objSamplePlugin);
22 | }
23 |
24 | public function _initRoute(Yaf_Dispatcher $dispatcher) {
25 | //在这里注册自己的路由协议,默认使用简单路由
26 | $fileName = APPLICATION_PATH . "/conf/routes.ini";
27 | if ( file_exists($fileName) ) {
28 | $config = new Yaf_Config_Ini($fileName);
29 | $dispatcher->getRouter()->addConfig($config->routes);
30 | }
31 | }
32 |
33 | public function _initView(Yaf_Dispatcher $dispatcher){
34 | //在这里注册自己的view控制器,例如smarty,firekylin
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/controllers/Error.php:
--------------------------------------------------------------------------------
1 | getView()->assign("exception", $exception);
14 | //5. render by Yaf
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/controllers/Form.php:
--------------------------------------------------------------------------------
1 | getRequest()->getPost ("fname");
15 | //var_dump( $post );
16 | $content['fname'] = $post["fname"];
17 | $content['lname'] = $post["lname"];
18 |
19 | //2. fetch model
20 | $model = new SampleModel();
21 |
22 | //3. assign
23 | $this->getView()->assign("content", $content);
24 | //$this->getView()->assign("name", $name);
25 | $this->display('index');
26 | //4. render by Yaf, 如果这里返回FALSE, Yaf将不会调用自动视图引擎Render模板
27 | return FALSE;
28 | }
29 |
30 | public function FormAction() {
31 | $get = HttpServer::$get;
32 | $this->getView()->assign("name", $get['name']);
33 | $this->display('form');
34 | return FALSE;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/controllers/Index.php:
--------------------------------------------------------------------------------
1 | getRequest()->getQuery("get", "default value");
18 | // $get = HttpServer::$get;
19 |
20 | //2. fetch model
21 | //$model = new SampleModel();
22 | //$model = new SampleModel();
23 | echo 'Hello Word';
24 | return FALSE;
25 |
26 | //3. assign
27 | //$this->getView()->assign("name", "test");
28 |
29 | //4. render by Yaf, 如果这里返回FALSE, Yaf将不会调用自动视图引擎Render模板
30 | return TRUE;
31 | }
32 |
33 | public function testAction() {
34 | $model = new SampleModel();
35 | echo $model->selectSample();
36 | return FALSE;
37 | }
38 |
39 | public function voteAction() {
40 | $get = $this->getRequest()->getParams();
41 |
42 | print_r($get);
43 | return false;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/favicon.ico.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moxiaobai/swoole-game/920f9ff4cb26c3d1ce686e52ff69443c99e6f79e/applications/swoole-yaf/application/favicon.ico.png
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/library/readme.txt:
--------------------------------------------------------------------------------
1 | 项目库文件放在这里
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/models/Sample.php:
--------------------------------------------------------------------------------
1 | getMessage();
3 | ?>
4 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/views/form/form.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/views/form/index.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
5 |
6 | Hello,
7 |
8 |
9 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/application/views/index/index.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello
4 |
9 |
10 | 请单击确认按钮
11 | click
12 |
13 |
14 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/conf/application.ini:
--------------------------------------------------------------------------------
1 | [common]
2 | application.directory = APPLICATION_PATH "/application"
3 | application.modules = "Index,Ajax,Api"
4 | application.dispatcher.catchException = TRUE
5 |
6 | [product : common]
7 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/conf/routes.ini:
--------------------------------------------------------------------------------
1 | routes.Home.type = rewrite
2 | routes.Home.match = /test
3 | routes.Home.route.module = Index
4 | routes.Home.route.controller = Index
5 | routes.Home.route.action = test
--------------------------------------------------------------------------------
/applications/swoole-yaf/server/server.php:
--------------------------------------------------------------------------------
1 | set(
18 | array(
19 | 'worker_num' => 4,
20 | 'daemonize' => false,
21 | 'max_request' => 10000,
22 | 'dispatch_mode' => 1
23 | )
24 | );
25 |
26 | $http->on('WorkerStart' , array( $this , 'onWorkerStart'));
27 |
28 | $http->on('request', function ($request, $response) {
29 | if( isset($request->server) ) {
30 | HttpServer::$server = $request->server;
31 | }
32 | if( isset($request->header) ) {
33 | HttpServer::$header = $request->header;
34 | }
35 | if( isset($request->get) ) {
36 | HttpServer::$get = $request->get;
37 | }
38 | if( isset($request->post) ) {
39 | HttpServer::$post = $request->post;
40 | }
41 |
42 | // TODO handle img
43 |
44 | ob_start();
45 | try {
46 | $yaf_request = new Yaf_Request_Http(HttpServer::$server['request_uri']);
47 |
48 | $this->application->getDispatcher()->dispatch($yaf_request);
49 |
50 | // unset(Yaf_Application::app());
51 | } catch ( Yaf_Exception $e ) {
52 | var_dump( $e );
53 | }
54 |
55 | $result = ob_get_contents();
56 |
57 | ob_end_clean();
58 |
59 | // add Header
60 |
61 | // add cookies
62 |
63 | // set status
64 | $response->end($result);
65 | });
66 |
67 | $http->start();
68 | }
69 |
70 | //Worker工作组
71 | public function onWorkerStart() {
72 | define('APPLICATION_PATH', dirname(__DIR__));
73 | $this->application = new Yaf_Application( APPLICATION_PATH .
74 | "/conf/application.ini");
75 | ob_start();
76 | $this->application->bootstrap()->run();
77 | ob_end_clean();
78 | }
79 |
80 | public static function getInstance() {
81 | if (!self::$instance) {
82 | self::$instance = new HttpServer;
83 | }
84 | return self::$instance;
85 | }
86 | }
87 |
88 | HttpServer::getInstance();
89 |
--------------------------------------------------------------------------------
/applications/swoole-yaf/yaf_classes.php:
--------------------------------------------------------------------------------
1 | $recv_length)
25 | {
26 | // 还有这么多字节要接收
27 | return $total_length - $recv_length;
28 | }
29 | // 接收完毕
30 | return 0;
31 | }
32 |
33 | // 打包
34 | public static function encode($data)
35 | {
36 | // 选用json格式化数据
37 | $buffer = json_encode($data);
38 | // 包的整体长度为json长度加首部四个字节(首部数据包长度存储占用空间)
39 | $total_length = 4 + strlen($buffer);
40 | return pack('N', $total_length) . $buffer;
41 | }
42 |
43 | // 解包
44 | public static function decode($buffer)
45 | {
46 | $buffer_data = unpack('Ntotal_length', $buffer);
47 | // 得到这次数据的整体长度(字节)
48 | $total_length = $buffer_data['total_length'];
49 | // json的数据
50 | $json_string = substr($buffer, 4);
51 | return json_decode($json_string, true);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/example/echo/client.php:
--------------------------------------------------------------------------------
1 | client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
15 |
16 | $this->client->on('Connect', array($this, 'onConnect'));
17 | $this->client->on('Receive', array($this, 'onReceive'));
18 | $this->client->on('Close', array($this, 'onClose'));
19 | $this->client->on('Error', array($this, 'onError'));
20 | }
21 |
22 | public function connect() {
23 | $fp = $this->client->connect('127.0.0.1', 9501, 0.5, 0);
24 | if( !$fp ) {
25 | echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";
26 | return;
27 | }
28 | }
29 |
30 | public function onConnect( $cli) {
31 | fwrite(STDOUT, "Enter Msg:\n");
32 | swoole_event_add(STDIN, function($fp){
33 | global $cli;
34 | fwrite(STDOUT, "Enter Msg:");
35 | $msg = trim(fgets(STDIN));
36 | $cli->send( $msg );
37 | });
38 | }
39 |
40 | public function onReceive( $cli, $data ) {
41 | echo "Get Message From Server: {$data}\n";
42 | }
43 |
44 | public function onClose( $cli) {
45 | echo "Client close connection\n";
46 | }
47 |
48 | public function onError() {
49 |
50 | }
51 |
52 | public function send($data) {
53 | $this->client->send( $data );
54 | }
55 |
56 | public function isConnected() {
57 | return $this->client->isConnected();
58 | }
59 | }
60 | $cli = new Client();
61 | $cli->connect();
--------------------------------------------------------------------------------
/example/echo/eofClient.php:
--------------------------------------------------------------------------------
1 | connect('127.0.0.1', 9501, 0.5, 0)) {
11 | echo "Over flow. errno=".$client->errCode;
12 | die("\n");
13 | }
14 |
15 | $data = array(
16 | 'name' => __FILE__,
17 | 'content' => str_repeat('A', 8192 * rand(100, 200)), //800K
18 | );
19 | $_send = serialize($data)."\r\n\r\n";
20 | echo "send length=".strlen($_send)."\n";
21 |
22 | if(!$client->send($_send))
23 | {
24 | die("send failed.\n");
25 | }
--------------------------------------------------------------------------------
/example/echo/eofServer.php:
--------------------------------------------------------------------------------
1 | set(array(
12 | 'package_eof' => "\r\n\r\n",
13 | 'open_eof_check' => true,
14 | 'worker_num' => 1,
15 | 'dispatch_mode' => 1,
16 | 'package_max_length' => 1024 * 1024 * 2, //2M
17 | 'debug_mode'=> 1
18 | ));
19 | //$serv->on('connect', function ($serv, $fd) {
20 | // //echo "[#" . posix_getpid() . "]\tClient:Connect.\n";
21 | //});
22 | $serv->on('receive', function (swoole_server $serv, $fd, $from_id, $data) {
23 | echo "[#" . posix_getpid() . "] recv length=".strlen($data)."\n";
24 | $req = unserialize(trim($data));
25 | //echo $req['name'] . "\n";
26 | //echo "content_length: " . strlen($data) . "\n";
27 | $respData = 'Welcome to swoole-server!
';
28 | $response = implode("\r\n", array(
29 | 'HTTP/1.1 200 OK',
30 | 'Cache-Control: must-revalidate,no-cache',
31 | 'Content-Language: zh-CN',
32 | 'Server: swoole-'.SWOOLE_VERSION,
33 | 'Content-Type: text/html',
34 | 'Connection: keep-alive',
35 | 'Content-Length: ' . strlen($respData),
36 | '',
37 | $respData));
38 | //print_r($response);
39 | usleep(500000);
40 | //if ($serv->worker_id == 2) sleep(100);
41 | //$serv->send($fd, $response);
42 | });
43 | //$serv->on('close', function ($serv, $fd) {
44 | //echo "[#" . posix_getpid() . "]\tClient: Close.\n";
45 | //});
46 | $serv->start();
--------------------------------------------------------------------------------
/example/echo/event.php:
--------------------------------------------------------------------------------
1 | \n");
13 | }
14 | fwrite($fp, "HELLO world");
15 | function stream_onRead($fp)
16 | {
17 | echo fread($fp, 1024)."\n";
18 | sleep(1);
19 | swoole_event_set($fp, null, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
20 | //swoole_event_del($fp);
21 | //fclose($fp);
22 | }
23 | function stream_onWrite($fp)
24 | {
25 | fwrite($fp, "hi swoole\n");
26 | swoole_event_set($fp, null, null, SWOOLE_EVENT_READ);
27 | }
28 | swoole_event_add($fp, 'stream_onRead', 'stream_onWrite');
29 | echo "start\n";
--------------------------------------------------------------------------------
/example/echo/server.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9501);
15 | $this->serv->set(array(
16 | //Worker进程数
17 | 'worker_num' => 4,
18 | //设置程序进入后台作为守护进程运行
19 | 'daemonize' => false,
20 | //每个worker进程允许处理的最大任务数
21 | 'max_request' => 10000,
22 | 'heartbeat_check_interval' => 60,
23 | 'dispatch_mode' => 2,
24 | 'debug_mode'=> 1
25 | ));
26 |
27 | //注册Server的事件回调函数
28 | $this->serv->on('Start', array($this, 'onStart'));
29 | $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
30 | $this->serv->on('Connect', array($this, 'onConnect'));
31 | $this->serv->on('Receive', array($this, 'onReceive'));
32 | $this->serv->on('Close', array($this, 'onClose'));
33 |
34 | $this->serv->start();
35 | }
36 |
37 | //主进程
38 | public function onStart($serv) {
39 | //cli_set_process_title('MainWorker');
40 | echo "Server Start" . PHP_EOL;
41 |
42 | //管理进程的PID,通过向管理进程发送SIGUSR1信号可实现柔性重启
43 | echo $serv->manager_pid . PHP_EOL;
44 |
45 | //主进程的PID,通过向主进程发送SIGTERM信号可安全关闭服务器
46 | echo $serv->master_pid . PHP_EOL;
47 | }
48 |
49 | //进程组
50 | public function onWorkerStart( $serv , $worker_id) {
51 | //cli_set_process_title('GroupWorker');
52 | // 在Worker进程开启时绑定定时器
53 | echo "Woker进程组: $worker_id" . PHP_EOL;
54 | }
55 |
56 | public function onConnect(swoole_server $serv, $fd, $from_id ) {
57 | //获取连接的客户端信息
58 | $fdInfo = $serv->connection_info($fd);
59 | echo '';
60 | print_r($fdInfo);
61 | echo '
';
62 |
63 | $serv->send( $fd, "Welcome {$fd} Connect Server" );
64 | }
65 |
66 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
67 | echo "Hello,Get Message From Client {$fd}:{$data}" . PHP_EOL;
68 | }
69 |
70 | public function onClose(swoole_server $serv, $fd, $from_id ) {
71 | echo "Client {$fd} close connection" . PHP_EOL;
72 | }
73 | }
74 |
75 | // 启动服务器
76 | $server = new Server();
--------------------------------------------------------------------------------
/example/http/index.php:
--------------------------------------------------------------------------------
1 | on('request', function ($request, $response) {
13 | echo '';
14 | print_r($request);
15 | echo '
';
16 |
17 | echo '';
18 | print_r($response);
19 | echo '
';
20 |
21 | $html = "Hello Swoole.
";
22 | $response->end($html);
23 | });
24 |
25 | $http->start();
--------------------------------------------------------------------------------
/example/member.php:
--------------------------------------------------------------------------------
1 | 13392);
17 |
18 | $method = 'authLogin';
19 | $params = array('username'=>'moxiaobai', 'password'=>'rxg622124');
20 | $data = array('class'=>$class, 'method'=>$method, 'params'=>$params);
21 |
22 | $buffer = JsonProtocol::encode($data);
23 |
24 | stream_socket_sendto($socket, $buffer);
25 |
26 | // 读取服务端返回的数据
27 | $result = stream_socket_recvfrom($socket, 65535);
28 |
29 |
30 | $rs = JsonProtocol::decode($result);
31 | echo '';
32 | print_r($rs);
33 | echo '
';
34 |
35 | // 关闭链接
36 | //fclose($socket);
37 |
38 |
39 |
40 | exit;
41 |
42 | class Client
43 | {
44 | private $client;
45 |
46 | public function __construct() {
47 | $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
48 |
49 | $this->client->on('Connect', array($this, 'onConnect'));
50 | $this->client->on('Receive', array($this, 'onReceive'));
51 | $this->client->on('Close', array($this, 'onClose'));
52 | $this->client->on('Error', array($this, 'onError'));
53 | }
54 |
55 | public function connect() {
56 | $fp = $this->client->connect("127.0.0.1", 9500 , 1);
57 | if( !$fp ) {
58 | echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";
59 | return;
60 | }
61 | }
62 |
63 | public function onConnect( $cli) {
64 | $class = 'Member';
65 | $method = 'userInfoByMid';
66 | $params = array('mid'=>13392);
67 | $data = array('class'=>$class, 'method'=>$method, 'params'=>$params);
68 |
69 | $buffer = JsonProtocol::encode($data);
70 | $cli->send( $buffer );
71 | }
72 |
73 | public function onReceive( $cli, $data ) {
74 | $rs = JsonProtocol::decode($data);
75 | echo '';
76 | print_r($rs);
77 | echo '
';
78 | }
79 |
80 | public function onClose( $cli) {
81 | echo "Client close connection\n";
82 | }
83 |
84 | public function onError() {
85 |
86 | }
87 |
88 | public function send($data) {
89 | $this->client->send( $data );
90 | }
91 |
92 | public function isConnected() {
93 | return $this->client->isConnected();
94 | }
95 | }
96 | $cli = new Client();
97 | $cli->connect();
98 |
--------------------------------------------------------------------------------
/example/mysql/async_mysql.php:
--------------------------------------------------------------------------------
1 | connect('127.0.0.1', 'root', '622124', 'crontab');
16 | $db->query("show tables", MYSQLI_ASYNC);
17 |
18 | swoole_event_add(swoole_get_mysqli_sock($db), function($__db_sock) {
19 | global $db;
20 |
21 | var_dump($__db_sock);
22 | $res = $db->reap_async_query();
23 | var_dump($res->fetch_all(MYSQLI_ASSOC));
24 | $db->query("show tables", MYSQLI_ASYNC);
25 |
26 | swoole_event_exit();
27 | });
28 |
29 | echo "Finish\n";
--------------------------------------------------------------------------------
/example/mysql/mysqlPool.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9306);
16 | $this->serv->set(array(
17 | 'worker_num' => 8,
18 | 'daemonize' => false,
19 | 'max_request' => 10000,
20 | 'dispatch_mode' => 3,
21 | 'debug_mode'=> 1 ,
22 | 'task_worker_num' => 8
23 | ));
24 | $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
25 | $this->serv->on('Connect', array($this, 'onConnect'));
26 | $this->serv->on('Receive', array($this, 'onReceive'));
27 | $this->serv->on('Close', array($this, 'onClose'));
28 | // bind callback
29 | $this->serv->on('Task', array($this, 'onTask'));
30 | $this->serv->on('Finish', array($this, 'onFinish'));
31 | $this->serv->start();
32 | }
33 |
34 | public function onWorkerStart( $serv , $worker_id) {
35 | echo "onWorkerStart\n";
36 | // 判定是否为Task Worker进程
37 | if( $worker_id >= $serv->setting['worker_num'] ) {
38 | $this->pdo = new PDO(
39 | "mysql:host=localhost;port=3306;dbname=Test",
40 | "root",
41 | "622124",
42 | array(
43 | PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8';",
44 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
45 | PDO::ATTR_PERSISTENT => true
46 | )
47 | );
48 | }
49 | }
50 |
51 | public function onConnect( $serv, $fd, $from_id ) {
52 | echo "Client {$fd} connect\n";
53 | }
54 |
55 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
56 | $sql = array(
57 | 'sql'=>'Insert into Test values( pid = ?, name = ?)',
58 | 'param' => array(
59 | 0 ,
60 | "'name'"
61 | ),
62 | 'fd' => $fd
63 | );
64 | $serv->task( json_encode($sql) );
65 | }
66 |
67 | public function onClose( $serv, $fd, $from_id ) {
68 | echo "Client {$fd} close connection\n";
69 | }
70 |
71 | public function onTask($serv,$task_id,$from_id, $data) {
72 | try{
73 | $sql = json_decode( $data , true );
74 |
75 | $statement = $this->pdo->prepare($sql['sql']);
76 | $statement->execute($sql['param']);
77 | $serv->send( $sql['fd'],"Insert");
78 | return true;
79 | } catch( PDOException $e ) {
80 | var_dump( $e );
81 | return false;
82 | }
83 | }
84 | public function onFinish($serv,$task_id, $data) {
85 | }
86 | }
87 |
88 | new MySQLPool();
--------------------------------------------------------------------------------
/example/process/server.php:
--------------------------------------------------------------------------------
1 | start();
18 | $workers[$pid] = $process;
19 | //echo "Master: new worker, PID=".$pid."\n";
20 | }
21 | master_async($workers);
22 | //master_sync($workers);
23 | //异步主进程
24 | function master_async($workers)
25 | {
26 | swoole_process::signal(SIGCHLD, function ($signo) use ($workers) {
27 | $ret = swoole_process::wait();
28 | $pid = $ret['pid'];
29 | unset($workers[$pid]);
30 | echo "Worker Exit, PID=" . $pid . PHP_EOL;
31 | });
32 | /**
33 | * @var $process swoole_process
34 | */
35 | foreach($workers as $pid => $process)
36 | {
37 | swoole_event_add($process->pipe, function($pipe) use ($process) {
38 | $recv = $process->read();
39 | if ($recv) echo "From Worker: " . $recv;
40 | });
41 | $process->write("hello worker[$pid]\n");
42 | }
43 | }
44 | //同步主进程
45 | function master_sync($workers)
46 | {
47 | foreach($workers as $pid => $process)
48 | {
49 | $process->write("hello worker[$pid]\n");
50 | echo "From Worker: ".$process->read();
51 | }
52 | }
53 | function child_sync(swoole_process $worker)
54 | {
55 | //echo "Worker: start. PID=".$worker->pid."\n";
56 | //recv data from master
57 | $recv = $worker->read();
58 | echo "From Master: $recv\n";
59 | //send data to master
60 | $worker->write("hello master\n");
61 | sleep(2);
62 | $worker->exit(0);
63 | }
64 | function child_async(swoole_process $worker)
65 | {
66 | //echo "Worker: start. PID=".$worker->pid."\n";
67 | //recv data from master
68 | $GLOBALS['worker'] = $worker;
69 | global $argv;
70 | $worker->name("{$argv[0]}: worker");
71 | swoole_process::signal(SIGTERM, function($signal_num) use ($worker) {
72 | echo "signal call = $signal_num, #{$worker->pid}\n";
73 | });
74 | swoole_event_add($worker->pipe, function($pipe) use($worker) {
75 | $recv = $worker->read();
76 | echo "From Master: $recv\n";
77 | $worker->write("hello master\n");
78 | });
79 | }
--------------------------------------------------------------------------------
/example/table/get.php:
--------------------------------------------------------------------------------
1 | get('350749960@qq.com'));
13 | var_dump($table->get('tianfenghan@qq.com'));
14 | var_dump($table->get('hello@qq.com'));
--------------------------------------------------------------------------------
/example/table/set.php:
--------------------------------------------------------------------------------
1 | start();
12 |
13 |
14 | //child
15 | function child1($worker){
16 | echo 111;
17 | }
--------------------------------------------------------------------------------
/example/task/client.php:
--------------------------------------------------------------------------------
1 | client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
15 |
16 | $this->client->on('Connect', array($this, 'onConnect'));
17 | $this->client->on('Receive', array($this, 'onReceive'));
18 | $this->client->on('Close', array($this, 'onClose'));
19 | $this->client->on('Error', array($this, 'onError'));
20 | }
21 |
22 | public function connect() {
23 | $fp = $this->client->connect("127.0.0.1", 9502 , 1);
24 | if( !$fp ) {
25 | echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";
26 | return;
27 | }
28 | }
29 |
30 | public function onConnect( $cli) {
31 | fwrite(STDOUT, "Enter Msg:");
32 | swoole_event_add(STDIN, function($fp){
33 | global $cli;
34 | fwrite(STDOUT, "Enter Msg:");
35 | $msg = trim(fgets(STDIN));
36 | $cli->send( $msg );
37 | });
38 | }
39 |
40 | public function onReceive( $cli, $data ) {
41 | echo "Get Message From Server: {$data}\n";
42 | }
43 |
44 | public function onClose( $cli) {
45 | echo "Client close connection\n";
46 | }
47 |
48 | public function onError() {
49 |
50 | }
51 |
52 | public function send($data) {
53 | $this->client->send( $data );
54 | }
55 |
56 | public function isConnected() {
57 | return $this->client->isConnected();
58 | }
59 | }
60 | $cli = new Client();
61 | $cli->connect();
--------------------------------------------------------------------------------
/example/task/server.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9502);
16 | $this->serv->set(array(
17 | 'worker_num' => 4,
18 | 'daemonize' => false,
19 | 'max_request' => 10000,
20 | 'dispatch_mode' => 2,
21 | 'debug_mode'=> 1,
22 | 'task_worker_num' => 8
23 | ));
24 |
25 | $this->serv->on('Start', array($this, 'onStart'));
26 | $this->serv->on('Connect', array($this, 'onConnect'));
27 | $this->serv->on('Receive', array($this, 'onReceive'));
28 | $this->serv->on('Close', array($this, 'onClose'));
29 |
30 | // bind task callback
31 | $this->serv->on('Task', array($this, 'onTask'));
32 | $this->serv->on('Finish', array($this, 'onFinish'));
33 | $this->serv->start();
34 | }
35 | public function onStart( $serv ) {
36 | cli_set_process_title('TaskMaster');
37 | echo "Start\n";
38 | }
39 |
40 | public function onConnect( $serv, $fd, $from_id ) {
41 | echo "工人: {$from_id}等待处理任务" . PHP_EOL;
42 | echo "Client {$fd} connect" . PHP_EOL;
43 | }
44 |
45 | public function onReceive( $serv, $fd, $from_id, $data ) {
46 | echo "工人: {$from_id} 开始处理任务" . PHP_EOL;
47 | echo "Get Message From Client {$fd}:{$data}\n";
48 |
49 | // send a task to task worker.
50 | $serv->task($data);
51 |
52 |
53 | echo "继续执行任务\n";
54 | }
55 |
56 | public function onClose( $serv, $fd, $from_id ) {
57 | echo "Client {$fd} close connection\n";
58 | }
59 |
60 | public function onTask($serv, $task_id, $from_id, $data) {
61 | echo "任务: {$task_id} 由任务工人: {$from_id} 执行\n";
62 | //echo "Data: {$data}\n";
63 |
64 | //处理业务逻辑
65 | for($i = 0 ; $i < 4 ; $i ++ ) {
66 | sleep(1);
67 | echo "Taks {$task_id} Handle {$i} times...\n";
68 | }
69 |
70 | return "$data -> OK";
71 | }
72 |
73 | public function onFinish($serv, $task_id, $data) {
74 | echo "Task {$task_id} finish\n";
75 | echo "Result: {$data}\n";
76 | }
77 | }
78 | $server = new Server();
--------------------------------------------------------------------------------
/example/timer/basic.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9503);
18 | $this->serv->set(array(
19 | 'worker_num' => 8,
20 | 'daemonize' => false,
21 | 'max_request' => 10000,
22 | 'dispatch_mode' => 2,
23 | 'debug_mode'=> 1 ,
24 | ));
25 |
26 | $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
27 | $this->serv->on('Connect', array($this, 'onConnect'));
28 | $this->serv->on('Receive', array($this, 'onReceive'));
29 | $this->serv->on('Close', array($this, 'onClose'));
30 |
31 | // bind callback
32 | $this->serv->on('Timer', array($this, 'onTimer'));
33 | $this->serv->start();
34 | }
35 |
36 | public function onWorkerStart( $serv , $worker_id) {
37 | // 在Worker进程开启时绑定定时器
38 | echo "onWorkerStart\n";
39 |
40 | // 只有当worker_id为0时才添加定时器,避免重复添加
41 | if( $worker_id == 0 ) {
42 | $serv->addtimer(60000);
43 | $serv->addtimer(300000);
44 | $serv->addtimer(600000);
45 | }
46 | }
47 |
48 | public function onConnect( $serv, $fd, $from_id ) {
49 | echo "Client {$fd} connect\n";
50 | }
51 |
52 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
53 | echo "Get Message From Client {$fd}:{$data}\n";
54 | }
55 |
56 | public function onClose( $serv, $fd, $from_id ) {
57 | echo "Client {$fd} close connection\n";
58 | }
59 |
60 | public function onTimer($serv, $interval) {
61 | switch( $interval ) {
62 | case 60000: { //
63 | echo "每分钟执行一次\n";
64 | break;
65 | }
66 | case 300000:{
67 | echo "每五分钟执行一次\n";
68 | break;
69 | }
70 | case 600000:{
71 | echo "每十分钟执行一次\n";
72 | break;
73 | }
74 | }
75 | }
76 | }
77 | new TimerServer();
--------------------------------------------------------------------------------
/example/websocket/server.php:
--------------------------------------------------------------------------------
1 | set(['worker_num' => 4, 'user'=>'www', 'group'=>'www', 'daemonize'=>0]);
13 |
14 | //handshake成功之后回调, 和js的onopen对应
15 | $http->on('open', function($response) {
16 | echo "handshake success" . PHP_EOL;
17 | //print_r($response);
18 | });
19 |
20 | //自定定握手规则,没有设置则用系统内置的(只支持version:13的)
21 | $http->on('handshake', function($request, $response) {
22 | print_r($request);
23 |
24 | if (!isset($request->header['sec-websocket-key'])) {
25 | //'Bad protocol implementation: it is not RFC6455.'
26 | $response->end();
27 | return false;
28 | }
29 |
30 | if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key']) || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))) {
31 | //Header Sec-WebSocket-Key is illegal;
32 | $response->end();
33 | return false;
34 | }
35 |
36 | $headers = array(
37 | 'Upgrade' => 'websocket',
38 | 'Connection' => 'Upgrade',
39 | 'Sec-WebSocket-Accept' => ''. base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)),
40 | 'Sec-WebSocket-Version' => '13',
41 | 'KeedpAlive' => 'off',
42 | );
43 |
44 | foreach($headers as $key => $val) {
45 | $response->header($key, $val);
46 | }
47 | $response->status(101);
48 | $response->end();
49 | });
50 |
51 | $http->on('message', function($response){
52 | var_dump($response);
53 |
54 | $response->message($response->data);
55 | });
56 |
57 | $http->on('request', function ($request, $response) {
58 | var_dump($request);
59 | $response->end("Hello Swoole. #".rand(1000, 9999)."
");
60 | });
61 |
62 | $http->on('close', function(){
63 | echo "on close" . PHP_EOL;
64 | });
65 |
66 | $http->start();
--------------------------------------------------------------------------------
/swoole-auto-complete-master/README.md:
--------------------------------------------------------------------------------
1 | swoole-auto-complete
2 | ====================
3 |
4 | [Swoole](https://github.com/matyhtf/swoole) 在IDE下自动识别类、函数、宏,自动补全函数名
5 |
6 | Swoole 结构,便于开发过程中查看文档,以及屏蔽IDE undefined 提示,便于快速查看函数用法。
7 |
8 | 当前适用Swoole版本: 1.6.10
9 |
10 | ### 使用方式
11 |
12 | 普通IDE:
13 |
14 | 开发Swoole项目同时,在IDE中打开/导入本文件即可。
15 |
16 | 如果IDE自带 Include Path 功能(如:PhpStorm),设置该文件路径即可。
17 |
18 | PhpStorm 另一种方法:
19 |
20 | WinRAR打开 /plugins/php/lib/php.jar 文件
21 |
22 | 复制 swoole.php 到路径:com\jetbrains\php\lang\psi\stubs\data\
23 |
24 | 当然你也可以直接使用已经做好的 [php.jar](https://github.com/EagleWu/swoole-auto-complete/tree/master/phpstorm) 直接覆盖即可。
25 |
26 | (php.jar 拷贝来源PhpStorm 7.1,其他版本如存在兼容性问题,请自行按上面方面进行处理,覆盖php.jar时注意备份)
27 |
28 | 保存文件,重启Phpstorm.
29 |
30 |
31 | PHPstorm使用演示(其他IDE同理):
32 |
33 | 
34 | 
35 | 
36 | 
37 |
38 | 使用php.jar包
39 |
40 | 
41 |
42 |
--------------------------------------------------------------------------------
/swoole-auto-complete-master/Swoole.php:
--------------------------------------------------------------------------------
1 | /plugins/php/lib/php.jar 文件
15 | * 复制 swoole.php 到路径:com\jetbrains\php\lang\psi\stubs\data\
16 | * 保存文件,重启Phpstorm.
17 | *
18 | * PS:替换前请备份php.jar 若发生错误便于恢复 :)
19 | *
20 | * Author:EagleWu
21 | * Date: 2014/01/17
22 | *
23 | */
24 |
25 |
26 | /**
27 | * swoole_server_set函数用于设置swoole_server运行时的各项参数
28 | *
29 | * @param $serv
30 | * @param $arguments
31 | */
32 | function swoole_server_set($serv, array $arguments) {}
33 |
34 |
35 | /**
36 | * 创建一个swoole server资源对象
37 | *
38 | * @param string $host 参数用来指定监听的ip地址,如127.0.0.1,或者外网地址,或者0.0.0.0监听全部地址
39 | * @param int $port 监听的端口,如9501,监听小于1024端口需要root权限,如果此端口被占用server-start时会失败
40 | * @param int $mode 运行的模式,swoole提供了3种运行模式,默认为多进程模式
41 | * @param string $sock_type 指定socket的类型,支持TCP/UDP、TCP6/UDP64种
42 | * @return int
43 | */
44 | function swoole_server_create($host, $port, $mode = SWOOLE_PROCESS, $sock_type = SWOOLE_SOCK_TCP) {}
45 |
46 |
47 | /**
48 | * 增加监听的端口
49 | *
50 | * 您可以混合使用UDP/TCP,同时监听内网和外网端口
51 | * 业务代码中可以通过调用swoole_connection_info来获取某个连接来自于哪个端口
52 | *
53 | * @param object $serv
54 | * @param string $host
55 | * @param int $port
56 | * @return void
57 | */
58 | function swoole_server_addlisten($serv, $host = '127.0.0.1', $port = 9502) {}
59 |
60 |
61 | /**
62 | * 设置定时器
63 | *
64 | * 第二个参数是定时器的间隔时间,单位为毫秒。
65 | * swoole定时器的最小颗粒是1毫秒,支持多个定时器。
66 | * 此函数可以用于worker进程中。或者通过swoole_server_set设置timer_interval来调整定时器最小间隔。
67 | *
68 | * 增加定时器后需要为Server设置onTimer回调函数,否则会造成严重错误。
69 | * 多个定时器都会回调此函数。
70 | * 在这个函数内需要自行switch,根据interval的值来判断是来自于哪个定时器。
71 | *
72 | * @param object $serv
73 | * @param int $interval
74 | * @return bool
75 | */
76 | function swoole_server_addtimer($serv, $interval) {}
77 |
78 |
79 | /**
80 | * 设置Server的事件回调函数
81 | *
82 | * 第一个参数是swoole的资源对象
83 | * 第二个参数是回调的名称, 大小写不敏感,具体内容参考回调函数列表
84 | * 第三个函数是回调的PHP函数,可以是字符串,数组,匿名函数。
85 | *
86 | * 设置成功后返回true。如果$event_name填写错误将返回false。
87 | *
88 | * onConnect/onClose/onReceive 这3个回调函数必须设置,其他事件回调函数可选。
89 | * 如果设定了timer定时器,onTimer事件回调函数也必须设置
90 | *
91 | * @param object $serv
92 | * @param string $event_name
93 | * @param is_callable $event_callback_function
94 | * @return bool
95 | */
96 | function swoole_server_handler($serv, $event_name, $event_callback_function) {}
97 |
98 |
99 | /**
100 | * 启动server,监听所有TCP/UDP端口
101 | *
102 | * 启动成功后会创建worker_num+2个进程。主进程+Manager进程+n*Worker进程。
103 | * 启动失败扩展内会抛出致命错误,请检查php error_log的相关信息。errno={number}是标准的Linux Errno,可参考相关文档。
104 | * 如果开启了log_file设置,信息会打印到指定的Log文件中。
105 | *
106 | * 如果想要在开机启动时,自动运行你的Server,可以在/etc/rc.local文件中加入:
107 | *
108 | * /usr/bin/php /data/webroot/www.swoole.com/server.php
109 | *
110 | * 常见的错误有及拍错方法:
111 | *
112 | * 1、bind端口失败,原因是其他进程已占用了此端口
113 | * 2、未设置必选回调函数,启动失败
114 | * 3、php有代码致命错误,请检查php的错误信息
115 | * 4、执行ulimit -c unlimited,打开core dump,查看是否有段错误
116 | * 5、关闭daemonize,关闭log,使错误信息可以打印到屏幕
117 | *
118 | * @param object $serv
119 | * @return bool
120 | */
121 | function swoole_server_start($serv) {}
122 |
123 |
124 | /**
125 | * 平滑重启Server
126 | *
127 | * 一台繁忙的后端服务器随时都在处理请求,如果管理员通过kill进程方式来终止/重启服务器程序,可能导致刚好代码执行到一半终止。
128 | * 这种情况下会产生数据的不一致。如交易系统中,支付逻辑的下一段是发货,假设在支付逻辑之后进程被终止了。
129 | * 会导致用户支付了货币,但并没有发货,后果非常严重。
130 | *
131 | * Swoole提供了柔性终止/重启的机制,管理员只需要向SwooleServer发送特定的信号,Server的worker进程可以安全的结束。
132 | *
133 | * SIGTREM: 向主进程发送此信号服务器将安全终止
134 | * SIGUSR1: 向管理进程发送SIGUSR1信号,将平稳地restart所有worker进程,在PHP代码中可以调用swoole_server_reload($serv)完成此操作
135 | *
136 | * @param object $serv
137 | * @return void
138 | */
139 | function swoole_server_reload($serv) {}
140 |
141 |
142 | /**
143 | * 关闭客户端连接
144 | *
145 | * Server主动close连接,也一样会触发onClose事件。
146 | * 不要在close之后写清理逻辑,应当放置到onClose回调中处理。
147 | *
148 | * @param object $serv
149 | * @param int $fd
150 | * @param int $from_id
151 | * @return bool
152 | */
153 | function swoole_server_close($serv, $fd, $from_id = 0) {}
154 |
155 |
156 | /**
157 | * 向客户端发送数据
158 | *
159 | * $data的长度可以是任意的。扩展函数内会进行切分。
160 | * 如果是UDP协议,会直接在worker进程内发送数据包。
161 | * 发送成功会返回true,如果连接已被关闭或发送失败会返回false.
162 | *
163 | * @param object $serv
164 | * @param int $fd
165 | * @param string $data
166 | * @param int $from_id
167 | * @return bool
168 | */
169 | function swoole_server_send($serv, $fd, $data, $from_id = 0) {}
170 |
171 |
172 | /**
173 | * 获取客户端连接的信息
174 | *
175 | * 返回数组含义:
176 | * from_id 来自哪个poll线程
177 | * from_fd 来自哪个server socket
178 | * from_port 来自哪个Server端口
179 | * remote_port 客户端连接的端口
180 | * remote_ip 客户端连接的ip
181 | *
182 | * 以下 v1.6.10 增加
183 | * connect_time 连接时间
184 | * last_time 最后一次发送数据的时间
185 | *
186 | * @param object $serv
187 | * @param int $fd
188 | * @return array on success or false on failure.
189 | */
190 | function swoole_connection_info($serv, $fd) {}
191 |
192 |
193 | /**
194 | * 遍历当前Server所有的客户端连接
195 | *
196 | * 此函数接受3个参数,第一个参数是server的资源对象,第二个参数是起始fd,第三个参数是每页取多少条,最大不得超过100。
197 | * 调用成功将返回一个数字索引数组,元素是取到的$fd。
198 | * 数组会按从小到大排序,最后一个$fd作为新的start_fd再次尝试获取。
199 | *
200 | * @param object $serv
201 | * @param int $start_fd
202 | * @param int $pagesize
203 | * @return array on success or false on failure
204 | */
205 | function swoole_connection_list($serv, $start_fd = 0, $pagesize = 10) {}
206 |
207 |
208 | /**
209 | * 设置进程的名称
210 | *
211 | * 修改进程名称后,通过ps命令看到的将不再是php your_file.php。而是设定的字符串。
212 | * 此函数接受一个字符串参数。
213 | * 此函数与PHP5.5提供的cli_set_process_title功能是相同的,但swoole_set_process_name可用于PHP5.2之上的任意版本。
214 | *
215 | * @param string $name
216 | * @return void
217 | */
218 | function swoole_set_process_name($name) {}
219 |
220 |
221 | /**
222 | * 将Socket加入到swoole的reactor事件监听中
223 | *
224 | * 此函数可以用在Server或Client模式下
225 | *
226 | * 参数1为socket的文件描述符;
227 | * 参数2为回调函数,可以是字符串函数名、对象+方法、类静态方法或匿名函数,当此socket可读是回调制定的函数。
228 | *
229 | * Server程序中会增加到server socket的reactor中。
230 | * Client程序中,如果是第一次调用此函数会自动创建一个reactor,并添加此socket,程序将在此处进行wait。
231 | * swoole_event_add函数之后的代码不会执行。当调用swoole_event_exit才会停止wait,程序继续向下执行。
232 | * 第二次调用只增加此socket到reactor中,开始监听事件
233 | *
234 | * @param int $sock
235 | * @param is_callable $callback
236 | * @return bool
237 | */
238 | function swoole_event_add($sock, $read_callback = null, $write_callback = null, $flag = null) {}
239 |
240 | /**
241 | * 修改socket的事件设置
242 | * 可以修改可读/可写事件的回调设置和监听的事件类型
243 | *
244 | * @param $sock
245 | * @param $read_callback
246 | * @param null $write_callback
247 | * @param null $flag
248 | */
249 | function swoole_event_set($sock, $read_callback = null, $write_callback = null, $flag = null) {}
250 |
251 | /**
252 | * 从reactor中移除监听的Socket
253 | *
254 | * swoole_event_del应当与 swoole_event_add 成对使用
255 | *
256 | * @param int $sock
257 | * @return bool
258 | */
259 | function swoole_event_del($sock) {}
260 |
261 |
262 | /**
263 | * 退出事件轮询
264 | *
265 | * @return void
266 | */
267 | function swoole_event_exit() {}
268 |
269 | /**
270 | * 获取MySQLi的socket文件描述符
271 | *
272 | * 可将mysql的socket增加到swoole中,执行异步MySQL查询。
273 | * 如果想要使用异步MySQL,需要在编译swoole时制定--enable-async-mysql
274 | * swoole_get_mysqli_sock仅支持mysqlnd驱动,php5.4以下版本不支持此特性
275 | *
276 | * @param resource $db mysqli
277 | * @return int
278 | */
279 | function swoole_get_mysqli_sock($db) {}
280 |
281 |
282 | /**
283 | * 投递异步任务到task_worker池中
284 | *
285 | * 此函数会立即返回,worker进程可以继续处理新的请求。
286 | * 此功能用于将慢速的任务异步地去执行,比如一个聊天室服务器,可以用它来进行发送广播。
287 | * 当任务完成时,在task_worker中调用swoole_server_finish($serv, "finish");
288 | * 告诉worker进程此任务已完成。当然swoole_server_finish是可选的。
289 | *
290 | * 发送的$data必须为字符串,如果是数组或对象,请在业务代码中进行serialize处理,并在onTask/onFinish中进行unserialize。
291 | * $data可以为二进制数据,最大长度为8K。字符串可以使用gzip进行压缩。
292 | *
293 | * 使用swoole_server_task必须为Server设置onTask和onFinish回调,
294 | * 否则swoole_server_start会失败。此回调函数会在task_worker进程中被调用。
295 | *
296 | * 函数会返回一个$task_id数字,表示此任务的ID。如果有finish回应,onFinish回调中会携带$task_id参数。
297 | *
298 | * task_worker的数量在swoole_server_set参数中调整,如task_worker_num => 64,表示启动64个进程来接收异步任务。
299 | * swoole_server_task和swoole_server_finish可发送$data的长度最大不得超过8K,此参数受SW_BUFFER_SIZE宏控制。
300 | *
301 | * @param object $serv
302 | * @param string $data
303 | * @return int $task_id
304 | */
305 | function swoole_server_task($serv, $data) {}
306 |
307 |
308 | /**
309 | * task_worker进程中通知worker进程,投递的任务已完成
310 | *
311 | * 此函数可以传递结果数据给worker进程
312 | * 使用swoole_server_finish函数必须为Server设置onFinish回调函数。此函数只可用于task_worker进程的onTask回调中
313 | * swoole_server_finish是可选的。如果worker进程不关心任务执行的结果,可以不调用此函数
314 | *
315 | * @param object $serv
316 | * @param string $response
317 | * @return void
318 | */
319 | function swoole_server_finish($serv, $response) {}
320 |
321 |
322 | /**
323 | * 删除定时器
324 | *
325 | * $interval 参数为定时器的间隔时间
326 | * 根据定时器时间区分不同的定时器
327 | *
328 | * @param object $serv
329 | * @param int $interval
330 | * @return void
331 | */
332 | function swoole_server_deltimer($serv, $interval) {}
333 |
334 |
335 | /**
336 | * 关闭服务器
337 | *
338 | * 此函数可以用在worker进程内。
339 | *
340 | * @param object $serv
341 | * @return void
342 | */
343 | function swoole_server_shutdown($serv) {}
344 |
345 |
346 | /**
347 | * 投递堵塞任务到task进程池
348 | *
349 | * taskwait与task方法作用相同,用于投递一个异步的任务到task进程池去执行。
350 | * 与task不同的是taskwait是阻塞等待的,直到任务完成或者超时返回。
351 | * $result为任务执行的结果,由$serv->finish函数发出。如果此任务超时,这里会返回false。
352 | *
353 | * taskwait是阻塞接口,如果你的Server是全异步的请不要使用它
354 | *
355 | * @param string $task_data
356 | * @param float $timeout
357 | * @return string
358 | */
359 | function swoole_server_taskwait($task_data, $timeout = 0.5) {}
360 |
361 | /**
362 | * 进行事件轮询
363 | *
364 | * PHP5.4之前的版本没有在ZendAPI中加入注册shutdown函数。所以swoole无法在脚本结尾处自动进行事件轮询。
365 | * 低于5.4的版本,需要在你的PHP脚本结尾处加swoole_event_wait函数,使脚本开始进行事件轮询。
366 | *
367 | * 5.4或更高版本不需要加此函数。
368 | *
369 | * @return void
370 | */
371 | function swoole_event_wait() {}
372 |
373 | /**
374 | * 添加定时器,可用于客户端环境和fpm中
375 | * @param $interval
376 | * @param $callback
377 | */
378 | function swoole_timer_add($interval, $callback) {}
379 |
380 | /**
381 | * 删除定时器
382 | * @param $interval
383 | * @param $callback
384 | */
385 | function swoole_timer_del($interval) {}
386 |
387 | /**
388 | * swoole_client
389 | */
390 | class swoole_client {
391 |
392 | /**
393 | * 函数执行错误会设置该变量
394 | *
395 | * @var
396 | */
397 | public $errCode;
398 |
399 |
400 | /**
401 | * socket的文件描述符
402 | *
403 | * PHP代码中可以使用:
404 | * $sock = fopen("php://fd/".$swoole_client->sock);
405 | *
406 | * 将swoole_client的socket转换成一个stream socket。可以调用fread/fwrite/fclose等函数进程操作。
407 | * swoole_server中的$fd不能用此方法转换,因为$fd只是一个数字,$fd文件描述符属于主进程
408 | * $swoole_client->sock可以转换成int作为数组的key.
409 | *
410 | * @var int
411 | */
412 | public $sock;
413 |
414 |
415 | /**
416 | * swoole_client构造函数
417 | *
418 | * @param int $sock_type 指定socket的类型,支持TCP/UDP、TCP6/UDP64种
419 | * @param int $sync_type SWOOLE_SOCK_SYNC/SWOOLE_SOCK_ASYNC 同步/异步
420 | */
421 | public function __construct($sock_type, $sync_type = SWOOLE_SOCK_SYNC) {}
422 |
423 |
424 | /**
425 | * 连接到远程服务器
426 | *
427 | * @param string $host 是远程服务器的地址 v1.6.10+ 支持填写域名 Swoole会自动进行DNS查询
428 | * @param int $port 是远程服务器端口
429 | * @param float $timeout 是网络IO的超时,单位是s,支持浮点数。默认为0.1s,即100ms
430 | * @param int $flag 参数在UDP类型时表示是否启用udp_connect。设定此选项后将绑定$host与$port,此UDP将会丢弃非指定host/port的数据包。
431 | * 在send/recv前必须使用swoole_client_select来检测是否完成了连接
432 | * @return bool
433 | */
434 | public function connect($host, $port, $timeout = 0.1, $flag = 0) {}
435 |
436 |
437 | /**
438 | * 向远程服务器发送数据
439 | *
440 | * 参数为字符串,支持二进制数据。
441 | * 成功发送返回的已发数据长度
442 | * 失败返回false,并设置$swoole_client->errCode
443 | *
444 | * @param string $data
445 | * @return bool
446 | */
447 | public function send($data) {}
448 |
449 |
450 | /**
451 | * 从服务器端接收数据
452 | *
453 | * 如果设定了$waitall就必须设定准确的$size,否则会一直等待,直到接收的数据长度达到$size
454 | * 如果设置了错误的$size,会导致recv超时,返回 false
455 | * 调用成功返回结果字符串,失败返回 false,并设置$swoole_client->errCode属性
456 | *
457 | * @param int $size 接收数据的最大长度
458 | * @param bool $waitall 是否等待所有数据到达后返回
459 | * @return string
460 | */
461 | public function recv($size = 65535, $waitall = false) {}
462 |
463 | /**
464 | * 关闭远程连接
465 | *
466 | * swoole_client对象在析构时会自动close
467 | *
468 | * @return bool
469 | */
470 | public function close() {}
471 |
472 | /**
473 | * 注册异步事件回调函数
474 | *
475 | * @return bool
476 | */
477 | public function on($event_name, $callback_function){}
478 | }
479 |
480 | class swoole_server
481 | {
482 | /**
483 | * 主进程PID
484 | * @var int
485 | */
486 | public $master_pid;
487 | /**
488 | * 管理进程PID
489 | * @var int
490 | */
491 | public $manager_pid;
492 | function __construct($host, $port, $mode = 3, $tcp_or_udp = 1){}
493 |
494 | /**
495 | * 设置事件回调函数
496 | * @param $event_name
497 | * @param $callback_function
498 | */
499 | function on($event_name, $callback_function){}
500 |
501 | /**
502 | * 设置运行时参数
503 | * @param array $config
504 | */
505 | function set(array $config){}
506 |
507 | /**
508 | * 启动服务器
509 | */
510 | function start(){}
511 |
512 | /**
513 | * 发送数据到客户端连接
514 | * @param int $fd
515 | * @param $response
516 | * @param int $from_id
517 | * @return bool
518 | */
519 | function send(int $fd, $response, $from_id = 0){}
520 |
521 | /**
522 | * 关闭连接
523 | * @param int $fd
524 | * @param int $from_id
525 | */
526 | function close(int $fd, $from_id = 0){}
527 |
528 | /**
529 | * 投递任务到task_worker进程去执行,并阻塞等待结果返回
530 | * @param string $task_data
531 | * @param float $timeout
532 | * @return string
533 | */
534 | function taskwait(string $task_data, float $timeout = 0.5){}
535 |
536 | /**
537 | * 投递一个异步任务
538 | * @param string $task_data
539 | * @param float $timeout
540 | * @return int
541 | */
542 | function task(string $task_data, int $dst_worker_id = -1){}
543 |
544 | /**
545 | * 任务完成后发送结果到对应的worker进程
546 | * @param string $task_data
547 | */
548 | function finish(string $task_data){}
549 |
550 | /**
551 | * 进行心跳检查,返回心跳超过约定时间的连接
552 | */
553 | function heartbeat(){}
554 |
555 | /**
556 | * 返回连接的信息,支持TCP/UDP
557 | * array (
558 | * 'from_id' => 0,
559 | * 'from_fd' => 12,
560 | * 'connect_time' => 1392895129,
561 | * 'last_time' => 1392895137,
562 | * 'from_port' => 9501,
563 | * 'remote_port' => 48918,
564 | * 'remote_ip' => '127.0.0.1',
565 | * )
566 | * @return array | bool
567 | */
568 | public function connection_info($fd, $from_id = -1){}
569 |
570 | /**
571 | * 遍历所有Server的TCP连接,这个接口是基于共享内存的,可以得到所有worker进程内的连接
572 | *
573 | * @return array | bool
574 | */
575 | public function connection_list($start_fd = -1, $pagesize = 100){}
576 |
577 | /**
578 | * 重启所有worker进程
579 | * @return null
580 | */
581 | public function reload(){}
582 |
583 | /**
584 | * 关闭服务器
585 | * @return null
586 | */
587 | public function shutdown(){}
588 |
589 | /**
590 | * 增加监听端口
591 | * @param $host
592 | * @param $port
593 | * @param $type
594 | */
595 | public function addlistener($host, $port, $type = SWOOLE_SOCK_TCP){}
596 |
597 | /**
598 | * 增加定时器
599 | * @param $interval
600 | */
601 | public function addtimer($interval){}
602 |
603 | /**
604 | * 删除定时器
605 | * @param $interval
606 | */
607 | public function deltimer($interval){}
608 | }
609 |
610 |
611 | /**
612 | * Class swoole_lock
613 | */
614 | class swoole_lock {
615 |
616 | /**
617 | * @param int $type 为锁的类型
618 | * @param string $lockfile 当类型为SWOOLE_FILELOCK时必须传入,指定文件锁的路径
619 | * 注意每一种类型的锁支持的方法都不一样。如读写锁、文件锁可以支持 $lock->lock_read()。
620 | * 另外除文件锁外,其他类型的锁必须在父进程内创建,这样fork出的子进程之间才可以互相争抢锁。
621 | */
622 | public function __construct($type, $lockfile = NULL) {}
623 |
624 |
625 | /**
626 | * 加锁操作
627 | *
628 | * 如果有其他进程持有锁,那这里将进入阻塞,直到持有锁的进程unlock。
629 | */
630 | public function lock() {}
631 |
632 |
633 | /**
634 | * 加锁操作
635 | *
636 | * 与lock方法不同的是,trylock()不会阻塞,它会立即返回。
637 | * 当返回false时表示抢锁失败,有其他进程持有锁。返回true时表示加锁成功,此时可以修改共享变量。
638 | *
639 | * SWOOlE_SEM 信号量没有trylock方法
640 | */
641 | public function trylock() {}
642 |
643 |
644 | /**
645 | * 释放锁
646 | */
647 | public function unlock() {}
648 |
649 |
650 | /**
651 | * 阻塞加锁
652 | *
653 | * lock_read方法仅可用在读写锁(SWOOLE_RWLOCK)和文件锁(SWOOLE_FILELOCK)中,表示仅仅锁定读。
654 | * 在持有读锁的过程中,其他进程依然可以获得读锁,可以继续发生读操作。但不能$lock->lock()或$lock->trylock(),这两个方法是获取独占锁的。
655 | *
656 | * 当另外一个进程获得了独占锁(调用$lock->lock/$lock->trylock)时,$lock->lock_read()会发生阻塞,直到持有锁的进程释放。
657 | */
658 | public function lock_read() {}
659 |
660 |
661 | /**
662 | * 非阻塞加锁
663 | *
664 | * 此方法与lock_read相同,但是非阻塞的。调用会立即返回,必须检测返回值以确定是否拿到了锁。
665 | */
666 | public function trylock_read() {}
667 | }
668 |
669 |
670 | /**
671 | * IO事件循环
672 | *
673 | *
674 | * swoole_client的并行处理中用了select来做IO事件循环。为什么要用select呢?
675 | * 因为client一般不会有太多连接,而且大部分socket会很快接收到响应数据。
676 | * 在少量连接的情况下select比epoll性能更好,另外select更简单。
677 | *
678 | * $read,$write,$error分别是可读/可写/错误的文件描述符。
679 | * 这3个参数必须是数组变量的引用。数组的元素必须为swoole_client对象。
680 | * $timeout参数是select的超时时间,单位为秒,接受浮点数。
681 | *
682 | * 调用成功后,会返回事件的数量,并修改$read/$write/$error数组。
683 | * 使用foreach遍历数组,然后执行$item->recv/$item->send来收发数据。
684 | * 或者调用$item->close()或unset($item)来关闭socket。
685 | *
686 | *
687 | * @param array $read 可读
688 | * @param array $write 可写
689 | * @param array $error 错误
690 | * @param float $timeout
691 | */
692 | function swoole_client_select(array &$read, array &$write, array &$error, float $timeout) {}
693 |
694 | /**
695 | * swoole进程管理类
696 | * 内置IPC通信支持,子进程和主进程之间可以方便的通信
697 | * 支持标准输入输出重定向,子进程内echo,会发送到管道中,而不是输出屏幕
698 | * Class swoole_process
699 | */
700 | class swoole_process
701 | {
702 | /**
703 | * 进程的PID
704 | * @var int
705 | */
706 | public $pid;
707 |
708 | /**
709 | * 管道PIPE
710 | * @var int
711 | */
712 | public $pipe;
713 |
714 | /**
715 | * @param mixed $callback 子进程的回调函数
716 | * @param bool $redirect_stdin_stdout 是否重定向标准输入输出
717 | * @param bool $create_pipe 是否创建管道
718 | */
719 | function __construct($callback, $redirect_stdin_stdout = false, $create_pipe = true){}
720 |
721 | /**
722 | * 向管道内写入数据
723 | * @param string $data
724 | */
725 | function write($data){}
726 |
727 | /**
728 | * 从管道内读取数据
729 | * @param int $buffer_len 最大读取的长度
730 | * @return string
731 | */
732 | function read($buffer_len = 8192){}
733 |
734 | /**
735 | * 退出子进程,实际函数名为exit,IDE将exit识别为关键词了,会有语法错误,所以这里叫_exit
736 | */
737 | function _exit($code = 0){}
738 |
739 | /**
740 | * 阻塞等待子进程退出,并回收
741 | * 成功返回一个数组包含子进程的PID和退出状态码
742 | * 如array('code' => 0, 'pid' => 15001),失败返回false
743 | * @return false | array
744 | */
745 | static function wait(){}
746 |
747 | /**
748 | * 启动子进程
749 | * @return int
750 | */
751 | function start(){}
752 | }
753 |
754 | define('SWOOLE_VERSION', '1.6.9'); //当前Swoole的版本号
755 |
756 | /**
757 | * new swoole_server 构造函数参数
758 | */
759 | define('SWOOLE_BASE', 1); //使用Base模式,业务代码在Reactor中直接执行
760 | define('SWOOLE_THREAD', 2); //使用线程模式,业务代码在Worker线程中执行
761 | define('SWOOLE_PROCESS', 3); //使用进程模式,业务代码在Worker进程中执行
762 |
763 | /**
764 | * new swoole_client 构造函数参数
765 | */
766 | define('SWOOLE_SOCK_TCP', 1); //创建tcp socket
767 | define('SWOOLE_SOCK_TCP6', 3); //创建tcp ipv6 socket
768 | define('SWOOLE_SOCK_UDP', 2); //创建udp socket
769 | define('SWOOLE_SOCK_UDP6', 4); //创建udp ipv6 socket
770 |
771 | define('SWOOLE_TCP', 1); //创建tcp socket
772 | define('SWOOLE_TCP6', 2); //创建tcp ipv6 socket
773 | define('SWOOLE_UDP', 3); //创建udp socket
774 | define('SWOOLE_UDP6', 4); //创建udp ipv6 socket
775 | define('SWOOLE_UNIX_DGRAM', 5);
776 | define('SWOOLE_UNIX_STREAM', 6);
777 |
778 | define('SWOOLE_SOCK_SYNC', 0); //同步客户端
779 | define('SWOOLE_SOCK_ASYNC', 1); //异步客户端
780 |
781 | define('SWOOLE_SYNC', 0); //同步客户端
782 | define('SWOOLE_ASYNC', 1); //异步客户端
783 |
784 | /**
785 | * new swoole_lock构造函数参数
786 | */
787 | define('SWOOLE_FILELOCK', 2); //创建文件锁
788 | define('SWOOLE_MUTEX', 3); //创建互斥锁
789 | define('SWOOLE_RWLOCK', 1); //创建读写锁
790 | define('SWOOLE_SPINLOCK', 5); //创建自旋锁
791 | define('SWOOLE_SEM', 4); //创建信号量
792 |
793 | define('SWOOLE_EVENT_WRITE', 1);
794 | define('SWOOLE_EVENT_READ', 2);
795 |
--------------------------------------------------------------------------------
/swoole-auto-complete-master/phpstorm/php.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moxiaobai/swoole-game/920f9ff4cb26c3d1ce686e52ff69443c99e6f79e/swoole-auto-complete-master/phpstorm/php.jar
--------------------------------------------------------------------------------