From 6f37c662fbec19e32039f5a85f083e0b4f7dacd5 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 22 May 2016 12:35:06 +0800 Subject: [PATCH 0001/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 19d67d7d7..a71b70538 100644 --- a/Worker.php +++ b/Worker.php @@ -717,9 +717,9 @@ protected static function reinstallSignal() pcntl_signal(SIGUSR2, SIG_IGN, false); // reinstall stop signal handler self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); - // uninstall reload signal handler + // reinstall reload signal handler self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); - // uninstall status signal handler + // reinstall status signal handler self::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); } From 3f8a1dfc4009ef81ec6d6a3a2655ea46918520dc Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 24 May 2016 22:18:03 +0800 Subject: [PATCH 0002/1216] log exception --- Connection/AsyncTcpConnection.php | 8 ++++---- Connection/TcpConnection.php | 31 +++++++++++++++++-------------- Events/Ev.php | 10 ++++++---- Events/Event.php | 6 ++++-- Events/Libevent.php | 6 ++++-- Protocols/Websocket.php | 17 +++++++++-------- Protocols/Ws.php | 18 ++++++++++-------- WebServer.php | 4 ++-- Worker.php | 22 +++++++++++----------- 9 files changed, 67 insertions(+), 55 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e546dc1f2..73829e9e7 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -109,10 +109,10 @@ protected function emitError($code, $msg) try { call_user_func($this->onError, $this, $code, $msg); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -151,10 +151,10 @@ public function checkConnection($socket) try { call_user_func($this->onConnect, $this); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 928bb6278..190522712 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -259,10 +259,10 @@ public function send($send_buffer, $raw = false) try { call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'client closed'); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -283,7 +283,10 @@ public function send($send_buffer, $raw = false) try { call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { - echo $e; + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); exit(250); } } @@ -418,13 +421,13 @@ public function baseRead($socket, $check_eof = true) continue; } try { - // Decode request buffer before Emiting onMessage callback. + // Decode request buffer before Emitting onMessage callback. call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -444,10 +447,10 @@ public function baseRead($socket, $check_eof = true) try { call_user_func($this->onMessage, $this, $this->_recvBuffer); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } // Clean receive buffer. @@ -470,10 +473,10 @@ public function baseWrite() try { call_user_func($this->onBufferDrain, $this); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -567,10 +570,10 @@ protected function checkBufferIsFull() try { call_user_func($this->onBufferFull, $this); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -603,10 +606,10 @@ public function destroy() try { call_user_func($this->onClose, $this); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } diff --git a/Events/Ev.php b/Events/Ev.php index 83cb66c10..acc1a3613 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -12,6 +12,8 @@ */ namespace Workerman\Events; +use Workerman\Worker; + /** * ev eventloop */ @@ -56,10 +58,10 @@ public function add($fd, $flag, $func, $args = null) try { call_user_func($func, $fd); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } }; @@ -138,10 +140,10 @@ public function timerCallback($event) try { call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } diff --git a/Events/Event.php b/Events/Event.php index 485c0bd44..2d85aafee 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -13,6 +13,8 @@ */ namespace Workerman\Events; +use Workerman\Worker; + /** * libevent eventloop */ @@ -155,10 +157,10 @@ public function timerCallback($fd, $what, $param) try { call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } diff --git a/Events/Libevent.php b/Events/Libevent.php index 9f2ded59d..5644bf1e7 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -13,6 +13,8 @@ */ namespace Workerman\Events; +use Workerman\Worker; + /** * libevent eventloop */ @@ -170,10 +172,10 @@ protected function timerCallback($_null1, $_null2, $timer_id) try { call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 145608a44..2eabc7c3d 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; +use Workerman\Worker; /** * WebSocket protocol. @@ -90,10 +91,10 @@ public static function input($buffer, ConnectionInterface $connection) try { call_user_func($connection->onWebSocketClose, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } // Close connection. @@ -108,10 +109,10 @@ public static function input($buffer, ConnectionInterface $connection) try { call_user_func($connection->onWebSocketPing, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } // Send pong package to client. @@ -135,10 +136,10 @@ public static function input($buffer, ConnectionInterface $connection) try { call_user_func($connection->onWebSocketPong, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -346,10 +347,10 @@ protected static function dealHandshake($buffer, $connection) try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } $_GET = $_COOKIE = $_SERVER = array(); diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 9bac6ece2..d33682759 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -1,6 +1,8 @@ onWebSocketClose, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } // Close connection. @@ -94,10 +96,10 @@ public static function input($buffer, $connection) try { call_user_func($connection->onWebSocketPing, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } // Send pong package to client. @@ -120,10 +122,10 @@ public static function input($buffer, $connection) try { call_user_func($connection->onWebSocketPong, $connection); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } @@ -319,10 +321,10 @@ public static function dealHandshake($buffer, $connection) try { call_user_func($connection->onWebSocketConnect, $connection, substr($buffer, 0, $handshake_respnse_length)); } catch (\Exception $e) { - echo $e; + Worker::log($e); exit(250); } catch (\Error $e) { - echo $e; + Worker::log($e); exit(250); } } diff --git a/WebServer.php b/WebServer.php index eba9013a6..543610feb 100644 --- a/WebServer.php +++ b/WebServer.php @@ -108,10 +108,10 @@ public function onWorkerStart() try { call_user_func($this->_onWorkerStart, $this); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } diff --git a/Worker.php b/Worker.php index a71b70538..7b9e50bdc 100644 --- a/Worker.php +++ b/Worker.php @@ -1110,10 +1110,10 @@ protected static function reload() try { call_user_func($worker->onWorkerReload, $worker); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } @@ -1291,7 +1291,7 @@ protected static function getErrorType($type) * @param string $msg * @return void */ - protected static function log($msg) + public static function log($msg) { $msg = $msg . "\n"; if (!self::$daemonize) { @@ -1460,10 +1460,10 @@ public function run() try { call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } @@ -1484,10 +1484,10 @@ public function stop() try { call_user_func($this->onWorkerStop, $this); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } @@ -1527,10 +1527,10 @@ public function acceptConnection($socket) try { call_user_func($this->onConnect, $connection); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } @@ -1560,10 +1560,10 @@ public function acceptUdpConnection($socket) try { call_user_func($this->onMessage, $connection, $recv_buffer); } catch (\Exception $e) { - echo $e; + self::log($e); exit(250); } catch (\Error $e) { - echo $e; + self::log($e); exit(250); } } From b46b34111130de3f699c2efd16d70827620f5dfe Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 24 May 2016 22:47:14 +0800 Subject: [PATCH 0003/1216] log pid --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 7b9e50bdc..7ca750e2a 100644 --- a/Worker.php +++ b/Worker.php @@ -1297,7 +1297,7 @@ public static function log($msg) if (!self::$daemonize) { echo $msg; } - file_put_contents(self::$logFile, date('Y-m-d H:i:s') . " " . $msg, FILE_APPEND | LOCK_EX); + file_put_contents(self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** From 2664114658ffa5eb0e5330d588ace4bfbb9b8a8e Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 24 May 2016 22:49:15 +0800 Subject: [PATCH 0004/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 7ca750e2a..812003db6 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.2'; + const VERSION = '3.3.3'; /** * Status starting. From 2424fb8dc1eb58385b88add56bbbc11c1367b9cc Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Jun 2016 10:42:21 +0800 Subject: [PATCH 0005/1216] Update WebServer.php --- WebServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebServer.php b/WebServer.php index 543610feb..df0481c05 100644 --- a/WebServer.php +++ b/WebServer.php @@ -162,7 +162,7 @@ public function onMessage($connection) return; } - $workerman_path = $workerman_url_info['path']; + $workerman_path = isset($workerman_url_info['path']) ? $workerman_url_info['path'] : '/'; $workerman_path_info = pathinfo($workerman_path); $workerman_file_extension = isset($workerman_path_info['extension']) ? $workerman_path_info['extension'] : ''; From feb3937a4e1cf637a78f506a0443cd24179672e6 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 3 Jun 2016 11:44:19 +0800 Subject: [PATCH 0006/1216] support ipv6 --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 190522712..6b7780193 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -307,7 +307,7 @@ public function getRemoteIp() { $pos = strrpos($this->_remoteAddress, ':'); if ($pos) { - return substr($this->_remoteAddress, 0, $pos); + return trim(substr($this->_remoteAddress, 0, $pos), '[]'); } return ''; } From fa3d232d7f55f5b76e46f7208b951b051a9847e7 Mon Sep 17 00:00:00 2001 From: technofiend <2281551151@qq.com> Date: Sat, 11 Jun 2016 09:48:37 +0800 Subject: [PATCH 0007/1216] add client request ajax header to php header --- Protocols/Http.php | 3 +++ 1 file changed, 3 insertions(+) mode change 100644 => 100755 Protocols/Http.php diff --git a/Protocols/Http.php b/Protocols/Http.php old mode 100644 new mode 100755 index 5ae77464d..53bf3e1da --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -156,6 +156,9 @@ public static function decode($recv_buffer, TcpConnection $connection) $http_post_boundary = '--' . $match[1]; } break; + case 'x-requested-with': + $_SERVER["HTTP_X_REQUESTED_WITH"] = $value; + break; } } From 623198937311e89583657942a219fd83035c4e41 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Jun 2016 14:32:29 +0800 Subject: [PATCH 0008/1216] check parameters for send --- Protocols/Websocket.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 2eabc7c3d..829286862 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -215,6 +215,9 @@ public static function input($buffer, ConnectionInterface $connection) */ public static function encode($buffer, ConnectionInterface $connection) { + if (!is_scalar($buffer)) { + throw new \Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to a string. "); + } $len = strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; From 2833d4b7a53fc1ece750d5c7c7ab467963a6dbf6 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 29 Jun 2016 15:53:43 +0800 Subject: [PATCH 0009/1216] Update Worker.php --- Worker.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Worker.php b/Worker.php index 812003db6..b9c1d9eb6 100644 --- a/Worker.php +++ b/Worker.php @@ -399,7 +399,6 @@ class Worker 'udp' => 'udp', 'unix' => 'unix', 'ssl' => 'tcp', - 'tsl' => 'tcp', 'sslv2' => 'tcp', 'sslv3' => 'tcp', 'tls' => 'tcp' From 4158eb764f5c4423e7a106a6a6148923840b3944 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 29 Jun 2016 16:42:37 +0800 Subject: [PATCH 0010/1216] AsyncTcpConnection ssl support --- Connection/AsyncTcpConnection.php | 36 ++++++++++++++++++++++++++----- Protocols/Http.php | 0 2 files changed, 31 insertions(+), 5 deletions(-) mode change 100755 => 100644 Protocols/Http.php diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 73829e9e7..45745460a 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -43,6 +43,28 @@ class AsyncTcpConnection extends TcpConnection */ protected $_remoteHost = ''; + /** + * PHP built-in protocols. + * + * @var array + */ + protected static $_builtinTransports = array( + 'tcp' => 'tcp', + 'udp' => 'udp', + 'unix' => 'unix', + 'ssl' => 'ssl', + 'sslv2' => 'sslv2', + 'sslv3' => 'sslv3', + 'tls' => 'tls' + ); + + /** + * Transport layer protocol. + * + * @var string + */ + protected $_transport = 'tcp'; + /** * Construct. * @@ -51,18 +73,22 @@ class AsyncTcpConnection extends TcpConnection */ public function __construct($remote_address) { + // Get the application layer communication protocol and listening address. list($scheme, $address) = explode(':', $remote_address, 2); - if ($scheme != 'tcp') { - // Get application layer protocol. + // Check application layer protocol class. + if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { - $this->protocol = '\\Workerman\\Protocols\\' . $scheme; + $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } + } else { + $this->_transport = self::$_builtinTransports[$scheme]; } + $this->_remoteAddress = substr($address, 2); $this->_remoteHost = substr($this->_remoteAddress, 0, strrpos($this->_remoteAddress, ':')); $this->id = self::$_idRecorder++; @@ -74,7 +100,7 @@ public function __construct($remote_address) public function connect() { // Open socket connection asynchronously. - $this->_socket = stream_socket_client("tcp://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->_socket = stream_socket_client("{$this->_transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); // If failed attempt to emit onError callback. if (!$this->_socket) { @@ -133,7 +159,7 @@ public function checkConnection($socket) // Nonblocking. stream_set_blocking($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream')) { + if (function_exists('socket_import_stream') && $this->_transport === 'tcp') { $raw_socket = socket_import_stream($socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); diff --git a/Protocols/Http.php b/Protocols/Http.php old mode 100755 new mode 100644 From f63c64934dc18e8745140018dd4bd1060860560a Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 30 Jun 2016 18:29:41 +0800 Subject: [PATCH 0011/1216] fix ssl fread --- Connection/AsyncTcpConnection.php | 8 ++++---- Connection/TcpConnection.php | 22 ++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 45745460a..f57475aa4 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -63,7 +63,7 @@ class AsyncTcpConnection extends TcpConnection * * @var string */ - protected $_transport = 'tcp'; + public $transport = 'tcp'; /** * Construct. @@ -86,7 +86,7 @@ public function __construct($remote_address) } } } else { - $this->_transport = self::$_builtinTransports[$scheme]; + $this->transport = self::$_builtinTransports[$scheme]; } $this->_remoteAddress = substr($address, 2); @@ -100,7 +100,7 @@ public function __construct($remote_address) public function connect() { // Open socket connection asynchronously. - $this->_socket = stream_socket_client("{$this->_transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); // If failed attempt to emit onError callback. if (!$this->_socket) { @@ -159,7 +159,7 @@ public function checkConnection($socket) // Nonblocking. stream_set_blocking($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && $this->_transport === 'tcp') { + if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = socket_import_stream($socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6b7780193..dd3cc6d5b 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -211,6 +211,7 @@ public function __construct($socket, $remote_address = '') $this->id = $this->_id = self::$_idRecorder++; $this->_socket = $socket; stream_set_blocking($this->_socket, 0); + stream_set_read_buffer($this->_socket, 0); Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_remoteAddress = $remote_address; @@ -354,24 +355,21 @@ public function resumeRecv() * Base read handler. * * @param resource $socket + * @param bool $check_eof * @return void */ public function baseRead($socket, $check_eof = true) { - $read_data = false; - while (1) { - $buffer = fread($socket, self::READ_BUFFER_SIZE); - if ($buffer === '' || $buffer === false) { - break; - } - $read_data = true; - $this->_recvBuffer .= $buffer; - } + $buffer = fread($socket, self::READ_BUFFER_SIZE); // Check connection closed. - if (!$read_data && $check_eof) { - $this->destroy(); - return; + if (!$buffer) { + if ($check_eof && (feof($socket) || !is_resource($socket) || $buffer === false)) { + $this->destroy(); + return; + } + } else { + $this->_recvBuffer .= $buffer; } // If the application layer protocol has been set up. From 7293906a7842c7efde5f625fac7a9465b15019b1 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 1 Jul 2016 20:13:29 +0800 Subject: [PATCH 0012/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index f57475aa4..e0a8685d3 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -158,6 +158,7 @@ public function checkConnection($socket) Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); + stream_set_read_buffer($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = socket_import_stream($socket); From 72dcfe49b70566be36cca7426542ea21dec2197b Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 1 Jul 2016 20:40:31 +0800 Subject: [PATCH 0013/1216] check buffer --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index dd3cc6d5b..d17ed4a19 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -363,7 +363,7 @@ public function baseRead($socket, $check_eof = true) $buffer = fread($socket, self::READ_BUFFER_SIZE); // Check connection closed. - if (!$buffer) { + if ($buffer === '' || $buffer === false) { if ($check_eof && (feof($socket) || !is_resource($socket) || $buffer === false)) { $this->destroy(); return; From afdfa4c207d0ede0517f7356fc7d2c3081e9cfb6 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Jul 2016 16:58:11 +0800 Subject: [PATCH 0014/1216] workerman.log --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index b9c1d9eb6..0e2edf6dd 100644 --- a/Worker.php +++ b/Worker.php @@ -598,7 +598,7 @@ protected static function parseCommand() // Start command. $mode = ''; if ($command === 'start') { - if ($command2 === '-d') { + if ($command2 === '-d' || Worker::$daemonize) { $mode = 'in DAEMON mode'; } else { $mode = 'in DEBUG mode'; From 2fa51b7e714f82b013cd853718a6d8cf8e84e972 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 10 Jul 2016 23:04:13 +0800 Subject: [PATCH 0015/1216] update Http Protocol --- Protocols/Http.php | 53 ++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 53bf3e1da..2679c1c6e 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -48,8 +48,11 @@ public static function input($recv_buffer, TcpConnection $connection) } else { return 0; } - } else { + } elseif (0 === strpos($recv_buffer, "GET")) { return strlen($header) + 4; + } else { + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; } } @@ -74,7 +77,7 @@ public static function decode($recv_buffer, TcpConnection $connection) 'REQUEST_METHOD' => '', 'REQUEST_URI' => '', 'SERVER_PROTOCOL' => '', - 'SERVER_SOFTWARE' => 'workerman/3.0', + 'SERVER_SOFTWARE' => 'workerman/3.3.3', 'SERVER_NAME' => '', 'HTTP_HOST' => '', 'HTTP_USER_AGENT' => '', @@ -102,12 +105,12 @@ public static function decode($recv_buffer, TcpConnection $connection) continue; } list($key, $value) = explode(':', $content, 2); - $key = strtolower($key); + $key = str_replace('-', '_', strtoupper($key)); $value = trim($value); + $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST - case 'host': - $_SERVER['HTTP_HOST'] = $value; + case 'HOST': $tmp = explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { @@ -115,49 +118,19 @@ public static function decode($recv_buffer, TcpConnection $connection) } break; // cookie - case 'cookie': - $_SERVER['HTTP_COOKIE'] = $value; + case 'COOKIE': parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; - // user-agent - case 'user-agent': - $_SERVER['HTTP_USER_AGENT'] = $value; - break; - // accept - case 'accept': - $_SERVER['HTTP_ACCEPT'] = $value; - break; - // accept-language - case 'accept-language': - $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $value; - break; - // accept-encoding - case 'accept-encoding': - $_SERVER['HTTP_ACCEPT_ENCODING'] = $value; - break; - // connection - case 'connection': - $_SERVER['HTTP_CONNECTION'] = $value; - break; - case 'referer': - $_SERVER['HTTP_REFERER'] = $value; - break; - case 'if-modified-since': - $_SERVER['HTTP_IF_MODIFIED_SINCE'] = $value; - break; - case 'if-none-match': - $_SERVER['HTTP_IF_NONE_MATCH'] = $value; - break; - case 'content-type': + // content-type + case 'CONTENT_TYPE': if (!preg_match('/boundary="?(\S+)"?/', $value, $match)) { $_SERVER['CONTENT_TYPE'] = $value; } else { $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $http_post_boundary = '--' . $match[1]; } - break; - case 'x-requested-with': - $_SERVER["HTTP_X_REQUESTED_WITH"] = $value; + case 'CONTENT_LENGTH': + $_SERVER['CONTENT_LENGTH'] = $value; break; } } From 74f57d18db76c3d5bd8b6707caedd67559bbbd20 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 16 Jul 2016 22:14:59 +0800 Subject: [PATCH 0016/1216] AsyncTcpConnection connect fail detail message --- Connection/AsyncTcpConnection.php | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e0a8685d3..443a6d3af 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -29,6 +29,13 @@ class AsyncTcpConnection extends TcpConnection */ public $onConnect = null; + /** + * Transport layer protocol. + * + * @var string + */ + public $transport = 'tcp'; + /** * Status. * @@ -43,6 +50,13 @@ class AsyncTcpConnection extends TcpConnection */ protected $_remoteHost = ''; + /** + * Connect start time. + * + * @var string + */ + protected $_connectStartTime = 0; + /** * PHP built-in protocols. * @@ -58,13 +72,6 @@ class AsyncTcpConnection extends TcpConnection 'tls' => 'tls' ); - /** - * Transport layer protocol. - * - * @var string - */ - public $transport = 'tcp'; - /** * Construct. * @@ -97,8 +104,14 @@ public function __construct($remote_address) $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; } + /** + * Do connect. + * + * @return void + */ public function connect() { + $this->_connectStartTime = microtime(true); // Open socket connection asynchronously. $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); @@ -187,7 +200,7 @@ public function checkConnection($socket) } } else { // Connection failed. - $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect fail'); + $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); $this->destroy(); $this->onConnect = null; } From eb7acbb4419395ea24b111fe43a902b8fe7963f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 17 Jul 2016 23:39:22 +0800 Subject: [PATCH 0017/1216] AsyncTcpConnection suport reconnect in onError/onClose callback --- Connection/AsyncTcpConnection.php | 22 ++++++++++++++++++---- Connection/TcpConnection.php | 22 ++++++++++++++++------ Connection/UdpConnection.php | 31 +++++++++---------------------- Worker.php | 2 +- 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 443a6d3af..30159301f 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -41,7 +41,7 @@ class AsyncTcpConnection extends TcpConnection * * @var int */ - protected $_status = self::STATUS_CONNECTING; + protected $_status = self::STATUS_INITIAL; /** * Remote host. @@ -111,14 +111,23 @@ public function __construct($remote_address) */ public function connect() { + if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && $this->_status !== self::STATUS_CLOSED) { + return; + } + $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = microtime(true); // Open socket connection asynchronously. $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); // If failed attempt to emit onError callback. if (!$this->_socket) { - $this->_status = self::STATUS_CLOSED; $this->emitError(WORKERMAN_CONNECT_FAIL, $errstr); + if ($this->_status === self::STATUS_CLOSING) { + $this->destroy(); + } + if ($this->_status === self::STATUS_CLOSED) { + $this->onConnect = null; + } return; } // Add socket to global event loop waiting connection is successfully established or faild. @@ -144,6 +153,7 @@ public function getRemoteHost() */ protected function emitError($code, $msg) { + $this->_status = self::STATUS_CLOSING; if ($this->onError) { try { call_user_func($this->onError, $this, $code, $msg); @@ -201,8 +211,12 @@ public function checkConnection($socket) } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); - $this->destroy(); - $this->onConnect = null; + if ($this->_status === self::STATUS_CLOSING) { + $this->destroy(); + } + if ($this->_status === self::STATUS_CLOSED) { + $this->onConnect = null; + } } } } diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index d17ed4a19..9d429b21b 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -29,6 +29,13 @@ class TcpConnection extends ConnectionInterface */ const READ_BUFFER_SIZE = 65535; + /** + * Status initial. + * + * @var int + */ + const STATUS_INITIAL = 0; + /** * Status connecting. * @@ -221,7 +228,7 @@ public function __construct($socket, $remote_address = '') * Sends data on the connection. * * @param string $send_buffer - * @param bool $raw + * @param bool $raw * @return void|bool|null */ public function send($send_buffer, $raw = false) @@ -235,7 +242,7 @@ public function send($send_buffer, $raw = false) } } - if ($this->_status === self::STATUS_CONNECTING) { + if ($this->_status === self::STATUS_INITIAL || $this->_status === self::STATUS_CONNECTING) { $this->_sendBuffer .= $send_buffer; return null; } elseif ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { @@ -529,15 +536,16 @@ public function consumeRecvBuffer($length) * Close connection. * * @param mixed $data + * @param bool $raw * @return void */ - public function close($data = null) + public function close($data = null, $raw = false) { if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { return; } else { if ($data !== null) { - $this->send($data); + $this->send($data, $raw); } $this->_status = self::STATUS_CLOSING; } @@ -611,8 +619,10 @@ public function destroy() exit(250); } } - // Cleaning up the callback to avoid memory leaks. - $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; + if ($this->_status === self::STATUS_CLOSED) { + // Cleaning up the callback to avoid memory leaks. + $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; + } } /** diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index b97590f8c..8636a55e7 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -33,20 +33,6 @@ class UdpConnection extends ConnectionInterface */ protected $_socket = null; - /** - * Remote ip. - * - * @var string - */ - protected $_remoteIp = ''; - - /** - * Remote port. - * - * @var int - */ - protected $_remotePort = 0; - /** * Remote address. * @@ -92,10 +78,11 @@ public function send($send_buffer, $raw = false) */ public function getRemoteIp() { - if (!$this->_remoteIp) { - list($this->_remoteIp, $this->_remotePort) = explode(':', $this->_remoteAddress, 2); + $pos = strrpos($this->_remoteAddress, ':'); + if ($pos) { + return trim(substr($this->_remoteAddress, 0, $pos), '[]'); } - return $this->_remoteIp; + return ''; } /** @@ -105,10 +92,10 @@ public function getRemoteIp() */ public function getRemotePort() { - if (!$this->_remotePort) { - list($this->_remoteIp, $this->_remotePort) = explode(':', $this->_remoteAddress, 2); + if ($this->_remoteAddress) { + return (int)substr(strrchr($this->_remoteAddress, ':'), 1); } - return $this->_remotePort; + return 0; } /** @@ -117,10 +104,10 @@ public function getRemotePort() * @param mixed $data * @return bool */ - public function close($data = null) + public function close($data = null, $raw = false) { if ($data !== null) { - $this->send($data); + $this->send($data, $raw); } return true; } diff --git a/Worker.php b/Worker.php index 0e2edf6dd..72368276c 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.3'; + const VERSION = '3.3.4'; /** * Status starting. From 064d8ff0d2065a889f414c69dd0a0c3b8da2a1f4 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 25 Jul 2016 23:31:41 +0800 Subject: [PATCH 0018/1216] Update WebServer.php --- WebServer.php | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/WebServer.php b/WebServer.php index df0481c05..9f43bd7ed 100644 --- a/WebServer.php +++ b/WebServer.php @@ -21,13 +21,6 @@ */ class WebServer extends Worker { - /** - * Mime. - * - * @var string - */ - protected static $defaultMimeType = 'text/html; charset=utf-8'; - /** * Virtual host to path mapping. * @@ -231,10 +224,10 @@ public function onMessage($connection) } } - public static function sendFile($connection, $file_name) + public static function sendFile($connection, $file_path) { // Check 304. - $info = stat($file_name); + $info = stat($file_path); $modified_time = $info ? date('D, d M Y H:i:s', $info['mtime']) . ' GMT' : ''; if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { // Http 304. @@ -251,22 +244,28 @@ public static function sendFile($connection, $file_name) if ($modified_time) { $modified_time = "Last-Modified: $modified_time\r\n"; } - $file_size = filesize($file_name); - $extension = pathinfo($file_name, PATHINFO_EXTENSION); - $content_type = isset(self::$mimeTypeMap[$extension]) ? self::$mimeTypeMap[$extension] : self::$defaultMimeType; + $file_size = filesize($file_path); + $file_info = pathinfo($file_path); + $extension = isset($file_info['extension']) ? $file_info['extension'] : ''; + $file_name = isset($file_info['filename']) ? $file_info['filename'] : ''; $header = "HTTP/1.1 200 OK\r\n"; - $header .= "Content-Type: $content_type\r\n"; + if (isset(self::$mimeTypeMap[$extension])) { + $header .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; + } else { + $header .= "Content-Type: application/octet-stream\r\n"; + $header .= "Content-Disposition: attachment; filename=\"$file_name\"\r\n"; + } $header .= "Connection: keep-alive\r\n"; $header .= $modified_time; $header .= "Content-Length: $file_size\r\n\r\n"; $trunk_limit_size = 1024*1024; if ($file_size < $trunk_limit_size) { - return $connection->send($header.file_get_contents($file_name), true); + return $connection->send($header.file_get_contents($file_path), true); } $connection->send($header, true); // Read file content from disk piece by piece and send to client. - $connection->fileHandler = fopen($file_name, 'r'); + $connection->fileHandler = fopen($file_path, 'r'); $do_write = function()use($connection) { // Send buffer not full. From 2be13d13a8b349e8a5f80fb0d53d8da0a2e4f62f Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Jul 2016 11:35:32 +0800 Subject: [PATCH 0019/1216] websocket http header optimization --- Protocols/Http.php | 8 +++++--- Protocols/Websocket.php | 42 ++++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 2679c1c6e..20af9ccae 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -104,9 +104,9 @@ public static function decode($recv_buffer, TcpConnection $connection) if (empty($content)) { continue; } - list($key, $value) = explode(':', $content, 2); - $key = str_replace('-', '_', strtoupper($key)); - $value = trim($value); + list($key, $value) = explode(':', $content, 2); + $key = str_replace('-', '_', strtoupper($key)); + $value = trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST @@ -129,6 +129,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $http_post_boundary = '--' . $match[1]; } + break; case 'CONTENT_LENGTH': $_SERVER['CONTENT_LENGTH'] = $value; break; @@ -338,6 +339,7 @@ public static function sessionStart() session_decode($raw); } } + return true; } /** diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 829286862..f079f8796 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -356,7 +356,10 @@ protected static function dealHandshake($buffer, $connection) Worker::log($e); exit(250); } - $_GET = $_COOKIE = $_SERVER = array(); + if ($_SESSION && class_exists('\GatewayWorker\Lib\Context')) { + $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); + } + $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); } if (strlen($buffer) > $header_length) { return self::input(substr($buffer, $header_length), $connection); @@ -384,45 +387,40 @@ protected static function dealHandshake($buffer, $connection) */ protected static function parseHttpHeader($buffer) { - $header_data = explode("\r\n", $buffer); - $_SERVER = array(); + // Parse headers. + list($http_header, ) = explode("\r\n\r\n", $buffer, 2); + $header_data = explode("\r\n", $http_header); + + if ($_SERVER) { + $_SERVER = array(); + } + list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $header_data[0]); + unset($header_data[0]); foreach ($header_data as $content) { // \r\n\r\n if (empty($content)) { continue; } - list($key, $value) = explode(':', $content, 2); - $key = strtolower($key); - $value = trim($value); + list($key, $value) = explode(':', $content, 2); + $key = str_replace('-', '_', strtoupper($key)); + $value = trim($value); + $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST - case 'host': - $_SERVER['HTTP_HOST'] = $value; + case 'HOST': $tmp = explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; } break; - // HTTP_COOKIE - case 'cookie': - $_SERVER['HTTP_COOKIE'] = $value; + // cookie + case 'COOKIE': parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; - // HTTP_USER_AGENT - case 'user-agent': - $_SERVER['HTTP_USER_AGENT'] = $value; - break; - // HTTP_REFERER - case 'referer': - $_SERVER['HTTP_REFERER'] = $value; - break; - case 'origin': - $_SERVER['HTTP_ORIGIN'] = $value; - break; } } From 9587d200a1bd6f11e8c3ab9937f42a3229d528a7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Jul 2016 12:23:57 +0800 Subject: [PATCH 0020/1216] http header of server --- Protocols/Http.php | 5 +++-- Protocols/Websocket.php | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 20af9ccae..07d4df4fe 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; use Workerman\Connection\TcpConnection; +use Workerman\Worker; /** * http protocol @@ -77,7 +78,7 @@ public static function decode($recv_buffer, TcpConnection $connection) 'REQUEST_METHOD' => '', 'REQUEST_URI' => '', 'SERVER_PROTOCOL' => '', - 'SERVER_SOFTWARE' => 'workerman/3.3.3', + 'SERVER_SOFTWARE' => 'workerman/'.Worker::VERSION, 'SERVER_NAME' => '', 'HTTP_HOST' => '', 'HTTP_USER_AGENT' => '', @@ -200,7 +201,7 @@ public static function encode($content, TcpConnection $connection) } // header - $header .= "Server: WorkerMan/3.0\r\nContent-Length: " . strlen($content) . "\r\n\r\n"; + $header .= "Server: workerman/" . Worker::VERSION . "\r\nContent-Length: " . strlen($content) . "\r\n\r\n"; // save session self::sessionWriteClose(); diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index f079f8796..0c7e876af 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -321,6 +321,7 @@ protected static function dealHandshake($buffer, $connection) $handshake_message .= "Upgrade: websocket\r\n"; $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; $handshake_message .= "Connection: Upgrade\r\n"; + $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; // Mark handshake complete.. $connection->websocketHandshake = true; @@ -356,7 +357,7 @@ protected static function dealHandshake($buffer, $connection) Worker::log($e); exit(250); } - if ($_SESSION && class_exists('\GatewayWorker\Lib\Context')) { + if (!empty($_SESSION) && class_exists('\GatewayWorker\Lib\Context')) { $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); From 7fb6bff9a759f1fa62c38649878633f7dab6eb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=AE?= Date: Tue, 2 Aug 2016 16:21:54 +0800 Subject: [PATCH 0021/1216] fix issue #77 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index db9bf79c0..edc0efeff 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ test.php ```php require_once './Workerman/Autoloader.php'; use Workerman\WebServer; +use Workerman\Worker; // WebServer $web = new WebServer("http://0.0.0.0:80"); From 6ad21a37e442b3ad5152a310a35bdf293955abff Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 2 Aug 2016 17:52:13 +0800 Subject: [PATCH 0022/1216] handshake automatically as ws client for issue #78 --- Connection/AsyncTcpConnection.php | 11 +++++++++++ Protocols/Ws.php | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 30159301f..9d9d829da 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -196,6 +196,17 @@ public function checkConnection($socket) } $this->_status = self::STATUS_ESTABLISH; $this->_remoteAddress = stream_socket_get_name($socket, true); + if (is_callable(array($this->protocol, 'onConnect'))) { + try { + call_user_func(array($this->protocol, 'onConnect'), $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } // Try to emit onConnect callback. if ($this->onConnect) { try { diff --git a/Protocols/Ws.php b/Protocols/Ws.php index d33682759..5e1381231 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -274,6 +274,16 @@ public static function decode($bytes, $connection) } } + /** + * Send websocket handshake data. + * + * @return void + */ + public static function onConnect($connection) + { + self::sendHandshake($connection); + } + /** * Send websocket handshake. * @@ -282,6 +292,9 @@ public static function decode($bytes, $connection) */ public static function sendHandshake($connection) { + if (!empty($connection->handshakeStep)) { + return; + } // Get Host. $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; @@ -296,7 +309,7 @@ public static function sendHandshake($connection) $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; - $connection->websocketDataBuffer = ''; + $connection->websocketDataBuffer = ''; if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } From e7fbed0d7e5e771c8e4275afc38997e3b1a312f9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Aug 2016 21:34:19 +0800 Subject: [PATCH 0023/1216] fix ws asyncTcpConnection reconnect --- Protocols/Ws.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 5e1381231..9da80d052 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -281,6 +281,7 @@ public static function decode($bytes, $connection) */ public static function onConnect($connection) { + $connection->handshakeStep = null; self::sendHandshake($connection); } @@ -353,6 +354,7 @@ public static function dealHandshake($buffer, $connection) $connection->consumeRecvBuffer($handshake_respnse_length); if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); + $connection->tmpWebsocketData = ''; } if (strlen($buffer > $handshake_respnse_length)) { return self::input(substr($buffer, $handshake_respnse_length)); From 3fc35c30cbeaa7fbeb54a5d46a064b839d1e6550 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 7 Aug 2016 15:09:11 +0800 Subject: [PATCH 0024/1216] support Protocol::onConnect Protocol::onClose --- Connection/AsyncTcpConnection.php | 16 ++++++----- Connection/TcpConnection.php | 12 +++++++++ Protocols/Websocket.php | 2 +- Protocols/Ws.php | 44 ++++++++++++++++++++++--------- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9d9d829da..80bbefba1 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -176,7 +176,7 @@ protected function emitError($code, $msg) public function checkConnection($socket) { // Check socket state. - if (stream_socket_get_name($socket, true)) { + if ($address = stream_socket_get_name($socket, true)) { // Remove write listener. Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. @@ -195,10 +195,12 @@ public function checkConnection($socket) Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISH; - $this->_remoteAddress = stream_socket_get_name($socket, true); - if (is_callable(array($this->protocol, 'onConnect'))) { + $this->_remoteAddress = $address; + + // Try to emit onConnect callback. + if ($this->onConnect) { try { - call_user_func(array($this->protocol, 'onConnect'), $this); + call_user_func($this->onConnect, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -207,10 +209,10 @@ public function checkConnection($socket) exit(250); } } - // Try to emit onConnect callback. - if ($this->onConnect) { + // Try to emit protocol::onConnect + if (method_exists($this->protocol, 'onConnect')) { try { - call_user_func($this->onConnect, $this); + call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 9d429b21b..f2e7805a4 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -619,6 +619,18 @@ public function destroy() exit(250); } } + // Try to emit protocol::onClose + if (method_exists($this->protocol, 'onClose')) { + try { + call_user_func(array($this->protocol, 'onClose'), $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } if ($this->_status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 0c7e876af..2e2bcec71 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -154,7 +154,7 @@ public static function input($buffer, ConnectionInterface $connection) break; // Wrong opcode. default : - echo "error opcode $opcode and close websocket connection\n"; + echo "error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"; $connection->close(); return 0; } diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 9da80d052..802052c30 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -2,6 +2,7 @@ namespace Workerman\Protocols; use Workerman\Worker; +use Workerman\Lib\Timer; /** * Websocket protocol for client. @@ -39,7 +40,7 @@ class Ws public static function input($buffer, $connection) { if (empty($connection->handshakeStep)) { - echo "recv data before handshake\n"; + echo "recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"; return false; } // Recv handshake response @@ -140,7 +141,7 @@ public static function input($buffer, $connection) break; // Wrong opcode. default : - echo "error opcode $opcode and close websocket connection\n"; + echo "error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"; $connection->close(); return 0; } @@ -195,6 +196,9 @@ public static function input($buffer, $connection) */ public static function encode($payload, $connection) { + if (empty($connection->websocketType)) { + $connection->websocketType = self::BINARY_TYPE_BLOB; + } $payload = (string)$payload; if (empty($connection->handshakeStep)) { self::sendHandshake($connection); @@ -281,10 +285,26 @@ public static function decode($bytes, $connection) */ public static function onConnect($connection) { - $connection->handshakeStep = null; self::sendHandshake($connection); } + /** + * Clean + * + * @param $connection + */ + public static function onClose($connection) + { + $connection->handshakeStep = null; + $connection->websocketCurrentFrameLength = 0; + $connection->tmpWebsocketData = ''; + $connection->websocketDataBuffer = ''; + if (!empty($connection->websocketPingTimer)) { + Timer::del($connection->websocketPingTimer); + $connection->websocketPingTimer = null; + } + } + /** * Send websocket handshake. * @@ -311,9 +331,6 @@ public static function sendHandshake($connection) $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; $connection->websocketDataBuffer = ''; - if (empty($connection->websocketType)) { - $connection->websocketType = self::BINARY_TYPE_BLOB; - } } /** @@ -329,11 +346,11 @@ public static function dealHandshake($buffer, $connection) if ($pos) { // handshake complete $connection->handshakeStep = 2; - $handshake_respnse_length = $pos + 4; + $handshake_response_length = $pos + 4; // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - call_user_func($connection->onWebSocketConnect, $connection, substr($buffer, 0, $handshake_respnse_length)); + call_user_func($connection->onWebSocketConnect, $connection, substr($buffer, 0, $handshake_response_length)); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -344,20 +361,21 @@ public static function dealHandshake($buffer, $connection) } // Headbeat. if (!empty($connection->websocketPingInterval)) { - $connection->websocketPingTimer = \Workerman\Lib\Timer::add($connection->websocketPingInterval, function() use ($connection){ + $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){ if (false === $connection->send(pack('H*', '8900'), true)) { - \Workerman\Lib\Timer::del($connection->websocketPingTimer); + Timer::del($connection->websocketPingTimer); + $connection->websocketPingTimer = null; } }); } - $connection->consumeRecvBuffer($handshake_respnse_length); + $connection->consumeRecvBuffer($handshake_response_length); if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } - if (strlen($buffer > $handshake_respnse_length)) { - return self::input(substr($buffer, $handshake_respnse_length)); + if (strlen($buffer > $handshake_response_length)) { + return self::input(substr($buffer, $handshake_response_length), $connection); } } return 0; From 0e7e11667d41ceb3cb1b1717e1afbd355524696b Mon Sep 17 00:00:00 2001 From: alacner Date: Sat, 20 Aug 2016 07:56:28 +0800 Subject: [PATCH 0025/1216] Update UdpConnection.php --- Connection/UdpConnection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 8636a55e7..e4cd2fee4 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -102,6 +102,7 @@ public function getRemotePort() * Close connection. * * @param mixed $data + * @param bool $raw * @return bool */ public function close($data = null, $raw = false) From 1ec30b182f20e2530374f9c407b0ff6398759fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=AE?= Date: Mon, 22 Aug 2016 09:52:40 +0800 Subject: [PATCH 0026/1216] Update Frame.php --- Protocols/Frame.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Frame.php b/Protocols/Frame.php index 66df5e000..4a6b13ecb 100644 --- a/Protocols/Frame.php +++ b/Protocols/Frame.php @@ -37,7 +37,7 @@ public static function input($buffer, TcpConnection $connection) } /** - * Encode. + * Decode. * * @param string $buffer * @return string @@ -48,7 +48,7 @@ public static function decode($buffer) } /** - * Decode. + * Encode. * * @param string $buffer * @return string From e1ebd4f1585ff91b9e1b786c155f2f5b1cac50df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=AE?= Date: Wed, 24 Aug 2016 17:17:43 +0800 Subject: [PATCH 0027/1216] websocket tips --- Protocols/Websocket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 2e2bcec71..43a37e1e7 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -309,7 +309,7 @@ protected static function dealHandshake($buffer, $connection) if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.", + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.
See http://wiki.workerman.net/Error1", true); $connection->close(); return 0; From 61b24f2ed26a8e5c8d1cc499c94b893fcd8dd175 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 25 Aug 2016 18:17:02 +0800 Subject: [PATCH 0028/1216] fix Ws for uri --- Connection/AsyncTcpConnection.php | 48 +++++++++++++++++++++++++++---- Protocols/Ws.php | 4 +-- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 80bbefba1..830b7edc5 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -57,6 +57,14 @@ class AsyncTcpConnection extends TcpConnection */ protected $_connectStartTime = 0; + /** + * Remote URI. + * + * @var string + */ + protected $_remoteURI = ''; + + /** * PHP built-in protocols. * @@ -80,8 +88,29 @@ class AsyncTcpConnection extends TcpConnection */ public function __construct($remote_address) { - // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $remote_address, 2); + $address_info = parse_url($remote_address); + if (!$address_info) { + echo new \Exception('bad remote_address'); + $this->_remoteAddress = $remote_address; + } else { + if (!isset($address_info['port'])) { + $address_info['port'] = 80; + } + if (!isset($address_info['path'])) { + $address_info['path'] = '/'; + } + if (!isset($address_info['query'])) { + $address_info['query'] = ''; + } else { + $address_info['query'] = '?' . $address_info['query']; + } + $this->_remoteAddress = "{$address_info['host']}:{$address_info['port']}"; + $this->_remoteHost = $address_info['host']; + $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; + $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; + } + + $this->id = self::$_idRecorder++; // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); @@ -95,10 +124,7 @@ public function __construct($remote_address) } else { $this->transport = self::$_builtinTransports[$scheme]; } - - $this->_remoteAddress = substr($address, 2); - $this->_remoteHost = substr($this->_remoteAddress, 0, strrpos($this->_remoteAddress, ':')); - $this->id = self::$_idRecorder++; + // For statistics. self::$statistics['connection_count']++; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; @@ -144,6 +170,16 @@ public function getRemoteHost() return $this->_remoteHost; } + /** + * Get remote URI. + * + * @return string + */ + public function getRemoteURI() + { + return $this->_remoteURI; + } + /** * Try to emit onError callback. * diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 802052c30..20fdc0ee0 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -320,7 +320,7 @@ public static function sendHandshake($connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $header = "GET / HTTP/1.1\r\n". + $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". "Host: $host\r\n". "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". @@ -374,7 +374,7 @@ public static function dealHandshake($buffer, $connection) $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } - if (strlen($buffer > $handshake_response_length)) { + if (strlen($buffer) > $handshake_response_length) { return self::input(substr($buffer, $handshake_response_length), $connection); } } From dffe18c9a3ba0c1dbb30729022485a0c0fa5dc2d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 1 Sep 2016 11:44:56 +0800 Subject: [PATCH 0029/1216] compatible with hhvm --- Connection/AsyncTcpConnection.php | 5 ++++- Connection/TcpConnection.php | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 830b7edc5..60ae851c7 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -217,7 +217,10 @@ public function checkConnection($socket) Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); - stream_set_read_buffer($socket, 0); + // Compatible with hhvm + if (function_exists('stream_set_read_buffer')) { + stream_set_read_buffer($socket, 0); + } // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = socket_import_stream($socket); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index f2e7805a4..d4ac76164 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -218,7 +218,10 @@ public function __construct($socket, $remote_address = '') $this->id = $this->_id = self::$_idRecorder++; $this->_socket = $socket; stream_set_blocking($this->_socket, 0); - stream_set_read_buffer($this->_socket, 0); + // Compatible with hhvm + if (function_exists('stream_set_read_buffer')) { + stream_set_read_buffer($this->_socket, 0); + } Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_remoteAddress = $remote_address; From fb170aadd1f617efbb649a4a6ab68c816d31259c Mon Sep 17 00:00:00 2001 From: Garveen Date: Sat, 3 Sep 2016 17:49:05 +0800 Subject: [PATCH 0030/1216] Avoid a problem which caused by docker always use a same pid --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 72368276c..d51d01064 100644 --- a/Worker.php +++ b/Worker.php @@ -611,7 +611,7 @@ protected static function parseCommand() $master_is_alive = $master_pid && @posix_kill($master_pid, 0); // Master is still alive? if ($master_is_alive) { - if ($command === 'start') { + if ($command === 'start' && posix_getpid() != $master_pid) { self::log("Workerman[$start_file] already running"); exit; } From 24e35989a939a88f67922a86ee2c38bfc51b7fee Mon Sep 17 00:00:00 2001 From: victorruan <250069802@qq.com> Date: Sat, 3 Sep 2016 19:44:13 +0800 Subject: [PATCH 0031/1216] =?UTF-8?q?=E5=8F=98=E6=9B=B4=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增强可读性 --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index d51d01064..d5626df5a 100644 --- a/Worker.php +++ b/Worker.php @@ -1313,8 +1313,8 @@ public function __construct($socket_name = '', $context_option = array()) self::$_pidMap[$this->workerId] = array(); // Get autoload root path. - $backrace = debug_backtrace(); - $this->_autoloadRootPath = dirname($backrace[0]['file']); + $backtrace = debug_backtrace(); + $this->_autoloadRootPath = dirname($backtrace[0]['file']); // Context for socket. if ($socket_name) { From d5f52b5081ba8f7f464341cf15bd547e6b17d1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=AE=E4=BD=B3=E4=BD=B3?= <250069802@qq.com> Date: Mon, 5 Sep 2016 13:46:40 +0800 Subject: [PATCH 0032/1216] change DEFAUL_BACKLOG! change DEFAUL_BACKLOG to DEFAULT_BACKLOG. --- Worker.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index d5626df5a..530166874 100644 --- a/Worker.php +++ b/Worker.php @@ -76,8 +76,7 @@ class Worker * * @var int */ - const DEFAUL_BACKLOG = 1024; - + const DEFAULT_BACKLOG = 1024; /** * Max udp package size. * @@ -1320,7 +1319,7 @@ public function __construct($socket_name = '', $context_option = array()) if ($socket_name) { $this->_socketName = $socket_name; if (!isset($context_option['socket']['backlog'])) { - $context_option['socket']['backlog'] = self::DEFAUL_BACKLOG; + $context_option['socket']['backlog'] = self::DEFAULT_BACKLOG; } $this->_context = stream_context_create($context_option); } From ccbbdf2137ab43ddd8c83f3835916570a86779c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=AE=E4=BD=B3=E4=BD=B3?= <250069802@qq.com> Date: Mon, 5 Sep 2016 14:32:29 +0800 Subject: [PATCH 0033/1216] change Eegister to Register change Eegister to Register --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 530166874..c926d2102 100644 --- a/Worker.php +++ b/Worker.php @@ -1425,7 +1425,7 @@ public function run() //Update process state. self::$_status = self::STATUS_RUNNING; - // Eegister shutdown function for checking errors. + // Register shutdown function for checking errors. register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); // Set autoload root path. From 7d61d8a34c1a83a4bb593e186fef563064466280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=AE=E4=BD=B3=E4=BD=B3?= <250069802@qq.com> Date: Mon, 5 Sep 2016 15:55:07 +0800 Subject: [PATCH 0034/1216] change hander to handler change hander to handler --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c926d2102..bc86f2674 100644 --- a/Worker.php +++ b/Worker.php @@ -722,7 +722,7 @@ protected static function reinstallSignal() } /** - * Signal hander. + * Signal handler. * * @param int $signal */ From ba5ca331d3f1c5a8e9255e74c4fa9e2f07e8c01b Mon Sep 17 00:00:00 2001 From: leon <764436364@qq.com> Date: Sun, 18 Sep 2016 15:16:09 +0800 Subject: [PATCH 0035/1216] =?UTF-8?q?worker=E8=AE=B0=E5=BD=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=87=BD=E6=95=B0=E5=8F=98=E9=87=8F=E5=90=8D=E8=A7=84?= =?UTF-8?q?=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index bc86f2674..7251afc36 100644 --- a/Worker.php +++ b/Worker.php @@ -1207,15 +1207,15 @@ protected static function writeStatisticsToStatusFile() // For child processes. /** @var Worker $worker */ $worker = current(self::$_workers); - $wrker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", + $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . str_pad($worker->getSocketName(), self::$_maxSocketNameLength) . " " . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), self::$_maxWorkerNameLength) . " "; - $wrker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], + $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], 14) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . str_pad(ConnectionInterface::$statistics['throw_exception'], 15) . "\n"; - file_put_contents(self::$_statisticsFile, $wrker_status_str, FILE_APPEND); + file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } /** From d6a7f02c21660e328b7a5aaea82eeb59653b313d Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Sep 2016 10:15:51 +0800 Subject: [PATCH 0036/1216] Update WebServer.php --- WebServer.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WebServer.php b/WebServer.php index 9f43bd7ed..a243a099e 100644 --- a/WebServer.php +++ b/WebServer.php @@ -209,7 +209,11 @@ public function onMessage($connection) } $content = ob_get_clean(); ini_set('display_errors', 'on'); - $connection->close($content); + if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $connection->send($content); + } else { + $connection->close($content); + } chdir($workerman_cwd); return; } From dc45329d3ad9c6096388478261cc9d8012f12e99 Mon Sep 17 00:00:00 2001 From: CismonX Date: Mon, 3 Oct 2016 12:31:42 +0800 Subject: [PATCH 0037/1216] fix udp --- Worker.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Worker.php b/Worker.php index 7251afc36..87b0a6104 100644 --- a/Worker.php +++ b/Worker.php @@ -1553,6 +1553,9 @@ public function acceptUdpConnection($socket) if ($this->protocol) { $parser = $this->protocol; $recv_buffer = $parser::decode($recv_buffer, $connection); + // Discard bad packets. + if ($recv_buffer === false) + return true; } ConnectionInterface::$statistics['total_request']++; try { From 1cecdf378f6d02ab5bcd7b8e95d8e716c98b1ce0 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 13 Oct 2016 09:37:09 +0800 Subject: [PATCH 0038/1216] status wait 500ms and remove kill command --- Worker.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Worker.php b/Worker.php index 87b0a6104..01a26f816 100644 --- a/Worker.php +++ b/Worker.php @@ -587,7 +587,7 @@ protected static function parseCommand() // Check argv; $start_file = $argv[0]; if (!isset($argv[1])) { - exit("Usage: php yourfile.php {start|stop|restart|reload|status|kill}\n"); + exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); } // Get command. @@ -614,18 +614,13 @@ protected static function parseCommand() self::log("Workerman[$start_file] already running"); exit; } - } elseif ($command !== 'start' && $command !== 'restart' && $command !== 'kill') { + } elseif ($command !== 'start' && $command !== 'restart') { self::log("Workerman[$start_file] not run"); exit; } // execute command. switch ($command) { - case 'kill': - exec("ps aux | grep $start_file | grep -v grep | awk '{print $2}' |xargs kill -SIGINT"); - usleep(100000); - exec("ps aux | grep $start_file | grep -v grep | awk '{print $2}' |xargs kill -SIGKILL"); - break; case 'start': if ($command2 === '-d') { Worker::$daemonize = true; @@ -638,7 +633,7 @@ protected static function parseCommand() // Master process will send status signal to all child processes. posix_kill($master_pid, SIGUSR2); // Waiting amoment. - usleep(100000); + usleep(500000); // Display statisitcs data from a disk file. @readfile(self::$_statisticsFile); exit(0); @@ -679,7 +674,7 @@ protected static function parseCommand() self::log("Workerman[$start_file] reload"); exit; default : - exit("Usage: php yourfile.php {start|stop|restart|reload|status|kill}\n"); + exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); } } From 4e65a66f8e4dda90f871668857f43daf8782d315 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 18 Oct 2016 16:33:38 +0800 Subject: [PATCH 0039/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 60ae851c7..0d8829f5e 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -64,6 +64,13 @@ class AsyncTcpConnection extends TcpConnection */ protected $_remoteURI = ''; + /** + * Context option. + * + * @var null + */ + protected $_contextOption = null; + /** * PHP built-in protocols. @@ -84,9 +91,10 @@ class AsyncTcpConnection extends TcpConnection * Construct. * * @param string $remote_address + * @param array $context_option * @throws Exception */ - public function __construct($remote_address) + public function __construct($remote_address, $context_option = null) { $address_info = parse_url($remote_address); if (!$address_info) { @@ -128,6 +136,7 @@ public function __construct($remote_address) // For statistics. self::$statistics['connection_count']++; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->_contextOption = $context_option; } /** @@ -137,14 +146,21 @@ public function __construct($remote_address) */ public function connect() { - if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && $this->_status !== self::STATUS_CLOSED) { + if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && + $this->_status !== self::STATUS_CLOSED) { return; } $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = microtime(true); // Open socket connection asynchronously. - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, - STREAM_CLIENT_ASYNC_CONNECT); + if ($this->_contextOption) { + $context = stream_context_create($this->_contextOption); + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + STREAM_CLIENT_ASYNC_CONNECT, $context); + } else { + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + STREAM_CLIENT_ASYNC_CONNECT); + } // If failed attempt to emit onError callback. if (!$this->_socket) { $this->emitError(WORKERMAN_CONNECT_FAIL, $errstr); From 9ae75829ec0d6037b10874dac22f8a9b6c1756ac Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 18 Oct 2016 22:44:34 +0800 Subject: [PATCH 0040/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 01a26f816..48a831f24 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.4'; + const VERSION = '3.3.5'; /** * Status starting. From d4c1c08bfcde77199afe0b0d118be4bddcafcab2 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Oct 2016 11:54:38 +0800 Subject: [PATCH 0041/1216] support dynamic log path --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 48a831f24..d542c7374 100644 --- a/Worker.php +++ b/Worker.php @@ -1290,7 +1290,7 @@ public static function log($msg) if (!self::$daemonize) { echo $msg; } - file_put_contents(self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); + file_put_contents((string)self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** From 13fafe69c9ea32776de48543ebdbddbbaa33e681 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Oct 2016 16:10:59 +0800 Subject: [PATCH 0042/1216] safe echo --- Worker.php | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Worker.php b/Worker.php index d542c7374..722b0cb5e 100644 --- a/Worker.php +++ b/Worker.php @@ -456,8 +456,9 @@ protected static function init() if (empty(self::$logFile)) { self::$logFile = __DIR__ . '/../workerman.log'; } - touch(self::$logFile); - chmod(self::$logFile, 0622); + $log_file = (string)self::$logFile; + touch($log_file); + chmod($log_file, 0622); // State. self::$_status = self::STATUS_STARTING; @@ -552,26 +553,26 @@ protected static function getCurrentUser() */ protected static function displayUI() { - echo "\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\n\033[0m"; - echo 'Workerman version:', Worker::VERSION, " PHP version:", PHP_VERSION, "\n"; - echo "------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"; - echo "\033[47;30muser\033[0m", str_pad('', - self::$_maxUserNameLength + 2 - strlen('user')), "\033[47;30mworker\033[0m", str_pad('', - self::$_maxWorkerNameLength + 2 - strlen('worker')), "\033[47;30mlisten\033[0m", str_pad('', - self::$_maxSocketNameLength + 2 - strlen('listen')), "\033[47;30mprocesses\033[0m \033[47;30m", "status\033[0m\n"; + self::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\n\033[0m"); + self::safeEcho('Workerman version:'. Worker::VERSION. " PHP version:". PHP_VERSION. "\n"); + self::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"); + self::safeEcho("\033[47;30muser\033[0m". str_pad('', + self::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', + self::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', + self::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); foreach (self::$_workers as $worker) { - echo str_pad($worker->user, self::$_maxUserNameLength + 2), str_pad($worker->name, - self::$_maxWorkerNameLength + 2), str_pad($worker->getSocketName(), - self::$_maxSocketNameLength + 2), str_pad(' ' . $worker->count, 9), " \033[32;40m [OK] \033[0m\n";; + self::safeEcho(str_pad($worker->user, self::$_maxUserNameLength + 2). str_pad($worker->name, + self::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), + self::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); } - echo "----------------------------------------------------------------\n"; + self::safeEcho("----------------------------------------------------------------\n"); if (self::$daemonize) { global $argv; $start_file = $argv[0]; - echo "Input \"php $start_file stop\" to quit. Start success.\n"; + self::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n"); } else { - echo "Press Ctrl-C to quit. Start success.\n"; + self::safeEcho("Press Ctrl-C to quit. Start success.\n"); } } @@ -907,7 +908,7 @@ protected static function getId($worker_id, $pid) { $id = array_search($pid, self::$_idMap[$worker_id]); if ($id === false) { - echo "getId fail\n"; + self::safeEcho("getId fail\n"); } return $id; } @@ -1288,11 +1289,23 @@ public static function log($msg) { $msg = $msg . "\n"; if (!self::$daemonize) { - echo $msg; + self::safeEcho($msg); } file_put_contents((string)self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); } + /** + * Safe Echo. + * + * @param $msg + */ + public static function safeEcho($msg) + { + if (!function_exists('posix_isatty') || posix_isatty(STDOUT)) { + echo $msg; + } + } + /** * Construct. * From 86b5a1728ad6e9d968786a3a2cccff801da742d3 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 30 Oct 2016 15:21:44 +0800 Subject: [PATCH 0043/1216] check sendbuffer full for websocket --- Connection/TcpConnection.php | 57 ++++++++++++++++++++++++------------ Protocols/Websocket.php | 39 ++++++++++++++++++++++++ Protocols/Ws.php | 40 ++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index d4ac76164..f63afa1ef 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -246,7 +246,14 @@ public function send($send_buffer, $raw = false) } if ($this->_status === self::STATUS_INITIAL || $this->_status === self::STATUS_CONNECTING) { + if ($this->_sendBuffer) { + if ($this->bufferIsFull()) { + self::$statistics['send_fail']++; + return false; + } + } $this->_sendBuffer .= $send_buffer; + $this->checkBufferWillFull(); return null; } elseif ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { return false; @@ -283,29 +290,18 @@ public function send($send_buffer, $raw = false) $this->_sendBuffer = $send_buffer; } Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); - // Check if the send buffer is full. - $this->checkBufferIsFull(); + // Check if the send buffer will be full. + $this->checkBufferWillFull(); return null; } else { - // Buffer has been marked as full but still has data to send the packet is discarded. - if ($this->maxSendBufferSize <= strlen($this->_sendBuffer)) { + if ($this->bufferIsFull()) { self::$statistics['send_fail']++; - if ($this->onError) { - try { - call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } return false; } + $this->_sendBuffer .= $send_buffer; // Check if the send buffer is full. - $this->checkBufferIsFull(); + $this->checkBufferWillFull(); } } @@ -568,11 +564,11 @@ public function getSocket() } /** - * Check whether the send buffer is full. + * Check whether the send buffer will be full. * * @return void */ - protected function checkBufferIsFull() + protected function checkBufferWillFull() { if ($this->maxSendBufferSize <= strlen($this->_sendBuffer)) { if ($this->onBufferFull) { @@ -589,6 +585,31 @@ protected function checkBufferIsFull() } } + /** + * Whether send buffer is full. + * + * @return bool + */ + protected function bufferIsFull() + { + // Buffer has been marked as full but still has data to send then the packet is discarded. + if ($this->maxSendBufferSize <= strlen($this->_sendBuffer)) { + if ($this->onError) { + try { + call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + return true; + } + return false; + } + /** * Destroy connection. * diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 43a37e1e7..bd98a5152 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; +use Workerman\Connection\TcpConnection; use Workerman\Worker; /** @@ -179,6 +180,14 @@ public static function input($buffer, ConnectionInterface $connection) } } $current_frame_length = $head_len + $data_len; + + $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; + if ($total_package_size > TcpConnection::$maxPackageSize) { + echo "error package. package_length=$total_package_size\n"; + $connection->close(); + return 0; + } + if ($is_fin_frame) { return $current_frame_length; } else { @@ -240,7 +249,37 @@ public static function encode($buffer, ConnectionInterface $connection) if (empty($connection->tmpWebsocketData)) { $connection->tmpWebsocketData = ''; } + // If buffer has already full then discard the current package. + if (strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if ($connection->onError) { + try { + call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + return ''; + } $connection->tmpWebsocketData .= $encode_buffer; + // Check buffer is full. + if ($connection->maxSendBufferSize <= strlen($connection->tmpWebsocketData)) { + if ($connection->onBufferFull) { + try { + call_user_func($connection->onBufferFull, $connection); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + } + // Return empty string. return ''; } diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 20fdc0ee0..bb1af4ebd 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -161,6 +161,14 @@ public static function input($buffer, $connection) } else { $current_frame_length = $data_len + 2; } + + $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; + if ($total_package_size > TcpConnection::$maxPackageSize) { + echo "error package. package_length=$total_package_size\n"; + $connection->close(); + return 0; + } + if ($is_fin_frame) { return $current_frame_length; } else { @@ -225,7 +233,36 @@ public static function encode($payload, $connection) $frame .= $payload[$i] ^ $mask_key[$i % 4]; } if ($connection->handshakeStep === 1) { - $connection->tmpWebsocketData = isset($connection->tmpWebsocketData) ? $connection->tmpWebsocketData . $frame : $frame; + // If buffer has already full then discard the current package. + if (strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if ($connection->onError) { + try { + call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + return ''; + } + $connection->tmpWebsocketData = $connection->tmpWebsocketData . $frame; + // Check buffer is full. + if ($connection->maxSendBufferSize <= strlen($connection->tmpWebsocketData)) { + if ($connection->onBufferFull) { + try { + call_user_func($connection->onBufferFull, $connection); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + } return ''; } return $frame; @@ -331,6 +368,7 @@ public static function sendHandshake($connection) $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; $connection->websocketDataBuffer = ''; + $connection->tmpWebsocketData = ''; } /** From 3c4fb8af19f6c11ec735eba05248d949ef5f6341 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 1 Nov 2016 22:18:34 +0800 Subject: [PATCH 0044/1216] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 290db9998..733ab8a6c 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name" : "workerman/workerman", - "type" : "project", + "type" : "library", "keywords": ["event-loop", "asynchronous"], "homepage": "http://www.workerman.net", "license" : "MIT", @@ -24,7 +24,7 @@ "php": ">=5.3" }, "suggest": { - "ext-libevent": "For better performance." + "ext-event": "For better performance." }, "autoload": { "psr-4": {"Workerman\\": "./"} From feb27f14717b89ebc277be919a60923cb5cb54ce Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 3 Nov 2016 21:44:15 +0800 Subject: [PATCH 0045/1216] Update Ws.php --- Protocols/Ws.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index bb1af4ebd..7dbc2554b 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -3,6 +3,7 @@ use Workerman\Worker; use Workerman\Lib\Timer; +use Workerman\Connection\TcpConnection; /** * Websocket protocol for client. From 013114daffe191f8d686d07ae4801b2decee5f8e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 3 Nov 2016 22:24:47 +0800 Subject: [PATCH 0046/1216] AsyncTcpConnection support reConnect --- Connection/AsyncTcpConnection.php | 32 ++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 0d8829f5e..9d97374b0 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -14,6 +14,7 @@ namespace Workerman\Connection; use Workerman\Events\EventInterface; +use Workerman\Lib\Timer; use Workerman\Worker; use Exception; @@ -67,10 +68,17 @@ class AsyncTcpConnection extends TcpConnection /** * Context option. * - * @var null + * @var resource */ protected $_contextOption = null; + /** + * Reconnect timer. + * + * @var int + */ + protected $_reconnectTimer = null; + /** * PHP built-in protocols. @@ -146,11 +154,11 @@ public function __construct($remote_address, $context_option = null) */ public function connect() { - if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && + if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && $this->_status !== self::STATUS_CLOSED) { return; } - $this->_status = self::STATUS_CONNECTING; + $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = microtime(true); // Open socket connection asynchronously. if ($this->_contextOption) { @@ -176,6 +184,24 @@ public function connect() Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); } + /** + * Reconnect. + * + * @param int $after + * @return void + */ + public function reConnect($after = 0) { + $this->_status = self::STATUS_INITIAL; + if ($this->_reconnectTimer) { + Timer::del($this->_reconnectTimer); + } + if ($after >= 0) { + $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false); + return; + } + return $this->connect(); + } + /** * Get remote address. * From 8a35dd5172651dd02325fecb9821563e99ac1f23 Mon Sep 17 00:00:00 2001 From: LingFeng Chen Date: Thu, 10 Nov 2016 14:26:29 +0800 Subject: [PATCH 0047/1216] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Worker=E7=9A=84?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8D=8F=E8=AE=AE=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E5=8F=AF=E4=BB=A5=E4=BD=BF=E7=94=A8namespace=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E6=8C=87=E5=AE=9A=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Worker.php | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Worker.php b/Worker.php index 722b0cb5e..cc23ffdc5 100644 --- a/Worker.php +++ b/Worker.php @@ -1356,14 +1356,21 @@ public function listen() list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { - $scheme = ucfirst($scheme); - $this->protocol = '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); - } - } + + if(class_exists($scheme){ + $this->protocol = $scheme; + } else { + $scheme = ucfirst($scheme); + $this->protocol = '\\Protocols\\' . $scheme; + if (!class_exists($this->protocol)) { + $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!class_exists($this->protocol)) { + throw new Exception("class \\Protocols\\$scheme not exist"); + } + } + } + + $local_socket = $this->transport . ":" . $address; } else { $this->transport = self::$_builtinTransports[$scheme]; From 262dcc21692e8ab8ac1d79d115e3adc6cca0535a Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Nov 2016 19:23:36 +0800 Subject: [PATCH 0048/1216] format --- Worker.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Worker.php b/Worker.php index cc23ffdc5..5b503545f 100644 --- a/Worker.php +++ b/Worker.php @@ -1356,21 +1356,18 @@ public function listen() list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { - - if(class_exists($scheme){ - $this->protocol = $scheme; - } else { - $scheme = ucfirst($scheme); - $this->protocol = '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); - } - } - } - - + if(class_exists($scheme)){ + $this->protocol = $scheme; + } else { + $scheme = ucfirst($scheme); + $this->protocol = '\\Protocols\\' . $scheme; + if (!class_exists($this->protocol)) { + $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!class_exists($this->protocol)) { + throw new Exception("class \\Protocols\\$scheme not exist"); + } + } + } $local_socket = $this->transport . ":" . $address; } else { $this->transport = self::$_builtinTransports[$scheme]; From 68fe39c5fc1f824e16a087333e0c11fe516a5cec Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 18 Nov 2016 14:50:47 +0800 Subject: [PATCH 0049/1216] Update Worker.php onMasterReload fix unix domain socket file missing --- Worker.php | 60 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/Worker.php b/Worker.php index 5b503545f..4dd1fa713 100644 --- a/Worker.php +++ b/Worker.php @@ -190,7 +190,14 @@ class Worker public $onWorkerStop = null; /** - * Emitted when worker processes get reload command. + * Emitted when the master process get reload signal. + * + * @var callback + */ + public static $onMasterReload = null; + + /** + * Emitted when worker processes get reload signal. * * @var callback */ @@ -524,6 +531,16 @@ protected static function initWorkers() } } + /** + * Get all worker instances. + * + * @return array + */ + public static function getAllWorkers() + { + return self::$_workers; + } + /** * Init idMap. * return void @@ -531,7 +548,11 @@ protected static function initWorkers() protected static function initId() { foreach (self::$_workers as $worker_id => $worker) { - self::$_idMap[$worker_id] = array_fill(0, $worker->count, 0); + $new_id_map = array(); + for($key = 0; $key < $worker->count; $key++) { + $new_id_map[$key] = isset(self::$_idMap[$worker_id][$key]) ? self::$_idMap[$worker_id][$key] : 0; + } + self::$_idMap[$worker_id] = $new_id_map; } } @@ -856,6 +877,7 @@ protected static function forkWorkers() } } + $worker->count = $worker->count <= 0 ? 1 : $worker->count; while (count(self::$_pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorker($worker); } @@ -870,9 +892,12 @@ protected static function forkWorkers() */ protected static function forkOneWorker($worker) { - $pid = pcntl_fork(); // Get available worker id. $id = self::getId($worker->workerId, 0); + if ($id === false) { + return; + } + $pid = pcntl_fork(); // For master process. if ($pid > 0) { self::$_pidMap[$worker->workerId][$pid] = $pid; @@ -906,11 +931,7 @@ protected static function forkOneWorker($worker) */ protected static function getId($worker_id, $pid) { - $id = array_search($pid, self::$_idMap[$worker_id]); - if ($id === false) { - self::safeEcho("getId fail\n"); - } - return $id; + return array_search($pid, self::$_idMap[$worker_id]); } /** @@ -1062,6 +1083,19 @@ protected static function reload() if (self::$_status !== self::STATUS_RELOADING && self::$_status !== self::STATUS_SHUTDOWN) { self::log("Workerman[" . basename(self::$_startFile) . "] reloading"); self::$_status = self::STATUS_RELOADING; + // Try to emit onMasterReload callback. + if (self::$onMasterReload) { + try { + call_user_func(self::$onMasterReload); + } catch (\Exception $e) { + self::log($e); + exit(250); + } catch (\Error $e) { + self::log($e); + exit(250); + } + self::initId(); + } } // Send reload signal to all child processes. @@ -1381,15 +1415,7 @@ public function listen() if ($this->reusePort) { stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); } - if ($this->transport === 'unix') { - umask(0); - list(, $address) = explode(':', $this->_socketName, 2); - if (!is_file($address)) { - register_shutdown_function(function () use ($address) { - @unlink($address); - }); - } - } + // Create an Internet or Unix domain server socket. $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { From 9b551e8215afa4014b886ca04bf0b3f39bbd044b Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 18 Nov 2016 18:07:52 +0800 Subject: [PATCH 0050/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9d97374b0..116aa6924 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -195,7 +195,7 @@ public function reConnect($after = 0) { if ($this->_reconnectTimer) { Timer::del($this->_reconnectTimer); } - if ($after >= 0) { + if ($after > 0) { $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false); return; } From 18ffa6631cc7a99d16876bb97104dc4beeaff732 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Nov 2016 23:07:36 +0800 Subject: [PATCH 0051/1216] Compatible IE10 IE11 pong package --- Protocols/Websocket.php | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index bd98a5152..a66504eee 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -22,13 +22,6 @@ */ class Websocket implements \Workerman\Protocols\ProtocolInterface { - /** - * Minimum head length of websocket protocol. - * - * @var int - */ - const MIN_HEAD_LEN = 2; - /** * Websocket blob type. * @@ -55,7 +48,7 @@ public static function input($buffer, ConnectionInterface $connection) // Receive length. $recv_len = strlen($buffer); // We need more data. - if ($recv_len < self::MIN_HEAD_LEN) { + if ($recv_len < 2) { return 0; } @@ -72,9 +65,11 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } } else { - $data_len = ord($buffer[1]) & 127; $firstbyte = ord($buffer[0]); + $secondbyte = ord($buffer[1]); + $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; + $masked = $secondbyte >> 7; $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: @@ -123,9 +118,10 @@ public static function input($buffer, ConnectionInterface $connection) // Consume data from receive buffer. if (!$data_len) { - $connection->consumeRecvBuffer(self::MIN_HEAD_LEN); - if ($recv_len > self::MIN_HEAD_LEN) { - return self::input(substr($buffer, self::MIN_HEAD_LEN), $connection); + $head_len = $masked ? 6 : 2; + $connection->consumeRecvBuffer($head_len); + if ($recv_len > $head_len) { + return self::input(substr($buffer, $head_len), $connection); } return 0; } @@ -146,9 +142,10 @@ public static function input($buffer, ConnectionInterface $connection) } // Consume data from receive buffer. if (!$data_len) { - $connection->consumeRecvBuffer(self::MIN_HEAD_LEN); - if ($recv_len > self::MIN_HEAD_LEN) { - return self::input(substr($buffer, self::MIN_HEAD_LEN), $connection); + $head_len = $masked ? 6 : 2; + $connection->consumeRecvBuffer($head_len); + if ($recv_len > $head_len) { + return self::input(substr($buffer, $head_len), $connection); } return 0; } @@ -296,7 +293,7 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $len = $masks = $data = $decoded = null; + $masks = $data = $decoded = null; $len = ord($buffer[1]) & 127; if ($len === 126) { $masks = substr($buffer, 4, 4); From 0ea2063b74be266427ec9eed8a20836ee9cfd651 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Nov 2016 23:10:07 +0800 Subject: [PATCH 0052/1216] Update Ws.php --- Protocols/Ws.php | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 7dbc2554b..da1451f40 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -1,4 +1,16 @@ + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ namespace Workerman\Protocols; use Workerman\Worker; @@ -10,13 +22,6 @@ */ class Ws { - /** - * Minimum head length of websocket protocol. - * - * @var int - */ - const MIN_HEAD_LEN = 2; - /** * Websocket blob type. * @@ -49,7 +54,7 @@ public static function input($buffer, $connection) return self::dealHandshake($buffer, $connection); } $recv_len = strlen($buffer); - if ($recv_len < self::MIN_HEAD_LEN) { + if ($recv_len < 2) { return 0; } // Buffer websocket frame data. @@ -60,10 +65,14 @@ public static function input($buffer, $connection) return 0; } } else { - $data_len = ord($buffer[1]) & 127; + $firstbyte = ord($buffer[0]); + $secondbyte = ord($buffer[1]); + $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; + $masked = $secondbyte >> 7; $opcode = $firstbyte & 0xf; + switch ($opcode) { case 0x0: break; @@ -110,9 +119,10 @@ public static function input($buffer, $connection) } // Consume data from receive buffer. if (!$data_len) { - $connection->consumeRecvBuffer(self::MIN_HEAD_LEN); - if ($recv_len > self::MIN_HEAD_LEN) { - return self::input(substr($buffer, self::MIN_HEAD_LEN), $connection); + $head_len = $masked ? 6 : 2; + $connection->consumeRecvBuffer($head_len); + if ($recv_len > $head_len) { + return self::input(substr($buffer, $head_len), $connection); } return 0; } @@ -133,9 +143,10 @@ public static function input($buffer, $connection) } // Consume data from receive buffer. if (!$data_len) { - $connection->consumeRecvBuffer(self::MIN_HEAD_LEN); - if ($recv_len > self::MIN_HEAD_LEN) { - return self::input(substr($buffer, self::MIN_HEAD_LEN), $connection); + $head_len = $masked ? 6 : 2; + $connection->consumeRecvBuffer($head_len); + if ($recv_len > $head_len) { + return self::input(substr($buffer, $head_len), $connection); } return 0; } From 9237b0d798e205e0fe9f449575bf49e0129e18a2 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 27 Nov 2016 16:16:28 +0800 Subject: [PATCH 0053/1216] Support ReactPHP --- Events/React.php | 230 ++++++++++++++++++++++++++++++ Events/React/ExtEventLoop.php | 76 ++++++++++ Events/React/LibEventLoop.php | 77 ++++++++++ Events/React/StreamSelectLoop.php | 71 +++++++++ Worker.php | 15 +- 5 files changed, 468 insertions(+), 1 deletion(-) create mode 100644 Events/React.php create mode 100644 Events/React/ExtEventLoop.php create mode 100644 Events/React/LibEventLoop.php create mode 100644 Events/React/StreamSelectLoop.php diff --git a/Events/React.php b/Events/React.php new file mode 100644 index 000000000..37eb2b390 --- /dev/null +++ b/Events/React.php @@ -0,0 +1,230 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events; +use React\EventLoop\LoopInterface; +use React\EventLoop\Timer\TimerInterface; + +/** + * select eventloop + */ +class React implements LoopInterface +{ + protected $_loop = null; + + public function __construct() { + if (function_exists('event_base_new')) { + $this->_loop = new \Workerman\Events\React\LibEventLoop(); + } elseif (class_exists('EventBase', false)) { + $this->_loop = new \Workerman\Events\React\ExtEventLoop(); + } else { + $this->_loop = new \Workerman\Events\React\StreamSelectLoop(); + } + } + + public function add($fd, $flag, $func, $args = array()) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->_loop->addReadStream($fd, $func); + case EventInterface::EV_WRITE: + return $this->_loop->addWriteStream($fd, $func); + case EventInterface::EV_SIGNAL: + return $this->_loop->addSignal($fd, $func); + case EventInterface::EV_TIMER: + return $this->_loop->addPeriodicTimer($fd, $func); + case EventInterface::EV_TIMER_ONCE: + return $this->_loop->addTimer($fd, $func); + } + return false; + } + + public function del($fd, $flag) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->_loop->removeReadStream($fd); + case EventInterface::EV_WRITE: + return $this->_loop->removeWriteStream($fd); + case EventInterface::EV_SIGNAL: + return $this->_loop->removeSignal($fd); + case EventInterface::EV_TIMER: + case EventInterface::EV_TIMER_ONCE; + return $this->_loop->cancelTimer($fd); + } + return false; + } + + /** + * {@inheritdoc} + */ + public function clearAllTimer() + { + + } + + public function getLoop() + { + return $this->_loop; + } + + + /** + * {@inheritdoc} + */ + public function loop() + { + $this->_loop->run(); + } + + /** + * Register a listener to be notified when a stream is ready to read. + * + * @param resource $stream The PHP stream resource to check. + * @param callable $listener Invoked when the stream is ready. + */ + public function addReadStream($stream, callable $listener) { + return call_user_func(array($this->_loop, 'addReadStream'), $stream, $listener); + } + + /** + * Register a listener to be notified when a stream is ready to write. + * + * @param resource $stream The PHP stream resource to check. + * @param callable $listener Invoked when the stream is ready. + */ + public function addWriteStream($stream, callable $listener) { + return call_user_func(array($this->_loop, 'addWriteStream'), $stream, $listener); + } + + /** + * Remove the read event listener for the given stream. + * + * @param resource $stream The PHP stream resource. + */ + public function removeReadStream($stream) { + return call_user_func(array($this->_loop, 'removeReadStream'), $stream); + } + + /** + * Remove the write event listener for the given stream. + * + * @param resource $stream The PHP stream resource. + */ + public function removeWriteStream($stream) { + return call_user_func(array($this->_loop, 'removeWriteStream'), $stream); + } + + /** + * Remove all listeners for the given stream. + * + * @param resource $stream The PHP stream resource. + */ + public function removeStream($stream) { + return call_user_func(array($this->_loop, 'removeStream'), $stream); + } + + /** + * Enqueue a callback to be invoked once after the given interval. + * + * The execution order of timers scheduled to execute at the same time is + * not guaranteed. + * + * @param int|float $interval The number of seconds to wait before execution. + * @param callable $callback The callback to invoke. + * + * @return TimerInterface + */ + public function addTimer($interval, callable $callback) { + return call_user_func(array($this->_loop, 'addTimer'), $interval, $callback); + } + + /** + * Enqueue a callback to be invoked repeatedly after the given interval. + * + * The execution order of timers scheduled to execute at the same time is + * not guaranteed. + * + * @param int|float $interval The number of seconds to wait before execution. + * @param callable $callback The callback to invoke. + * + * @return TimerInterface + */ + public function addPeriodicTimer($interval, callable $callback) { + return call_user_func(array($this->_loop, 'addPeriodicTimer'), $interval, $callback); + } + + /** + * Cancel a pending timer. + * + * @param TimerInterface $timer The timer to cancel. + */ + public function cancelTimer(TimerInterface $timer) { + return call_user_func(array($this->_loop, 'cancelTimer'), $timer); + } + + /** + * Check if a given timer is active. + * + * @param TimerInterface $timer The timer to check. + * + * @return boolean True if the timer is still enqueued for execution. + */ + public function isTimerActive(TimerInterface $timer) { + return call_user_func(array($this->_loop, 'isTimerActive'), $timer); + } + + /** + * Schedule a callback to be invoked on the next tick of the event loop. + * + * Callbacks are guaranteed to be executed in the order they are enqueued, + * before any timer or stream events. + * + * @param callable $listener The callback to invoke. + */ + public function nextTick(callable $listener) { + return call_user_func(array($this->_loop, 'nextTick'), $listener); + } + + /** + * Schedule a callback to be invoked on a future tick of the event loop. + * + * Callbacks are guaranteed to be executed in the order they are enqueued. + * + * @param callable $listener The callback to invoke. + */ + public function futureTick(callable $listener) { + return call_user_func(array($this->_loop, 'futureTick'), $listener); + } + + /** + * Perform a single iteration of the event loop. + */ + public function tick() { + return call_user_func(array($this->_loop, 'tick')); + } + + /** + * Run the event loop until there are no more tasks to perform. + */ + public function run() { + return call_user_func(array($this->_loop, 'run')); + } + + /** + * Instruct a running event loop to stop. + */ + public function stop() { + return call_user_func(array($this->_loop, 'stop')); + } +} diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php new file mode 100644 index 000000000..ccb504182 --- /dev/null +++ b/Events/React/ExtEventLoop.php @@ -0,0 +1,76 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events\React; + +/** + * Class ExtEventLoop + * @package Workerman\Events\React + */ +class ExtEventLoop extends \React\EventLoop\ExtEventLoop +{ + /** + * Event base. + * + * @var EventBase + */ + protected $_eventBase = null; + + /** + * All signal Event instances. + * + * @var array + */ + protected $_signalEvents = array(); + + /** + * Construct + */ + public function __construct() + { + parent::__construct(); + $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop'); + $property = $class->getProperty('eventBase'); + $property->setAccessible(true); + $this->_eventBase = $property->getValue($this); + } + + /** + * Add signal handler. + * + * @param $signal + * @param $callback + * @return bool + */ + public function addSignal($signal, $callback) + { + $event = \Event::signal($this->_eventBase, $signal, $callback); + if (!$event||!$event->add()) { + return false; + } + $this->_signalEvents[$signal] = $event; + } + + /** + * Remove signal handler. + * + * @param $signal + */ + public function removeSignal($signal) + { + if (isset($this->_signalEvents[$signal])) { + $this->_signalEvents[$signal]->del(); + unset($this->_signalEvents[$signal]); + } + } +} diff --git a/Events/React/LibEventLoop.php b/Events/React/LibEventLoop.php new file mode 100644 index 000000000..1dbf3900d --- /dev/null +++ b/Events/React/LibEventLoop.php @@ -0,0 +1,77 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events\React; + +/** + * Class LibEventLoop + * @package Workerman\Events\React + */ +class LibEventLoop extends \React\EventLoop\LibEventLoop +{ + /** + * Event base. + * + * @var event_base resource + */ + protected $_eventBase = null; + + /** + * All signal Event instances. + * + * @var array + */ + protected $_signalEvents = array(); + + /** + * Construct. + */ + public function __construct() + { + parent::__construct(); + $class = new \ReflectionClass('\React\EventLoop\LibEventLoop'); + $property = $class->getProperty('eventBase'); + $property->setAccessible(true); + $this->_eventBase = $property->getValue($this); + } + + /** + * Add signal handler. + * + * @param $signal + * @param $callback + * @return bool + */ + public function addSignal($signal, $callback) + { + $event = event_new(); + $this->_signalEvents[$signal] = $event; + event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback); + event_base_set($event, $this->_eventBase); + event_add($event); + } + + /** + * Remove signal handler. + * + * @param $signal + */ + public function removeSignal($signal) + { + if (isset($this->_signalEvents[$signal])) { + $event = $this->_signalEvents[$signal]; + event_del($event); + unset($this->_signalEvents[$signal]); + } + } +} diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php new file mode 100644 index 000000000..a83420646 --- /dev/null +++ b/Events/React/StreamSelectLoop.php @@ -0,0 +1,71 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events\React; + +/** + * Class StreamSelectLoop + * @package Workerman\Events\React + */ +class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop +{ + /** + * Add signal handler. + * + * @param $signal + * @param $callback + * @return bool + */ + public function addSignal($signal, $callback) + { + pcntl_signal($signal, $callback); + } + + /** + * Remove signal handler. + * + * @param $signal + */ + public function removeSignal($signal) + { + pcntl_signal($signal, SIG_IGN); + } + + /** + * Emulate a stream_select() implementation that does not break when passed + * empty stream arrays. + * + * @param array &$read An array of read streams to select upon. + * @param array &$write An array of write streams to select upon. + * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. + * + * @return integer|false The total number of streams that are ready for read/write. + * Can return false if stream_select() is interrupted by a signal. + */ + protected function streamSelect(array &$read, array &$write, $timeout) + { + if ($read || $write) { + $except = null; + // Calls signal handlers for pending signals + pcntl_signal_dispatch(); + // suppress warnings that occur, when stream_select is interrupted by a signal + return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); + } + + // Calls signal handlers for pending signals + pcntl_signal_dispatch(); + $timeout && usleep($timeout); + + return 0; + } +} diff --git a/Worker.php b/Worker.php index 4dd1fa713..e63a2fc81 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.5'; + const VERSION = '3.3.6'; /** * Status starting. @@ -541,6 +541,16 @@ public static function getAllWorkers() return self::$_workers; } + /** + * Get global event-loop instance. + * + * @return EventInterface + */ + public static function getEventLoop() + { + return self::$globalEvent; + } + /** * Init idMap. * return void @@ -834,6 +844,9 @@ protected static function saveMasterPid() */ protected static function getEventLoopName() { + if (interface_exists('\React\EventLoop\LoopInterface')) { + return 'React'; + } foreach (self::$_availableEventLoops as $name) { if (extension_loaded($name)) { self::$_eventLoopName = $name; From c2e66e75a8c461a52a738ba004ef845397ce64ff Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 27 Nov 2016 16:23:04 +0800 Subject: [PATCH 0054/1216] comments --- Events/React.php | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/Events/React.php b/Events/React.php index 37eb2b390..c4a7a8aec 100644 --- a/Events/React.php +++ b/Events/React.php @@ -20,8 +20,14 @@ */ class React implements LoopInterface { + /** + * @var React\EventLoop\LoopInterface + */ protected $_loop = null; + /** + * React constructor. + */ public function __construct() { if (function_exists('event_base_new')) { $this->_loop = new \Workerman\Events\React\LibEventLoop(); @@ -32,6 +38,15 @@ public function __construct() { } } + /** + * Add event listener to event loop. + * + * @param $fd + * @param $flag + * @param $func + * @param array $args + * @return bool + */ public function add($fd, $flag, $func, $args = array()) { switch ($flag) { @@ -49,6 +64,13 @@ public function add($fd, $flag, $func, $args = array()) return false; } + /** + * Remove event listener from event loop. + * + * @param mixed $fd + * @param int $flag + * @return bool + */ public function del($fd, $flag) { switch ($flag) { @@ -65,22 +87,11 @@ public function del($fd, $flag) return false; } - /** - * {@inheritdoc} - */ - public function clearAllTimer() - { - - } - - public function getLoop() - { - return $this->_loop; - } - /** - * {@inheritdoc} + * Main loop. + * + * @return void */ public function loop() { From c7f8e3eab14ba3dbda71efb4840ab139ad915379 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 28 Nov 2016 21:25:24 +0800 Subject: [PATCH 0055/1216] gc session --- Protocols/Http.php | 55 ++++++++++++++++++++++++++++++++++++++++------ WebServer.php | 6 ++--- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 07d4df4fe..ebe726c3c 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -307,8 +307,11 @@ public static function sessionStart() if (PHP_SAPI != 'cli') { return session_start(); } + + self::tryGcSessions(); + if (HttpCache::$instance->sessionStarted) { - echo "already sessionStarted\nn"; + echo "already sessionStarted\n"; return true; } HttpCache::$instance->sessionStarted = true; @@ -433,6 +436,27 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) } } } + + /** + * Try GC sessions. + * + * @return void + */ + public static function tryGcSessions() + { + if (HttpCache::$sessionGcProbability <= 0 || + HttpCache::$sessionGcDivisor <= 0 || + rand(1, HttpCache::$sessionGcDivisor) > HttpCache::$sessionGcProbability) { + return; + } + + $time_now = time(); + foreach(glob(HttpCache::$sessionPath.'/ses*') as $file) { + if(is_file($file) && $time_now - filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { + unlink($file); + } + } + } } /** @@ -489,11 +513,13 @@ class HttpCache /** * @var HttpCache */ - public static $instance = null; - - public static $header = array(); - public static $sessionPath = ''; - public static $sessionName = ''; + public static $instance = null; + public static $header = array(); + public static $sessionPath = ''; + public static $sessionName = ''; + public static $sessionGcProbability = 1; + public static $sessionGcDivisor = 1000; + public static $sessionGcMaxLifeTime = 1440; public $sessionStarted = false; public $sessionFile = ''; @@ -501,9 +527,24 @@ public static function init() { self::$sessionName = ini_get('session.name'); self::$sessionPath = session_save_path(); - if (!self::$sessionPath) { + if (!self::$sessionPath || strpos(self::$sessionPath, 'tcp://') === 0) { self::$sessionPath = sys_get_temp_dir(); } + + if ($gc_probability = ini_get('session.gc_probability')) { + self::$sessionGcProbability = $gc_probability; + } + + if ($gc_divisor = ini_get('session.gc_divisor')) { + self::$sessionGcDivisor = $gc_divisor; + } + + if ($gc_max_life_time = ini_get('session.gc_maxlifetime')) { + self::$sessionGcMaxLifeTime = $gc_max_life_time; + } + @\session_start(); } } + +HttpCache::init(); diff --git a/WebServer.php b/WebServer.php index a243a099e..235246d96 100644 --- a/WebServer.php +++ b/WebServer.php @@ -89,10 +89,10 @@ public function run() public function onWorkerStart() { if (empty($this->serverRoot)) { - throw new \Exception('server root not set, please use WebServer::addRoot($domain, $root_path) to set server root path'); + echo new \Exception('server root not set, please use WebServer::addRoot($domain, $root_path) to set server root path'); + exit(250); } - // Init HttpCache. - HttpCache::init(); + // Init mimeMap. $this->initMimeTypeMap(); From f197c4614945f9bdcedf9e79749ece0a8cb268a4 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 29 Nov 2016 20:56:05 +0800 Subject: [PATCH 0056/1216] Update Websocket.php --- Protocols/Websocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index a66504eee..81969f680 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -345,7 +345,7 @@ protected static function dealHandshake($buffer, $connection) if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.
See http://wiki.workerman.net/Error1", + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.
See http://wiki.workerman.net/Error1 for detail.", true); $connection->close(); return 0; @@ -410,7 +410,7 @@ protected static function dealHandshake($buffer, $connection) return 0; } // Bad websocket handshake request. - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Invalid handshake data for websocket. ", + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Invalid handshake data for websocket.
See http://wiki.workerman.net/Error1 for detail.", true); $connection->close(); return 0; From fa22658b4598836239161cc29795677ce7850119 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 1 Dec 2016 23:16:38 +0800 Subject: [PATCH 0057/1216] Update README.md --- README.md | 174 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 154 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index edc0efeff..4f807da82 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,9 @@ composer require workerman/workerman ## Basic Usage ### A websocket server -test.php ```php onWorkerStart = function($task) Worker::runAll(); ``` -run with: +### AsyncTcpConnection +```php +require_once __DIR__ . '/vendor/autoload.php'; +use Workerman\Worker; +use Workerman\Connection\AsyncTcpConnection; + +$worker = new Worker(); +$worker->onWorkerStart = function() +{ + // Websocket protocol for client. + $ws_connection = new AsyncTcpConnection("ws://echo.websocket.org:80"); + $ws_connection->onConnect = function($connection){ + $connection->send('hello'); + }; + $ws_connection->onMessage = function($connection, $data){ + echo "recv: $data\n"; + }; + $ws_connection->onError = function($connection, $code, $msg){ + echo "error: $msg\n"; + }; + $ws_connection->onClose = function($connection){ + echo "connection closed\n"; + }; + $ws_connection->connect(); +}; +Worker::runAll(); +``` + +### Work with Async Mysql of ReactPHP +``` +composer require react/mysql +``` + +```php +onWorkerStart = function() { + global $mysql; + $loop = Worker::getEventLoop(); + $mysql = new React\MySQL\Connection($loop, array( + 'host' => '127.0.0.1', + 'dbname' => 'dbname', + 'user' => 'user', + 'passwd' => 'passwd', + )); + $mysql->on('error', function($e){ + echo $e; + }); + $mysql->connect(function ($e) { + if($e) { + echo $e; + } else { + echo "connect success\n"; + } + }); +}; +$worker->onMessage = function($connection, $data) { + global $mysql; + $mysql->query('show databases' /*trim($data)*/, function ($command, $mysql) use ($connection) { + if ($command->hasError()) { + $error = $command->getError(); + } else { + $results = $command->resultRows; + $fields = $command->resultFields; + $connection->send(json_encode($results)); + } + }); +}; +Worker::runAll(); +``` + +### Work with Async Redis of ReactPHP +``` +composer require clue/redis-react +``` + +```php +onWorkerStart = function() { + global $factory; + $loop = Worker::getEventLoop(); + $factory = new Factory($loop); +}; + +$worker->onMessage = function($connection, $data) { + global $factory; + $factory->createClient('localhost:6379')->then(function (Client $client) use ($connection) { + $client->set('greeting', 'Hello world'); + $client->append('greeting', '!'); + + $client->get('greeting')->then(function ($greeting) use ($connection){ + // Hello world! + echo $greeting . PHP_EOL; + $connection->send($greeting); + }); + + $client->incr('invocation')->then(function ($n) use ($connection){ + echo 'This is invocation #' . $n . PHP_EOL; + $connection->send($n); + }); + }); +}; + +Worker::runAll(); +``` + +### Work with Aysnc dns of ReactPHP +``` +composer require react/dns +``` + +```php +require_once __DIR__ . '/vendor/autoload.php'; +use Workerman\Worker; +$worker = new Worker('tcp://0.0.0.0:6161'); +$worker->onWorkerStart = function() { + global $dns; + // Get event-loop. + $loop = Worker::getEventLoop(); + $factory = new React\Dns\Resolver\Factory(); + $dns = $factory->create('8.8.8.8', $loop); +}; +$worker->onMessage = function($connection, $host) { + global $dns; + $host = trim($host); + $dns->resolve($host)->then(function($ip) use($host, $connection) { + $connection->send("$host: $ip"); + },function($e) use($host, $connection){ + $connection->send("$host: {$e->getMessage()}"); + }); +}; + +Worker::runAll(); +``` ## Available commands ```php test.php start ``` @@ -325,7 +459,12 @@ Percentage of the requests served within a certain time (ms) ``` -# Demos +## other links with workerman + +## [PHPSocket.IO](https://github.com/walkor/phpsocket.io) +[Live demo](http://www.workerman.net/demos/phpsocketio-chat/) +[Source code](https://github.com/walkor/phpsocket.io) +![phpsocket.io](http://www.workerman.net/img/socket.io.png) ## [tadpole](http://kedou.workerman.net/) [Live demo](http://kedou.workerman.net/) @@ -359,11 +498,6 @@ Percentage of the requests served within a certain time (ms) [Source code](https://github.com/walkor/workerman-chat) ![workerman-chat](http://www.workerman.net/img/workerman-chat.png) -## [PHPSocket.IO](https://github.com/walkor/phpsocket.io) -[Live demo](http://www.workerman.net/demos/phpsocketio-chat/) -[Source code](https://github.com/walkor/phpsocket.io) -![phpsocket.io](http://www.workerman.net/img/socket.io.png) - ## [statistics](http://www.workerman.net:55757/) [Live demo](http://www.workerman.net:55757/) [Source code](https://github.com/walkor/workerman-statistics) From 4c0fc3b5d47b26250f306f260d6827869aa13f6c Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 1 Dec 2016 23:29:35 +0800 Subject: [PATCH 0058/1216] Update README.md --- README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4f807da82..d4b5a14c3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ composer require workerman/workerman ### A websocket server ```php onWorkerStart = function($task) Worker::runAll(); ``` -### AsyncTcpConnection +### AsyncTcpConnection (tcp/ws/text/frame etc...) ```php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; @@ -241,7 +242,7 @@ $worker->onWorkerStart = function() Worker::runAll(); ``` -### Work with Async Mysql of ReactPHP +### Async Mysql of ReactPHP ``` composer require react/mysql ``` @@ -287,7 +288,7 @@ $worker->onMessage = function($connection, $data) { Worker::runAll(); ``` -### Work with Async Redis of ReactPHP +### Async Redis of ReactPHP ``` composer require clue/redis-react ``` @@ -329,7 +330,7 @@ $worker->onMessage = function($connection, $data) { Worker::runAll(); ``` -### Work with Aysnc dns of ReactPHP +### Aysnc dns of ReactPHP ``` composer require react/dns ``` @@ -358,6 +359,145 @@ $worker->onMessage = function($connection, $host) { Worker::runAll(); ``` +### Http client of ReactPHP +``` +composer require react/http-client +``` + +```php +onWorkerStart = function() { + global $client; + $loop = Worker::getEventLoop(); + $factory = new React\Dns\Resolver\Factory(); + $dns = $factory->createCached('8.8.8.8', $loop); + $factory = new React\HttpClient\Factory(); + $client = $factory->create($loop, $dns); +}; + +$worker->onMessage = function($connection, $host) { + global $client; + $request = $client->request('GET', trim($host)); + $request->on('error', function(Exception $e) use ($connection) { + $connection->send($e); + }); + $request->on('response', function ($response) use ($connection) { + $response->on('data', function ($data, $response) use ($connection) { + $connection->send($data); + }); + }); + $request->end(); +}; + +Worker::runAll(); +``` + +### Http client of ReactPHP +``` +composer require react/http-client +``` + +```php +onWorkerStart = function() { + global $client; + $loop = Worker::getEventLoop(); + $factory = new React\Dns\Resolver\Factory(); + $dns = $factory->createCached('8.8.8.8', $loop); + $factory = new React\HttpClient\Factory(); + $client = $factory->create($loop, $dns); +}; + +$worker->onMessage = function($connection, $host) { + global $client; + $request = $client->request('GET', trim($host)); + $request->on('error', function(Exception $e) use ($connection) { + $connection->send($e); + }); + $request->on('response', function ($response) use ($connection) { + $response->on('data', function ($data, $response) use ($connection) { + $connection->send($data); + }); + }); + $request->end(); +}; + +Worker::runAll(); +``` + +### ZMQ of ReactPHP +``` +composer require react/zmq +``` + +```php +onWorkerStart = function() { + global $pull; + $loop = Worker::getEventLoop(); + $context = new React\ZMQ\Context($loop); + $pull = $context->getSocket(ZMQ::SOCKET_PULL); + $pull->bind('tcp://127.0.0.1:5555'); + + $pull->on('error', function ($e) { + var_dump($e->getMessage()); + }); + + $pull->on('message', function ($msg) { + echo "Received: $msg\n"; + }); +}; + +Worker::runAll(); +``` + +### STOMP of ReactPHP +``` +composer require react/stomp +``` + +```php +onWorkerStart = function() { + global $client; + $loop = Worker::getEventLoop(); + $factory = new React\Stomp\Factory($loop); + $client = $factory->createClient(array('vhost' => '/', 'login' => 'guest', 'passcode' => 'guest')); + + $client + ->connect() + ->then(function ($client) use ($loop) { + $client->subscribe('/topic/foo', function ($frame) { + echo "Message received: {$frame->body}\n"; + }); + }); +}; + +Worker::runAll(); +``` + + + ## Available commands ```php test.php start ``` ```php test.php start -d ``` From 0b675f34f353e2b9b7bf95db3738ff18b8d8da14 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 1 Dec 2016 23:40:50 +0800 Subject: [PATCH 0059/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4b5a14c3..ef90b1164 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Gitter](https://badges.gitter.im/walkor/Workerman.svg)](https://gitter.im/walkor/Workerman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) ## What is it -Workerman is a library for event-driven programming in PHP. It has a huge number of features. Each worker is able to handle thousands of connections. +Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications.Supports HTTP, Websocket and other custom protocols. Supports libevent, HHVM, [ReactPHP](https://github.com/reactphp/react). ## Requires From 69b3b7b481541dea3c41979b888f44ed77e8776b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 1 Dec 2016 23:41:24 +0800 Subject: [PATCH 0060/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef90b1164..c77a433e6 100644 --- a/README.md +++ b/README.md @@ -599,7 +599,7 @@ Percentage of the requests served within a certain time (ms) ``` -## other links with workerman +## Other links with workerman ## [PHPSocket.IO](https://github.com/walkor/phpsocket.io) [Live demo](http://www.workerman.net/demos/phpsocketio-chat/) From f0b1dc485d69d95704454eb7d906b9d90c6b05a6 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 2 Dec 2016 23:48:42 +0800 Subject: [PATCH 0061/1216] Update README.md --- README.md | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/README.md b/README.md index c77a433e6..17b687dec 100644 --- a/README.md +++ b/README.md @@ -397,44 +397,6 @@ $worker->onMessage = function($connection, $host) { Worker::runAll(); ``` -### Http client of ReactPHP -``` -composer require react/http-client -``` - -```php -onWorkerStart = function() { - global $client; - $loop = Worker::getEventLoop(); - $factory = new React\Dns\Resolver\Factory(); - $dns = $factory->createCached('8.8.8.8', $loop); - $factory = new React\HttpClient\Factory(); - $client = $factory->create($loop, $dns); -}; - -$worker->onMessage = function($connection, $host) { - global $client; - $request = $client->request('GET', trim($host)); - $request->on('error', function(Exception $e) use ($connection) { - $connection->send($e); - }); - $request->on('response', function ($response) use ($connection) { - $response->on('data', function ($data, $response) use ($connection) { - $connection->send($data); - }); - }); - $request->end(); -}; - -Worker::runAll(); -``` - ### ZMQ of ReactPHP ``` composer require react/zmq From 2511ff527c46c4609974ffe012569b81dbd86d56 Mon Sep 17 00:00:00 2001 From: sm2017 Date: Sun, 11 Dec 2016 14:02:33 +0330 Subject: [PATCH 0062/1216] Update Websocket.php To easier extending WebSocket protocol --- Protocols/Websocket.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 81969f680..2ab5635da 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -54,7 +54,7 @@ public static function input($buffer, ConnectionInterface $connection) // Has not yet completed the handshake. if (empty($connection->websocketHandshake)) { - return self::dealHandshake($buffer, $connection); + return static::dealHandshake($buffer, $connection); } // Buffer websocket frame data. @@ -121,7 +121,7 @@ public static function input($buffer, ConnectionInterface $connection) $head_len = $masked ? 6 : 2; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { - return self::input(substr($buffer, $head_len), $connection); + return static::input(substr($buffer, $head_len), $connection); } return 0; } @@ -145,7 +145,7 @@ public static function input($buffer, ConnectionInterface $connection) $head_len = $masked ? 6 : 2; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { - return self::input(substr($buffer, $head_len), $connection); + return static::input(substr($buffer, $head_len), $connection); } return 0; } @@ -194,18 +194,18 @@ public static function input($buffer, ConnectionInterface $connection) // Received just a frame length data. if ($connection->websocketCurrentFrameLength === $recv_len) { - self::decode($buffer, $connection); + static::decode($buffer, $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $connection->websocketCurrentFrameLength = 0; return 0; } // The length of the received data is greater than the length of a frame. elseif ($connection->websocketCurrentFrameLength < $recv_len) { - self::decode(substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); + static::decode(substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $current_frame_length = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. - return self::input(substr($buffer, $current_frame_length), $connection); + return static::input(substr($buffer, $current_frame_length), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -226,7 +226,7 @@ public static function encode($buffer, ConnectionInterface $connection) } $len = strlen($buffer); if (empty($connection->websocketType)) { - $connection->websocketType = self::BINARY_TYPE_BLOB; + $connection->websocketType = static::BINARY_TYPE_BLOB; } $first_byte = $connection->websocketType; @@ -379,11 +379,11 @@ protected static function dealHandshake($buffer, $connection) } // blob or arraybuffer if (empty($connection->websocketType)) { - $connection->websocketType = self::BINARY_TYPE_BLOB; + $connection->websocketType = static::BINARY_TYPE_BLOB; } // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { - self::parseHttpHeader($buffer); + static::parseHttpHeader($buffer); try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { @@ -399,7 +399,7 @@ protected static function dealHandshake($buffer, $connection) $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); } if (strlen($buffer) > $header_length) { - return self::input(substr($buffer, $header_length), $connection); + return static::input(substr($buffer, $header_length), $connection); } return 0; } // Is flash policy-file-request. From a3c1c513343204f4718fcf3bc4e61da3a8fb47bc Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 11 Dec 2016 21:55:01 +0800 Subject: [PATCH 0063/1216] Update React.php --- Events/React.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Events/React.php b/Events/React.php index c4a7a8aec..52e6f710b 100644 --- a/Events/React.php +++ b/Events/React.php @@ -57,9 +57,13 @@ public function add($fd, $flag, $func, $args = array()) case EventInterface::EV_SIGNAL: return $this->_loop->addSignal($fd, $func); case EventInterface::EV_TIMER: - return $this->_loop->addPeriodicTimer($fd, $func); + return $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); case EventInterface::EV_TIMER_ONCE: - return $this->_loop->addTimer($fd, $func); + return $this->_loop->addTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); } return false; } From 601c7cdd21c8b718937b980b5bb3013a09ed0e7d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Dec 2016 18:48:13 +0800 Subject: [PATCH 0064/1216] Fix #120 --- Events/React.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Events/React.php b/Events/React.php index 52e6f710b..cae8c5013 100644 --- a/Events/React.php +++ b/Events/React.php @@ -58,11 +58,11 @@ public function add($fd, $flag, $func, $args = array()) return $this->_loop->addSignal($fd, $func); case EventInterface::EV_TIMER: return $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); + call_user_func_array($func, (array)$args); }); case EventInterface::EV_TIMER_ONCE: return $this->_loop->addTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); + call_user_func_array($func, (array)$args); }); } return false; From 0a44018e7850d6d3d78166b89c59bb1dccc77b47 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Dec 2016 19:05:51 +0800 Subject: [PATCH 0065/1216] Update React.php --- Events/React.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Events/React.php b/Events/React.php index cae8c5013..3b66bde80 100644 --- a/Events/React.php +++ b/Events/React.php @@ -49,6 +49,7 @@ public function __construct() { */ public function add($fd, $flag, $func, $args = array()) { + $args = (array)$args; switch ($flag) { case EventInterface::EV_READ: return $this->_loop->addReadStream($fd, $func); @@ -58,11 +59,11 @@ public function add($fd, $flag, $func, $args = array()) return $this->_loop->addSignal($fd, $func); case EventInterface::EV_TIMER: return $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, (array)$args); + call_user_func_array($func, $args); }); case EventInterface::EV_TIMER_ONCE: return $this->_loop->addTimer($fd, function() use ($func, $args) { - call_user_func_array($func, (array)$args); + call_user_func_array($func, $args); }); } return false; From cd23eadedced3186d50950b75aab8d9ff37ab3fc Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Dec 2016 22:26:44 +0800 Subject: [PATCH 0066/1216] Support Worker::$onMasterStop callback --- Worker.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Worker.php b/Worker.php index e63a2fc81..74aa40cd2 100644 --- a/Worker.php +++ b/Worker.php @@ -189,13 +189,6 @@ class Worker */ public $onWorkerStop = null; - /** - * Emitted when the master process get reload signal. - * - * @var callback - */ - public static $onMasterReload = null; - /** * Emitted when worker processes get reload signal. * @@ -266,6 +259,20 @@ class Worker */ public static $globalEvent = null; + /** + * Emitted when the master process get reload signal. + * + * @var callback + */ + public static $onMasterReload = null; + + /** + * Emitted when the master process terminated. + * + * @var callback + */ + public static $onMasterStop = null; + /** * The PID of master process. * @@ -1080,6 +1087,9 @@ protected static function exitAndClearAll() } @unlink(self::$pidFile); self::log("Workerman[" . basename(self::$_startFile) . "] has been stopped"); + if (self::$onMasterStop) { + call_user_func(self::$onMasterStop); + } exit(0); } From cc02f47bb7bd5f2ce053cf75fcac02565aa729cf Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Dec 2016 22:28:34 +0800 Subject: [PATCH 0067/1216] Compatible with windows --- Events/React/StreamSelectLoop.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index a83420646..5ab8bc7e8 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -28,7 +28,9 @@ class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop */ public function addSignal($signal, $callback) { - pcntl_signal($signal, $callback); + if(PHP_EOL !== "\r\n") { + pcntl_signal($signal, $callback); + } } /** @@ -38,7 +40,9 @@ public function addSignal($signal, $callback) */ public function removeSignal($signal) { - pcntl_signal($signal, SIG_IGN); + if(PHP_EOL !== "\r\n") { + pcntl_signal($signal, SIG_IGN); + } } /** @@ -63,7 +67,9 @@ protected function streamSelect(array &$read, array &$write, $timeout) } // Calls signal handlers for pending signals - pcntl_signal_dispatch(); + if(PHP_EOL !== "\r\n") { + pcntl_signal_dispatch(); + } $timeout && usleep($timeout); return 0; From e3b1eea5ef24cb1bf394541a1ade35143c0d73b0 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 29 Dec 2016 21:25:09 +0800 Subject: [PATCH 0068/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 74aa40cd2..240a60776 100644 --- a/Worker.php +++ b/Worker.php @@ -76,7 +76,7 @@ class Worker * * @var int */ - const DEFAULT_BACKLOG = 1024; + const DEFAULT_BACKLOG = 102400; /** * Max udp package size. * From ce50ca62010fa6bb4af9c57daa088dd5e339455b Mon Sep 17 00:00:00 2001 From: Stephen Lee Date: Mon, 2 Jan 2017 22:45:37 +0800 Subject: [PATCH 0069/1216] Added the HTTP request method: PUT,DELETE,HEAD,OPTIONS to Http.php --- Protocols/Http.php | 53 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index ebe726c3c..30c3ba918 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -21,6 +21,12 @@ */ class Http { + /** + * The supported HTTP methods + * @var array + */ + public static $methods = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'); + /** * Check the integrity of the package. * @@ -40,23 +46,36 @@ public static function input($recv_buffer, TcpConnection $connection) } list($header,) = explode("\r\n\r\n", $recv_buffer, 2); - if (0 === strpos($recv_buffer, "POST")) { - // find Content-Length - $match = array(); - if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) { - $content_length = $match[1]; - return $content_length + strlen($header) + 4; - } else { - return 0; - } - } elseif (0 === strpos($recv_buffer, "GET")) { - return strlen($header) + 4; - } else { + $method = substr($header, 0, strpos($header, ' ')); + + if(in_array($method, static::$methods)) { + return static::getRequestSize($header, $method); + }else{ $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } } + /** + * Get whole size of the request + * includes the request headers and request body. + * @param string $header The request headers + * @param string $method The request method + * @return integer + */ + protected static function getRequestSize($header, $method) + { + if($method=='GET') { + return strlen($header) + 4; + } + $match = array(); + if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) { + $content_length = isset($match[1]) ? $match[1] : 0; + return $content_length + strlen($header) + 4; + } + return 0; + } + /** * Parse $_POST、$_GET、$_COOKIE. * @@ -144,10 +163,18 @@ public static function decode($recv_buffer, TcpConnection $connection) } else { parse_str($http_body, $_POST); // $GLOBALS['HTTP_RAW_POST_DATA'] - $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } } + if ($_SERVER['REQUEST_METHOD'] === 'PUT') { + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; + } + + if ($_SERVER['REQUEST_METHOD'] === 'DELETE') { + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; + } + // QUERY_STRING $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { From 1d27cfa43364db53202415e93e7d3178faa1ed8d Mon Sep 17 00:00:00 2001 From: Joanne Date: Fri, 13 Jan 2017 15:45:32 +0100 Subject: [PATCH 0070/1216] Check if $fd is null before call cancelTimer Fix error: "Argument 1 passed to React\EventLoop\StreamSelectLoop::cancelTimer() must implement interface React\EventLoop\Timer\TimerInterface, null given, called in workerman/Events/React.php on line 90" --- Events/React.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Events/React.php b/Events/React.php index 3b66bde80..be8c87fb7 100644 --- a/Events/React.php +++ b/Events/React.php @@ -87,7 +87,9 @@ public function del($fd, $flag) return $this->_loop->removeSignal($fd); case EventInterface::EV_TIMER: case EventInterface::EV_TIMER_ONCE; - return $this->_loop->cancelTimer($fd); + if ($fd !== null){ + return $this->_loop->cancelTimer($fd); + } } return false; } From f31dfd214f09fd4b3b757c2b861f6f31e8ec86a1 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Jan 2017 19:08:22 +0800 Subject: [PATCH 0071/1216] support ssl --- Worker.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Worker.php b/Worker.php index 240a60776..524e42cec 100644 --- a/Worker.php +++ b/Worker.php @@ -411,10 +411,7 @@ class Worker 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', - 'ssl' => 'tcp', - 'sslv2' => 'tcp', - 'sslv3' => 'tcp', - 'tls' => 'tcp' + 'ssl' => 'tcp' ); /** @@ -1408,7 +1405,6 @@ public function listen() // Autoload. Autoloader::setRootPath($this->_autoloadRootPath); - $local_socket = $this->_socketName; // Get the application layer communication protocol and listening address. list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. @@ -1425,11 +1421,15 @@ public function listen() } } } - $local_socket = $this->transport . ":" . $address; + if (!isset(self::$_builtinTransports[$this->transport])) { + throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); + } } else { - $this->transport = self::$_builtinTransports[$scheme]; + $this->transport = $scheme; } + $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address; + // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $errno = 0; @@ -1445,8 +1445,12 @@ public function listen() throw new Exception($errmsg); } + if ($this->transport === 'ssl') { + stream_socket_enable_crypto($this->_mainSocket, false); + } + // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && $this->transport === 'tcp') { + if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); @@ -1575,6 +1579,7 @@ public function acceptConnection($socket) $this->connections[$connection->id] = $connection; $connection->worker = $this; $connection->protocol = $this->protocol; + $connection->transport = $this->transport; $connection->onMessage = $this->onMessage; $connection->onClose = $this->onClose; $connection->onError = $this->onError; From 6ba6d72fa05a97c32b1c8995db50aca28c3ca2fd Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Jan 2017 19:10:05 +0800 Subject: [PATCH 0072/1216] support ssl --- Connection/TcpConnection.php | 52 +++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index f63afa1ef..0083e4690 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -107,6 +107,13 @@ class TcpConnection extends ConnectionInterface */ public $protocol = null; + /** + * Transport (tcp/udp/unix/ssl). + * + * @var string + */ + public $transport = 'tcp'; + /** * Which worker belong to. * @@ -206,6 +213,13 @@ class TcpConnection extends ConnectionInterface */ protected $_isPaused = false; + /** + * SSL handshake completed or not + * + * @var bool + */ + protected $_sslHandshakeCompleted = false; + /** * Construct. * @@ -236,6 +250,10 @@ public function __construct($socket, $remote_address = '') */ public function send($send_buffer, $raw = false) { + if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { + return false; + } + // Try to call protocol::encode($send_buffer) before sending. if (false === $raw && $this->protocol) { $parser = $this->protocol; @@ -245,7 +263,9 @@ public function send($send_buffer, $raw = false) } } - if ($this->_status === self::STATUS_INITIAL || $this->_status === self::STATUS_CONNECTING) { + if ($this->_status !== self::STATUS_ESTABLISH || + ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) + ) { if ($this->_sendBuffer) { if ($this->bufferIsFull()) { self::$statistics['send_fail']++; @@ -255,10 +275,9 @@ public function send($send_buffer, $raw = false) $this->_sendBuffer .= $send_buffer; $this->checkBufferWillFull(); return null; - } elseif ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { - return false; } + // Attempt to send data directly. if ($this->_sendBuffer === '') { $len = @fwrite($this->_socket, $send_buffer); @@ -366,6 +385,33 @@ public function resumeRecv() */ public function baseRead($socket, $check_eof = true) { + // SSL handshake. + if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { + stream_set_blocking($socket, true); + stream_set_timeout($socket, 1); + $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER); + if(!$ret) { + echo new \Exception('ssl handshake fail, stream_socket_enable_crypto return ' . var_export($ret, true)); + return $this->destroy(); + } + if (isset($this->onSslHandshake)) { + try { + call_user_func($this->onSslHandshake, $this); + } catch (\Exception $e) { + self::log($e); + exit(250); + } catch (\Error $e) { + self::log($e); + exit(250); + } + } + $this->_sslHandshakeCompleted = true; + if ($this->_sendBuffer) { + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + } + return; + } + $buffer = fread($socket, self::READ_BUFFER_SIZE); // Check connection closed. From d466c0f4b37c6cfb4f27c69b158175c7e7ccc24c Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Feb 2017 10:52:58 +0800 Subject: [PATCH 0073/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 524e42cec..08e7dd6a8 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.6'; + const VERSION = '3.3.7'; /** * Status starting. From 40dd0d10ff379f2bf2eeb472a7cafd6263796b5c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Feb 2017 15:03:07 +0800 Subject: [PATCH 0074/1216] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 17b687dec..ced289d6d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ $ws_worker = new Worker("websocket://0.0.0.0:2346"); // 4 processes $ws_worker->count = 4; +// WebSockets over SSL (wss) +//$ws_worker->transport = 'ssl'; + // Emitted when new connection come $ws_worker->onConnect = function($connection) { @@ -64,6 +67,9 @@ $http_worker = new Worker("http://0.0.0.0:2345"); // 4 processes $http_worker->count = 4; +// HTTP over SSL (https) +//$ws_worker->transport = 'ssl'; + // Emitted when data received $http_worker->onMessage = function($connection, $data) { From d131cc357a853a1b95979e137e4352cefd48a283 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Feb 2017 15:03:48 +0800 Subject: [PATCH 0075/1216] Update README.md --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index ced289d6d..17b687dec 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,6 @@ $ws_worker = new Worker("websocket://0.0.0.0:2346"); // 4 processes $ws_worker->count = 4; -// WebSockets over SSL (wss) -//$ws_worker->transport = 'ssl'; - // Emitted when new connection come $ws_worker->onConnect = function($connection) { @@ -67,9 +64,6 @@ $http_worker = new Worker("http://0.0.0.0:2345"); // 4 processes $http_worker->count = 4; -// HTTP over SSL (https) -//$ws_worker->transport = 'ssl'; - // Emitted when data received $http_worker->onMessage = function($connection, $data) { From c92ae3c34610bf257a71a2f9159e28852819aac1 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 8 Feb 2017 17:47:06 +0800 Subject: [PATCH 0076/1216] Update Timer.php --- Lib/Timer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index b382cbb4b..4bd4ac5af 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -78,7 +78,7 @@ public static function signalHandle() * @param callback $func * @param mixed $args * @param bool $persistent - * @return bool + * @return int/false */ public static function add($time_interval, $func, $args = array(), $persistent = true) { @@ -107,7 +107,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = self::$_tasks[$run_time] = array(); } self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); - return true; + return 1; } From 7f034dfd8a2bf497c12e9796c394e4b35eae8af1 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Feb 2017 15:24:56 +0800 Subject: [PATCH 0077/1216] Timer::add() should return integer Timer::add() returned TimerInterface with reactPHP. But we need integer. --- Events/React.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Events/React.php b/Events/React.php index be8c87fb7..79e6f96e4 100644 --- a/Events/React.php +++ b/Events/React.php @@ -25,6 +25,16 @@ class React implements LoopInterface */ protected $_loop = null; + /** + * @var array + */ + protected $_timerIdMap = array(); + + /** + * @var int + */ + protected $_timerIdIndex = 0; + /** * React constructor. */ @@ -58,13 +68,17 @@ public function add($fd, $flag, $func, $args = array()) case EventInterface::EV_SIGNAL: return $this->_loop->addSignal($fd, $func); case EventInterface::EV_TIMER: - return $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { + $timer_obj = $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { call_user_func_array($func, $args); }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; case EventInterface::EV_TIMER_ONCE: - return $this->_loop->addTimer($fd, function() use ($func, $args) { + $timer_obj = $this->_loop->addTimer($fd, function() use ($func, $args) { call_user_func_array($func, $args); }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; } return false; } @@ -87,8 +101,11 @@ public function del($fd, $flag) return $this->_loop->removeSignal($fd); case EventInterface::EV_TIMER: case EventInterface::EV_TIMER_ONCE; - if ($fd !== null){ - return $this->_loop->cancelTimer($fd); + if (isset($this->_timerIdMap[$fd])){ + $timer_obj = $this->_timerIdMap[$fd]; + unset($this->_timerIdMap[$fd]); + $this->_loop->cancelTimer($timer_obj); + return true; } } return false; From 72aa0aa51665d7a0ad07ec2c17240f65b622defc Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Feb 2017 15:32:13 +0800 Subject: [PATCH 0078/1216] log event-loop exited message --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index 08e7dd6a8..c0dd8972a 100644 --- a/Worker.php +++ b/Worker.php @@ -934,6 +934,8 @@ protected static function forkOneWorker($worker) $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); + $err = new Exception('event-loop exited'); + self::log($err); exit(250); } else { throw new Exception("forkOneWorker fail"); From bbcfd9169cf6acd9d9866e17ed2f2189ee6d7f91 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Feb 2017 16:07:55 +0800 Subject: [PATCH 0079/1216] version 3.3.8 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c0dd8972a..c09bd33b3 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.7'; + const VERSION = '3.3.8'; /** * Status starting. From a4f2899054598b6999213b802e40466e2411415f Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Feb 2017 18:00:58 +0800 Subject: [PATCH 0080/1216] Update README.md --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 17b687dec..820fa248e 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,36 @@ $tcp_worker->onClose = function($connection) Worker::runAll(); ``` +### Enable SSL. +```php + array( + 'local_cert' => '/your/path/of/server.pem', + 'local_pk' => '/your/path/of/server.key', + ) +); + +// Create a Websocket server with ssl context. +$ws_worker = new Worker("websocket://0.0.0.0:2346", $context); + +// Enable SSL. WebSocket+SSL means that Secure WebSocket (wss://). +// The similar approaches for Https etc. +$ws_worker->transport = 'ssl'; + +$ws_worker->onMessage = function($connection, $data) +{ + // Send hello $data + $connection->send('hello ' . $data); +}; + +Worker::runAll(); +``` + ### Custom protocol Protocols/MyTextProtocol.php ```php From 0e9decf7b85e7c450b42dc3530ff8d39e578398e Mon Sep 17 00:00:00 2001 From: sudevva Date: Thu, 9 Feb 2017 18:28:18 +0200 Subject: [PATCH 0081/1216] Update AsyncTcpConnection.php fix unix connection error --- Connection/AsyncTcpConnection.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 116aa6924..9eff23f01 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -106,8 +106,10 @@ public function __construct($remote_address, $context_option = null) { $address_info = parse_url($remote_address); if (!$address_info) { - echo new \Exception('bad remote_address'); - $this->_remoteAddress = $remote_address; + list($scheme, $this->_remoteAddress) = explode(':', $remote_address, 2); + if (!$this->_remoteAddress) { + echo new \Exception('bad remote_address'); + } } else { if (!isset($address_info['port'])) { $address_info['port'] = 80; From 8b60aee583e43417e463fcbd4477768f028c6c03 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Feb 2017 12:54:52 +0800 Subject: [PATCH 0082/1216] ssl using nonblocking socket stream_socket_enable_crypto using nonblocking socket --- Connection/TcpConnection.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 0083e4690..65929bc4d 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -387,12 +387,19 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - stream_set_blocking($socket, true); - stream_set_timeout($socket, 1); $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER); - if(!$ret) { - echo new \Exception('ssl handshake fail, stream_socket_enable_crypto return ' . var_export($ret, true)); + // Negotiation has failed. + if(false === $ret) { + $error = error_get_last(); + $error_msg = ''; + if ($error) { + $error_msg = "{$error['message']} in {$error['file']} on line {$error['line']}"; + } + echo new \Exception("SSL handshake fail $error_msg"); return $this->destroy(); + } elseif(0 === $ret) { + // There isn't enough data and should try again. + return; } if (isset($this->onSslHandshake)) { try { From e69fc0a5b3417420af4b7542733c5528d442b77a Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Feb 2017 16:02:20 +0800 Subject: [PATCH 0083/1216] support SSLv2 SSLv3 crypto method --- Connection/TcpConnection.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 65929bc4d..0c5517c27 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -387,15 +387,11 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER); + $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | + STREAM_CRYPTO_METHOD_SSLv3_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER); // Negotiation has failed. if(false === $ret) { - $error = error_get_last(); - $error_msg = ''; - if ($error) { - $error_msg = "{$error['message']} in {$error['file']} on line {$error['line']}"; - } - echo new \Exception("SSL handshake fail $error_msg"); + echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; return $this->destroy(); } elseif(0 === $ret) { // There isn't enough data and should try again. From d8bf0dbdb3312bf3227f6a32b1e46296c4d30493 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Feb 2017 16:19:15 +0800 Subject: [PATCH 0084/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c09bd33b3..abd645f43 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.8'; + const VERSION = '3.3.9'; /** * Status starting. From 02e71eef4714bd251e1b456cb047d3c0d6732192 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Feb 2017 20:29:56 +0800 Subject: [PATCH 0085/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 0c5517c27..6a5f73756 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -391,7 +391,9 @@ public function baseRead($socket, $check_eof = true) STREAM_CRYPTO_METHOD_SSLv3_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER); // Negotiation has failed. if(false === $ret) { - echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; + if (!feof($socket)) { + echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; + } return $this->destroy(); } elseif(0 === $ret) { // There isn't enough data and should try again. From cbaeb6e765476be2c238f9728457b36f2f6590c5 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 25 Feb 2017 21:38:14 +0800 Subject: [PATCH 0086/1216] fix #146 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index abd645f43..f8d6132c0 100644 --- a/Worker.php +++ b/Worker.php @@ -1210,7 +1210,7 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (self::$_masterPid === posix_getpid()) { - $loadavg = sys_getloadavg(); + $loadavg = function_exists('sys_getloadavg') ? sys_getloadavg() : array('-', '-', '-'); file_put_contents(self::$_statisticsFile, "---------------------------------------GLOBAL STATUS--------------------------------------------\n"); file_put_contents(self::$_statisticsFile, From 152756a04f95645217d159f5a496077de0be65cd Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Mar 2017 14:26:06 +0800 Subject: [PATCH 0087/1216] Update Worker.php --- Worker.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index f8d6132c0..a19b70572 100644 --- a/Worker.php +++ b/Worker.php @@ -468,8 +468,10 @@ protected static function init() self::$logFile = __DIR__ . '/../workerman.log'; } $log_file = (string)self::$logFile; - touch($log_file); - chmod($log_file, 0622); + if (!is_file($log_file)) { + touch($log_file); + chmod($log_file, 0622); + } // State. self::$_status = self::STATUS_STARTING; From 28542ebdb9443b64072109c08cb26ad67638791c Mon Sep 17 00:00:00 2001 From: "xiaobo.sun" <5ini99@sohu.com> Date: Tue, 7 Mar 2017 14:43:11 +0800 Subject: [PATCH 0088/1216] Update Http.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在$_SERVER中新增REQUEST_TIME --- Protocols/Http.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 30c3ba918..47906ac90 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -108,6 +108,7 @@ public static function decode($recv_buffer, TcpConnection $connection) 'HTTP_CONNECTION' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', + 'REQUEST_TIME' => time() ); // Parse headers. From 77d1a90f03bd0f6843b415736a84c53260d2a675 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Mar 2017 23:29:32 +0800 Subject: [PATCH 0089/1216] support eventLoopClass #119 --- Events/Ev.php | 15 ++++- Events/Event.php | 15 ++++- Events/EventInterface.php | 7 +++ Events/Libevent.php | 12 ++++ Events/React/ExtEventLoop.php | 97 +++++++++++++++++++++++++++++++ Events/React/LibEventLoop.php | 97 +++++++++++++++++++++++++++++++ Events/React/StreamSelectLoop.php | 95 ++++++++++++++++++++++++++++++ Events/Select.php | 10 ++++ 8 files changed, 344 insertions(+), 4 deletions(-) diff --git a/Events/Ev.php b/Events/Ev.php index acc1a3613..5018fec86 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -65,7 +65,6 @@ public function add($fd, $flag, $func, $args = null) exit(250); } }; - switch ($flag) { case self::EV_SIGNAL: $event = new \EvSignal($fd, $callback); @@ -109,7 +108,7 @@ public function del($fd, $flag) case self::EV_SIGNAL: $fd_key = (int)$fd; if (isset($this->_eventSignal[$fd_key])) { - $this->_allEvents[$fd_key][$flag]->stop(); + $this->_eventSignal[$fd_key]->stop(); unset($this->_eventSignal[$fd_key]); } break; @@ -170,4 +169,16 @@ public function loop() { \Ev::run(); } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + foreach ($this->_allEvents as $event) { + $event->stop(); + } + } } diff --git a/Events/Event.php b/Events/Event.php index 2d85aafee..1322c738c 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -120,10 +120,9 @@ public function del($fd, $flag) break; case self::EV_SIGNAL: - $fd_key = (int)$fd; if (isset($this->_eventSignal[$fd_key])) { - $this->_allEvents[$fd_key][$flag]->del(); + $this->_eventSignal[$fd_key]->del(); unset($this->_eventSignal[$fd_key]); } break; @@ -185,4 +184,16 @@ public function loop() { $this->_eventBase->loop(); } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + foreach ($this->_eventSignal as $event) { + $event->del(); + } + } } diff --git a/Events/EventInterface.php b/Events/EventInterface.php index d71b5d438..b9718512a 100644 --- a/Events/EventInterface.php +++ b/Events/EventInterface.php @@ -83,4 +83,11 @@ public function clearAllTimer(); * @return void */ public function loop(); + + /** + * Destroy loop. + * + * @return mixed + */ + public function destroy(); } diff --git a/Events/Libevent.php b/Events/Libevent.php index 5644bf1e7..d5a8409ba 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -201,5 +201,17 @@ public function loop() { event_base_loop($this->_eventBase); } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + foreach ($this->_eventSignal as $event) { + event_del($event); + } + } } diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php index ccb504182..a14525687 100644 --- a/Events/React/ExtEventLoop.php +++ b/Events/React/ExtEventLoop.php @@ -12,6 +12,7 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; +use Workerman\Events\EventInterface; /** * Class ExtEventLoop @@ -33,6 +34,90 @@ class ExtEventLoop extends \React\EventLoop\ExtEventLoop */ protected $_signalEvents = array(); + /** + * @var array + */ + protected $_timerIdMap = array(); + + /** + * @var int + */ + protected $_timerIdIndex = 0; + + /** + * Add event listener to event loop. + * + * @param $fd + * @param $flag + * @param $func + * @param array $args + * @return bool + */ + public function add($fd, $flag, $func, $args = array()) + { + $args = (array)$args; + switch ($flag) { + case EventInterface::EV_READ: + return $this->addReadStream($fd, $func); + case EventInterface::EV_WRITE: + return $this->addWriteStream($fd, $func); + case EventInterface::EV_SIGNAL: + return $this->addSignal($fd, $func); + case EventInterface::EV_TIMER: + $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + case EventInterface::EV_TIMER_ONCE: + $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + } + return false; + } + + /** + * Remove event listener from event loop. + * + * @param mixed $fd + * @param int $flag + * @return bool + */ + public function del($fd, $flag) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->removeReadStream($fd); + case EventInterface::EV_WRITE: + return $this->removeWriteStream($fd); + case EventInterface::EV_SIGNAL: + return $this->removeSignal($fd); + case EventInterface::EV_TIMER: + case EventInterface::EV_TIMER_ONCE; + if (isset($this->_timerIdMap[$fd])){ + $timer_obj = $this->_timerIdMap[$fd]; + unset($this->_timerIdMap[$fd]); + $this->cancelTimer($timer_obj); + return true; + } + } + return false; + } + + + /** + * Main loop. + * + * @return void + */ + public function loop() + { + $this->run(); + } + /** * Construct */ @@ -73,4 +158,16 @@ public function removeSignal($signal) unset($this->_signalEvents[$signal]); } } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + foreach ($this->_signalEvents as $event) { + $event->del(); + } + } } diff --git a/Events/React/LibEventLoop.php b/Events/React/LibEventLoop.php index 1dbf3900d..7a3a93a2f 100644 --- a/Events/React/LibEventLoop.php +++ b/Events/React/LibEventLoop.php @@ -12,6 +12,7 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; +use Workerman\Events\EventInterface; /** * Class LibEventLoop @@ -33,6 +34,90 @@ class LibEventLoop extends \React\EventLoop\LibEventLoop */ protected $_signalEvents = array(); + /** + * @var array + */ + protected $_timerIdMap = array(); + + /** + * @var int + */ + protected $_timerIdIndex = 0; + + /** + * Add event listener to event loop. + * + * @param $fd + * @param $flag + * @param $func + * @param array $args + * @return bool + */ + public function add($fd, $flag, $func, $args = array()) + { + $args = (array)$args; + switch ($flag) { + case EventInterface::EV_READ: + return $this->addReadStream($fd, $func); + case EventInterface::EV_WRITE: + return $this->addWriteStream($fd, $func); + case EventInterface::EV_SIGNAL: + return $this->addSignal($fd, $func); + case EventInterface::EV_TIMER: + $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + case EventInterface::EV_TIMER_ONCE: + $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + } + return false; + } + + /** + * Remove event listener from event loop. + * + * @param mixed $fd + * @param int $flag + * @return bool + */ + public function del($fd, $flag) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->removeReadStream($fd); + case EventInterface::EV_WRITE: + return $this->removeWriteStream($fd); + case EventInterface::EV_SIGNAL: + return $this->removeSignal($fd); + case EventInterface::EV_TIMER: + case EventInterface::EV_TIMER_ONCE; + if (isset($this->_timerIdMap[$fd])){ + $timer_obj = $this->_timerIdMap[$fd]; + unset($this->_timerIdMap[$fd]); + $this->cancelTimer($timer_obj); + return true; + } + } + return false; + } + + + /** + * Main loop. + * + * @return void + */ + public function loop() + { + $this->run(); + } + /** * Construct. */ @@ -74,4 +159,16 @@ public function removeSignal($signal) unset($this->_signalEvents[$signal]); } } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + foreach ($this->_signalEvents as $event) { + event_del($event); + } + } } diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index 5ab8bc7e8..badbac1eb 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -12,6 +12,7 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; +use Workerman\Events\EventInterface; /** * Class StreamSelectLoop @@ -19,6 +20,90 @@ */ class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop { + /** + * @var array + */ + protected $_timerIdMap = array(); + + /** + * @var int + */ + protected $_timerIdIndex = 0; + + /** + * Add event listener to event loop. + * + * @param $fd + * @param $flag + * @param $func + * @param array $args + * @return bool + */ + public function add($fd, $flag, $func, $args = array()) + { + $args = (array)$args; + switch ($flag) { + case EventInterface::EV_READ: + return $this->addReadStream($fd, $func); + case EventInterface::EV_WRITE: + return $this->addWriteStream($fd, $func); + case EventInterface::EV_SIGNAL: + return $this->addSignal($fd, $func); + case EventInterface::EV_TIMER: + $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + case EventInterface::EV_TIMER_ONCE: + $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + } + return false; + } + + /** + * Remove event listener from event loop. + * + * @param mixed $fd + * @param int $flag + * @return bool + */ + public function del($fd, $flag) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->removeReadStream($fd); + case EventInterface::EV_WRITE: + return $this->removeWriteStream($fd); + case EventInterface::EV_SIGNAL: + return $this->removeSignal($fd); + case EventInterface::EV_TIMER: + case EventInterface::EV_TIMER_ONCE; + if (isset($this->_timerIdMap[$fd])){ + $timer_obj = $this->_timerIdMap[$fd]; + unset($this->_timerIdMap[$fd]); + $this->cancelTimer($timer_obj); + return true; + } + } + return false; + } + + + /** + * Main loop. + * + * @return void + */ + public function loop() + { + $this->run(); + } + /** * Add signal handler. * @@ -74,4 +159,14 @@ protected function streamSelect(array &$read, array &$write, $timeout) return 0; } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + + } } diff --git a/Events/Select.php b/Events/Select.php index 1b9d16f16..4f1d7bea8 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -260,4 +260,14 @@ public function loop() } } } + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + + } } From 16bcc9edbf14dbcf4d95bb4d180c5e740470f6f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Mar 2017 23:32:37 +0800 Subject: [PATCH 0090/1216] some optimization --- Events/React.php | 265 ----------------------------------------------- Worker.php | 60 +++++++---- 2 files changed, 41 insertions(+), 284 deletions(-) delete mode 100644 Events/React.php diff --git a/Events/React.php b/Events/React.php deleted file mode 100644 index 79e6f96e4..000000000 --- a/Events/React.php +++ /dev/null @@ -1,265 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; -use React\EventLoop\LoopInterface; -use React\EventLoop\Timer\TimerInterface; - -/** - * select eventloop - */ -class React implements LoopInterface -{ - /** - * @var React\EventLoop\LoopInterface - */ - protected $_loop = null; - - /** - * @var array - */ - protected $_timerIdMap = array(); - - /** - * @var int - */ - protected $_timerIdIndex = 0; - - /** - * React constructor. - */ - public function __construct() { - if (function_exists('event_base_new')) { - $this->_loop = new \Workerman\Events\React\LibEventLoop(); - } elseif (class_exists('EventBase', false)) { - $this->_loop = new \Workerman\Events\React\ExtEventLoop(); - } else { - $this->_loop = new \Workerman\Events\React\StreamSelectLoop(); - } - } - - /** - * Add event listener to event loop. - * - * @param $fd - * @param $flag - * @param $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, $args = array()) - { - $args = (array)$args; - switch ($flag) { - case EventInterface::EV_READ: - return $this->_loop->addReadStream($fd, $func); - case EventInterface::EV_WRITE: - return $this->_loop->addWriteStream($fd, $func); - case EventInterface::EV_SIGNAL: - return $this->_loop->addSignal($fd, $func); - case EventInterface::EV_TIMER: - $timer_obj = $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); - }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; - case EventInterface::EV_TIMER_ONCE: - $timer_obj = $this->_loop->addTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); - }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; - } - return false; - } - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag) - { - switch ($flag) { - case EventInterface::EV_READ: - return $this->_loop->removeReadStream($fd); - case EventInterface::EV_WRITE: - return $this->_loop->removeWriteStream($fd); - case EventInterface::EV_SIGNAL: - return $this->_loop->removeSignal($fd); - case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE; - if (isset($this->_timerIdMap[$fd])){ - $timer_obj = $this->_timerIdMap[$fd]; - unset($this->_timerIdMap[$fd]); - $this->_loop->cancelTimer($timer_obj); - return true; - } - } - return false; - } - - - /** - * Main loop. - * - * @return void - */ - public function loop() - { - $this->_loop->run(); - } - - /** - * Register a listener to be notified when a stream is ready to read. - * - * @param resource $stream The PHP stream resource to check. - * @param callable $listener Invoked when the stream is ready. - */ - public function addReadStream($stream, callable $listener) { - return call_user_func(array($this->_loop, 'addReadStream'), $stream, $listener); - } - - /** - * Register a listener to be notified when a stream is ready to write. - * - * @param resource $stream The PHP stream resource to check. - * @param callable $listener Invoked when the stream is ready. - */ - public function addWriteStream($stream, callable $listener) { - return call_user_func(array($this->_loop, 'addWriteStream'), $stream, $listener); - } - - /** - * Remove the read event listener for the given stream. - * - * @param resource $stream The PHP stream resource. - */ - public function removeReadStream($stream) { - return call_user_func(array($this->_loop, 'removeReadStream'), $stream); - } - - /** - * Remove the write event listener for the given stream. - * - * @param resource $stream The PHP stream resource. - */ - public function removeWriteStream($stream) { - return call_user_func(array($this->_loop, 'removeWriteStream'), $stream); - } - - /** - * Remove all listeners for the given stream. - * - * @param resource $stream The PHP stream resource. - */ - public function removeStream($stream) { - return call_user_func(array($this->_loop, 'removeStream'), $stream); - } - - /** - * Enqueue a callback to be invoked once after the given interval. - * - * The execution order of timers scheduled to execute at the same time is - * not guaranteed. - * - * @param int|float $interval The number of seconds to wait before execution. - * @param callable $callback The callback to invoke. - * - * @return TimerInterface - */ - public function addTimer($interval, callable $callback) { - return call_user_func(array($this->_loop, 'addTimer'), $interval, $callback); - } - - /** - * Enqueue a callback to be invoked repeatedly after the given interval. - * - * The execution order of timers scheduled to execute at the same time is - * not guaranteed. - * - * @param int|float $interval The number of seconds to wait before execution. - * @param callable $callback The callback to invoke. - * - * @return TimerInterface - */ - public function addPeriodicTimer($interval, callable $callback) { - return call_user_func(array($this->_loop, 'addPeriodicTimer'), $interval, $callback); - } - - /** - * Cancel a pending timer. - * - * @param TimerInterface $timer The timer to cancel. - */ - public function cancelTimer(TimerInterface $timer) { - return call_user_func(array($this->_loop, 'cancelTimer'), $timer); - } - - /** - * Check if a given timer is active. - * - * @param TimerInterface $timer The timer to check. - * - * @return boolean True if the timer is still enqueued for execution. - */ - public function isTimerActive(TimerInterface $timer) { - return call_user_func(array($this->_loop, 'isTimerActive'), $timer); - } - - /** - * Schedule a callback to be invoked on the next tick of the event loop. - * - * Callbacks are guaranteed to be executed in the order they are enqueued, - * before any timer or stream events. - * - * @param callable $listener The callback to invoke. - */ - public function nextTick(callable $listener) { - return call_user_func(array($this->_loop, 'nextTick'), $listener); - } - - /** - * Schedule a callback to be invoked on a future tick of the event loop. - * - * Callbacks are guaranteed to be executed in the order they are enqueued. - * - * @param callable $listener The callback to invoke. - */ - public function futureTick(callable $listener) { - return call_user_func(array($this->_loop, 'futureTick'), $listener); - } - - /** - * Perform a single iteration of the event loop. - */ - public function tick() { - return call_user_func(array($this->_loop, 'tick')); - } - - /** - * Run the event loop until there are no more tasks to perform. - */ - public function run() { - return call_user_func(array($this->_loop, 'run')); - } - - /** - * Instruct a running event loop to stop. - */ - public function stop() { - return call_user_func(array($this->_loop, 'stop')); - } -} diff --git a/Worker.php b/Worker.php index a19b70572..58b319b90 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.3.9'; + const VERSION = '3.4.0'; /** * Status starting. @@ -273,6 +273,13 @@ class Worker */ public static $onMasterStop = null; + /** + * EventLoopClass + * + * @var string + */ + public static $eventLoopClass = ''; + /** * The PID of master process. * @@ -390,18 +397,10 @@ class Worker * @var array */ protected static $_availableEventLoops = array( - 'libevent', - 'event', - 'ev' + 'libevent' => '\Workerman\Events\Libevent', + 'event' => '\Workerman\Events\Event' ); - /** - * Current eventLoop name. - * - * @var string - */ - protected static $_eventLoopName = 'select'; - /** * PHP built-in protocols. * @@ -850,16 +849,38 @@ protected static function saveMasterPid() */ protected static function getEventLoopName() { - if (interface_exists('\React\EventLoop\LoopInterface')) { - return 'React'; + if (self::$eventLoopClass) { + return self::$eventLoopClass; } - foreach (self::$_availableEventLoops as $name) { + + $loop_name = ''; + foreach (self::$_availableEventLoops as $name=>$class) { if (extension_loaded($name)) { - self::$_eventLoopName = $name; + $loop_name = $name; break; } } - return self::$_eventLoopName; + + if ($loop_name) { + if (interface_exists('\React\EventLoop\LoopInterface')) { + switch ($loop_name) { + case 'libevent': + self::$eventLoopClass = '\Workerman\Events\React\LibEventLoop'; + break; + case 'event': + self::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop'; + break; + default : + self::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop'; + break; + } + } else { + self::$eventLoopClass = self::$_availableEventLoops[$loop_name]; + } + } else { + self::$eventLoopClass = '\Workerman\Events\Select'; + } + return self::$eventLoopClass; } /** @@ -1199,6 +1220,7 @@ public static function stopAll() foreach (self::$_workers as $worker) { $worker->stop(); } + self::$globalEvent->destroy(); exit(0); } } @@ -1212,7 +1234,7 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (self::$_masterPid === posix_getpid()) { - $loadavg = function_exists('sys_getloadavg') ? sys_getloadavg() : array('-', '-', '-'); + $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); file_put_contents(self::$_statisticsFile, "---------------------------------------GLOBAL STATUS--------------------------------------------\n"); file_put_contents(self::$_statisticsFile, @@ -1502,8 +1524,8 @@ public function run() // Create a global event loop. if (!self::$globalEvent) { - $eventLoopClass = "\\Workerman\\Events\\" . ucfirst(self::getEventLoopName()); - self::$globalEvent = new $eventLoopClass; + $event_loop_class = self::getEventLoopName(); + self::$globalEvent = new $event_loop_class; // Register a listener to be notified when server socket is ready to read. if ($this->_socketName) { if ($this->transport !== 'udp') { From 8b7680b3dca08d491e874b870633578beb2a9a8a Mon Sep 17 00:00:00 2001 From: "xiaobo.sun" <5ini99@sohu.com> Date: Tue, 14 Mar 2017 11:00:43 +0800 Subject: [PATCH 0091/1216] Update Http.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在上传文件时为$_FILES中的文件信息新增name及file_type数据 --- Protocols/Http.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 47906ac90..bd6933702 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -438,16 +438,19 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) list($boundary_header_buffer, $boundary_value) = explode("\r\n\r\n", $boundary_data_buffer, 2); // Remove \r\n from the end of buffer. $boundary_value = substr($boundary_value, 0, -2); + $key = -1; foreach (explode("\r\n", $boundary_header_buffer) as $item) { list($header_key, $header_value) = explode(": ", $item); $header_key = strtolower($header_key); switch ($header_key) { case "content-disposition": + $key ++; // Is file data. - if (preg_match('/name=".*?"; filename="(.*?)"$/', $header_value, $match)) { + if (preg_match('/name="(.*?)"; filename="(.*?)"$/', $header_value, $match)) { // Parse $_FILES. - $_FILES[] = array( - 'file_name' => $match[1], + $_FILES[$key] = array( + 'name' => $match[1], + 'file_name' => $match[2], 'file_data' => $boundary_value, 'file_size' => strlen($boundary_value), ); @@ -460,6 +463,10 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) } } break; + case "content-type": + // add file_type + $_FILES[$key]['file_type'] = trim($header_value); + break; } } } From d74fdd6fe9a384e61c5c453124a15eb949a5e32b Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 7 Apr 2017 10:46:23 +0800 Subject: [PATCH 0092/1216] Update WebServer.php --- WebServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebServer.php b/WebServer.php index 235246d96..afa412a02 100644 --- a/WebServer.php +++ b/WebServer.php @@ -232,7 +232,7 @@ public static function sendFile($connection, $file_path) { // Check 304. $info = stat($file_path); - $modified_time = $info ? date('D, d M Y H:i:s', $info['mtime']) . ' GMT' : ''; + $modified_time = $info ? date('D, d M Y H:i:s', $info['mtime']) . ' ' . date_default_timezone_get() : ''; if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { // Http 304. if ($modified_time === $_SERVER['HTTP_IF_MODIFIED_SINCE']) { From 01433af338a7013bcf267ad6ae7647662fd863a1 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 7 Apr 2017 16:36:23 +0800 Subject: [PATCH 0093/1216] Reset opcache --- Lib/Constants.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 81440747a..2f9d3dfcc 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -21,6 +21,11 @@ // Reporting all. error_reporting(E_ALL); +// Reset opcache. +if (function_exists('opcache_reset')) { + opcache_reset(); +} + // For onError callback. define('WORKERMAN_CONNECT_FAIL', 1); // For onError callback. @@ -32,4 +37,4 @@ class Error extends Exception { } -} \ No newline at end of file +} From 1003fb4869a60d09322f7abf00b5846d8e41f6c8 Mon Sep 17 00:00:00 2001 From: adrien Date: Fri, 7 Apr 2017 20:48:54 +0100 Subject: [PATCH 0094/1216] Allow Log rotation by making the redirection public --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 58b319b90..d0c39fe38 100644 --- a/Worker.php +++ b/Worker.php @@ -811,7 +811,7 @@ protected static function daemonize() * * @throws Exception */ - protected static function resetStd() + public static function resetStd() { if (!self::$daemonize) { return; From b007a796a58e620b4ded93a19174e86d86d61d0c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 11 Apr 2017 21:03:01 +0800 Subject: [PATCH 0095/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index d0c39fe38..03600ff93 100644 --- a/Worker.php +++ b/Worker.php @@ -606,7 +606,7 @@ protected static function displayUI() if (self::$daemonize) { global $argv; $start_file = $argv[0]; - self::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n"); + self::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n\n"); } else { self::safeEcho("Press Ctrl-C to quit. Start success.\n"); } From c1644f574bd3427cb246b6b5f0f6ecdec0508f53 Mon Sep 17 00:00:00 2001 From: sm2017 Date: Sat, 15 Apr 2017 09:46:57 +0430 Subject: [PATCH 0096/1216] Default React for SELECT --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 03600ff93..d2b08141d 100644 --- a/Worker.php +++ b/Worker.php @@ -878,7 +878,7 @@ protected static function getEventLoopName() self::$eventLoopClass = self::$_availableEventLoops[$loop_name]; } } else { - self::$eventLoopClass = '\Workerman\Events\Select'; + self::$eventLoopClass = interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; } return self::$eventLoopClass; } From 5f2d958dfd3577f0ccaa15df5bb8484ce5978c1f Mon Sep 17 00:00:00 2001 From: victorruan <250069802@qq.com> Date: Thu, 20 Apr 2017 15:04:24 +0800 Subject: [PATCH 0097/1216] self::log is wrong --- Connection/TcpConnection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6a5f73756..9ff6a00e7 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -403,10 +403,10 @@ public function baseRead($socket, $check_eof = true) try { call_user_func($this->onSslHandshake, $this); } catch (\Exception $e) { - self::log($e); + Worker::log($e); exit(250); } catch (\Error $e) { - self::log($e); + Worker::log($e); exit(250); } } From cb055aff5173365b8c8af52a32793ca456908d41 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Apr 2017 00:19:57 +0800 Subject: [PATCH 0098/1216] Fix ssl. --- Connection/AsyncTcpConnection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9eff23f01..49493019d 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -277,8 +277,9 @@ public function checkConnection($socket) if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } - $this->_status = self::STATUS_ESTABLISH; - $this->_remoteAddress = $address; + $this->_status = self::STATUS_ESTABLISH; + $this->_remoteAddress = $address; + $this->_sslHandshakeCompleted = true; // Try to emit onConnect callback. if ($this->onConnect) { From 59506827fe677ac6df4f27c291026d17a52590d7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Apr 2017 08:40:51 +0800 Subject: [PATCH 0099/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index d2b08141d..abbf273b4 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.0'; + const VERSION = '3.4.1'; /** * Status starting. From 4eee7e0d16e62a6eb133b9192e4429b352eadfc3 Mon Sep 17 00:00:00 2001 From: Atef Ben Ali Date: Fri, 21 Apr 2017 09:57:42 +0100 Subject: [PATCH 0100/1216] add space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 820fa248e..539c8612a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Gitter](https://badges.gitter.im/walkor/Workerman.svg)](https://gitter.im/walkor/Workerman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) ## What is it -Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications.Supports HTTP, Websocket and other custom protocols. Supports libevent, HHVM, [ReactPHP](https://github.com/reactphp/react). +Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket and other custom protocols. Supports libevent, HHVM, [ReactPHP](https://github.com/reactphp/react). ## Requires From 84c50e7edb0de29d96bd51bf81bf86cae2796ec5 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 26 Apr 2017 11:32:55 +0430 Subject: [PATCH 0101/1216] Update README.md Fix Links & add SSL Support Info --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 539c8612a..9e47bc024 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ [![Gitter](https://badges.gitter.im/walkor/Workerman.svg)](https://gitter.im/walkor/Workerman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) ## What is it -Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket and other custom protocols. Supports libevent, HHVM, [ReactPHP](https://github.com/reactphp/react). +Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket, SSL and other custom protocols. Supports libevent, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). ## Requires - PHP 5.3 or Higher A POSIX compatible operating system (Linux, OSX, BSD) POSIX and PCNTL extensions for PHP From 5b688bb3d6166cb7158b2d375bbd742c093b5b1b Mon Sep 17 00:00:00 2001 From: ruolinn Date: Fri, 28 Apr 2017 18:26:56 +0800 Subject: [PATCH 0102/1216] session_save_path warning --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index bd6933702..8761bf274 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -561,7 +561,7 @@ class HttpCache public static function init() { self::$sessionName = ini_get('session.name'); - self::$sessionPath = session_save_path(); + self::$sessionPath = @session_save_path(); if (!self::$sessionPath || strpos(self::$sessionPath, 'tcp://') === 0) { self::$sessionPath = sys_get_temp_dir(); } From c6de4fc561442307a974244d566be6a65a37ceb1 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 2 May 2017 14:21:52 +0800 Subject: [PATCH 0103/1216] Standard for timer --- Events/Select.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 4f1d7bea8..95d2e1b31 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -60,7 +60,7 @@ class Select implements EventInterface * * @var array */ - protected $_task = array(); + protected $_eventTimer = array(); /** * Timer id. @@ -124,7 +124,7 @@ public function add($fd, $flag, $func, $args = array()) case self::EV_TIMER_ONCE: $run_time = microtime(true) + $fd; $this->_scheduler->insert($this->_timerId, -$run_time); - $this->_task[$this->_timerId] = array($func, (array)$args, $flag, $fd); + $this->_eventTimer[$this->_timerId] = array($func, (array)$args, $flag, $fd); $this->tick(); return $this->_timerId++; } @@ -167,7 +167,7 @@ public function del($fd, $flag) break; case self::EV_TIMER: case self::EV_TIMER_ONCE; - unset($this->_task[$fd_key]); + unset($this->_eventTimer[$fd_key]); return true; } return false; @@ -189,18 +189,18 @@ protected function tick() if ($this->_selectTimeout <= 0) { $this->_scheduler->extract(); - if (!isset($this->_task[$timer_id])) { + if (!isset($this->_eventTimer[$timer_id])) { continue; } // [func, args, flag, timer_interval] - $task_data = $this->_task[$timer_id]; + $task_data = $this->_eventTimer[$timer_id]; if ($task_data[2] === self::EV_TIMER) { $next_run_time = $time_now + $task_data[3]; $this->_scheduler->insert($timer_id, -$next_run_time); } call_user_func_array($task_data[0], $task_data[1]); - if (isset($this->_task[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { + if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { $this->del($timer_id, self::EV_TIMER_ONCE); } continue; @@ -217,7 +217,7 @@ public function clearAllTimer() { $this->_scheduler = new \SplPriorityQueue(); $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); - $this->_task = array(); + $this->_eventTimer = array(); } /** From d63433e249093cea5742db40d451187c7faf58ae Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 4 May 2017 14:32:30 +0800 Subject: [PATCH 0104/1216] fix for #154 --- Protocols/Http.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 8761bf274..768af49b2 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -159,21 +159,30 @@ public static function decode($recv_buffer, TcpConnection $connection) // Parse $_POST. if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'multipart/form-data') { - self::parseUploadFiles($http_body, $http_post_boundary); + if (isset($_SERVER['CONTENT_TYPE'])) { + switch ($_SERVER['CONTENT_TYPE']) { + case 'multipart/form-data': + self::parseUploadFiles($http_body, $http_post_boundary); + break; + case 'application/x-www-form-urlencoded': + parse_str($http_body, $_POST); + break; + default: + // $GLOBALS['HTTP_RAW_POST_DATA'] + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; + } } else { - parse_str($http_body, $_POST); // $GLOBALS['HTTP_RAW_POST_DATA'] $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } } if ($_SERVER['REQUEST_METHOD'] === 'PUT') { - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; } if ($_SERVER['REQUEST_METHOD'] === 'DELETE') { - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; } // QUERY_STRING From 081eb84da7058eb2eb20db1ee14eb8f05b2c0bf3 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 4 May 2017 18:35:47 +0800 Subject: [PATCH 0105/1216] Fix fwrite() on non-blocking SSL sockets Fix ```1409F07F: SSL routines: SSL3_WRITE_PENDING: bad write retry``` error. Relate http://stackoverflow.com/questions/14695247/in-php-openssl-error-messages-error-1409f07f-ssl-routines-ssl3-write-pendin . --- Connection/TcpConnection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 9ff6a00e7..3b8383002 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -280,7 +280,7 @@ public function send($send_buffer, $raw = false) // Attempt to send data directly. if ($this->_sendBuffer === '') { - $len = @fwrite($this->_socket, $send_buffer); + $len = @fwrite($this->_socket, $send_buffer, 8192); // send successful. if ($len === strlen($send_buffer)) { return true; @@ -519,7 +519,7 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - $len = @fwrite($this->_socket, $this->_sendBuffer); + $len = @fwrite($this->_socket, $this->_sendBuffer, 8192); if ($len === strlen($this->_sendBuffer)) { Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; From a10f58e546af755f3546a309afea7ac71f879aaf Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 4 May 2017 23:08:38 +0800 Subject: [PATCH 0106/1216] Update version --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index abbf273b4..297c1e13e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.1'; + const VERSION = '3.4.2'; /** * Status starting. From aba2614e127455f7dbbab89b3a0cb1010c0e7bc8 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 6 May 2017 17:38:18 +0800 Subject: [PATCH 0107/1216] Fix 166 --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 768af49b2..fef6451ef 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -65,7 +65,7 @@ public static function input($recv_buffer, TcpConnection $connection) */ protected static function getRequestSize($header, $method) { - if($method=='GET') { + if($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { return strlen($header) + 4; } $match = array(); From 4aca5faa807fe5a1ed45008345f02099952da86e Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 20 May 2017 22:42:38 +0800 Subject: [PATCH 0108/1216] test --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 733ab8a6c..e270ddd2a 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "php": ">=5.3" }, "suggest": { - "ext-event": "For better performance." + "ext-event": "For better performance. " }, "autoload": { "psr-4": {"Workerman\\": "./"} From ea3a0987385ef2bfe50d7fe1367eaf90b2385550 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 20 May 2017 22:45:26 +0800 Subject: [PATCH 0109/1216] composer.json format --- composer.json | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index e270ddd2a..95c30972c 100644 --- a/composer.json +++ b/composer.json @@ -1,33 +1,38 @@ { - "name" : "workerman/workerman", - "type" : "library", - "keywords": ["event-loop", "asynchronous"], + "name": "workerman/workerman", + "type": "library", + "keywords": [ + "event-loop", + "asynchronous" + ], "homepage": "http://www.workerman.net", - "license" : "MIT", + "license": "MIT", "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", - "authors" : [ + "authors": [ { - "name" : "walkor", - "email" : "walkor@workerman.net", - "homepage" : "http://www.workerman.net", + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "http://www.workerman.net", "role": "Developer" } ], - "support" : { - "email" : "walkor@workerman.net", + "support": { + "email": "walkor@workerman.net", "issues": "https://github.com/walkor/workerman/issues", - "forum" : "http://wenda.workerman.net/", - "wiki" : "http://doc3.workerman.net/index.html", + "forum": "http://wenda.workerman.net/", + "wiki": "http://doc3.workerman.net/index.html", "source": "https://github.com/walkor/workerman" }, "require": { "php": ">=5.3" }, "suggest": { - "ext-event": "For better performance. " + "ext-event": "For better performance. " }, "autoload": { - "psr-4": {"Workerman\\": "./"} + "psr-4": { + "Workerman\\": "./" + } }, - "minimum-stability":"dev" + "minimum-stability": "dev" } From 192f2cd275db687d2b2779e3c0d54993e4a3c0a9 Mon Sep 17 00:00:00 2001 From: moon Date: Fri, 26 May 2017 12:14:06 +0800 Subject: [PATCH 0110/1216] fix PHP7 bitwise operation warning: A non-numeric value encountered --- Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index da1451f40..020014ee9 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -289,7 +289,7 @@ public static function encode($payload, $connection) */ public static function decode($bytes, $connection) { - $masked = $bytes[1] >> 7; + $masked = ord($bytes[1]) >> 7; $data_length = $masked ? ord($bytes[1]) & 127 : ord($bytes[1]); $decoded_data = ''; if ($masked === true) { From 1a1b5e7fec04d53c2669b73d9e380577fa6c7f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=AE?= Date: Mon, 5 Jun 2017 19:40:21 +0800 Subject: [PATCH 0111/1216] Compatible windows system --- Connection/AsyncTcpConnection.php | 10 ++++- Events/EventInterface.php | 7 +++ Events/React/StreamSelectLoop.php | 10 +++-- Events/Select.php | 75 ++++++++++++++++++++++++------- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 49493019d..fc5b43148 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -184,6 +184,10 @@ public function connect() } // Add socket to global event loop waiting connection is successfully established or faild. Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); + // For windows. + if(DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection')); + } } /** @@ -201,7 +205,7 @@ public function reConnect($after = 0) { $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false); return; } - return $this->connect(); + $this->connect(); } /** @@ -255,6 +259,10 @@ protected function emitError($code, $msg) */ public function checkConnection($socket) { + // Remove EV_EXPECT for windows. + if(DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); + } // Check socket state. if ($address = stream_socket_get_name($socket, true)) { // Remove write listener. diff --git a/Events/EventInterface.php b/Events/EventInterface.php index b9718512a..eb4a9d57a 100644 --- a/Events/EventInterface.php +++ b/Events/EventInterface.php @@ -29,6 +29,13 @@ interface EventInterface */ const EV_WRITE = 2; + /** + * Except event + * + * @var int + */ + const EV_EXCEPT = 3; + /** * Signal event. * diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index badbac1eb..2211753b2 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -113,7 +113,7 @@ public function loop() */ public function addSignal($signal, $callback) { - if(PHP_EOL !== "\r\n") { + if(DIRECTORY_SEPARATOR === '/') { pcntl_signal($signal, $callback); } } @@ -125,7 +125,7 @@ public function addSignal($signal, $callback) */ public function removeSignal($signal) { - if(PHP_EOL !== "\r\n") { + if(DIRECTORY_SEPARATOR === '/') { pcntl_signal($signal, SIG_IGN); } } @@ -146,13 +146,15 @@ protected function streamSelect(array &$read, array &$write, $timeout) if ($read || $write) { $except = null; // Calls signal handlers for pending signals - pcntl_signal_dispatch(); + if(DIRECTORY_SEPARATOR === '/') { + pcntl_signal_dispatch(); + } // suppress warnings that occur, when stream_select is interrupted by a signal return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); } // Calls signal handlers for pending signals - if(PHP_EOL !== "\r\n") { + if(DIRECTORY_SEPARATOR === '/') { pcntl_signal_dispatch(); } $timeout && usleep($timeout); diff --git a/Events/Select.php b/Events/Select.php index 95d2e1b31..1054080e7 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -46,6 +46,13 @@ class Select implements EventInterface */ protected $_writeFds = array(); + /** + * Fds waiting for except event. + * + * @var array + */ + protected $_exceptFds = array(); + /** * Timer scheduler. * {['data':timer_id, 'priority':run_timestamp], ..} @@ -89,8 +96,9 @@ class Select implements EventInterface public function __construct() { // Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling. - $this->channel = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); - if ($this->channel) { + $this->channel = stream_socket_pair(DIRECTORY_SEPARATOR === '/' ? STREAM_PF_UNIX : STREAM_PF_INET, + STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); + if($this->channel) { stream_set_blocking($this->channel[0], 0); $this->_readFds[0] = $this->channel[0]; } @@ -115,7 +123,16 @@ public function add($fd, $flag, $func, $args = array()) $this->_allEvents[$fd_key][$flag] = array($func, $fd); $this->_writeFds[$fd_key] = $fd; break; + case self::EV_EXCEPT: + $fd_key = (int)$fd; + $this->_allEvents[$fd_key][$flag] = array($func, $fd); + $this->_exceptFds[$fd_key] = $fd; + break; case self::EV_SIGNAL: + // Windows not support signal. + if(DIRECTORY_SEPARATOR !== '/') { + return false; + } $fd_key = (int)$fd; $this->_signalEvents[$fd_key][$flag] = array($func, $fd); pcntl_signal($fd, array($this, 'signalHandler')); @@ -161,7 +178,17 @@ public function del($fd, $flag) unset($this->_allEvents[$fd_key]); } return true; + case self::EV_EXCEPT: + unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]); + if(empty($this->_allEvents[$fd_key])) + { + unset($this->_allEvents[$fd_key]); + } + return true; case self::EV_SIGNAL: + if(DIRECTORY_SEPARATOR !== '/') { + return false; + } unset($this->_signalEvents[$fd_key]); pcntl_signal($fd, SIG_IGN); break; @@ -227,13 +254,17 @@ public function loop() { $e = null; while (1) { - // Calls signal handlers for pending signals - pcntl_signal_dispatch(); + if(DIRECTORY_SEPARATOR === '/') { + // Calls signal handlers for pending signals + pcntl_signal_dispatch(); + } $read = $this->_readFds; $write = $this->_writeFds; + $except = $this->_writeFds; + // Waiting read/write/signal/timeout events. - $ret = @stream_select($read, $write, $e, 0, $this->_selectTimeout); + $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); if (!$this->_scheduler->isEmpty()) { $this->tick(); @@ -243,19 +274,33 @@ public function loop() continue; } - foreach ($read as $fd) { - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][self::EV_READ])) { - call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], - array($this->_allEvents[$fd_key][self::EV_READ][1])); + if ($read) { + foreach ($read as $fd) { + $fd_key = (int)$fd; + if (isset($this->_allEvents[$fd_key][self::EV_READ])) { + call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], + array($this->_allEvents[$fd_key][self::EV_READ][1])); + } } } - foreach ($write as $fd) { - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { - call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], - array($this->_allEvents[$fd_key][self::EV_WRITE][1])); + if ($write) { + foreach ($write as $fd) { + $fd_key = (int)$fd; + if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { + call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], + array($this->_allEvents[$fd_key][self::EV_WRITE][1])); + } + } + } + + if($except) { + foreach($except as $fd) { + $fd_key = (int) $fd; + if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) { + call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], + array($this->_allEvents[$fd_key][self::EV_EXCEPT][1])); + } } } } From 6f89c2314a5f617b2f7dce2cc3543fe65da4096b Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 13 Jun 2017 11:48:48 +0800 Subject: [PATCH 0112/1216] Avoid rapid infinite loop exit --- Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Worker.php b/Worker.php index 297c1e13e..f582a5d8a 100644 --- a/Worker.php +++ b/Worker.php @@ -1550,9 +1550,13 @@ public function run() call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { self::log($e); + // Avoid rapid infinite loop exit. + sleep(1); exit(250); } catch (\Error $e) { self::log($e); + // Avoid rapid infinite loop exit. + sleep(1); exit(250); } } From 7ca271252ed9057af31027740f45120f1506b4b9 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Jun 2017 13:02:30 +0800 Subject: [PATCH 0113/1216] Remove statistics file when stop. --- Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Worker.php b/Worker.php index f582a5d8a..f3e49fb4a 100644 --- a/Worker.php +++ b/Worker.php @@ -1214,6 +1214,10 @@ public static function stopAll() posix_kill($worker_pid, SIGINT); Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); } + // Remove statistics file. + if (is_file(self::$_statisticsFile)) { + @unlink(self::$_statisticsFile); + } } // For child processes. else { // Execute exit. From b395c7fd09178d6efbd26e30142c66d14192aa75 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Jun 2017 19:16:56 +0800 Subject: [PATCH 0114/1216] Session compatible with php7 Fix Warning: session_decode(): Session is not active. You cannot decode session data --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index fef6451ef..018859116 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -377,7 +377,7 @@ public static function sessionStart() if (HttpCache::$instance->sessionFile) { $raw = file_get_contents(HttpCache::$instance->sessionFile); if ($raw) { - session_decode($raw); + $_SESSION = unserialize($raw); } } return true; @@ -394,7 +394,7 @@ public static function sessionWriteClose() return session_write_close(); } if (!empty(HttpCache::$instance->sessionStarted) && !empty($_SESSION)) { - $session_str = session_encode(); + $session_str = serialize($_SESSION); if ($session_str && HttpCache::$instance->sessionFile) { return file_put_contents(HttpCache::$instance->sessionFile, $session_str); } From 9667e352cdf071820b90be5a754ea209222fd7cc Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 20 Jun 2017 23:20:40 +0800 Subject: [PATCH 0115/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index f3e49fb4a..d29c140fa 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.2'; + const VERSION = '3.4.3'; /** * Status starting. From aed29ddf08ccddd801d40233e183a720d05584f2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 26 Jun 2017 13:29:27 +0800 Subject: [PATCH 0116/1216] compatible Content-Type compatible with Content-Type:application/x-www-form-urlencoded; charset=UTF-8 --- Protocols/Http.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 018859116..09bfe631c 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -145,7 +145,11 @@ public static function decode($recv_buffer, TcpConnection $connection) // content-type case 'CONTENT_TYPE': if (!preg_match('/boundary="?(\S+)"?/', $value, $match)) { - $_SERVER['CONTENT_TYPE'] = $value; + if ($pos = strpos($value, ';')) { + $_SERVER['CONTENT_TYPE'] = substr($value, 0, $pos); + } else { + $_SERVER['CONTENT_TYPE'] = $value; + } } else { $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $http_post_boundary = '--' . $match[1]; From 0db65635cff7298eb8b580d30b8720b44e79f7b9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 30 Jun 2017 17:41:49 +0800 Subject: [PATCH 0117/1216] fix #185 --- Events/Select.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 1054080e7..9e0ffede8 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -139,11 +139,12 @@ public function add($fd, $flag, $func, $args = array()) break; case self::EV_TIMER: case self::EV_TIMER_ONCE: + $timer_id = $this->_timerId++; $run_time = microtime(true) + $fd; - $this->_scheduler->insert($this->_timerId, -$run_time); - $this->_eventTimer[$this->_timerId] = array($func, (array)$args, $flag, $fd); + $this->_scheduler->insert($timer_id, -$run_time); + $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); $this->tick(); - return $this->_timerId++; + return $timer_id; } return true; From 7acdb9b929bbf487e69b39d10dd377e9d836065c Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 Jul 2017 00:03:43 +0800 Subject: [PATCH 0118/1216] Humanization tips --- Worker.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index d29c140fa..a205c6e35 100644 --- a/Worker.php +++ b/Worker.php @@ -1306,7 +1306,7 @@ protected static function writeStatisticsToStatusFile() public static function checkErrors() { if (self::STATUS_SHUTDOWN != self::$_status) { - $error_msg = "WORKER EXIT UNEXPECTED "; + $error_msg = 'Worker['. posix_getpid() .'] process terminated with '; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || @@ -1314,7 +1314,9 @@ public static function checkErrors() $errors['type'] === E_COMPILE_ERROR || $errors['type'] === E_RECOVERABLE_ERROR) ) { - $error_msg .= self::getErrorType($errors['type']) . " {$errors['message']} in {$errors['file']} on line {$errors['line']}"; + $error_msg .= self::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; + } else { + $error_msg .= 'exit()/die(). Please do not call exit()/die() in workerman.'; } self::log($error_msg); } From bb24527ca468ac005afd1b5f63e0de5ec5786522 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 6 Jul 2017 14:59:53 +0800 Subject: [PATCH 0119/1216] $GLOBALS['HTTP_RAW_POST_DATA'] $GLOBALS['HTTP_RAW_POST_DATA'] is always accessible. --- Protocols/Http.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 09bfe631c..d4b008aa2 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -171,23 +171,12 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; - default: - // $GLOBALS['HTTP_RAW_POST_DATA'] - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } - } else { - // $GLOBALS['HTTP_RAW_POST_DATA'] - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } } - if ($_SERVER['REQUEST_METHOD'] === 'PUT') { - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; - } - - if ($_SERVER['REQUEST_METHOD'] === 'DELETE') { - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $http_body; - } + // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA + $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; // QUERY_STRING $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); From 486280fc3a60cc8c26953478bf4933fcd0898486 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 6 Jul 2017 15:00:56 +0800 Subject: [PATCH 0120/1216] 3.4.4 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a205c6e35..10e7e362e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.3'; + const VERSION = '3.4.4'; /** * Status starting. From eddcf505231278e4844ec1dda00a83000c7eb26d Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 7 Jul 2017 14:14:01 +0800 Subject: [PATCH 0121/1216] support multiple files upload --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index d4b008aa2..9d6736c35 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -436,17 +436,17 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) if ($boundary_data_array[0] === '') { unset($boundary_data_array[0]); } + $key = -1; foreach ($boundary_data_array as $boundary_data_buffer) { list($boundary_header_buffer, $boundary_value) = explode("\r\n\r\n", $boundary_data_buffer, 2); // Remove \r\n from the end of buffer. $boundary_value = substr($boundary_value, 0, -2); - $key = -1; + $key ++; foreach (explode("\r\n", $boundary_header_buffer) as $item) { list($header_key, $header_value) = explode(": ", $item); $header_key = strtolower($header_key); switch ($header_key) { case "content-disposition": - $key ++; // Is file data. if (preg_match('/name="(.*?)"; filename="(.*?)"$/', $header_value, $match)) { // Parse $_FILES. From 39aface0b5846a25debf2e4b4deb26d1a373fc0a Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 10 Jul 2017 14:33:51 +0800 Subject: [PATCH 0122/1216] remove session_start call --- Protocols/Http.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 9d6736c35..98add4a93 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -579,8 +579,6 @@ public static function init() if ($gc_max_life_time = ini_get('session.gc_maxlifetime')) { self::$sessionGcMaxLifeTime = $gc_max_life_time; } - - @\session_start(); } } From 212aa15bc0edc1226246de52a2fbece0db58414d Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 14 Jul 2017 10:24:43 +0800 Subject: [PATCH 0123/1216] 3.4.5 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 10e7e362e..a6cb4dacd 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.4'; + const VERSION = '3.4.5'; /** * Status starting. From 76fb849dd7c5a6e205b1326e04a2d0bf1b761e40 Mon Sep 17 00:00:00 2001 From: 2276225819 <2276225819@qq.com> Date: Wed, 19 Jul 2017 18:25:15 +0800 Subject: [PATCH 0124/1216] Update StreamSelectLoop.php memory leak --- Events/React/StreamSelectLoop.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index 2211753b2..2b4fc5abc 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -56,10 +56,12 @@ public function add($fd, $flag, $func, $args = array()) $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; return $this->_timerIdIndex; case EventInterface::EV_TIMER_ONCE: - $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + $index = ++$this->_timerIdIndex; + $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { + $this->del($index,EventInterface::EV_TIMER_ONCE); call_user_func_array($func, $args); }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + $this->_timerIdMap[$index] = $timer_obj; return $this->_timerIdIndex; } return false; From 8619f134458e8c44530c843de183d9ef3a7d7e77 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 19 Jul 2017 18:36:26 +0800 Subject: [PATCH 0125/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a6cb4dacd..e2c37ecd7 100644 --- a/Worker.php +++ b/Worker.php @@ -643,7 +643,7 @@ protected static function parseCommand() self::log("Workerman[$start_file] $command $mode"); // Get master process PID. - $master_pid = @file_get_contents(self::$pidFile); + $master_pid = is_file(self::$pidFile) ? file_get_contents(self::$pidFile) : 0; $master_is_alive = $master_pid && @posix_kill($master_pid, 0); // Master is still alive? if ($master_is_alive) { From b2f0ad2f196c9d33e35951bba305ebfc90414475 Mon Sep 17 00:00:00 2001 From: 2276225819 <2276225819@qq.com> Date: Wed, 19 Jul 2017 19:07:09 +0800 Subject: [PATCH 0126/1216] Update Select.php --- Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index 9e0ffede8..af667ff13 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -143,7 +143,7 @@ public function add($fd, $flag, $func, $args = array()) $run_time = microtime(true) + $fd; $this->_scheduler->insert($timer_id, -$run_time); $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); - $this->tick(); + $this->_selectTimeout = ($run_time - time()) * 1000000; return $timer_id; } From eb9f8b057b3456357082600db493e0fc391c0b14 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 20 Jul 2017 23:38:53 +0800 Subject: [PATCH 0127/1216] update Sec-WebSocket-Key algorithm --- Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 020014ee9..a3a019393 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -375,7 +375,7 @@ public static function sendHandshake($connection) "Upgrade: websocket\r\n". "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". "Sec-WebSocket-Version: 13\r\n". - "Sec-WebSocket-Key: ".base64_encode(sha1(uniqid(mt_rand(), true), true))."\r\n\r\n"; + "Sec-WebSocket-Key: " . base64_encode(md5(mt_rand(), true)) . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; From f5b12caef09b4f882983cb7284b72ecd7307a7a6 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 20 Jul 2017 23:43:53 +0800 Subject: [PATCH 0128/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index e2c37ecd7..61c366f5d 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.5'; + const VERSION = '3.4.6'; /** * Status starting. From 95dc8a94cef0a868d0e63c72b73cdd9a26be8cbe Mon Sep 17 00:00:00 2001 From: 2276225819 <2276225819@qq.com> Date: Fri, 21 Jul 2017 00:26:53 +0800 Subject: [PATCH 0129/1216] bugfix --- Events/Select.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index af667ff13..c769bbfd9 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -143,7 +143,10 @@ public function add($fd, $flag, $func, $args = array()) $run_time = microtime(true) + $fd; $this->_scheduler->insert($timer_id, -$run_time); $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); - $this->_selectTimeout = ($run_time - time()) * 1000000; + $select_timeout = ($run_time - microtime(true)) * 1000000; + if( $this->_selectTimeout > $select_timeout ){ + $this->_selectTimeout = $select_timeout; + } return $timer_id; } From 1041c5a1cdb7b17d308dabe803c219333b1c06c0 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 24 Jul 2017 17:32:26 +0800 Subject: [PATCH 0130/1216] optimization --- Worker.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Worker.php b/Worker.php index 61c366f5d..6f9d9c3b7 100644 --- a/Worker.php +++ b/Worker.php @@ -623,8 +623,15 @@ protected static function parseCommand() global $argv; // Check argv; $start_file = $argv[0]; - if (!isset($argv[1])) { - exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); + $available_commands = array( + 'start', + 'stop', + 'restart', + 'reload', + 'status', + ); + if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { + exit("Usage: php yourfile.php {" . implode('|', $available_commands) . "}\n"); } // Get command. @@ -644,10 +651,10 @@ protected static function parseCommand() // Get master process PID. $master_pid = is_file(self::$pidFile) ? file_get_contents(self::$pidFile) : 0; - $master_is_alive = $master_pid && @posix_kill($master_pid, 0); + $master_is_alive = $master_pid && @posix_kill($master_pid, 0) && posix_getpid() != $master_pid; // Master is still alive? if ($master_is_alive) { - if ($command === 'start' && posix_getpid() != $master_pid) { + if ($command === 'start') { self::log("Workerman[$start_file] already running"); exit; } @@ -711,7 +718,7 @@ protected static function parseCommand() self::log("Workerman[$start_file] reload"); exit; default : - exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); + exit("Usage: php yourfile.php {" . implode('|', $available_commands) . "}\n"); } } From b4ea10d42a1e9c87ab82b78a7c4b681f105016b0 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 24 Jul 2017 17:40:15 +0800 Subject: [PATCH 0131/1216] Update composer.json --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 95c30972c..c57dee72f 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,9 @@ "source": "https://github.com/walkor/workerman" }, "require": { - "php": ">=5.3" + "php": ">=5.3", + "ext-pcntl": "*", + "ext-posix": "*" }, "suggest": { "ext-event": "For better performance. " From 51fb2f37b71bbb8a9c8ebd90d82bc77f667a39d4 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Aug 2017 14:20:37 +0800 Subject: [PATCH 0132/1216] fclose mainSocket if it exists --- Worker.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 6f9d9c3b7..ce602f247 100644 --- a/Worker.php +++ b/Worker.php @@ -1598,8 +1598,10 @@ public function stop() } } // Remove listener for server socket. - self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); - @fclose($this->_mainSocket); + if ($this->_mainSocket) { + self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); + @fclose($this->_mainSocket); + } } /** From f285b7ead4f5186781e8fe7cfafdfc56dcd1754a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=AE?= Date: Tue, 8 Aug 2017 16:46:03 +0800 Subject: [PATCH 0133/1216] add timer statistic --- Events/Ev.php | 10 ++++++++++ Events/Event.php | 10 ++++++++++ Events/EventInterface.php | 7 +++++++ Events/Libevent.php | 10 ++++++++++ Events/React/ExtEventLoop.php | 23 ++++++++++++++++++----- Events/React/LibEventLoop.php | 23 ++++++++++++++++++----- Events/React/StreamSelectLoop.php | 10 ++++++++++ Events/Select.php | 10 ++++++++++ Worker.php | 4 ++-- 9 files changed, 95 insertions(+), 12 deletions(-) diff --git a/Events/Ev.php b/Events/Ev.php index 5018fec86..1e6471d78 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -181,4 +181,14 @@ public function destroy() $event->stop(); } } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_eventTimer); + } } diff --git a/Events/Event.php b/Events/Event.php index 1322c738c..a1b7da214 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -196,4 +196,14 @@ public function destroy() $event->del(); } } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_eventTimer); + } } diff --git a/Events/EventInterface.php b/Events/EventInterface.php index eb4a9d57a..88f38f2a8 100644 --- a/Events/EventInterface.php +++ b/Events/EventInterface.php @@ -97,4 +97,11 @@ public function loop(); * @return mixed */ public function destroy(); + + /** + * Get Timer count. + * + * @return mixed + */ + public function getTimerCount(); } diff --git a/Events/Libevent.php b/Events/Libevent.php index d5a8409ba..0b3f7c039 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -213,5 +213,15 @@ public function destroy() event_del($event); } } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_eventTimer); + } } diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php index a14525687..f1998b497 100644 --- a/Events/React/ExtEventLoop.php +++ b/Events/React/ExtEventLoop.php @@ -64,17 +64,20 @@ public function add($fd, $flag, $func, $args = array()) case EventInterface::EV_SIGNAL: return $this->addSignal($fd, $func); case EventInterface::EV_TIMER: + $timer_id = ++$this->_timerIdIndex; $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { call_user_func_array($func, $args); }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; + $this->_timerIdMap[$timer_id] = $timer_obj; + return $timer_id; case EventInterface::EV_TIMER_ONCE: - $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + $timer_id = ++$this->_timerIdIndex; + $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { + unset($this->_timerIdMap[$timer_id]); call_user_func_array($func, $args); }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; + $this->_timerIdMap[$timer_id] = $timer_obj; + return $timer_id; } return false; } @@ -170,4 +173,14 @@ public function destroy() $event->del(); } } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_timerIdMap); + } } diff --git a/Events/React/LibEventLoop.php b/Events/React/LibEventLoop.php index 7a3a93a2f..14620afe7 100644 --- a/Events/React/LibEventLoop.php +++ b/Events/React/LibEventLoop.php @@ -64,17 +64,20 @@ public function add($fd, $flag, $func, $args = array()) case EventInterface::EV_SIGNAL: return $this->addSignal($fd, $func); case EventInterface::EV_TIMER: + $timer_id = ++$this->_timerIdIndex; $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { call_user_func_array($func, $args); }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; + $this->_timerIdMap[$timer_id] = $timer_obj; + return $timer_id; case EventInterface::EV_TIMER_ONCE: - $timer_obj = $this->addTimer($fd, function() use ($func, $args) { + $timer_id = ++$this->_timerIdIndex; + $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { + unset($this->_timerIdMap[$timer_id]); call_user_func_array($func, $args); }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; + $this->_timerIdMap[$timer_id] = $timer_obj; + return $timer_id; } return false; } @@ -171,4 +174,14 @@ public function destroy() event_del($event); } } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_timerIdMap); + } } diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index 2b4fc5abc..0c8c9f2d4 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -173,4 +173,14 @@ public function destroy() { } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_timerIdMap); + } } diff --git a/Events/Select.php b/Events/Select.php index c769bbfd9..aecd6b714 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -319,4 +319,14 @@ public function destroy() { } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_eventTimer); + } } diff --git a/Worker.php b/Worker.php index ce602f247..dd9cd5f4c 100644 --- a/Worker.php +++ b/Worker.php @@ -1281,7 +1281,7 @@ protected static function writeStatisticsToStatusFile() file_put_contents(self::$_statisticsFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', self::$_maxWorkerNameLength) . " connections " . str_pad('total_request', - 13) . " " . str_pad('send_fail', 9) . " " . str_pad('throw_exception', 15) . "\n", FILE_APPEND); + 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 15) . "\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); @@ -1301,7 +1301,7 @@ protected static function writeStatisticsToStatusFile() $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], 14) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], - 9) . " " . str_pad(ConnectionInterface::$statistics['throw_exception'], 15) . "\n"; + 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 15) . "\n"; file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } From 2818bf310cb903a940f6b5a38f5e520c776db056 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 8 Aug 2017 16:51:56 +0800 Subject: [PATCH 0134/1216] 3.4.7 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index dd9cd5f4c..0cfbb9ed4 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.6'; + const VERSION = '3.4.7'; /** * Status starting. From 42623cabe4ceec22711eba60043f652e7a993361 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Aug 2017 17:43:30 +0800 Subject: [PATCH 0135/1216] add connection status --- Connection/ConnectionInterface.php | 42 ++++++++++ Connection/TcpConnection.php | 121 ++++++++++++++++++++++++++++- Connection/UdpConnection.php | 76 ++++++++++++++++++ Worker.php | 84 +++++++++++++++++++- 4 files changed, 319 insertions(+), 4 deletions(-) diff --git a/Connection/ConnectionInterface.php b/Connection/ConnectionInterface.php index b39e5ae9b..f1a4f8fc1 100644 --- a/Connection/ConnectionInterface.php +++ b/Connection/ConnectionInterface.php @@ -73,6 +73,48 @@ abstract public function getRemoteIp(); */ abstract public function getRemotePort(); + /** + * Get remote address. + * + * @return string + */ + abstract public function getRemoteAddress(); + + /** + * Get remote IP. + * + * @return string + */ + abstract public function getLocalIp(); + + /** + * Get remote port. + * + * @return int + */ + abstract public function getLocalPort(); + + /** + * Get remote address. + * + * @return string + */ + abstract public function getLocalAddress(); + + /** + * Is ipv4. + * + * @return bool + */ + abstract public function isIPv4(); + + /** + * Is ipv6. + * + * @return bool + */ + abstract public function isIPv6(); + /** * Close connection. * diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 3b8383002..b67ba6a68 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -121,6 +121,20 @@ class TcpConnection extends ConnectionInterface */ public $worker = null; + /** + * Bytes read. + * + * @var int + */ + public $bytesRead = 0; + + /** + * Bytes written. + * + * @var int + */ + public $bytesWritten = 0; + /** * Connection->id. * @@ -214,7 +228,7 @@ class TcpConnection extends ConnectionInterface protected $_isPaused = false; /** - * SSL handshake completed or not + * SSL handshake completed or not. * * @var bool */ @@ -283,11 +297,13 @@ public function send($send_buffer, $raw = false) $len = @fwrite($this->_socket, $send_buffer, 8192); // send successful. if ($len === strlen($send_buffer)) { + $this->bytesWritten += $len; return true; } // Send only part of the data. if ($len > 0) { $this->_sendBuffer = substr($send_buffer, $len); + $this->bytesWritten += $len; } else { // Connection closed? if (!is_resource($this->_socket) || feof($this->_socket)) { @@ -333,7 +349,7 @@ public function getRemoteIp() { $pos = strrpos($this->_remoteAddress, ':'); if ($pos) { - return trim(substr($this->_remoteAddress, 0, $pos), '[]'); + return substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -351,6 +367,102 @@ public function getRemotePort() return 0; } + /** + * Get remote address. + * + * @return string + */ + public function getRemoteAddress() + { + return $this->_remoteAddress; + } + + /** + * Get local IP. + * + * @return string + */ + public function getLocalIp() + { + $address = $this->getLocalAddress(); + $pos = strrpos($address, ':'); + if (!$pos) { + return ''; + } + return substr($address, 0, $pos); + } + + /** + * Get local port. + * + * @return int + */ + public function getLocalPort() + { + $address = $this->getLocalAddress(); + $pos = strrpos($address, ':'); + if (!$pos) { + return 0; + } + return (int)substr(strrchr($address, ':'), 1); + } + + /** + * Get local address. + * + * @return string + */ + public function getLocalAddress() + { + return (string)@stream_socket_get_name($this->_socket, false); + } + + /** + * Get send buffer queue size. + * + * @return integer + */ + public function getSendBufferQueueSize() + { + return strlen($this->_sendBuffer); + } + + /** + * Get recv buffer queue size. + * + * @return integer + */ + public function getRecvBufferQueueSize() + { + return strlen($this->_recvBuffer); + } + + /** + * Is ipv4. + * + * return bool. + */ + public function isIpV4() + { + if ($this->transport === 'unix') { + return false; + } + return strpos($this->getRemoteIp(), ':') === false; + } + + /** + * Is ipv6. + * + * return bool. + */ + public function isIpV6() + { + if ($this->transport === 'unix') { + return false; + } + return strpos($this->getRemoteIp(), ':') !== false; + } + /** * Pauses the reading of data. That is onMessage will not be emitted. Useful to throttle back an upload. * @@ -417,7 +529,7 @@ public function baseRead($socket, $check_eof = true) return; } - $buffer = fread($socket, self::READ_BUFFER_SIZE); + $buffer = @fread($socket, self::READ_BUFFER_SIZE); // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -426,6 +538,7 @@ public function baseRead($socket, $check_eof = true) return; } } else { + $this->bytesRead += strlen($buffer); $this->_recvBuffer .= $buffer; } @@ -521,6 +634,7 @@ public function baseWrite() { $len = @fwrite($this->_socket, $this->_sendBuffer, 8192); if ($len === strlen($this->_sendBuffer)) { + $this->bytesWritten += $len; Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. @@ -541,6 +655,7 @@ public function baseWrite() return true; } if ($len > 0) { + $this->bytesWritten += $len; $this->_sendBuffer = substr($this->_sendBuffer, $len); } else { self::$statistics['send_fail']++; diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index e4cd2fee4..2e7aeee58 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -98,6 +98,82 @@ public function getRemotePort() return 0; } + /** + * Get remote address. + * + * @return string + */ + public function getRemoteAddress() + { + return $this->_remoteAddress; + } + + /** + * Get local IP. + * + * @return string + */ + public function getLocalIp() + { + $address = $this->getLocalAddress(); + $pos = strrpos($address, ':'); + if (!$pos) { + return ''; + } + return substr($address, 0, $pos); + } + + /** + * Get local port. + * + * @return int + */ + public function getLocalPort() + { + $address = $this->getLocalAddress(); + $pos = strrpos($address, ':'); + if (!$pos) { + return 0; + } + return (int)substr(strrchr($address, ':'), 1); + } + + /** + * Get local address. + * + * @return string + */ + public function getLocalAddress() + { + return (string)@stream_socket_get_name($this->_socket, false); + } + + /** + * Is ipv4. + * + * return bool. + */ + public function isIpV4() + { + if ($this->transport === 'unix') { + return false; + } + return strpos($this->getRemoteIp(), ':') === false; + } + + /** + * Is ipv6. + * + * return bool. + */ + public function isIpV6() + { + if ($this->transport === 'unix') { + return false; + } + return strpos($this->getRemoteIp(), ':') !== false; + } + /** * Close connection. * diff --git a/Worker.php b/Worker.php index dd9cd5f4c..f9f5755ba 100644 --- a/Worker.php +++ b/Worker.php @@ -629,6 +629,7 @@ protected static function parseCommand() 'restart', 'reload', 'status', + 'connections', ); if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { exit("Usage: php yourfile.php {" . implode('|', $available_commands) . "}\n"); @@ -671,11 +672,13 @@ protected static function parseCommand() } break; case 'status': + case 'connections': if (is_file(self::$_statisticsFile)) { @unlink(self::$_statisticsFile); } // Master process will send status signal to all child processes. - posix_kill($master_pid, SIGUSR2); + $signal = $command === 'status' ? SIGUSR2 : SIGIO; + posix_kill($master_pid, $signal); // Waiting amoment. usleep(500000); // Display statisitcs data from a disk file. @@ -735,6 +738,8 @@ protected static function installSignal() pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); // status pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); + // connection status + pcntl_signal(SIGIO, array('\Workerman\Worker', 'signalHandler'), false); // ignore pcntl_signal(SIGPIPE, SIG_IGN, false); } @@ -758,6 +763,8 @@ protected static function reinstallSignal() self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall status signal handler self::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + // reinstall connection status signal handler + self::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); } /** @@ -781,6 +788,10 @@ public static function signalHandler($signal) case SIGUSR2: self::writeStatisticsToStatusFile(); break; + // Show connection status. + case SIGIO: + self::writeConnectionsStatisticsToStatusFile(); + break; } } @@ -1305,6 +1316,77 @@ protected static function writeStatisticsToStatusFile() file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } + /** + * Write statistics data to disk. + * + * @return void + */ + protected static function writeConnectionsStatisticsToStatusFile() + { + // For master process. + if (self::$_masterPid === posix_getpid()) { + file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address PID ID Protocol Worker\n", FILE_APPEND); + chmod(self::$_statisticsFile, 0722); + foreach (self::getAllWorkerPids() as $worker_pid) { + posix_kill($worker_pid, SIGIO); + } + return; + } + + // For child processes. + $bytes_format = function($bytes) + { + if($bytes > 1024*1024*1024*1024) { + return round($bytes/(1024*1024*1024*1024), 1)."TB"; + } + if($bytes > 1024*1024*1024) { + return round($bytes/(1024*1024*1024), 1)."GB"; + } + if($bytes > 1024*1024) { + return round($bytes/(1024*1024), 1)."MB"; + } + if($bytes > 1024) { + return round($bytes/(1024), 1)."KB"; + } + return $bytes."B"; + }; + + $pid = posix_getpid(); + $str = ''; + /** @var Worker $worker */ + foreach(self::$_workers as $worker) { + foreach($worker->connections as $connection) { + /** @var Connection\TcpConnection $connection */ + $transport = $connection->transport; + $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; + $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; + $recv_q = $bytes_format($connection->getRecvBufferQueueSize()); + $send_q = $bytes_format($connection->getSendBufferQueueSize()); + $local_address = $connection->getLocalAddress(); + $remote_address = $connection->getRemoteAddress(); + $bytes_read = $bytes_format($connection->bytesRead); + $bytes_written = $bytes_format($connection->bytesWritten); + $id = $connection->id; + $pos = strrpos($connection->protocol, '\\'); + if ($pos) { + $protocol = substr($connection->protocol, $pos+1); + } else { + $protocol = $connection->protocol; + } + + $str .= str_pad($transport, 8).str_pad($ipv4, 7).str_pad($ipv6, 7) + .str_pad($recv_q, 13).str_pad($send_q, 13).str_pad($bytes_read, 13).str_pad($bytes_written, 13) + .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' '.str_pad($pid, 8).str_pad($id, 10) + .str_pad($protocol, 12).' '.$worker->name."\n" ; + } + } + if ($str) { + file_put_contents(self::$_statisticsFile, $str, FILE_APPEND); + } + + reset(self::$_workers); + } + /** * Check errors when current process exited. * From 709ba2780222b1a0da568f4906edbec462b96098 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Aug 2017 00:05:02 +0800 Subject: [PATCH 0136/1216] connection status --- Connection/AsyncTcpConnection.php | 9 +++--- Connection/TcpConnection.php | 49 +++++++++++++++++++++++++++---- Worker.php | 28 +++++++++++------- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index fc5b43148..d1eaf4414 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -128,7 +128,7 @@ public function __construct($remote_address, $context_option = null) $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; } - $this->id = self::$_idRecorder++; + $this->id = $this->_id = self::$_idRecorder++; // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); @@ -145,8 +145,9 @@ public function __construct($remote_address, $context_option = null) // For statistics. self::$statistics['connection_count']++; - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->_contextOption = $context_option; + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->_contextOption = $context_option; + static::$connections[$this->id] = $this; } /** @@ -285,7 +286,7 @@ public function checkConnection($socket) if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } - $this->_status = self::STATUS_ESTABLISH; + $this->_status = self::STATUS_ESTABLISHED; $this->_remoteAddress = $address; $this->_sslHandshakeCompleted = true; diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index b67ba6a68..8be7f05fd 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -48,7 +48,7 @@ class TcpConnection extends ConnectionInterface * * @var int */ - const STATUS_ESTABLISH = 2; + const STATUS_ESTABLISHED = 2; /** * Status closing. @@ -105,7 +105,7 @@ class TcpConnection extends ConnectionInterface * * @var \Workerman\Protocols\ProtocolInterface */ - public $protocol = null; + public $protocol = 'tcp'; /** * Transport (tcp/udp/unix/ssl). @@ -211,7 +211,7 @@ class TcpConnection extends ConnectionInterface * * @var int */ - protected $_status = self::STATUS_ESTABLISH; + protected $_status = self::STATUS_ESTABLISHED; /** * Remote address. @@ -234,6 +234,26 @@ class TcpConnection extends ConnectionInterface */ protected $_sslHandshakeCompleted = false; + /** + * All connection instances. + * + * @var array + */ + public static $connections = array(); + + /** + * Status to string. + * + * @var array + */ + public static $_statusToString = array( + self::STATUS_INITIAL => 'INITIAL', + self::STATUS_CONNECTING => 'CONNECTING', + self::STATUS_ESTABLISHED => 'ESTABLISHED', + self::STATUS_CLOSING => 'CLOSING', + self::STATUS_CLOSED => 'CLOSED', + ); + /** * Construct. * @@ -253,6 +273,22 @@ public function __construct($socket, $remote_address = '') Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_remoteAddress = $remote_address; + static::$connections[$this->id] = $this; + } + + /** + * Get status. + * + * @param bool $raw_output + * + * @return int + */ + public function getStatus($raw_output = true) + { + if ($raw_output) { + return $this->_status; + } + return self::$_statusToString[$this->_status]; } /** @@ -269,7 +305,7 @@ public function send($send_buffer, $raw = false) } // Try to call protocol::encode($send_buffer) before sending. - if (false === $raw && $this->protocol) { + if (false === $raw && $this->protocol !== 'tcp') { $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { @@ -277,7 +313,7 @@ public function send($send_buffer, $raw = false) } } - if ($this->_status !== self::STATUS_ESTABLISH || + if ($this->_status !== self::STATUS_ESTABLISHED || ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) ) { if ($this->_sendBuffer) { @@ -543,7 +579,7 @@ public function baseRead($socket, $check_eof = true) } // If the application layer protocol has been set up. - if ($this->protocol) { + if ($this->protocol !== 'tcp') { $parser = $this->protocol; while ($this->_recvBuffer !== '' && !$this->_isPaused) { // The current packet length is known. @@ -796,6 +832,7 @@ public function destroy() if ($this->worker) { unset($this->worker->connections[$this->_id]); } + unset(static::$connections[$this->_id]); $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { diff --git a/Worker.php b/Worker.php index bc80c360c..7e6b171f6 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.7'; + const VERSION = '3.4.8'; /** * Status starting. @@ -215,7 +215,7 @@ class Worker * * @var Protocols\ProtocolInterface */ - public $protocol = ''; + public $protocol = 'tcp'; /** * Root path for autoload. @@ -988,6 +988,8 @@ protected static function forkOneWorker($worker) * * @param int $worker_id * @param int $pid + * + * @return integer */ protected static function getId($worker_id, $pid) { @@ -1195,6 +1197,7 @@ protected static function reload() Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); } // For child processes. else { + reset(self::$_workers); $worker = current(self::$_workers); // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { @@ -1325,7 +1328,8 @@ protected static function writeConnectionsStatisticsToStatusFile() { // For master process. if (self::$_masterPid === posix_getpid()) { - file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address PID ID Protocol Worker\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "------------------------------------------------------------ WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address Status PID ID Protocol Worker\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); foreach (self::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGIO); @@ -1353,9 +1357,12 @@ protected static function writeConnectionsStatisticsToStatusFile() $pid = posix_getpid(); $str = ''; + reset(self::$_workers); + $current_worker = current(self::$_workers); + $default_worker_name = $current_worker->name; + /** @var Worker $worker */ - foreach(self::$_workers as $worker) { - foreach($worker->connections as $connection) { + foreach(TcpConnection::$connections as $connection) { /** @var Connection\TcpConnection $connection */ $transport = $connection->transport; $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; @@ -1364,6 +1371,7 @@ protected static function writeConnectionsStatisticsToStatusFile() $send_q = $bytes_format($connection->getSendBufferQueueSize()); $local_address = $connection->getLocalAddress(); $remote_address = $connection->getRemoteAddress(); + $state = $connection->getStatus(false); $bytes_read = $bytes_format($connection->bytesRead); $bytes_written = $bytes_format($connection->bytesWritten); $id = $connection->id; @@ -1373,18 +1381,16 @@ protected static function writeConnectionsStatisticsToStatusFile() } else { $protocol = $connection->protocol; } - + $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; $str .= str_pad($transport, 8).str_pad($ipv4, 7).str_pad($ipv6, 7) .str_pad($recv_q, 13).str_pad($send_q, 13).str_pad($bytes_read, 13).str_pad($bytes_written, 13) - .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' '.str_pad($pid, 8).str_pad($id, 10) - .str_pad($protocol, 12).' '.$worker->name."\n" ; - } + .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' ' . str_pad($state, 12) . str_pad($pid, 8).str_pad($id, 10) + .str_pad($protocol, 12).' '.$worker_name."\n" ; + } if ($str) { file_put_contents(self::$_statisticsFile, $str, FILE_APPEND); } - - reset(self::$_workers); } /** From 7442b2fb125ddbf629ae386fc6cbb575813b3e6d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Aug 2017 00:14:17 +0800 Subject: [PATCH 0137/1216] connection status --- Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 7e6b171f6..80fd3ae89 100644 --- a/Worker.php +++ b/Worker.php @@ -1329,7 +1329,7 @@ protected static function writeConnectionsStatisticsToStatusFile() // For master process. if (self::$_masterPid === posix_getpid()) { file_put_contents(self::$_statisticsFile, "------------------------------------------------------------ WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address Status PID ID Protocol Worker\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address Status PID ID Protocol Worker\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); foreach (self::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGIO); @@ -1384,8 +1384,8 @@ protected static function writeConnectionsStatisticsToStatusFile() $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; $str .= str_pad($transport, 8).str_pad($ipv4, 7).str_pad($ipv6, 7) .str_pad($recv_q, 13).str_pad($send_q, 13).str_pad($bytes_read, 13).str_pad($bytes_written, 13) - .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' ' . str_pad($state, 12) . str_pad($pid, 8).str_pad($id, 10) - .str_pad($protocol, 12).' '.$worker_name."\n" ; + .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' ' . str_pad($state, 14) . str_pad($pid, 8).str_pad($id, 10) + .str_pad($protocol, 15).' '.$worker_name."\n" ; } if ($str) { From 457d42475bb652102206977dcf965597382b8aaf Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Aug 2017 21:55:36 +0800 Subject: [PATCH 0138/1216] connection status --- Connection/TcpConnection.php | 6 ++-- Connection/UdpConnection.php | 2 +- Worker.php | 66 +++++++++++++++++------------------- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 8be7f05fd..643113860 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -105,7 +105,7 @@ class TcpConnection extends ConnectionInterface * * @var \Workerman\Protocols\ProtocolInterface */ - public $protocol = 'tcp'; + public $protocol = null; /** * Transport (tcp/udp/unix/ssl). @@ -305,7 +305,7 @@ public function send($send_buffer, $raw = false) } // Try to call protocol::encode($send_buffer) before sending. - if (false === $raw && $this->protocol !== 'tcp') { + if (false === $raw && $this->protocol !== null) { $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { @@ -579,7 +579,7 @@ public function baseRead($socket, $check_eof = true) } // If the application layer protocol has been set up. - if ($this->protocol !== 'tcp') { + if ($this->protocol !== null) { $parser = $this->protocol; while ($this->_recvBuffer !== '' && !$this->_isPaused) { // The current packet length is known. diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 2e7aeee58..56287c19c 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -61,7 +61,7 @@ public function __construct($socket, $remote_address) */ public function send($send_buffer, $raw = false) { - if (false === $raw && $this->protocol) { + if (false === $raw && $this->protocol !== 'udp') { $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { diff --git a/Worker.php b/Worker.php index 80fd3ae89..07d5500ce 100644 --- a/Worker.php +++ b/Worker.php @@ -215,7 +215,7 @@ class Worker * * @var Protocols\ProtocolInterface */ - public $protocol = 'tcp'; + public $protocol = null; /** * Root path for autoload. @@ -1363,29 +1363,30 @@ protected static function writeConnectionsStatisticsToStatusFile() /** @var Worker $worker */ foreach(TcpConnection::$connections as $connection) { - /** @var Connection\TcpConnection $connection */ - $transport = $connection->transport; - $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; - $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; - $recv_q = $bytes_format($connection->getRecvBufferQueueSize()); - $send_q = $bytes_format($connection->getSendBufferQueueSize()); - $local_address = $connection->getLocalAddress(); - $remote_address = $connection->getRemoteAddress(); - $state = $connection->getStatus(false); - $bytes_read = $bytes_format($connection->bytesRead); - $bytes_written = $bytes_format($connection->bytesWritten); - $id = $connection->id; - $pos = strrpos($connection->protocol, '\\'); - if ($pos) { - $protocol = substr($connection->protocol, $pos+1); - } else { - $protocol = $connection->protocol; - } - $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; - $str .= str_pad($transport, 8).str_pad($ipv4, 7).str_pad($ipv6, 7) - .str_pad($recv_q, 13).str_pad($send_q, 13).str_pad($bytes_read, 13).str_pad($bytes_written, 13) - .str_pad($local_address, 22).' '.str_pad($remote_address, 22).' ' . str_pad($state, 14) . str_pad($pid, 8).str_pad($id, 10) - .str_pad($protocol, 15).' '.$worker_name."\n" ; + /** @var Connection\TcpConnection $connection */ + $transport = $connection->transport; + $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; + $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; + $recv_q = $bytes_format($connection->getRecvBufferQueueSize()); + $send_q = $bytes_format($connection->getSendBufferQueueSize()); + $local_address = trim($connection->getLocalAddress()); + $remote_address = trim($connection->getRemoteAddress()); + $state = $connection->getStatus(false); + $bytes_read = $bytes_format($connection->bytesRead); + $bytes_written = $bytes_format($connection->bytesWritten); + $id = $connection->id; + $protocol = $connection->protocol ? $connection->protocol : $connection->transport; + $pos = strrpos($protocol, '\\'); + if ($pos) { + $protocol = substr($protocol, $pos+1); + } + + $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; + $str .= str_pad($transport, 8) . str_pad($ipv4, 7) . str_pad($ipv6, 7) + . str_pad($recv_q, 13) . str_pad($send_q, 13) . str_pad($bytes_read, 13) + . str_pad($bytes_written, 13) . str_pad($local_address, 22) . ' ' + . str_pad($remote_address, 22) . ' ' . str_pad($state, 14) . str_pad($pid, 8) + . str_pad($id, 10) . str_pad($protocol, 15) . ' ' . $worker_name."\n" ; } if ($str) { @@ -1536,18 +1537,15 @@ public function listen() list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { - if(class_exists($scheme)){ - $this->protocol = $scheme; - } else { - $scheme = ucfirst($scheme); - $this->protocol = '\\Protocols\\' . $scheme; + $scheme = ucfirst($scheme); + $this->protocol = '\\Protocols\\' . $scheme; + if (!class_exists($this->protocol)) { + $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); - } + throw new Exception("class \\Protocols\\$scheme not exist"); } } + if (!isset(self::$_builtinTransports[$this->transport])) { throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); } @@ -1749,7 +1747,7 @@ public function acceptUdpConnection($socket) $connection = new UdpConnection($socket, $remote_address); $connection->protocol = $this->protocol; if ($this->onMessage) { - if ($this->protocol) { + if ($this->protocol !== null) { $parser = $this->protocol; $recv_buffer = $parser::decode($recv_buffer, $connection); // Discard bad packets. From 423bb7cfb97426e82e4e458889a4f51f2dbf1b09 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Aug 2017 13:35:12 +0800 Subject: [PATCH 0139/1216] status add busy/idle column --- Worker.php | 64 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/Worker.php b/Worker.php index 07d5500ce..546531ab9 100644 --- a/Worker.php +++ b/Worker.php @@ -682,7 +682,11 @@ protected static function parseCommand() // Waiting amoment. usleep(500000); // Display statisitcs data from a disk file. - @readfile(self::$_statisticsFile); + if ($command !== 'status') { + @readfile(self::$_statisticsFile); + exit(0); + } + echo self::formatStatusData(); exit(0); case 'restart': case 'stop': @@ -725,6 +729,46 @@ protected static function parseCommand() } } + /** + * Format status data. + * + * @return string + */ + protected static function formatStatusData() + { + $info = @file(self::$_statisticsFile, FILE_IGNORE_NEW_LINES); + if (!$info) { + return ''; + } + $status_str = ''; + $worker_info = json_decode($info[0], true); + ksort($worker_info, SORT_NUMERIC); + unset($info[0]); + $data_waiting_sort = array(); + foreach($info as $key => $value) { + if ($key < 10) { + $status_str .= $value . "\n"; + continue; + } + if(preg_match('/^[0-9]+/', $value, $pid)) { + $data_waiting_sort[$pid[0]] = $value; + } + } + foreach($worker_info as $pid => $info) { + if (!isset($data_waiting_sort[$pid])) { + $status_str .= "$pid\t" . str_pad('N/A', 7) . " " + . str_pad($info['listen'], self::$_maxSocketNameLength) . " " + . str_pad($info['name'], self::$_maxWorkerNameLength) . " " + . str_pad('N/A', 11) . " " . str_pad('N/A', 14) . " " + . str_pad('N/A', 9) . " " . str_pad('N/A', 9) . "[busy]\n"; + continue; + } + $status_str .= $data_waiting_sort[$pid]. "[idle]\n"; + } + return $status_str; + } + + /** * Install signal handler. * @@ -1259,9 +1303,19 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (self::$_masterPid === posix_getpid()) { + $all_worker_info = array(); + foreach(self::$_pidMap as $worker_id => $pid_array) { + /** @var Worker $worker */ + $worker = self::$_workers[$worker_id]; + foreach($pid_array as $pid) { + $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName()); + } + } + + file_put_contents(self::$_statisticsFile, json_encode($all_worker_info)."\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); file_put_contents(self::$_statisticsFile, - "---------------------------------------GLOBAL STATUS--------------------------------------------\n"); + "---------------------------------------GLOBAL STATUS--------------------------------------------\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, 'Workerman version:' . Worker::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', @@ -1295,7 +1349,7 @@ protected static function writeStatisticsToStatusFile() file_put_contents(self::$_statisticsFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', self::$_maxWorkerNameLength) . " connections " . str_pad('total_request', - 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 15) . "\n", FILE_APPEND); + 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 9) . " status\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); @@ -1307,7 +1361,7 @@ protected static function writeStatisticsToStatusFile() // For child processes. /** @var Worker $worker */ - $worker = current(self::$_workers); + $worker = current(self::$_workers); $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . str_pad($worker->getSocketName(), self::$_maxSocketNameLength) . " " . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), @@ -1315,7 +1369,7 @@ protected static function writeStatisticsToStatusFile() $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], 14) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], - 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 15) . "\n"; + 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 9) . "\n"; file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } From f3a23f2ce626a3326a6ebbee3627e7faa1d859ab Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Aug 2017 14:37:14 +0800 Subject: [PATCH 0140/1216] connection status --- Worker.php | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Worker.php b/Worker.php index 546531ab9..fb5d283ed 100644 --- a/Worker.php +++ b/Worker.php @@ -759,11 +759,11 @@ protected static function formatStatusData() $status_str .= "$pid\t" . str_pad('N/A', 7) . " " . str_pad($info['listen'], self::$_maxSocketNameLength) . " " . str_pad($info['name'], self::$_maxWorkerNameLength) . " " - . str_pad('N/A', 11) . " " . str_pad('N/A', 14) . " " - . str_pad('N/A', 9) . " " . str_pad('N/A', 9) . "[busy]\n"; + . str_pad('N/A', 11) . " " . str_pad('N/A', 13) . " " + . str_pad('N/A', 9) . " " . str_pad('N/A', 8) . " [busy] \n"; continue; } - $status_str .= $data_waiting_sort[$pid]. "[idle]\n"; + $status_str .= $data_waiting_sort[$pid]. " [idle] \n"; } return $status_str; } @@ -1328,7 +1328,7 @@ protected static function writeStatisticsToStatusFile() count(self::$_pidMap) . ' workers ' . count(self::getAllWorkerPids()) . " processes\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, - str_pad('worker_name', self::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); + str_pad('worker_name', self::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (self::$_pidMap as $worker_id => $worker_pid_array) { $worker = self::$_workers[$worker_id]; if (isset(self::$_globalStatistics['worker_exit_info'][$worker_id])) { @@ -1349,7 +1349,7 @@ protected static function writeStatisticsToStatusFile() file_put_contents(self::$_statisticsFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', self::$_maxWorkerNameLength) . " connections " . str_pad('total_request', - 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 9) . " status\n", FILE_APPEND); + 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . " status\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); @@ -1368,8 +1368,8 @@ protected static function writeStatisticsToStatusFile() self::$_maxWorkerNameLength) . " "; $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], - 14) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], - 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 9) . "\n"; + 13) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], + 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 8) . "\n"; file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } @@ -1382,8 +1382,8 @@ protected static function writeConnectionsStatisticsToStatusFile() { // For master process. if (self::$_masterPid === posix_getpid()) { - file_put_contents(self::$_statisticsFile, "------------------------------------------------------------ WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, "Trans ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Local Address Foreign Address Status PID ID Protocol Worker\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); foreach (self::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGIO); @@ -1434,14 +1434,17 @@ protected static function writeConnectionsStatisticsToStatusFile() if ($pos) { $protocol = substr($protocol, $pos+1); } - + if (strlen($protocol) > 15) { + $protocol = substr($protocol, 0, 13) . '..'; + } $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; - $str .= str_pad($transport, 8) . str_pad($ipv4, 7) . str_pad($ipv6, 7) - . str_pad($recv_q, 13) . str_pad($send_q, 13) . str_pad($bytes_read, 13) - . str_pad($bytes_written, 13) . str_pad($local_address, 22) . ' ' - . str_pad($remote_address, 22) . ' ' . str_pad($state, 14) . str_pad($pid, 8) - . str_pad($id, 10) . str_pad($protocol, 15) . ' ' . $worker_name."\n" ; - + if (strlen($worker_name) > 14) { + $worker_name = substr($worker_name, 0, 12) . '..'; + } + $str .= str_pad($pid, 9) . str_pad($worker_name, 16) . str_pad($id, 10) . str_pad($transport, 8) + . str_pad($protocol, 16) . str_pad($ipv4, 7) . str_pad($ipv6, 7) . str_pad($recv_q, 13) + . str_pad($send_q, 13) . str_pad($bytes_read, 13) . str_pad($bytes_written, 13) . ' ' + . str_pad($state, 14) . ' ' . str_pad($local_address, 22) . ' ' . str_pad($remote_address, 22) ."\n"; } if ($str) { file_put_contents(self::$_statisticsFile, $str, FILE_APPEND); From 441139228fc69cd2dda1c09a9b772e5466963af9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Aug 2017 14:39:42 +0800 Subject: [PATCH 0141/1216] connection status --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index fb5d283ed..f5a343c20 100644 --- a/Worker.php +++ b/Worker.php @@ -1383,7 +1383,7 @@ protected static function writeConnectionsStatisticsToStatusFile() // For master process. if (self::$_masterPid === posix_getpid()) { file_put_contents(self::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + file_put_contents(self::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); foreach (self::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGIO); From f31808bb58ab830d519a0deb3b305eca4d85d0d8 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Aug 2017 18:30:27 +0800 Subject: [PATCH 0142/1216] checkErrors tips --- Worker.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index f5a343c20..5ea70fe6f 100644 --- a/Worker.php +++ b/Worker.php @@ -1459,7 +1459,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (self::STATUS_SHUTDOWN != self::$_status) { - $error_msg = 'Worker['. posix_getpid() .'] process terminated with '; + $error_msg = 'Worker['. posix_getpid() .'] process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || @@ -1467,9 +1467,7 @@ public static function checkErrors() $errors['type'] === E_COMPILE_ERROR || $errors['type'] === E_RECOVERABLE_ERROR) ) { - $error_msg .= self::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; - } else { - $error_msg .= 'exit()/die(). Please do not call exit()/die() in workerman.'; + $error_msg .= ' with ERROR: ' . self::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } self::log($error_msg); } From 801d914397ab0efee9ecba95f1de8e45b7c970a9 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 20 Aug 2017 20:59:38 +0800 Subject: [PATCH 0143/1216] Fix status some lines missing Fix #201 --- Worker.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 5ea70fe6f..ef2c8f552 100644 --- a/Worker.php +++ b/Worker.php @@ -745,9 +745,13 @@ protected static function formatStatusData() ksort($worker_info, SORT_NUMERIC); unset($info[0]); $data_waiting_sort = array(); + $read_process_status = false; foreach($info as $key => $value) { - if ($key < 10) { + if (!$read_process_status) { $status_str .= $value . "\n"; + if (preg_match('/^pid.*?memory.*?listening/', $value)) { + $read_process_status = true; + } continue; } if(preg_match('/^[0-9]+/', $value, $pid)) { @@ -1315,7 +1319,7 @@ protected static function writeStatisticsToStatusFile() file_put_contents(self::$_statisticsFile, json_encode($all_worker_info)."\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); file_put_contents(self::$_statisticsFile, - "---------------------------------------GLOBAL STATUS--------------------------------------------\n", FILE_APPEND); + "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, 'Workerman version:' . Worker::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', @@ -1344,7 +1348,7 @@ protected static function writeStatisticsToStatusFile() } } file_put_contents(self::$_statisticsFile, - "---------------------------------------PROCESS STATUS-------------------------------------------\n", + "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", FILE_APPEND); file_put_contents(self::$_statisticsFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', From ea47ff196fb56db812ed5231ee55655139b115f8 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 Aug 2017 15:11:28 +0800 Subject: [PATCH 0144/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ef2c8f552..83d3cb16c 100644 --- a/Worker.php +++ b/Worker.php @@ -427,8 +427,8 @@ public static function runAll() self::initWorkers(); self::installSignal(); self::saveMasterPid(); - self::forkWorkers(); self::displayUI(); + self::forkWorkers(); self::resetStd(); self::monitorWorkers(); } From d0ceb68782e27537f78735880581829253981c03 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Aug 2017 14:03:59 +0800 Subject: [PATCH 0145/1216] 3.5.0 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 83d3cb16c..7474cedf2 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.4.8'; + const VERSION = '3.5.0'; /** * Status starting. From 90b07354d90add9963d4cbcbc724e0b69fea9d12 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Aug 2017 14:14:54 +0800 Subject: [PATCH 0146/1216] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9e47bc024..c594a7e2f 100644 --- a/README.md +++ b/README.md @@ -490,14 +490,15 @@ Worker::runAll(); ## Available commands -```php test.php start ``` -```php test.php start -d ``` +```php start.php start ``` +```php start.php start -d ``` ![workerman start](http://www.workerman.net/img/workerman-start.png) -```php test.php status ``` +```php start.php status ``` ![workerman satus](http://www.workerman.net/img/workerman-status.png?a=123) -```php test.php stop ``` -```php test.php restart ``` -```php test.php reload ``` +```php start.php connections +```php start.php stop ``` +```php start.php restart ``` +```php start.php reload ``` ## Documentation From 4a0f9f5780afca71a133c904c32b1cb4bc7da09b Mon Sep 17 00:00:00 2001 From: sunhlh Date: Wed, 23 Aug 2017 19:40:00 +0800 Subject: [PATCH 0147/1216] ok --- Connection/TcpConnection.php | 10 ++++++++++ Protocols/Http.php | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 3b8383002..d5502e83c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -660,6 +660,16 @@ protected function bufferIsFull() } return false; } + + /** + * Whether send buffer is Empty. + * + * @return bool + */ + public function bufferIsEmpty() + { + return empty($this->_sendBuffer); + } /** * Destroy connection. diff --git a/Protocols/Http.php b/Protocols/Http.php index 98add4a93..43ffbf14b 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -171,9 +171,23 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; + case 'application/json': + $_POST = json_decode($http_body, true); + break; } } } + + // 解析其他HTTP动作参数 + if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { + $data = array(); + if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { + parse_str($http_body, $data); + } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { + $data = json_decode($http_body, true); + } + $_REQUEST = array_merge($_REQUEST, $data); + } // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; @@ -188,7 +202,7 @@ public static function decode($recv_buffer, TcpConnection $connection) } // REQUEST - $_REQUEST = array_merge($_GET, $_POST); + $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); From 89f846025071786ba0b5d98ff2ce041b065347fe Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Aug 2017 16:21:52 +0800 Subject: [PATCH 0148/1216] Update UdpConnection.php --- Connection/UdpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 56287c19c..2e7aeee58 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -61,7 +61,7 @@ public function __construct($socket, $remote_address) */ public function send($send_buffer, $raw = false) { - if (false === $raw && $this->protocol !== 'udp') { + if (false === $raw && $this->protocol) { $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { From 01aadefdc3e7bf65dd0956d1d876bc9d27cd9156 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Aug 2017 16:26:28 +0800 Subject: [PATCH 0149/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 7474cedf2..97485b6f4 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.0'; + const VERSION = '3.5.1'; /** * Status starting. From 6a0419c6b901533069dd83bb15d663ff6906f011 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 9 Sep 2017 20:44:20 +0800 Subject: [PATCH 0150/1216] status support QPS statistics --- Worker.php | 70 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/Worker.php b/Worker.php index 97485b6f4..7891e0668 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.1'; + const VERSION = '3.5.2'; /** * Status starting. @@ -672,21 +672,30 @@ protected static function parseCommand() } break; case 'status': + while (1) { + if (is_file(self::$_statisticsFile)) { + @unlink(self::$_statisticsFile); + } + // Master process will send SIGUSR2 signal to all child processes. + posix_kill($master_pid, SIGUSR2); + // Sleep 1 second. + sleep(1); + // Clear terminal. + echo chr(27).chr(91).chr(72).chr(27).chr(91).chr(50).chr(74); + // Echo status data. + echo self::formatStatusData(); + } + exit(0); case 'connections': if (is_file(self::$_statisticsFile)) { @unlink(self::$_statisticsFile); } - // Master process will send status signal to all child processes. - $signal = $command === 'status' ? SIGUSR2 : SIGIO; - posix_kill($master_pid, $signal); + // Master process will send SIGIO signal to all child processes. + posix_kill($master_pid, SIGIO); // Waiting amoment. usleep(500000); // Display statisitcs data from a disk file. - if ($command !== 'status') { - @readfile(self::$_statisticsFile); - exit(0); - } - echo self::formatStatusData(); + @readfile(self::$_statisticsFile); exit(0); case 'restart': case 'stop': @@ -736,11 +745,13 @@ protected static function parseCommand() */ protected static function formatStatusData() { + static $total_request_cache = array(); $info = @file(self::$_statisticsFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } $status_str = ''; + $current_total_request = array(); $worker_info = json_decode($info[0], true); ksort($worker_info, SORT_NUMERIC); unset($info[0]); @@ -754,8 +765,12 @@ protected static function formatStatusData() } continue; } - if(preg_match('/^[0-9]+/', $value, $pid)) { - $data_waiting_sort[$pid[0]] = $value; + if(preg_match('/^[0-9]+/', $value, $pid_math)) { + $pid = $pid_math[0]; + $data_waiting_sort[$pid] = $value; + if(preg_match('/^\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?(\S+?)\s+?/', $value, $match)) { + $current_total_request[$pid] = $match[1]; + } } } foreach($worker_info as $pid => $info) { @@ -763,12 +778,19 @@ protected static function formatStatusData() $status_str .= "$pid\t" . str_pad('N/A', 7) . " " . str_pad($info['listen'], self::$_maxSocketNameLength) . " " . str_pad($info['name'], self::$_maxWorkerNameLength) . " " - . str_pad('N/A', 11) . " " . str_pad('N/A', 13) . " " - . str_pad('N/A', 9) . " " . str_pad('N/A', 8) . " [busy] \n"; + . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " + . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; continue; } - $status_str .= $data_waiting_sort[$pid]. " [idle] \n"; + //$qps = isset($total_request_cache[$pid]) ? $current_total_request[$pid] + if (!isset($total_request_cache[$pid]) || !isset($current_total_request[$pid])) { + $qps = 0; + } else { + $qps = $current_total_request[$pid] - $total_request_cache[$pid]; + } + $status_str .= $data_waiting_sort[$pid]. " " . str_pad($qps, 6) ." [idle]\n"; } + $total_request_cache = $current_total_request; return $status_str; } @@ -1352,8 +1374,8 @@ protected static function writeStatisticsToStatusFile() FILE_APPEND); file_put_contents(self::$_statisticsFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', - self::$_maxWorkerNameLength) . " connections " . str_pad('total_request', - 13) . " " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . " status\n", FILE_APPEND); + self::$_maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " + . str_pad('timers', 8) . str_pad('total_request', 13) ." qps status\n", FILE_APPEND); chmod(self::$_statisticsFile, 0722); @@ -1366,14 +1388,14 @@ protected static function writeStatisticsToStatusFile() // For child processes. /** @var Worker $worker */ $worker = current(self::$_workers); - $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", - 7) . " " . str_pad($worker->getSocketName(), - self::$_maxSocketNameLength) . " " . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), - self::$_maxWorkerNameLength) . " "; - $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], - 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], - 13) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], - 9) . " " . str_pad(self::$globalEvent->getTimerCount(), 8) . "\n"; + $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) + . " " . str_pad($worker->getSocketName(), self::$_maxSocketNameLength) . " " + . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), self::$_maxWorkerNameLength) + . " "; + $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) + . " " . str_pad(ConnectionInterface::$statistics['send_fail'], 9) + . " " . str_pad(self::$globalEvent->getTimerCount(), 7) + . " " . str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); } From 08286d8d7317d32a0be3c55531d4c1b64d0cb9cf Mon Sep 17 00:00:00 2001 From: farwish Date: Wed, 20 Sep 2017 17:32:36 +0800 Subject: [PATCH 0151/1216] Let the usage shows to users the second optional available argument -d --- Worker.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 7891e0668..b7f473eca 100644 --- a/Worker.php +++ b/Worker.php @@ -614,7 +614,7 @@ protected static function displayUI() /** * Parse command. - * php yourfile.php start | stop | restart | reload | status + * php yourfile.php start | stop | restart | reload | status [-d] * * @return void */ @@ -631,8 +631,9 @@ protected static function parseCommand() 'status', 'connections', ); + $usage = "Usage: php yourfile.php {" . implode('|', $available_commands) . "} [-d]\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - exit("Usage: php yourfile.php {" . implode('|', $available_commands) . "}\n"); + exit($usage); } // Get command. @@ -734,7 +735,7 @@ protected static function parseCommand() self::log("Workerman[$start_file] reload"); exit; default : - exit("Usage: php yourfile.php {" . implode('|', $available_commands) . "}\n"); + exit($usage); } } From 7bd75da44e8346f9bb4f526a487a9951d881f5a6 Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 21 Sep 2017 22:35:41 +0800 Subject: [PATCH 0152/1216] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=95=B4=E5=9E=8B?= =?UTF-8?q?=E6=BA=A2=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 解决整型溢出 --- Connection/TcpConnection.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 643113860..fad29c933 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -264,6 +264,9 @@ public function __construct($socket, $remote_address = '') { self::$statistics['connection_count']++; $this->id = $this->_id = self::$_idRecorder++; + if(self::$_idRecorder===PHP_INT_MAX){ + self::$_idRecorder=0; + } $this->_socket = $socket; stream_set_blocking($this->_socket, 0); // Compatible with hhvm From 7d2e68006eff8bf5f85e6fbbbf2c18bb03dcf72e Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 22 Sep 2017 11:05:32 +0800 Subject: [PATCH 0153/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index fad29c933..581340a51 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -263,9 +263,9 @@ class TcpConnection extends ConnectionInterface public function __construct($socket, $remote_address = '') { self::$statistics['connection_count']++; - $this->id = $this->_id = self::$_idRecorder++; - if(self::$_idRecorder===PHP_INT_MAX){ - self::$_idRecorder=0; + $this->id = $this->_id = self::$_idRecorder++; + if(self::$_idRecorder === PHP_INT_MAX){ + self::$_idRecorder = 0; } $this->_socket = $socket; stream_set_blocking($this->_socket, 0); From ef42b9f730044684cfbea507a0023c65d260159d Mon Sep 17 00:00:00 2001 From: Ares Date: Sat, 30 Sep 2017 16:58:13 +0800 Subject: [PATCH 0154/1216] Fix unix domain socket file permission Socket file permission is not same with forked worker.Fix it. --- Worker.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Worker.php b/Worker.php index b7f473eca..b24697bcb 100644 --- a/Worker.php +++ b/Worker.php @@ -1654,6 +1654,14 @@ public function listen() if ($this->transport === 'ssl') { stream_socket_enable_crypto($this->_mainSocket, false); + } elseif ($this->transport === 'unix') { + $socketFile = substr($address, 2); + if ($this->user) { + chown($socketFile, $this->user); + } + if ($this->group) { + chgrp($socketFile, $this->group); + } } // Try to open keepalive for tcp and disable Nagle algorithm. From 7ef9b1159715ca476090e097e39e74a661b21960 Mon Sep 17 00:00:00 2001 From: Vitaliy Ponomarev Date: Mon, 2 Oct 2017 01:08:54 +0300 Subject: [PATCH 0155/1216] Added support of setting onWebSocketConnect, onWebSocketClose, onWebSocketPing, onWebSocketPong events via worker instance for Websocket protocol, like: $worker = new Worker("websocket://0.0.0.0:443"); $worker->onWebSocketConnect = function($conn, $buffer) { ... --- Protocols/Websocket.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 2ab5635da..21a2e4704 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -83,9 +83,9 @@ public static function input($buffer, ConnectionInterface $connection) // Close package. case 0x8: // Try to emit onWebSocketClose callback. - if (isset($connection->onWebSocketClose)) { + if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) { try { - call_user_func($connection->onWebSocketClose, $connection); + call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -101,9 +101,9 @@ public static function input($buffer, ConnectionInterface $connection) // Ping package. case 0x9: // Try to emit onWebSocketPing callback. - if (isset($connection->onWebSocketPing)) { + if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { try { - call_user_func($connection->onWebSocketPing, $connection); + call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -129,9 +129,9 @@ public static function input($buffer, ConnectionInterface $connection) // Pong package. case 0xa: // Try to emit onWebSocketPong callback. - if (isset($connection->onWebSocketPong)) { + if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { try { - call_user_func($connection->onWebSocketPong, $connection); + call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -382,10 +382,10 @@ protected static function dealHandshake($buffer, $connection) $connection->websocketType = static::BINARY_TYPE_BLOB; } // Try to emit onWebSocketConnect callback. - if (isset($connection->onWebSocketConnect)) { + if (isset($connection->onWebSocketConnect) || isset($connection->worker->onWebSocketConnect)) { static::parseHttpHeader($buffer); try { - call_user_func($connection->onWebSocketConnect, $connection, $buffer); + call_user_func(isset($connection->onWebSocketConnect)?$connection->onWebSocketConnect:$connection->worker->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { Worker::log($e); exit(250); From f46d92b4cd515e08b7634c64523c4d96ea98ad51 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Oct 2017 01:04:52 -0500 Subject: [PATCH 0156/1216] Update README.md --- README.md | 84 ++++++++++--------------------------------------------- 1 file changed, 14 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index c594a7e2f..4fb717de9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # Workerman [![Gitter](https://badges.gitter.im/walkor/Workerman.svg)](https://gitter.im/walkor/Workerman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) +[![Latest Stable Version](https://poser.pugx.org/workerman/workerman/v/stable)](https://packagist.org/packages/workerman/workerman) +[![Total Downloads](https://poser.pugx.org/workerman/workerman/downloads)](https://packagist.org/packages/workerman/workerman) +[![Monthly Downloads](https://poser.pugx.org/workerman/workerman/d/monthly)](https://packagist.org/packages/workerman/workerman) +[![Daily Downloads](https://poser.pugx.org/workerman/workerman/d/daily)](https://packagist.org/packages/workerman/workerman) +[![License](https://poser.pugx.org/workerman/workerman/license)](https://packagist.org/packages/workerman/workerman) ## What is it Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket, SSL and other custom protocols. Supports libevent, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). @@ -494,8 +499,8 @@ Worker::runAll(); ```php start.php start -d ``` ![workerman start](http://www.workerman.net/img/workerman-start.png) ```php start.php status ``` -![workerman satus](http://www.workerman.net/img/workerman-status.png?a=123) -```php start.php connections +![workerman satus](http://www.workerman.net/img/workerman-status.png?a=123) +```php start.php connections```   ```php start.php stop ``` ```php start.php restart ``` ```php start.php reload ``` @@ -504,7 +509,7 @@ Worker::runAll(); 中文主页:[http://www.workerman.net](http://www.workerman.net) -中文文档: [http://doc3.workerman.net](http://doc3.workerman.net) +中文文档: [http://doc.workerman.net](http://doc.workerman.net) Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/src/SUMMARY.md) @@ -593,73 +598,12 @@ Percentage of the requests served within a certain time (ms) ## Other links with workerman -## [PHPSocket.IO](https://github.com/walkor/phpsocket.io) -[Live demo](http://www.workerman.net/demos/phpsocketio-chat/) -[Source code](https://github.com/walkor/phpsocket.io) -![phpsocket.io](http://www.workerman.net/img/socket.io.png) - -## [tadpole](http://kedou.workerman.net/) -[Live demo](http://kedou.workerman.net/) -[Source code](https://github.com/walkor/workerman) -![workerman todpole](http://www.workerman.net/img/workerman-todpole.png) - -## [BrowserQuest](http://www.workerman.net/demos/browserquest/) -[Live demo](http://www.workerman.net/demos/browserquest/) -[Source code](https://github.com/walkor/BrowserQuest-PHP) -![BrowserQuest width workerman](http://www.workerman.net/img/browserquest.jpg) - -## [web vmstat](http://www.workerman.net/demos/vmstat/) -[Live demo](http://www.workerman.net/demos/vmstat/) -[Source code](https://github.com/walkor/workerman-vmstat) -![web vmstat](http://www.workerman.net/img/workerman-vmstat.png) - -## [live-ascii-camera](https://github.com/walkor/live-ascii-camera) -[Live demo camera page](http://www.workerman.net/demos/live-ascii-camera/camera.html) -[Live demo receive page](http://www.workerman.net/demos/live-ascii-camera/) -[Source code](https://github.com/walkor/live-ascii-camera) -![live-ascii-camera](http://www.workerman.net/img/live-ascii-camera.png) - -## [live-camera](https://github.com/walkor/live-camera) -[Live demo camera page](http://www.workerman.net/demos/live-camera/camera.html) -[Live demo receive page](http://www.workerman.net/demos/live-camera/) -[Source code](https://github.com/walkor/live-camera) -![live-camera](http://www.workerman.net/img/live-camera.jpg) - -## [chat room](http://chat.workerman.net/) -[Live demo](http://chat.workerman.net/) -[Source code](https://github.com/walkor/workerman-chat) -![workerman-chat](http://www.workerman.net/img/workerman-chat.png) - -## [statistics](http://www.workerman.net:55757/) -[Live demo](http://www.workerman.net:55757/) -[Source code](https://github.com/walkor/workerman-statistics) -![workerman-statistics](http://www.workerman.net/img/workerman-statistics.png) - -## [flappybird](http://workerman.net/demos/flappy-bird/) -[Live demo](http://workerman.net/demos/flappy-bird/) -[Source code](https://github.com/walkor/workerman-flappy-bird) -![workerman-statistics](http://www.workerman.net/img/workerman-flappy-bird.png) - -## [jsonRpc](https://github.com/walkor/workerman-JsonRpc) -[Source code](https://github.com/walkor/workerman-JsonRpc) -![workerman-jsonRpc](http://www.workerman.net/img/workerman-json-rpc.png) - -## [thriftRpc](https://github.com/walkor/workerman-thrift) -[Source code](https://github.com/walkor/workerman-thrift) -![workerman-thriftRpc](http://www.workerman.net/img/workerman-thrift.png) - -## [web-msg-sender](https://github.com/walkor/web-msg-sender) -[Live demo send page](http://workerman.net:3333/) -[Live demo receive page](http://workerman.net/web-msg-sender.html) -[Source code](https://github.com/walkor/web-msg-sender) -![web-msg-sender](http://www.workerman.net/img/web-msg-sender.png) - -## [shadowsocks-php](https://github.com/walkor/shadowsocks-php) -[Source code](https://github.com/walkor/shadowsocks-php) -![shadowsocks-php](http://www.workerman.net/img/shadowsocks-php.png) - -## [queue](https://github.com/walkor/workerman-queue) -[Source code](https://github.com/walkor/workerman-queue) +[PHPSocket.IO](https://github.com/walkor/phpsocket.io) +[php-socks5](https://github.com/walkor/php-socks5) +[php-http-proxy](https://github.com/walkor/php-http-proxy) + +## Donate + ## LICENSE From 56e4145c60722133259f542e9e138d846476ff3a Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Oct 2017 01:06:36 -0500 Subject: [PATCH 0157/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fb717de9..17749951b 100644 --- a/README.md +++ b/README.md @@ -500,7 +500,7 @@ Worker::runAll(); ![workerman start](http://www.workerman.net/img/workerman-start.png) ```php start.php status ``` ![workerman satus](http://www.workerman.net/img/workerman-status.png?a=123) -```php start.php connections```   +```php start.php connections``` ```php start.php stop ``` ```php start.php restart ``` ```php start.php reload ``` From 055657a9fac9483a5e4fe4edb229aeb307a456d7 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Oct 2017 01:11:38 -0500 Subject: [PATCH 0158/1216] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 17749951b..41e708635 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ $tcp_worker->onClose = function($connection) Worker::runAll(); ``` -### Enable SSL. +### Enable SSL ```php array( - 'local_cert' => '/your/path/of/server.pem', - 'local_pk' => '/your/path/of/server.key', + 'local_cert' => '/your/path/of/server.pem', + 'local_pk' => '/your/path/of/server.key', + 'verify_peer' => false, ) ); From ea04a07d2951dbbab164e17b2d3d0826a3aa5067 Mon Sep 17 00:00:00 2001 From: Vitaliy Ponomarev Date: Sun, 8 Oct 2017 20:39:15 +0300 Subject: [PATCH 0159/1216] Websocket - outgoing PING packets, now this packet contains MASK. According to Section 5.2 of the specification, all frames from client to server have the mask bit set to 1. --- Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index a3a019393..43605f36b 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -412,7 +412,7 @@ public static function dealHandshake($buffer, $connection) // Headbeat. if (!empty($connection->websocketPingInterval)) { $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){ - if (false === $connection->send(pack('H*', '8900'), true)) { + if (false === $connection->send(pack('H*', '898000000000'), true)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; } From b6737b0012a29fdeea9648fe3252cfcdc020ad69 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Oct 2017 22:55:02 -0500 Subject: [PATCH 0160/1216] Fix SSL Reconnect issue --- Connection/AsyncTcpConnection.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index d1eaf4414..49df45793 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -51,6 +51,13 @@ class AsyncTcpConnection extends TcpConnection */ protected $_remoteHost = ''; + /** + * Remote port. + * + * @var int + */ + protected $_remotePort = 80; + /** * Connect start time. * @@ -124,6 +131,7 @@ public function __construct($remote_address, $context_option = null) } $this->_remoteAddress = "{$address_info['host']}:{$address_info['port']}"; $this->_remoteHost = $address_info['host']; + $this->_remotePort = $address_info['port']; $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; } @@ -166,10 +174,10 @@ public function connect() // Open socket connection asynchronously. if ($this->_contextOption) { $context = stream_context_create($this->_contextOption); - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. From 5d6c5a0e9440faf31a2b3c55fd0a31ed3105f2ef Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 12 Oct 2017 12:43:53 +0800 Subject: [PATCH 0161/1216] solve int overflow --- Connection/AsyncTcpConnection.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 49df45793..e848bfbd8 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -137,6 +137,9 @@ public function __construct($remote_address, $context_option = null) } $this->id = $this->_id = self::$_idRecorder++; + if(PHP_INT_MAX === self::$_idRecorder){ + self::$_idRecorder = 0; + } // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); From d9d6b9e3fe0a0cb8bb6bd14c96e96117ee9074d7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Oct 2017 01:09:44 -0500 Subject: [PATCH 0162/1216] add unlisten method --- Worker.php | 107 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/Worker.php b/Worker.php index b24697bcb..9a9ace602 100644 --- a/Worker.php +++ b/Worker.php @@ -1602,7 +1602,7 @@ public function __construct($socket_name = '', $context_option = array()) } /** - * Listen port. + * Listen. * * @throws Exception */ @@ -1615,65 +1615,67 @@ public function listen() // Autoload. Autoloader::setRootPath($this->_autoloadRootPath); - // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $this->_socketName, 2); - // Check application layer protocol class. - if (!isset(self::$_builtinTransports[$scheme])) { - $scheme = ucfirst($scheme); - $this->protocol = '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!$this->_mainSocket) { + // Get the application layer communication protocol and listening address. + list($scheme, $address) = explode(':', $this->_socketName, 2); + // Check application layer protocol class. + if (!isset(self::$_builtinTransports[$scheme])) { + $scheme = ucfirst($scheme); + $this->protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); + $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!class_exists($this->protocol)) { + throw new Exception("class \\Protocols\\$scheme not exist"); + } } - } - if (!isset(self::$_builtinTransports[$this->transport])) { - throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); + if (!isset(self::$_builtinTransports[$this->transport])) { + throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); + } + } else { + $this->transport = $scheme; } - } else { - $this->transport = $scheme; - } - $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address; + $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address; - // Flag. - $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; - $errno = 0; - $errmsg = ''; - // SO_REUSEPORT. - if ($this->reusePort) { - stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); - } + // Flag. + $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; + $errno = 0; + $errmsg = ''; + // SO_REUSEPORT. + if ($this->reusePort) { + stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); + } - // Create an Internet or Unix domain server socket. - $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); - if (!$this->_mainSocket) { - throw new Exception($errmsg); - } + // Create an Internet or Unix domain server socket. + $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); + if (!$this->_mainSocket) { + throw new Exception($errmsg); + } - if ($this->transport === 'ssl') { - stream_socket_enable_crypto($this->_mainSocket, false); - } elseif ($this->transport === 'unix') { - $socketFile = substr($address, 2); - if ($this->user) { - chown($socketFile, $this->user); + if ($this->transport === 'ssl') { + stream_socket_enable_crypto($this->_mainSocket, false); + } elseif ($this->transport === 'unix') { + $socketFile = substr($address, 2); + if ($this->user) { + chown($socketFile, $this->user); + } + if ($this->group) { + chgrp($socketFile, $this->group); + } } - if ($this->group) { - chgrp($socketFile, $this->group); + + // Try to open keepalive for tcp and disable Nagle algorithm. + if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') { + $socket = socket_import_stream($this->_mainSocket); + @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); + @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); } - } - // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') { - $socket = socket_import_stream($this->_mainSocket); - @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); - @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + // Non blocking. + stream_set_blocking($this->_mainSocket, 0); } - // Non blocking. - stream_set_blocking($this->_mainSocket, 0); - // Register a listener to be notified when server socket is ready to read. if (self::$globalEvent) { if ($this->transport !== 'udp') { @@ -1685,6 +1687,17 @@ public function listen() } } + /** + * Unlisten. + * + * @return void + */ + public function unlisten() { + if (self::$globalEvent && $this->_mainSocket) { + self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); + } + } + /** * Get socket name. * From 30245d20eb5c1a4442abb6bf4fbc8d38e6dd46eb Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 15:23:13 +0800 Subject: [PATCH 0163/1216] update listen() correspond unlisten() --- Worker.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index 9a9ace602..d46373bb9 100644 --- a/Worker.php +++ b/Worker.php @@ -223,6 +223,13 @@ class Worker * @var string */ protected $_autoloadRootPath = ''; + + /** + * Pause listening or not. + * + * @var string + */ + protected $_pauseListen = false; /** * Daemonize. @@ -1608,7 +1615,7 @@ public function __construct($socket_name = '', $context_option = array()) */ public function listen() { - if (!$this->_socketName || $this->_mainSocket) { + if (!$this->_socketName) { return; } @@ -1677,13 +1684,14 @@ public function listen() } // Register a listener to be notified when server socket is ready to read. - if (self::$globalEvent) { + if (self::$globalEvent || $this->_pauseListen) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } + $this->_pauseListen = false; } } @@ -1695,6 +1703,7 @@ public function listen() public function unlisten() { if (self::$globalEvent && $this->_mainSocket) { self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); + $this->_pauseListen = true; } } @@ -1787,10 +1796,7 @@ public function stop() } } // Remove listener for server socket. - if ($this->_mainSocket) { - self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); - @fclose($this->_mainSocket); - } + $this->unlisten(); } /** From a968d460bdfcfc3e106731668c2cabde45fba4b3 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Oct 2017 02:52:48 -0500 Subject: [PATCH 0164/1216] Update Worker.php --- Worker.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index d46373bb9..139740aa5 100644 --- a/Worker.php +++ b/Worker.php @@ -464,9 +464,12 @@ protected static function init() $backtrace = debug_backtrace(); self::$_startFile = $backtrace[count($backtrace) - 1]['file']; + + $unique_prefix = str_replace('/', '_', self::$_startFile); + // Pid file. if (empty(self::$pidFile)) { - self::$pidFile = __DIR__ . "/../" . str_replace('/', '_', self::$_startFile) . ".pid"; + self::$pidFile = __DIR__ . "/../$unique_prefix.pid"; } // Log file. @@ -484,7 +487,7 @@ protected static function init() // For statistics. self::$_globalStatistics['start_timestamp'] = time(); - self::$_statisticsFile = sys_get_temp_dir() . '/workerman.status'; + self::$_statisticsFile = sys_get_temp_dir() . "/$unique_prefix.status"; // Process title. self::setProcessTitle('WorkerMan: master process start_file=' . self::$_startFile); @@ -615,7 +618,7 @@ protected static function displayUI() $start_file = $argv[0]; self::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n\n"); } else { - self::safeEcho("Press Ctrl-C to quit. Start success.\n"); + self::safeEcho("Press Ctrl+C to quit. Start success.\n"); } } @@ -689,9 +692,15 @@ protected static function parseCommand() // Sleep 1 second. sleep(1); // Clear terminal. - echo chr(27).chr(91).chr(72).chr(27).chr(91).chr(50).chr(74); + if ($command2 === '-d') { + echo "\33[H\33[2J\33(B\33[m"; + } // Echo status data. echo self::formatStatusData(); + if ($command2 !== '-d') { + exit(0); + } + echo "\nPress Ctrl+C to quit.\n\n"; } exit(0); case 'connections': From 78869fec16391b727dcfb848d1ed66f70b0de3ef Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 17:31:06 +0800 Subject: [PATCH 0165/1216] add graceful stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “php file.php stop -g” will stop process when all connections closed. This is not conflict with original function. --- Worker.php | 64 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index 139740aa5..ca68edc14 100644 --- a/Worker.php +++ b/Worker.php @@ -419,6 +419,13 @@ class Worker 'unix' => 'unix', 'ssl' => 'tcp' ); + + /** + * Graceful stop or not. + * + * @var string + */ + protected static $_gracefulStop = false; /** * Run all worker instances. @@ -716,9 +723,16 @@ protected static function parseCommand() exit(0); case 'restart': case 'stop': + if($command2 === '-g'){ + self::$_gracefulStop = true; + $sig = SIGTERM; + }else{ + self::$_gracefulStop = false; + $sig = SIGINT; + } self::log("Workerman[$start_file] is stoping ..."); // Send stop signal to master process. - $master_pid && posix_kill($master_pid, SIGINT); + $master_pid && posix_kill($master_pid, $sig); // Timeout. $timeout = 5; $start_time = time(); @@ -727,7 +741,7 @@ protected static function parseCommand() $master_is_alive = $master_pid && posix_kill($master_pid, 0); if ($master_is_alive) { // Timeout? - if (time() - $start_time >= $timeout) { + if (!self::$_gracefulStop && time() - $start_time >= $timeout) { self::log("Workerman[$start_file] stop fail"); exit; } @@ -821,6 +835,8 @@ protected static function installSignal() { // stop pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false); + // graceful stop + pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); // reload pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); // status @@ -840,12 +856,16 @@ protected static function reinstallSignal() { // uninstall stop signal handler pcntl_signal(SIGINT, SIG_IGN, false); + // uninstall graceful stop signal handler + pcntl_signal(SIGTERM, SIG_IGN, false); // uninstall reload signal handler pcntl_signal(SIGUSR1, SIG_IGN, false); // uninstall status signal handler pcntl_signal(SIGUSR2, SIG_IGN, false); // reinstall stop signal handler self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + // reinstall graceful stop signal handler + self::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall reload signal handler self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall status signal handler @@ -864,8 +884,13 @@ public static function signalHandler($signal) switch ($signal) { // Stop. case SIGINT: + self::$_gracefulStop = false; self::stopAll(); break; + // Graceful stop. + case SIGTERM: + self::$_gracefulStop = true; + self::stopAll(); // Reload. case SIGUSR1: self::$_pidsToRestart = self::getAllWorkerPids(); @@ -1318,9 +1343,16 @@ public static function stopAll() self::log("Workerman[" . basename(self::$_startFile) . "] Stopping ..."); $worker_pid_array = self::getAllWorkerPids(); // Send stop signal to all child processes. + if(self::$_gracefulStop){ + $sig = SIGTERM; + }else{ + $sig = SIGINT; + } foreach ($worker_pid_array as $worker_pid) { - posix_kill($worker_pid, SIGINT); - Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); + posix_kill($worker_pid, $sig); + if(!self::$_gracefulStop){ + Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); + } } // Remove statistics file. if (is_file(self::$_statisticsFile)) { @@ -1332,10 +1364,30 @@ public static function stopAll() foreach (self::$_workers as $worker) { $worker->stop(); } - self::$globalEvent->destroy(); - exit(0); + if(!self::$_gracefulStop) { + self::$globalEvent->destroy(); + exit(0); + } } } + + /** + * Get process status. + * + * @return number + */ + public static function getStatus(){ + return self::$_status; + } + + /** + * If stop gracefully. + * + * @return number + */ + public static function getGracefulStop(){ + return self::$_gracefulStop; + } /** * Write statistics data to disk. From b04d5886b66d38c56dffcc825c75f96473b48532 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 17:43:00 +0800 Subject: [PATCH 0166/1216] add graceful stop --- Connection/TcpConnection.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 581340a51..72973110e 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -874,6 +874,19 @@ public function destroy() */ public function __destruct() { + static $mod; self::$statistics['connection_count']--; + if(Worker::getGracefulStop() && Worker::getStatus() === Worker::STATUS_SHUTDOWN){ + if(!isset($mod)){ + $mod=round((self::$statistics['connection_count']+1)/3); + } + if(0 === self::$statistics['connection_count']%$mod){ + Worker::log('worker('.posix_getpid().') remains '.self::$statistics['connection_count'].' connection(s)'."\r"); + } + if(0 === self::$statistics['connection_count']){ + Worker::$globalEvent->destroy(); + exit(0); + } + } } } From 848166495fbe26628e457608ab87a2759f7c7280 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 18:07:45 +0800 Subject: [PATCH 0167/1216] fix break bug --- Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Worker.php b/Worker.php index ca68edc14..0f8306ac5 100644 --- a/Worker.php +++ b/Worker.php @@ -891,6 +891,7 @@ public static function signalHandler($signal) case SIGTERM: self::$_gracefulStop = true; self::stopAll(); + break; // Reload. case SIGUSR1: self::$_pidsToRestart = self::getAllWorkerPids(); From 77465f735307a03a8fd54044326d9cc3e8dbbb85 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 18:23:33 +0800 Subject: [PATCH 0168/1216] update graceful stop log --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 72973110e..6b7fb0728 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -881,7 +881,7 @@ public function __destruct() $mod=round((self::$statistics['connection_count']+1)/3); } if(0 === self::$statistics['connection_count']%$mod){ - Worker::log('worker('.posix_getpid().') remains '.self::$statistics['connection_count'].' connection(s)'."\r"); + Worker::log('worker('.posix_getpid().') remains '.self::$statistics['connection_count'].' connection(s)'); } if(0 === self::$statistics['connection_count']){ Worker::$globalEvent->destroy(); From d3df9f5ff395cb50d032a9e150f600080390ecaa Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 18:33:35 +0800 Subject: [PATCH 0169/1216] Adjust code format --- Worker.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 0f8306ac5..4d852d45c 100644 --- a/Worker.php +++ b/Worker.php @@ -1377,7 +1377,8 @@ public static function stopAll() * * @return number */ - public static function getStatus(){ + public static function getStatus() + { return self::$_status; } @@ -1386,7 +1387,8 @@ public static function getStatus(){ * * @return number */ - public static function getGracefulStop(){ + public static function getGracefulStop() + { return self::$_gracefulStop; } From e7cdd124194a667e44b0096da5c2be5da236ce65 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 20:51:20 +0800 Subject: [PATCH 0170/1216] Add graceful reload functionality useing SIGQUIT. --- Worker.php | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index 4d852d45c..15d744612 100644 --- a/Worker.php +++ b/Worker.php @@ -761,7 +761,12 @@ protected static function parseCommand() } break; case 'reload': - posix_kill($master_pid, SIGUSR1); + if($command2 === '-g'){ + $sig = SIGQUIT; + }else{ + $sig = SIGUSR1; + } + posix_kill($master_pid, $sig); self::log("Workerman[$start_file] reload"); exit; default : @@ -839,6 +844,8 @@ protected static function installSignal() pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); // reload pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); + // graceful reload + pcntl_signal(SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); // status pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); // connection status @@ -860,14 +867,18 @@ protected static function reinstallSignal() pcntl_signal(SIGTERM, SIG_IGN, false); // uninstall reload signal handler pcntl_signal(SIGUSR1, SIG_IGN, false); - // uninstall status signal handler + // uninstall graceful reload signal handler + pcntl_signal(SIGQUIT, SIG_IGN, false); + // uninstall status signal handler pcntl_signal(SIGUSR2, SIG_IGN, false); // reinstall stop signal handler self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful stop signal handler self::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); - // reinstall reload signal handler + // reinstall reload signal handler self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + // reinstall graceful reload signal handler + self::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall status signal handler self::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall connection status signal handler @@ -893,7 +904,13 @@ public static function signalHandler($signal) self::stopAll(); break; // Reload. + case SIGQUIT: case SIGUSR1: + if($signal === SIGQUIT){ + self::$_gracefulStop = true; + }else{ + self::$_gracefulStop = false; + } self::$_pidsToRestart = self::getAllWorkerPids(); self::reload(); break; @@ -1275,6 +1292,12 @@ protected static function reload() self::initId(); } } + + if(self::$_gracefulStop){ + $sig = SIGQUIT; + }else{ + $sig = SIGUSR1; + } // Send reload signal to all child processes. $reloadable_pid_array = array(); @@ -1287,7 +1310,7 @@ protected static function reload() } else { foreach ($worker_pid_array as $pid) { // Send reload signal to a worker process which reloadable is false. - posix_kill($pid, SIGUSR1); + posix_kill($pid, $sig); } } } @@ -1305,7 +1328,7 @@ protected static function reload() // Continue reload. $one_worker_pid = current(self::$_pidsToRestart); // Send reload signal to a worker process. - posix_kill($one_worker_pid, SIGUSR1); + posix_kill($one_worker_pid, $sig); // If the process does not exit after self::KILL_WORKER_TIMER_TIME seconds try to kill it. Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); } // For child processes. @@ -1940,4 +1963,4 @@ public function acceptUdpConnection($socket) } return true; } -} +} \ No newline at end of file From 7822308789f4bfcbaa3866a1a7610a0b7c57b089 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 21:03:19 +0800 Subject: [PATCH 0171/1216] Fix force kill when reloading and timeout reached. --- Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 15d744612..3fd55ce38 100644 --- a/Worker.php +++ b/Worker.php @@ -1330,7 +1330,9 @@ protected static function reload() // Send reload signal to a worker process. posix_kill($one_worker_pid, $sig); // If the process does not exit after self::KILL_WORKER_TIMER_TIME seconds try to kill it. - Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); + if(!self::$_gracefulStop){ + Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); + } } // For child processes. else { reset(self::$_workers); From f40eccd3c1c700196c216752d8e3cf609a55cd77 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 13 Oct 2017 21:10:10 +0800 Subject: [PATCH 0172/1216] Fix logging twice when reload on command line. --- Worker.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Worker.php b/Worker.php index 3fd55ce38..f40c8adca 100644 --- a/Worker.php +++ b/Worker.php @@ -767,7 +767,6 @@ protected static function parseCommand() $sig = SIGUSR1; } posix_kill($master_pid, $sig); - self::log("Workerman[$start_file] reload"); exit; default : exit($usage); From b06660e00acac602b445ce0065694c1e921d4261 Mon Sep 17 00:00:00 2001 From: codekissyoung Date: Sat, 14 Oct 2017 22:35:00 -0500 Subject: [PATCH 0173/1216] unlisten method start newline --- Worker.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index f40c8adca..f7ebd3eb5 100644 --- a/Worker.php +++ b/Worker.php @@ -1788,7 +1788,8 @@ public function listen() * * @return void */ - public function unlisten() { + public function unlisten() + { if (self::$globalEvent && $this->_mainSocket) { self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); $this->_pauseListen = true; @@ -1964,4 +1965,4 @@ public function acceptUdpConnection($socket) } return true; } -} \ No newline at end of file +} From 72bbd4b9afa62ac7b04020522d3408af25f227ed Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 15 Oct 2017 07:27:16 -0500 Subject: [PATCH 0174/1216] Fix #227 --- Connection/TcpConnection.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6b7fb0728..ba7ca760f 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -876,14 +876,16 @@ public function __destruct() { static $mod; self::$statistics['connection_count']--; - if(Worker::getGracefulStop() && Worker::getStatus() === Worker::STATUS_SHUTDOWN){ - if(!isset($mod)){ - $mod=round((self::$statistics['connection_count']+1)/3); + if (Worker::getGracefulStop()) { + if (!isset($mod)) { + $mod = ceil((self::$statistics['connection_count'] + 1) / 3); } - if(0 === self::$statistics['connection_count']%$mod){ - Worker::log('worker('.posix_getpid().') remains '.self::$statistics['connection_count'].' connection(s)'); + + if (0 === self::$statistics['connection_count'] % $mod) { + Worker::log('worker[' . posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } - if(0 === self::$statistics['connection_count']){ + + if(0 === self::$statistics['connection_count']) { Worker::$globalEvent->destroy(); exit(0); } From 94d6140525e6ac402f1b383aaeaa8c4964702285 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 15 Oct 2017 07:28:52 -0500 Subject: [PATCH 0175/1216] Fix #227 --- Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index f7ebd3eb5..78fdf1c93 100644 --- a/Worker.php +++ b/Worker.php @@ -1368,9 +1368,9 @@ public static function stopAll() self::log("Workerman[" . basename(self::$_startFile) . "] Stopping ..."); $worker_pid_array = self::getAllWorkerPids(); // Send stop signal to all child processes. - if(self::$_gracefulStop){ + if (self::$_gracefulStop) { $sig = SIGTERM; - }else{ + } else { $sig = SIGINT; } foreach ($worker_pid_array as $worker_pid) { @@ -1389,7 +1389,7 @@ public static function stopAll() foreach (self::$_workers as $worker) { $worker->stop(); } - if(!self::$_gracefulStop) { + if(!self::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { self::$globalEvent->destroy(); exit(0); } @@ -1409,7 +1409,7 @@ public static function getStatus() /** * If stop gracefully. * - * @return number + * @return boolean */ public static function getGracefulStop() { From 916f6d683377ff9c8e0d40c8fa7307517f730336 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 15 Oct 2017 09:09:18 -0500 Subject: [PATCH 0176/1216] Add pauseAccept resumeAccept methods for worker --- Worker.php | 108 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/Worker.php b/Worker.php index 78fdf1c93..be3e21430 100644 --- a/Worker.php +++ b/Worker.php @@ -223,13 +223,13 @@ class Worker * @var string */ protected $_autoloadRootPath = ''; - + /** - * Pause listening or not. + * Pause accept new connections or not. * * @var string */ - protected $_pauseListen = false; + protected $_pauseAccept = false; /** * Daemonize. @@ -419,7 +419,7 @@ class Worker 'unix' => 'unix', 'ssl' => 'tcp' ); - + /** * Graceful stop or not. * @@ -610,14 +610,14 @@ protected static function displayUI() self::safeEcho('Workerman version:'. Worker::VERSION. " PHP version:". PHP_VERSION. "\n"); self::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"); self::safeEcho("\033[47;30muser\033[0m". str_pad('', - self::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', - self::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', - self::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); + self::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', + self::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', + self::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); foreach (self::$_workers as $worker) { self::safeEcho(str_pad($worker->user, self::$_maxUserNameLength + 2). str_pad($worker->name, - self::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), - self::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); + self::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), + self::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); } self::safeEcho("----------------------------------------------------------------\n"); if (self::$daemonize) { @@ -723,14 +723,15 @@ protected static function parseCommand() exit(0); case 'restart': case 'stop': - if($command2 === '-g'){ + if ($command2 === '-g') { self::$_gracefulStop = true; $sig = SIGTERM; - }else{ + self::log("Workerman[$start_file] is gracefully stoping ..."); + } else { self::$_gracefulStop = false; $sig = SIGINT; + self::log("Workerman[$start_file] is stoping ..."); } - self::log("Workerman[$start_file] is stoping ..."); // Send stop signal to master process. $master_pid && posix_kill($master_pid, $sig); // Timeout. @@ -1291,10 +1292,10 @@ protected static function reload() self::initId(); } } - - if(self::$_gracefulStop){ + + if (self::$_gracefulStop) { $sig = SIGQUIT; - }else{ + } else { $sig = SIGUSR1; } @@ -1365,7 +1366,7 @@ public static function stopAll() self::$_status = self::STATUS_SHUTDOWN; // For master process. if (self::$_masterPid === posix_getpid()) { - self::log("Workerman[" . basename(self::$_startFile) . "] Stopping ..."); + self::log("Workerman[" . basename(self::$_startFile) . "] stopping ..."); $worker_pid_array = self::getAllWorkerPids(); // Send stop signal to all child processes. if (self::$_gracefulStop) { @@ -1389,13 +1390,13 @@ public static function stopAll() foreach (self::$_workers as $worker) { $worker->stop(); } - if(!self::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { + if (!self::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { self::$globalEvent->destroy(); exit(0); } } } - + /** * Get process status. * @@ -1405,7 +1406,7 @@ public static function getStatus() { return self::$_status; } - + /** * If stop gracefully. * @@ -1690,12 +1691,9 @@ public function __construct($socket_name = '', $context_option = array()) } $this->_context = stream_context_create($context_option); } - - // Set an empty onMessage callback. - $this->onMessage = function () { - }; } + /** * Listen. * @@ -1771,16 +1769,7 @@ public function listen() stream_set_blocking($this->_mainSocket, 0); } - // Register a listener to be notified when server socket is ready to read. - if (self::$globalEvent || $this->_pauseListen) { - if ($this->transport !== 'udp') { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); - } else { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, - array($this, 'acceptUdpConnection')); - } - $this->_pauseListen = false; - } + $this->resumeAccept(); } /** @@ -1788,11 +1777,43 @@ public function listen() * * @return void */ - public function unlisten() + public function unlisten() { + $this->pauseAccept(); + if ($this->_mainSocket) { + @fclose($this->_mainSocket); + $this->_mainSocket = null; + } + } + + /** + * Pause accept new connections. + * + * @return void + */ + public function pauseAccept() { - if (self::$globalEvent && $this->_mainSocket) { + if (self::$globalEvent && $this->_mainSocket && false === $this->_pauseAccept) { self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); - $this->_pauseListen = true; + $this->_pauseAccept = true; + } + } + + /** + * Resume accept new connections. + * + * @return void + */ + public function resumeAccept() + { + // Register a listener to be notified when server socket is ready to read. + if (self::$globalEvent && $this->_pauseAccept && $this->_mainSocket) { + if ($this->transport !== 'udp') { + self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); + } else { + self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, + array($this, 'acceptUdpConnection')); + } + $this->_pauseAccept = false; } } @@ -1844,6 +1865,11 @@ public function run() // Init Timer. Timer::init(self::$globalEvent); + // Set an empty onMessage callback. + if (empty($this->onMessage)) { + $this->onMessage = function () {}; + } + // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { @@ -1886,6 +1912,16 @@ public function stop() } // Remove listener for server socket. $this->unlisten(); + // Close all connections for the worker. + if (!self::$_gracefulStop) { + foreach ($this->connections as $connection) { + $connection->close(); + } + } + // Clear callback. + $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; + // Remove worker instance from self::$_workers. + unset(self::$_workers[$this->workerId]); } /** From a32e2defd8f2d38e86245f2eaaae2b3cdb84ecd5 Mon Sep 17 00:00:00 2001 From: codekissyoung Date: Tue, 17 Oct 2017 01:56:30 -0500 Subject: [PATCH 0177/1216] fix wrong comments --- Connection/ConnectionInterface.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Connection/ConnectionInterface.php b/Connection/ConnectionInterface.php index f1a4f8fc1..5ddd2f827 100644 --- a/Connection/ConnectionInterface.php +++ b/Connection/ConnectionInterface.php @@ -81,21 +81,21 @@ abstract public function getRemotePort(); abstract public function getRemoteAddress(); /** - * Get remote IP. + * Get local IP. * * @return string */ abstract public function getLocalIp(); /** - * Get remote port. + * Get local port. * * @return int */ abstract public function getLocalPort(); /** - * Get remote address. + * Get local address. * * @return string */ From 5fbfbffaa2d2dbb2f0851a3fdba99e4a68f9f0bb Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Oct 2017 22:33:53 -0500 Subject: [PATCH 0178/1216] Update Worker.php --- Worker.php | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Worker.php b/Worker.php index be3e21430..164bdec59 100644 --- a/Worker.php +++ b/Worker.php @@ -229,7 +229,7 @@ class Worker * * @var string */ - protected $_pauseAccept = false; + protected $_pauseAccept = true; /** * Daemonize. @@ -1792,7 +1792,7 @@ public function unlisten() { */ public function pauseAccept() { - if (self::$globalEvent && $this->_mainSocket && false === $this->_pauseAccept) { + if (self::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) { self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); $this->_pauseAccept = true; } @@ -1806,7 +1806,7 @@ public function pauseAccept() public function resumeAccept() { // Register a listener to be notified when server socket is ready to read. - if (self::$globalEvent && $this->_pauseAccept && $this->_mainSocket) { + if (self::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { @@ -1847,16 +1847,7 @@ public function run() if (!self::$globalEvent) { $event_loop_class = self::getEventLoopName(); self::$globalEvent = new $event_loop_class; - // Register a listener to be notified when server socket is ready to read. - if ($this->_socketName) { - if ($this->transport !== 'udp') { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, - array($this, 'acceptConnection')); - } else { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, - array($this, 'acceptUdpConnection')); - } - } + $this->resumeAccept(); } // Reinstall signal. From 796c413d0ef42b44da2e9ff6756241ab76c90b9c Mon Sep 17 00:00:00 2001 From: Vitaliy Ponomarev Date: Thu, 19 Oct 2017 23:31:40 +0300 Subject: [PATCH 0179/1216] Adding support of custom functions within protocols. Adding support of WebSocket subprotocols for WebSocket client. Usage example: $worker->onWorkerStart = function() { $ws = new AsyncTcpConnection("ws://192.168.1.16:1884/"); $ws->WSSetProtocol('mqtt'); $ws->onWebSocketConnect = function($conn) { echo "WebSocketConnection is set, server protocol is: [".$conn->WSGetServerProtocol()."]\n"; }; --- Connection/TcpConnection.php | 25 +++++++++++++++++++++++++ Protocols/Ws.php | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index ba7ca760f..200894ebc 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -254,6 +254,31 @@ class TcpConnection extends ConnectionInterface self::STATUS_CLOSED => 'CLOSED', ); + + /** + * Adding support of custom functions within protocols + * + * @param string $name + * @param array $arguments + */ + public function __call($name, $arguments) { + // Try to emit custom function within protocol + if (method_exists($this->protocol, $name)) { + try { + return call_user_func(array($this->protocol, $name), $this, $arguments); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } else { + trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR); + } + + } + /** * Construct. * diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 43605f36b..99fcc1d95 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -374,6 +374,7 @@ public static function sendHandshake($connection) "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". + (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). "Sec-WebSocket-Version: 13\r\n". "Sec-WebSocket-Key: " . base64_encode(md5(mt_rand(), true)) . "\r\n\r\n"; $connection->send($header, true); @@ -395,6 +396,16 @@ public static function dealHandshake($buffer, $connection) $pos = strpos($buffer, "\r\n\r\n"); if ($pos) { // handshake complete + + // Get WebSocket subprotocol (if specified by server) + $header = explode("\r\n", substr($buffer, 0, $pos)); + foreach ($header as $hrow) { + if (preg_match("#^(.+?)\:(.+?)$#", $hrow, $m) && ($m[1] == "Sec-WebSocket-Protocol")) { + $connection->WSServerProtocol = trim($m[2]); + } + + } + $connection->handshakeStep = 2; $handshake_response_length = $pos + 4; // Try to emit onWebSocketConnect callback. @@ -430,4 +441,13 @@ public static function dealHandshake($buffer, $connection) } return 0; } + + public static function WSSetProtocol($connection, $params) { + $connection->WSClientProtocol = $params[0]; + } + + public static function WSGetServerProtocol($connection) { + return (property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null); + } + } From 0828af6cb231a86fd183ffc8e1a51720a7019491 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 23 Oct 2017 09:38:24 -0500 Subject: [PATCH 0180/1216] Fix unix socket connect --- Connection/AsyncTcpConnection.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e848bfbd8..0b3f915aa 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -174,13 +174,18 @@ public function connect() } $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = microtime(true); - // Open socket connection asynchronously. - if ($this->_contextOption) { - $context = stream_context_create($this->_contextOption); - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, - STREAM_CLIENT_ASYNC_CONNECT, $context); + if ($this->transport !== 'unix') { + // Open socket connection asynchronously. + if ($this->_contextOption) { + $context = stream_context_create($this->_contextOption); + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", + $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); + } else { + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", + $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); + } } else { - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, + $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. From c8ebcffdd0f4abdb3041549ff1dd4c0a124d8daa Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Oct 2017 00:17:31 -0500 Subject: [PATCH 0181/1216] Update Timer.php --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index 4bd4ac5af..f87a3f523 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -75,7 +75,7 @@ public static function signalHandle() * Add a timer. * * @param int $time_interval - * @param callback $func + * @param callable $func * @param mixed $args * @param bool $persistent * @return int/false From 51b314e80b9a1473cd0346eb55671c11729490e9 Mon Sep 17 00:00:00 2001 From: Ares Date: Mon, 30 Oct 2017 10:17:42 +0800 Subject: [PATCH 0182/1216] Add .DS_Store to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9b668caef..f3f9e18c5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ logs .buildpath .project .settings -.idea \ No newline at end of file +.idea +.DS_Store From 3660eb5b887e4230285e4d563922ab4f85a16176 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Nov 2017 00:50:07 -0500 Subject: [PATCH 0183/1216] For #238 --- Worker.php | 536 ++++++++++++++++++++++++++--------------------------- 1 file changed, 268 insertions(+), 268 deletions(-) diff --git a/Worker.php b/Worker.php index 164bdec59..22dac8f46 100644 --- a/Worker.php +++ b/Worker.php @@ -434,17 +434,17 @@ class Worker */ public static function runAll() { - self::checkSapiEnv(); - self::init(); - self::parseCommand(); - self::daemonize(); - self::initWorkers(); - self::installSignal(); - self::saveMasterPid(); - self::displayUI(); - self::forkWorkers(); - self::resetStd(); - self::monitorWorkers(); + static::checkSapiEnv(); + static::init(); + static::parseCommand(); + static::daemonize(); + static::initWorkers(); + static::installSignal(); + static::saveMasterPid(); + static::displayUI(); + static::forkWorkers(); + static::resetStd(); + static::monitorWorkers(); } /** @@ -469,38 +469,38 @@ protected static function init() { // Start file. $backtrace = debug_backtrace(); - self::$_startFile = $backtrace[count($backtrace) - 1]['file']; + static::$_startFile = $backtrace[count($backtrace) - 1]['file']; - $unique_prefix = str_replace('/', '_', self::$_startFile); + $unique_prefix = str_replace('/', '_', static::$_startFile); // Pid file. - if (empty(self::$pidFile)) { - self::$pidFile = __DIR__ . "/../$unique_prefix.pid"; + if (empty(static::$pidFile)) { + static::$pidFile = __DIR__ . "/../$unique_prefix.pid"; } // Log file. - if (empty(self::$logFile)) { - self::$logFile = __DIR__ . '/../workerman.log'; + if (empty(static::$logFile)) { + static::$logFile = __DIR__ . '/../workerman.log'; } - $log_file = (string)self::$logFile; + $log_file = (string)static::$logFile; if (!is_file($log_file)) { touch($log_file); chmod($log_file, 0622); } // State. - self::$_status = self::STATUS_STARTING; + static::$_status = static::STATUS_STARTING; // For statistics. - self::$_globalStatistics['start_timestamp'] = time(); - self::$_statisticsFile = sys_get_temp_dir() . "/$unique_prefix.status"; + static::$_globalStatistics['start_timestamp'] = time(); + static::$_statisticsFile = sys_get_temp_dir() . "/$unique_prefix.status"; // Process title. - self::setProcessTitle('WorkerMan: master process start_file=' . self::$_startFile); + static::setProcessTitle('WorkerMan: master process start_file=' . static::$_startFile); // Init data for worker id. - self::initId(); + static::initId(); // Timer init. Timer::init(); @@ -513,7 +513,7 @@ protected static function init() */ protected static function initWorkers() { - foreach (self::$_workers as $worker) { + foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { $worker->name = 'none'; @@ -521,29 +521,29 @@ protected static function initWorkers() // Get maximum length of worker name. $worker_name_length = strlen($worker->name); - if (self::$_maxWorkerNameLength < $worker_name_length) { - self::$_maxWorkerNameLength = $worker_name_length; + if (static::$_maxWorkerNameLength < $worker_name_length) { + static::$_maxWorkerNameLength = $worker_name_length; } // Get maximum length of socket name. $socket_name_length = strlen($worker->getSocketName()); - if (self::$_maxSocketNameLength < $socket_name_length) { - self::$_maxSocketNameLength = $socket_name_length; + if (static::$_maxSocketNameLength < $socket_name_length) { + static::$_maxSocketNameLength = $socket_name_length; } // Get unix user of the worker process. if (empty($worker->user)) { - $worker->user = self::getCurrentUser(); + $worker->user = static::getCurrentUser(); } else { - if (posix_getuid() !== 0 && $worker->user != self::getCurrentUser()) { - self::log('Warning: You must have the root privileges to change uid and gid.'); + if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { + static::log('Warning: You must have the root privileges to change uid and gid.'); } } // Get maximum length of unix user name. $user_name_length = strlen($worker->user); - if (self::$_maxUserNameLength < $user_name_length) { - self::$_maxUserNameLength = $user_name_length; + if (static::$_maxUserNameLength < $user_name_length) { + static::$_maxUserNameLength = $user_name_length; } // Listen. @@ -560,7 +560,7 @@ protected static function initWorkers() */ public static function getAllWorkers() { - return self::$_workers; + return static::$_workers; } /** @@ -570,7 +570,7 @@ public static function getAllWorkers() */ public static function getEventLoop() { - return self::$globalEvent; + return static::$globalEvent; } /** @@ -579,12 +579,12 @@ public static function getEventLoop() */ protected static function initId() { - foreach (self::$_workers as $worker_id => $worker) { + foreach (static::$_workers as $worker_id => $worker) { $new_id_map = array(); for($key = 0; $key < $worker->count; $key++) { - $new_id_map[$key] = isset(self::$_idMap[$worker_id][$key]) ? self::$_idMap[$worker_id][$key] : 0; + $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; } - self::$_idMap[$worker_id] = $new_id_map; + static::$_idMap[$worker_id] = $new_id_map; } } @@ -606,26 +606,26 @@ protected static function getCurrentUser() */ protected static function displayUI() { - self::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\n\033[0m"); - self::safeEcho('Workerman version:'. Worker::VERSION. " PHP version:". PHP_VERSION. "\n"); - self::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"); - self::safeEcho("\033[47;30muser\033[0m". str_pad('', - self::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', - self::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', - self::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); - - foreach (self::$_workers as $worker) { - self::safeEcho(str_pad($worker->user, self::$_maxUserNameLength + 2). str_pad($worker->name, - self::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), - self::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); + static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\n\033[0m"); + static::safeEcho('Workerman version:'. Worker::VERSION. " PHP version:". PHP_VERSION. "\n"); + static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"); + static::safeEcho("\033[47;30muser\033[0m". str_pad('', + static::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', + static::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', + static::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); + + foreach (static::$_workers as $worker) { + static::safeEcho(str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, + static::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), + static::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); } - self::safeEcho("----------------------------------------------------------------\n"); - if (self::$daemonize) { + static::safeEcho("----------------------------------------------------------------\n"); + if (static::$daemonize) { global $argv; $start_file = $argv[0]; - self::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n\n"); + static::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n\n"); } else { - self::safeEcho("Press Ctrl+C to quit. Start success.\n"); + static::safeEcho("Press Ctrl+C to quit. Start success.\n"); } } @@ -666,19 +666,19 @@ protected static function parseCommand() $mode = 'in DEBUG mode'; } } - self::log("Workerman[$start_file] $command $mode"); + static::log("Workerman[$start_file] $command $mode"); // Get master process PID. - $master_pid = is_file(self::$pidFile) ? file_get_contents(self::$pidFile) : 0; + $master_pid = is_file(static::$pidFile) ? file_get_contents(static::$pidFile) : 0; $master_is_alive = $master_pid && @posix_kill($master_pid, 0) && posix_getpid() != $master_pid; // Master is still alive? if ($master_is_alive) { if ($command === 'start') { - self::log("Workerman[$start_file] already running"); + static::log("Workerman[$start_file] already running"); exit; } } elseif ($command !== 'start' && $command !== 'restart') { - self::log("Workerman[$start_file] not run"); + static::log("Workerman[$start_file] not run"); exit; } @@ -691,8 +691,8 @@ protected static function parseCommand() break; case 'status': while (1) { - if (is_file(self::$_statisticsFile)) { - @unlink(self::$_statisticsFile); + if (is_file(static::$_statisticsFile)) { + @unlink(static::$_statisticsFile); } // Master process will send SIGUSR2 signal to all child processes. posix_kill($master_pid, SIGUSR2); @@ -703,7 +703,7 @@ protected static function parseCommand() echo "\33[H\33[2J\33(B\33[m"; } // Echo status data. - echo self::formatStatusData(); + echo static::formatStatusData(); if ($command2 !== '-d') { exit(0); } @@ -711,26 +711,26 @@ protected static function parseCommand() } exit(0); case 'connections': - if (is_file(self::$_statisticsFile)) { - @unlink(self::$_statisticsFile); + if (is_file(static::$_statisticsFile)) { + @unlink(static::$_statisticsFile); } // Master process will send SIGIO signal to all child processes. posix_kill($master_pid, SIGIO); // Waiting amoment. usleep(500000); // Display statisitcs data from a disk file. - @readfile(self::$_statisticsFile); + @readfile(static::$_statisticsFile); exit(0); case 'restart': case 'stop': if ($command2 === '-g') { - self::$_gracefulStop = true; + static::$_gracefulStop = true; $sig = SIGTERM; - self::log("Workerman[$start_file] is gracefully stoping ..."); + static::log("Workerman[$start_file] is gracefully stoping ..."); } else { - self::$_gracefulStop = false; + static::$_gracefulStop = false; $sig = SIGINT; - self::log("Workerman[$start_file] is stoping ..."); + static::log("Workerman[$start_file] is stoping ..."); } // Send stop signal to master process. $master_pid && posix_kill($master_pid, $sig); @@ -742,8 +742,8 @@ protected static function parseCommand() $master_is_alive = $master_pid && posix_kill($master_pid, 0); if ($master_is_alive) { // Timeout? - if (!self::$_gracefulStop && time() - $start_time >= $timeout) { - self::log("Workerman[$start_file] stop fail"); + if (!static::$_gracefulStop && time() - $start_time >= $timeout) { + static::log("Workerman[$start_file] stop fail"); exit; } // Waiting amoment. @@ -751,7 +751,7 @@ protected static function parseCommand() continue; } // Stop success. - self::log("Workerman[$start_file] stop success"); + static::log("Workerman[$start_file] stop success"); if ($command === 'stop') { exit(0); } @@ -782,7 +782,7 @@ protected static function parseCommand() protected static function formatStatusData() { static $total_request_cache = array(); - $info = @file(self::$_statisticsFile, FILE_IGNORE_NEW_LINES); + $info = @file(static::$_statisticsFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } @@ -812,8 +812,8 @@ protected static function formatStatusData() foreach($worker_info as $pid => $info) { if (!isset($data_waiting_sort[$pid])) { $status_str .= "$pid\t" . str_pad('N/A', 7) . " " - . str_pad($info['listen'], self::$_maxSocketNameLength) . " " - . str_pad($info['name'], self::$_maxWorkerNameLength) . " " + . str_pad($info['listen'], static::$_maxSocketNameLength) . " " + . str_pad($info['name'], static::$_maxWorkerNameLength) . " " . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; continue; @@ -872,17 +872,17 @@ protected static function reinstallSignal() // uninstall status signal handler pcntl_signal(SIGUSR2, SIG_IGN, false); // reinstall stop signal handler - self::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful stop signal handler - self::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall reload signal handler - self::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful reload signal handler - self::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall status signal handler - self::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall connection status signal handler - self::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); } /** @@ -895,32 +895,32 @@ public static function signalHandler($signal) switch ($signal) { // Stop. case SIGINT: - self::$_gracefulStop = false; - self::stopAll(); + static::$_gracefulStop = false; + static::stopAll(); break; // Graceful stop. case SIGTERM: - self::$_gracefulStop = true; - self::stopAll(); + static::$_gracefulStop = true; + static::stopAll(); break; // Reload. case SIGQUIT: case SIGUSR1: if($signal === SIGQUIT){ - self::$_gracefulStop = true; + static::$_gracefulStop = true; }else{ - self::$_gracefulStop = false; + static::$_gracefulStop = false; } - self::$_pidsToRestart = self::getAllWorkerPids(); - self::reload(); + static::$_pidsToRestart = static::getAllWorkerPids(); + static::reload(); break; // Show status. case SIGUSR2: - self::writeStatisticsToStatusFile(); + static::writeStatisticsToStatusFile(); break; // Show connection status. case SIGIO: - self::writeConnectionsStatisticsToStatusFile(); + static::writeConnectionsStatisticsToStatusFile(); break; } } @@ -932,7 +932,7 @@ public static function signalHandler($signal) */ protected static function daemonize() { - if (!self::$daemonize) { + if (!static::$daemonize) { return; } umask(0); @@ -961,19 +961,19 @@ protected static function daemonize() */ public static function resetStd() { - if (!self::$daemonize) { + if (!static::$daemonize) { return; } global $STDOUT, $STDERR; - $handle = fopen(self::$stdoutFile, "a"); + $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); @fclose(STDOUT); @fclose(STDERR); - $STDOUT = fopen(self::$stdoutFile, "a"); - $STDERR = fopen(self::$stdoutFile, "a"); + $STDOUT = fopen(static::$stdoutFile, "a"); + $STDERR = fopen(static::$stdoutFile, "a"); } else { - throw new Exception('can not open stdoutFile ' . self::$stdoutFile); + throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } } @@ -984,9 +984,9 @@ public static function resetStd() */ protected static function saveMasterPid() { - self::$_masterPid = posix_getpid(); - if (false === @file_put_contents(self::$pidFile, self::$_masterPid)) { - throw new Exception('can not save pid to ' . self::$pidFile); + static::$_masterPid = posix_getpid(); + if (false === @file_put_contents(static::$pidFile, static::$_masterPid)) { + throw new Exception('can not save pid to ' . static::$pidFile); } } @@ -997,12 +997,12 @@ protected static function saveMasterPid() */ protected static function getEventLoopName() { - if (self::$eventLoopClass) { - return self::$eventLoopClass; + if (static::$eventLoopClass) { + return static::$eventLoopClass; } $loop_name = ''; - foreach (self::$_availableEventLoops as $name=>$class) { + foreach (static::$_availableEventLoops as $name=>$class) { if (extension_loaded($name)) { $loop_name = $name; break; @@ -1013,22 +1013,22 @@ protected static function getEventLoopName() if (interface_exists('\React\EventLoop\LoopInterface')) { switch ($loop_name) { case 'libevent': - self::$eventLoopClass = '\Workerman\Events\React\LibEventLoop'; + static::$eventLoopClass = '\Workerman\Events\React\LibEventLoop'; break; case 'event': - self::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop'; + static::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop'; break; default : - self::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop'; + static::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop'; break; } } else { - self::$eventLoopClass = self::$_availableEventLoops[$loop_name]; + static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; } } else { - self::$eventLoopClass = interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; + static::$eventLoopClass = interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; } - return self::$eventLoopClass; + return static::$eventLoopClass; } /** @@ -1039,7 +1039,7 @@ protected static function getEventLoopName() protected static function getAllWorkerPids() { $pid_array = array(); - foreach (self::$_pidMap as $worker_pid_array) { + foreach (static::$_pidMap as $worker_pid_array) { foreach ($worker_pid_array as $worker_pid) { $pid_array[$worker_pid] = $worker_pid; } @@ -1054,19 +1054,19 @@ protected static function getAllWorkerPids() */ protected static function forkWorkers() { - foreach (self::$_workers as $worker) { - if (self::$_status === self::STATUS_STARTING) { + foreach (static::$_workers as $worker) { + if (static::$_status === static::STATUS_STARTING) { if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } $worker_name_length = strlen($worker->name); - if (self::$_maxWorkerNameLength < $worker_name_length) { - self::$_maxWorkerNameLength = $worker_name_length; + if (static::$_maxWorkerNameLength < $worker_name_length) { + static::$_maxWorkerNameLength = $worker_name_length; } } $worker->count = $worker->count <= 0 ? 1 : $worker->count; - while (count(self::$_pidMap[$worker->workerId]) < $worker->count) { + while (count(static::$_pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorker($worker); } } @@ -1081,32 +1081,32 @@ protected static function forkWorkers() protected static function forkOneWorker($worker) { // Get available worker id. - $id = self::getId($worker->workerId, 0); + $id = static::getId($worker->workerId, 0); if ($id === false) { return; } $pid = pcntl_fork(); // For master process. if ($pid > 0) { - self::$_pidMap[$worker->workerId][$pid] = $pid; - self::$_idMap[$worker->workerId][$id] = $pid; + static::$_pidMap[$worker->workerId][$pid] = $pid; + static::$_idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { if ($worker->reusePort) { $worker->listen(); } - if (self::$_status === self::STATUS_STARTING) { - self::resetStd(); + if (static::$_status === static::STATUS_STARTING) { + static::resetStd(); } - self::$_pidMap = array(); - self::$_workers = array($worker->workerId => $worker); + static::$_pidMap = array(); + static::$_workers = array($worker->workerId => $worker); Timer::delAll(); - self::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); + static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); $err = new Exception('event-loop exited'); - self::log($err); + static::log($err); exit(250); } else { throw new Exception("forkOneWorker fail"); @@ -1123,7 +1123,7 @@ protected static function forkOneWorker($worker) */ protected static function getId($worker_id, $pid) { - return array_search($pid, self::$_idMap[$worker_id]); + return array_search($pid, static::$_idMap[$worker_id]); } /** @@ -1136,7 +1136,7 @@ public function setUserAndGroup() // Get uid. $user_info = posix_getpwnam($this->user); if (!$user_info) { - self::log("Warning: User {$this->user} not exsits"); + static::log("Warning: User {$this->user} not exsits"); return; } $uid = $user_info['uid']; @@ -1144,7 +1144,7 @@ public function setUserAndGroup() if ($this->group) { $group_info = posix_getgrnam($this->group); if (!$group_info) { - self::log("Warning: Group {$this->group} not exsits"); + static::log("Warning: Group {$this->group} not exsits"); return; } $gid = $group_info['gid']; @@ -1155,7 +1155,7 @@ public function setUserAndGroup() // Set uid and gid. if ($uid != posix_getuid() || $gid != posix_getgid()) { if (!posix_setgid($gid) || !posix_initgroups($user_info['name'], $gid) || !posix_setuid($uid)) { - self::log("Warning: change gid or uid fail."); + static::log("Warning: change gid or uid fail."); } } } @@ -1184,7 +1184,7 @@ protected static function setProcessTitle($title) */ protected static function monitorWorkers() { - self::$_status = self::STATUS_RUNNING; + static::$_status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. pcntl_signal_dispatch(); @@ -1196,48 +1196,48 @@ protected static function monitorWorkers() // If a child has already exited. if ($pid > 0) { // Find out witch worker process exited. - foreach (self::$_pidMap as $worker_id => $worker_pid_array) { + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { if (isset($worker_pid_array[$pid])) { - $worker = self::$_workers[$worker_id]; + $worker = static::$_workers[$worker_id]; // Exit status. if ($status !== 0) { - self::log("worker[" . $worker->name . ":$pid] exit with status $status"); + static::log("worker[" . $worker->name . ":$pid] exit with status $status"); } // For Statistics. - if (!isset(self::$_globalStatistics['worker_exit_info'][$worker_id][$status])) { - self::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0; + if (!isset(static::$_globalStatistics['worker_exit_info'][$worker_id][$status])) { + static::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0; } - self::$_globalStatistics['worker_exit_info'][$worker_id][$status]++; + static::$_globalStatistics['worker_exit_info'][$worker_id][$status]++; // Clear process data. - unset(self::$_pidMap[$worker_id][$pid]); + unset(static::$_pidMap[$worker_id][$pid]); // Mark id is available. - $id = self::getId($worker_id, $pid); - self::$_idMap[$worker_id][$id] = 0; + $id = static::getId($worker_id, $pid); + static::$_idMap[$worker_id][$id] = 0; break; } } // Is still running state then fork a new worker process. - if (self::$_status !== self::STATUS_SHUTDOWN) { - self::forkWorkers(); + if (static::$_status !== static::STATUS_SHUTDOWN) { + static::forkWorkers(); // If reloading continue. - if (isset(self::$_pidsToRestart[$pid])) { - unset(self::$_pidsToRestart[$pid]); - self::reload(); + if (isset(static::$_pidsToRestart[$pid])) { + unset(static::$_pidsToRestart[$pid]); + static::reload(); } } else { // If shutdown state and all child processes exited then master process exit. - if (!self::getAllWorkerPids()) { - self::exitAndClearAll(); + if (!static::getAllWorkerPids()) { + static::exitAndClearAll(); } } } else { // If shutdown state and all child processes exited then master process exit. - if (self::$_status === self::STATUS_SHUTDOWN && !self::getAllWorkerPids()) { - self::exitAndClearAll(); + if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + static::exitAndClearAll(); } } } @@ -1250,17 +1250,17 @@ protected static function monitorWorkers() */ protected static function exitAndClearAll() { - foreach (self::$_workers as $worker) { + foreach (static::$_workers as $worker) { $socket_name = $worker->getSocketName(); if ($worker->transport === 'unix' && $socket_name) { list(, $address) = explode(':', $socket_name, 2); @unlink($address); } } - @unlink(self::$pidFile); - self::log("Workerman[" . basename(self::$_startFile) . "] has been stopped"); - if (self::$onMasterStop) { - call_user_func(self::$onMasterStop); + @unlink(static::$pidFile); + static::log("Workerman[" . basename(static::$_startFile) . "] has been stopped"); + if (static::$onMasterStop) { + call_user_func(static::$onMasterStop); } exit(0); } @@ -1273,27 +1273,27 @@ protected static function exitAndClearAll() protected static function reload() { // For master process. - if (self::$_masterPid === posix_getpid()) { + if (static::$_masterPid === posix_getpid()) { // Set reloading state. - if (self::$_status !== self::STATUS_RELOADING && self::$_status !== self::STATUS_SHUTDOWN) { - self::log("Workerman[" . basename(self::$_startFile) . "] reloading"); - self::$_status = self::STATUS_RELOADING; + if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) { + static::log("Workerman[" . basename(static::$_startFile) . "] reloading"); + static::$_status = static::STATUS_RELOADING; // Try to emit onMasterReload callback. - if (self::$onMasterReload) { + if (static::$onMasterReload) { try { - call_user_func(self::$onMasterReload); + call_user_func(static::$onMasterReload); } catch (\Exception $e) { - self::log($e); + static::log($e); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); exit(250); } - self::initId(); + static::initId(); } } - if (self::$_gracefulStop) { + if (static::$_gracefulStop) { $sig = SIGQUIT; } else { $sig = SIGUSR1; @@ -1301,8 +1301,8 @@ protected static function reload() // Send reload signal to all child processes. $reloadable_pid_array = array(); - foreach (self::$_pidMap as $worker_id => $worker_pid_array) { - $worker = self::$_workers[$worker_id]; + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + $worker = static::$_workers[$worker_id]; if ($worker->reloadable) { foreach ($worker_pid_array as $pid) { $reloadable_pid_array[$pid] = $pid; @@ -1316,42 +1316,42 @@ protected static function reload() } // Get all pids that are waiting reload. - self::$_pidsToRestart = array_intersect(self::$_pidsToRestart, $reloadable_pid_array); + static::$_pidsToRestart = array_intersect(static::$_pidsToRestart, $reloadable_pid_array); // Reload complete. - if (empty(self::$_pidsToRestart)) { - if (self::$_status !== self::STATUS_SHUTDOWN) { - self::$_status = self::STATUS_RUNNING; + if (empty(static::$_pidsToRestart)) { + if (static::$_status !== static::STATUS_SHUTDOWN) { + static::$_status = static::STATUS_RUNNING; } return; } // Continue reload. - $one_worker_pid = current(self::$_pidsToRestart); + $one_worker_pid = current(static::$_pidsToRestart); // Send reload signal to a worker process. posix_kill($one_worker_pid, $sig); - // If the process does not exit after self::KILL_WORKER_TIMER_TIME seconds try to kill it. - if(!self::$_gracefulStop){ - Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); + // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it. + if(!static::$_gracefulStop){ + Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); } } // For child processes. else { - reset(self::$_workers); - $worker = current(self::$_workers); + reset(static::$_workers); + $worker = current(static::$_workers); // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { try { call_user_func($worker->onWorkerReload, $worker); } catch (\Exception $e) { - self::log($e); + static::log($e); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); exit(250); } } if ($worker->reloadable) { - self::stopAll(); + static::stopAll(); } } } @@ -1363,35 +1363,35 @@ protected static function reload() */ public static function stopAll() { - self::$_status = self::STATUS_SHUTDOWN; + static::$_status = static::STATUS_SHUTDOWN; // For master process. - if (self::$_masterPid === posix_getpid()) { - self::log("Workerman[" . basename(self::$_startFile) . "] stopping ..."); - $worker_pid_array = self::getAllWorkerPids(); + if (static::$_masterPid === posix_getpid()) { + static::log("Workerman[" . basename(static::$_startFile) . "] stopping ..."); + $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. - if (self::$_gracefulStop) { + if (static::$_gracefulStop) { $sig = SIGTERM; } else { $sig = SIGINT; } foreach ($worker_pid_array as $worker_pid) { posix_kill($worker_pid, $sig); - if(!self::$_gracefulStop){ - Timer::add(self::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); + if(!static::$_gracefulStop){ + Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); } } // Remove statistics file. - if (is_file(self::$_statisticsFile)) { - @unlink(self::$_statisticsFile); + if (is_file(static::$_statisticsFile)) { + @unlink(static::$_statisticsFile); } } // For child processes. else { // Execute exit. - foreach (self::$_workers as $worker) { + foreach (static::$_workers as $worker) { $worker->stop(); } - if (!self::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { - self::$globalEvent->destroy(); + if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { + static::$globalEvent->destroy(); exit(0); } } @@ -1404,7 +1404,7 @@ public static function stopAll() */ public static function getStatus() { - return self::$_status; + return static::$_status; } /** @@ -1414,7 +1414,7 @@ public static function getStatus() */ public static function getGracefulStop() { - return self::$_gracefulStop; + return static::$_gracefulStop; } /** @@ -1425,58 +1425,58 @@ public static function getGracefulStop() protected static function writeStatisticsToStatusFile() { // For master process. - if (self::$_masterPid === posix_getpid()) { + if (static::$_masterPid === posix_getpid()) { $all_worker_info = array(); - foreach(self::$_pidMap as $worker_id => $pid_array) { + foreach(static::$_pidMap as $worker_id => $pid_array) { /** @var Worker $worker */ - $worker = self::$_workers[$worker_id]; + $worker = static::$_workers[$worker_id]; foreach($pid_array as $pid) { $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName()); } } - file_put_contents(self::$_statisticsFile, json_encode($all_worker_info)."\n", FILE_APPEND); + file_put_contents(static::$_statisticsFile, json_encode($all_worker_info)."\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); - file_put_contents(self::$_statisticsFile, + file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, + file_put_contents(static::$_statisticsFile, 'Workerman version:' . Worker::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', - self::$_globalStatistics['start_timestamp']) . ' run ' . floor((time() - self::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - self::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", + file_put_contents(static::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', + static::$_globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); $load_str = 'load average: ' . implode(", ", $loadavg); - file_put_contents(self::$_statisticsFile, - str_pad($load_str, 33) . 'event-loop:' . self::getEventLoopName() . "\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, - count(self::$_pidMap) . ' workers ' . count(self::getAllWorkerPids()) . " processes\n", + file_put_contents(static::$_statisticsFile, + str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); + file_put_contents(static::$_statisticsFile, + count(static::$_pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, - str_pad('worker_name', self::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); - foreach (self::$_pidMap as $worker_id => $worker_pid_array) { - $worker = self::$_workers[$worker_id]; - if (isset(self::$_globalStatistics['worker_exit_info'][$worker_id])) { - foreach (self::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { - file_put_contents(self::$_statisticsFile, - str_pad($worker->name, self::$_maxWorkerNameLength) . " " . str_pad($worker_exit_status, + file_put_contents(static::$_statisticsFile, + str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + $worker = static::$_workers[$worker_id]; + if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) { + foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { + file_put_contents(static::$_statisticsFile, + str_pad($worker->name, static::$_maxWorkerNameLength) . " " . str_pad($worker_exit_status, 16) . " $worker_exit_count\n", FILE_APPEND); } } else { - file_put_contents(self::$_statisticsFile, - str_pad($worker->name, self::$_maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n", + file_put_contents(static::$_statisticsFile, + str_pad($worker->name, static::$_maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n", FILE_APPEND); } } - file_put_contents(self::$_statisticsFile, + file_put_contents(static::$_statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, - "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', - self::$_maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " + file_put_contents(static::$_statisticsFile, + "pid\tmemory " . str_pad('listening', static::$_maxSocketNameLength) . " " . str_pad('worker_name', + static::$_maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . str_pad('total_request', 13) ." qps status\n", FILE_APPEND); - chmod(self::$_statisticsFile, 0722); + chmod(static::$_statisticsFile, 0722); - foreach (self::getAllWorkerPids() as $worker_pid) { + foreach (static::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGUSR2); } return; @@ -1484,16 +1484,16 @@ protected static function writeStatisticsToStatusFile() // For child processes. /** @var Worker $worker */ - $worker = current(self::$_workers); + $worker = current(static::$_workers); $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) - . " " . str_pad($worker->getSocketName(), self::$_maxSocketNameLength) . " " - . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), self::$_maxWorkerNameLength) + . " " . str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " + . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) . " "; $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], 9) - . " " . str_pad(self::$globalEvent->getTimerCount(), 7) + . " " . str_pad(static::$globalEvent->getTimerCount(), 7) . " " . str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - file_put_contents(self::$_statisticsFile, $worker_status_str, FILE_APPEND); + file_put_contents(static::$_statisticsFile, $worker_status_str, FILE_APPEND); } /** @@ -1504,11 +1504,11 @@ protected static function writeStatisticsToStatusFile() protected static function writeConnectionsStatisticsToStatusFile() { // For master process. - if (self::$_masterPid === posix_getpid()) { - file_put_contents(self::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(self::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); - chmod(self::$_statisticsFile, 0722); - foreach (self::getAllWorkerPids() as $worker_pid) { + if (static::$_masterPid === posix_getpid()) { + file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + chmod(static::$_statisticsFile, 0722); + foreach (static::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGIO); } return; @@ -1534,8 +1534,8 @@ protected static function writeConnectionsStatisticsToStatusFile() $pid = posix_getpid(); $str = ''; - reset(self::$_workers); - $current_worker = current(self::$_workers); + reset(static::$_workers); + $current_worker = current(static::$_workers); $default_worker_name = $current_worker->name; /** @var Worker $worker */ @@ -1570,7 +1570,7 @@ protected static function writeConnectionsStatisticsToStatusFile() . str_pad($state, 14) . ' ' . str_pad($local_address, 22) . ' ' . str_pad($remote_address, 22) ."\n"; } if ($str) { - file_put_contents(self::$_statisticsFile, $str, FILE_APPEND); + file_put_contents(static::$_statisticsFile, $str, FILE_APPEND); } } @@ -1581,7 +1581,7 @@ protected static function writeConnectionsStatisticsToStatusFile() */ public static function checkErrors() { - if (self::STATUS_SHUTDOWN != self::$_status) { + if (static::STATUS_SHUTDOWN != static::$_status) { $error_msg = 'Worker['. posix_getpid() .'] process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || @@ -1590,9 +1590,9 @@ public static function checkErrors() $errors['type'] === E_COMPILE_ERROR || $errors['type'] === E_RECOVERABLE_ERROR) ) { - $error_msg .= ' with ERROR: ' . self::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; + $error_msg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } - self::log($error_msg); + static::log($error_msg); } } @@ -1648,10 +1648,10 @@ protected static function getErrorType($type) public static function log($msg) { $msg = $msg . "\n"; - if (!self::$daemonize) { - self::safeEcho($msg); + if (!static::$daemonize) { + static::safeEcho($msg); } - file_put_contents((string)self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); + file_put_contents((string)static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** @@ -1676,8 +1676,8 @@ public function __construct($socket_name = '', $context_option = array()) { // Save all worker instances. $this->workerId = spl_object_hash($this); - self::$_workers[$this->workerId] = $this; - self::$_pidMap[$this->workerId] = array(); + static::$_workers[$this->workerId] = $this; + static::$_pidMap[$this->workerId] = array(); // Get autoload root path. $backtrace = debug_backtrace(); @@ -1687,7 +1687,7 @@ public function __construct($socket_name = '', $context_option = array()) if ($socket_name) { $this->_socketName = $socket_name; if (!isset($context_option['socket']['backlog'])) { - $context_option['socket']['backlog'] = self::DEFAULT_BACKLOG; + $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } $this->_context = stream_context_create($context_option); } @@ -1712,7 +1712,7 @@ public function listen() // Get the application layer communication protocol and listening address. list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. - if (!isset(self::$_builtinTransports[$scheme])) { + if (!isset(static::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { @@ -1722,14 +1722,14 @@ public function listen() } } - if (!isset(self::$_builtinTransports[$this->transport])) { + if (!isset(static::$_builtinTransports[$this->transport])) { throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); } } else { $this->transport = $scheme; } - $local_socket = self::$_builtinTransports[$this->transport] . ":" . $address; + $local_socket = static::$_builtinTransports[$this->transport] . ":" . $address; // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; @@ -1759,7 +1759,7 @@ public function listen() } // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && self::$_builtinTransports[$this->transport] === 'tcp') { + if (function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); @@ -1792,8 +1792,8 @@ public function unlisten() { */ public function pauseAccept() { - if (self::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) { - self::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); + if (static::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) { + static::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); $this->_pauseAccept = true; } } @@ -1806,11 +1806,11 @@ public function pauseAccept() public function resumeAccept() { // Register a listener to be notified when server socket is ready to read. - if (self::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) { + if (static::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) { if ($this->transport !== 'udp') { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); + static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { - self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, + static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } $this->_pauseAccept = false; @@ -1835,7 +1835,7 @@ public function getSocketName() public function run() { //Update process state. - self::$_status = self::STATUS_RUNNING; + static::$_status = static::STATUS_RUNNING; // Register shutdown function for checking errors. register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); @@ -1844,17 +1844,17 @@ public function run() Autoloader::setRootPath($this->_autoloadRootPath); // Create a global event loop. - if (!self::$globalEvent) { - $event_loop_class = self::getEventLoopName(); - self::$globalEvent = new $event_loop_class; + if (!static::$globalEvent) { + $event_loop_class = static::getEventLoopName(); + static::$globalEvent = new $event_loop_class; $this->resumeAccept(); } // Reinstall signal. - self::reinstallSignal(); + static::reinstallSignal(); // Init Timer. - Timer::init(self::$globalEvent); + Timer::init(static::$globalEvent); // Set an empty onMessage callback. if (empty($this->onMessage)) { @@ -1866,12 +1866,12 @@ public function run() try { call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { - self::log($e); + static::log($e); // Avoid rapid infinite loop exit. sleep(1); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); // Avoid rapid infinite loop exit. sleep(1); exit(250); @@ -1879,7 +1879,7 @@ public function run() } // Main loop. - self::$globalEvent->loop(); + static::$globalEvent->loop(); } /** @@ -1894,25 +1894,25 @@ public function stop() try { call_user_func($this->onWorkerStop, $this); } catch (\Exception $e) { - self::log($e); + static::log($e); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); exit(250); } } // Remove listener for server socket. $this->unlisten(); // Close all connections for the worker. - if (!self::$_gracefulStop) { + if (!static::$_gracefulStop) { foreach ($this->connections as $connection) { $connection->close(); } } // Clear callback. $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; - // Remove worker instance from self::$_workers. - unset(self::$_workers[$this->workerId]); + // Remove worker instance from static::$_workers. + unset(static::$_workers[$this->workerId]); } /** @@ -1947,10 +1947,10 @@ public function acceptConnection($socket) try { call_user_func($this->onConnect, $connection); } catch (\Exception $e) { - self::log($e); + static::log($e); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); exit(250); } } @@ -1964,7 +1964,7 @@ public function acceptConnection($socket) */ public function acceptUdpConnection($socket) { - $recv_buffer = stream_socket_recvfrom($socket, self::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + $recv_buffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); if (false === $recv_buffer || empty($remote_address)) { return false; } @@ -1983,10 +1983,10 @@ public function acceptUdpConnection($socket) try { call_user_func($this->onMessage, $connection, $recv_buffer); } catch (\Exception $e) { - self::log($e); + static::log($e); exit(250); } catch (\Error $e) { - self::log($e); + static::log($e); exit(250); } } From 58a16cb06d245399d1349a073214fd0f31db7fc1 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 5 Nov 2017 21:37:39 +0800 Subject: [PATCH 0184/1216] support windows --- Lib/Timer.php | 4 +- Worker.php | 263 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 242 insertions(+), 25 deletions(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index f87a3f523..5ee576520 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -54,7 +54,9 @@ public static function init($event = null) if ($event) { self::$_event = $event; } else { - pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); + if (function_exists('pcntl_signal')) { + pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); + } } } diff --git a/Worker.php b/Worker.php index 22dac8f46..d76f56046 100644 --- a/Worker.php +++ b/Worker.php @@ -12,7 +12,6 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman; - require_once __DIR__ . '/Lib/Constants.php'; use Workerman\Events\EventInterface; @@ -20,6 +19,7 @@ use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; use Workerman\Lib\Timer; +use Workerman\Events\Select; use Exception; /** @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.2'; + const VERSION = '3.5.3'; /** * Status starting. @@ -213,7 +213,7 @@ class Worker /** * Application layer protocol. * - * @var Protocols\ProtocolInterface + * @var string */ public $protocol = null; @@ -388,6 +388,20 @@ class Worker */ protected static $_startFile = ''; + /** + * OS. + * + * @var string + */ + protected static $_OS = 'linux'; + + /** + * Processes for windows. + * + * @var array + */ + protected static $_processForWindows = array(); + /** * Status info of current worker process. * @@ -458,6 +472,9 @@ protected static function checkSapiEnv() if (php_sapi_name() != "cli") { exit("only run in command line mode \n"); } + if (DIRECTORY_SEPARATOR === '\\') { + self::$_OS = 'windows'; + } } /** @@ -513,6 +530,9 @@ protected static function init() */ protected static function initWorkers() { + if (static::$_OS !== 'linux') { + return; + } foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -532,11 +552,13 @@ protected static function initWorkers() } // Get unix user of the worker process. - if (empty($worker->user)) { - $worker->user = static::getCurrentUser(); - } else { - if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { - static::log('Warning: You must have the root privileges to change uid and gid.'); + if (static::$_OS === 'linux') { + if (empty($worker->user)) { + $worker->user = static::getCurrentUser(); + } else { + if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { + static::log('Warning: You must have the root privileges to change uid and gid.'); + } } } @@ -606,9 +628,17 @@ protected static function getCurrentUser() */ protected static function displayUI() { - static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\n\033[0m"); - static::safeEcho('Workerman version:'. Worker::VERSION. " PHP version:". PHP_VERSION. "\n"); - static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\n"); + global $argv; + if (isset($argv[1]) && $argv[1] === '-q') { + return; + } + static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\r\n\033[0m"); + static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); + static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\r\n"); + if (static::$_OS !== 'linux') { + static::safeEcho("worker listen processes status\r\n"); + return; + } static::safeEcho("\033[47;30muser\033[0m". str_pad('', static::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', static::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', @@ -637,6 +667,9 @@ protected static function displayUI() */ protected static function parseCommand() { + if (static::$_OS !== 'linux') { + return; + } global $argv; // Check argv; $start_file = $argv[0]; @@ -660,7 +693,7 @@ protected static function parseCommand() // Start command. $mode = ''; if ($command === 'start') { - if ($command2 === '-d' || Worker::$daemonize) { + if ($command2 === '-d' || static::$daemonize) { $mode = 'in DAEMON mode'; } else { $mode = 'in DEBUG mode'; @@ -686,7 +719,7 @@ protected static function parseCommand() switch ($command) { case 'start': if ($command2 === '-d') { - Worker::$daemonize = true; + static::$daemonize = true; } break; case 'status': @@ -756,7 +789,7 @@ protected static function parseCommand() exit(0); } if ($command2 === '-d') { - Worker::$daemonize = true; + static::$daemonize = true; } break; } @@ -838,6 +871,9 @@ protected static function formatStatusData() */ protected static function installSignal() { + if (static::$_OS !== 'linux') { + return; + } // stop pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false); // graceful stop @@ -861,6 +897,9 @@ protected static function installSignal() */ protected static function reinstallSignal() { + if (static::$_OS !== 'linux') { + return; + } // uninstall stop signal handler pcntl_signal(SIGINT, SIG_IGN, false); // uninstall graceful stop signal handler @@ -984,6 +1023,9 @@ public static function resetStd() */ protected static function saveMasterPid() { + if (static::$_OS !== 'linux') { + return; + } static::$_masterPid = posix_getpid(); if (false === @file_put_contents(static::$pidFile, static::$_masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); @@ -1054,6 +1096,21 @@ protected static function getAllWorkerPids() */ protected static function forkWorkers() { + if (static::$_OS === 'linux') { + static::forkWorkersForLinux(); + } else { + static::forkWorkersForWindows(); + } + } + + /** + * Fork some worker processes. + * + * @return void + */ + protected static function forkWorkersForLinux() + { + foreach (static::$_workers as $worker) { if (static::$_status === static::STATUS_STARTING) { if (empty($worker->name)) { @@ -1067,18 +1124,148 @@ protected static function forkWorkers() $worker->count = $worker->count <= 0 ? 1 : $worker->count; while (count(static::$_pidMap[$worker->workerId]) < $worker->count) { - static::forkOneWorker($worker); + static::forkOneWorkerForLinux($worker); + } + } + } + + /** + * Fork some worker processes. + * + * @return void + */ + public static function forkWorkersForWindows() + { + $files = static::getStartFilesForWindows(); + global $argv; + if(isset($argv[1]) && $argv[1] === '-q') + { + if(count(static::$_workers) > 1) + { + echo "@@@ Error: multi workers init in one php file are not support @@@\r\n"; + echo "@@@ Please visit http://wiki.workerman.net/Multi_woker_for_win @@@\r\n"; + } + elseif(count(static::$_workers) <= 0) + { + exit("@@@no worker inited@@@\r\n\r\n"); + } + + reset(static::$_workers); + /** @var Worker $worker */ + $worker = current(static::$_workers); + + // Display UI. + echo str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"; + $worker->listen(); + $worker->run(); + exit("@@@child exit@@@\r\n"); + } + else + { + static::$globalEvent = new \Workerman\Events\Select(); + Timer::init(static::$globalEvent); + foreach($files as $start_file) + { + static::forkOneWorkerForWindows($start_file); + } + } + } + + /** + * Get start files for windows. + * + * @return array + */ + public static function getStartFilesForWindows() { + global $argv; + $files = array(); + foreach($argv as $file) + { + $ext = pathinfo($file, PATHINFO_EXTENSION ); + if($ext !== 'php') + { + continue; + } + if(is_file($file)) + { + $files[$file] = $file; } } + return $files; } /** * Fork one worker process. * - * @param Worker $worker + * @param string $start_file + */ + public static function forkOneWorkerForWindows($start_file) + { + $start_file = realpath($start_file); + $std_file = sys_get_temp_dir() . '/'.str_replace(array('/', "\\", ':'), '_', $start_file).'.out.txt'; + + $descriptorspec = array( + 0 => array('pipe', 'a'), // stdin + 1 => array('file', $std_file, 'w'), // stdout + 2 => array('file', $std_file, 'w') // stderr + ); + + + $pipes = array(); + $process = proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); + $std_handler = fopen($std_file, 'a+'); + stream_set_blocking($std_handler, 0); + + if (empty(static::$globalEvent)) { + static::$globalEvent = new Select(); + Timer::init(static::$globalEvent); + } + $timer_id = Timer::add(1, function()use($std_handler) + { + echo fread($std_handler, 65535); + }); + + // 保存子进程句柄 + static::$_processForWindows[$start_file] = array($process, $start_file, $timer_id); + } + + /** + * check worker status for windows. + * @return void + */ + public static function checkWorkerStatusForWindows() + { + foreach(static::$_processForWindows as $process_data) + { + $process = $process_data[0]; + $start_file = $process_data[1]; + $timer_id = $process_data[2]; + $status = proc_get_status($process); + if(isset($status['running'])) + { + if(!$status['running']) + { + echo "process $start_file terminated and try to restart\n"; + Timer::del($timer_id); + @proc_close($process); + static::forkOneWorkerForWindows($start_file); + } + } + else + { + echo "proc_get_status fail\n"; + } + } + } + + + /** + * Fork one worker process. + * + * @param \Workerman\Worker $worker * @throws Exception */ - protected static function forkOneWorker($worker) + protected static function forkOneWorkerForLinux($worker) { // Get available worker id. $id = static::getId($worker->workerId, 0); @@ -1183,6 +1370,20 @@ protected static function setProcessTitle($title) * @return void */ protected static function monitorWorkers() + { + if (static::$_OS === 'linux') { + static::monitorWorkersForLinux(); + } else { + static::monitorWorkersForWindows(); + } + } + + /** + * Monitor all child processes. + * + * @return void + */ + protected static function monitorWorkersForLinux() { static::$_status = static::STATUS_RUNNING; while (1) { @@ -1243,6 +1444,18 @@ protected static function monitorWorkers() } } + /** + * Monitor all child processes. + * + * @return void + */ + protected static function monitorWorkersForWindows() + { + Timer::add(0.5, "\\Workerman\\Worker::checkWorkerStatusForWindows"); + + static::$globalEvent->loop(); + } + /** * Exit current process. * @@ -1428,7 +1641,7 @@ protected static function writeStatisticsToStatusFile() if (static::$_masterPid === posix_getpid()) { $all_worker_info = array(); foreach(static::$_pidMap as $worker_id => $pid_array) { - /** @var Worker $worker */ + /** @var /Workerman/Worker $worker */ $worker = static::$_workers[$worker_id]; foreach($pid_array as $pid) { $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName()); @@ -1440,7 +1653,7 @@ protected static function writeStatisticsToStatusFile() file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); file_put_contents(static::$_statisticsFile, - 'Workerman version:' . Worker::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); + 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); file_put_contents(static::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', static::$_globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); @@ -1483,7 +1696,7 @@ protected static function writeStatisticsToStatusFile() } // For child processes. - /** @var Worker $worker */ + /** @var \Workerman\Worker $worker */ $worker = current(static::$_workers); $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " @@ -1538,9 +1751,9 @@ protected static function writeConnectionsStatisticsToStatusFile() $current_worker = current(static::$_workers); $default_worker_name = $current_worker->name; - /** @var Worker $worker */ + /** @var \Workerman\Worker $worker */ foreach(TcpConnection::$connections as $connection) { - /** @var Connection\TcpConnection $connection */ + /** @var \Workerman\Connection\TcpConnection $connection */ $transport = $connection->transport; $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; @@ -1582,7 +1795,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN != static::$_status) { - $error_msg = 'Worker['. posix_getpid() .'] process terminated'; + $error_msg = static::$_OS === 'linx' ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || @@ -1651,7 +1864,8 @@ public static function log($msg) if (!static::$daemonize) { static::safeEcho($msg); } - file_put_contents((string)static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX); + file_put_contents((string)static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' + . (static::$_OS === 'linux' ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** @@ -1973,6 +2187,7 @@ public function acceptUdpConnection($socket) $connection->protocol = $this->protocol; if ($this->onMessage) { if ($this->protocol !== null) { + /** @var \Workerman\Protocols\ProtocolInterface $parser */ $parser = $this->protocol; $recv_buffer = $parser::decode($recv_buffer, $connection); // Discard bad packets. From 511e7661c3ff5182dbe5390464a412d012608e47 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Nov 2017 23:32:04 -0600 Subject: [PATCH 0185/1216] Check for windows --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index d76f56046..3782c98ac 100644 --- a/Worker.php +++ b/Worker.php @@ -971,7 +971,7 @@ public static function signalHandler($signal) */ protected static function daemonize() { - if (!static::$daemonize) { + if (!static::$daemonize || static::$_OS !== 'linux') { return; } umask(0); @@ -1000,7 +1000,7 @@ protected static function daemonize() */ public static function resetStd() { - if (!static::$daemonize) { + if (!static::$daemonize || static::$_OS !== 'linux') { return; } global $STDOUT, $STDERR; From 66449ccb2f67a1893bf91ac5164524829aeaa95b Mon Sep 17 00:00:00 2001 From: lvshuang Date: Mon, 20 Nov 2017 16:41:16 +0800 Subject: [PATCH 0186/1216] Add content type 'application/json' support in post request --- Protocols/Http.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 98add4a93..f0f39df13 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -168,6 +168,9 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'multipart/form-data': self::parseUploadFiles($http_body, $http_post_boundary); break; + case 'application/json': + $_POST = json_decode($http_body, true); + break; case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; From f5369137eacc25e33bb0b6c8008b96e292cf670f Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Dec 2017 14:09:14 +0800 Subject: [PATCH 0187/1216] SSL 3 is dead see #246 --- Connection/TcpConnection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 200894ebc..c6f577c7c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -563,8 +563,8 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | - STREAM_CRYPTO_METHOD_SSLv3_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER); + $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | + STREAM_CRYPTO_METHOD_SSLv23_SERVER); // Negotiation has failed. if(false === $ret) { if (!feof($socket)) { From 27a186d123403d7418a2310907f55e1395dca3c8 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Dec 2017 16:26:21 +0800 Subject: [PATCH 0188/1216] Update Timer.php --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index 5ee576520..e2e6d5eed 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -76,7 +76,7 @@ public static function signalHandle() /** * Add a timer. * - * @param int $time_interval + * @param float $time_interval * @param callable $func * @param mixed $args * @param bool $persistent From f527fa6adedb20cc515d3e536a882fa08962b924 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 6 Dec 2017 11:37:22 +0800 Subject: [PATCH 0189/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 3782c98ac..13783de80 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.3'; + const VERSION = '3.5.4'; /** * Status starting. From f6e129079e5f5398bffc218024f2dd95678fc564 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 6 Dec 2017 12:17:52 +0800 Subject: [PATCH 0190/1216] Update composer.json --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index c57dee72f..95c30972c 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,7 @@ "source": "https://github.com/walkor/workerman" }, "require": { - "php": ">=5.3", - "ext-pcntl": "*", - "ext-posix": "*" + "php": ">=5.3" }, "suggest": { "ext-event": "For better performance. " From 7f1ab4574859e8e40b53223c6821aa020b7ce6de Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Dec 2017 11:33:49 +0800 Subject: [PATCH 0191/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 13783de80..ec98aac40 100644 --- a/Worker.php +++ b/Worker.php @@ -653,9 +653,9 @@ protected static function displayUI() if (static::$daemonize) { global $argv; $start_file = $argv[0]; - static::safeEcho("Input \"php $start_file stop\" to quit. Start success.\n\n"); + static::safeEcho("Input \"php $start_file stop\" to stop. Start success.\n\n"); } else { - static::safeEcho("Press Ctrl+C to quit. Start success.\n"); + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } } From 09a0edb93980ed5764440dd3e17eb889ef223688 Mon Sep 17 00:00:00 2001 From: sm2017 Date: Sun, 24 Dec 2017 13:31:39 +0330 Subject: [PATCH 0192/1216] Support Fully qualified name for Protocols --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ec98aac40..c7412f1e0 100644 --- a/Worker.php +++ b/Worker.php @@ -1928,7 +1928,7 @@ public function listen() // Check application layer protocol class. if (!isset(static::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); - $this->protocol = '\\Protocols\\' . $scheme; + $this->protocol = substr($scheme,0,1)==='\\'?$scheme:'\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { From 380c57860dc7eeb1413808769c575f9e5fd29751 Mon Sep 17 00:00:00 2001 From: farwish Date: Sun, 14 Jan 2018 21:21:27 +0800 Subject: [PATCH 0193/1216] Fix command option -q and clear code --- Worker.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index c7412f1e0..e5c25e3cb 100644 --- a/Worker.php +++ b/Worker.php @@ -629,8 +629,11 @@ protected static function getCurrentUser() protected static function displayUI() { global $argv; - if (isset($argv[1]) && $argv[1] === '-q') { - return; + if (isset($argv[1])) { + // Support not display ui: php serv.php start/restart -q , php serv.php start/restart -d -q + if ( (isset($argv[2]) && ($argv[2] === '-q')) || (isset($argv[2]) && ($argv[2] === '-d') && isset($argv[3]) && ($argv[3] === '-q')) ) { + return; + } } static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\r\n\033[0m"); static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); @@ -651,9 +654,7 @@ protected static function displayUI() } static::safeEcho("----------------------------------------------------------------\n"); if (static::$daemonize) { - global $argv; - $start_file = $argv[0]; - static::safeEcho("Input \"php $start_file stop\" to stop. Start success.\n\n"); + static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } @@ -1928,7 +1929,7 @@ public function listen() // Check application layer protocol class. if (!isset(static::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); - $this->protocol = substr($scheme,0,1)==='\\'?$scheme:'\\Protocols\\' . $scheme; + $this->protocol = substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { From 5a954448b05287888e1b1b8ea11c393376d83903 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 20 Jan 2018 16:10:22 +0800 Subject: [PATCH 0194/1216] Update Select.php --- Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index aecd6b714..ff1dc3d92 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -265,7 +265,7 @@ public function loop() $read = $this->_readFds; $write = $this->_writeFds; - $except = $this->_writeFds; + $except = $this->_exceptFds; // Waiting read/write/signal/timeout events. $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); From 991f3cdf317b73cc5e9c89ad5fb24eba45e4d9f4 Mon Sep 17 00:00:00 2001 From: laogui Date: Thu, 1 Feb 2018 20:16:09 +0800 Subject: [PATCH 0195/1216] fixbug fix process exit with status 139 when they don't have protocol --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index c6f577c7c..455482f53 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -875,7 +875,7 @@ public function destroy() } } // Try to emit protocol::onClose - if (method_exists($this->protocol, 'onClose')) { + if (is_object($this->protocol) && method_exists($this->protocol, 'onClose')) { try { call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { From f54a4c8a9dc54f62f064b1f6e3890a140b7cbcd2 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Feb 2018 14:40:44 +0800 Subject: [PATCH 0196/1216] -q for windows --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index e5c25e3cb..3001b8285 100644 --- a/Worker.php +++ b/Worker.php @@ -631,7 +631,7 @@ protected static function displayUI() global $argv; if (isset($argv[1])) { // Support not display ui: php serv.php start/restart -q , php serv.php start/restart -d -q - if ( (isset($argv[2]) && ($argv[2] === '-q')) || (isset($argv[2]) && ($argv[2] === '-d') && isset($argv[3]) && ($argv[3] === '-q')) ) { + if ( $argv[1] === '-q' || (isset($argv[2]) && ($argv[2] === '-q')) || (isset($argv[2]) && ($argv[2] === '-d') && isset($argv[3]) && ($argv[3] === '-q')) ) { return; } } From b5166c896812e0946d9bcc18a43f05e450c93099 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Feb 2018 14:49:48 +0800 Subject: [PATCH 0197/1216] Display ui for windows --- Worker.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Worker.php b/Worker.php index 3001b8285..e3a2200c2 100644 --- a/Worker.php +++ b/Worker.php @@ -629,19 +629,19 @@ protected static function getCurrentUser() protected static function displayUI() { global $argv; - if (isset($argv[1])) { - // Support not display ui: php serv.php start/restart -q , php serv.php start/restart -d -q - if ( $argv[1] === '-q' || (isset($argv[2]) && ($argv[2] === '-q')) || (isset($argv[2]) && ($argv[2] === '-d') && isset($argv[3]) && ($argv[3] === '-q')) ) { - return; - } + if (in_array('-q', $argv)) { + return; } - static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\r\n\033[0m"); - static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); - static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\r\n"); if (static::$_OS !== 'linux') { + static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); + static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; } + static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\r\n\033[0m"); + static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); + static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\r\n"); static::safeEcho("\033[47;30muser\033[0m". str_pad('', static::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', static::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', From 3d0f6ec18ee6c26f68e218acb002f932166b6c07 Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Thu, 22 Feb 2018 18:06:42 +0800 Subject: [PATCH 0198/1216] Removing unnecessary OS comparison. Signed-off-by: tianhe1986 --- Worker.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Worker.php b/Worker.php index e3a2200c2..5f3fc6762 100644 --- a/Worker.php +++ b/Worker.php @@ -552,13 +552,11 @@ protected static function initWorkers() } // Get unix user of the worker process. - if (static::$_OS === 'linux') { - if (empty($worker->user)) { - $worker->user = static::getCurrentUser(); - } else { - if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { - static::log('Warning: You must have the root privileges to change uid and gid.'); - } + if (empty($worker->user)) { + $worker->user = static::getCurrentUser(); + } else { + if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { + static::log('Warning: You must have the root privileges to change uid and gid.'); } } From 843e34639427863979756e338720d3ed253102d2 Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Fri, 23 Feb 2018 17:15:04 +0800 Subject: [PATCH 0199/1216] Add checking for Sec-WebSocket-Accept header field. Signed-off-by: tianhe1986 --- Protocols/Ws.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 99fcc1d95..679491486 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -369,14 +369,15 @@ public static function sendHandshake($connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. + $connection->websocketSecKey = base64_encode(md5(mt_rand(), true)); $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". "Host: $host\r\n". "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". - (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). + (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). "Sec-WebSocket-Version: 13\r\n". - "Sec-WebSocket-Key: " . base64_encode(md5(mt_rand(), true)) . "\r\n\r\n"; + "Sec-WebSocket-Key: " . $connection->websocketSecKey . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; @@ -395,6 +396,19 @@ public static function dealHandshake($buffer, $connection) { $pos = strpos($buffer, "\r\n\r\n"); if ($pos) { + //checking Sec-WebSocket-Accept + if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { + if ($match[1] !== base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { + echo "Sec-WebSocket-Accept not match. Buffer:" . $buffer . "\n"; + $connection->close(); + return 0; + } + } else { + echo "Sec-WebSocket-Accept not found. Buffer:" . $buffer . "\n"; + $connection->close(); + return 0; + } + // handshake complete // Get WebSocket subprotocol (if specified by server) From 499566845e1c4c9ab304bcfdd7e28fdea4c4c91e Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Fri, 23 Feb 2018 17:21:39 +0800 Subject: [PATCH 0200/1216] Simplifying subprotocol parse. Signed-off-by: tianhe1986 --- Protocols/Ws.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 679491486..dbadf72d5 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -411,14 +411,10 @@ public static function dealHandshake($buffer, $connection) // handshake complete - // Get WebSocket subprotocol (if specified by server) - $header = explode("\r\n", substr($buffer, 0, $pos)); - foreach ($header as $hrow) { - if (preg_match("#^(.+?)\:(.+?)$#", $hrow, $m) && ($m[1] == "Sec-WebSocket-Protocol")) { - $connection->WSServerProtocol = trim($m[2]); - } - - } + // Get WebSocket subprotocol (if specified by server) + if (preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) { + $connection->WSServerProtocol = trim($match[1]); + } $connection->handshakeStep = 2; $handshake_response_length = $pos + 4; From 481b0982e97fd724f08e099542f5c4f19fd30da5 Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Fri, 23 Feb 2018 18:01:29 +0800 Subject: [PATCH 0201/1216] Just echoing header info. Signed-off-by: tianhe1986 --- Protocols/Ws.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index dbadf72d5..79143fcae 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -399,12 +399,12 @@ public static function dealHandshake($buffer, $connection) //checking Sec-WebSocket-Accept if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { if ($match[1] !== base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { - echo "Sec-WebSocket-Accept not match. Buffer:" . $buffer . "\n"; + echo "Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n"; $connection->close(); return 0; } } else { - echo "Sec-WebSocket-Accept not found. Buffer:" . $buffer . "\n"; + echo "Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n"; $connection->close(); return 0; } From ce840bb654a1890beea6da61ac74657cb1946f2e Mon Sep 17 00:00:00 2001 From: ishland <30385023+ishland@users.noreply.github.com> Date: Fri, 23 Feb 2018 22:08:51 +0800 Subject: [PATCH 0202/1216] More detailed help --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 5f3fc6762..e747cd123 100644 --- a/Worker.php +++ b/Worker.php @@ -680,7 +680,7 @@ protected static function parseCommand() 'status', 'connections', ); - $usage = "Usage: php yourfile.php {" . implode('|', $available_commands) . "} [-d]\n"; + $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { exit($usage); } From add3cce9f7acf5b861c8d8b00927e0accdf287df Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Sat, 24 Feb 2018 18:14:12 +0800 Subject: [PATCH 0203/1216] Checking mask bit. Signed-off-by: tianhe1986 --- Protocols/Websocket.php | 7 +++++++ Protocols/Ws.php | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 21a2e4704..00e7395a4 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -70,6 +70,13 @@ public static function input($buffer, ConnectionInterface $connection) $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; $masked = $secondbyte >> 7; + + if (!$masked) { + echo "frame not masked\n"; + $connection->close(); + return 0; + } + $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 79143fcae..3a76708ae 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -71,6 +71,13 @@ public static function input($buffer, $connection) $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; $masked = $secondbyte >> 7; + + if ($masked) { + echo "frame masked\n"; + $connection->close(); + return 0; + } + $opcode = $firstbyte & 0xf; switch ($opcode) { From 2d3522d24a8b334e9cb270cdc4702523f6954a0c Mon Sep 17 00:00:00 2001 From: tianhe1986 Date: Sat, 24 Feb 2018 18:32:24 +0800 Subject: [PATCH 0204/1216] Processing head length. Signed-off-by: tianhe1986 --- Protocols/Websocket.php | 6 +++--- Protocols/Ws.php | 37 ++++++++++--------------------------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 00e7395a4..bb2002f94 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -48,7 +48,7 @@ public static function input($buffer, ConnectionInterface $connection) // Receive length. $recv_len = strlen($buffer); // We need more data. - if ($recv_len < 2) { + if ($recv_len < 6) { return 0; } @@ -125,7 +125,7 @@ public static function input($buffer, ConnectionInterface $connection) // Consume data from receive buffer. if (!$data_len) { - $head_len = $masked ? 6 : 2; + $head_len = 6; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { return static::input(substr($buffer, $head_len), $connection); @@ -149,7 +149,7 @@ public static function input($buffer, ConnectionInterface $connection) } // Consume data from receive buffer. if (!$data_len) { - $head_len = $masked ? 6 : 2; + $head_len = 6; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { return static::input(substr($buffer, $head_len), $connection); diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 3a76708ae..04e67422e 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -126,7 +126,7 @@ public static function input($buffer, $connection) } // Consume data from receive buffer. if (!$data_len) { - $head_len = $masked ? 6 : 2; + $head_len = 2; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { return self::input(substr($buffer, $head_len), $connection); @@ -150,7 +150,7 @@ public static function input($buffer, $connection) } // Consume data from receive buffer. if (!$data_len) { - $head_len = $masked ? 6 : 2; + $head_len = 2; $connection->consumeRecvBuffer($head_len); if ($recv_len > $head_len) { return self::input(substr($buffer, $head_len), $connection); @@ -166,7 +166,7 @@ public static function input($buffer, $connection) } // Calculate packet length. if ($data_len === 126) { - if (strlen($buffer) < 6) { + if (strlen($buffer) < 4) { return 0; } $pack = unpack('nn/ntotal_len', $buffer); @@ -296,31 +296,14 @@ public static function encode($payload, $connection) */ public static function decode($bytes, $connection) { - $masked = ord($bytes[1]) >> 7; - $data_length = $masked ? ord($bytes[1]) & 127 : ord($bytes[1]); - $decoded_data = ''; - if ($masked === true) { - if ($data_length === 126) { - $mask = substr($bytes, 4, 4); - $coded_data = substr($bytes, 8); - } else if ($data_length === 127) { - $mask = substr($bytes, 10, 4); - $coded_data = substr($bytes, 14); - } else { - $mask = substr($bytes, 2, 4); - $coded_data = substr($bytes, 6); - } - for ($i = 0; $i < strlen($coded_data); $i++) { - $decoded_data .= $coded_data[$i] ^ $mask[$i % 4]; - } + $data_length = ord($bytes[1]); + + if ($data_length === 126) { + $decoded_data = substr($bytes, 4); + } else if ($data_length === 127) { + $decoded_data = substr($bytes, 10); } else { - if ($data_length === 126) { - $decoded_data = substr($bytes, 4); - } else if ($data_length === 127) { - $decoded_data = substr($bytes, 10); - } else { - $decoded_data = substr($bytes, 2); - } + $decoded_data = substr($bytes, 2); } if ($connection->websocketCurrentFrameLength) { $connection->websocketDataBuffer .= $decoded_data; From 3f2e828d401c431f5a0abddd6ab17d63e28747d4 Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 1 Mar 2018 00:32:36 +0900 Subject: [PATCH 0205/1216] Add user defined http header for websocket client protocol. --- Protocols/Ws.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 04e67422e..23aa2391d 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -158,7 +158,7 @@ public static function input($buffer, $connection) return 0; } break; - // Wrong opcode. + // Wrong opcode. default : echo "error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"; $connection->close(); @@ -348,7 +348,7 @@ public static function onClose($connection) * Send websocket handshake. * * @param \Workerman\Connection\TcpConnection $connection - * @return void + * @return void */ public static function sendHandshake($connection) { @@ -360,6 +360,17 @@ public static function sendHandshake($connection) $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->websocketSecKey = base64_encode(md5(mt_rand(), true)); + $userHeader = ''; + if (!empty($connection->wsHttpHeader)) { + if (is_array($connection->wsHttpHeader)){ + foreach($connection->wsHttpHeader as $k=>$v){ + $userHeader .= "$k: $v\r\n"; + } + }else{ + $userHeader .= $connection->wsHttpHeader; + } + $userHeader = "\r\n".trim($userHeader); + } $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". "Host: $host\r\n". "Connection: Upgrade\r\n". @@ -367,7 +378,7 @@ public static function sendHandshake($connection) "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). "Sec-WebSocket-Version: 13\r\n". - "Sec-WebSocket-Key: " . $connection->websocketSecKey . "\r\n\r\n"; + "Sec-WebSocket-Key: " . $connection->websocketSecKey . $userHeader . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; From 7b7a090ce84e1ec5d4534126853cc6d3644b4481 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 7 Mar 2018 11:24:04 +0800 Subject: [PATCH 0206/1216] for issue #268 --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index c6f577c7c..9689dc4f9 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -875,7 +875,7 @@ public function destroy() } } // Try to emit protocol::onClose - if (method_exists($this->protocol, 'onClose')) { + if ($this->protocol && method_exists($this->protocol, 'onClose')) { try { call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { From 4af9dc5b22e19c6b3123e437052f38a059b8199d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Mar 2018 16:06:57 +0800 Subject: [PATCH 0207/1216] Create AsyncUdpConnection.php --- Connection/AsyncUdpConnection.php | 187 ++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 Connection/AsyncUdpConnection.php diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php new file mode 100644 index 000000000..2170f8315 --- /dev/null +++ b/Connection/AsyncUdpConnection.php @@ -0,0 +1,187 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Connection; + +use Workerman\Events\EventInterface; +use Workerman\Worker; +use Exception; + +/** + * AsyncTcpConnection. + */ +class AsyncUdpConnection extends UdpConnection +{ + /** + * Emitted when socket connection is successfully established. + * + * @var callback + */ + public $onConnect = null; + + /** + * Emitted when socket connection closed. + * + * @var callback + */ + public $onClose = null; + + /** + * Connected or not. + * + * @var bool + */ + protected $connected = false; + + /** + * Construct. + * + * @param string $remote_address + * @throws Exception + */ + public function __construct($remote_address) + { + // Get the application layer communication protocol and listening address. + list($scheme, $address) = explode(':', $remote_address, 2); + // Check application layer protocol class. + if ($scheme !== 'udp') { + $scheme = ucfirst($scheme); + $this->protocol = '\\Protocols\\' . $scheme; + if (!class_exists($this->protocol)) { + $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!class_exists($this->protocol)) { + throw new Exception("class \\Protocols\\$scheme not exist"); + } + } + } + + $this->_remoteAddress = substr($address, 2); + } + + /** + * For udp package. + * + * @param resource $socket + * @return bool + */ + public function baseRead($socket) + { + $recv_buffer = stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + if (false === $recv_buffer || empty($remote_address)) { + return false; + } + + if ($this->onMessage) { + if ($this->protocol) { + $parser = $this->protocol; + $recv_buffer = $parser::decode($recv_buffer, $this); + } + ConnectionInterface::$statistics['total_request']++; + try { + call_user_func($this->onMessage, $this, $recv_buffer); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + return true; + } + + /** + * Sends data on the connection. + * + * @param string $send_buffer + * @param bool $raw + * @return void|boolean + */ + public function send($send_buffer, $raw = false) + { + if (false === $raw && $this->protocol) { + $parser = $this->protocol; + $send_buffer = $parser::encode($send_buffer, $this); + if ($send_buffer === '') { + return null; + } + } + if ($this->connected === false) { + $this->connect(); + } + return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0); + } + + + /** + * Close connection. + * + * @param mixed $data + * @param bool $raw + * + * @return bool + */ + public function close($data = null, $raw = false) + { + if ($data !== null) { + $this->send($data, $raw); + } + Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); + fclose($this->_socket); + $this->connected = false; + // Try to emit onClose callback. + if ($this->onClose) { + try { + call_user_func($this->onClose, $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + $this->onConnect = $this->onMessage = $this->onClose = null; + return true; + } + + /** + * Connect. + * + * @return void + */ + public function connect() + { + if ($this->connected === true) { + return; + } + $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}"); + if ($this->onMessage) { + Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + } + $this->connected = true; + // Try to emit onConnect callback. + if ($this->onConnect) { + try { + call_user_func($this->onConnect, $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + } + +} From 90f5aa4f98a151b0632594bbfcee1afc8e5fc805 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 17 Mar 2018 23:01:37 +0800 Subject: [PATCH 0208/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 72 +++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 106cae807..6282da245 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -552,6 +552,8 @@ public function resumeRecv() } } + + /** * Base read handler. * @@ -563,32 +565,8 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | - STREAM_CRYPTO_METHOD_SSLv23_SERVER); - // Negotiation has failed. - if(false === $ret) { - if (!feof($socket)) { - echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; - } - return $this->destroy(); - } elseif(0 === $ret) { - // There isn't enough data and should try again. - return; - } - if (isset($this->onSslHandshake)) { - try { - call_user_func($this->onSslHandshake, $this); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } - $this->_sslHandshakeCompleted = true; - if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + if ($this->doSslHandshake($socket)) { + $this->_sslHandshakeCompleted = true; } return; } @@ -727,6 +705,48 @@ public function baseWrite() } } + /** + * SSL handshake. + * + * @param $socket + * @return bool + */ + public function doSslHandshake($socket){ + if (feof($socket)) { + $this->destroy(); + return false; + } + $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | + STREAM_CRYPTO_METHOD_SSLv23_SERVER); + // Negotiation has failed. + if(false === $ret) { + if (!feof($socket)) { + echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; + } + $this->destroy(); + return false; + } elseif(0 === $ret) { + // There isn't enough data and should try again. + return false; + } + if (isset($this->onSslHandshake)) { + try { + call_user_func($this->onSslHandshake, $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + + if ($this->_sendBuffer) { + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + } + return true; + } + /** * This method pulls all the data out of a readable stream, and writes it to the supplied destination. * From 06aa6d8fec4509787fd55d09eb74e75ef2f414c9 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 17 Mar 2018 23:03:44 +0800 Subject: [PATCH 0209/1216] nonblocking ssl handshake --- Connection/AsyncTcpConnection.php | 54 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 0b3f915aa..aad6ded14 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -178,10 +178,10 @@ public function connect() // Open socket connection asynchronously. if ($this->_contextOption) { $context = stream_context_create($this->_contextOption); - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", + $this->_socket = stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteHost}:{$this->_remotePort}", + $this->_socket = stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); } } else { @@ -296,15 +296,20 @@ public function checkConnection($socket) socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } + + // SSL handshake. + if ($this->transport === 'ssl' && $this->doSslHandshake($socket)) { + $this->_sslHandshakeCompleted = true; + } + // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); // There are some data waiting to send. - if ($this->_sendBuffer) { + if ($this->_sendBuffer && $this->transport !== 'ssl') { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISHED; $this->_remoteAddress = $address; - $this->_sslHandshakeCompleted = true; // Try to emit onConnect callback. if ($this->onConnect) { @@ -341,4 +346,45 @@ public function checkConnection($socket) } } } + + /** + * SSL handshake. + * + * @param $socket + * @return bool + */ + public function doSslHandshake($socket){ + if (feof($socket)) { + $this->destroy(); + return false; + } + $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_CLIENT | + STREAM_CRYPTO_METHOD_SSLv23_CLIENT); + // Negotiation has failed. + if(false === $ret) { + if (!feof($socket)) { + echo "\nSSL Handshake as client fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; + } + $this->destroy(); + return false; + } elseif(0 === $ret) { + // There isn't enough data and should try again. + return false; + } + if (isset($this->onSslHandshake)) { + try { + call_user_func($this->onSslHandshake, $this); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + if ($this->_sendBuffer) { + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + } + return true; + } } From 697391ea3dc0e408cb851091304eff4b5741ca39 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 17 Mar 2018 23:44:49 +0800 Subject: [PATCH 0210/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index e747cd123..5166f3821 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.4'; + const VERSION = '3.5.5'; /** * Status starting. From da93463f78442963d8c22112b08c872a59d33972 Mon Sep 17 00:00:00 2001 From: Linkec Date: Sun, 18 Mar 2018 14:55:19 +0800 Subject: [PATCH 0211/1216] add Custom 404 page and Custom Headers for WebServer. --- WebServer.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/WebServer.php b/WebServer.php index afa412a02..f3c823132 100644 --- a/WebServer.php +++ b/WebServer.php @@ -47,12 +47,12 @@ class WebServer extends Worker * Add virtual host. * * @param string $domain - * @param string $root_path + * @param string $config * @return void */ - public function addRoot($domain, $root_path) + public function addRoot($domain, $config) { - $this->serverRoot[$domain] = $root_path; + $this->serverRoot[$domain] = $config; } /** @@ -164,10 +164,12 @@ public function onMessage($connection) $workerman_file_extension = 'php'; } - $workerman_root_dir = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : current($this->serverRoot); - + $workerman_siteConfig = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : current($this->serverRoot); + $workerman_root_dir = $workerman_siteConfig['root']; $workerman_file = "$workerman_root_dir/$workerman_path"; - + if(isset($workerman_siteConfig['additionHeader'])){ + Http::header($workerman_siteConfig['additionHeader']); + } if ($workerman_file_extension === 'php' && !is_file($workerman_file)) { $workerman_file = "$workerman_root_dir/index.php"; if (!is_file($workerman_file)) { @@ -223,7 +225,12 @@ public function onMessage($connection) } else { // 404 Http::header("HTTP/1.1 404 Not Found"); - $connection->close('404 File not found

404 Not Found

'); + if(isset($workerman_siteConfig['custom404'])){ + $html404 = '404 File not found

404 Not Found

'; + }else{ + $html404 = file_get_contents($workerman_siteConfig['custom404']); + } + $connection->close($html404); return; } } From 818b3cce49d480c11111c5d1820ac26c826de1fc Mon Sep 17 00:00:00 2001 From: Linkec Date: Sun, 18 Mar 2018 15:15:15 +0800 Subject: [PATCH 0212/1216] add Custom 404 page and Custom Headers for WebServer.check 404 file exist or not. --- WebServer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WebServer.php b/WebServer.php index f3c823132..cb4e2db1f 100644 --- a/WebServer.php +++ b/WebServer.php @@ -225,10 +225,10 @@ public function onMessage($connection) } else { // 404 Http::header("HTTP/1.1 404 Not Found"); - if(isset($workerman_siteConfig['custom404'])){ - $html404 = '404 File not found

404 Not Found

'; - }else{ + if(isset($workerman_siteConfig['custom404']) && file_exists($workerman_siteConfig['custom404'])){ $html404 = file_get_contents($workerman_siteConfig['custom404']); + }else{ + $html404 = '404 File not found

404 Not Found

'; } $connection->close($html404); return; From 1efb0356d99dfe42c9517be8c0349916e49e88b3 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Mar 2018 10:56:18 +0800 Subject: [PATCH 0213/1216] Update WebServer.php --- WebServer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WebServer.php b/WebServer.php index cb4e2db1f..34315f3bb 100644 --- a/WebServer.php +++ b/WebServer.php @@ -52,6 +52,9 @@ class WebServer extends Worker */ public function addRoot($domain, $config) { + if (is_string($config)) { + $config = array('root' => $config); + } $this->serverRoot[$domain] = $config; } From e92dcff1855c18a6081a1f09f9de8264960265a0 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Mar 2018 15:35:25 +0800 Subject: [PATCH 0214/1216] control header in onWebSocketConnect ```php $worker = new Worker('websocket://0.0.0.0:2000'); $worker->onConnect = function($connection){ $connection->onWebSocketConnect = function($connection, $header) { $connection->headers = array( 'Server: x-server', 'Sec-WebSocket-Protocol: ' . $_SERVER['HTTP_SEC_WEBSOCKET_PROTOCOL']); }; }; --- Protocols/Websocket.php | 44 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index bb2002f94..ac6546661 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -364,10 +364,8 @@ protected static function dealHandshake($buffer, $connection) $handshake_message .= "Upgrade: websocket\r\n"; $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; $handshake_message .= "Connection: Upgrade\r\n"; - $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; - $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; - // Mark handshake complete.. - $connection->websocketHandshake = true; + $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n"; + // Websocket data buffer. $connection->websocketDataBuffer = ''; // Current websocket frame length. @@ -376,18 +374,14 @@ protected static function dealHandshake($buffer, $connection) $connection->websocketCurrentFrameBuffer = ''; // Consume handshake data. $connection->consumeRecvBuffer($header_length); - // Send handshake response. - $connection->send($handshake_message, true); - // There are data waiting to be sent. - if (!empty($connection->tmpWebsocketData)) { - $connection->send($connection->tmpWebsocketData, true); - $connection->tmpWebsocketData = ''; - } // blob or arraybuffer if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; } + + $has_server_header = false; + // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect) || isset($connection->worker->onWebSocketConnect)) { static::parseHttpHeader($buffer); @@ -404,10 +398,36 @@ protected static function dealHandshake($buffer, $connection) $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); + + if (isset($connection->headers)) { + if (is_array($connection->headers)) { + foreach ($connection->headers as $header) { + if (strpos($header, 'Server:') === 0) { + $has_server_header = true; + } + $handshake_message .= "$header\r\n"; + } + } else { + $handshake_message .= "$connection->headers\r\n"; + } + } + } + if (!$has_server_header) { + $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; + } + $handshake_message .= "\r\n"; + // Send handshake response. + $connection->send($handshake_message, true); + // Mark handshake complete.. + $connection->websocketHandshake = true; + // There are data waiting to be sent. + if (!empty($connection->tmpWebsocketData)) { + $connection->send($connection->tmpWebsocketData, true); + $connection->tmpWebsocketData = ''; } if (strlen($buffer) > $header_length) { return static::input(substr($buffer, $header_length), $connection); - } + } return 0; } // Is flash policy-file-request. elseif (0 === strpos($buffer, ' Date: Tue, 20 Mar 2018 02:35:55 +0800 Subject: [PATCH 0215/1216] add Summary for Status --- Worker.php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 5166f3821..a113a7b86 100644 --- a/Worker.php +++ b/Worker.php @@ -825,6 +825,10 @@ protected static function formatStatusData() unset($info[0]); $data_waiting_sort = array(); $read_process_status = false; + $total_requests = 0; + $total_qps = 0; + $maxLen1 = static::$_maxSocketNameLength; + $maxLen2 = static::$_maxWorkerNameLength; foreach($info as $key => $value) { if (!$read_process_status) { $status_str .= $value . "\n"; @@ -836,8 +840,15 @@ protected static function formatStatusData() if(preg_match('/^[0-9]+/', $value, $pid_math)) { $pid = $pid_math[0]; $data_waiting_sort[$pid] = $value; - if(preg_match('/^\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?\S+?\s+?(\S+?)\s+?/', $value, $match)) { - $current_total_request[$pid] = $match[1]; + if(preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { + $total_memory += intval(str_ireplace('M','',$match[1])); + $maxLen1 = max($maxLen1,strlen($match[2])); + $maxLen2 = max($maxLen2,strlen($match[3])); + $total_connections += intval($match[4]); + $total_fails += intval($match[5]); + $total_timers += intval($match[6]); + $current_total_request[$pid] = $match[7]; + $total_requests += intval($match[7]); } } } @@ -855,10 +866,18 @@ protected static function formatStatusData() $qps = 0; } else { $qps = $current_total_request[$pid] - $total_request_cache[$pid]; + $total_qps += $qps; } $status_str .= $data_waiting_sort[$pid]. " " . str_pad($qps, 6) ." [idle]\n"; } $total_request_cache = $current_total_request; + $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; + $status_str .= "Summary\t" . str_pad($total_memory.'M', 7) . " " + . str_pad('-', $maxLen1) . " " + . str_pad('-', $maxLen2) . " " + . str_pad($total_connections, 11) . " " . str_pad($total_fails, 9) . " " + . str_pad($total_timers, 7) . " " . str_pad($total_requests, 13) . " " + . str_pad($total_qps,6)." [Summary] \n"; return $status_str; } From 1eb1f9660b5791aeb570fee5bccc822efe5802eb Mon Sep 17 00:00:00 2001 From: Linkec Date: Tue, 20 Mar 2018 02:43:57 +0800 Subject: [PATCH 0216/1216] fix undefined varible --- Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Worker.php b/Worker.php index a113a7b86..3087e3614 100644 --- a/Worker.php +++ b/Worker.php @@ -827,6 +827,10 @@ protected static function formatStatusData() $read_process_status = false; $total_requests = 0; $total_qps = 0; + $total_connections = 0; + $total_fails = 0; + $total_memory = 0; + $total_timers = 0; $maxLen1 = static::$_maxSocketNameLength; $maxLen2 = static::$_maxWorkerNameLength; foreach($info as $key => $value) { From 6b6ec77930e0a09c32efed4abc69e92c9b0c38a7 Mon Sep 17 00:00:00 2001 From: ares Date: Tue, 20 Mar 2018 15:33:01 +0800 Subject: [PATCH 0217/1216] Add swoole support. 1.Add swoole support.\Worker::$eventLoopClass = \Workerman\Events\Swoole 2.Fix infinite loop when Worker::count=0. 3.Fix fatal error cause by SIGUSER1 and SIGIIO when the worker is graceful stopping. --- Connection/TcpConnection.php | 5 +- Events/Swoole.php | 159 +++++++++++++++++++++++++++++++++++ Worker.php | 24 ++++-- 3 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 Events/Swoole.php diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6282da245..6a1f00e5c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -679,7 +679,7 @@ public function baseWrite() $this->bytesWritten += $len; Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; - // Try to emit onBufferDrain callback when the send buffer becomes empty. + // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { call_user_func($this->onBufferDrain, $this); @@ -941,8 +941,7 @@ public function __destruct() } if(0 === self::$statistics['connection_count']) { - Worker::$globalEvent->destroy(); - exit(0); + Worker::stopAll(); } } } diff --git a/Events/Swoole.php b/Events/Swoole.php new file mode 100644 index 000000000..0c2777d85 --- /dev/null +++ b/Events/Swoole.php @@ -0,0 +1,159 @@ + + * @link http://www.workerman.net/ + * @link https://github.com/ares333/Workerman + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events; + +use Swoole\Event; +use Swoole\Timer; +use Swoole\Process; + +class Swoole implements EventInterface +{ + + protected $_timer = array(); + + protected $_fd = array(); + + public static $usePcntl = true; + + // Swoole\Process::signal() is not stable in some version of php and swoole. + // The problem may be caused by using pcntl_signal() and pcntl_fork() and Swoole\Process::signal() together. + protected $_hasSignal = false; + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::add() + */ + public function add($fd, $flag, $func, $args = null) + { + if (! isset($args)) { + $args = array(); + } + switch ($flag) { + case self::EV_SIGNAL: + if (static::$usePcntl) { + $res = pcntl_signal($fd, $func, false); + if (! $this->_hasSignal && $res) { + Timer::tick(800, + function () { + pcntl_signal_dispatch(); + }); + $this->_hasSignal = true; + } + return $res; + } else { + return Process::signal($fd, $func); + } + case self::EV_TIMER: + case self::EV_TIMER_ONCE: + $method = self::EV_TIMER == $flag ? 'tick' : 'after'; + $timer_id = Timer::$method($fd * 1000, + function ($timer_id = null) use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timer[] = $timer_id; + return $timer_id; + case self::EV_READ: + case self::EV_WRITE: + if ($flag == self::EV_READ) { + $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); + } else { + $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE); + } + if (! in_array((int) $fd, $this->_fd) && $res) { + $this->_fd[] = (int) $fd; + } + return $res; + } + } + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::del() + */ + public function del($fd, $flag) + { + switch ($flag) { + case self::EV_SIGNAL: + if (static::$usePcntl) { + return pcntl_signal($fd, SIG_IGN, false); + } else { + return Process::signal($fd, null); + } + case self::EV_TIMER: + case self::EV_TIMER_ONCE: + return Timer::clear($fd); + case self::EV_READ: + case self::EV_WRITE: + $key = array_search((int) $fd, $this->_fd); + if (false !== $key) { + $res = Event::del($fd); + if ($res) { + unset($this->_fd[$key]); + } + return $res; + } + } + } + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::clearAllTimer() + */ + public function clearAllTimer() + { + foreach ($this->_timer as $v) { + Timer::clear($v); + } + $this->_timer = array(); + } + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::loop() + */ + public function loop() + { + Event::wait(); + } + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::destroy() + */ + public function destroy() + { + Event::exit(); + } + + /** + * + * {@inheritdoc} + * + * @see \Workerman\Events\EventInterface::getTimerCount() + */ + public function getTimerCount() + { + return count($this->_timer); + } +} diff --git a/Worker.php b/Worker.php index 5166f3821..e43532062 100644 --- a/Worker.php +++ b/Worker.php @@ -227,9 +227,15 @@ class Worker /** * Pause accept new connections or not. * - * @var string + * @var bool */ protected $_pauseAccept = true; + + /** + * Is worker stopping ? + * @var bool + */ + public $stopping = false; /** * Daemonize. @@ -601,6 +607,7 @@ protected static function initId() { foreach (static::$_workers as $worker_id => $worker) { $new_id_map = array(); + $worker->count = $worker->count <= 0 ? 1 : $worker->count; for($key = 0; $key < $worker->count; $key++) { $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; } @@ -758,11 +765,11 @@ protected static function parseCommand() if ($command2 === '-g') { static::$_gracefulStop = true; $sig = SIGTERM; - static::log("Workerman[$start_file] is gracefully stoping ..."); + static::log("Workerman[$start_file] is gracefully stopping ..."); } else { static::$_gracefulStop = false; $sig = SIGINT; - static::log("Workerman[$start_file] is stoping ..."); + static::log("Workerman[$start_file] is stopping ..."); } // Send stop signal to master process. $master_pid && posix_kill($master_pid, $sig); @@ -917,7 +924,7 @@ protected static function reinstallSignal() static::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful reload signal handler static::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); - // reinstall status signal handler + // reinstall status signal handler static::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall connection status signal handler static::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); @@ -1121,7 +1128,6 @@ protected static function forkWorkersForLinux() } } - $worker->count = $worker->count <= 0 ? 1 : $worker->count; while (count(static::$_pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorkerForLinux($worker); } @@ -1600,9 +1606,13 @@ public static function stopAll() else { // Execute exit. foreach (static::$_workers as $worker) { - $worker->stop(); + if(!$worker->stopping){ + $worker->stop(); + $worker->stopping = true; + } } if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { + static::$_workers = array(); static::$globalEvent->destroy(); exit(0); } @@ -2124,8 +2134,6 @@ public function stop() } // Clear callback. $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; - // Remove worker instance from static::$_workers. - unset(static::$_workers[$this->workerId]); } /** From 54bf051ccb137ed62e10ff6e5ecd287537a40031 Mon Sep 17 00:00:00 2001 From: ares Date: Tue, 20 Mar 2018 16:32:35 +0800 Subject: [PATCH 0218/1216] Set EV_SIGNAL dispatch interval to user defined. --- Events/Swoole.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 0c2777d85..d8587b868 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -24,7 +24,8 @@ class Swoole implements EventInterface protected $_fd = array(); - public static $usePcntl = true; + // milisecond + public static $signalDispatchInterval = 200; // Swoole\Process::signal() is not stable in some version of php and swoole. // The problem may be caused by using pcntl_signal() and pcntl_fork() and Swoole\Process::signal() together. @@ -43,10 +44,10 @@ public function add($fd, $flag, $func, $args = null) } switch ($flag) { case self::EV_SIGNAL: - if (static::$usePcntl) { + if (isset(static::$signalDispatchInterval)) { $res = pcntl_signal($fd, $func, false); if (! $this->_hasSignal && $res) { - Timer::tick(800, + Timer::tick(static::$signalDispatchInterval, function () { pcntl_signal_dispatch(); }); @@ -89,7 +90,7 @@ public function del($fd, $flag) { switch ($flag) { case self::EV_SIGNAL: - if (static::$usePcntl) { + if (isset(static::$signalDispatchInterval)) { return pcntl_signal($fd, SIG_IGN, false); } else { return Process::signal($fd, null); From fdeea968404986701a0ff45ff069aa1747ac36bc Mon Sep 17 00:00:00 2001 From: ares Date: Tue, 20 Mar 2018 16:32:35 +0800 Subject: [PATCH 0219/1216] Set EV_SIGNAL dispatch interval to user defined. --- Events/Swoole.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 0c2777d85..0a4d9bdfd 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -24,7 +24,8 @@ class Swoole implements EventInterface protected $_fd = array(); - public static $usePcntl = true; + // milisecond, set to null will use swoole signal. + public static $signalDispatchInterval = 200; // Swoole\Process::signal() is not stable in some version of php and swoole. // The problem may be caused by using pcntl_signal() and pcntl_fork() and Swoole\Process::signal() together. @@ -43,10 +44,10 @@ public function add($fd, $flag, $func, $args = null) } switch ($flag) { case self::EV_SIGNAL: - if (static::$usePcntl) { + if (isset(static::$signalDispatchInterval)) { $res = pcntl_signal($fd, $func, false); if (! $this->_hasSignal && $res) { - Timer::tick(800, + Timer::tick(static::$signalDispatchInterval, function () { pcntl_signal_dispatch(); }); @@ -89,7 +90,7 @@ public function del($fd, $flag) { switch ($flag) { case self::EV_SIGNAL: - if (static::$usePcntl) { + if (isset(static::$signalDispatchInterval)) { return pcntl_signal($fd, SIG_IGN, false); } else { return Process::signal($fd, null); From 84d841f46e6cbefcca592394e682268206b7c6e6 Mon Sep 17 00:00:00 2001 From: Ares Date: Tue, 20 Mar 2018 19:32:39 +0800 Subject: [PATCH 0220/1216] Replace EV_SIGNAL to pcntl only. --- Events/Swoole.php | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index db36c0791..60f7d74ad 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -24,11 +24,9 @@ class Swoole implements EventInterface protected $_fd = array(); - // milisecond. Set to null will use swoole signal. + // milisecond public static $signalDispatchInterval = 200; - // Swoole\Process::signal() is not stable in some version of php and swoole. - // The problem may be caused by using pcntl_signal() and pcntl_fork() and Swoole\Process::signal() together. protected $_hasSignal = false; /** @@ -44,19 +42,15 @@ public function add($fd, $flag, $func, $args = null) } switch ($flag) { case self::EV_SIGNAL: - if (isset(static::$signalDispatchInterval)) { - $res = pcntl_signal($fd, $func, false); - if (! $this->_hasSignal && $res) { - Timer::tick(static::$signalDispatchInterval, - function () { - pcntl_signal_dispatch(); - }); - $this->_hasSignal = true; - } - return $res; - } else { - return Process::signal($fd, $func); + $res = pcntl_signal($fd, $func, false); + if (! $this->_hasSignal && $res) { + Timer::tick(static::$signalDispatchInterval, + function () { + pcntl_signal_dispatch(); + }); + $this->_hasSignal = true; } + return $res; case self::EV_TIMER: case self::EV_TIMER_ONCE: $method = self::EV_TIMER == $flag ? 'tick' : 'after'; @@ -90,11 +84,7 @@ public function del($fd, $flag) { switch ($flag) { case self::EV_SIGNAL: - if (isset(static::$signalDispatchInterval)) { - return pcntl_signal($fd, SIG_IGN, false); - } else { - return Process::signal($fd, null); - } + return pcntl_signal($fd, SIG_IGN, false); case self::EV_TIMER: case self::EV_TIMER_ONCE: return Timer::clear($fd); From 01e7fb21e53ba74a0e91096fe73e3024f1d00275 Mon Sep 17 00:00:00 2001 From: wujingke Date: Wed, 21 Mar 2018 09:29:35 +0800 Subject: [PATCH 0221/1216] Update Worker.php add worker.php swoole event support --- Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index e4fa90de4..dbf3f716c 100644 --- a/Worker.php +++ b/Worker.php @@ -425,7 +425,8 @@ class Worker */ protected static $_availableEventLoops = array( 'libevent' => '\Workerman\Events\Libevent', - 'event' => '\Workerman\Events\Event' + 'event' => '\Workerman\Events\Event', + 'swoole' => '\Workerman\Events\Swoole' ); /** From d7db822417198a50281d601e291c16b12e5ff198 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 21 Mar 2018 11:03:13 +0800 Subject: [PATCH 0222/1216] Update ExtEventLoop.php --- Events/React/ExtEventLoop.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php index f1998b497..2a0f8b4f4 100644 --- a/Events/React/ExtEventLoop.php +++ b/Events/React/ExtEventLoop.php @@ -99,7 +99,7 @@ public function del($fd, $flag) case EventInterface::EV_SIGNAL: return $this->removeSignal($fd); case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE; + case EventInterface::EV_TIMER_ONCE: if (isset($this->_timerIdMap[$fd])){ $timer_obj = $this->_timerIdMap[$fd]; unset($this->_timerIdMap[$fd]); From 87908b251dab6bf69c4862ef8fd3b61b8bb6578f Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 21 Mar 2018 11:03:30 +0800 Subject: [PATCH 0223/1216] Update LibEventLoop.php --- Events/React/LibEventLoop.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/React/LibEventLoop.php b/Events/React/LibEventLoop.php index 14620afe7..4db9522ea 100644 --- a/Events/React/LibEventLoop.php +++ b/Events/React/LibEventLoop.php @@ -99,7 +99,7 @@ public function del($fd, $flag) case EventInterface::EV_SIGNAL: return $this->removeSignal($fd); case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE; + case EventInterface::EV_TIMER_ONCE: if (isset($this->_timerIdMap[$fd])){ $timer_obj = $this->_timerIdMap[$fd]; unset($this->_timerIdMap[$fd]); From 95074c31c4e94c30575e4229251767b342518fbd Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 21 Mar 2018 11:07:48 +0800 Subject: [PATCH 0224/1216] Update StreamSelectLoop.php --- Events/React/StreamSelectLoop.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index 0c8c9f2d4..0c92385ba 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -84,7 +84,7 @@ public function del($fd, $flag) case EventInterface::EV_SIGNAL: return $this->removeSignal($fd); case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE; + case EventInterface::EV_TIMER_ONCE: if (isset($this->_timerIdMap[$fd])){ $timer_obj = $this->_timerIdMap[$fd]; unset($this->_timerIdMap[$fd]); From aff12aebeb65aab3a600c6facd6e7f75c6acd91e Mon Sep 17 00:00:00 2001 From: Ares Date: Wed, 21 Mar 2018 17:52:51 +0800 Subject: [PATCH 0225/1216] Fix tcp connection lost bug and EV_WRITE register twice bug. 1.Fix AsyncTcpConnection being unset in TcpConnection::$connections and never add back when reconnected. 2.Fix AsyncTcpConnection adding EV_WRITE event multi times in ssl handshake stage. --- Connection/AsyncTcpConnection.php | 33 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index aad6ded14..d0cd63dd0 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -158,13 +158,12 @@ public function __construct($remote_address, $context_option = null) self::$statistics['connection_count']++; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_contextOption = $context_option; - static::$connections[$this->id] = $this; } /** * Do connect. * - * @return void + * @return void */ public function connect() { @@ -199,7 +198,7 @@ public function connect() } return; } - // Add socket to global event loop waiting connection is successfully established or faild. + // Add socket to global event loop waiting connection is successfully established or faild. Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); // For windows. if(DIRECTORY_SEPARATOR === '\\') { @@ -228,7 +227,7 @@ public function reConnect($after = 0) { /** * Get remote address. * - * @return string + * @return string */ public function getRemoteHost() { @@ -276,14 +275,8 @@ protected function emitError($code, $msg) */ public function checkConnection($socket) { - // Remove EV_EXPECT for windows. - if(DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); - } // Check socket state. if ($address = stream_socket_get_name($socket, true)) { - // Remove write listener. - Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); // Compatible with hhvm @@ -298,14 +291,24 @@ public function checkConnection($socket) } // SSL handshake. - if ($this->transport === 'ssl' && $this->doSslHandshake($socket)) { - $this->_sslHandshakeCompleted = true; + if ($this->transport === 'ssl') { + $this->_sslHandshakeCompleted = $this->doSslHandshake($socket); + if(!$this->_sslHandshakeCompleted){ + return; + } + } + + // Remove EV_EXPECT for windows. + if(DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); } + // Remove write listener. + Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); // There are some data waiting to send. - if ($this->_sendBuffer && $this->transport !== 'ssl') { + if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISHED; @@ -335,6 +338,7 @@ public function checkConnection($socket) exit(250); } } + static::$connections[$this->id] = $this; } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); @@ -382,9 +386,6 @@ public function doSslHandshake($socket){ exit(250); } } - if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); - } return true; } } From df46b1db321bc6db681d9235ba15ea7bd73b9e98 Mon Sep 17 00:00:00 2001 From: Ares Date: Wed, 21 Mar 2018 18:42:25 +0800 Subject: [PATCH 0226/1216] Combine doSslHandshake() --- Connection/AsyncTcpConnection.php | 40 +------------------------------ Connection/TcpConnection.php | 24 +++++++++++-------- 2 files changed, 15 insertions(+), 49 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index d0cd63dd0..9da4d3ee9 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -292,7 +292,7 @@ public function checkConnection($socket) // SSL handshake. if ($this->transport === 'ssl') { - $this->_sslHandshakeCompleted = $this->doSslHandshake($socket); + $this->_sslHandshakeCompleted = $this->doSslHandshake($socket,true); if(!$this->_sslHandshakeCompleted){ return; } @@ -350,42 +350,4 @@ public function checkConnection($socket) } } } - - /** - * SSL handshake. - * - * @param $socket - * @return bool - */ - public function doSslHandshake($socket){ - if (feof($socket)) { - $this->destroy(); - return false; - } - $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_CLIENT | - STREAM_CRYPTO_METHOD_SSLv23_CLIENT); - // Negotiation has failed. - if(false === $ret) { - if (!feof($socket)) { - echo "\nSSL Handshake as client fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; - } - $this->destroy(); - return false; - } elseif(0 === $ret) { - // There isn't enough data and should try again. - return false; - } - if (isset($this->onSslHandshake)) { - try { - call_user_func($this->onSslHandshake, $this); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } - return true; - } } diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6a1f00e5c..f20677e8f 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -565,10 +565,14 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - if ($this->doSslHandshake($socket)) { + if ($this->doSslHandshake($socket,false)) { $this->_sslHandshakeCompleted = true; + if ($this->_sendBuffer) { + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + } + }else{ + return; } - return; } $buffer = @fread($socket, self::READ_BUFFER_SIZE); @@ -711,17 +715,21 @@ public function baseWrite() * @param $socket * @return bool */ - public function doSslHandshake($socket){ + public function doSslHandshake($socket,$async){ if (feof($socket)) { $this->destroy(); return false; } - $ret = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER | - STREAM_CRYPTO_METHOD_SSLv23_SERVER); + if($async){ + $type=STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + }else{ + $type=STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; + } + $ret = stream_socket_enable_crypto($socket, true, $type); // Negotiation has failed. if(false === $ret) { if (!feof($socket)) { - echo "\nSSL Handshake fail. \nBuffer:".bin2hex(fread($socket, 8182))."\n"; + echo "\nSSL Handshake fail as ".($async?'client':'server').". \nBuffer:".bin2hex(fread($socket, 8182))."\n"; } $this->destroy(); return false; @@ -740,10 +748,6 @@ public function doSslHandshake($socket){ exit(250); } } - - if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); - } return true; } From e7d3001595f3a34f6a5a6f3ca7bd2ac677e8d184 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Mar 2018 14:57:38 +0800 Subject: [PATCH 0227/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index f20677e8f..3d607e6a1 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -565,12 +565,12 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - if ($this->doSslHandshake($socket,false)) { + if ($this->doSslHandshake($socket, false)) { $this->_sslHandshakeCompleted = true; if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } - }else{ + } else { return; } } @@ -715,7 +715,7 @@ public function baseWrite() * @param $socket * @return bool */ - public function doSslHandshake($socket,$async){ + public function doSslHandshake($socket, $async){ if (feof($socket)) { $this->destroy(); return false; @@ -727,13 +727,13 @@ public function doSslHandshake($socket,$async){ } $ret = stream_socket_enable_crypto($socket, true, $type); // Negotiation has failed. - if(false === $ret) { + if (false === $ret) { if (!feof($socket)) { echo "\nSSL Handshake fail as ".($async?'client':'server').". \nBuffer:".bin2hex(fread($socket, 8182))."\n"; } $this->destroy(); return false; - } elseif(0 === $ret) { + } elseif (0 === $ret) { // There isn't enough data and should try again. return false; } From f8e5871e39ea723808c5908c5bbe612d51ef7df5 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Mar 2018 15:02:11 +0800 Subject: [PATCH 0228/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9da4d3ee9..36308c467 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -158,6 +158,7 @@ public function __construct($remote_address, $context_option = null) self::$statistics['connection_count']++; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_contextOption = $context_option; + static::$connections[$this->id] = $this; } /** @@ -168,7 +169,7 @@ public function __construct($remote_address, $context_option = null) public function connect() { if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && - $this->_status !== self::STATUS_CLOSED) { + $this->_status !== self::STATUS_CLOSED) { return; } $this->_status = self::STATUS_CONNECTING; @@ -275,6 +276,11 @@ protected function emitError($code, $msg) */ public function checkConnection($socket) { + // Remove EV_EXPECT for windows. + if(DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); + } + // Check socket state. if ($address = stream_socket_get_name($socket, true)) { // Nonblocking. @@ -290,27 +296,22 @@ public function checkConnection($socket) socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } + // Remove write listener. + Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); + // SSL handshake. if ($this->transport === 'ssl') { - $this->_sslHandshakeCompleted = $this->doSslHandshake($socket,true); - if(!$this->_sslHandshakeCompleted){ - return; + $this->_sslHandshakeCompleted = $this->doSslHandshake($socket, true); + } else { + // There are some data waiting to send. + if ($this->_sendBuffer) { + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } } - - // Remove EV_EXPECT for windows. - if(DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); - } - // Remove write listener. - Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); - // There are some data waiting to send. - if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); - } + $this->_status = self::STATUS_ESTABLISHED; $this->_remoteAddress = $address; @@ -338,7 +339,6 @@ public function checkConnection($socket) exit(250); } } - static::$connections[$this->id] = $this; } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); From fd78b42d04310a0608e26d64bf33c038cfeaee29 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Mar 2018 15:51:14 +0800 Subject: [PATCH 0229/1216] Update Worker.php --- Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Worker.php b/Worker.php index dbf3f716c..0267e80cf 100644 --- a/Worker.php +++ b/Worker.php @@ -1729,6 +1729,7 @@ protected static function writeStatisticsToStatusFile() } // For child processes. + reset(static::$_workers); /** @var \Workerman\Worker $worker */ $worker = current(static::$_workers); $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) From 94fb4a8a635a92e835c224d9dee8d7bba0ff841b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Mar 2018 22:56:04 +0800 Subject: [PATCH 0230/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 3d607e6a1..142dcbb76 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -890,11 +890,6 @@ public function destroy() Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // Close socket. @fclose($this->_socket); - // Remove from worker->connections. - if ($this->worker) { - unset($this->worker->connections[$this->_id]); - } - unset(static::$connections[$this->_id]); $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { @@ -923,6 +918,11 @@ public function destroy() if ($this->_status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; + // Remove from worker->connections. + if ($this->worker) { + unset($this->worker->connections[$this->_id]); + } + unset(static::$connections[$this->_id]); } } From 4ce11de6bf8b14c6a716226b9d811d7e6f3fb0e3 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 23 Mar 2018 10:33:46 +0800 Subject: [PATCH 0231/1216] Fix EV_TIMER_ONCE auto remove problem. EV_TIMER_ONCE will delete itself when triggered.But timer array not cleaned and remove unexist timer will trigger a php warning log. --- Events/Swoole.php | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 60f7d74ad..6d7e07eab 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -22,6 +22,8 @@ class Swoole implements EventInterface protected $_timer = array(); + protected $_timerOnceMap = array(); + protected $_fd = array(); // milisecond @@ -54,11 +56,26 @@ function () { case self::EV_TIMER: case self::EV_TIMER_ONCE: $method = self::EV_TIMER == $flag ? 'tick' : 'after'; + $mapId = count($this->_timerOnceMap); $timer_id = Timer::$method($fd * 1000, - function ($timer_id = null) use ($func, $args) { + function ($timer_id = null) use ($func, $args, $mapId) { call_user_func_array($func, $args); + // EV_TIMER_ONCE + if (! isset($timer_id)) { + //may be deleted in $func + if (array_key_exists($mapId, $this->_timerOnceMap)) { + $timer_id = $this->_timerOnceMap[$mapId]; + unset($this->_timer[$timer_id], + $this->_timerOnceMap[$mapId]); + } + } }); - $this->_timer[] = $timer_id; + if ($flag == self::EV_TIMER_ONCE) { + $this->_timerOnceMap[$mapId] = $timer_id; + $this->_timer[$timer_id] = $mapId; + } else { + $this->_timer[$timer_id] = null; + } return $timer_id; case self::EV_READ: case self::EV_WRITE: @@ -87,7 +104,19 @@ public function del($fd, $flag) return pcntl_signal($fd, SIG_IGN, false); case self::EV_TIMER: case self::EV_TIMER_ONCE: - return Timer::clear($fd); + // already remove in EV_TIMER_ONCE callback. + if (! array_key_exists($fd, $this->_timer)) { + return true; + } + $res = Timer::clear($fd); + if ($res) { + $mapId = $this->_timer[$fd]; + if (isset($mapId)) { + unset($this->_timerOnceMap[$mapId]); + } + unset($this->_timer[$fd]); + } + return $res; case self::EV_READ: case self::EV_WRITE: $key = array_search((int) $fd, $this->_fd); @@ -109,10 +138,11 @@ public function del($fd, $flag) */ public function clearAllTimer() { - foreach ($this->_timer as $v) { + foreach (array_keys($this->_timer) as $v) { Timer::clear($v); } $this->_timer = array(); + $this->_timerOnceMap = array(); } /** From c605ac9452d29637f4a0d7cbc7f19ac08b872d01 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 23 Mar 2018 11:25:43 +0800 Subject: [PATCH 0232/1216] Fix doSslHandshake() bug. Client or server side is hard coded.In inherit condiction client side will become server side.Change the condiction to dynamic. --- Connection/AsyncTcpConnection.php | 2 +- Connection/TcpConnection.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 36308c467..954abc873 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -301,7 +301,7 @@ public function checkConnection($socket) // SSL handshake. if ($this->transport === 'ssl') { - $this->_sslHandshakeCompleted = $this->doSslHandshake($socket, true); + $this->_sslHandshakeCompleted = $this->doSslHandshake($socket); } else { // There are some data waiting to send. if ($this->_sendBuffer) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 142dcbb76..71519262f 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -565,7 +565,7 @@ public function baseRead($socket, $check_eof = true) { // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { - if ($this->doSslHandshake($socket, false)) { + if ($this->doSslHandshake($socket)) { $this->_sslHandshakeCompleted = true; if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); @@ -715,11 +715,12 @@ public function baseWrite() * @param $socket * @return bool */ - public function doSslHandshake($socket, $async){ + public function doSslHandshake($socket){ if (feof($socket)) { $this->destroy(); return false; } + $async=$this instanceof AsyncTcpConnection; if($async){ $type=STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; }else{ From ca6cb9845554897144623c3b55962be923c677ac Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 23 Mar 2018 12:04:36 +0800 Subject: [PATCH 0233/1216] fix connections missing in statistics --- Connection/AsyncTcpConnection.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 954abc873..66477bce9 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -156,9 +156,9 @@ public function __construct($remote_address, $context_option = null) // For statistics. self::$statistics['connection_count']++; - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->_contextOption = $context_option; - static::$connections[$this->id] = $this; + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->_contextOption = $context_option; + static::$connections[$this->_id] = $this; } /** @@ -214,7 +214,8 @@ public function connect() * @return void */ public function reConnect($after = 0) { - $this->_status = self::STATUS_INITIAL; + $this->_status = self::STATUS_INITIAL; + static::$connections[$this->_id] = $this; if ($this->_reconnectTimer) { Timer::del($this->_reconnectTimer); } From fbcf67668bdc432f3840de45abc5cf08341a2782 Mon Sep 17 00:00:00 2001 From: Ares Date: Sun, 25 Mar 2018 01:08:32 +0800 Subject: [PATCH 0234/1216] Fix EV_READ and EV_WRITE bug for swoole event loop. A big bug fixed... --- Events/Swoole.php | 64 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 6d7e07eab..7945ae7af 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -15,7 +15,6 @@ use Swoole\Event; use Swoole\Timer; -use Swoole\Process; class Swoole implements EventInterface { @@ -62,7 +61,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { call_user_func_array($func, $args); // EV_TIMER_ONCE if (! isset($timer_id)) { - //may be deleted in $func + // may be deleted in $func if (array_key_exists($mapId, $this->_timerOnceMap)) { $timer_id = $this->_timerOnceMap[$mapId]; unset($this->_timer[$timer_id], @@ -79,13 +78,34 @@ function ($timer_id = null) use ($func, $args, $mapId) { return $timer_id; case self::EV_READ: case self::EV_WRITE: - if ($flag == self::EV_READ) { - $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); + $fd_key = (int) $fd; + if (! isset($this->_fd[$fd_key])) { + if ($flag == self::EV_READ) { + $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); + $fd_type = SWOOLE_EVENT_READ; + } else { + $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE); + $fd_type = SWOOLE_EVENT_WRITE; + } + if ($res) { + $this->_fd[$fd_key] = $fd_type; + } } else { - $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE); - } - if (! in_array((int) $fd, $this->_fd) && $res) { - $this->_fd[] = (int) $fd; + $fd_val = $this->_fd[$fd_key]; + $res = true; + if ($flag == self::EV_READ) { + if (($fd_val & SWOOLE_EVENT_READ) != SWOOLE_EVENT_READ) { + $res = Event::set($fd, $func, null, + SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); + $this->_fd[$fd_key] |= SWOOLE_EVENT_READ; + } + } else { + if (($fd_val & SWOOLE_EVENT_WRITE) != SWOOLE_EVENT_WRITE) { + $res = Event::set($fd, null, $func, + SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); + $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE; + } + } } return $res; } @@ -119,14 +139,30 @@ public function del($fd, $flag) return $res; case self::EV_READ: case self::EV_WRITE: - $key = array_search((int) $fd, $this->_fd); - if (false !== $key) { - $res = Event::del($fd); - if ($res) { - unset($this->_fd[$key]); + $fd_key = (int) $fd; + if (isset($this->_fd[$fd_key])) { + $fd_val = $this->_fd[$fd_key]; + if ($flag == self::EV_READ) { + $flag_remove = ~ SWOOLE_EVENT_READ; + } else { + $flag_remove = ~ SWOOLE_EVENT_WRITE; + } + $fd_val &= $flag_remove; + if (0 === $fd_val) { + $res = Event::del($fd); + if ($res) { + unset($this->_fd[$fd_key]); + } + } else { + $res = Event::set($fd, null, null, $fd_val); + if ($res) { + $this->_fd[$fd_key] = $fd_val; + } } - return $res; + } else { + $res = true; } + return $res; } } From 92ae5477f985a96831a8dfdbbcc0244322411952 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 17:56:37 +0300 Subject: [PATCH 0235/1216] Improve the HTTP Session management --- Protocols/Http.php | 119 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 23 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index c99d0d83d..2c7083f73 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -174,23 +174,9 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; - case 'application/json': - $_POST = json_decode($http_body, true); - break; } } } - - // 解析其他HTTP动作参数 - if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { - $data = array(); - if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { - parse_str($http_body, $data); - } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { - $data = json_decode($http_body, true); - } - $_REQUEST = array_merge($_REQUEST, $data); - } // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; @@ -205,7 +191,7 @@ public static function decode($recv_buffer, TcpConnection $connection) } // REQUEST - $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); + $_REQUEST = array_merge($_GET, $_POST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); @@ -344,6 +330,89 @@ public static function setcookie( . (!$HTTPOnly ? '' : '; HttpOnly'), false); } + /** + * sessionId + * + * @param string $id + * + * @return string|null + */ + public static function sessionId($id = null) + { + if (PHP_SAPI != 'cli') { + return $id ? session_id($id) : session_id(); + } + if (static::sessionStarted()) { + return str_replace('sess_', '', basename(HttpCache::$instance->sessionFile)); + } + return ''; + } + + /** + * sessionName + * + * @param string $name + * + * @return string + */ + public static function sessionName($name = null) + { + if (PHP_SAPI != 'cli') { + return $name ? session_name($name) : session_name(); + } + $session_name = HttpCache::$sessionName; + if ($name && ! static::sessionStarted()) { + HttpCache::$sessionName = $name; + } + return $session_name; + } + + /** + * sessionSavePath + * + * @param string $path + * + * @return void + */ + public static function sessionSavePath($path = null) + { + if (PHP_SAPI != 'cli') { + return $path ? session_save_path($path) : session_save_path(); + } + if ($path && is_dir($path) && is_writable($path) && !static::sessionStarted()) { + HttpCache::$sessionPath = $path; + } + return HttpCache::$sessionPath; + } + + /** + * sessionStatus + * + * @return int + */ + public static function sessionStatus() + { + if (PHP_SAPI != 'cli') { + return session_status(); + } + if (!extension_loaded('session')) { + return PHP_SESSION_DISABLED; + } + return static::sessionStarted() ? PHP_SESSION_ACTIVE : PHP_SESSION_NONE; + } + + /** + * sessionStarted + * + * @return bool + */ + public static function sessionStarted() + { + if (!HttpCache::$instance) return false; + + return HttpCache::$instance->sessionStarted; + } + /** * sessionStart * @@ -363,13 +432,13 @@ public static function sessionStart() } HttpCache::$instance->sessionStarted = true; // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName])) { - $file_name = tempnam(HttpCache::$sessionPath, 'ses'); - if (!$file_name) { - return false; + if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName])) { + // Create a new unique session_id and its associated file name. + while (true) { + $session_id = session_create_id(); + if (!is_file($file_name = HttpCache::$sessionPath . '/sess_' . $session_id)) break; } HttpCache::$instance->sessionFile = $file_name; - $session_id = substr(basename($file_name), strlen('ses')); return self::setcookie( HttpCache::$sessionName , $session_id @@ -381,7 +450,7 @@ public static function sessionStart() ); } if (!HttpCache::$instance->sessionFile) { - HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName]; + HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName]; } // Read session from session file. if (HttpCache::$instance->sessionFile) { @@ -579,8 +648,12 @@ class HttpCache public static function init() { - self::$sessionName = ini_get('session.name'); - self::$sessionPath = @session_save_path(); + if (!self::$sessionName) { + self::$sessionName = ini_get('session.name'); + } + if (!self::$sessionPath) { + self::$sessionPath = @session_save_path(); + } if (!self::$sessionPath || strpos(self::$sessionPath, 'tcp://') === 0) { self::$sessionPath = sys_get_temp_dir(); } From 7f171a2643138ace75850d3a7264452bb3b01258 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 18:03:18 +0300 Subject: [PATCH 0236/1216] Improve the Workerman\Protocols\Http --- Protocols/Http.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 2c7083f73..378fee827 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -174,10 +174,24 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; + case 'application/json': + $_POST = json_decode($http_body, true); + break; } } } + // 解析其他HTTP动作参数 + if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { + $data = array(); + if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { + parse_str($http_body, $data); + } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { + $data = json_decode($http_body, true); + } + $_REQUEST = array_merge($_REQUEST, $data); + } + // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; @@ -191,7 +205,7 @@ public static function decode($recv_buffer, TcpConnection $connection) } // REQUEST - $_REQUEST = array_merge($_GET, $_POST); + $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); @@ -432,7 +446,7 @@ public static function sessionStart() } HttpCache::$instance->sessionStarted = true; // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName])) { + if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName])) { // Create a new unique session_id and its associated file name. while (true) { $session_id = session_create_id(); @@ -450,7 +464,7 @@ public static function sessionStart() ); } if (!HttpCache::$instance->sessionFile) { - HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName]; + HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName]; } // Read session from session file. if (HttpCache::$instance->sessionFile) { From fc835dcaaa91f842b17c8fedddff1d6e3ae173e2 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 18:12:51 +0300 Subject: [PATCH 0237/1216] Improve the Workerman\Protocols\Http --- Protocols/Http.php | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 378fee827..46722e96e 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -344,6 +344,18 @@ public static function setcookie( . (!$HTTPOnly ? '' : '; HttpOnly'), false); } + /** + * sessionCreateId + * + * @param string|prefix $prefix + * + * @return string + */ + public static function sessionCreateId($prefix = null) + { + return session_create_id($prefix); + } + /** * sessionId * @@ -399,22 +411,6 @@ public static function sessionSavePath($path = null) return HttpCache::$sessionPath; } - /** - * sessionStatus - * - * @return int - */ - public static function sessionStatus() - { - if (PHP_SAPI != 'cli') { - return session_status(); - } - if (!extension_loaded('session')) { - return PHP_SESSION_DISABLED; - } - return static::sessionStarted() ? PHP_SESSION_ACTIVE : PHP_SESSION_NONE; - } - /** * sessionStarted * @@ -449,7 +445,7 @@ public static function sessionStart() if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName])) { // Create a new unique session_id and its associated file name. while (true) { - $session_id = session_create_id(); + $session_id = static::sessionCreateId(); if (!is_file($file_name = HttpCache::$sessionPath . '/sess_' . $session_id)) break; } HttpCache::$instance->sessionFile = $file_name; From 8cd7a62bf5e92bc5e7e368ef2cf9f438e14953a5 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 18:15:56 +0300 Subject: [PATCH 0238/1216] Comments change --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 46722e96e..1edb0938c 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -443,7 +443,7 @@ public static function sessionStart() HttpCache::$instance->sessionStarted = true; // Generate a SID. if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName])) { - // Create a new unique session_id and its associated file name. + // Create a unique session_id and the associated file name. while (true) { $session_id = static::sessionCreateId(); if (!is_file($file_name = HttpCache::$sessionPath . '/sess_' . $session_id)) break; From ca1d022f8d8b1f37edb617b356ab37123e4efbce Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 18:18:26 +0300 Subject: [PATCH 0239/1216] Improve the Workerman\Protocols\Http --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 1edb0938c..89c2bbff6 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -368,7 +368,7 @@ public static function sessionId($id = null) if (PHP_SAPI != 'cli') { return $id ? session_id($id) : session_id(); } - if (static::sessionStarted()) { + if (static::sessionStarted() && HttpCache::$instance->sessionFile) { return str_replace('sess_', '', basename(HttpCache::$instance->sessionFile)); } return ''; From 44070b844e263b3d12ff2bea1d6ee093c171ede8 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 19:15:40 +0300 Subject: [PATCH 0240/1216] Small changes --- Protocols/Http.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 89c2bbff6..cb8b819f6 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -175,21 +175,21 @@ public static function decode($recv_buffer, TcpConnection $connection) parse_str($http_body, $_POST); break; case 'application/json': - $_POST = json_decode($http_body, true); - break; + $_POST = json_decode($http_body, true); + break; } } } - // 解析其他HTTP动作参数 + // Parse other HTTP action parameters if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { - $data = array(); - if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { - parse_str($http_body, $data); - } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { - $data = json_decode($http_body, true); - } - $_REQUEST = array_merge($_REQUEST, $data); + $data = array(); + if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { + parse_str($http_body, $data); + } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { + $data = json_decode($http_body, true); + } + $_REQUEST = array_merge($_REQUEST, $data); } // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA @@ -661,9 +661,11 @@ public static function init() if (!self::$sessionName) { self::$sessionName = ini_get('session.name'); } + if (!self::$sessionPath) { self::$sessionPath = @session_save_path(); } + if (!self::$sessionPath || strpos(self::$sessionPath, 'tcp://') === 0) { self::$sessionPath = sys_get_temp_dir(); } From 881d74e14d6f6f0307f8676f2255e045bf598ed0 Mon Sep 17 00:00:00 2001 From: Virgil-Adrian Teaca Date: Mon, 2 Apr 2018 21:34:26 +0300 Subject: [PATCH 0241/1216] Improve the Workerman\Protocols\Http --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index cb8b819f6..da6bdf2fd 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -442,7 +442,7 @@ public static function sessionStart() } HttpCache::$instance->sessionStarted = true; // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName])) { + if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName])) { // Create a unique session_id and the associated file name. while (true) { $session_id = static::sessionCreateId(); @@ -460,7 +460,7 @@ public static function sessionStart() ); } if (!HttpCache::$instance->sessionFile) { - HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/ses' . $_COOKIE[HttpCache::$sessionName]; + HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName]; } // Read session from session file. if (HttpCache::$instance->sessionFile) { From 6a711f3327dc07f05bf3e5d0efc11abe9a675d63 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 10 Apr 2018 18:31:37 +0800 Subject: [PATCH 0242/1216] Update Swoole.php --- Events/Swoole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 7945ae7af..baefdb99b 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -200,7 +200,7 @@ public function loop() */ public function destroy() { - Event::exit(); + //Event::exit(); } /** From b1d5078a424045762db7306f95b72bf167624632 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:23:01 +0800 Subject: [PATCH 0243/1216] Create Base.php --- Events/React/Base.php | 262 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 Events/React/Base.php diff --git a/Events/React/Base.php b/Events/React/Base.php new file mode 100644 index 000000000..d558b88e8 --- /dev/null +++ b/Events/React/Base.php @@ -0,0 +1,262 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events\React; +use Workerman\Events\EventInterface; +use React\EventLoop\TimerInterface; + +/** + * Class StreamSelectLoop + * @package Workerman\Events\React + */ +class Base implements \React\EventLoop\LoopInterface +{ + /** + * @var array + */ + protected $_timerIdMap = array(); + + /** + * @var int + */ + protected $_timerIdIndex = 0; + + /** + * @var array + */ + protected $_signalHandlerMap = array(); + + /** + * @var \React\EventLoop\LoopInterface + */ + protected $_eventLoop = null; + + /** + * Base constructor. + */ + public function __construct() + { + $this->_eventLoop = new \React\EventLoop\StreamSelectLoop(); + } + + /** + * Add event listener to event loop. + * + * @param $fd + * @param $flag + * @param $func + * @param array $args + * @return bool + */ + public function add($fd, $flag, $func, $args = array()) + { + $args = (array)$args; + switch ($flag) { + case EventInterface::EV_READ: + return $this->addReadStream($fd, $func); + case EventInterface::EV_WRITE: + return $this->addWriteStream($fd, $func); + case EventInterface::EV_SIGNAL: + if (isset($this->_signalHandlerMap[$fd])) { + $this->removeSignal($fd, $this->_signalHandlerMap[$fd]); + } + $this->_signalHandlerMap[$fd] = $func; + return $this->addSignal($fd, $func); + case EventInterface::EV_TIMER: + $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { + call_user_func_array($func, $args); + }); + $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; + return $this->_timerIdIndex; + case EventInterface::EV_TIMER_ONCE: + $index = ++$this->_timerIdIndex; + $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { + $this->del($index,EventInterface::EV_TIMER_ONCE); + call_user_func_array($func, $args); + }); + $this->_timerIdMap[$index] = $timer_obj; + return $this->_timerIdIndex; + } + return false; + } + + /** + * Remove event listener from event loop. + * + * @param mixed $fd + * @param int $flag + * @return bool + */ + public function del($fd, $flag) + { + switch ($flag) { + case EventInterface::EV_READ: + return $this->removeReadStream($fd); + case EventInterface::EV_WRITE: + return $this->removeWriteStream($fd); + case EventInterface::EV_SIGNAL: + if (!isset($this->_eventLoop[$fd])) { + return false; + } + $func = $this->_eventLoop[$fd]; + unset($this->_eventLoop[$fd]); + return $this->removeSignal($fd, $func); + + case EventInterface::EV_TIMER: + case EventInterface::EV_TIMER_ONCE: + if (isset($this->_timerIdMap[$fd])){ + $timer_obj = $this->_timerIdMap[$fd]; + unset($this->_timerIdMap[$fd]); + $this->cancelTimer($timer_obj); + return true; + } + } + return false; + } + + + /** + * Main loop. + * + * @return void + */ + public function loop() + { + $this->run(); + } + + + /** + * Destroy loop. + * + * @return void + */ + public function destroy() + { + + } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return count($this->_timerIdMap); + } + + /** + * @param resource $stream + * @param callable $listener + */ + public function addReadStream($stream, $listener) + { + return $this->_eventLoop->addReadStream($stream, $listener); + } + + /** + * @param resource $stream + * @param callable $listener + */ + public function addWriteStream($stream, $listener) + { + return $this->_eventLoop->addWriteStream($stream, $listener); + } + + /** + * @param resource $stream + */ + public function removeReadStream($stream) + { + return $this->_eventLoop->removeReadStream($stream); + } + + /** + * @param resource $stream + */ + public function removeWriteStream($stream) + { + return $this->_eventLoop->removeWriteStream($stream); + } + + /** + * @param float|int $interval + * @param callable $callback + * @return \React\EventLoop\Timer\Timer|TimerInterface + */ + public function addTimer($interval, $callback) + { + return $this->_eventLoop->addTimer($interval, $callback); + } + + /** + * @param float|int $interval + * @param callable $callback + * @return \React\EventLoop\Timer\Timer|TimerInterface + */ + public function addPeriodicTimer($interval, $callback) + { + return $this->_eventLoop->addPeriodicTimer($interval, $callback); + } + + /** + * @param TimerInterface $timer + */ + public function cancelTimer(TimerInterface $timer) + { + return $this->_eventLoop->cancelTimer($timer); + } + + /** + * @param callable $listener + */ + public function futureTick($listener) + { + return $this->_eventLoop->futureTick($listener); + } + + /** + * @param int $signal + * @param callable $listener + */ + public function addSignal($signal, $listener) + { + return $this->_eventLoop->addSignal($signal, $listener); + } + + /** + * @param int $signal + * @param callable $listener + */ + public function removeSignal($signal, $listener) + { + return $this->_eventLoop->removeSignal($signal, $listener); + } + + /** + * Run. + */ + public function run() + { + return $this->_eventLoop->run(); + } + + /** + * Stop. + */ + public function stop() + { + return $this->_eventLoop->stop(); + } +} From e5bcaf7ba8025c750533a08d56f7e30d2df667d2 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:23:33 +0800 Subject: [PATCH 0244/1216] Delete LibEventLoop.php --- Events/React/LibEventLoop.php | 187 ---------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 Events/React/LibEventLoop.php diff --git a/Events/React/LibEventLoop.php b/Events/React/LibEventLoop.php deleted file mode 100644 index 4db9522ea..000000000 --- a/Events/React/LibEventLoop.php +++ /dev/null @@ -1,187 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events\React; -use Workerman\Events\EventInterface; - -/** - * Class LibEventLoop - * @package Workerman\Events\React - */ -class LibEventLoop extends \React\EventLoop\LibEventLoop -{ - /** - * Event base. - * - * @var event_base resource - */ - protected $_eventBase = null; - - /** - * All signal Event instances. - * - * @var array - */ - protected $_signalEvents = array(); - - /** - * @var array - */ - protected $_timerIdMap = array(); - - /** - * @var int - */ - protected $_timerIdIndex = 0; - - /** - * Add event listener to event loop. - * - * @param $fd - * @param $flag - * @param $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, $args = array()) - { - $args = (array)$args; - switch ($flag) { - case EventInterface::EV_READ: - return $this->addReadStream($fd, $func); - case EventInterface::EV_WRITE: - return $this->addWriteStream($fd, $func); - case EventInterface::EV_SIGNAL: - return $this->addSignal($fd, $func); - case EventInterface::EV_TIMER: - $timer_id = ++$this->_timerIdIndex; - $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); - }); - $this->_timerIdMap[$timer_id] = $timer_obj; - return $timer_id; - case EventInterface::EV_TIMER_ONCE: - $timer_id = ++$this->_timerIdIndex; - $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { - unset($this->_timerIdMap[$timer_id]); - call_user_func_array($func, $args); - }); - $this->_timerIdMap[$timer_id] = $timer_obj; - return $timer_id; - } - return false; - } - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag) - { - switch ($flag) { - case EventInterface::EV_READ: - return $this->removeReadStream($fd); - case EventInterface::EV_WRITE: - return $this->removeWriteStream($fd); - case EventInterface::EV_SIGNAL: - return $this->removeSignal($fd); - case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE: - if (isset($this->_timerIdMap[$fd])){ - $timer_obj = $this->_timerIdMap[$fd]; - unset($this->_timerIdMap[$fd]); - $this->cancelTimer($timer_obj); - return true; - } - } - return false; - } - - - /** - * Main loop. - * - * @return void - */ - public function loop() - { - $this->run(); - } - - /** - * Construct. - */ - public function __construct() - { - parent::__construct(); - $class = new \ReflectionClass('\React\EventLoop\LibEventLoop'); - $property = $class->getProperty('eventBase'); - $property->setAccessible(true); - $this->_eventBase = $property->getValue($this); - } - - /** - * Add signal handler. - * - * @param $signal - * @param $callback - * @return bool - */ - public function addSignal($signal, $callback) - { - $event = event_new(); - $this->_signalEvents[$signal] = $event; - event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback); - event_base_set($event, $this->_eventBase); - event_add($event); - } - - /** - * Remove signal handler. - * - * @param $signal - */ - public function removeSignal($signal) - { - if (isset($this->_signalEvents[$signal])) { - $event = $this->_signalEvents[$signal]; - event_del($event); - unset($this->_signalEvents[$signal]); - } - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - foreach ($this->_signalEvents as $event) { - event_del($event); - } - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return count($this->_timerIdMap); - } -} From b8022598abe36d2b76f68233e0652f7286313d99 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:24:20 +0800 Subject: [PATCH 0245/1216] Create ExtLibEventLoop.php --- Events/React/ExtLibEventLoop.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Events/React/ExtLibEventLoop.php diff --git a/Events/React/ExtLibEventLoop.php b/Events/React/ExtLibEventLoop.php new file mode 100644 index 000000000..eb02b358e --- /dev/null +++ b/Events/React/ExtLibEventLoop.php @@ -0,0 +1,27 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events\React; +use Workerman\Events\EventInterface; + +/** + * Class ExtLibEventLoop + * @package Workerman\Events\React + */ +class ExtLibEventLoop extends Base +{ + public function __construct() + { + $this->_eventLoop = new \React\EventLoop\ExtLibeventLoop(); + } +} From c697350bcc1ee3c31f07c1870a31fa2a3632e693 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:24:41 +0800 Subject: [PATCH 0246/1216] Update ExtEventLoop.php --- Events/React/ExtEventLoop.php | 163 +--------------------------------- 1 file changed, 2 insertions(+), 161 deletions(-) diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php index 2a0f8b4f4..3dab25b9d 100644 --- a/Events/React/ExtEventLoop.php +++ b/Events/React/ExtEventLoop.php @@ -12,175 +12,16 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; -use Workerman\Events\EventInterface; /** * Class ExtEventLoop * @package Workerman\Events\React */ -class ExtEventLoop extends \React\EventLoop\ExtEventLoop +class ExtEventLoop extends Base { - /** - * Event base. - * - * @var EventBase - */ - protected $_eventBase = null; - /** - * All signal Event instances. - * - * @var array - */ - protected $_signalEvents = array(); - - /** - * @var array - */ - protected $_timerIdMap = array(); - - /** - * @var int - */ - protected $_timerIdIndex = 0; - - /** - * Add event listener to event loop. - * - * @param $fd - * @param $flag - * @param $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, $args = array()) - { - $args = (array)$args; - switch ($flag) { - case EventInterface::EV_READ: - return $this->addReadStream($fd, $func); - case EventInterface::EV_WRITE: - return $this->addWriteStream($fd, $func); - case EventInterface::EV_SIGNAL: - return $this->addSignal($fd, $func); - case EventInterface::EV_TIMER: - $timer_id = ++$this->_timerIdIndex; - $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); - }); - $this->_timerIdMap[$timer_id] = $timer_obj; - return $timer_id; - case EventInterface::EV_TIMER_ONCE: - $timer_id = ++$this->_timerIdIndex; - $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { - unset($this->_timerIdMap[$timer_id]); - call_user_func_array($func, $args); - }); - $this->_timerIdMap[$timer_id] = $timer_obj; - return $timer_id; - } - return false; - } - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag) - { - switch ($flag) { - case EventInterface::EV_READ: - return $this->removeReadStream($fd); - case EventInterface::EV_WRITE: - return $this->removeWriteStream($fd); - case EventInterface::EV_SIGNAL: - return $this->removeSignal($fd); - case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE: - if (isset($this->_timerIdMap[$fd])){ - $timer_obj = $this->_timerIdMap[$fd]; - unset($this->_timerIdMap[$fd]); - $this->cancelTimer($timer_obj); - return true; - } - } - return false; - } - - - /** - * Main loop. - * - * @return void - */ - public function loop() - { - $this->run(); - } - - /** - * Construct - */ public function __construct() { - parent::__construct(); - $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop'); - $property = $class->getProperty('eventBase'); - $property->setAccessible(true); - $this->_eventBase = $property->getValue($this); - } - - /** - * Add signal handler. - * - * @param $signal - * @param $callback - * @return bool - */ - public function addSignal($signal, $callback) - { - $event = \Event::signal($this->_eventBase, $signal, $callback); - if (!$event||!$event->add()) { - return false; - } - $this->_signalEvents[$signal] = $event; - } - - /** - * Remove signal handler. - * - * @param $signal - */ - public function removeSignal($signal) - { - if (isset($this->_signalEvents[$signal])) { - $this->_signalEvents[$signal]->del(); - unset($this->_signalEvents[$signal]); - } - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - foreach ($this->_signalEvents as $event) { - $event->del(); - } - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return count($this->_timerIdMap); + $this->_eventLoop = new \React\EventLoop\ExtEventLoop(); } } From ab3cad98955c339658ac3cb815c64d5fd19a7ef4 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:25:05 +0800 Subject: [PATCH 0247/1216] Update StreamSelectLoop.php --- Events/React/StreamSelectLoop.php | 166 +----------------------------- 1 file changed, 3 insertions(+), 163 deletions(-) diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php index 0c92385ba..7f5f94bda 100644 --- a/Events/React/StreamSelectLoop.php +++ b/Events/React/StreamSelectLoop.php @@ -12,175 +12,15 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; -use Workerman\Events\EventInterface; /** * Class StreamSelectLoop * @package Workerman\Events\React */ -class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop +class StreamSelectLoop extends Base { - /** - * @var array - */ - protected $_timerIdMap = array(); - - /** - * @var int - */ - protected $_timerIdIndex = 0; - - /** - * Add event listener to event loop. - * - * @param $fd - * @param $flag - * @param $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, $args = array()) - { - $args = (array)$args; - switch ($flag) { - case EventInterface::EV_READ: - return $this->addReadStream($fd, $func); - case EventInterface::EV_WRITE: - return $this->addWriteStream($fd, $func); - case EventInterface::EV_SIGNAL: - return $this->addSignal($fd, $func); - case EventInterface::EV_TIMER: - $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); - }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; - case EventInterface::EV_TIMER_ONCE: - $index = ++$this->_timerIdIndex; - $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { - $this->del($index,EventInterface::EV_TIMER_ONCE); - call_user_func_array($func, $args); - }); - $this->_timerIdMap[$index] = $timer_obj; - return $this->_timerIdIndex; - } - return false; - } - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag) - { - switch ($flag) { - case EventInterface::EV_READ: - return $this->removeReadStream($fd); - case EventInterface::EV_WRITE: - return $this->removeWriteStream($fd); - case EventInterface::EV_SIGNAL: - return $this->removeSignal($fd); - case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE: - if (isset($this->_timerIdMap[$fd])){ - $timer_obj = $this->_timerIdMap[$fd]; - unset($this->_timerIdMap[$fd]); - $this->cancelTimer($timer_obj); - return true; - } - } - return false; - } - - - /** - * Main loop. - * - * @return void - */ - public function loop() - { - $this->run(); - } - - /** - * Add signal handler. - * - * @param $signal - * @param $callback - * @return bool - */ - public function addSignal($signal, $callback) - { - if(DIRECTORY_SEPARATOR === '/') { - pcntl_signal($signal, $callback); - } - } - - /** - * Remove signal handler. - * - * @param $signal - */ - public function removeSignal($signal) - { - if(DIRECTORY_SEPARATOR === '/') { - pcntl_signal($signal, SIG_IGN); - } - } - - /** - * Emulate a stream_select() implementation that does not break when passed - * empty stream arrays. - * - * @param array &$read An array of read streams to select upon. - * @param array &$write An array of write streams to select upon. - * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. - * - * @return integer|false The total number of streams that are ready for read/write. - * Can return false if stream_select() is interrupted by a signal. - */ - protected function streamSelect(array &$read, array &$write, $timeout) - { - if ($read || $write) { - $except = null; - // Calls signal handlers for pending signals - if(DIRECTORY_SEPARATOR === '/') { - pcntl_signal_dispatch(); - } - // suppress warnings that occur, when stream_select is interrupted by a signal - return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); - } - - // Calls signal handlers for pending signals - if(DIRECTORY_SEPARATOR === '/') { - pcntl_signal_dispatch(); - } - $timeout && usleep($timeout); - - return 0; - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() + public function __construct() { - return count($this->_timerIdMap); + $this->_eventLoop = new \React\EventLoop\StreamSelectLoop(); } } From 46a77574a5ca39def6dec51ddf350cf50daab309 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:25:52 +0800 Subject: [PATCH 0248/1216] Update Worker.php --- Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 0267e80cf..518f8af8f 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.5'; + const VERSION = '3.5.6'; /** * Status starting. @@ -426,7 +426,7 @@ class Worker protected static $_availableEventLoops = array( 'libevent' => '\Workerman\Events\Libevent', 'event' => '\Workerman\Events\Event', - 'swoole' => '\Workerman\Events\Swoole' + 'swoole' => '\Workerman\Events\Swoole' ); /** @@ -1085,7 +1085,7 @@ protected static function getEventLoopName() if (interface_exists('\React\EventLoop\LoopInterface')) { switch ($loop_name) { case 'libevent': - static::$eventLoopClass = '\Workerman\Events\React\LibEventLoop'; + static::$eventLoopClass = '\Workerman\Events\React\ExtLibEventLoop'; break; case 'event': static::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop'; From e850012056b08133cd429f5814fdf88edc805fb1 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Apr 2018 19:45:04 +0800 Subject: [PATCH 0249/1216] Update README.md --- README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 41e708635..c0d4ddb3a 100644 --- a/README.md +++ b/README.md @@ -406,23 +406,15 @@ use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:6161'); -$worker->onWorkerStart = function() { - global $client; - $loop = Worker::getEventLoop(); - $factory = new React\Dns\Resolver\Factory(); - $dns = $factory->createCached('8.8.8.8', $loop); - $factory = new React\HttpClient\Factory(); - $client = $factory->create($loop, $dns); -}; - $worker->onMessage = function($connection, $host) { - global $client; + $loop = Worker::getEventLoop(); + $client = new \React\HttpClient\Client($loop); $request = $client->request('GET', trim($host)); $request->on('error', function(Exception $e) use ($connection) { $connection->send($e); }); $request->on('response', function ($response) use ($connection) { - $response->on('data', function ($data, $response) use ($connection) { + $response->on('data', function ($data) use ($connection) { $connection->send($data); }); }); From 7932b3008d55f7b249f03162f9c99dbcfa06938d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 12 Apr 2018 13:31:24 +0800 Subject: [PATCH 0250/1216] Update Worker.php --- Worker.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 518f8af8f..34086d8aa 100644 --- a/Worker.php +++ b/Worker.php @@ -1315,7 +1315,13 @@ protected static function forkOneWorkerForLinux($worker) static::resetStd(); } static::$_pidMap = array(); - static::$_workers = array($worker->workerId => $worker); + // Remove other listener. + foreach(static::$_workers as $key => $one_worker) { + if ($one_worker->workerId !== $worker->workerId) { + $one_worker->unlisten(); + unset(static::$_workers[$key]); + } + } Timer::delAll(); static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); From f0546bc6c078b040b34668b1e0629d2343118929 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 20 Apr 2018 22:39:31 +0800 Subject: [PATCH 0251/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 34086d8aa..a193c6f0f 100644 --- a/Worker.php +++ b/Worker.php @@ -1163,7 +1163,7 @@ protected static function forkWorkersForLinux() * * @return void */ - public static function forkWorkersForWindows() + protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; From c7ebfa7af8d81b126087f6083df7d94a9ef63a9e Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 10:40:04 +0800 Subject: [PATCH 0252/1216] Add commands error --- Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Worker.php b/Worker.php index a193c6f0f..94807c45e 100644 --- a/Worker.php +++ b/Worker.php @@ -810,6 +810,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : + echo 'Unknow command: ' . $command . '\n'; exit($usage); } } From 82d1ff85e94a7a2eac88a58d42c31829273a7678 Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 10:50:01 +0800 Subject: [PATCH 0253/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 94807c45e..7696484d7 100644 --- a/Worker.php +++ b/Worker.php @@ -810,7 +810,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - echo 'Unknow command: ' . $command . '\n'; + fputs(STDERR, 'Unknow command: ' . $command . '\n'); exit($usage); } } From b54a8872ad6109c42b3c7a8e2a297ed11abec106 Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 10:53:51 +0800 Subject: [PATCH 0254/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 7696484d7..94807c45e 100644 --- a/Worker.php +++ b/Worker.php @@ -810,7 +810,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - fputs(STDERR, 'Unknow command: ' . $command . '\n'); + echo 'Unknow command: ' . $command . '\n'; exit($usage); } } From f0353ed6136803fe92fb0d67f3b4d2acd26fae2f Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 10:57:27 +0800 Subject: [PATCH 0255/1216] Update Worker.php --- Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 94807c45e..dce283bec 100644 --- a/Worker.php +++ b/Worker.php @@ -690,6 +690,7 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { + echo 'Unknown command: ' . $argv[1] . '\n'; exit($usage); } @@ -810,7 +811,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - echo 'Unknow command: ' . $command . '\n'; + echo 'Unknown command: ' . $command . '\n'; exit($usage); } } From 0a3fc0d58e129bc7466839420fb456f484f4b0c1 Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 10:59:21 +0800 Subject: [PATCH 0256/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index dce283bec..ad6685628 100644 --- a/Worker.php +++ b/Worker.php @@ -690,7 +690,7 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - echo 'Unknown command: ' . $argv[1] . '\n'; + echo 'Unknown command: ' . $argv[1] . "\n"; exit($usage); } @@ -811,7 +811,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - echo 'Unknown command: ' . $command . '\n'; + echo 'Unknown command: ' . $command . "\n"; exit($usage); } } From 8789ff43011fb7d3a92a74c7180bfcf7ace6588c Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 11:04:07 +0800 Subject: [PATCH 0257/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ad6685628..1d2a0f84e 100644 --- a/Worker.php +++ b/Worker.php @@ -690,7 +690,7 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - echo 'Unknown command: ' . $argv[1] . "\n"; + if(isset($argv[1])) echo 'Unknown command: ' . $argv[1] . "\n"; exit($usage); } From 7c7c6e7d78e9337c75c9fdb73487a32979f6536f Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 11:05:35 +0800 Subject: [PATCH 0258/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 1d2a0f84e..2cceda6e0 100644 --- a/Worker.php +++ b/Worker.php @@ -811,7 +811,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - echo 'Unknown command: ' . $command . "\n"; + if(isset($command)) echo 'Unknown command: ' . $command . "\n"; exit($usage); } } From 8afc8d731d0aa2818c10714195de982c14e181bf Mon Sep 17 00:00:00 2001 From: ishland Date: Sat, 5 May 2018 11:08:02 +0800 Subject: [PATCH 0259/1216] Add command error report --- Worker.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 2cceda6e0..8ef9d5233 100644 --- a/Worker.php +++ b/Worker.php @@ -668,7 +668,6 @@ protected static function displayUI() /** * Parse command. - * php yourfile.php start | stop | restart | reload | status [-d] * * @return void */ @@ -690,7 +689,7 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - if(isset($argv[1])) echo 'Unknown command: ' . $argv[1] . "\n"; + if (isset($argv[1])) echo 'Unknown command: ' . $argv[1] . "\n"; exit($usage); } @@ -811,7 +810,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - if(isset($command)) echo 'Unknown command: ' . $command . "\n"; + if (isset($command)) echo 'Unknown command: ' . $command . "\n"; exit($usage); } } From 95926ddca84c58cd9e318b7d8c19c5e3d0b6f702 Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Mon, 7 May 2018 12:06:51 +0300 Subject: [PATCH 0260/1216] Fix error without content type When I made a request `curl -v 'http://localhost:9999/'`, I got an error `Notice: Undefined index: HTTP_CONTENT_TYPE`. --- Protocols/Http.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index da6bdf2fd..644cd99a4 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -106,6 +106,7 @@ public static function decode($recv_buffer, TcpConnection $connection) 'HTTP_ACCEPT_ENCODING' => '', 'HTTP_COOKIE' => '', 'HTTP_CONNECTION' => '', + 'CONTENT_TYPE' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', 'REQUEST_TIME' => time() @@ -184,9 +185,9 @@ public static function decode($recv_buffer, TcpConnection $connection) // Parse other HTTP action parameters if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { $data = array(); - if ($_SERVER['HTTP_CONTENT_TYPE'] === "application/x-www-form-urlencoded") { + if ($_SERVER['CONTENT_TYPE'] === "application/x-www-form-urlencoded") { parse_str($http_body, $data); - } elseif ($_SERVER['HTTP_CONTENT_TYPE'] === "application/json") { + } elseif ($_SERVER['CONTENT_TYPE'] === "application/json") { $data = json_decode($http_body, true); } $_REQUEST = array_merge($_REQUEST, $data); From 46ede6d6d4361adee3bee66afe0f30ac4883a6c1 Mon Sep 17 00:00:00 2001 From: zqhong Date: Wed, 9 May 2018 19:37:20 +0800 Subject: [PATCH 0261/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 8ef9d5233..370c58655 100644 --- a/Worker.php +++ b/Worker.php @@ -1836,7 +1836,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN != static::$_status) { - $error_msg = static::$_OS === 'linx' ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; + $error_msg = static::$_OS === 'linux' ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || From fe53bc2695776f61796e06d9c8c9d82bf508e717 Mon Sep 17 00:00:00 2001 From: zqhong Date: Thu, 10 May 2018 18:18:02 +0800 Subject: [PATCH 0262/1216] improve --- Lib/Constants.php | 4 ++++ Worker.php | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 2f9d3dfcc..5048a3970 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -31,6 +31,10 @@ // For onError callback. define('WORKERMAN_SEND_FAIL', 2); +// Define OS Type +define('OS_TYPE_LINUX', 'linux'); +define('OS_TYPE_WINDOWS', 'windows'); + // Compatible with php7 if(!class_exists('Error')) { diff --git a/Worker.php b/Worker.php index 370c58655..189e6d67a 100644 --- a/Worker.php +++ b/Worker.php @@ -399,7 +399,7 @@ class Worker * * @var string */ - protected static $_OS = 'linux'; + protected static $_OS = OS_TYPE_LINUX; /** * Processes for windows. @@ -480,7 +480,7 @@ protected static function checkSapiEnv() exit("only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { - self::$_OS = 'windows'; + self::$_OS = OS_TYPE_WINDOWS; } } @@ -537,7 +537,7 @@ protected static function init() */ protected static function initWorkers() { - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { return; } foreach (static::$_workers as $worker) { @@ -638,7 +638,7 @@ protected static function displayUI() if (in_array('-q', $argv)) { return; } - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); @@ -673,7 +673,7 @@ protected static function displayUI() */ protected static function parseCommand() { - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { return; } global $argv; @@ -902,7 +902,7 @@ protected static function formatStatusData() */ protected static function installSignal() { - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { return; } // stop @@ -928,7 +928,7 @@ protected static function installSignal() */ protected static function reinstallSignal() { - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { return; } // uninstall stop signal handler @@ -1002,7 +1002,7 @@ public static function signalHandler($signal) */ protected static function daemonize() { - if (!static::$daemonize || static::$_OS !== 'linux') { + if (!static::$daemonize || static::$_OS !== OS_TYPE_LINUX) { return; } umask(0); @@ -1031,7 +1031,7 @@ protected static function daemonize() */ public static function resetStd() { - if (!static::$daemonize || static::$_OS !== 'linux') { + if (!static::$daemonize || static::$_OS !== OS_TYPE_LINUX) { return; } global $STDOUT, $STDERR; @@ -1054,7 +1054,7 @@ public static function resetStd() */ protected static function saveMasterPid() { - if (static::$_OS !== 'linux') { + if (static::$_OS !== OS_TYPE_LINUX) { return; } static::$_masterPid = posix_getpid(); @@ -1127,7 +1127,7 @@ protected static function getAllWorkerPids() */ protected static function forkWorkers() { - if (static::$_OS === 'linux') { + if (static::$_OS === OS_TYPE_LINUX) { static::forkWorkersForLinux(); } else { static::forkWorkersForWindows(); @@ -1407,7 +1407,7 @@ protected static function setProcessTitle($title) */ protected static function monitorWorkers() { - if (static::$_OS === 'linux') { + if (static::$_OS === OS_TYPE_LINUX) { static::monitorWorkersForLinux(); } else { static::monitorWorkersForWindows(); @@ -1836,7 +1836,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN != static::$_status) { - $error_msg = static::$_OS === 'linux' ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; + $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || @@ -1906,7 +1906,7 @@ public static function log($msg) static::safeEcho($msg); } file_put_contents((string)static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' - . (static::$_OS === 'linux' ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); + . (static::$_OS === OS_TYPE_LINUX ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** From 7c2e10ed8dfff11d6c01351bef9135fe62ad34cc Mon Sep 17 00:00:00 2001 From: malacca Date: Wed, 16 May 2018 11:45:07 +0800 Subject: [PATCH 0263/1216] forced stop master process all worker process maybe has exit, but master process still can not stop, check worker running status and stop master process --- Worker.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 189e6d67a..aee851b20 100644 --- a/Worker.php +++ b/Worker.php @@ -1421,6 +1421,7 @@ protected static function monitorWorkers() */ protected static function monitorWorkersForLinux() { + $checkTimes = 0; static::$_status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. @@ -1432,6 +1433,8 @@ protected static function monitorWorkersForLinux() pcntl_signal_dispatch(); // If a child has already exited. if ($pid > 0) { + // reset $checkTimes + $checkTimes = 0; // Find out witch worker process exited. foreach (static::$_pidMap as $worker_id => $worker_pid_array) { if (isset($worker_pid_array[$pid])) { @@ -1472,9 +1475,26 @@ protected static function monitorWorkersForLinux() } } } else { + // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { - static::exitAndClearAll(); + if (static::$_status === static::STATUS_SHUTDOWN) { + $pids = static::getAllWorkerPids(); + if (!$pids) { + static::exitAndClearAll(); + } elseif ($checkTimes > 500) { + // forced stop if all pid exited + $allExited = true; + foreach ($pids as $pid) { + if (posix_kill($pid, 0)) { + $allExited = false; + break; + } + } + if ($allExited) { + static::exitAndClearAll(); + } + } + $checkTimes++; } } } From b4ea13b0ebea470f9687c83070e32e0c20ae1728 Mon Sep 17 00:00:00 2001 From: malacca Date: Sat, 19 May 2018 18:24:56 +0800 Subject: [PATCH 0264/1216] remove argv extension check may be start file not have .php extension --- Worker.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Worker.php b/Worker.php index aee851b20..c0402f278 100644 --- a/Worker.php +++ b/Worker.php @@ -1211,11 +1211,6 @@ public static function getStartFilesForWindows() { $files = array(); foreach($argv as $file) { - $ext = pathinfo($file, PATHINFO_EXTENSION ); - if($ext !== 'php') - { - continue; - } if(is_file($file)) { $files[$file] = $file; From 2dacceeef7468ea93c6b09aa8cc96c06cb665fac Mon Sep 17 00:00:00 2001 From: malacca Date: Sun, 20 May 2018 12:00:03 +0800 Subject: [PATCH 0265/1216] reset checkTimes --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index c0402f278..7b6cc6f51 100644 --- a/Worker.php +++ b/Worker.php @@ -1487,6 +1487,8 @@ protected static function monitorWorkersForLinux() } if ($allExited) { static::exitAndClearAll(); + } else { + $checkTimes = 0; } } $checkTimes++; From e529adb70519ba0ef36f701fefd914a73ed44421 Mon Sep 17 00:00:00 2001 From: malacca Date: Sun, 20 May 2018 18:44:08 +0800 Subject: [PATCH 0266/1216] improve saveEcho method --- Worker.php | 122 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 22 deletions(-) diff --git a/Worker.php b/Worker.php index 7b6cc6f51..67643c671 100644 --- a/Worker.php +++ b/Worker.php @@ -447,6 +447,18 @@ class Worker * @var string */ protected static $_gracefulStop = false; + + /** + * output stream + * @var resource + */ + protected static $outputStream = null; + + /** + * if output stream support decorated + * @var bool + */ + protected static $outputDecorated = false; /** * Run all worker instances. @@ -645,18 +657,18 @@ protected static function displayUI() static::safeEcho("worker listen processes status\r\n"); return; } - static::safeEcho("\033[1A\n\033[K-----------------------\033[47;30m WORKERMAN \033[0m-----------------------------\r\n\033[0m"); + static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); - static::safeEcho("------------------------\033[47;30m WORKERS \033[0m-------------------------------\r\n"); - static::safeEcho("\033[47;30muser\033[0m". str_pad('', - static::$_maxUserNameLength + 2 - strlen('user')). "\033[47;30mworker\033[0m". str_pad('', - static::$_maxWorkerNameLength + 2 - strlen('worker')). "\033[47;30mlisten\033[0m". str_pad('', - static::$_maxSocketNameLength + 2 - strlen('listen')). "\033[47;30mprocesses\033[0m \033[47;30m". "status\033[0m\n"); + static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); + static::safeEcho("user". str_pad('', + static::$_maxUserNameLength + 2 - strlen('user')). "worker". str_pad('', + static::$_maxWorkerNameLength + 2 - strlen('worker')). "listen". str_pad('', + static::$_maxSocketNameLength + 2 - strlen('listen')). "processes status\n"); foreach (static::$_workers as $worker) { static::safeEcho(str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, static::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), - static::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " \033[32;40m [OK] \033[0m\n"); + static::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " [OK] \n"); } static::safeEcho("----------------------------------------------------------------\n"); if (static::$daemonize) { @@ -689,7 +701,7 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - if (isset($argv[1])) echo 'Unknown command: ' . $argv[1] . "\n"; + if (isset($argv[1])) static::safeEcho('Unknown command: ' . $argv[1] . "\n"); exit($usage); } @@ -740,14 +752,14 @@ protected static function parseCommand() sleep(1); // Clear terminal. if ($command2 === '-d') { - echo "\33[H\33[2J\33(B\33[m"; + static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - echo static::formatStatusData(); + static::safeEcho(static::formatStatusData()); if ($command2 !== '-d') { exit(0); } - echo "\nPress Ctrl+C to quit.\n\n"; + static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } exit(0); case 'connections': @@ -810,7 +822,7 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - if (isset($command)) echo 'Unknown command: ' . $command . "\n"; + if (isset($command)) static::safeEcho('Unknown command: ' . $command . "\n"); exit($usage); } } @@ -1172,8 +1184,8 @@ protected static function forkWorkersForWindows() { if(count(static::$_workers) > 1) { - echo "@@@ Error: multi workers init in one php file are not support @@@\r\n"; - echo "@@@ Please visit http://wiki.workerman.net/Multi_woker_for_win @@@\r\n"; + static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); + static::safeEcho("@@@ Please visit http://wiki.workerman.net/Multi_woker_for_win @@@\r\n"); } elseif(count(static::$_workers) <= 0) { @@ -1185,7 +1197,7 @@ protected static function forkWorkersForWindows() $worker = current(static::$_workers); // Display UI. - echo str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"; + static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); @@ -1247,7 +1259,7 @@ public static function forkOneWorkerForWindows($start_file) } $timer_id = Timer::add(1, function()use($std_handler) { - echo fread($std_handler, 65535); + static::safeEcho(fread($std_handler, 65535)); }); // 保存子进程句柄 @@ -1270,7 +1282,7 @@ public static function checkWorkerStatusForWindows() { if(!$status['running']) { - echo "process $start_file terminated and try to restart\n"; + static::safeEcho("process $start_file terminated and try to restart\n"); Timer::del($timer_id); @proc_close($process); static::forkOneWorkerForWindows($start_file); @@ -1278,7 +1290,7 @@ public static function checkWorkerStatusForWindows() } else { - echo "proc_get_status fail\n"; + static::safeEcho("proc_get_status fail\n"); } } } @@ -1928,14 +1940,80 @@ public static function log($msg) /** * Safe Echo. - * * @param $msg + * @param bool $decorated */ - public static function safeEcho($msg) + public static function safeEcho($msg, $decorated = false) { - if (!function_exists('posix_isatty') || posix_isatty(STDOUT)) { - echo $msg; + $stream = static::getOutputStream(); + if (!$decorated) { + $line = $white = $green = $end = ''; + if (static::$outputDecorated) { + $line = "\033[1A\n\033[K"; + $white = "\033[47;30m"; + $green = "\033[32;40m"; + $end = "\033[0m"; + } + $msg = str_replace('', $line, $msg); + $msg = str_replace('', $white, $msg); + $msg = str_replace('', $green, $msg); + $msg = str_replace(['', '', ''], $end, $msg); + } elseif (!static::$outputDecorated) { + return; } + fwrite($stream, $msg); + fflush($stream); + } + + /** + * get output stream + * @return bool|null|resource + */ + protected static function getOutputStream() + { + if (static::$outputStream) { + return static::$outputStream; + } + $stream = !static::isRunningOS400() ? @fopen('php://stdout', 'w') : null; + if (!$stream) { + $stream = fopen('php://output', 'w'); + } + $stat = fstat($stream); + if (($stat['mode'] & 0170000) === 0100000) { + // output to file + static::$outputDecorated = false; + } elseif (false !== getenv('BABUN_HOME')) { + // win Babun + static::$outputDecorated = true; + } elseif (static::$_OS === OS_TYPE_LINUX) { + // linux + static::$outputDecorated = function_exists('posix_isatty') && @posix_isatty($stream); + } else { + // window + static::$outputDecorated = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || stripos(getenv('TERM'), 'xterm') === 0; + } + return static::$outputStream = $stream; + } + + /** + * Checks if current executing environment is IBM iSeries (OS400), which + * doesn't properly convert character-encodings between ASCII to EBCDIC. + * Licensed under the MIT/X11 License (http://opensource.org/licenses/MIT) + * (c) Fabien Potencier + * @see https://github.com/symfony/console/blob/master/Output/ConsoleOutput.php#L121 + * @return bool + */ + private static function isRunningOS400() + { + $checks = array( + function_exists('php_uname') ? php_uname('s') : '', + getenv('OSTYPE'), + PHP_OS, + ); + return false !== stripos(implode(';', $checks), 'OS400'); } /** From 04be7185eb06687684b1dbed96bd113309f5949d Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 13:53:29 +0800 Subject: [PATCH 0267/1216] improve safeEcho method --- Worker.php | 133 +++++++++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 70 deletions(-) diff --git a/Worker.php b/Worker.php index 67643c671..9dc0d3478 100644 --- a/Worker.php +++ b/Worker.php @@ -230,7 +230,7 @@ class Worker * @var bool */ protected $_pauseAccept = true; - + /** * Is worker stopping ? * @var bool @@ -447,18 +447,18 @@ class Worker * @var string */ protected static $_gracefulStop = false; - + /** - * output stream + * standard output stream * @var resource */ protected static $outputStream = null; /** - * if output stream support decorated + * if $outputStream support decorated * @var bool */ - protected static $outputDecorated = false; + protected static $outputDecorated = null; /** * Run all worker instances. @@ -664,7 +664,6 @@ protected static function displayUI() static::$_maxUserNameLength + 2 - strlen('user')). "worker". str_pad('', static::$_maxWorkerNameLength + 2 - strlen('worker')). "listen". str_pad('', static::$_maxSocketNameLength + 2 - strlen('listen')). "processes status\n"); - foreach (static::$_workers as $worker) { static::safeEcho(str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, static::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), @@ -701,7 +700,9 @@ protected static function parseCommand() ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { - if (isset($argv[1])) static::safeEcho('Unknown command: ' . $argv[1] . "\n"); + if (isset($argv[1])) { + static::safeEcho('Unknown command: ' . $argv[1] . "\n"); + } exit($usage); } @@ -752,14 +753,14 @@ protected static function parseCommand() sleep(1); // Clear terminal. if ($command2 === '-d') { - static::safeEcho("\33[H\33[2J\33(B\33[m", true); + static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - static::safeEcho(static::formatStatusData()); + self::safeEcho(static::formatStatusData()); if ($command2 !== '-d') { exit(0); } - static::safeEcho("\nPress Ctrl+C to quit.\n\n"); + self::safeEcho("\nPress Ctrl+C to quit.\n\n"); } exit(0); case 'connections': @@ -822,7 +823,9 @@ protected static function parseCommand() posix_kill($master_pid, $sig); exit; default : - if (isset($command)) static::safeEcho('Unknown command: ' . $command . "\n"); + if (isset($command)) { + static::safeEcho('Unknown command: ' . $command . "\n"); + } exit($usage); } } @@ -846,14 +849,14 @@ protected static function formatStatusData() unset($info[0]); $data_waiting_sort = array(); $read_process_status = false; - $total_requests = 0; - $total_qps = 0; - $total_connections = 0; - $total_fails = 0; - $total_memory = 0; - $total_timers = 0; - $maxLen1 = static::$_maxSocketNameLength; - $maxLen2 = static::$_maxWorkerNameLength; + $total_requests = 0; + $total_qps = 0; + $total_connections = 0; + $total_fails = 0; + $total_memory = 0; + $total_timers = 0; + $maxLen1 = static::$_maxSocketNameLength; + $maxLen2 = static::$_maxWorkerNameLength; foreach($info as $key => $value) { if (!$read_process_status) { $status_str .= $value . "\n"; @@ -866,14 +869,14 @@ protected static function formatStatusData() $pid = $pid_math[0]; $data_waiting_sort[$pid] = $value; if(preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $total_memory += intval(str_ireplace('M','',$match[1])); - $maxLen1 = max($maxLen1,strlen($match[2])); - $maxLen2 = max($maxLen2,strlen($match[3])); - $total_connections += intval($match[4]); - $total_fails += intval($match[5]); - $total_timers += intval($match[6]); + $total_memory += intval(str_ireplace('M','',$match[1])); + $maxLen1 = max($maxLen1,strlen($match[2])); + $maxLen2 = max($maxLen2,strlen($match[3])); + $total_connections += intval($match[4]); + $total_fails += intval($match[5]); + $total_timers += intval($match[6]); $current_total_request[$pid] = $match[7]; - $total_requests += intval($match[7]); + $total_requests += intval($match[7]); } } } @@ -891,18 +894,18 @@ protected static function formatStatusData() $qps = 0; } else { $qps = $current_total_request[$pid] - $total_request_cache[$pid]; - $total_qps += $qps; + $total_qps += $qps; } $status_str .= $data_waiting_sort[$pid]. " " . str_pad($qps, 6) ." [idle]\n"; } $total_request_cache = $current_total_request; - $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $status_str .= "Summary\t" . str_pad($total_memory.'M', 7) . " " - . str_pad('-', $maxLen1) . " " - . str_pad('-', $maxLen2) . " " - . str_pad($total_connections, 11) . " " . str_pad($total_fails, 9) . " " - . str_pad($total_timers, 7) . " " . str_pad($total_requests, 13) . " " - . str_pad($total_qps,6)." [Summary] \n"; + $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; + $status_str .= "Summary\t" . str_pad($total_memory.'M', 7) . " " + . str_pad('-', $maxLen1) . " " + . str_pad('-', $maxLen2) . " " + . str_pad($total_connections, 11) . " " . str_pad($total_fails, 9) . " " + . str_pad($total_timers, 7) . " " . str_pad($total_requests, 13) . " " + . str_pad($total_qps,6)." [Summary] \n"; return $status_str; } @@ -1054,6 +1057,7 @@ public static function resetStd() @fclose(STDERR); $STDOUT = fopen(static::$stdoutFile, "a"); $STDERR = fopen(static::$stdoutFile, "a"); + static::$outputStream = static::$outputDecorated = null; } else { throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } @@ -1197,7 +1201,7 @@ protected static function forkWorkersForWindows() $worker = current(static::$_workers); // Display UI. - static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"); + static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); @@ -1259,7 +1263,7 @@ public static function forkOneWorkerForWindows($start_file) } $timer_id = Timer::add(1, function()use($std_handler) { - static::safeEcho(fread($std_handler, 65535)); + self::safeEcho(fread($std_handler, 65535)); }); // 保存子进程句柄 @@ -1282,7 +1286,7 @@ public static function checkWorkerStatusForWindows() { if(!$status['running']) { - static::safeEcho("process $start_file terminated and try to restart\n"); + static::safeEcho("process $start_file terminated and try to restart\n"); Timer::del($timer_id); @proc_close($process); static::forkOneWorkerForWindows($start_file); @@ -1428,7 +1432,6 @@ protected static function monitorWorkers() */ protected static function monitorWorkersForLinux() { - $checkTimes = 0; static::$_status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. @@ -1440,8 +1443,6 @@ protected static function monitorWorkersForLinux() pcntl_signal_dispatch(); // If a child has already exited. if ($pid > 0) { - // reset $checkTimes - $checkTimes = 0; // Find out witch worker process exited. foreach (static::$_pidMap as $worker_id => $worker_pid_array) { if (isset($worker_pid_array[$pid])) { @@ -1482,28 +1483,9 @@ protected static function monitorWorkersForLinux() } } } else { - // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN) { - $pids = static::getAllWorkerPids(); - if (!$pids) { - static::exitAndClearAll(); - } elseif ($checkTimes > 500) { - // forced stop if all pid exited - $allExited = true; - foreach ($pids as $pid) { - if (posix_kill($pid, 0)) { - $allExited = false; - break; - } - } - if ($allExited) { - static::exitAndClearAll(); - } else { - $checkTimes = 0; - } - } - $checkTimes++; + if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + static::exitAndClearAll(); } } } @@ -1658,6 +1640,16 @@ public static function stopAll() Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); } } + // check if child processes is really running + Timer::add(1, function() { + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + foreach ($worker_pid_array as $pid => $worker_pid) { + if (!posix_kill($pid, 0)) { + unset(static::$_pidMap[$worker_id][$pid]); + } + } + } + }); // Remove statistics file. if (is_file(static::$_statisticsFile)) { @unlink(static::$_statisticsFile); @@ -1946,6 +1938,9 @@ public static function log($msg) public static function safeEcho($msg, $decorated = false) { $stream = static::getOutputStream(); + if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) { + return; + } if (!$decorated) { $line = $white = $green = $end = ''; if (static::$outputDecorated) { @@ -1954,9 +1949,7 @@ public static function safeEcho($msg, $decorated = false) $green = "\033[32;40m"; $end = "\033[0m"; } - $msg = str_replace('', $line, $msg); - $msg = str_replace('', $white, $msg); - $msg = str_replace('', $green, $msg); + $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); $msg = str_replace(['', '', ''], $end, $msg); } elseif (!static::$outputDecorated) { return; @@ -1980,10 +1973,10 @@ protected static function getOutputStream() } $stat = fstat($stream); if (($stat['mode'] & 0170000) === 0100000) { - // output to file + // file static::$outputDecorated = false; } elseif (false !== getenv('BABUN_HOME')) { - // win Babun + // Babun static::$outputDecorated = true; } elseif (static::$_OS === OS_TYPE_LINUX) { // linux @@ -1991,9 +1984,9 @@ protected static function getOutputStream() } else { // window static::$outputDecorated = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || stripos(getenv('TERM'), 'xterm') === 0; + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || stripos(getenv('TERM'), 'xterm') === 0; } return static::$outputStream = $stream; } @@ -2003,7 +1996,7 @@ protected static function getOutputStream() * doesn't properly convert character-encodings between ASCII to EBCDIC. * Licensed under the MIT/X11 License (http://opensource.org/licenses/MIT) * (c) Fabien Potencier - * @see https://github.com/symfony/console/blob/master/Output/ConsoleOutput.php#L121 + * @see https://github.com/symfony/console/blob/master/Output/ConsoleOutput.php#L131 * @return bool */ private static function isRunningOS400() From 935a5746287574e93aa89612d4d3d03393c860f1 Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 14:01:25 +0800 Subject: [PATCH 0268/1216] compatible stdoutFile --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 9dc0d3478..336dd2ab6 100644 --- a/Worker.php +++ b/Worker.php @@ -455,7 +455,7 @@ class Worker protected static $outputStream = null; /** - * if $outputStream support decorated + * if outputStream support decorated * @var bool */ protected static $outputDecorated = null; From 0e63bf1340721dc622aaa2b3f17a459ee2a86f15 Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 14:27:25 +0800 Subject: [PATCH 0269/1216] compatible php7 lower --- Worker.php | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/Worker.php b/Worker.php index 336dd2ab6..a23fd6349 100644 --- a/Worker.php +++ b/Worker.php @@ -452,13 +452,13 @@ class Worker * standard output stream * @var resource */ - protected static $outputStream = null; + protected static $_outputStream = null; /** - * if outputStream support decorated + * if $outputStream support decorated * @var bool */ - protected static $outputDecorated = null; + protected static $_outputDecorated = null; /** * Run all worker instances. @@ -1057,7 +1057,7 @@ public static function resetStd() @fclose(STDERR); $STDOUT = fopen(static::$stdoutFile, "a"); $STDERR = fopen(static::$stdoutFile, "a"); - static::$outputStream = static::$outputDecorated = null; + static::$_outputStream = static::$_outputDecorated = null; } else { throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } @@ -1640,16 +1640,7 @@ public static function stopAll() Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); } } - // check if child processes is really running - Timer::add(1, function() { - foreach (static::$_pidMap as $worker_id => $worker_pid_array) { - foreach ($worker_pid_array as $pid => $worker_pid) { - if (!posix_kill($pid, 0)) { - unset(static::$_pidMap[$worker_id][$pid]); - } - } - } - }); + Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); // Remove statistics file. if (is_file(static::$_statisticsFile)) { @unlink(static::$_statisticsFile); @@ -1671,6 +1662,20 @@ public static function stopAll() } } + /** + * check if child processes is really running + */ + public static function checkIfChildRunning() + { + foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + foreach ($worker_pid_array as $pid => $worker_pid) { + if (!posix_kill($pid, 0)) { + unset(static::$_pidMap[$worker_id][$pid]); + } + } + } + } + /** * Get process status. * @@ -1943,7 +1948,7 @@ public static function safeEcho($msg, $decorated = false) } if (!$decorated) { $line = $white = $green = $end = ''; - if (static::$outputDecorated) { + if (static::$_outputDecorated) { $line = "\033[1A\n\033[K"; $white = "\033[47;30m"; $green = "\033[32;40m"; @@ -1951,7 +1956,7 @@ public static function safeEcho($msg, $decorated = false) } $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); $msg = str_replace(['', '', ''], $end, $msg); - } elseif (!static::$outputDecorated) { + } elseif (!static::$_outputDecorated) { return; } fwrite($stream, $msg); @@ -1964,8 +1969,8 @@ public static function safeEcho($msg, $decorated = false) */ protected static function getOutputStream() { - if (static::$outputStream) { - return static::$outputStream; + if (static::$_outputStream) { + return static::$_outputStream; } $stream = !static::isRunningOS400() ? @fopen('php://stdout', 'w') : null; if (!$stream) { @@ -1974,21 +1979,21 @@ protected static function getOutputStream() $stat = fstat($stream); if (($stat['mode'] & 0170000) === 0100000) { // file - static::$outputDecorated = false; + static::$_outputDecorated = false; } elseif (false !== getenv('BABUN_HOME')) { // Babun - static::$outputDecorated = true; + static::$_outputDecorated = true; } elseif (static::$_OS === OS_TYPE_LINUX) { // linux - static::$outputDecorated = function_exists('posix_isatty') && @posix_isatty($stream); + static::$_outputDecorated = function_exists('posix_isatty') && @posix_isatty($stream); } else { // window - static::$outputDecorated = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD + static::$_outputDecorated = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || stripos(getenv('TERM'), 'xterm') === 0; } - return static::$outputStream = $stream; + return static::$_outputStream = $stream; } /** From 538d1ed9ede7d9cc4ba5436b4db28a537d31d115 Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 15:00:40 +0800 Subject: [PATCH 0270/1216] improve win colorful verification --- Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a23fd6349..0956217e3 100644 --- a/Worker.php +++ b/Worker.php @@ -1988,7 +1988,8 @@ protected static function getOutputStream() static::$_outputDecorated = function_exists('posix_isatty') && @posix_isatty($stream); } else { // window - static::$_outputDecorated = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD + static::$_outputDecorated = + (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support($stream)) || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || stripos(getenv('TERM'), 'xterm') === 0; From 81cb3aa2c17fda7a3b4e5529c323b9e4418c0a5c Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 15:51:12 +0800 Subject: [PATCH 0271/1216] improve safeEcho method --- Worker.php | 82 ++++++++++++++---------------------------------------- 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/Worker.php b/Worker.php index 0956217e3..8a8fd5421 100644 --- a/Worker.php +++ b/Worker.php @@ -756,11 +756,11 @@ protected static function parseCommand() static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - self::safeEcho(static::formatStatusData()); + static::safeEcho(static::formatStatusData()); if ($command2 !== '-d') { exit(0); } - self::safeEcho("\nPress Ctrl+C to quit.\n\n"); + static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } exit(0); case 'connections': @@ -1263,7 +1263,7 @@ public static function forkOneWorkerForWindows($start_file) } $timer_id = Timer::add(1, function()use($std_handler) { - self::safeEcho(fread($std_handler, 65535)); + Worker::safeEcho(fread($std_handler, 65535)); }); // 保存子进程句柄 @@ -1942,8 +1942,20 @@ public static function log($msg) */ public static function safeEcho($msg, $decorated = false) { - $stream = static::getOutputStream(); - if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) { + if (!static::$_outputStream) { + static::$_outputStream = STDOUT; + $stat = fstat(static::$_outputStream); + if (($stat['mode'] & 0170000) === 0100000) { + // file + static::$_outputDecorated = false; + } else { + static::$_outputDecorated = + static::$_OS === OS_TYPE_LINUX && + function_exists('posix_isatty') && + @posix_isatty(static::$_outputStream); + } + } + if (!is_resource(static::$_outputStream) || 'stream' !== get_resource_type(static::$_outputStream)) { return; } if (!$decorated) { @@ -1954,65 +1966,13 @@ public static function safeEcho($msg, $decorated = false) $green = "\033[32;40m"; $end = "\033[0m"; } - $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); - $msg = str_replace(['', '', ''], $end, $msg); + $msg = str_replace(array('', '', ''), array($line, $white, $green), $msg); + $msg = str_replace(array('', '', ''), $end, $msg); } elseif (!static::$_outputDecorated) { return; } - fwrite($stream, $msg); - fflush($stream); - } - - /** - * get output stream - * @return bool|null|resource - */ - protected static function getOutputStream() - { - if (static::$_outputStream) { - return static::$_outputStream; - } - $stream = !static::isRunningOS400() ? @fopen('php://stdout', 'w') : null; - if (!$stream) { - $stream = fopen('php://output', 'w'); - } - $stat = fstat($stream); - if (($stat['mode'] & 0170000) === 0100000) { - // file - static::$_outputDecorated = false; - } elseif (false !== getenv('BABUN_HOME')) { - // Babun - static::$_outputDecorated = true; - } elseif (static::$_OS === OS_TYPE_LINUX) { - // linux - static::$_outputDecorated = function_exists('posix_isatty') && @posix_isatty($stream); - } else { - // window - static::$_outputDecorated = - (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support($stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || stripos(getenv('TERM'), 'xterm') === 0; - } - return static::$_outputStream = $stream; - } - - /** - * Checks if current executing environment is IBM iSeries (OS400), which - * doesn't properly convert character-encodings between ASCII to EBCDIC. - * Licensed under the MIT/X11 License (http://opensource.org/licenses/MIT) - * (c) Fabien Potencier - * @see https://github.com/symfony/console/blob/master/Output/ConsoleOutput.php#L131 - * @return bool - */ - private static function isRunningOS400() - { - $checks = array( - function_exists('php_uname') ? php_uname('s') : '', - getenv('OSTYPE'), - PHP_OS, - ); - return false !== stripos(implode(';', $checks), 'OS400'); + fwrite(static::$_outputStream, $msg); + fflush(static::$_outputStream); } /** From 48f10b81481904e008dcff6aa7699b8e55f4c8ae Mon Sep 17 00:00:00 2001 From: malacca Date: Mon, 21 May 2018 17:10:50 +0800 Subject: [PATCH 0272/1216] improve safeEcho method --- Worker.php | 55 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/Worker.php b/Worker.php index 8a8fd5421..1099506b0 100644 --- a/Worker.php +++ b/Worker.php @@ -1057,7 +1057,9 @@ public static function resetStd() @fclose(STDERR); $STDOUT = fopen(static::$stdoutFile, "a"); $STDERR = fopen(static::$stdoutFile, "a"); - static::$_outputStream = static::$_outputDecorated = null; + // change output stream + static::$_outputStream = null; + static::outputStream($STDOUT); } else { throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } @@ -1939,24 +1941,13 @@ public static function log($msg) * Safe Echo. * @param $msg * @param bool $decorated + * @return bool */ public static function safeEcho($msg, $decorated = false) { - if (!static::$_outputStream) { - static::$_outputStream = STDOUT; - $stat = fstat(static::$_outputStream); - if (($stat['mode'] & 0170000) === 0100000) { - // file - static::$_outputDecorated = false; - } else { - static::$_outputDecorated = - static::$_OS === OS_TYPE_LINUX && - function_exists('posix_isatty') && - @posix_isatty(static::$_outputStream); - } - } - if (!is_resource(static::$_outputStream) || 'stream' !== get_resource_type(static::$_outputStream)) { - return; + $stream = static::outputStream(); + if (!$stream) { + return false; } if (!$decorated) { $line = $white = $green = $end = ''; @@ -1969,10 +1960,36 @@ function_exists('posix_isatty') && $msg = str_replace(array('', '', ''), array($line, $white, $green), $msg); $msg = str_replace(array('', '', ''), $end, $msg); } elseif (!static::$_outputDecorated) { - return; + return false; + } + fwrite($stream, $msg); + fflush($stream); + return true; + } + + /** + * @param null $stream + * @return bool|resource + */ + private static function outputStream($stream = null) + { + if (!$stream) { + $stream = static::$_outputStream ? static::$_outputStream : STDOUT; + } + if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) { + return false; + } + $stat = fstat($stream); + if (($stat['mode'] & 0170000) === 0100000) { + // file + static::$_outputDecorated = false; + } else { + static::$_outputDecorated = + static::$_OS === OS_TYPE_LINUX && + function_exists('posix_isatty') && + @posix_isatty($stream); } - fwrite(static::$_outputStream, $msg); - fflush(static::$_outputStream); + return static::$_outputStream = $stream; } /** From b74f6379835241b5ecd70f2dcacd71aab07f69f2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 21 May 2018 21:56:00 +0800 Subject: [PATCH 0273/1216] set error handler --- Worker.php | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/Worker.php b/Worker.php index 1099506b0..c081223f3 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.6'; + const VERSION = '3.5.7'; /** * Status starting. @@ -449,13 +449,13 @@ class Worker protected static $_gracefulStop = false; /** - * standard output stream + * Standard output stream * @var resource */ protected static $_outputStream = null; /** - * if $outputStream support decorated + * If $outputStream support decorated * @var bool */ protected static $_outputDecorated = null; @@ -503,6 +503,8 @@ protected static function checkSapiEnv() */ protected static function init() { + set_error_handler(null); + // Start file. $backtrace = debug_backtrace(); static::$_startFile = $backtrace[count($backtrace) - 1]['file']; @@ -1464,7 +1466,7 @@ protected static function monitorWorkersForLinux() unset(static::$_pidMap[$worker_id][$pid]); // Mark id is available. - $id = static::getId($worker_id, $pid); + $id = static::getId($worker_id, $pid); static::$_idMap[$worker_id][$id] = 0; break; @@ -2001,7 +2003,7 @@ function_exists('posix_isatty') && public function __construct($socket_name = '', $context_option = array()) { // Save all worker instances. - $this->workerId = spl_object_hash($this); + $this->workerId = spl_object_hash($this); static::$_workers[$this->workerId] = $this; static::$_pidMap[$this->workerId] = array(); @@ -2204,6 +2206,7 @@ public function run() } } + restore_error_handler(); // Main loop. static::$globalEvent->loop(); } @@ -2248,7 +2251,10 @@ public function stop() public function acceptConnection($socket) { // Accept a connection on server socket. - $new_socket = @stream_socket_accept($socket, 0, $remote_address); + set_error_handler(function(){}); + $new_socket = stream_socket_accept($socket, 0, $remote_address); + restore_error_handler(); + // Thundering herd. if (!$new_socket) { return; @@ -2288,7 +2294,9 @@ public function acceptConnection($socket) */ public function acceptUdpConnection($socket) { + set_error_handler(function(){}); $recv_buffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + restore_error_handler(); if (false === $recv_buffer || empty($remote_address)) { return false; } @@ -2296,16 +2304,16 @@ public function acceptUdpConnection($socket) $connection = new UdpConnection($socket, $remote_address); $connection->protocol = $this->protocol; if ($this->onMessage) { - if ($this->protocol !== null) { - /** @var \Workerman\Protocols\ProtocolInterface $parser */ - $parser = $this->protocol; - $recv_buffer = $parser::decode($recv_buffer, $connection); - // Discard bad packets. - if ($recv_buffer === false) - return true; - } - ConnectionInterface::$statistics['total_request']++; try { + if ($this->protocol !== null) { + /** @var \Workerman\Protocols\ProtocolInterface $parser */ + $parser = $this->protocol; + $recv_buffer = $parser::decode($recv_buffer, $connection); + // Discard bad packets. + if ($recv_buffer === false) + return true; + } + ConnectionInterface::$statistics['total_request']++; call_user_func($this->onMessage, $connection, $recv_buffer); } catch (\Exception $e) { static::log($e); From 1fa7bef652a548c78d6ff899e4bdb93c11523a6c Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 21 May 2018 21:57:58 +0800 Subject: [PATCH 0274/1216] set error handler --- Connection/TcpConnection.php | 49 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 71519262f..048a4f729 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -260,6 +260,7 @@ class TcpConnection extends ConnectionInterface * * @param string $name * @param array $arguments + * @return void */ public function __call($name, $arguments) { // Try to emit custom function within protocol @@ -273,10 +274,7 @@ public function __call($name, $arguments) { Worker::log($e); exit(250); } - } else { - trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR); - } - + } } /** @@ -299,8 +297,8 @@ public function __construct($socket, $remote_address = '') stream_set_read_buffer($this->_socket, 0); } Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->_remoteAddress = $remote_address; + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; } @@ -358,7 +356,9 @@ public function send($send_buffer, $raw = false) // Attempt to send data directly. if ($this->_sendBuffer === '') { - $len = @fwrite($this->_socket, $send_buffer, 8192); + set_error_handler(function(){}); + $len = fwrite($this->_socket, $send_buffer, 8192); + restore_error_handler(); // send successful. if ($len === strlen($send_buffer)) { $this->bytesWritten += $len; @@ -575,7 +575,9 @@ public function baseRead($socket, $check_eof = true) } } - $buffer = @fread($socket, self::READ_BUFFER_SIZE); + set_error_handler(function(){}); + $buffer = fread($socket, self::READ_BUFFER_SIZE); + restore_error_handler(); // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -600,7 +602,9 @@ public function baseRead($socket, $check_eof = true) } } else { // Get current package length. + set_error_handler(null); $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); + restore_error_handler(); // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -678,7 +682,9 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - $len = @fwrite($this->_socket, $this->_sendBuffer, 8192); + set_error_handler(function(){}); + $len = fwrite($this->_socket, $this->_sendBuffer, 8192); + restore_error_handler(); if ($len === strlen($this->_sendBuffer)) { $this->bytesWritten += $len; Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); @@ -720,18 +726,23 @@ public function doSslHandshake($socket){ $this->destroy(); return false; } - $async=$this instanceof AsyncTcpConnection; + $async = $this instanceof AsyncTcpConnection; if($async){ - $type=STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; }else{ - $type=STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; + $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - $ret = stream_socket_enable_crypto($socket, true, $type); + + // Hidden error. + set_error_handler(function($errno, $errstr, $file){ + if (!Worker::$daemonize) { + echo 'SSL handshake error: ',$errstr, "\n"; + } + }); + $ret = stream_socket_enable_crypto($socket, true, $type); + restore_error_handler(); // Negotiation has failed. if (false === $ret) { - if (!feof($socket)) { - echo "\nSSL Handshake fail as ".($async?'client':'server').". \nBuffer:".bin2hex(fread($socket, 8182))."\n"; - } $this->destroy(); return false; } elseif (0 === $ret) { @@ -889,8 +900,12 @@ public function destroy() // Remove event listener. Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + // Close socket. - @fclose($this->_socket); + set_error_handler(function(){}); + fclose($this->_socket); + restore_error_handler(); + $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { From 41b6c927187305389a567ebbce86fa29ea11e325 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 21 May 2018 21:59:00 +0800 Subject: [PATCH 0275/1216] Update AsyncUdpConnection.php --- Connection/AsyncUdpConnection.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 2170f8315..59938e79c 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -165,7 +165,11 @@ public function connect() if ($this->connected === true) { return; } - $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}"); + $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); + if (!$this->_socket) { + echo new \Exception($errmsg); + return; + } if ($this->onMessage) { Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); } From b4b166061e536b202436effc99956f4cfde4a208 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 21 May 2018 21:59:45 +0800 Subject: [PATCH 0276/1216] set error handler --- Events/Select.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index ff1dc3d92..0345710a7 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -268,7 +268,10 @@ public function loop() $except = $this->_exceptFds; // Waiting read/write/signal/timeout events. - $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); + set_error_handler(function(){}); + $ret = stream_select($read, $write, $except, 0, $this->_selectTimeout); + restore_error_handler(); + if (!$this->_scheduler->isEmpty()) { $this->tick(); From 375ca21bf6705de86f98a19b95d5be0565d08b11 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 May 2018 16:38:17 +0800 Subject: [PATCH 0277/1216] Update Worker.php --- Worker.php | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/Worker.php b/Worker.php index c081223f3..15b2f1ccb 100644 --- a/Worker.php +++ b/Worker.php @@ -503,7 +503,9 @@ protected static function checkSapiEnv() */ protected static function init() { - set_error_handler(null); + set_error_handler(function($code, $msg, $file, $line){ + echo "$msg in file $file on line $line\n"; + }); // Start file. $backtrace = debug_backtrace(); @@ -725,7 +727,7 @@ protected static function parseCommand() // Get master process PID. $master_pid = is_file(static::$pidFile) ? file_get_contents(static::$pidFile) : 0; - $master_is_alive = $master_pid && @posix_kill($master_pid, 0) && posix_getpid() != $master_pid; + $master_is_alive = $master_pid && posix_kill($master_pid, 0) && posix_getpid() != $master_pid; // Master is still alive? if ($master_is_alive) { if ($command === 'start') { @@ -766,15 +768,17 @@ protected static function parseCommand() } exit(0); case 'connections': - if (is_file(static::$_statisticsFile)) { - @unlink(static::$_statisticsFile); + if (is_file(static::$_statisticsFile) && is_writable(static::$_statisticsFile)) { + unlink(static::$_statisticsFile); } // Master process will send SIGIO signal to all child processes. posix_kill($master_pid, SIGIO); // Waiting amoment. usleep(500000); // Display statisitcs data from a disk file. - @readfile(static::$_statisticsFile); + if(is_readable(static::$_statisticsFile)) { + readfile(static::$_statisticsFile); + } exit(0); case 'restart': case 'stop': @@ -840,7 +844,10 @@ protected static function parseCommand() protected static function formatStatusData() { static $total_request_cache = array(); - $info = @file(static::$_statisticsFile, FILE_IGNORE_NEW_LINES); + if (!is_readable(static::$_statisticsFile)) { + return ''; + } + $info = file(static::$_statisticsFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } @@ -1055,8 +1062,8 @@ public static function resetStd() $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - @fclose(STDOUT); - @fclose(STDERR); + fclose(STDOUT); + fclose(STDERR); $STDOUT = fopen(static::$stdoutFile, "a"); $STDERR = fopen(static::$stdoutFile, "a"); // change output stream @@ -1078,7 +1085,7 @@ protected static function saveMasterPid() return; } static::$_masterPid = posix_getpid(); - if (false === @file_put_contents(static::$pidFile, static::$_masterPid)) { + if (false === file_put_contents(static::$pidFile, static::$_masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); } } @@ -1292,7 +1299,7 @@ public static function checkWorkerStatusForWindows() { static::safeEcho("process $start_file terminated and try to restart\n"); Timer::del($timer_id); - @proc_close($process); + proc_close($process); static::forkOneWorkerForWindows($start_file); } } @@ -1406,13 +1413,15 @@ public function setUserAndGroup() */ protected static function setProcessTitle($title) { + set_error_handler(function(){}); // >=php 5.5 if (function_exists('cli_set_process_title')) { - @cli_set_process_title($title); + cli_set_process_title($title); } // Need proctitle when php<=5.5 . elseif (extension_loaded('proctitle') && function_exists('setproctitle')) { - @setproctitle($title); + setproctitle($title); } + restore_error_handler(); } /** @@ -1660,7 +1669,9 @@ public static function stopAll() } if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { static::$_workers = array(); - static::$globalEvent->destroy(); + if (static::$globalEvent) { + static::$globalEvent->destroy(); + } exit(0); } } @@ -1989,7 +2000,7 @@ private static function outputStream($stream = null) static::$_outputDecorated = static::$_OS === OS_TYPE_LINUX && function_exists('posix_isatty') && - @posix_isatty($stream); + posix_isatty($stream); } return static::$_outputStream = $stream; } @@ -2088,9 +2099,11 @@ public function listen() // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { + set_error_handler(function(){}); $socket = socket_import_stream($this->_mainSocket); - @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); - @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); + socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + restore_error_handler(); } // Non blocking. @@ -2108,7 +2121,9 @@ public function listen() public function unlisten() { $this->pauseAccept(); if ($this->_mainSocket) { - @fclose($this->_mainSocket); + set_error_handler(function(){}); + fclose($this->_mainSocket); + restore_error_handler(); $this->_mainSocket = null; } } From 9dcbee3706a4d56bb565f8cfeefcbfd4bdaff3d5 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 May 2018 16:44:08 +0800 Subject: [PATCH 0278/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 048a4f729..a3be72021 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -602,7 +602,9 @@ public function baseRead($socket, $check_eof = true) } } else { // Get current package length. - set_error_handler(null); + set_error_handler(function($code, $msg, $file, $line){ + echo "$msg in file $file on line $line\n"; + }); $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); restore_error_handler(); // The packet length is unknown. From d7470cf5084ff3b85942cbf8b1ab57b05cf3c6c1 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 May 2018 13:35:58 +0800 Subject: [PATCH 0279/1216] Compatible low version PHP --- Protocols/Http.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 644cd99a4..3cdd5d38b 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -348,13 +348,12 @@ public static function setcookie( /** * sessionCreateId * - * @param string|prefix $prefix - * * @return string */ - public static function sessionCreateId($prefix = null) + public static function sessionCreateId() { - return session_create_id($prefix); + mt_srand(); + return bin2hex(pack('d', microtime(true)) . pack('N',mt_rand(0, 2147483647))); } /** From cbc6e46deb9e1a82a5f628118c850ebeea7b2224 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 May 2018 13:36:47 +0800 Subject: [PATCH 0280/1216] 3.5.8 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 15b2f1ccb..93364e6c8 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.7'; + const VERSION = '3.5.8'; /** * Status starting. From 0bf5cf018912286a26bd14e1981dfc060fd98bb0 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 29 May 2018 13:40:06 +0800 Subject: [PATCH 0281/1216] 3.5.9 --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 93364e6c8..d7e12ab2c 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.8'; + const VERSION = '3.5.9'; /** * Status starting. @@ -1195,7 +1195,7 @@ protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; - if(isset($argv[1]) && $argv[1] === '-q') + if(in_array('-q', $argv) || count($files) === 1) { if(count(static::$_workers) > 1) { From 2f04302a79167dce75ce12157d96cbf0610340e2 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:25:54 +0800 Subject: [PATCH 0282/1216] safeEcho --- Connection/AsyncTcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 66477bce9..e21cb686a 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -115,7 +115,7 @@ public function __construct($remote_address, $context_option = null) if (!$address_info) { list($scheme, $this->_remoteAddress) = explode(':', $remote_address, 2); if (!$this->_remoteAddress) { - echo new \Exception('bad remote_address'); + Worker::safeEcho(new \Exception('bad remote_address')); } } else { if (!isset($address_info['port'])) { From c0d3b8359ad21201b0985f86f0ac7b6beb806bf6 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:26:26 +0800 Subject: [PATCH 0283/1216] Update AsyncUdpConnection.php --- Connection/AsyncUdpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 59938e79c..892d6b57a 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -167,7 +167,7 @@ public function connect() } $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); if (!$this->_socket) { - echo new \Exception($errmsg); + Worker::safeEcho(new \Exception($errmsg)); return; } if ($this->onMessage) { From ba74c26542c7658f90f749ba894e63f549596456 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:27:12 +0800 Subject: [PATCH 0284/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index a3be72021..dae108d6c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -603,7 +603,7 @@ public function baseRead($socket, $check_eof = true) } else { // Get current package length. set_error_handler(function($code, $msg, $file, $line){ - echo "$msg in file $file on line $line\n"; + Worker::safeEcho("$msg in file $file on line $line\n"); }); $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); restore_error_handler(); @@ -617,7 +617,7 @@ public function baseRead($socket, $check_eof = true) } } // Wrong package. else { - echo 'error package. package_length=' . var_export($this->_currentPackageLength, true); + Worker::safeEcho('error package. package_length=' . var_export($this->_currentPackageLength, true)); $this->destroy(); return; } @@ -738,7 +738,7 @@ public function doSslHandshake($socket){ // Hidden error. set_error_handler(function($errno, $errstr, $file){ if (!Worker::$daemonize) { - echo 'SSL handshake error: ',$errstr, "\n"; + Worker::safeEcho("SSL handshake error: $errstr \n"); } }); $ret = stream_socket_enable_crypto($socket, true, $type); From ff9ba728f7cc58ad53c257d9199d209b7836eb14 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:27:56 +0800 Subject: [PATCH 0285/1216] Update Timer.php --- Lib/Timer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index e2e6d5eed..3c5e26d58 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -85,7 +85,7 @@ public static function signalHandle() public static function add($time_interval, $func, $args = array(), $persistent = true) { if ($time_interval <= 0) { - echo new Exception("bad time_interval"); + Worker::safeEcho(new Exception("bad time_interval")); return false; } @@ -95,7 +95,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = } if (!is_callable($func)) { - echo new Exception("not callable"); + Worker::safeEcho(new Exception("not callable")); return false; } @@ -136,7 +136,7 @@ public static function tick() try { call_user_func_array($task_func, $task_args); } catch (\Exception $e) { - echo $e; + Worker::safeEcho($e); } if ($persistent) { self::add($time_interval, $task_func, $task_args); From 23976315561b43b218c9837990bc4d9f4700cc12 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:28:30 +0800 Subject: [PATCH 0286/1216] Update Http.php --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 3cdd5d38b..7a82f076e 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -437,7 +437,7 @@ public static function sessionStart() self::tryGcSessions(); if (HttpCache::$instance->sessionStarted) { - echo "already sessionStarted\n"; + Worker::safeEcho("already sessionStarted\n"); return true; } HttpCache::$instance->sessionStarted = true; @@ -503,7 +503,7 @@ public static function end($msg = '') exit($msg); } if ($msg) { - echo $msg; + Worker::safeEcho($msg); } throw new \Exception('jump_exit'); } From 387be29709ab20a4d8d5ee2751fdfab741a86242 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:29:18 +0800 Subject: [PATCH 0287/1216] Update Websocket.php --- Protocols/Websocket.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index ac6546661..af6a3dc2b 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -72,7 +72,7 @@ public static function input($buffer, ConnectionInterface $connection) $masked = $secondbyte >> 7; if (!$masked) { - echo "frame not masked\n"; + Worker::safeEcho("frame not masked so close the connection\n"); $connection->close(); return 0; } @@ -159,7 +159,7 @@ public static function input($buffer, ConnectionInterface $connection) break; // Wrong opcode. default : - echo "error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"; + Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"); $connection->close(); return 0; } @@ -187,7 +187,7 @@ public static function input($buffer, ConnectionInterface $connection) $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; if ($total_package_size > TcpConnection::$maxPackageSize) { - echo "error package. package_length=$total_package_size\n"; + Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; } From 9c419cac75d41842046e25c5dce022e94627ca2e Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:30:06 +0800 Subject: [PATCH 0288/1216] Update Ws.php --- Protocols/Ws.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 23aa2391d..b9c655c77 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -46,7 +46,7 @@ class Ws public static function input($buffer, $connection) { if (empty($connection->handshakeStep)) { - echo "recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"; + Worker::safeEcho("recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"); return false; } // Recv handshake response @@ -73,7 +73,7 @@ public static function input($buffer, $connection) $masked = $secondbyte >> 7; if ($masked) { - echo "frame masked\n"; + Worker::safeEcho("frame masked so close the connection\n"); $connection->close(); return 0; } @@ -160,7 +160,7 @@ public static function input($buffer, $connection) break; // Wrong opcode. default : - echo "error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"; + Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"); $connection->close(); return 0; } @@ -183,7 +183,7 @@ public static function input($buffer, $connection) $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; if ($total_package_size > TcpConnection::$maxPackageSize) { - echo "error package. package_length=$total_package_size\n"; + Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; } @@ -400,12 +400,12 @@ public static function dealHandshake($buffer, $connection) //checking Sec-WebSocket-Accept if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { if ($match[1] !== base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { - echo "Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n"; + Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } } else { - echo "Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n"; + Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } From b12dd8eab80f7b09ef0aacc498e165d9ded5df23 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:30:47 +0800 Subject: [PATCH 0289/1216] Update WebServer.php --- WebServer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WebServer.php b/WebServer.php index 34315f3bb..0a22b293a 100644 --- a/WebServer.php +++ b/WebServer.php @@ -92,7 +92,7 @@ public function run() public function onWorkerStart() { if (empty($this->serverRoot)) { - echo new \Exception('server root not set, please use WebServer::addRoot($domain, $root_path) to set server root path'); + Worker::safeEcho(new \Exception('server root not set, please use WebServer::addRoot($domain, $root_path) to set server root path')); exit(250); } @@ -209,7 +209,7 @@ public function onMessage($connection) } catch (\Exception $e) { // Jump_exit? if ($e->getMessage() != 'jump_exit') { - echo $e; + Worker::safeEcho($e); } } $content = ob_get_clean(); From 744e1bb38195adeec2eb09924e0f0a4235df7085 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 30 May 2018 13:31:54 +0800 Subject: [PATCH 0290/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index d7e12ab2c..a13cc5b5f 100644 --- a/Worker.php +++ b/Worker.php @@ -504,7 +504,7 @@ protected static function checkSapiEnv() protected static function init() { set_error_handler(function($code, $msg, $file, $line){ - echo "$msg in file $file on line $line\n"; + Worker::safeEcho("$msg in file $file on line $line\n"); }); // Start file. From d4247f2513744da291361d5f5da07ffffcafebf8 Mon Sep 17 00:00:00 2001 From: sunx Date: Thu, 31 May 2018 09:40:19 +0800 Subject: [PATCH 0291/1216] ide friendly --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a13cc5b5f..17cc4b00f 100644 --- a/Worker.php +++ b/Worker.php @@ -324,7 +324,7 @@ class Worker /** * All worker instances. * - * @var array + * @var Worker[] */ protected static $_workers = array(); From fb125237a5650eb1adea5bb2467aab74d596f4fd Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 3 Jun 2018 22:45:31 +0800 Subject: [PATCH 0292/1216] Update Worker.php --- Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Worker.php b/Worker.php index 17cc4b00f..97b0a5d0b 100644 --- a/Worker.php +++ b/Worker.php @@ -1062,6 +1062,9 @@ public static function resetStd() $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); + set_error_handler(function(){}); + fclose($STDOUT); + fclose($STDERR); fclose(STDOUT); fclose(STDERR); $STDOUT = fopen(static::$stdoutFile, "a"); @@ -1069,6 +1072,7 @@ public static function resetStd() // change output stream static::$_outputStream = null; static::outputStream($STDOUT); + restore_error_handler(); } else { throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } From d0bf91dbdde3766bec98273c047c70cae0722357 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Jun 2018 21:14:20 +0800 Subject: [PATCH 0293/1216] Update Http.php --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 7a82f076e..5eabe0b9b 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -503,7 +503,7 @@ public static function end($msg = '') exit($msg); } if ($msg) { - Worker::safeEcho($msg); + echo $msg; } throw new \Exception('jump_exit'); } From 37124ceb2e6de051589a3d8e7bb20ddebc86d87c Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Jun 2018 21:18:02 +0800 Subject: [PATCH 0294/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 97b0a5d0b..31256dc1e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.9'; + const VERSION = '3.5.10'; /** * Status starting. From c83e189b5855d91f99a7d01ac58f5bbc7161b5e5 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Jun 2018 17:36:14 +0800 Subject: [PATCH 0295/1216] Update Worker.php --- Worker.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 31256dc1e..b3a36c79b 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.10'; + const VERSION = '3.5.11'; /** * Status starting. @@ -2208,6 +2208,8 @@ public function run() $this->onMessage = function () {}; } + restore_error_handler(); + // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { @@ -2225,7 +2227,6 @@ public function run() } } - restore_error_handler(); // Main loop. static::$globalEvent->loop(); } From 0bf3fc567a50ed384356c451c28bec5c33cf0452 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 19 Jun 2018 09:51:39 +0800 Subject: [PATCH 0296/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e21cb686a..fd6375ffe 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -275,43 +275,47 @@ protected function emitError($code, $msg) * @param resource $socket * @return void */ - public function checkConnection($socket) + public function checkConnection() { + if ($this->_status != self::STATUS_CONNECTING) { + return; + } + // Remove EV_EXPECT for windows. if(DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->del($socket, EventInterface::EV_EXCEPT); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT); } // Check socket state. - if ($address = stream_socket_get_name($socket, true)) { + if ($address = stream_socket_get_name($this->_socket, true)) { // Nonblocking. - stream_set_blocking($socket, 0); + stream_set_blocking($this->_socket, 0); // Compatible with hhvm if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($socket, 0); + stream_set_read_buffer($this->_socket, 0); } // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { - $raw_socket = socket_import_stream($socket); + $raw_socket = socket_import_stream($this->_socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } // Remove write listener. - Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // SSL handshake. if ($this->transport === 'ssl') { - $this->_sslHandshakeCompleted = $this->doSslHandshake($socket); + $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket); } else { // There are some data waiting to send. if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } } // Register a listener waiting read event. - Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->_status = self::STATUS_ESTABLISHED; $this->_remoteAddress = $address; From 9298ee816b4ad7c94012f189847f01169fd1ed70 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Jun 2018 16:27:14 +0800 Subject: [PATCH 0297/1216] add context option --- Connection/AsyncUdpConnection.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 892d6b57a..62dca92de 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -43,13 +43,20 @@ class AsyncUdpConnection extends UdpConnection */ protected $connected = false; + /** + * Context option. + * + * @var array + */ + protected $_contextOption = null; + /** * Construct. * * @param string $remote_address * @throws Exception */ - public function __construct($remote_address) + public function __construct($remote_address, $context_option = null) { // Get the application layer communication protocol and listening address. list($scheme, $address) = explode(':', $remote_address, 2); @@ -66,6 +73,7 @@ public function __construct($remote_address) } $this->_remoteAddress = substr($address, 2); + $this->_contextOption = $context_option; } /** @@ -165,7 +173,14 @@ public function connect() if ($this->connected === true) { return; } - $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); + if ($this->_contextOption) { + $context = stream_context_create($this->_contextOption); + $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, + 30, STREAM_CLIENT_CONNECT, $context); + } else { + $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); + } + if (!$this->_socket) { Worker::safeEcho(new \Exception($errmsg)); return; From b70b5142ea9207fb91bcae6bc90ae52ee8bbfc7d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Jun 2018 16:31:04 +0800 Subject: [PATCH 0298/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index fd6375ffe..162c33a8d 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -75,7 +75,7 @@ class AsyncTcpConnection extends TcpConnection /** * Context option. * - * @var resource + * @var array */ protected $_contextOption = null; @@ -213,7 +213,8 @@ public function connect() * @param int $after * @return void */ - public function reConnect($after = 0) { + public function reconnect($after = 0) + { $this->_status = self::STATUS_INITIAL; static::$connections[$this->_id] = $this; if ($this->_reconnectTimer) { @@ -226,6 +227,16 @@ public function reConnect($after = 0) { $this->connect(); } + /** + * CancelReconnect. + */ + public function cancelReconnect() + { + if ($this->_reconnectTimer) { + Timer::del($this->_reconnectTimer); + } + } + /** * Get remote address. * From aaf562383588ea150b35366fec4387ac0ba24d65 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 3 Jul 2018 23:33:18 +0800 Subject: [PATCH 0299/1216] Update Websocket.php --- Protocols/Websocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index af6a3dc2b..0c9da62bd 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -102,7 +102,7 @@ public static function input($buffer, ConnectionInterface $connection) } } // Close connection. else { - $connection->close(); + $connection->close("\x88\x02\x27\x10", true); } return 0; // Ping package. @@ -120,7 +120,7 @@ public static function input($buffer, ConnectionInterface $connection) } } // Send pong package to client. else { - $connection->send(pack('H*', '8a00'), true); + $connection->send("\x8a\x00", true); } // Consume data from receive buffer. From 49c963ded45ae42e8f76e74b0ee2d009cc068f9c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 4 Jul 2018 17:43:52 +0800 Subject: [PATCH 0300/1216] deal with ping/pong with payload --- Protocols/Websocket.php | 96 +++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 0c9da62bd..bcb23a092 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -107,55 +107,9 @@ public static function input($buffer, ConnectionInterface $connection) return 0; // Ping package. case 0x9: - // Try to emit onWebSocketPing callback. - if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { - try { - call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } // Send pong package to client. - else { - $connection->send("\x8a\x00", true); - } - - // Consume data from receive buffer. - if (!$data_len) { - $head_len = 6; - $connection->consumeRecvBuffer($head_len); - if ($recv_len > $head_len) { - return static::input(substr($buffer, $head_len), $connection); - } - return 0; - } break; // Pong package. case 0xa: - // Try to emit onWebSocketPong callback. - if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { - try { - call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } - // Consume data from receive buffer. - if (!$data_len) { - $head_len = 6; - $connection->consumeRecvBuffer($head_len); - if ($recv_len > $head_len) { - return static::input(substr($buffer, $head_len), $connection); - } - return 0; - } break; // Wrong opcode. default : @@ -193,6 +147,56 @@ public static function input($buffer, ConnectionInterface $connection) } if ($is_fin_frame) { + if ($opcode === 0x9) { + if ($recv_len >= $current_frame_length) { + $ping_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $connection->consumeRecvBuffer($current_frame_length); + $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $connection->websocketType = "\x8a"; + if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { + try { + call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } else { + $connection->send($ping_data); + } + $connection->websocketType = $tmp_connection_type; + if ($recv_len > $current_frame_length) { + return static::input(substr($buffer, $current_frame_length), $connection); + } + } + return 0; + } else if ($opcode === 0xa) { + if ($recv_len >= $current_frame_length) { + $pong_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $connection->consumeRecvBuffer($current_frame_length); + $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $connection->websocketType = "\x8a"; + // Try to emit onWebSocketPong callback. + if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { + try { + call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + $connection->websocketType = $tmp_connection_type; + if ($recv_len > $current_frame_length) { + return static::input(substr($buffer, $current_frame_length), $connection); + } + } + return 0; + } return $current_frame_length; } else { $connection->websocketCurrentFrameLength = $current_frame_length; From ae5291623c879d76f9e249aecc5920c7c0afdb5c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 4 Jul 2018 17:44:57 +0800 Subject: [PATCH 0301/1216] deal with ping/pong with payload --- Protocols/Ws.php | 96 +++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index b9c655c77..482e57f6c 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -109,54 +109,9 @@ public static function input($buffer, $connection) return 0; // Ping package. case 0x9: - // Try to emit onWebSocketPing callback. - if (isset($connection->onWebSocketPing)) { - try { - call_user_func($connection->onWebSocketPing, $connection); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } // Send pong package to client. - else { - $connection->send(pack('H*', '8a00'), true); - } - // Consume data from receive buffer. - if (!$data_len) { - $head_len = 2; - $connection->consumeRecvBuffer($head_len); - if ($recv_len > $head_len) { - return self::input(substr($buffer, $head_len), $connection); - } - return 0; - } break; // Pong package. case 0xa: - // Try to emit onWebSocketPong callback. - if (isset($connection->onWebSocketPong)) { - try { - call_user_func($connection->onWebSocketPong, $connection); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } - // Consume data from receive buffer. - if (!$data_len) { - $head_len = 2; - $connection->consumeRecvBuffer($head_len); - if ($recv_len > $head_len) { - return self::input(substr($buffer, $head_len), $connection); - } - return 0; - } break; // Wrong opcode. default : @@ -189,6 +144,57 @@ public static function input($buffer, $connection) } if ($is_fin_frame) { + if ($opcode === 0x9) { + if ($recv_len >= $current_frame_length) { + $ping_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $connection->consumeRecvBuffer($current_frame_length); + $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $connection->websocketType = "\x8a"; + if (isset($connection->onWebSocketPing)) { + try { + call_user_func($connection->onWebSocketPing, $connection, $ping_data); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } else { + $connection->send($ping_data); + } + $connection->websocketType = $tmp_connection_type; + if ($recv_len > $current_frame_length) { + return static::input(substr($buffer, $current_frame_length), $connection); + } + } + return 0; + + } else if ($opcode === 0xa) { + if ($recv_len >= $current_frame_length) { + $pong_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $connection->consumeRecvBuffer($current_frame_length); + $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $connection->websocketType = "\x8a"; + // Try to emit onWebSocketPong callback. + if (isset($connection->onWebSocketPong)) { + try { + call_user_func($connection->onWebSocketPong, $connection, $pong_data); + } catch (\Exception $e) { + Worker::log($e); + exit(250); + } catch (\Error $e) { + Worker::log($e); + exit(250); + } + } + $connection->websocketType = $tmp_connection_type; + if ($recv_len > $current_frame_length) { + return static::input(substr($buffer, $current_frame_length), $connection); + } + } + return 0; + } return $current_frame_length; } else { $connection->websocketCurrentFrameLength = $current_frame_length; From 017e086917a03cb3c58187cf7e473e4f271056af Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Jul 2018 16:31:20 +0800 Subject: [PATCH 0302/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index b3a36c79b..696e2593e 100644 --- a/Worker.php +++ b/Worker.php @@ -1276,7 +1276,7 @@ public static function forkOneWorkerForWindows($start_file) static::$globalEvent = new Select(); Timer::init(static::$globalEvent); } - $timer_id = Timer::add(1, function()use($std_handler) + $timer_id = Timer::add(0.1, function()use($std_handler) { Worker::safeEcho(fread($std_handler, 65535)); }); @@ -1515,7 +1515,7 @@ protected static function monitorWorkersForLinux() */ protected static function monitorWorkersForWindows() { - Timer::add(0.5, "\\Workerman\\Worker::checkWorkerStatusForWindows"); + Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows"); static::$globalEvent->loop(); } From 2f89ef966809cb54de776bfb1ac8582d1deae185 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Jul 2018 16:31:48 +0800 Subject: [PATCH 0303/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 696e2593e..06edb0e11 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.11'; + const VERSION = '3.5.12'; /** * Status starting. From 69b800984b806bc010c8fd3bd330c9614258bfe8 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Jul 2018 21:37:14 +0800 Subject: [PATCH 0304/1216] Update Http.php --- Protocols/Http.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 5eabe0b9b..132dbe09f 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -175,9 +175,6 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'application/x-www-form-urlencoded': parse_str($http_body, $_POST); break; - case 'application/json': - $_POST = json_decode($http_body, true); - break; } } } @@ -205,8 +202,13 @@ public static function decode($recv_buffer, TcpConnection $connection) $_SERVER['QUERY_STRING'] = ''; } - // REQUEST - $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); + if (is_array($_POST)) { + // REQUEST + $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); + } else { + // REQUEST + $_REQUEST = array_merge($_GET, $_REQUEST); + } // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); From 35dac7b3e1ea4abbd949472270352ac08dd9c871 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jul 2018 10:05:36 +0800 Subject: [PATCH 0305/1216] Update Websocket.php --- Protocols/Websocket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index bcb23a092..b7c9dbd72 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -304,7 +304,7 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $masks = $data = $decoded = null; + $masks = $data = $decoded = ''; $len = ord($buffer[1]) & 127; if ($len === 126) { $masks = substr($buffer, 4, 4); From cf2538169af989fbba4d55be1bfc8c8d80fa71e9 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jul 2018 10:11:10 +0800 Subject: [PATCH 0306/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 06edb0e11..6d0a2909c 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.12'; + const VERSION = '3.5.13'; /** * Status starting. From f1d71f67b0b60ee5d08f6fe438d94bde3cb0be71 Mon Sep 17 00:00:00 2001 From: dtfreeman Date: Thu, 19 Jul 2018 22:48:26 +0800 Subject: [PATCH 0307/1216] =?UTF-8?q?=E4=BD=BF=E7=94=A8static::$maxPackage?= =?UTF-8?q?Size=20=E4=BB=A5=E6=9B=B4=E6=96=B9=E4=BE=BF=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E7=BB=A7=E6=89=BFTcpConnection=E6=9D=A5=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E6=9C=8D=E5=8A=A1=E6=8E=A5=E6=94=B6=E7=9A=84?= =?UTF-8?q?=E5=8C=85=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index dae108d6c..23c0150ee 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -610,7 +610,7 @@ public function baseRead($socket, $check_eof = true) // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; - } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= self::$maxPackageSize) { + } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= static::$maxPackageSize) { // Data is not enough for a package. if ($this->_currentPackageLength > strlen($this->_recvBuffer)) { break; From 96e3252bd2860c85cf5e0c892a84333466c4c341 Mon Sep 17 00:00:00 2001 From: dtfreeman Date: Thu, 19 Jul 2018 23:13:39 +0800 Subject: [PATCH 0308/1216] =?UTF-8?q?=E9=80=9A=E8=BF=87=20$connection::$ma?= =?UTF-8?q?xPackageSize=20=20=E7=9A=84=E8=B0=83=E7=94=A8=E6=96=B9=E5=BC=8F?= =?UTF-8?q?,=E9=81=BF=E5=85=8D=E5=9B=A0=E4=B8=BA=E7=BB=A7=E6=89=BF/?= =?UTF-8?q?=E5=AE=9A=E5=88=B6TcpConnection=E5=AF=BC=E8=87=B4=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=88=A4=E6=96=AD=E4=B8=8D=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Protocols/Http.php | 2 +- Protocols/Text.php | 2 +- Protocols/Websocket.php | 2 +- Protocols/Ws.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 132dbe09f..6c142a4f1 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -38,7 +38,7 @@ public static function input($recv_buffer, TcpConnection $connection) { if (!strpos($recv_buffer, "\r\n\r\n")) { // Judge whether the package length exceeds the limit. - if (strlen($recv_buffer) >= TcpConnection::$maxPackageSize) { + if (strlen($recv_buffer) >= $connection::$maxPackageSize) { $connection->close(); return 0; } diff --git a/Protocols/Text.php b/Protocols/Text.php index 189baf416..5c78852c7 100644 --- a/Protocols/Text.php +++ b/Protocols/Text.php @@ -30,7 +30,7 @@ class Text public static function input($buffer, TcpConnection $connection) { // Judge whether the package length exceeds the limit. - if (strlen($buffer) >= TcpConnection::$maxPackageSize) { + if (strlen($buffer) >= $connection::$maxPackageSize) { $connection->close(); return 0; } diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index b7c9dbd72..7ebf59111 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -140,7 +140,7 @@ public static function input($buffer, ConnectionInterface $connection) $current_frame_length = $head_len + $data_len; $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > TcpConnection::$maxPackageSize) { + if ($total_package_size > $connection::$maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 482e57f6c..e5a7d66dd 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -137,7 +137,7 @@ public static function input($buffer, $connection) } $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > TcpConnection::$maxPackageSize) { + if ($total_package_size > $connection::$maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; From 9c78d283e494bee5c060b910e41c3287be004ce5 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 20 Jul 2018 16:01:21 +0800 Subject: [PATCH 0309/1216] Increase the speed of transmission see #344 --- Connection/TcpConnection.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 23c0150ee..927a0d302 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -322,7 +322,7 @@ public function getStatus($raw_output = true) * * @param string $send_buffer * @param bool $raw - * @return void|bool|null + * @return bool|null */ public function send($send_buffer, $raw = false) { @@ -353,11 +353,16 @@ public function send($send_buffer, $raw = false) return null; } - // Attempt to send data directly. if ($this->_sendBuffer === '') { + if ($this->transport === 'ssl') { + Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + $this->_sendBuffer = $send_buffer; + $this->checkBufferWillFull(); + return null; + } set_error_handler(function(){}); - $len = fwrite($this->_socket, $send_buffer, 8192); + $len = fwrite($this->_socket, $send_buffer); restore_error_handler(); // send successful. if ($len === strlen($send_buffer)) { @@ -685,7 +690,11 @@ public function baseRead($socket, $check_eof = true) public function baseWrite() { set_error_handler(function(){}); - $len = fwrite($this->_socket, $this->_sendBuffer, 8192); + if ($this->transport === 'ssl') { + $len = fwrite($this->_socket, $this->_sendBuffer, 8192); + } else { + $len = fwrite($this->_socket, $this->_sendBuffer); + } restore_error_handler(); if ($len === strlen($this->_sendBuffer)) { $this->bytesWritten += $len; From 482e0623de2fcea05c4ab1379a3330e01a29b412 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jul 2018 16:56:18 +0800 Subject: [PATCH 0310/1216] Update Worker.php --- Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Worker.php b/Worker.php index 6d0a2909c..b10f5abf9 100644 --- a/Worker.php +++ b/Worker.php @@ -1105,6 +1105,10 @@ protected static function getEventLoopName() return static::$eventLoopClass; } + if (!class_exists('\Swoole\Event')) { + unset(static::$_availableEventLoops['swoole']); + } + $loop_name = ''; foreach (static::$_availableEventLoops as $name=>$class) { if (extension_loaded($name)) { From 04412816d38234357360260740eb9a2bb6bbc71f Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 4 Aug 2018 20:40:10 +0800 Subject: [PATCH 0311/1216] compatible event extension with namesapce --- Events/Event.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Events/Event.php b/Events/Event.php index a1b7da214..0bbe404fb 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -57,7 +57,12 @@ class Event implements EventInterface */ public function __construct() { - $this->_eventBase = new \EventBase(); + if (class_exists('\\\\EventBase')) { + $class_name = '\\\\EventBase'; + } else { + $class_name = '\EventBase'; + } + $this->_eventBase = new $class_name(); } /** @@ -65,11 +70,16 @@ public function __construct() */ public function add($fd, $flag, $func, $args=array()) { + if (class_exists('\\\\Event')) { + $class_name = '\\\\Event'; + } else { + $class_name = '\Event'; + } switch ($flag) { case self::EV_SIGNAL: $fd_key = (int)$fd; - $event = \Event::signal($this->_eventBase, $fd, $func); + $event = $class_name::signal($this->_eventBase, $fd, $func); if (!$event||!$event->add()) { return false; } @@ -80,7 +90,7 @@ public function add($fd, $flag, $func, $args=array()) case self::EV_TIMER_ONCE: $param = array($func, (array)$args, $flag, $fd, self::$_timerId); - $event = new \Event($this->_eventBase, -1, \Event::TIMEOUT|\Event::PERSIST, array($this, "timerCallback"), $param); + $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param); if (!$event||!$event->addTimer($fd)) { return false; } @@ -89,8 +99,8 @@ public function add($fd, $flag, $func, $args=array()) default : $fd_key = (int)$fd; - $real_flag = $flag === self::EV_READ ? \Event::READ | \Event::PERSIST : \Event::WRITE | \Event::PERSIST; - $event = new \Event($this->_eventBase, $fd, $real_flag, $func, $fd); + $real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST; + $event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd); if (!$event||!$event->add()) { return false; } From 6d70996b2b4ec94000e807246aca0e861c9601d8 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 4 Aug 2018 20:41:54 +0800 Subject: [PATCH 0312/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index b10f5abf9..5ba3bc757 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.13'; + const VERSION = '3.5.14'; /** * Status starting. From 25530493dab1b4199bd963d3cee7e5687a4a61eb Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Aug 2018 16:58:31 +0800 Subject: [PATCH 0313/1216] Update WebServer.php --- WebServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebServer.php b/WebServer.php index 0a22b293a..82ea77695 100644 --- a/WebServer.php +++ b/WebServer.php @@ -151,7 +151,7 @@ public function initMimeTypeMap() public function onMessage($connection) { // REQUEST_URI. - $workerman_url_info = parse_url($_SERVER['REQUEST_URI']); + $workerman_url_info = parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); if (!$workerman_url_info) { Http::header('HTTP/1.1 400 Bad Request'); $connection->close('

400 Bad Request

'); From c0248ba49973cae0731189b8e80a9548062ced04 Mon Sep 17 00:00:00 2001 From: Arul Date: Wed, 15 Aug 2018 22:01:52 +0800 Subject: [PATCH 0314/1216] Fix for DELETE requests that keep the connection hanging When a `DELETE` request is made without **Content-Length** header, it makes the connection hanging without a response This commit makes sure we don't return 0 for **getRequestSize** method when it is a delete request. Following request is an example to showcase this bug ``` DELETE /examples/_007_crud/authors/1 HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: localhost:8080 Connection: close ``` --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 6c142a4f1..b7bfc2ecd 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -73,7 +73,7 @@ protected static function getRequestSize($header, $method) $content_length = isset($match[1]) ? $match[1] : 0; return $content_length + strlen($header) + 4; } - return 0; + return $method === 'DELETE' ? strlen($header) + 4 : 0; } /** From 0beb9659ce65567c1a604df9c54be21e01e607b5 Mon Sep 17 00:00:00 2001 From: wonderful60 <924211739@qq.com> Date: Mon, 20 Aug 2018 10:26:56 +0800 Subject: [PATCH 0315/1216] add proto for staring ui --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 5ba3bc757..aa1a4a978 100644 --- a/Worker.php +++ b/Worker.php @@ -664,12 +664,12 @@ protected static function displayUI() static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("user". str_pad('', + static::safeEcho("proto user". str_pad('', static::$_maxUserNameLength + 2 - strlen('user')). "worker". str_pad('', static::$_maxWorkerNameLength + 2 - strlen('worker')). "listen". str_pad('', static::$_maxSocketNameLength + 2 - strlen('listen')). "processes status\n"); foreach (static::$_workers as $worker) { - static::safeEcho(str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, + static::safeEcho(str_pad($worker->transport,9). str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, static::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), static::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " [OK] \n"); } From 93b32f517c720b57cef90c585eaa0a71c2e367de Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 21 Aug 2018 16:03:28 +0800 Subject: [PATCH 0316/1216] Update Event.php --- Events/Event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Events/Event.php b/Events/Event.php index 0bbe404fb..b4d371a72 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -57,7 +57,7 @@ class Event implements EventInterface */ public function __construct() { - if (class_exists('\\\\EventBase')) { + if (class_exists('\\\\EventBase', false)) { $class_name = '\\\\EventBase'; } else { $class_name = '\EventBase'; @@ -70,7 +70,7 @@ public function __construct() */ public function add($fd, $flag, $func, $args=array()) { - if (class_exists('\\\\Event')) { + if (class_exists('\\\\Event', false)) { $class_name = '\\\\Event'; } else { $class_name = '\Event'; From b6162f6cd8579f7bc9959048e8326f1e4ecfaed6 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 22 Aug 2018 10:17:29 +0800 Subject: [PATCH 0317/1216] 1024 fds check --- Events/Select.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 0345710a7..a1e2cf084 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -114,14 +114,20 @@ public function add($fd, $flag, $func, $args = array()) { switch ($flag) { case self::EV_READ: - $fd_key = (int)$fd; - $this->_allEvents[$fd_key][$flag] = array($func, $fd); - $this->_readFds[$fd_key] = $fd; - break; case self::EV_WRITE: + $count = $flag === self::EV_READ ? count($this->_readFds) : count($this->_writeFds); + if ($count >= 1024) { + echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; + } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + echo "Warning: system call select exceeded the maximum number of connections 256.\n"; + } $fd_key = (int)$fd; $this->_allEvents[$fd_key][$flag] = array($func, $fd); - $this->_writeFds[$fd_key] = $fd; + if ($flag === self::EV_READ) { + $this->_readFds[$fd_key] = $fd; + } else { + $this->_writeFds[$fd_key] = $fd; + } break; case self::EV_EXCEPT: $fd_key = (int)$fd; From f49b1534ac5e92f0d8e690f2b090db17d1afc6a5 Mon Sep 17 00:00:00 2001 From: Linkec Date: Fri, 24 Aug 2018 18:03:55 +0800 Subject: [PATCH 0318/1216] add gzip encode --- Protocols/Http.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index b7bfc2ecd..fc6350040 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -161,7 +161,9 @@ public static function decode($recv_buffer, TcpConnection $connection) break; } } - + if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE){ + HttpCache::$gzip = true; + } // Parse $_POST. if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_SERVER['CONTENT_TYPE'])) { @@ -249,7 +251,10 @@ public static function encode($content, TcpConnection $connection) $header .= $item . "\r\n"; } } - + if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ + $header .= "Content-Encoding: gzip\r\n"; + $content = gzencode($content,$connection->gzip); + } // header $header .= "Server: workerman/" . Worker::VERSION . "\r\nContent-Length: " . strlen($content) . "\r\n\r\n"; @@ -650,6 +655,7 @@ class HttpCache */ public static $instance = null; public static $header = array(); + public static $gzip = false; public static $sessionPath = ''; public static $sessionName = ''; public static $sessionGcProbability = 1; From 7fc1b6c8a47e158124c7028ee919624c24576231 Mon Sep 17 00:00:00 2001 From: Linkec Date: Fri, 24 Aug 2018 21:45:59 +0800 Subject: [PATCH 0319/1216] add https to wss upgrade switch protocol usage: if($connection->protocol=='\\Workerman\\Protocols\\Websocket'){ $connection->send('wss'); } --- Protocols/Http.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index fc6350040..0ff125b76 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -159,6 +159,12 @@ public static function decode($recv_buffer, TcpConnection $connection) case 'CONTENT_LENGTH': $_SERVER['CONTENT_LENGTH'] = $value; break; + case 'UPGRADE': + if($value=='websocket'){ + $connection->protocol = "\\Workerman\\Protocols\\Websocket"; + return \Workerman\Protocols\Websocket::input($recv_buffer,$connection); + } + break; } } if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE){ From 8d3ab8668ae9b43935a55a6cd461e2305ea04122 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 3 Sep 2018 17:17:08 +0800 Subject: [PATCH 0320/1216] Update Worker.php --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index aa1a4a978..49733167f 100644 --- a/Worker.php +++ b/Worker.php @@ -1339,6 +1339,8 @@ protected static function forkOneWorkerForLinux($worker) static::$_idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { + srand(); + mt_srand(); if ($worker->reusePort) { $worker->listen(); } From 767df16e6da4bfcdd3f0144ea44ea8c982653aa4 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sat, 8 Sep 2018 04:44:38 +0800 Subject: [PATCH 0321/1216] Optimize UI displays --- Worker.php | 145 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 117 insertions(+), 28 deletions(-) diff --git a/Worker.php b/Worker.php index 49733167f..e8e4340c8 100644 --- a/Worker.php +++ b/Worker.php @@ -84,6 +84,13 @@ class Worker */ const MAX_UDP_PACKAGE_SIZE = 65535; + /** + * The safe distance for columns adjacent + * + * @var int + */ + const UI_SAFE_LENGTH = 4; + /** * Worker id. * @@ -380,6 +387,27 @@ class Worker */ protected static $_maxUserNameLength = 12; + /** + * Maximum length of the Proto names. + * + * @var int + */ + protected static $_maxProtoNameLength = 4; + + /** + * Maximum length of the Processes names. + * + * @var int + */ + protected static $_maxProcessesNameLength = 9; + + /** + * Maximum length of the Status names. + * + * @var int + */ + protected static $_maxStatusNameLength = 1; + /** * The file to store status info of current worker process. * @@ -562,18 +590,6 @@ protected static function initWorkers() $worker->name = 'none'; } - // Get maximum length of worker name. - $worker_name_length = strlen($worker->name); - if (static::$_maxWorkerNameLength < $worker_name_length) { - static::$_maxWorkerNameLength = $worker_name_length; - } - - // Get maximum length of socket name. - $socket_name_length = strlen($worker->getSocketName()); - if (static::$_maxSocketNameLength < $socket_name_length) { - static::$_maxSocketNameLength = $socket_name_length; - } - // Get unix user of the worker process. if (empty($worker->user)) { $worker->user = static::getCurrentUser(); @@ -583,11 +599,19 @@ protected static function initWorkers() } } - // Get maximum length of unix user name. - $user_name_length = strlen($worker->user); - if (static::$_maxUserNameLength < $user_name_length) { - static::$_maxUserNameLength = $user_name_length; - } + // Socket name. + $worker->socket = $worker->getSocketName(); + + // Status name. + $worker->status = ' [OK] '; + + // Get clolumn mapping for UI + foreach(static::getUiColumns() as $column_name => $prop){ + !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; + $prop_length = strlen($worker->{$prop}); + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + static::$$key = max(static::$$key, $prop_length); + } // Listen. if (!$worker->reusePort) { @@ -661,19 +685,41 @@ protected static function displayUI() static::safeEcho("worker listen processes status\r\n"); return; } - static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); - static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("proto user". str_pad('', - static::$_maxUserNameLength + 2 - strlen('user')). "worker". str_pad('', - static::$_maxWorkerNameLength + 2 - strlen('worker')). "listen". str_pad('', - static::$_maxSocketNameLength + 2 - strlen('listen')). "processes status\n"); + + //show version + $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); + $total_length = static::getSingleLineTotalLength(); + $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; + $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + static::safeEcho($line_one . $line_version . $line_two); + + //Show title + $title = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + //just keep compatible with listen name + $column_name == 'socket' && $column_name = 'listen'; + $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); + } + $title && static::safeEcho($title . PHP_EOL); + + //Show content foreach (static::$_workers as $worker) { - static::safeEcho(str_pad($worker->transport,9). str_pad($worker->user, static::$_maxUserNameLength + 2). str_pad($worker->name, - static::$_maxWorkerNameLength + 2). str_pad($worker->getSocketName(), - static::$_maxSocketNameLength + 2). str_pad(' ' . $worker->count, 9). " [OK] \n"); + $content = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + } + $content && static::safeEcho($content . PHP_EOL); } - static::safeEcho("----------------------------------------------------------------\n"); + + //Show last line + $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + $content && static::safeEcho($line_last); + if (static::$daemonize) { static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); } else { @@ -681,6 +727,49 @@ protected static function displayUI() } } + /** + * Get UI columns to be shown in terminal + * + * 1. $column_map: array('ui_column_name' => 'clas_property_name') + * 2. Consider move into configuration in future + * + * @return array + */ + public static function getUiColumns() + { + $column_map = array( + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', + 'processes' => 'count', + 'status' => 'status', + ); + + return $column_map; + } + + /** + * Get single line total length for ui + * + * @return int + */ + public static function getSingleLineTotalLength() + { + $total_length = 0; + + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $total_length += static::$$key + static::UI_SAFE_LENGTH; + } + + //keep beauty when show less colums + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); + $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; + + return $total_length; + } + /** * Parse command. * From 5447974cac1cb268fad9f230237b9f8662186352 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sat, 8 Sep 2018 04:59:01 +0800 Subject: [PATCH 0322/1216] Update Worker.php Optimize UI displays --- Worker.php | 110 ++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/Worker.php b/Worker.php index e8e4340c8..bb1e6d1f0 100644 --- a/Worker.php +++ b/Worker.php @@ -686,38 +686,38 @@ protected static function displayUI() return; } - //show version - $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); - $total_length = static::getSingleLineTotalLength(); - $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; - $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; - static::safeEcho($line_one . $line_version . $line_two); - - //Show title - $title = ''; + //show version + $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); + $total_length = static::getSingleLineTotalLength(); + $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; + $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + static::safeEcho($line_one . $line_version . $line_two); + + //Show title + $title = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + //just keep compatible with listen name + $column_name == 'socket' && $column_name = 'listen'; + $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); + } + $title && static::safeEcho($title . PHP_EOL); + + //Show content + foreach (static::$_workers as $worker) { + $content = ''; foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - //just keep compatible with listen name - $column_name == 'socket' && $column_name = 'listen'; - $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); + preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); } - $title && static::safeEcho($title . PHP_EOL); - - //Show content - foreach (static::$_workers as $worker) { - $content = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); - $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; - $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); - } - $content && static::safeEcho($content . PHP_EOL); + $content && static::safeEcho($content . PHP_EOL); } - //Show last line - $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + //Show last line + $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; $content && static::safeEcho($line_last); if (static::$daemonize) { @@ -729,46 +729,46 @@ protected static function displayUI() /** * Get UI columns to be shown in terminal - * - * 1. $column_map: array('ui_column_name' => 'clas_property_name') - * 2. Consider move into configuration in future + * + * 1. $column_map: array('ui_column_name' => 'clas_property_name') + * 2. Consider move into configuration in future * * @return array */ public static function getUiColumns() - { - $column_map = array( - 'proto' => 'transport', - 'user' => 'user', - 'worker' => 'name', - 'socket' => 'socket', - 'processes' => 'count', - 'status' => 'status', - ); - - return $column_map; - } + { + $column_map = array( + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', + 'processes' => 'count', + 'status' => 'status', + ); + + return $column_map; + } /** * Get single line total length for ui - * + * * @return int */ - public static function getSingleLineTotalLength() - { - $total_length = 0; + public static function getSingleLineTotalLength() + { + $total_length = 0; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - $total_length += static::$$key + static::UI_SAFE_LENGTH; - } + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $total_length += static::$$key + static::UI_SAFE_LENGTH; + } - //keep beauty when show less colums - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); - $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; + //keep beauty when show less colums + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); + $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; - return $total_length; - } + return $total_length; + } /** * Parse command. From f4858ac41e56f57831bb1577f0d154c39098b868 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sat, 8 Sep 2018 05:22:08 +0800 Subject: [PATCH 0323/1216] Optimize UI displays --- Worker.php | 144 ++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/Worker.php b/Worker.php index bb1e6d1f0..339565463 100644 --- a/Worker.php +++ b/Worker.php @@ -686,88 +686,88 @@ protected static function displayUI() return; } - //show version - $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); - $total_length = static::getSingleLineTotalLength(); - $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; - $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; - static::safeEcho($line_one . $line_version . $line_two); - - //Show title - $title = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - //just keep compatible with listen name - $column_name == 'socket' && $column_name = 'listen'; - $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); - } - $title && static::safeEcho($title . PHP_EOL); - - //Show content - foreach (static::$_workers as $worker) { - $content = ''; + //show version + $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); + $total_length = static::getSingleLineTotalLength(); + $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; + $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + static::safeEcho($line_one . $line_version . $line_two); + + //Show title + $title = ''; foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); - $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; - $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + //just keep compatible with listen name + $column_name == 'socket' && $column_name = 'listen'; + $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); } - $content && static::safeEcho($content . PHP_EOL); - } + $title && static::safeEcho($title . PHP_EOL); - //Show last line - $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; - $content && static::safeEcho($line_last); - - if (static::$daemonize) { - static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); - } else { - static::safeEcho("Press Ctrl+C to stop. Start success.\n"); - } - } + //Show content + foreach (static::$_workers as $worker) { + $content = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + } + $content && static::safeEcho($content . PHP_EOL); + } - /** - * Get UI columns to be shown in terminal - * - * 1. $column_map: array('ui_column_name' => 'clas_property_name') - * 2. Consider move into configuration in future - * - * @return array - */ - public static function getUiColumns() - { - $column_map = array( - 'proto' => 'transport', - 'user' => 'user', - 'worker' => 'name', - 'socket' => 'socket', - 'processes' => 'count', - 'status' => 'status', - ); - - return $column_map; - } + //Show last line + $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + $content && static::safeEcho($line_last); - /** - * Get single line total length for ui - * - * @return int - */ - public static function getSingleLineTotalLength() - { - $total_length = 0; + if (static::$daemonize) { + static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); + } else { + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); + } + } - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - $total_length += static::$$key + static::UI_SAFE_LENGTH; + /** + * Get UI columns to be shown in terminal + * + * 1. $column_map: array('ui_column_name' => 'clas_property_name') + * 2. Consider move into configuration in future + * + * @return array + */ + public static function getUiColumns() + { + $column_map = array( + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', + 'processes' => 'count', + 'status' => 'status', + ); + + return $column_map; } - //keep beauty when show less colums - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); - $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; + /** + * Get single line total length for ui + * + * @return int + */ + public static function getSingleLineTotalLength() + { + $total_length = 0; + + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $total_length += static::$$key + static::UI_SAFE_LENGTH; + } + + //keep beauty when show less colums + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); + $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; - return $total_length; + return $total_length; } /** From 1d8d104dede52c02d58b255351976bcc3d2bf8d6 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sun, 9 Sep 2018 23:10:57 +0800 Subject: [PATCH 0324/1216] Remove redundant code --- Worker.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Worker.php b/Worker.php index 339565463..b606d829b 100644 --- a/Worker.php +++ b/Worker.php @@ -1588,18 +1588,13 @@ protected static function monitorWorkersForLinux() unset(static::$_pidsToRestart[$pid]); static::reload(); } - } else { - // If shutdown state and all child processes exited then master process exit. - if (!static::getAllWorkerPids()) { - static::exitAndClearAll(); - } - } - } else { - // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { - static::exitAndClearAll(); - } - } + } + } + + // If shutdown state and all child processes exited then master process exit. + if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + static::exitAndClearAll(); + } } } From 0c70d0f431cf676a5b86ef42da0fde4a0a780cba Mon Sep 17 00:00:00 2001 From: blogdaren Date: Mon, 10 Sep 2018 16:41:26 +0800 Subject: [PATCH 0325/1216] Reformat code modified in pull request #364 --- Worker.php | 194 ++++++++++++++++++++++++++--------------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/Worker.php b/Worker.php index b606d829b..7bee4cfd2 100644 --- a/Worker.php +++ b/Worker.php @@ -600,18 +600,18 @@ protected static function initWorkers() } // Socket name. - $worker->socket = $worker->getSocketName(); + $worker->socket = $worker->getSocketName(); // Status name. - $worker->status = ' [OK] '; + $worker->status = ' [OK] '; - // Get clolumn mapping for UI - foreach(static::getUiColumns() as $column_name => $prop){ - !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; - $prop_length = strlen($worker->{$prop}); - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - static::$$key = max(static::$$key, $prop_length); - } + // Get clolumn mapping for UI + foreach(static::getUiColumns() as $column_name => $prop){ + !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; + $prop_length = strlen($worker->{$prop}); + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + static::$$key = max(static::$$key, $prop_length); + } // Listen. if (!$worker->reusePort) { @@ -686,88 +686,88 @@ protected static function displayUI() return; } - //show version - $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); - $total_length = static::getSingleLineTotalLength(); - $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; - $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; - static::safeEcho($line_one . $line_version . $line_two); - - //Show title - $title = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - //just keep compatible with listen name - $column_name == 'socket' && $column_name = 'listen'; - $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); - } - $title && static::safeEcho($title . PHP_EOL); - - //Show content - foreach (static::$_workers as $worker) { - $content = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); - $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; - $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); - } - $content && static::safeEcho($content . PHP_EOL); - } - - //Show last line - $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; - $content && static::safeEcho($line_last); - - if (static::$daemonize) { - static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); - } else { - static::safeEcho("Press Ctrl+C to stop. Start success.\n"); - } - } - - /** - * Get UI columns to be shown in terminal - * - * 1. $column_map: array('ui_column_name' => 'clas_property_name') - * 2. Consider move into configuration in future - * - * @return array - */ - public static function getUiColumns() - { - $column_map = array( - 'proto' => 'transport', - 'user' => 'user', - 'worker' => 'name', - 'socket' => 'socket', - 'processes' => 'count', - 'status' => 'status', - ); - - return $column_map; - } - - /** - * Get single line total length for ui - * - * @return int - */ - public static function getSingleLineTotalLength() - { - $total_length = 0; - - foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - $total_length += static::$$key + static::UI_SAFE_LENGTH; - } - - //keep beauty when show less colums - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); - $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; - - return $total_length; + //show version + $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); + $total_length = static::getSingleLineTotalLength(); + $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; + $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + static::safeEcho($line_one . $line_version . $line_two); + + //Show title + $title = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + //just keep compatible with listen name + $column_name == 'socket' && $column_name = 'listen'; + $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); + } + $title && static::safeEcho($title . PHP_EOL); + + //Show content + foreach (static::$_workers as $worker) { + $content = ''; + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + } + $content && static::safeEcho($content . PHP_EOL); + } + + //Show last line + $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + $content && static::safeEcho($line_last); + + if (static::$daemonize) { + static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); + } else { + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); + } + } + + /** + * Get UI columns to be shown in terminal + * + * 1. $column_map: array('ui_column_name' => 'clas_property_name') + * 2. Consider move into configuration in future + * + * @return array + */ + public static function getUiColumns() + { + $column_map = array( + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', + 'processes' => 'count', + 'status' => 'status', + ); + + return $column_map; + } + + /** + * Get single line total length for ui + * + * @return int + */ + public static function getSingleLineTotalLength() + { + $total_length = 0; + + foreach(static::getUiColumns() as $column_name => $prop){ + $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $total_length += static::$$key + static::UI_SAFE_LENGTH; + } + + //keep beauty when show less colums + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); + $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; + + return $total_length; } /** @@ -1588,13 +1588,13 @@ protected static function monitorWorkersForLinux() unset(static::$_pidsToRestart[$pid]); static::reload(); } - } - } + } + } - // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { - static::exitAndClearAll(); - } + // If shutdown state and all child processes exited then master process exit. + if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + static::exitAndClearAll(); + } } } From 2dbc07f371a56c517864dd8d176076e76dc56cb6 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 11 Sep 2018 15:25:06 +0800 Subject: [PATCH 0326/1216] Update Timer.php --- Lib/Timer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/Timer.php b/Lib/Timer.php index 3c5e26d58..2dc2302b1 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -14,6 +14,7 @@ namespace Workerman\Lib; use Workerman\Events\EventInterface; +use Workerman\Worker; use Exception; /** From ecae985c3b651ea231d408875608a77691aa07f1 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 20 Sep 2018 17:10:57 +0800 Subject: [PATCH 0327/1216] Update Worker.php --- Worker.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 7bee4cfd2..674e7fa26 100644 --- a/Worker.php +++ b/Worker.php @@ -453,8 +453,9 @@ class Worker */ protected static $_availableEventLoops = array( 'libevent' => '\Workerman\Events\Libevent', - 'event' => '\Workerman\Events\Event', - 'swoole' => '\Workerman\Events\Swoole' + 'event' => '\Workerman\Events\Event' + // Temporarily removed swoole because it is not stable enough + //'swoole' => '\Workerman\Events\Swoole' ); /** @@ -1194,7 +1195,7 @@ protected static function getEventLoopName() return static::$eventLoopClass; } - if (!class_exists('\Swoole\Event')) { + if (!class_exists('\Swoole\Event', false)) { unset(static::$_availableEventLoops['swoole']); } From 6df60271e514201a17a96acb8ea16936000444cb Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 20 Sep 2018 17:11:43 +0800 Subject: [PATCH 0328/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 674e7fa26..401b3d485 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.14'; + const VERSION = '3.5.15'; /** * Status starting. From 219d1aedbc27c1673b01ee5c7ace9ec975851083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E9=AC=BC?= Date: Fri, 21 Sep 2018 14:21:11 +0800 Subject: [PATCH 0329/1216] update --- Worker.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Worker.php b/Worker.php index 7bee4cfd2..1e6359086 100644 --- a/Worker.php +++ b/Worker.php @@ -2247,8 +2247,7 @@ public function resumeAccept() if ($this->transport !== 'udp') { static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { - static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, - array($this, 'acceptUdpConnection')); + static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } $this->_pauseAccept = false; } @@ -2418,13 +2417,25 @@ public function acceptUdpConnection($socket) if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ $parser = $this->protocol; - $recv_buffer = $parser::decode($recv_buffer, $connection); - // Discard bad packets. - if ($recv_buffer === false) - return true; + if(method_exists($parser,'input')){ + while($recv_buffer !== ''){ + $len = $parser::input($recv_buffer, $connection); + $package = substr($recv_buffer,0,$len); + $recv_buffer = substr($recv_buffer,$len); + $data = $parser::decode($package,$connection); + if ($data === false) + continue; + call_user_func($this->onMessage, $connection, $data); + } + }else{ + $data = $parser::decode($recv_buffer, $connection); + // Discard bad packets. + if ($data === false) + return true; + call_user_func($this->onMessage, $connection, $data); + } } ConnectionInterface::$statistics['total_request']++; - call_user_func($this->onMessage, $connection, $recv_buffer); } catch (\Exception $e) { static::log($e); exit(250); From c40391375b5af8575b43e7d04bdd03650de400f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E9=AC=BC?= Date: Fri, 21 Sep 2018 14:29:20 +0800 Subject: [PATCH 0330/1216] fixbug --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index 1e6359086..c92610f65 100644 --- a/Worker.php +++ b/Worker.php @@ -2434,6 +2434,8 @@ public function acceptUdpConnection($socket) return true; call_user_func($this->onMessage, $connection, $data); } + }else{ + call_user_func($this->onMessage, $connection, $recv_buffer); } ConnectionInterface::$statistics['total_request']++; } catch (\Exception $e) { From 14f563fb81b1c22d819d6b90f2b6809935e8d7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E9=AC=BC?= Date: Fri, 21 Sep 2018 15:52:44 +0800 Subject: [PATCH 0331/1216] update --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index c92610f65..6ea78fec7 100644 --- a/Worker.php +++ b/Worker.php @@ -2420,6 +2420,8 @@ public function acceptUdpConnection($socket) if(method_exists($parser,'input')){ while($recv_buffer !== ''){ $len = $parser::input($recv_buffer, $connection); + if($len == 0) + return true; $package = substr($recv_buffer,0,$len); $recv_buffer = substr($recv_buffer,$len); $data = $parser::decode($package,$connection); From c5306c1be1c9029270b6b905751343cb8d15b77f Mon Sep 17 00:00:00 2001 From: Jack Cherng Date: Mon, 1 Oct 2018 09:32:59 +0800 Subject: [PATCH 0332/1216] Fix PHP 7.3 warning: "continue" targeting switch is equivalent to "break" Signed-off-by: Jack Cherng --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 0ff125b76..2bea47149 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -565,7 +565,7 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) 'file_data' => $boundary_value, 'file_size' => strlen($boundary_value), ); - continue; + continue 2; } // Is post field. else { // Parse $_POST. From f7c1797bc73188ed78ce666c53f745b4765d5fc3 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Oct 2018 15:35:16 +0800 Subject: [PATCH 0333/1216] Update AsyncUdpConnection.php --- Connection/AsyncUdpConnection.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 62dca92de..fdae3480c 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -185,6 +185,9 @@ public function connect() Worker::safeEcho(new \Exception($errmsg)); return; } + + stream_set_blocking($this->_socket, false); + if ($this->onMessage) { Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); } From 774cd174e7342947f5d6a8f32c1f9cb55227725f Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Oct 2018 18:30:00 +0800 Subject: [PATCH 0334/1216] support host header setting #373 --- Protocols/Ws.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index e5a7d66dd..0f92cfb05 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -366,25 +366,27 @@ public static function sendHandshake($connection) $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->websocketSecKey = base64_encode(md5(mt_rand(), true)); - $userHeader = ''; - if (!empty($connection->wsHttpHeader)) { - if (is_array($connection->wsHttpHeader)){ - foreach($connection->wsHttpHeader as $k=>$v){ - $userHeader .= "$k: $v\r\n"; + $user_header = isset($connection->headers) ? $connection->headers : + (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); + $user_header_str = ''; + if (!empty($user_header)) { + if (is_array($user_header)){ + foreach($user_header as $k=>$v){ + $user_header_str .= "$k: $v\r\n"; } - }else{ - $userHeader .= $connection->wsHttpHeader; + } else { + $user_header_str .= $user_header; } - $userHeader = "\r\n".trim($userHeader); + $user_header_str = "\r\n".trim($user_header_str); } $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". - "Host: $host\r\n". + (!preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). "Sec-WebSocket-Version: 13\r\n". - "Sec-WebSocket-Key: " . $connection->websocketSecKey . $userHeader . "\r\n\r\n"; + "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; From 26bcc71f7e91a426775ccca5642f93e63b5c5a93 Mon Sep 17 00:00:00 2001 From: Mikhail Shemelin Date: Mon, 15 Oct 2018 23:40:51 +0200 Subject: [PATCH 0335/1216] Allow to use different max package sizes for connections --- Connection/TcpConnection.php | 14 +++++++++++--- Protocols/Http.php | 2 +- Protocols/Text.php | 2 +- Protocols/Websocket.php | 2 +- Protocols/Ws.php | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 927a0d302..12c61f04b 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -165,11 +165,18 @@ class TcpConnection extends ConnectionInterface public static $defaultMaxSendBufferSize = 1048576; /** - * Maximum acceptable packet size. + * Sets the maximum acceptable packet size for the current connection. * * @var int */ - public static $maxPackageSize = 10485760; + public $maxPackageSize = 1048576; + + /** + * Default maximum acceptable packet size. + * + * @var int + */ + public static $defaultMaxPackageSize = 10485760; /** * Id recorder. @@ -298,6 +305,7 @@ public function __construct($socket, $remote_address = '') } Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; } @@ -615,7 +623,7 @@ public function baseRead($socket, $check_eof = true) // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; - } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= static::$maxPackageSize) { + } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. if ($this->_currentPackageLength > strlen($this->_recvBuffer)) { break; diff --git a/Protocols/Http.php b/Protocols/Http.php index 2bea47149..99febed83 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -38,7 +38,7 @@ public static function input($recv_buffer, TcpConnection $connection) { if (!strpos($recv_buffer, "\r\n\r\n")) { // Judge whether the package length exceeds the limit. - if (strlen($recv_buffer) >= $connection::$maxPackageSize) { + if (strlen($recv_buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } diff --git a/Protocols/Text.php b/Protocols/Text.php index 5c78852c7..a0b1cc9e4 100644 --- a/Protocols/Text.php +++ b/Protocols/Text.php @@ -30,7 +30,7 @@ class Text public static function input($buffer, TcpConnection $connection) { // Judge whether the package length exceeds the limit. - if (strlen($buffer) >= $connection::$maxPackageSize) { + if (strlen($buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 7ebf59111..146063f96 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -140,7 +140,7 @@ public static function input($buffer, ConnectionInterface $connection) $current_frame_length = $head_len + $data_len; $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > $connection::$maxPackageSize) { + if ($total_package_size > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 0f92cfb05..917ca02e3 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -137,7 +137,7 @@ public static function input($buffer, $connection) } $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > $connection::$maxPackageSize) { + if ($total_package_size > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); return 0; From 56e585078920246250ab808b6452a760267608b5 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 26 Oct 2018 21:34:33 +0800 Subject: [PATCH 0336/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index afe2b50e1..9c8ea44e8 100644 --- a/Worker.php +++ b/Worker.php @@ -336,7 +336,7 @@ class Worker protected static $_workers = array(); /** - * All worker porcesses pid. + * All worker processes pid. * The format is like this [worker_id=>[pid=>pid, pid=>pid, ..], ..] * * @var array @@ -606,7 +606,7 @@ protected static function initWorkers() // Status name. $worker->status = ' [OK] '; - // Get clolumn mapping for UI + // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; $prop_length = strlen($worker->{$prop}); From b480e579427321ce6305b1971fdbc303947b9b71 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 7 Nov 2018 17:51:43 +0800 Subject: [PATCH 0337/1216] Update Select.php --- Events/Select.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index a1e2cf084..801586b52 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -262,7 +262,6 @@ public function clearAllTimer() */ public function loop() { - $e = null; while (1) { if(DIRECTORY_SEPARATOR === '/') { // Calls signal handlers for pending signals From 7369e76fe2538596478c772b44d2a5cf6f6a17b6 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 18 Nov 2018 14:02:17 +0800 Subject: [PATCH 0338/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 12c61f04b..b85c6e69a 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -835,6 +835,8 @@ public function close($data = null, $raw = false) } if ($this->_sendBuffer === '') { $this->destroy(); + } else { + $this->pauseRecv(); } } From 9db5b06274e4f38cac2e72915cef8143479d3740 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 18 Nov 2018 14:03:01 +0800 Subject: [PATCH 0339/1216] Update AsyncTcpConnection.php --- Connection/AsyncTcpConnection.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 162c33a8d..ce6bfad73 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -288,15 +288,18 @@ protected function emitError($code, $msg) */ public function checkConnection() { - if ($this->_status != self::STATUS_CONNECTING) { - return; - } - // Remove EV_EXPECT for windows. if(DIRECTORY_SEPARATOR === '\\') { Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT); } + // Remove write listener. + Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + + if ($this->_status != self::STATUS_CONNECTING) { + return; + } + // Check socket state. if ($address = stream_socket_get_name($this->_socket, true)) { // Nonblocking. @@ -312,9 +315,6 @@ public function checkConnection() socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } - // Remove write listener. - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); - // SSL handshake. if ($this->transport === 'ssl') { $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket); From b374bb86f9dae74bf373e924173a891eb6435c7a Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 18 Nov 2018 14:16:58 +0800 Subject: [PATCH 0340/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 9c8ea44e8..a72e9fc7b 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.15'; + const VERSION = '3.5.16'; /** * Status starting. From 9893a3b26eb06f9d35a760e0dd049a5dacbfcb40 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Nov 2018 14:54:52 +0800 Subject: [PATCH 0341/1216] fix #386 fix #386 --- Protocols/Text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Text.php b/Protocols/Text.php index a0b1cc9e4..84b937a99 100644 --- a/Protocols/Text.php +++ b/Protocols/Text.php @@ -65,6 +65,6 @@ public static function encode($buffer) public static function decode($buffer) { // Remove "\n" - return trim($buffer); + return rtrim($buffer, "\r\n"); } } From 7858f62f2d2fe650ca0af88b6fc0057c4db8946d Mon Sep 17 00:00:00 2001 From: Linke Cheng Date: Sun, 2 Dec 2018 19:58:44 +0800 Subject: [PATCH 0342/1216] add Lib\SendFile.php --- Lib/SendFile.php | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Lib/SendFile.php diff --git a/Lib/SendFile.php b/Lib/SendFile.php new file mode 100644 index 000000000..9c9fa4858 --- /dev/null +++ b/Lib/SendFile.php @@ -0,0 +1,83 @@ + + * @copyright linkec + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Lib; + +use Workerman\Events\EventInterface; +use Workerman\Worker; +use Exception; + +class SendFile +{ + private $connection = null; + private $handle = null; + private $offset = 0; + private $fileSize = 0; + private $chunkSize = 1048576; + + function __construct($connection,$file) + { + $this->connection = $connection; + if(!file_exists($file)){ + return; + } + $this->fileSize = filesize($file); + $this->handle = fopen($file,"rb"); + } + + public function _sendFile($socket) + { + if($this->offset>$this->fileSize){ + //release handle and remove event + fclose($this->handle); + Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); + return; + } + eio_sendfile($socket,$this->handle,$this->offset,$this->chunkSize); + $this->offset += $this->chunkSize; + eio_event_loop(); + } + + public function send(){ + if(!$this->handle){ + $header = "HTTP/1.1 404 Content Not Found\r\n"; + $header .= "Content-Type: text/html;\r\n"; + $header .= "Server: workerman/" . Worker::VERSION . "\r\n"; + $header .= "\r\n"; + $content = '

404 Content Not Found!

'; + $this->connection->send($header.$content,true); + return; + } + // Default http-code. + if (!isset(\Workerman\Protocols\HttpCache::$header['Http-Code'])) { + $header = "HTTP/1.1 200 OK\r\n"; + } else { + $header = \Workerman\Protocols\HttpCache::$header['Http-Code'] . "\r\n"; + unset(\Workerman\Protocols\HttpCache::$header['Http-Code']); + } + + // Content-Type + if (!isset(\Workerman\Protocols\HttpCache::$header['Content-Type'])) { + $header .= "Content-Type: application/octet-stream;\r\n"; + } + + // header + $header .= "Server: workerman/" . Worker::VERSION . "\r\n"; + $header .= "Content-Length: ". $this->fileSize .";\r\n"; + $header .= "\r\n"; + $this->connection->send($header,true); + + //regist event + Worker::$globalEvent->add($this->connection->getSocket(), EventInterface::EV_WRITE, array($this, '_sendFile')); + } +} \ No newline at end of file From 823aa7c9dd185ae2648f8c7164fbe934bc5e0ef4 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 10 Dec 2018 16:30:33 +0800 Subject: [PATCH 0343/1216] fix notice --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a72e9fc7b..e10e359db 100644 --- a/Worker.php +++ b/Worker.php @@ -719,7 +719,7 @@ protected static function displayUI() //Show last line $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; - $content && static::safeEcho($line_last); + !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); From 1c02b02397230adaa50ca769db6f5c6402c79884 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 27 Dec 2018 15:38:27 +0800 Subject: [PATCH 0344/1216] Avoid conflict with php-fpm/apache --- Protocols/Http.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 99febed83..7ad7ebe8b 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -382,7 +382,7 @@ public static function sessionId($id = null) return $id ? session_id($id) : session_id(); } if (static::sessionStarted() && HttpCache::$instance->sessionFile) { - return str_replace('sess_', '', basename(HttpCache::$instance->sessionFile)); + return str_replace('ses_', '', basename(HttpCache::$instance->sessionFile)); } return ''; } @@ -455,11 +455,11 @@ public static function sessionStart() } HttpCache::$instance->sessionStarted = true; // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName])) { + if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName])) { // Create a unique session_id and the associated file name. while (true) { $session_id = static::sessionCreateId(); - if (!is_file($file_name = HttpCache::$sessionPath . '/sess_' . $session_id)) break; + if (!is_file($file_name = HttpCache::$sessionPath . '/ses_' . $session_id)) break; } HttpCache::$instance->sessionFile = $file_name; return self::setcookie( @@ -473,7 +473,7 @@ public static function sessionStart() ); } if (!HttpCache::$instance->sessionFile) { - HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName]; + HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName]; } // Read session from session file. if (HttpCache::$instance->sessionFile) { From 8b2be5101c9f4359b98d33e5cce0f2460add709d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 27 Dec 2018 16:12:05 +0800 Subject: [PATCH 0345/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index e10e359db..a7bfbc384 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.16'; + const VERSION = '3.5.17'; /** * Status starting. From 5441016548e3a3ce2d68b3a7d34d6373d11bb684 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 27 Dec 2018 16:13:00 +0800 Subject: [PATCH 0346/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a7bfbc384..bdb6bcd66 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.17'; + const VERSION = '3.5.18'; /** * Status starting. From f615edc0a550645778c6f8911830e4e12b0c5d45 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 19 Jan 2019 10:36:12 +0800 Subject: [PATCH 0347/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index b85c6e69a..3f5e732d4 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -952,6 +952,7 @@ public function destroy() exit(250); } } + $this->_sendBuffer = $this->_recvBuffer = ''; if ($this->_status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; From 9f36bb4cb718c6fd5b03771bd5f266cd371bb23e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 24 Jan 2019 14:47:15 +0800 Subject: [PATCH 0348/1216] Avoid running multiple times --- Worker.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Worker.php b/Worker.php index bdb6bcd66..d9e62d68d 100644 --- a/Worker.php +++ b/Worker.php @@ -1178,6 +1178,14 @@ protected static function saveMasterPid() if (static::$_OS !== OS_TYPE_LINUX) { return; } + + clearstatcache(); + $master_pid = is_file(static::$pidFile) ? file_get_contents(static::$pidFile) : 0; + $master_is_alive = $master_pid && posix_kill($master_pid, 0) && posix_getpid() != $master_pid; + if ($master_is_alive) { + static::log("Workerman already running"); + exit; + } static::$_masterPid = posix_getpid(); if (false === file_put_contents(static::$pidFile, static::$_masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); From c141341367ac15a13e045c703925f44540e66988 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 14 Feb 2019 16:23:56 +0800 Subject: [PATCH 0349/1216] Add file lock for avoid running multiple times close #400 --- Worker.php | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Worker.php b/Worker.php index d9e62d68d..da984e820 100644 --- a/Worker.php +++ b/Worker.php @@ -498,11 +498,13 @@ public static function runAll() { static::checkSapiEnv(); static::init(); + static::lock(); static::parseCommand(); static::daemonize(); static::initWorkers(); static::installSignal(); static::saveMasterPid(); + static::unlock(); static::displayUI(); static::forkWorkers(); static::resetStd(); @@ -575,6 +577,31 @@ protected static function init() Timer::init(); } + /** + * Lock. + * + * @return void + */ + protected static function lock() + { + $fd = fopen(static::$_startFile, 'r'); + if (!$fd || !flock($fd, LOCK_EX)) { + static::log("Workerman[".static::$_startFile."] already running"); + exit; + } + } + + /** + * Unlock. + * + * @return void + */ + protected static function unlock() + { + $fd = fopen(static::$_startFile, 'r'); + $fd && flock($fd, LOCK_UN); + } + /** * Init All worker instances. * @@ -1179,13 +1206,6 @@ protected static function saveMasterPid() return; } - clearstatcache(); - $master_pid = is_file(static::$pidFile) ? file_get_contents(static::$pidFile) : 0; - $master_is_alive = $master_pid && posix_kill($master_pid, 0) && posix_getpid() != $master_pid; - if ($master_is_alive) { - static::log("Workerman already running"); - exit; - } static::$_masterPid = posix_getpid(); if (false === file_put_contents(static::$pidFile, static::$_masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); From 12a9eb936a5884cd98d60981953f862cedb94762 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 14 Feb 2019 17:02:33 +0800 Subject: [PATCH 0350/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index da984e820..eb539361a 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.18'; + const VERSION = '3.5.19'; /** * Status starting. From fb14f039c724cfcac35f16f33e47a62101819848 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 21 Feb 2019 12:20:47 +0800 Subject: [PATCH 0351/1216] ssl3 info --- Connection/TcpConnection.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 3f5e732d4..c6f563724 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -746,12 +746,23 @@ public function doSslHandshake($socket){ return false; } $async = $this instanceof AsyncTcpConnection; + + /** + * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. + * You can enable ssl3 by the codes below. + */ + /*if($async){ + $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT; + }else{ + $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER; + }*/ + if($async){ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; }else{ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - + // Hidden error. set_error_handler(function($errno, $errstr, $file){ if (!Worker::$daemonize) { From 844a4c4ffe4e00aad521331ae6a714e3ee46906a Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 21 Feb 2019 20:53:09 +0800 Subject: [PATCH 0352/1216] fix duplicate EV_TIMER_ONCE id --- Events/Swoole.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index baefdb99b..40ef499de 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -23,6 +23,8 @@ class Swoole implements EventInterface protected $_timerOnceMap = array(); + protected $mapId = 0; + protected $_fd = array(); // milisecond @@ -55,7 +57,10 @@ function () { case self::EV_TIMER: case self::EV_TIMER_ONCE: $method = self::EV_TIMER == $flag ? 'tick' : 'after'; - $mapId = count($this->_timerOnceMap); + if ($this->mapId > PHP_INT_MAX) { + $this->mapId = 0; + } + $mapId = $this->mapId++; $timer_id = Timer::$method($fd * 1000, function ($timer_id = null) use ($func, $args, $mapId) { call_user_func_array($func, $args); From 89831799e9bb511404ce0289b1e7c2fdcd83d1a6 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Feb 2019 16:29:16 +0800 Subject: [PATCH 0353/1216] check valid stream --- Connection/AsyncTcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index ce6bfad73..8800d19bd 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -189,7 +189,7 @@ public function connect() STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. - if (!$this->_socket) { + if (!$this->_socket || !is_resource($this->_socket)) { $this->emitError(WORKERMAN_CONNECT_FAIL, $errstr); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); From 23ed0c5274523277d9d2f6fc732a54af5630cbda Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 20 Mar 2019 14:45:25 +0800 Subject: [PATCH 0354/1216] Update Http.php --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 7ad7ebe8b..12f7a2fb5 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -565,7 +565,7 @@ protected static function parseUploadFiles($http_body, $http_post_boundary) 'file_data' => $boundary_value, 'file_size' => strlen($boundary_value), ); - continue 2; + break; } // Is post field. else { // Parse $_POST. From 9e14e3784ce8d1c99f834200728beda8d33fb682 Mon Sep 17 00:00:00 2001 From: Linke Cheng Date: Mon, 25 Mar 2019 12:01:07 +0800 Subject: [PATCH 0355/1216] remove sendfile --- Lib/SendFile.php | 83 ------------------------------------------------ 1 file changed, 83 deletions(-) delete mode 100644 Lib/SendFile.php diff --git a/Lib/SendFile.php b/Lib/SendFile.php deleted file mode 100644 index 9c9fa4858..000000000 --- a/Lib/SendFile.php +++ /dev/null @@ -1,83 +0,0 @@ - - * @copyright linkec - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Lib; - -use Workerman\Events\EventInterface; -use Workerman\Worker; -use Exception; - -class SendFile -{ - private $connection = null; - private $handle = null; - private $offset = 0; - private $fileSize = 0; - private $chunkSize = 1048576; - - function __construct($connection,$file) - { - $this->connection = $connection; - if(!file_exists($file)){ - return; - } - $this->fileSize = filesize($file); - $this->handle = fopen($file,"rb"); - } - - public function _sendFile($socket) - { - if($this->offset>$this->fileSize){ - //release handle and remove event - fclose($this->handle); - Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); - return; - } - eio_sendfile($socket,$this->handle,$this->offset,$this->chunkSize); - $this->offset += $this->chunkSize; - eio_event_loop(); - } - - public function send(){ - if(!$this->handle){ - $header = "HTTP/1.1 404 Content Not Found\r\n"; - $header .= "Content-Type: text/html;\r\n"; - $header .= "Server: workerman/" . Worker::VERSION . "\r\n"; - $header .= "\r\n"; - $content = '

404 Content Not Found!

'; - $this->connection->send($header.$content,true); - return; - } - // Default http-code. - if (!isset(\Workerman\Protocols\HttpCache::$header['Http-Code'])) { - $header = "HTTP/1.1 200 OK\r\n"; - } else { - $header = \Workerman\Protocols\HttpCache::$header['Http-Code'] . "\r\n"; - unset(\Workerman\Protocols\HttpCache::$header['Http-Code']); - } - - // Content-Type - if (!isset(\Workerman\Protocols\HttpCache::$header['Content-Type'])) { - $header .= "Content-Type: application/octet-stream;\r\n"; - } - - // header - $header .= "Server: workerman/" . Worker::VERSION . "\r\n"; - $header .= "Content-Length: ". $this->fileSize .";\r\n"; - $header .= "\r\n"; - $this->connection->send($header,true); - - //regist event - Worker::$globalEvent->add($this->connection->getSocket(), EventInterface::EV_WRITE, array($this, '_sendFile')); - } -} \ No newline at end of file From e5128bcd86f88370fe9aaebfef160a715864eb12 Mon Sep 17 00:00:00 2001 From: laogui Date: Mon, 1 Apr 2019 20:04:00 +0800 Subject: [PATCH 0356/1216] Add get main socket resource function UDP application can init UdpConnection class and send message where have a client remote address --- Worker.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Worker.php b/Worker.php index eb539361a..8dbbb57f6 100644 --- a/Worker.php +++ b/Worker.php @@ -667,6 +667,14 @@ public static function getEventLoop() { return static::$globalEvent; } + + /** + * Get main socket resource + * @return resource + */ + public function getMainSocket(){ + return $this->_mainSocket; + } /** * Init idMap. From 4e5c24073b431fd950287efbfb5cc9b4c0fc7367 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Apr 2019 18:35:31 +0800 Subject: [PATCH 0357/1216] remove default timezone #411 --- Lib/Constants.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 5048a3970..1b3561b11 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -12,10 +12,6 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ -// Date.timezone -if (!ini_get('date.timezone')) { - date_default_timezone_set('Asia/Shanghai'); -} // Display errors. ini_set('display_errors', 'on'); // Reporting all. From 13649907f05014fcfffcfccaef01e63ad3339351 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 30 Apr 2019 09:51:25 +0800 Subject: [PATCH 0358/1216] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c0d4ddb3a..33869e560 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,13 @@ [![License](https://poser.pugx.org/workerman/workerman/license)](https://packagist.org/packages/workerman/workerman) ## What is it -Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket, SSL and other custom protocols. Supports libevent, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). +Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket, SSL and other custom protocols. Supports libevent/event extension, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). ## Requires PHP 5.3 or Higher A POSIX compatible operating system (Linux, OSX, BSD) -POSIX and PCNTL extensions for PHP +POSIX and PCNTL extensions required +Event extension recommended for better performance ## Installation From 0506d795e3d99cd5270186ee6311b21307517c9f Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Jun 2019 14:44:34 +0800 Subject: [PATCH 0359/1216] check closed state on ssl handshake --- Connection/AsyncTcpConnection.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 8800d19bd..e785bf775 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -318,6 +318,9 @@ public function checkConnection() // SSL handshake. if ($this->transport === 'ssl') { $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket); + if ($this->_sslHandshakeCompleted === false) { + return; + } } else { // There are some data waiting to send. if ($this->_sendBuffer) { From e23ffda31bc1241a50cc3c0635e866c27ecee2e5 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Jun 2019 14:46:07 +0800 Subject: [PATCH 0360/1216] check closed state after ssl handshake --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index c6f563724..b05a43c04 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -777,7 +777,7 @@ public function doSslHandshake($socket){ return false; } elseif (0 === $ret) { // There isn't enough data and should try again. - return false; + return 0; } if (isset($this->onSslHandshake)) { try { From 6127e345e967780ed78d144b21ed1546cc8d9d9a Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Jun 2019 14:47:01 +0800 Subject: [PATCH 0361/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 8dbbb57f6..97efa5151 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.19'; + const VERSION = '3.5.20'; /** * Status starting. From b5145b12f9ceddce36a69fa50d0dca0abbe78218 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 2 Jul 2019 18:19:42 +0800 Subject: [PATCH 0362/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 97efa5151..bd4b7c084 100644 --- a/Worker.php +++ b/Worker.php @@ -1334,7 +1334,7 @@ protected static function forkWorkersForWindows() if(count(static::$_workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); - static::safeEcho("@@@ Please visit http://wiki.workerman.net/Multi_woker_for_win @@@\r\n"); + static::safeEcho("@@@ See http://doc.workerman.net/faq/multi-woker-for-windows.html @@@\r\n"); } elseif(count(static::$_workers) <= 0) { From 4c173c30505d49656b71d315963f960280ba3d41 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 2 Jul 2019 18:22:09 +0800 Subject: [PATCH 0363/1216] websocket tips --- Protocols/Websocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 146063f96..7d1bd9e63 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -356,7 +356,7 @@ protected static function dealHandshake($buffer, $connection) if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Sec-WebSocket-Key not found.
This is a WebSocket service and can not be accessed via HTTP.
See http://wiki.workerman.net/Error1 for detail.", + $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n", true); $connection->close(); return 0; @@ -441,7 +441,7 @@ protected static function dealHandshake($buffer, $connection) return 0; } // Bad websocket handshake request. - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n400 Bad Request
Invalid handshake data for websocket.
See http://wiki.workerman.net/Error1 for detail.", + $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n", true); $connection->close(); return 0; From 4d590130310a8d7632f807120c3ca1c0f55ed0d7 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 2 Jul 2019 18:23:18 +0800 Subject: [PATCH 0364/1216] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 95c30972c..fdd4808a2 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "email": "walkor@workerman.net", "issues": "https://github.com/walkor/workerman/issues", "forum": "http://wenda.workerman.net/", - "wiki": "http://doc3.workerman.net/index.html", + "wiki": "http://doc.workerman.net/", "source": "https://github.com/walkor/workerman" }, "require": { From fe7f9c30780871738823af582ce9b7f17e9bf18b Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 11 Jul 2019 00:59:03 +0800 Subject: [PATCH 0365/1216] Remove forced ws client header 'Origin'. This is not needed in common cases and may cause 4xx response. The default value '*' is also invalid. --- Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 917ca02e3..8b3aae74a 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -383,7 +383,7 @@ public static function sendHandshake($connection) (!preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". - "Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n". + (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":''). (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). "Sec-WebSocket-Version: 13\r\n". "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; From bc5d3a4db2002f116fc403c71ccee0058a5d4f13 Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 11 Jul 2019 01:21:08 +0800 Subject: [PATCH 0366/1216] Fix sendHandshake() child override --- Protocols/Ws.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 8b3aae74a..caeaff785 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -234,7 +234,7 @@ public static function encode($payload, $connection) } $payload = (string)$payload; if (empty($connection->handshakeStep)) { - self::sendHandshake($connection); + static::sendHandshake($connection); } $mask = 1; $mask_key = "\x00\x00\x00\x00"; @@ -330,7 +330,7 @@ public static function decode($bytes, $connection) */ public static function onConnect($connection) { - self::sendHandshake($connection); + static::sendHandshake($connection); } /** From 01ea5037f268fcc465f61a6039327e4212fe3463 Mon Sep 17 00:00:00 2001 From: Ares Date: Wed, 24 Jul 2019 16:48:06 +0800 Subject: [PATCH 0367/1216] Discard sending data when status is connecting on close. --- Connection/TcpConnection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index b05a43c04..c0297ac67 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -836,6 +836,10 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { + if($this->_status === self::STATUS_CONNECTING){ + $this->destroy(); + return; + } if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { return; } else { From c3f33c4354fa3a87784d00d3b7c8d761f5c56f50 Mon Sep 17 00:00:00 2001 From: Ares Date: Fri, 26 Jul 2019 12:35:55 +0800 Subject: [PATCH 0368/1216] Bump websocket decode performance to %40000 or more in heavy traffic. --- Protocols/Websocket.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 7d1bd9e63..6237f2153 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -304,7 +304,6 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $masks = $data = $decoded = ''; $len = ord($buffer[1]) & 127; if ($len === 126) { $masks = substr($buffer, 4, 4); @@ -318,9 +317,9 @@ public static function decode($buffer, ConnectionInterface $connection) $data = substr($buffer, 6); } } - for ($index = 0; $index < strlen($data); $index++) { - $decoded .= $data[$index] ^ $masks[$index % 4]; - } + $dataLength = strlen($data); + $masks = str_repeat($masks, floor($dataLength / 4)) . substr($masks, 0, $dataLength % 4); + $decoded = $data ^ $masks; if ($connection->websocketCurrentFrameLength) { $connection->websocketDataBuffer .= $decoded; return $connection->websocketDataBuffer; From 981eea39b26653a88769745905a0c2a459eefdd0 Mon Sep 17 00:00:00 2001 From: Ares Date: Sat, 27 Jul 2019 00:40:44 +0800 Subject: [PATCH 0369/1216] optimize Ws protocol encode performance --- Protocols/Ws.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index caeaff785..e3ce4a615 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -254,9 +254,8 @@ public static function encode($payload, $connection) $frame = $head . $mask_key; // append payload to frame: - for ($i = 0; $i < $length; $i++) { - $frame .= $payload[$i] ^ $mask_key[$i % 4]; - } + $mask_key = str_repeat($mask_key, floor($length / 4)) . substr($mask_key, 0, $length % 4); + $frame .= $payload ^ $mask_key; if ($connection->handshakeStep === 1) { // If buffer has already full then discard the current package. if (strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { From 078cf5f339ebdbf6e93362bc44b983cfc4fab1c1 Mon Sep 17 00:00:00 2001 From: Link Date: Sat, 27 Jul 2019 17:35:37 +0800 Subject: [PATCH 0370/1216] fix keep-alived only on php --- WebServer.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/WebServer.php b/WebServer.php index 82ea77695..f529399f9 100644 --- a/WebServer.php +++ b/WebServer.php @@ -154,7 +154,11 @@ public function onMessage($connection) $workerman_url_info = parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); if (!$workerman_url_info) { Http::header('HTTP/1.1 400 Bad Request'); - $connection->close('

400 Bad Request

'); + if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $connection->send('

400 Bad Request

'); + } else { + $connection->close('

400 Bad Request

'); + } return; } @@ -188,7 +192,11 @@ public function onMessage($connection) $workerman_root_dir_realpath) ) { Http::header('HTTP/1.1 400 Bad Request'); - $connection->close('

400 Bad Request

'); + if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $connection->send('

400 Bad Request

'); + } else { + $connection->close('

400 Bad Request

'); + } return; } @@ -233,7 +241,11 @@ public function onMessage($connection) }else{ $html404 = '404 File not found

404 Not Found

'; } - $connection->close($html404); + if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $connection->send($html404); + } else { + $connection->close($html404); + } return; } } @@ -249,7 +261,11 @@ public static function sendFile($connection, $file_path) // 304 Http::header('HTTP/1.1 304 Not Modified'); // Send nothing but http headers.. - $connection->close(''); + if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $connection->send(''); + } else { + $connection->close(''); + } return; } } From 5dc6da08eeb789a2ea1cfd5262d87bd4dc7b550f Mon Sep 17 00:00:00 2001 From: Ares Date: Thu, 1 Aug 2019 14:56:27 +0800 Subject: [PATCH 0371/1216] Different protocol has different type for Protocol::encode().Fix ide complain of param type mismatch. --- Connection/ConnectionInterface.php | 2 +- Connection/TcpConnection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Connection/ConnectionInterface.php b/Connection/ConnectionInterface.php index 5ddd2f827..622862a5c 100644 --- a/Connection/ConnectionInterface.php +++ b/Connection/ConnectionInterface.php @@ -54,7 +54,7 @@ abstract class ConnectionInterface /** * Sends data on the connection. * - * @param string $send_buffer + * @param mixed $send_buffer * @return void|boolean */ abstract public function send($send_buffer); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index c0297ac67..98419d364 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -328,7 +328,7 @@ public function getStatus($raw_output = true) /** * Sends data on the connection. * - * @param string $send_buffer + * @param mixed $send_buffer * @param bool $raw * @return bool|null */ From 17b8cf08a76b0cf426047ed24a0fc29853e6aea7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 2 Aug 2019 18:53:39 +0800 Subject: [PATCH 0372/1216] Update Worker.php --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index bd4b7c084..eda9a6855 100644 --- a/Worker.php +++ b/Worker.php @@ -1090,6 +1090,8 @@ protected static function reinstallSignal() pcntl_signal(SIGQUIT, SIG_IGN, false); // uninstall status signal handler pcntl_signal(SIGUSR2, SIG_IGN, false); + // uninstall connections status signal handler + pcntl_signal(SIGIO, SIG_IGN, false); // reinstall stop signal handler static::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful stop signal handler From ef6fe16cff13ce0e853934adc8fc90ef0d2f9212 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 28 Aug 2019 16:49:03 +0800 Subject: [PATCH 0373/1216] performance optimization --- Autoloader.php | 14 +- Connection/AsyncTcpConnection.php | 48 +-- Connection/AsyncUdpConnection.php | 30 +- Connection/TcpConnection.php | 124 +++---- Connection/UdpConnection.php | 22 +- Events/Ev.php | 6 +- Events/Event.php | 8 +- Events/Libevent.php | 40 +-- Events/React/Base.php | 6 +- Events/Select.php | 34 +- Events/Swoole.php | 12 +- Lib/Timer.php | 20 +- Protocols/Frame.php | 10 +- Protocols/Http.php | 167 +++++----- Protocols/Text.php | 6 +- Protocols/Websocket.php | 108 +++--- Protocols/Ws.php | 92 +++--- WebServer.php | 70 ++-- Worker.php | 532 +++++++++++++++--------------- 19 files changed, 675 insertions(+), 674 deletions(-) diff --git a/Autoloader.php b/Autoloader.php index 45773c914..2a2e59e15 100644 --- a/Autoloader.php +++ b/Autoloader.php @@ -44,21 +44,21 @@ public static function setRootPath($root_path) */ public static function loadByNamespace($name) { - $class_path = str_replace('\\', DIRECTORY_SEPARATOR, $name); - if (strpos($name, 'Workerman\\') === 0) { - $class_file = __DIR__ . substr($class_path, strlen('Workerman')) . '.php'; + $class_path = \str_replace('\\', DIRECTORY_SEPARATOR, $name); + if (\strpos($name, 'Workerman\\') === 0) { + $class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php'; } else { if (self::$_autoloadRootPath) { $class_file = self::$_autoloadRootPath . DIRECTORY_SEPARATOR . $class_path . '.php'; } - if (empty($class_file) || !is_file($class_file)) { + if (empty($class_file) || !\is_file($class_file)) { $class_file = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . "$class_path.php"; } } - if (is_file($class_file)) { + if (\is_file($class_file)) { require_once($class_file); - if (class_exists($name, false)) { + if (\class_exists($name, false)) { return true; } } @@ -66,4 +66,4 @@ public static function loadByNamespace($name) } } -spl_autoload_register('\Workerman\Autoloader::loadByNamespace'); \ No newline at end of file +\spl_autoload_register('\Workerman\Autoloader::loadByNamespace'); \ No newline at end of file diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e785bf775..5dd64afe2 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -111,9 +111,9 @@ class AsyncTcpConnection extends TcpConnection */ public function __construct($remote_address, $context_option = null) { - $address_info = parse_url($remote_address); + $address_info = \parse_url($remote_address); if (!$address_info) { - list($scheme, $this->_remoteAddress) = explode(':', $remote_address, 2); + list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2); if (!$this->_remoteAddress) { Worker::safeEcho(new \Exception('bad remote_address')); } @@ -142,11 +142,11 @@ public function __construct($remote_address, $context_option = null) } // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { - $scheme = ucfirst($scheme); + $scheme = \ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { + if (!\class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { + if (!\class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } @@ -173,23 +173,23 @@ public function connect() return; } $this->_status = self::STATUS_CONNECTING; - $this->_connectStartTime = microtime(true); + $this->_connectStartTime = \microtime(true); if ($this->transport !== 'unix') { // Open socket connection asynchronously. if ($this->_contextOption) { - $context = stream_context_create($this->_contextOption); - $this->_socket = stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + $context = \stream_context_create($this->_contextOption); + $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->_socket = stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); } } else { - $this->_socket = stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. - if (!$this->_socket || !is_resource($this->_socket)) { + if (!$this->_socket || !\is_resource($this->_socket)) { $this->emitError(WORKERMAN_CONNECT_FAIL, $errstr); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); @@ -269,7 +269,7 @@ protected function emitError($code, $msg) $this->_status = self::STATUS_CLOSING; if ($this->onError) { try { - call_user_func($this->onError, $this, $code, $msg); + \call_user_func($this->onError, $this, $code, $msg); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -301,18 +301,18 @@ public function checkConnection() } // Check socket state. - if ($address = stream_socket_get_name($this->_socket, true)) { + if ($address = \stream_socket_get_name($this->_socket, true)) { // Nonblocking. - stream_set_blocking($this->_socket, 0); + \stream_set_blocking($this->_socket, 0); // Compatible with hhvm - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->_socket, 0); + if (\function_exists('stream_set_read_buffer')) { + \stream_set_read_buffer($this->_socket, 0); } // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && $this->transport === 'tcp') { - $raw_socket = socket_import_stream($this->_socket); - socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); - socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); + if (\function_exists('socket_import_stream') && $this->transport === 'tcp') { + $raw_socket = \socket_import_stream($this->_socket); + \socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); + \socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } // SSL handshake. @@ -337,7 +337,7 @@ public function checkConnection() // Try to emit onConnect callback. if ($this->onConnect) { try { - call_user_func($this->onConnect, $this); + \call_user_func($this->onConnect, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -347,9 +347,9 @@ public function checkConnection() } } // Try to emit protocol::onConnect - if (method_exists($this->protocol, 'onConnect')) { + if (\method_exists($this->protocol, 'onConnect')) { try { - call_user_func(array($this->protocol, 'onConnect'), $this); + \call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -360,7 +360,7 @@ public function checkConnection() } } else { // Connection failed. - $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); + $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index fdae3480c..15b151f33 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -59,20 +59,20 @@ class AsyncUdpConnection extends UdpConnection public function __construct($remote_address, $context_option = null) { // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $remote_address, 2); + list($scheme, $address) = \explode(':', $remote_address, 2); // Check application layer protocol class. if ($scheme !== 'udp') { - $scheme = ucfirst($scheme); + $scheme = \ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { + if (!\class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { + if (!\class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } } - $this->_remoteAddress = substr($address, 2); + $this->_remoteAddress = \substr($address, 2); $this->_contextOption = $context_option; } @@ -84,7 +84,7 @@ public function __construct($remote_address, $context_option = null) */ public function baseRead($socket) { - $recv_buffer = stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + $recv_buffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); if (false === $recv_buffer || empty($remote_address)) { return false; } @@ -96,7 +96,7 @@ public function baseRead($socket) } ConnectionInterface::$statistics['total_request']++; try { - call_user_func($this->onMessage, $this, $recv_buffer); + \call_user_func($this->onMessage, $this, $recv_buffer); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -127,7 +127,7 @@ public function send($send_buffer, $raw = false) if ($this->connected === false) { $this->connect(); } - return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0); + return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0); } @@ -145,12 +145,12 @@ public function close($data = null, $raw = false) $this->send($data, $raw); } Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); - fclose($this->_socket); + \fclose($this->_socket); $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { try { - call_user_func($this->onClose, $this); + \call_user_func($this->onClose, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -174,11 +174,11 @@ public function connect() return; } if ($this->_contextOption) { - $context = stream_context_create($this->_contextOption); - $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, + $context = \stream_context_create($this->_contextOption); + $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, 30, STREAM_CLIENT_CONNECT, $context); } else { - $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); + $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); } if (!$this->_socket) { @@ -186,7 +186,7 @@ public function connect() return; } - stream_set_blocking($this->_socket, false); + \stream_set_blocking($this->_socket, false); if ($this->onMessage) { Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); @@ -195,7 +195,7 @@ public function connect() // Try to emit onConnect callback. if ($this->onConnect) { try { - call_user_func($this->onConnect, $this); + \call_user_func($this->onConnect, $this); } catch (\Exception $e) { Worker::log($e); exit(250); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 98419d364..4b0018f35 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -271,9 +271,9 @@ class TcpConnection extends ConnectionInterface */ public function __call($name, $arguments) { // Try to emit custom function within protocol - if (method_exists($this->protocol, $name)) { + if (\method_exists($this->protocol, $name)) { try { - return call_user_func(array($this->protocol, $name), $this, $arguments); + return \call_user_func(array($this->protocol, $name), $this, $arguments); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -298,10 +298,10 @@ public function __construct($socket, $remote_address = '') self::$_idRecorder = 0; } $this->_socket = $socket; - stream_set_blocking($this->_socket, 0); + \stream_set_blocking($this->_socket, 0); // Compatible with hhvm - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->_socket, 0); + if (\function_exists('stream_set_read_buffer')) { + \stream_set_read_buffer($this->_socket, 0); } Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; @@ -369,25 +369,25 @@ public function send($send_buffer, $raw = false) $this->checkBufferWillFull(); return null; } - set_error_handler(function(){}); - $len = fwrite($this->_socket, $send_buffer); - restore_error_handler(); + \set_error_handler(function(){}); + $len = \fwrite($this->_socket, $send_buffer); + \restore_error_handler(); // send successful. - if ($len === strlen($send_buffer)) { + if ($len === \strlen($send_buffer)) { $this->bytesWritten += $len; return true; } // Send only part of the data. if ($len > 0) { - $this->_sendBuffer = substr($send_buffer, $len); + $this->_sendBuffer = \substr($send_buffer, $len); $this->bytesWritten += $len; } else { // Connection closed? - if (!is_resource($this->_socket) || feof($this->_socket)) { + if (!\is_resource($this->_socket) || \feof($this->_socket)) { self::$statistics['send_fail']++; if ($this->onError) { try { - call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'client closed'); + \call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'client closed'); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -424,9 +424,9 @@ public function send($send_buffer, $raw = false) */ public function getRemoteIp() { - $pos = strrpos($this->_remoteAddress, ':'); + $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return substr($this->_remoteAddress, 0, $pos); + return \substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -439,7 +439,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int)substr(strrchr($this->_remoteAddress, ':'), 1); + return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -462,11 +462,11 @@ public function getRemoteAddress() public function getLocalIp() { $address = $this->getLocalAddress(); - $pos = strrpos($address, ':'); + $pos = \strrpos($address, ':'); if (!$pos) { return ''; } - return substr($address, 0, $pos); + return \substr($address, 0, $pos); } /** @@ -477,11 +477,11 @@ public function getLocalIp() public function getLocalPort() { $address = $this->getLocalAddress(); - $pos = strrpos($address, ':'); + $pos = \strrpos($address, ':'); if (!$pos) { return 0; } - return (int)substr(strrchr($address, ':'), 1); + return (int)\substr(\strrchr($address, ':'), 1); } /** @@ -491,7 +491,7 @@ public function getLocalPort() */ public function getLocalAddress() { - return (string)@stream_socket_get_name($this->_socket, false); + return (string)@\stream_socket_get_name($this->_socket, false); } /** @@ -501,7 +501,7 @@ public function getLocalAddress() */ public function getSendBufferQueueSize() { - return strlen($this->_sendBuffer); + return \strlen($this->_sendBuffer); } /** @@ -511,7 +511,7 @@ public function getSendBufferQueueSize() */ public function getRecvBufferQueueSize() { - return strlen($this->_recvBuffer); + return \strlen($this->_recvBuffer); } /** @@ -524,7 +524,7 @@ public function isIpV4() if ($this->transport === 'unix') { return false; } - return strpos($this->getRemoteIp(), ':') === false; + return \strpos($this->getRemoteIp(), ':') === false; } /** @@ -537,7 +537,7 @@ public function isIpV6() if ($this->transport === 'unix') { return false; } - return strpos($this->getRemoteIp(), ':') !== false; + return \strpos($this->getRemoteIp(), ':') !== false; } /** @@ -588,18 +588,18 @@ public function baseRead($socket, $check_eof = true) } } - set_error_handler(function(){}); - $buffer = fread($socket, self::READ_BUFFER_SIZE); - restore_error_handler(); + \set_error_handler(function(){}); + $buffer = \fread($socket, self::READ_BUFFER_SIZE); + \restore_error_handler(); // Check connection closed. if ($buffer === '' || $buffer === false) { - if ($check_eof && (feof($socket) || !is_resource($socket) || $buffer === false)) { + if ($check_eof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) { $this->destroy(); return; } } else { - $this->bytesRead += strlen($buffer); + $this->bytesRead += \strlen($buffer); $this->_recvBuffer .= $buffer; } @@ -610,22 +610,22 @@ public function baseRead($socket, $check_eof = true) // The current packet length is known. if ($this->_currentPackageLength) { // Data is not enough for a package. - if ($this->_currentPackageLength > strlen($this->_recvBuffer)) { + if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { break; } } else { // Get current package length. - set_error_handler(function($code, $msg, $file, $line){ + \set_error_handler(function($code, $msg, $file, $line){ Worker::safeEcho("$msg in file $file on line $line\n"); }); $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - restore_error_handler(); + \restore_error_handler(); // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. - if ($this->_currentPackageLength > strlen($this->_recvBuffer)) { + if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { break; } } // Wrong package. @@ -639,14 +639,14 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. self::$statistics['total_request']++; // The current packet length is equal to the length of the buffer. - if (strlen($this->_recvBuffer) === $this->_currentPackageLength) { + if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; $this->_recvBuffer = ''; } else { // Get a full package from the buffer. - $one_request_buffer = substr($this->_recvBuffer, 0, $this->_currentPackageLength); + $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); // Remove the current package from the receive buffer. - $this->_recvBuffer = substr($this->_recvBuffer, $this->_currentPackageLength); + $this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength); } // Reset the current packet length to 0. $this->_currentPackageLength = 0; @@ -655,7 +655,7 @@ public function baseRead($socket, $check_eof = true) } try { // Decode request buffer before Emitting onMessage callback. - call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); + \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -678,7 +678,7 @@ public function baseRead($socket, $check_eof = true) return; } try { - call_user_func($this->onMessage, $this, $this->_recvBuffer); + \call_user_func($this->onMessage, $this, $this->_recvBuffer); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -697,21 +697,21 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - set_error_handler(function(){}); + \set_error_handler(function(){}); if ($this->transport === 'ssl') { - $len = fwrite($this->_socket, $this->_sendBuffer, 8192); + $len = \fwrite($this->_socket, $this->_sendBuffer, 8192); } else { - $len = fwrite($this->_socket, $this->_sendBuffer); + $len = \fwrite($this->_socket, $this->_sendBuffer); } - restore_error_handler(); - if ($len === strlen($this->_sendBuffer)) { + \restore_error_handler(); + if ($len === \strlen($this->_sendBuffer)) { $this->bytesWritten += $len; Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { - call_user_func($this->onBufferDrain, $this); + \call_user_func($this->onBufferDrain, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -727,7 +727,7 @@ public function baseWrite() } if ($len > 0) { $this->bytesWritten += $len; - $this->_sendBuffer = substr($this->_sendBuffer, $len); + $this->_sendBuffer = \substr($this->_sendBuffer, $len); } else { self::$statistics['send_fail']++; $this->destroy(); @@ -741,7 +741,7 @@ public function baseWrite() * @return bool */ public function doSslHandshake($socket){ - if (feof($socket)) { + if (\feof($socket)) { $this->destroy(); return false; } @@ -764,13 +764,13 @@ public function doSslHandshake($socket){ } // Hidden error. - set_error_handler(function($errno, $errstr, $file){ + \set_error_handler(function($errno, $errstr, $file){ if (!Worker::$daemonize) { Worker::safeEcho("SSL handshake error: $errstr \n"); } }); - $ret = stream_socket_enable_crypto($socket, true, $type); - restore_error_handler(); + $ret = \stream_socket_enable_crypto($socket, true, $type); + \restore_error_handler(); // Negotiation has failed. if (false === $ret) { $this->destroy(); @@ -781,7 +781,7 @@ public function doSslHandshake($socket){ } if (isset($this->onSslHandshake)) { try { - call_user_func($this->onSslHandshake, $this); + \call_user_func($this->onSslHandshake, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -824,7 +824,7 @@ public function pipe($dest) */ public function consumeRecvBuffer($length) { - $this->_recvBuffer = substr($this->_recvBuffer, $length); + $this->_recvBuffer = \substr($this->_recvBuffer, $length); } /** @@ -872,10 +872,10 @@ public function getSocket() */ protected function checkBufferWillFull() { - if ($this->maxSendBufferSize <= strlen($this->_sendBuffer)) { + if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onBufferFull) { try { - call_user_func($this->onBufferFull, $this); + \call_user_func($this->onBufferFull, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -895,10 +895,10 @@ protected function checkBufferWillFull() protected function bufferIsFull() { // Buffer has been marked as full but still has data to send then the packet is discarded. - if ($this->maxSendBufferSize <= strlen($this->_sendBuffer)) { + if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { - call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -938,15 +938,15 @@ public function destroy() Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // Close socket. - set_error_handler(function(){}); - fclose($this->_socket); - restore_error_handler(); + \set_error_handler(function(){}); + \fclose($this->_socket); + \restore_error_handler(); $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { - call_user_func($this->onClose, $this); + \call_user_func($this->onClose, $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -956,9 +956,9 @@ public function destroy() } } // Try to emit protocol::onClose - if ($this->protocol && method_exists($this->protocol, 'onClose')) { + if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { - call_user_func(array($this->protocol, 'onClose'), $this); + \call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -994,7 +994,7 @@ public function __destruct() } if (0 === self::$statistics['connection_count'] % $mod) { - Worker::log('worker[' . posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); + Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } if(0 === self::$statistics['connection_count']) { diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 2e7aeee58..fba154ec4 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -68,7 +68,7 @@ public function send($send_buffer, $raw = false) return null; } } - return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); + return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); } /** @@ -78,9 +78,9 @@ public function send($send_buffer, $raw = false) */ public function getRemoteIp() { - $pos = strrpos($this->_remoteAddress, ':'); + $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return trim(substr($this->_remoteAddress, 0, $pos), '[]'); + return \trim(\substr($this->_remoteAddress, 0, $pos), '[]'); } return ''; } @@ -93,7 +93,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int)substr(strrchr($this->_remoteAddress, ':'), 1); + return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -116,11 +116,11 @@ public function getRemoteAddress() public function getLocalIp() { $address = $this->getLocalAddress(); - $pos = strrpos($address, ':'); + $pos = \strrpos($address, ':'); if (!$pos) { return ''; } - return substr($address, 0, $pos); + return \substr($address, 0, $pos); } /** @@ -131,11 +131,11 @@ public function getLocalIp() public function getLocalPort() { $address = $this->getLocalAddress(); - $pos = strrpos($address, ':'); + $pos = \strrpos($address, ':'); if (!$pos) { return 0; } - return (int)substr(strrchr($address, ':'), 1); + return (int)\substr(\strrchr($address, ':'), 1); } /** @@ -145,7 +145,7 @@ public function getLocalPort() */ public function getLocalAddress() { - return (string)@stream_socket_get_name($this->_socket, false); + return (string)@\stream_socket_get_name($this->_socket, false); } /** @@ -158,7 +158,7 @@ public function isIpV4() if ($this->transport === 'unix') { return false; } - return strpos($this->getRemoteIp(), ':') === false; + return \strpos($this->getRemoteIp(), ':') === false; } /** @@ -171,7 +171,7 @@ public function isIpV6() if ($this->transport === 'unix') { return false; } - return strpos($this->getRemoteIp(), ':') !== false; + return \strpos($this->getRemoteIp(), ':') !== false; } /** diff --git a/Events/Ev.php b/Events/Ev.php index 1e6471d78..17010e151 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -56,7 +56,7 @@ public function add($fd, $flag, $func, $args = null) { $callback = function ($event, $socket) use ($fd, $func) { try { - call_user_func($func, $fd); + \call_user_func($func, $fd); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -137,7 +137,7 @@ public function timerCallback($event) unset($this->_eventTimer[$timer_id]); } try { - call_user_func_array($param[0], $param[1]); + \call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -189,6 +189,6 @@ public function destroy() */ public function getTimerCount() { - return count($this->_eventTimer); + return \count($this->_eventTimer); } } diff --git a/Events/Event.php b/Events/Event.php index b4d371a72..c7d7aa261 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -57,7 +57,7 @@ class Event implements EventInterface */ public function __construct() { - if (class_exists('\\\\EventBase', false)) { + if (\class_exists('\\\\EventBase', false)) { $class_name = '\\\\EventBase'; } else { $class_name = '\EventBase'; @@ -70,7 +70,7 @@ public function __construct() */ public function add($fd, $flag, $func, $args=array()) { - if (class_exists('\\\\Event', false)) { + if (\class_exists('\\\\Event', false)) { $class_name = '\\\\Event'; } else { $class_name = '\Event'; @@ -164,7 +164,7 @@ public function timerCallback($fd, $what, $param) } try { - call_user_func_array($param[0], $param[1]); + \call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -214,6 +214,6 @@ public function destroy() */ public function getTimerCount() { - return count($this->_eventTimer); + return \count($this->_eventTimer); } } diff --git a/Events/Libevent.php b/Events/Libevent.php index 0b3f7c039..e6652acc7 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -67,30 +67,30 @@ public function add($fd, $flag, $func, $args = array()) $fd_key = (int)$fd; $real_flag = EV_SIGNAL | EV_PERSIST; $this->_eventSignal[$fd_key] = event_new(); - if (!event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { + if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { return false; } - if (!event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { + if (!\event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { return false; } - if (!event_add($this->_eventSignal[$fd_key])) { + if (!\event_add($this->_eventSignal[$fd_key])) { return false; } return true; case self::EV_TIMER: case self::EV_TIMER_ONCE: - $event = event_new(); + $event = \event_new(); $timer_id = (int)$event; - if (!event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { + if (!\event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { return false; } - if (!event_base_set($event, $this->_eventBase)) { + if (!\event_base_set($event, $this->_eventBase)) { return false; } $time_interval = $fd * 1000000; - if (!event_add($event, $time_interval)) { + if (!\event_add($event, $time_interval)) { return false; } $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); @@ -100,17 +100,17 @@ public function add($fd, $flag, $func, $args = array()) $fd_key = (int)$fd; $real_flag = $flag === self::EV_READ ? EV_READ | EV_PERSIST : EV_WRITE | EV_PERSIST; - $event = event_new(); + $event = \event_new(); - if (!event_set($event, $fd, $real_flag, $func, null)) { + if (!\event_set($event, $fd, $real_flag, $func, null)) { return false; } - if (!event_base_set($event, $this->_eventBase)) { + if (!\event_base_set($event, $this->_eventBase)) { return false; } - if (!event_add($event)) { + if (!\event_add($event)) { return false; } @@ -131,7 +131,7 @@ public function del($fd, $flag) case self::EV_WRITE: $fd_key = (int)$fd; if (isset($this->_allEvents[$fd_key][$flag])) { - event_del($this->_allEvents[$fd_key][$flag]); + \event_del($this->_allEvents[$fd_key][$flag]); unset($this->_allEvents[$fd_key][$flag]); } if (empty($this->_allEvents[$fd_key])) { @@ -141,7 +141,7 @@ public function del($fd, $flag) case self::EV_SIGNAL: $fd_key = (int)$fd; if (isset($this->_eventSignal[$fd_key])) { - event_del($this->_eventSignal[$fd_key]); + \event_del($this->_eventSignal[$fd_key]); unset($this->_eventSignal[$fd_key]); } break; @@ -149,7 +149,7 @@ public function del($fd, $flag) case self::EV_TIMER_ONCE: // 这里 fd 为timerid if (isset($this->_eventTimer[$fd])) { - event_del($this->_eventTimer[$fd][2]); + \event_del($this->_eventTimer[$fd][2]); unset($this->_eventTimer[$fd]); } break; @@ -167,10 +167,10 @@ public function del($fd, $flag) protected function timerCallback($_null1, $_null2, $timer_id) { if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { - event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); + \event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); } try { - call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); + \call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -189,7 +189,7 @@ protected function timerCallback($_null1, $_null2, $timer_id) public function clearAllTimer() { foreach ($this->_eventTimer as $task_data) { - event_del($task_data[2]); + \event_del($task_data[2]); } $this->_eventTimer = array(); } @@ -199,7 +199,7 @@ public function clearAllTimer() */ public function loop() { - event_base_loop($this->_eventBase); + \event_base_loop($this->_eventBase); } /** @@ -210,7 +210,7 @@ public function loop() public function destroy() { foreach ($this->_eventSignal as $event) { - event_del($event); + \event_del($event); } } @@ -221,7 +221,7 @@ public function destroy() */ public function getTimerCount() { - return count($this->_eventTimer); + return \count($this->_eventTimer); } } diff --git a/Events/React/Base.php b/Events/React/Base.php index d558b88e8..fac174cd5 100644 --- a/Events/React/Base.php +++ b/Events/React/Base.php @@ -74,7 +74,7 @@ public function add($fd, $flag, $func, $args = array()) return $this->addSignal($fd, $func); case EventInterface::EV_TIMER: $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { - call_user_func_array($func, $args); + \call_user_func_array($func, $args); }); $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; return $this->_timerIdIndex; @@ -82,7 +82,7 @@ public function add($fd, $flag, $func, $args = array()) $index = ++$this->_timerIdIndex; $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { $this->del($index,EventInterface::EV_TIMER_ONCE); - call_user_func_array($func, $args); + \call_user_func_array($func, $args); }); $this->_timerIdMap[$index] = $timer_obj; return $this->_timerIdIndex; @@ -153,7 +153,7 @@ public function destroy() */ public function getTimerCount() { - return count($this->_timerIdMap); + return \count($this->_timerIdMap); } /** diff --git a/Events/Select.php b/Events/Select.php index 801586b52..8b82971b7 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -96,10 +96,10 @@ class Select implements EventInterface public function __construct() { // Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling. - $this->channel = stream_socket_pair(DIRECTORY_SEPARATOR === '/' ? STREAM_PF_UNIX : STREAM_PF_INET, + $this->channel = \stream_socket_pair(DIRECTORY_SEPARATOR === '/' ? STREAM_PF_UNIX : STREAM_PF_INET, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); if($this->channel) { - stream_set_blocking($this->channel[0], 0); + \stream_set_blocking($this->channel[0], 0); $this->_readFds[0] = $this->channel[0]; } // Init SplPriorityQueue. @@ -115,7 +115,7 @@ public function add($fd, $flag, $func, $args = array()) switch ($flag) { case self::EV_READ: case self::EV_WRITE: - $count = $flag === self::EV_READ ? count($this->_readFds) : count($this->_writeFds); + $count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { @@ -141,15 +141,15 @@ public function add($fd, $flag, $func, $args = array()) } $fd_key = (int)$fd; $this->_signalEvents[$fd_key][$flag] = array($func, $fd); - pcntl_signal($fd, array($this, 'signalHandler')); + \pcntl_signal($fd, array($this, 'signalHandler')); break; case self::EV_TIMER: case self::EV_TIMER_ONCE: $timer_id = $this->_timerId++; - $run_time = microtime(true) + $fd; + $run_time = \microtime(true) + $fd; $this->_scheduler->insert($timer_id, -$run_time); $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); - $select_timeout = ($run_time - microtime(true)) * 1000000; + $select_timeout = ($run_time - \microtime(true)) * 1000000; if( $this->_selectTimeout > $select_timeout ){ $this->_selectTimeout = $select_timeout; } @@ -166,7 +166,7 @@ public function add($fd, $flag, $func, $args = array()) */ public function signalHandler($signal) { - call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal)); + \call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal)); } /** @@ -200,7 +200,7 @@ public function del($fd, $flag) return false; } unset($this->_signalEvents[$fd_key]); - pcntl_signal($fd, SIG_IGN); + \pcntl_signal($fd, SIG_IGN); break; case self::EV_TIMER: case self::EV_TIMER_ONCE; @@ -221,7 +221,7 @@ protected function tick() $scheduler_data = $this->_scheduler->top(); $timer_id = $scheduler_data['data']; $next_run_time = -$scheduler_data['priority']; - $time_now = microtime(true); + $time_now = \microtime(true); $this->_selectTimeout = ($next_run_time - $time_now) * 1000000; if ($this->_selectTimeout <= 0) { $this->_scheduler->extract(); @@ -236,7 +236,7 @@ protected function tick() $next_run_time = $time_now + $task_data[3]; $this->_scheduler->insert($timer_id, -$next_run_time); } - call_user_func_array($task_data[0], $task_data[1]); + \call_user_func_array($task_data[0], $task_data[1]); if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { $this->del($timer_id, self::EV_TIMER_ONCE); } @@ -265,7 +265,7 @@ public function loop() while (1) { if(DIRECTORY_SEPARATOR === '/') { // Calls signal handlers for pending signals - pcntl_signal_dispatch(); + \pcntl_signal_dispatch(); } $read = $this->_readFds; @@ -273,9 +273,9 @@ public function loop() $except = $this->_exceptFds; // Waiting read/write/signal/timeout events. - set_error_handler(function(){}); + \set_error_handler(function(){}); $ret = stream_select($read, $write, $except, 0, $this->_selectTimeout); - restore_error_handler(); + \restore_error_handler(); if (!$this->_scheduler->isEmpty()) { @@ -290,7 +290,7 @@ public function loop() foreach ($read as $fd) { $fd_key = (int)$fd; if (isset($this->_allEvents[$fd_key][self::EV_READ])) { - call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], + \call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], array($this->_allEvents[$fd_key][self::EV_READ][1])); } } @@ -300,7 +300,7 @@ public function loop() foreach ($write as $fd) { $fd_key = (int)$fd; if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { - call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], + \call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], array($this->_allEvents[$fd_key][self::EV_WRITE][1])); } } @@ -310,7 +310,7 @@ public function loop() foreach($except as $fd) { $fd_key = (int) $fd; if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) { - call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], + \call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], array($this->_allEvents[$fd_key][self::EV_EXCEPT][1])); } } @@ -335,6 +335,6 @@ public function destroy() */ public function getTimerCount() { - return count($this->_eventTimer); + return \count($this->_eventTimer); } } diff --git a/Events/Swoole.php b/Events/Swoole.php index 40ef499de..26af419d5 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -45,11 +45,11 @@ public function add($fd, $flag, $func, $args = null) } switch ($flag) { case self::EV_SIGNAL: - $res = pcntl_signal($fd, $func, false); + $res = \pcntl_signal($fd, $func, false); if (! $this->_hasSignal && $res) { Timer::tick(static::$signalDispatchInterval, function () { - pcntl_signal_dispatch(); + \pcntl_signal_dispatch(); }); $this->_hasSignal = true; } @@ -63,7 +63,7 @@ function () { $mapId = $this->mapId++; $timer_id = Timer::$method($fd * 1000, function ($timer_id = null) use ($func, $args, $mapId) { - call_user_func_array($func, $args); + \call_user_func_array($func, $args); // EV_TIMER_ONCE if (! isset($timer_id)) { // may be deleted in $func @@ -126,11 +126,11 @@ public function del($fd, $flag) { switch ($flag) { case self::EV_SIGNAL: - return pcntl_signal($fd, SIG_IGN, false); + return \pcntl_signal($fd, SIG_IGN, false); case self::EV_TIMER: case self::EV_TIMER_ONCE: // already remove in EV_TIMER_ONCE callback. - if (! array_key_exists($fd, $this->_timer)) { + if (! \array_key_exists($fd, $this->_timer)) { return true; } $res = Timer::clear($fd); @@ -216,6 +216,6 @@ public function destroy() */ public function getTimerCount() { - return count($this->_timer); + return \count($this->_timer); } } diff --git a/Lib/Timer.php b/Lib/Timer.php index 2dc2302b1..c4d08295e 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -55,8 +55,8 @@ public static function init($event = null) if ($event) { self::$_event = $event; } else { - if (function_exists('pcntl_signal')) { - pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); + if (\function_exists('pcntl_signal')) { + \pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); } } } @@ -69,7 +69,7 @@ public static function init($event = null) public static function signalHandle() { if (!self::$_event) { - pcntl_alarm(1); + \pcntl_alarm(1); self::tick(); } } @@ -95,16 +95,16 @@ public static function add($time_interval, $func, $args = array(), $persistent = $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); } - if (!is_callable($func)) { + if (!\is_callable($func)) { Worker::safeEcho(new Exception("not callable")); return false; } if (empty(self::$_tasks)) { - pcntl_alarm(1); + \pcntl_alarm(1); } - $time_now = time(); + $time_now = \time(); $run_time = $time_now + $time_interval; if (!isset(self::$_tasks[$run_time])) { self::$_tasks[$run_time] = array(); @@ -122,11 +122,11 @@ public static function add($time_interval, $func, $args = array(), $persistent = public static function tick() { if (empty(self::$_tasks)) { - pcntl_alarm(0); + \pcntl_alarm(0); return; } - $time_now = time(); + $time_now = \time(); foreach (self::$_tasks as $run_time => $task_data) { if ($time_now >= $run_time) { foreach ($task_data as $index => $one_task) { @@ -135,7 +135,7 @@ public static function tick() $persistent = $one_task[2]; $time_interval = $one_task[3]; try { - call_user_func_array($task_func, $task_args); + \call_user_func_array($task_func, $task_args); } catch (\Exception $e) { Worker::safeEcho($e); } @@ -171,7 +171,7 @@ public static function del($timer_id) public static function delAll() { self::$_tasks = array(); - pcntl_alarm(0); + \pcntl_alarm(0); if (self::$_event) { self::$_event->clearAllTimer(); } diff --git a/Protocols/Frame.php b/Protocols/Frame.php index 4a6b13ecb..26b04de41 100644 --- a/Protocols/Frame.php +++ b/Protocols/Frame.php @@ -29,10 +29,10 @@ class Frame */ public static function input($buffer, TcpConnection $connection) { - if (strlen($buffer) < 4) { + if (\strlen($buffer) < 4) { return 0; } - $unpack_data = unpack('Ntotal_length', $buffer); + $unpack_data = \unpack('Ntotal_length', $buffer); return $unpack_data['total_length']; } @@ -44,7 +44,7 @@ public static function input($buffer, TcpConnection $connection) */ public static function decode($buffer) { - return substr($buffer, 4); + return \substr($buffer, 4); } /** @@ -55,7 +55,7 @@ public static function decode($buffer) */ public static function encode($buffer) { - $total_length = 4 + strlen($buffer); - return pack('N', $total_length) . $buffer; + $total_length = 4 + \strlen($buffer); + return \pack('N', $total_length) . $buffer; } } diff --git a/Protocols/Http.php b/Protocols/Http.php index 12f7a2fb5..7dcfe5f1b 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -36,19 +36,19 @@ class Http */ public static function input($recv_buffer, TcpConnection $connection) { - if (!strpos($recv_buffer, "\r\n\r\n")) { + if (!\strpos($recv_buffer, "\r\n\r\n")) { // Judge whether the package length exceeds the limit. - if (strlen($recv_buffer) >= $connection->maxPackageSize) { + if (\strlen($recv_buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } return 0; } - list($header,) = explode("\r\n\r\n", $recv_buffer, 2); - $method = substr($header, 0, strpos($header, ' ')); + list($header,) = \explode("\r\n\r\n", $recv_buffer, 2); + $method = \substr($header, 0, \strpos($header, ' ')); - if(in_array($method, static::$methods)) { + if(\in_array($method, static::$methods)) { return static::getRequestSize($header, $method); }else{ $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); @@ -66,14 +66,14 @@ public static function input($recv_buffer, TcpConnection $connection) protected static function getRequestSize($header, $method) { if($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { - return strlen($header) + 4; + return \strlen($header) + 4; } $match = array(); - if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) { + if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) { $content_length = isset($match[1]) ? $match[1] : 0; - return $content_length + strlen($header) + 4; + return $content_length + \strlen($header) + 4; } - return $method === 'DELETE' ? strlen($header) + 4 : 0; + return $method === 'DELETE' ? \strlen($header) + 4 : 0; } /** @@ -109,14 +109,14 @@ public static function decode($recv_buffer, TcpConnection $connection) 'CONTENT_TYPE' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', - 'REQUEST_TIME' => time() + 'REQUEST_TIME' => \time() ); // Parse headers. - list($http_header, $http_body) = explode("\r\n\r\n", $recv_buffer, 2); - $header_data = explode("\r\n", $http_header); + list($http_header, $http_body) = \explode("\r\n\r\n", $recv_buffer, 2); + $header_data = \explode("\r\n", $http_header); - list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', + list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ', $header_data[0]); $http_post_boundary = ''; @@ -126,14 +126,14 @@ public static function decode($recv_buffer, TcpConnection $connection) if (empty($content)) { continue; } - list($key, $value) = explode(':', $content, 2); - $key = str_replace('-', '_', strtoupper($key)); - $value = trim($value); + list($key, $value) = \explode(':', $content, 2); + $key = \str_replace('-', '_', strtoupper($key)); + $value = \trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST case 'HOST': - $tmp = explode(':', $value); + $tmp = \explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; @@ -141,13 +141,13 @@ public static function decode($recv_buffer, TcpConnection $connection) break; // cookie case 'COOKIE': - parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); + \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; // content-type case 'CONTENT_TYPE': - if (!preg_match('/boundary="?(\S+)"?/', $value, $match)) { - if ($pos = strpos($value, ';')) { - $_SERVER['CONTENT_TYPE'] = substr($value, 0, $pos); + if (!\preg_match('/boundary="?(\S+)"?/', $value, $match)) { + if ($pos = \strpos($value, ';')) { + $_SERVER['CONTENT_TYPE'] = \substr($value, 0, $pos); } else { $_SERVER['CONTENT_TYPE'] = $value; } @@ -167,7 +167,7 @@ public static function decode($recv_buffer, TcpConnection $connection) break; } } - if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE){ + if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE){ HttpCache::$gzip = true; } // Parse $_POST. @@ -178,10 +178,10 @@ public static function decode($recv_buffer, TcpConnection $connection) self::parseUploadFiles($http_body, $http_post_boundary); break; case 'application/json': - $_POST = json_decode($http_body, true); + $_POST = \json_decode($http_body, true); break; case 'application/x-www-form-urlencoded': - parse_str($http_body, $_POST); + \parse_str($http_body, $_POST); break; } } @@ -191,31 +191,31 @@ public static function decode($recv_buffer, TcpConnection $connection) if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { $data = array(); if ($_SERVER['CONTENT_TYPE'] === "application/x-www-form-urlencoded") { - parse_str($http_body, $data); + \parse_str($http_body, $data); } elseif ($_SERVER['CONTENT_TYPE'] === "application/json") { - $data = json_decode($http_body, true); + $data = \json_decode($http_body, true); } - $_REQUEST = array_merge($_REQUEST, $data); + $_REQUEST = \array_merge($_REQUEST, $data); } // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; // QUERY_STRING - $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); + $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET - parse_str($_SERVER['QUERY_STRING'], $_GET); + \parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; } - if (is_array($_POST)) { + if (\is_array($_POST)) { // REQUEST - $_REQUEST = array_merge($_GET, $_POST, $_REQUEST); + $_REQUEST = \array_merge($_GET, $_POST, $_REQUEST); } else { // REQUEST - $_REQUEST = array_merge($_GET, $_REQUEST); + $_REQUEST = \array_merge($_GET, $_REQUEST); } // REMOTE_ADDR REMOTE_PORT @@ -249,7 +249,7 @@ public static function encode($content, TcpConnection $connection) // other headers foreach (HttpCache::$header as $key => $item) { - if ('Set-Cookie' === $key && is_array($item)) { + if ('Set-Cookie' === $key && \is_array($item)) { foreach ($item as $it) { $header .= $it . "\r\n"; } @@ -259,10 +259,10 @@ public static function encode($content, TcpConnection $connection) } if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ $header .= "Content-Encoding: gzip\r\n"; - $content = gzencode($content,$connection->gzip); + $content = \gzencode($content,$connection->gzip); } // header - $header .= "Server: workerman/" . Worker::VERSION . "\r\nContent-Length: " . strlen($content) . "\r\n\r\n"; + $header .= "Server: workerman/" . Worker::VERSION . "\r\nContent-Length: " . \strlen($content) . "\r\n\r\n"; // save session self::sessionWriteClose(); @@ -279,18 +279,18 @@ public static function encode($content, TcpConnection $connection) public static function header($content, $replace = true, $http_response_code = 0) { if (PHP_SAPI != 'cli') { - return $http_response_code ? header($content, $replace, $http_response_code) : header($content, $replace); + return $http_response_code ? \header($content, $replace, $http_response_code) : \header($content, $replace); } - if (strpos($content, 'HTTP') === 0) { + if (\strpos($content, 'HTTP') === 0) { $key = 'Http-Code'; } else { - $key = strstr($content, ":", true); + $key = \strstr($content, ":", true); if (empty($key)) { return false; } } - if ('location' === strtolower($key) && !$http_response_code) { + if ('location' === \strtolower($key) && !$http_response_code) { return self::header($content, true, 302); } @@ -319,7 +319,7 @@ public static function header($content, $replace = true, $http_response_code = 0 public static function headerRemove($name) { if (PHP_SAPI != 'cli') { - header_remove($name); + \header_remove($name); return; } unset(HttpCache::$header[$name]); @@ -347,7 +347,7 @@ public static function setcookie( $HTTPOnly = false ) { if (PHP_SAPI != 'cli') { - return setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); + return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); } return self::header( 'Set-Cookie: ' . $name . '=' . rawurlencode($value) @@ -365,8 +365,8 @@ public static function setcookie( */ public static function sessionCreateId() { - mt_srand(); - return bin2hex(pack('d', microtime(true)) . pack('N',mt_rand(0, 2147483647))); + \mt_srand(); + return bin2hex(\pack('d', \microtime(true)) . \pack('N',\mt_rand(0, 2147483647))); } /** @@ -379,10 +379,10 @@ public static function sessionCreateId() public static function sessionId($id = null) { if (PHP_SAPI != 'cli') { - return $id ? session_id($id) : session_id(); + return $id ? \session_id($id) : \session_id(); } if (static::sessionStarted() && HttpCache::$instance->sessionFile) { - return str_replace('ses_', '', basename(HttpCache::$instance->sessionFile)); + return \str_replace('ses_', '', \basename(HttpCache::$instance->sessionFile)); } return ''; } @@ -397,7 +397,7 @@ public static function sessionId($id = null) public static function sessionName($name = null) { if (PHP_SAPI != 'cli') { - return $name ? session_name($name) : session_name(); + return $name ? \session_name($name) : \session_name(); } $session_name = HttpCache::$sessionName; if ($name && ! static::sessionStarted()) { @@ -416,9 +416,9 @@ public static function sessionName($name = null) public static function sessionSavePath($path = null) { if (PHP_SAPI != 'cli') { - return $path ? session_save_path($path) : session_save_path(); + return $path ? \session_save_path($path) : \session_save_path(); } - if ($path && is_dir($path) && is_writable($path) && !static::sessionStarted()) { + if ($path && \is_dir($path) && \is_writable($path) && !static::sessionStarted()) { HttpCache::$sessionPath = $path; } return HttpCache::$sessionPath; @@ -444,7 +444,7 @@ public static function sessionStarted() public static function sessionStart() { if (PHP_SAPI != 'cli') { - return session_start(); + return \session_start(); } self::tryGcSessions(); @@ -455,21 +455,21 @@ public static function sessionStart() } HttpCache::$instance->sessionStarted = true; // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName])) { + if (!isset($_COOKIE[HttpCache::$sessionName]) || !\is_file(HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName])) { // Create a unique session_id and the associated file name. while (true) { $session_id = static::sessionCreateId(); - if (!is_file($file_name = HttpCache::$sessionPath . '/ses_' . $session_id)) break; + if (!\is_file($file_name = HttpCache::$sessionPath . '/ses_' . $session_id)) break; } HttpCache::$instance->sessionFile = $file_name; return self::setcookie( HttpCache::$sessionName , $session_id - , ini_get('session.cookie_lifetime') - , ini_get('session.cookie_path') - , ini_get('session.cookie_domain') - , ini_get('session.cookie_secure') - , ini_get('session.cookie_httponly') + , \ini_get('session.cookie_lifetime') + , \ini_get('session.cookie_path') + , \ini_get('session.cookie_domain') + , \ini_get('session.cookie_secure') + , \ini_get('session.cookie_httponly') ); } if (!HttpCache::$instance->sessionFile) { @@ -477,9 +477,9 @@ public static function sessionStart() } // Read session from session file. if (HttpCache::$instance->sessionFile) { - $raw = file_get_contents(HttpCache::$instance->sessionFile); + $raw = \file_get_contents(HttpCache::$instance->sessionFile); if ($raw) { - $_SESSION = unserialize($raw); + $_SESSION = \unserialize($raw); } } return true; @@ -493,12 +493,13 @@ public static function sessionStart() public static function sessionWriteClose() { if (PHP_SAPI != 'cli') { - return session_write_close(); + \session_write_close(); + return true; } if (!empty(HttpCache::$instance->sessionStarted) && !empty($_SESSION)) { - $session_str = serialize($_SESSION); + $session_str = \serialize($_SESSION); if ($session_str && HttpCache::$instance->sessionFile) { - return file_put_contents(HttpCache::$instance->sessionFile, $session_str); + return \file_put_contents(HttpCache::$instance->sessionFile, $session_str); } } return empty($_SESSION); @@ -540,43 +541,43 @@ public static function getMimeTypesFile() */ protected static function parseUploadFiles($http_body, $http_post_boundary) { - $http_body = substr($http_body, 0, strlen($http_body) - (strlen($http_post_boundary) + 4)); - $boundary_data_array = explode($http_post_boundary . "\r\n", $http_body); + $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); + $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); if ($boundary_data_array[0] === '') { unset($boundary_data_array[0]); } $key = -1; foreach ($boundary_data_array as $boundary_data_buffer) { - list($boundary_header_buffer, $boundary_value) = explode("\r\n\r\n", $boundary_data_buffer, 2); + list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); // Remove \r\n from the end of buffer. - $boundary_value = substr($boundary_value, 0, -2); + $boundary_value = \substr($boundary_value, 0, -2); $key ++; - foreach (explode("\r\n", $boundary_header_buffer) as $item) { - list($header_key, $header_value) = explode(": ", $item); - $header_key = strtolower($header_key); + foreach (\explode("\r\n", $boundary_header_buffer) as $item) { + list($header_key, $header_value) = \explode(": ", $item); + $header_key = \strtolower($header_key); switch ($header_key) { case "content-disposition": // Is file data. - if (preg_match('/name="(.*?)"; filename="(.*?)"$/', $header_value, $match)) { + if (\preg_match('/name="(.*?)"; filename="(.*?)"$/', $header_value, $match)) { // Parse $_FILES. $_FILES[$key] = array( 'name' => $match[1], 'file_name' => $match[2], 'file_data' => $boundary_value, - 'file_size' => strlen($boundary_value), + 'file_size' => \strlen($boundary_value), ); break; } // Is post field. else { // Parse $_POST. - if (preg_match('/name="(.*?)"$/', $header_value, $match)) { + if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { $_POST[$match[1]] = $boundary_value; } } break; case "content-type": // add file_type - $_FILES[$key]['file_type'] = trim($header_value); + $_FILES[$key]['file_type'] = \trim($header_value); break; } } @@ -592,14 +593,14 @@ public static function tryGcSessions() { if (HttpCache::$sessionGcProbability <= 0 || HttpCache::$sessionGcDivisor <= 0 || - rand(1, HttpCache::$sessionGcDivisor) > HttpCache::$sessionGcProbability) { + \rand(1, HttpCache::$sessionGcDivisor) > HttpCache::$sessionGcProbability) { return; } - $time_now = time(); + $time_now = \time(); foreach(glob(HttpCache::$sessionPath.'/ses*') as $file) { - if(is_file($file) && $time_now - filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { - unlink($file); + if(\is_file($file) && $time_now - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { + \unlink($file); } } } @@ -673,26 +674,26 @@ class HttpCache public static function init() { if (!self::$sessionName) { - self::$sessionName = ini_get('session.name'); + self::$sessionName = \ini_get('session.name'); } if (!self::$sessionPath) { - self::$sessionPath = @session_save_path(); + self::$sessionPath = @\session_save_path(); } - if (!self::$sessionPath || strpos(self::$sessionPath, 'tcp://') === 0) { - self::$sessionPath = sys_get_temp_dir(); + if (!self::$sessionPath || \strpos(self::$sessionPath, 'tcp://') === 0) { + self::$sessionPath = \sys_get_temp_dir(); } - if ($gc_probability = ini_get('session.gc_probability')) { + if ($gc_probability = \ini_get('session.gc_probability')) { self::$sessionGcProbability = $gc_probability; } - if ($gc_divisor = ini_get('session.gc_divisor')) { + if ($gc_divisor = \ini_get('session.gc_divisor')) { self::$sessionGcDivisor = $gc_divisor; } - if ($gc_max_life_time = ini_get('session.gc_maxlifetime')) { + if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { self::$sessionGcMaxLifeTime = $gc_max_life_time; } } diff --git a/Protocols/Text.php b/Protocols/Text.php index 84b937a99..8d6b2ec93 100644 --- a/Protocols/Text.php +++ b/Protocols/Text.php @@ -30,12 +30,12 @@ class Text public static function input($buffer, TcpConnection $connection) { // Judge whether the package length exceeds the limit. - if (strlen($buffer) >= $connection->maxPackageSize) { + if (\strlen($buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } // Find the position of "\n". - $pos = strpos($buffer, "\n"); + $pos = \strpos($buffer, "\n"); // No "\n", packet length is unknown, continue to wait for the data so return 0. if ($pos === false) { return 0; @@ -65,6 +65,6 @@ public static function encode($buffer) public static function decode($buffer) { // Remove "\n" - return rtrim($buffer, "\r\n"); + return \rtrim($buffer, "\r\n"); } } diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 6237f2153..fd02116db 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -46,7 +46,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface public static function input($buffer, ConnectionInterface $connection) { // Receive length. - $recv_len = strlen($buffer); + $recv_len = \strlen($buffer); // We need more data. if ($recv_len < 6) { return 0; @@ -65,8 +65,8 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } } else { - $firstbyte = ord($buffer[0]); - $secondbyte = ord($buffer[1]); + $firstbyte = \ord($buffer[0]); + $secondbyte = \ord($buffer[1]); $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; $masked = $secondbyte >> 7; @@ -92,7 +92,7 @@ public static function input($buffer, ConnectionInterface $connection) // Try to emit onWebSocketClose callback. if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) { try { - call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); + \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -125,7 +125,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($head_len > $recv_len) { return 0; } - $pack = unpack('nn/ntotal_len', $buffer); + $pack = \unpack('nn/ntotal_len', $buffer); $data_len = $pack['total_len']; } else { if ($data_len === 127) { @@ -133,13 +133,13 @@ public static function input($buffer, ConnectionInterface $connection) if ($head_len > $recv_len) { return 0; } - $arr = unpack('n/N2c', $buffer); + $arr = \unpack('n/N2c', $buffer); $data_len = $arr['c1']*4294967296 + $arr['c2']; } } $current_frame_length = $head_len + $data_len; - $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; + $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length; if ($total_package_size > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); @@ -149,13 +149,13 @@ public static function input($buffer, ConnectionInterface $connection) if ($is_fin_frame) { if ($opcode === 0x9) { if ($recv_len >= $current_frame_length) { - $ping_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { try { - call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); + \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -168,20 +168,20 @@ public static function input($buffer, ConnectionInterface $connection) } $connection->websocketType = $tmp_connection_type; if ($recv_len > $current_frame_length) { - return static::input(substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $current_frame_length), $connection); } } return 0; } else if ($opcode === 0xa) { if ($recv_len >= $current_frame_length) { - $pong_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { try { - call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); + \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -192,7 +192,7 @@ public static function input($buffer, ConnectionInterface $connection) } $connection->websocketType = $tmp_connection_type; if ($recv_len > $current_frame_length) { - return static::input(substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $current_frame_length), $connection); } } return 0; @@ -211,12 +211,12 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } // The length of the received data is greater than the length of a frame. elseif ($connection->websocketCurrentFrameLength < $recv_len) { - static::decode(substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); + static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $current_frame_length = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. - return static::input(substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $current_frame_length), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -235,7 +235,7 @@ public static function encode($buffer, ConnectionInterface $connection) if (!is_scalar($buffer)) { throw new \Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to a string. "); } - $len = strlen($buffer); + $len = \strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; } @@ -243,12 +243,12 @@ public static function encode($buffer, ConnectionInterface $connection) $first_byte = $connection->websocketType; if ($len <= 125) { - $encode_buffer = $first_byte . chr($len) . $buffer; + $encode_buffer = $first_byte . \chr($len) . $buffer; } else { if ($len <= 65535) { - $encode_buffer = $first_byte . chr(126) . pack("n", $len) . $buffer; + $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer; } else { - $encode_buffer = $first_byte . chr(127) . pack("xxxxN", $len) . $buffer; + $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer; } } @@ -258,10 +258,10 @@ public static function encode($buffer, ConnectionInterface $connection) $connection->tmpWebsocketData = ''; } // If buffer has already full then discard the current package. - if (strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -274,10 +274,10 @@ public static function encode($buffer, ConnectionInterface $connection) } $connection->tmpWebsocketData .= $encode_buffer; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { if ($connection->onBufferFull) { try { - call_user_func($connection->onBufferFull, $connection); + \call_user_func($connection->onBufferFull, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -304,21 +304,21 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $len = ord($buffer[1]) & 127; + $len = \ord($buffer[1]) & 127; if ($len === 126) { - $masks = substr($buffer, 4, 4); - $data = substr($buffer, 8); + $masks = \substr($buffer, 4, 4); + $data = \substr($buffer, 8); } else { if ($len === 127) { - $masks = substr($buffer, 10, 4); - $data = substr($buffer, 14); + $masks = \substr($buffer, 10, 4); + $data = \substr($buffer, 14); } else { - $masks = substr($buffer, 2, 4); - $data = substr($buffer, 6); + $masks = \substr($buffer, 2, 4); + $data = \substr($buffer, 6); } } - $dataLength = strlen($data); - $masks = str_repeat($masks, floor($dataLength / 4)) . substr($masks, 0, $dataLength % 4); + $dataLength = \strlen($data); + $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4); $decoded = $data ^ $masks; if ($connection->websocketCurrentFrameLength) { $connection->websocketDataBuffer .= $decoded; @@ -342,9 +342,9 @@ public static function decode($buffer, ConnectionInterface $connection) protected static function dealHandshake($buffer, $connection) { // HTTP protocol. - if (0 === strpos($buffer, 'GET')) { + if (0 === \strpos($buffer, 'GET')) { // Find \r\n\r\n. - $heder_end_pos = strpos($buffer, "\r\n\r\n"); + $heder_end_pos = \strpos($buffer, "\r\n\r\n"); if (!$heder_end_pos) { return 0; } @@ -352,7 +352,7 @@ protected static function dealHandshake($buffer, $connection) // Get Sec-WebSocket-Key. $Sec_WebSocket_Key = ''; - if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { + if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n", @@ -361,7 +361,7 @@ protected static function dealHandshake($buffer, $connection) return 0; } // Calculation websocket key. - $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); + $new_key = \base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"; $handshake_message .= "Upgrade: websocket\r\n"; @@ -389,7 +389,7 @@ protected static function dealHandshake($buffer, $connection) if (isset($connection->onWebSocketConnect) || isset($connection->worker->onWebSocketConnect)) { static::parseHttpHeader($buffer); try { - call_user_func(isset($connection->onWebSocketConnect)?$connection->onWebSocketConnect:$connection->worker->onWebSocketConnect, $connection, $buffer); + \call_user_func(isset($connection->onWebSocketConnect)?$connection->onWebSocketConnect:$connection->worker->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -397,15 +397,15 @@ protected static function dealHandshake($buffer, $connection) Worker::log($e); exit(250); } - if (!empty($_SESSION) && class_exists('\GatewayWorker\Lib\Context')) { + if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) { $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); if (isset($connection->headers)) { - if (is_array($connection->headers)) { + if (\is_array($connection->headers)) { foreach ($connection->headers as $header) { - if (strpos($header, 'Server:') === 0) { + if (\strpos($header, 'Server:') === 0) { $has_server_header = true; } $handshake_message .= "$header\r\n"; @@ -428,15 +428,15 @@ protected static function dealHandshake($buffer, $connection) $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } - if (strlen($buffer) > $header_length) { - return static::input(substr($buffer, $header_length), $connection); + if (\strlen($buffer) > $header_length) { + return static::input(\substr($buffer, $header_length), $connection); } return 0; } // Is flash policy-file-request. - elseif (0 === strpos($buffer, 'send($policy_xml, true); - $connection->consumeRecvBuffer(strlen($buffer)); + $connection->consumeRecvBuffer(\strlen($buffer)); return 0; } // Bad websocket handshake request. @@ -455,14 +455,14 @@ protected static function dealHandshake($buffer, $connection) protected static function parseHttpHeader($buffer) { // Parse headers. - list($http_header, ) = explode("\r\n\r\n", $buffer, 2); - $header_data = explode("\r\n", $http_header); + list($http_header, ) = \explode("\r\n\r\n", $buffer, 2); + $header_data = \explode("\r\n", $http_header); if ($_SERVER) { $_SERVER = array(); } - list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', + list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ', $header_data[0]); unset($header_data[0]); @@ -471,14 +471,14 @@ protected static function parseHttpHeader($buffer) if (empty($content)) { continue; } - list($key, $value) = explode(':', $content, 2); - $key = str_replace('-', '_', strtoupper($key)); - $value = trim($value); + list($key, $value) = \explode(':', $content, 2); + $key = \str_replace('-', '_', strtoupper($key)); + $value = \trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST case 'HOST': - $tmp = explode(':', $value); + $tmp = \explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; @@ -486,16 +486,16 @@ protected static function parseHttpHeader($buffer) break; // cookie case 'COOKIE': - parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); + \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; } } // QUERY_STRING - $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); + $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET - parse_str($_SERVER['QUERY_STRING'], $_GET); + \parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; } diff --git a/Protocols/Ws.php b/Protocols/Ws.php index e3ce4a615..211404866 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -53,7 +53,7 @@ public static function input($buffer, $connection) if ($connection->handshakeStep === 1) { return self::dealHandshake($buffer, $connection); } - $recv_len = strlen($buffer); + $recv_len = \strlen($buffer); if ($recv_len < 2) { return 0; } @@ -66,8 +66,8 @@ public static function input($buffer, $connection) } } else { - $firstbyte = ord($buffer[0]); - $secondbyte = ord($buffer[1]); + $firstbyte = \ord($buffer[0]); + $secondbyte = \ord($buffer[1]); $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; $masked = $secondbyte >> 7; @@ -94,7 +94,7 @@ public static function input($buffer, $connection) // Try to emit onWebSocketClose callback. if (isset($connection->onWebSocketClose)) { try { - call_user_func($connection->onWebSocketClose, $connection); + \call_user_func($connection->onWebSocketClose, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -121,22 +121,22 @@ public static function input($buffer, $connection) } // Calculate packet length. if ($data_len === 126) { - if (strlen($buffer) < 4) { + if (\strlen($buffer) < 4) { return 0; } - $pack = unpack('nn/ntotal_len', $buffer); + $pack = \unpack('nn/ntotal_len', $buffer); $current_frame_length = $pack['total_len'] + 4; } else if ($data_len === 127) { - if (strlen($buffer) < 10) { + if (\strlen($buffer) < 10) { return 0; } - $arr = unpack('n/N2c', $buffer); + $arr = \unpack('n/N2c', $buffer); $current_frame_length = $arr['c1']*4294967296 + $arr['c2'] + 10; } else { $current_frame_length = $data_len + 2; } - $total_package_size = strlen($connection->websocketDataBuffer) + $current_frame_length; + $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length; if ($total_package_size > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); @@ -146,13 +146,13 @@ public static function input($buffer, $connection) if ($is_fin_frame) { if ($opcode === 0x9) { if ($recv_len >= $current_frame_length) { - $ping_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing)) { try { - call_user_func($connection->onWebSocketPing, $connection, $ping_data); + \call_user_func($connection->onWebSocketPing, $connection, $ping_data); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -165,21 +165,21 @@ public static function input($buffer, $connection) } $connection->websocketType = $tmp_connection_type; if ($recv_len > $current_frame_length) { - return static::input(substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $current_frame_length), $connection); } } return 0; } else if ($opcode === 0xa) { if ($recv_len >= $current_frame_length) { - $pong_data = static::decode(substr($buffer, 0, $current_frame_length), $connection); + $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong)) { try { - call_user_func($connection->onWebSocketPong, $connection, $pong_data); + \call_user_func($connection->onWebSocketPong, $connection, $pong_data); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -190,7 +190,7 @@ public static function input($buffer, $connection) } $connection->websocketType = $tmp_connection_type; if ($recv_len > $current_frame_length) { - return static::input(substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $current_frame_length), $connection); } } return 0; @@ -208,12 +208,12 @@ public static function input($buffer, $connection) return 0; } // The length of the received data is greater than the length of a frame. elseif ($connection->websocketCurrentFrameLength < $recv_len) { - self::decode(substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); + self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $current_frame_length = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. - return self::input(substr($buffer, $current_frame_length), $connection); + return self::input(\substr($buffer, $current_frame_length), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -240,28 +240,28 @@ public static function encode($payload, $connection) $mask_key = "\x00\x00\x00\x00"; $pack = ''; - $length = $length_flag = strlen($payload); + $length = $length_flag = \strlen($payload); if (65535 < $length) { - $pack = pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); + $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); $length_flag = 127; } else if (125 < $length) { - $pack = pack('n*', $length); + $pack = \pack('n*', $length); $length_flag = 126; } $head = ($mask << 7) | $length_flag; - $head = $connection->websocketType . chr($head) . $pack; + $head = $connection->websocketType . \chr($head) . $pack; $frame = $head . $mask_key; // append payload to frame: - $mask_key = str_repeat($mask_key, floor($length / 4)) . substr($mask_key, 0, $length % 4); + $mask_key = \str_repeat($mask_key, \floor($length / 4)) . \substr($mask_key, 0, $length % 4); $frame .= $payload ^ $mask_key; if ($connection->handshakeStep === 1) { // If buffer has already full then discard the current package. - if (strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -274,10 +274,10 @@ public static function encode($payload, $connection) } $connection->tmpWebsocketData = $connection->tmpWebsocketData . $frame; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { if ($connection->onBufferFull) { try { - call_user_func($connection->onBufferFull, $connection); + \call_user_func($connection->onBufferFull, $connection); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -301,14 +301,14 @@ public static function encode($payload, $connection) */ public static function decode($bytes, $connection) { - $data_length = ord($bytes[1]); + $data_length = \ord($bytes[1]); if ($data_length === 126) { - $decoded_data = substr($bytes, 4); + $decoded_data = \substr($bytes, 4); } else if ($data_length === 127) { - $decoded_data = substr($bytes, 10); + $decoded_data = \substr($bytes, 10); } else { - $decoded_data = substr($bytes, 2); + $decoded_data = \substr($bytes, 2); } if ($connection->websocketCurrentFrameLength) { $connection->websocketDataBuffer .= $decoded_data; @@ -364,22 +364,22 @@ public static function sendHandshake($connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $connection->websocketSecKey = base64_encode(md5(mt_rand(), true)); + $connection->websocketSecKey = \base64_encode(md5(\mt_rand(), true)); $user_header = isset($connection->headers) ? $connection->headers : (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); $user_header_str = ''; if (!empty($user_header)) { - if (is_array($user_header)){ + if (\is_array($user_header)){ foreach($user_header as $k=>$v){ $user_header_str .= "$k: $v\r\n"; } } else { $user_header_str .= $user_header; } - $user_header_str = "\r\n".trim($user_header_str); + $user_header_str = "\r\n".\trim($user_header_str); } $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". - (!preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). + (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). "Connection: Upgrade\r\n". "Upgrade: websocket\r\n". (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":''). @@ -402,17 +402,17 @@ public static function sendHandshake($connection) */ public static function dealHandshake($buffer, $connection) { - $pos = strpos($buffer, "\r\n\r\n"); + $pos = \strpos($buffer, "\r\n\r\n"); if ($pos) { //checking Sec-WebSocket-Accept - if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { - if ($match[1] !== base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { - Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n"); + if (\preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { + if ($match[1] !== \base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { + Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . \substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } } else { - Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n"); + Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . \substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } @@ -420,8 +420,8 @@ public static function dealHandshake($buffer, $connection) // handshake complete // Get WebSocket subprotocol (if specified by server) - if (preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) { - $connection->WSServerProtocol = trim($match[1]); + if (\preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) { + $connection->WSServerProtocol = \trim($match[1]); } $connection->handshakeStep = 2; @@ -429,7 +429,7 @@ public static function dealHandshake($buffer, $connection) // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - call_user_func($connection->onWebSocketConnect, $connection, substr($buffer, 0, $handshake_response_length)); + \call_user_func($connection->onWebSocketConnect, $connection, \substr($buffer, 0, $handshake_response_length)); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -441,7 +441,7 @@ public static function dealHandshake($buffer, $connection) // Headbeat. if (!empty($connection->websocketPingInterval)) { $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){ - if (false === $connection->send(pack('H*', '898000000000'), true)) { + if (false === $connection->send(\pack('H*', '898000000000'), true)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; } @@ -453,8 +453,8 @@ public static function dealHandshake($buffer, $connection) $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } - if (strlen($buffer) > $handshake_response_length) { - return self::input(substr($buffer, $handshake_response_length), $connection); + if (\strlen($buffer) > $handshake_response_length) { + return self::input(\substr($buffer, $handshake_response_length), $connection); } } return 0; @@ -465,7 +465,7 @@ public static function WSSetProtocol($connection, $params) { } public static function WSGetServerProtocol($connection) { - return (property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null); + return (\property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null); } } diff --git a/WebServer.php b/WebServer.php index f529399f9..e31de9083 100644 --- a/WebServer.php +++ b/WebServer.php @@ -52,9 +52,9 @@ class WebServer extends Worker */ public function addRoot($domain, $config) { - if (is_string($config)) { + if (is_string($config)) { $config = array('root' => $config); - } + } $this->serverRoot[$domain] = $config; } @@ -66,7 +66,7 @@ public function addRoot($domain, $config) */ public function __construct($socket_name, $context_option = array()) { - list(, $address) = explode(':', $socket_name, 2); + list(, $address) = \explode(':', $socket_name, 2); parent::__construct('http:' . $address, $context_option); $this->name = 'WebServer'; } @@ -102,7 +102,7 @@ public function onWorkerStart() // Try to emit onWorkerStart callback. if ($this->_onWorkerStart) { try { - call_user_func($this->_onWorkerStart, $this); + \call_user_func($this->_onWorkerStart, $this); } catch (\Exception $e) { self::log($e); exit(250); @@ -121,20 +121,20 @@ public function onWorkerStart() public function initMimeTypeMap() { $mime_file = Http::getMimeTypesFile(); - if (!is_file($mime_file)) { + if (!\is_file($mime_file)) { $this->log("$mime_file mime.type file not fond"); return; } - $items = file($mime_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if (!is_array($items)) { + $items = \file($mime_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + if (!\is_array($items)) { $this->log("get $mime_file mime.type content fail"); return; } foreach ($items as $content) { - if (preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { + if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { $mime_type = $match[1]; $workerman_file_extension_var = $match[2]; - $workerman_file_extension_array = explode(' ', substr($workerman_file_extension_var, 0, -1)); + $workerman_file_extension_array = \explode(' ', \substr($workerman_file_extension_var, 0, -1)); foreach ($workerman_file_extension_array as $workerman_file_extension) { self::$mimeTypeMap[$workerman_file_extension] = $mime_type; } @@ -151,10 +151,10 @@ public function initMimeTypeMap() public function onMessage($connection) { // REQUEST_URI. - $workerman_url_info = parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); + $workerman_url_info = \parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); if (!$workerman_url_info) { Http::header('HTTP/1.1 400 Bad Request'); - if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send('

400 Bad Request

'); } else { $connection->close('

400 Bad Request

'); @@ -164,10 +164,10 @@ public function onMessage($connection) $workerman_path = isset($workerman_url_info['path']) ? $workerman_url_info['path'] : '/'; - $workerman_path_info = pathinfo($workerman_path); + $workerman_path_info = \pathinfo($workerman_path); $workerman_file_extension = isset($workerman_path_info['extension']) ? $workerman_path_info['extension'] : ''; if ($workerman_file_extension === '') { - $workerman_path = ($len = strlen($workerman_path)) && $workerman_path[$len - 1] === '/' ? $workerman_path . 'index.php' : $workerman_path . '/index.php'; + $workerman_path = ($len = \strlen($workerman_path)) && $workerman_path[$len - 1] === '/' ? $workerman_path . 'index.php' : $workerman_path . '/index.php'; $workerman_file_extension = 'php'; } @@ -177,22 +177,22 @@ public function onMessage($connection) if(isset($workerman_siteConfig['additionHeader'])){ Http::header($workerman_siteConfig['additionHeader']); } - if ($workerman_file_extension === 'php' && !is_file($workerman_file)) { + if ($workerman_file_extension === 'php' && !\is_file($workerman_file)) { $workerman_file = "$workerman_root_dir/index.php"; - if (!is_file($workerman_file)) { + if (!\is_file($workerman_file)) { $workerman_file = "$workerman_root_dir/index.html"; $workerman_file_extension = 'html'; } } // File exsits. - if (is_file($workerman_file)) { + if (\is_file($workerman_file)) { // Security check. - if ((!($workerman_request_realpath = realpath($workerman_file)) || !($workerman_root_dir_realpath = realpath($workerman_root_dir))) || 0 !== strpos($workerman_request_realpath, + if ((!($workerman_request_realpath = \realpath($workerman_file)) || !($workerman_root_dir_realpath = \realpath($workerman_root_dir))) || 0 !== \strpos($workerman_request_realpath, $workerman_root_dir_realpath) ) { Http::header('HTTP/1.1 400 Bad Request'); - if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send('

400 Bad Request

'); } else { $connection->close('

400 Bad Request

'); @@ -200,14 +200,14 @@ public function onMessage($connection) return; } - $workerman_file = realpath($workerman_file); + $workerman_file = \realpath($workerman_file); // Request php file. if ($workerman_file_extension === 'php') { $workerman_cwd = getcwd(); - chdir($workerman_root_dir); - ini_set('display_errors', 'off'); - ob_start(); + \chdir($workerman_root_dir); + \ini_set('display_errors', 'off'); + \ob_start(); // Try to include php file. try { // $_SERVER. @@ -220,14 +220,14 @@ public function onMessage($connection) Worker::safeEcho($e); } } - $content = ob_get_clean(); - ini_set('display_errors', 'on'); - if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + $content = \ob_get_clean(); + \ini_set('display_errors', 'on'); + if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send($content); } else { $connection->close($content); } - chdir($workerman_cwd); + \chdir($workerman_cwd); return; } @@ -237,11 +237,11 @@ public function onMessage($connection) // 404 Http::header("HTTP/1.1 404 Not Found"); if(isset($workerman_siteConfig['custom404']) && file_exists($workerman_siteConfig['custom404'])){ - $html404 = file_get_contents($workerman_siteConfig['custom404']); + $html404 = \file_get_contents($workerman_siteConfig['custom404']); }else{ $html404 = '404 File not found

404 Not Found

'; } - if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send($html404); } else { $connection->close($html404); @@ -254,14 +254,14 @@ public static function sendFile($connection, $file_path) { // Check 304. $info = stat($file_path); - $modified_time = $info ? date('D, d M Y H:i:s', $info['mtime']) . ' ' . date_default_timezone_get() : ''; + $modified_time = $info ? \date('D, d M Y H:i:s', $info['mtime']) . ' ' . \date_default_timezone_get() : ''; if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { // Http 304. if ($modified_time === $_SERVER['HTTP_IF_MODIFIED_SINCE']) { // 304 Http::header('HTTP/1.1 304 Not Modified'); // Send nothing but http headers.. - if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { + if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send(''); } else { $connection->close(''); @@ -274,8 +274,8 @@ public static function sendFile($connection, $file_path) if ($modified_time) { $modified_time = "Last-Modified: $modified_time\r\n"; } - $file_size = filesize($file_path); - $file_info = pathinfo($file_path); + $file_size = \filesize($file_path); + $file_info = \pathinfo($file_path); $extension = isset($file_info['extension']) ? $file_info['extension'] : ''; $file_name = isset($file_info['filename']) ? $file_info['filename'] : ''; $header = "HTTP/1.1 200 OK\r\n"; @@ -290,19 +290,19 @@ public static function sendFile($connection, $file_path) $header .= "Content-Length: $file_size\r\n\r\n"; $trunk_limit_size = 1024*1024; if ($file_size < $trunk_limit_size) { - return $connection->send($header.file_get_contents($file_path), true); + return $connection->send($header.\file_get_contents($file_path), true); } $connection->send($header, true); // Read file content from disk piece by piece and send to client. - $connection->fileHandler = fopen($file_path, 'r'); + $connection->fileHandler = \fopen($file_path, 'r'); $do_write = function()use($connection) { // Send buffer not full. while(empty($connection->bufferFull)) { // Read from disk. - $buffer = fread($connection->fileHandler, 8192); + $buffer = \fread($connection->fileHandler, 8192); // Read eof. if($buffer === '' || $buffer === false) { diff --git a/Worker.php b/Worker.php index eda9a6855..74ad43d03 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.20'; + const VERSION = '3.5.21'; /** * Status starting. @@ -519,7 +519,7 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (php_sapi_name() != "cli") { + if (\php_sapi_name() != "cli") { exit("only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { @@ -534,16 +534,16 @@ protected static function checkSapiEnv() */ protected static function init() { - set_error_handler(function($code, $msg, $file, $line){ + \set_error_handler(function($code, $msg, $file, $line){ Worker::safeEcho("$msg in file $file on line $line\n"); }); // Start file. - $backtrace = debug_backtrace(); - static::$_startFile = $backtrace[count($backtrace) - 1]['file']; + $backtrace = \debug_backtrace(); + static::$_startFile = $backtrace[\count($backtrace) - 1]['file']; - $unique_prefix = str_replace('/', '_', static::$_startFile); + $unique_prefix = \str_replace('/', '_', static::$_startFile); // Pid file. if (empty(static::$pidFile)) { @@ -555,17 +555,17 @@ protected static function init() static::$logFile = __DIR__ . '/../workerman.log'; } $log_file = (string)static::$logFile; - if (!is_file($log_file)) { - touch($log_file); - chmod($log_file, 0622); + if (!\is_file($log_file)) { + \touch($log_file); + \chmod($log_file, 0622); } // State. static::$_status = static::STATUS_STARTING; // For statistics. - static::$_globalStatistics['start_timestamp'] = time(); - static::$_statisticsFile = sys_get_temp_dir() . "/$unique_prefix.status"; + static::$_globalStatistics['start_timestamp'] = \time(); + static::$_statisticsFile = \sys_get_temp_dir() . "/$unique_prefix.status"; // Process title. static::setProcessTitle('WorkerMan: master process start_file=' . static::$_startFile); @@ -584,7 +584,7 @@ protected static function init() */ protected static function lock() { - $fd = fopen(static::$_startFile, 'r'); + $fd = \fopen(static::$_startFile, 'r'); if (!$fd || !flock($fd, LOCK_EX)) { static::log("Workerman[".static::$_startFile."] already running"); exit; @@ -598,7 +598,7 @@ protected static function lock() */ protected static function unlock() { - $fd = fopen(static::$_startFile, 'r'); + $fd = \fopen(static::$_startFile, 'r'); $fd && flock($fd, LOCK_UN); } @@ -622,7 +622,7 @@ protected static function initWorkers() if (empty($worker->user)) { $worker->user = static::getCurrentUser(); } else { - if (posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { + if (\posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { static::log('Warning: You must have the root privileges to change uid and gid.'); } } @@ -636,9 +636,9 @@ protected static function initWorkers() // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; - $prop_length = strlen($worker->{$prop}); - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - static::$$key = max(static::$$key, $prop_length); + $prop_length = \strlen($worker->{$prop}); + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + static::$$key = \max(static::$$key, $prop_length); } // Listen. @@ -699,7 +699,7 @@ protected static function initId() */ protected static function getCurrentUser() { - $user_info = posix_getpwuid(posix_getuid()); + $user_info = \posix_getpwuid(\posix_getuid()); return $user_info['name']; } @@ -711,7 +711,7 @@ protected static function getCurrentUser() protected static function displayUI() { global $argv; - if (in_array('-q', $argv)) { + if (\in_array('-q', $argv)) { return; } if (static::$_OS !== OS_TYPE_LINUX) { @@ -723,20 +723,20 @@ protected static function displayUI() } //show version - $line_version = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($line_version)); + $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); $total_length = static::getSingleLineTotalLength(); - $line_one = '' . str_pad(' WORKERMAN ', $total_length + strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; - $line_two = str_pad(' WORKERS ' , $total_length + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; + $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; static::safeEcho($line_one . $line_version . $line_two); //Show title $title = ''; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; //just keep compatible with listen name $column_name == 'socket' && $column_name = 'listen'; - $title.= "{$column_name}" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($column_name)); + $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); } $title && static::safeEcho($title . PHP_EOL); @@ -744,16 +744,16 @@ protected static function displayUI() foreach (static::$_workers as $worker) { $content = ''; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; - preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); - $place_holder_length = !empty($matches) ? strlen(implode('', $matches[0])) : 0; - $content .= str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; + $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); } $content && static::safeEcho($content . PHP_EOL); } //Show last line - $line_last = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { @@ -795,12 +795,12 @@ public static function getSingleLineTotalLength() $total_length = 0; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . ucfirst(strtolower($column_name)) . 'NameLength'; + $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; $total_length += static::$$key + static::UI_SAFE_LENGTH; } //keep beauty when show less colums - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); + !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', 0); $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; return $total_length; @@ -828,7 +828,7 @@ protected static function parseCommand() 'connections', ); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; - if (!isset($argv[1]) || !in_array($argv[1], $available_commands)) { + if (!isset($argv[1]) || !\in_array($argv[1], $available_commands)) { if (isset($argv[1])) { static::safeEcho('Unknown command: ' . $argv[1] . "\n"); } @@ -836,7 +836,7 @@ protected static function parseCommand() } // Get command. - $command = trim($argv[1]); + $command = \trim($argv[1]); $command2 = isset($argv[2]) ? $argv[2] : ''; // Start command. @@ -851,8 +851,8 @@ protected static function parseCommand() static::log("Workerman[$start_file] $command $mode"); // Get master process PID. - $master_pid = is_file(static::$pidFile) ? file_get_contents(static::$pidFile) : 0; - $master_is_alive = $master_pid && posix_kill($master_pid, 0) && posix_getpid() != $master_pid; + $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0; + $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() != $master_pid; // Master is still alive? if ($master_is_alive) { if ($command === 'start') { @@ -873,13 +873,13 @@ protected static function parseCommand() break; case 'status': while (1) { - if (is_file(static::$_statisticsFile)) { - @unlink(static::$_statisticsFile); + if (\is_file(static::$_statisticsFile)) { + @\unlink(static::$_statisticsFile); } // Master process will send SIGUSR2 signal to all child processes. - posix_kill($master_pid, SIGUSR2); + \posix_kill($master_pid, SIGUSR2); // Sleep 1 second. - sleep(1); + \sleep(1); // Clear terminal. if ($command2 === '-d') { static::safeEcho("\33[H\33[2J\33(B\33[m", true); @@ -893,13 +893,13 @@ protected static function parseCommand() } exit(0); case 'connections': - if (is_file(static::$_statisticsFile) && is_writable(static::$_statisticsFile)) { - unlink(static::$_statisticsFile); + if (\is_file(static::$_statisticsFile) && \is_writable(static::$_statisticsFile)) { + \unlink(static::$_statisticsFile); } // Master process will send SIGIO signal to all child processes. - posix_kill($master_pid, SIGIO); + \posix_kill($master_pid, SIGIO); // Waiting amoment. - usleep(500000); + \usleep(500000); // Display statisitcs data from a disk file. if(is_readable(static::$_statisticsFile)) { readfile(static::$_statisticsFile); @@ -917,21 +917,21 @@ protected static function parseCommand() static::log("Workerman[$start_file] is stopping ..."); } // Send stop signal to master process. - $master_pid && posix_kill($master_pid, $sig); + $master_pid && \posix_kill($master_pid, $sig); // Timeout. $timeout = 5; - $start_time = time(); + $start_time = \time(); // Check master process is still alive? while (1) { - $master_is_alive = $master_pid && posix_kill($master_pid, 0); + $master_is_alive = $master_pid && \posix_kill($master_pid, 0); if ($master_is_alive) { // Timeout? - if (!static::$_gracefulStop && time() - $start_time >= $timeout) { + if (!static::$_gracefulStop && \time() - $start_time >= $timeout) { static::log("Workerman[$start_file] stop fail"); exit; } // Waiting amoment. - usleep(10000); + \usleep(10000); continue; } // Stop success. @@ -951,7 +951,7 @@ protected static function parseCommand() }else{ $sig = SIGUSR1; } - posix_kill($master_pid, $sig); + \posix_kill($master_pid, $sig); exit; default : if (isset($command)) { @@ -978,8 +978,8 @@ protected static function formatStatusData() } $status_str = ''; $current_total_request = array(); - $worker_info = json_decode($info[0], true); - ksort($worker_info, SORT_NUMERIC); + $worker_info = \json_decode($info[0], true); + \ksort($worker_info, SORT_NUMERIC); unset($info[0]); $data_waiting_sort = array(); $read_process_status = false; @@ -994,33 +994,33 @@ protected static function formatStatusData() foreach($info as $key => $value) { if (!$read_process_status) { $status_str .= $value . "\n"; - if (preg_match('/^pid.*?memory.*?listening/', $value)) { + if (\preg_match('/^pid.*?memory.*?listening/', $value)) { $read_process_status = true; } continue; } - if(preg_match('/^[0-9]+/', $value, $pid_math)) { + if(\preg_match('/^[0-9]+/', $value, $pid_math)) { $pid = $pid_math[0]; $data_waiting_sort[$pid] = $value; - if(preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $total_memory += intval(str_ireplace('M','',$match[1])); - $maxLen1 = max($maxLen1,strlen($match[2])); - $maxLen2 = max($maxLen2,strlen($match[3])); - $total_connections += intval($match[4]); - $total_fails += intval($match[5]); - $total_timers += intval($match[6]); + if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { + $total_memory += \intval(str_ireplace('M','',$match[1])); + $maxLen1 = \max($maxLen1,\strlen($match[2])); + $maxLen2 = \max($maxLen2,\strlen($match[3])); + $total_connections += \intval($match[4]); + $total_fails += \intval($match[5]); + $total_timers += \intval($match[6]); $current_total_request[$pid] = $match[7]; - $total_requests += intval($match[7]); + $total_requests += \intval($match[7]); } } } foreach($worker_info as $pid => $info) { if (!isset($data_waiting_sort[$pid])) { - $status_str .= "$pid\t" . str_pad('N/A', 7) . " " - . str_pad($info['listen'], static::$_maxSocketNameLength) . " " - . str_pad($info['name'], static::$_maxWorkerNameLength) . " " - . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " - . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; + $status_str .= "$pid\t" . \str_pad('N/A', 7) . " " + . \str_pad($info['listen'], static::$_maxSocketNameLength) . " " + . \str_pad($info['name'], static::$_maxWorkerNameLength) . " " + . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " + . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; continue; } //$qps = isset($total_request_cache[$pid]) ? $current_total_request[$pid] @@ -1030,16 +1030,16 @@ protected static function formatStatusData() $qps = $current_total_request[$pid] - $total_request_cache[$pid]; $total_qps += $qps; } - $status_str .= $data_waiting_sort[$pid]. " " . str_pad($qps, 6) ." [idle]\n"; + $status_str .= $data_waiting_sort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n"; } $total_request_cache = $current_total_request; $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $status_str .= "Summary\t" . str_pad($total_memory.'M', 7) . " " - . str_pad('-', $maxLen1) . " " - . str_pad('-', $maxLen2) . " " - . str_pad($total_connections, 11) . " " . str_pad($total_fails, 9) . " " - . str_pad($total_timers, 7) . " " . str_pad($total_requests, 13) . " " - . str_pad($total_qps,6)." [Summary] \n"; + $status_str .= "Summary\t" . \str_pad($total_memory.'M', 7) . " " + . \str_pad('-', $maxLen1) . " " + . \str_pad('-', $maxLen2) . " " + . \str_pad($total_connections, 11) . " " . \str_pad($total_fails, 9) . " " + . \str_pad($total_timers, 7) . " " . \str_pad($total_requests, 13) . " " + . \str_pad($total_qps,6)." [Summary] \n"; return $status_str; } @@ -1055,19 +1055,19 @@ protected static function installSignal() return; } // stop - pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false); // graceful stop - pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); // reload - pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); // graceful reload - pcntl_signal(SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); // status - pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); // connection status - pcntl_signal(SIGIO, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(SIGIO, array('\Workerman\Worker', 'signalHandler'), false); // ignore - pcntl_signal(SIGPIPE, SIG_IGN, false); + \pcntl_signal(SIGPIPE, SIG_IGN, false); } /** @@ -1081,17 +1081,17 @@ protected static function reinstallSignal() return; } // uninstall stop signal handler - pcntl_signal(SIGINT, SIG_IGN, false); + \pcntl_signal(SIGINT, SIG_IGN, false); // uninstall graceful stop signal handler - pcntl_signal(SIGTERM, SIG_IGN, false); + \pcntl_signal(SIGTERM, SIG_IGN, false); // uninstall reload signal handler - pcntl_signal(SIGUSR1, SIG_IGN, false); + \pcntl_signal(SIGUSR1, SIG_IGN, false); // uninstall graceful reload signal handler - pcntl_signal(SIGQUIT, SIG_IGN, false); + \pcntl_signal(SIGQUIT, SIG_IGN, false); // uninstall status signal handler - pcntl_signal(SIGUSR2, SIG_IGN, false); + \pcntl_signal(SIGUSR2, SIG_IGN, false); // uninstall connections status signal handler - pcntl_signal(SIGIO, SIG_IGN, false); + \pcntl_signal(SIGIO, SIG_IGN, false); // reinstall stop signal handler static::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful stop signal handler @@ -1156,18 +1156,18 @@ protected static function daemonize() if (!static::$daemonize || static::$_OS !== OS_TYPE_LINUX) { return; } - umask(0); - $pid = pcntl_fork(); + \umask(0); + $pid = \pcntl_fork(); if (-1 === $pid) { throw new Exception('fork fail'); } elseif ($pid > 0) { exit(0); } - if (-1 === posix_setsid()) { + if (-1 === \posix_setsid()) { throw new Exception("setsid fail"); } // Fork again avoid SVR4 system regain the control of terminal. - $pid = pcntl_fork(); + $pid = \pcntl_fork(); if (-1 === $pid) { throw new Exception("fork fail"); } elseif (0 !== $pid) { @@ -1186,20 +1186,20 @@ public static function resetStd() return; } global $STDOUT, $STDERR; - $handle = fopen(static::$stdoutFile, "a"); + $handle = \fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - set_error_handler(function(){}); - fclose($STDOUT); - fclose($STDERR); - fclose(STDOUT); - fclose(STDERR); - $STDOUT = fopen(static::$stdoutFile, "a"); - $STDERR = fopen(static::$stdoutFile, "a"); + \set_error_handler(function(){}); + \fclose($STDOUT); + \fclose($STDERR); + \fclose(STDOUT); + \fclose(STDERR); + $STDOUT = \fopen(static::$stdoutFile, "a"); + $STDERR = \fopen(static::$stdoutFile, "a"); // change output stream static::$_outputStream = null; static::outputStream($STDOUT); - restore_error_handler(); + \restore_error_handler(); } else { throw new Exception('can not open stdoutFile ' . static::$stdoutFile); } @@ -1216,8 +1216,8 @@ protected static function saveMasterPid() return; } - static::$_masterPid = posix_getpid(); - if (false === file_put_contents(static::$pidFile, static::$_masterPid)) { + static::$_masterPid = \posix_getpid(); + if (false === \file_put_contents(static::$pidFile, static::$_masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); } } @@ -1233,20 +1233,20 @@ protected static function getEventLoopName() return static::$eventLoopClass; } - if (!class_exists('\Swoole\Event', false)) { + if (!\class_exists('\Swoole\Event', false)) { unset(static::$_availableEventLoops['swoole']); } $loop_name = ''; foreach (static::$_availableEventLoops as $name=>$class) { - if (extension_loaded($name)) { + if (\extension_loaded($name)) { $loop_name = $name; break; } } if ($loop_name) { - if (interface_exists('\React\EventLoop\LoopInterface')) { + if (\interface_exists('\React\EventLoop\LoopInterface')) { switch ($loop_name) { case 'libevent': static::$eventLoopClass = '\Workerman\Events\React\ExtLibEventLoop'; @@ -1262,7 +1262,7 @@ protected static function getEventLoopName() static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; } } else { - static::$eventLoopClass = interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; + static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; } return static::$eventLoopClass; } @@ -1310,13 +1310,13 @@ protected static function forkWorkersForLinux() if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } - $worker_name_length = strlen($worker->name); + $worker_name_length = \strlen($worker->name); if (static::$_maxWorkerNameLength < $worker_name_length) { static::$_maxWorkerNameLength = $worker_name_length; } } - while (count(static::$_pidMap[$worker->workerId]) < $worker->count) { + while (\count(static::$_pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorkerForLinux($worker); } } @@ -1331,24 +1331,24 @@ protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; - if(in_array('-q', $argv) || count($files) === 1) + if(\in_array('-q', $argv) || \count($files) === 1) { - if(count(static::$_workers) > 1) + if(\count(static::$_workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); static::safeEcho("@@@ See http://doc.workerman.net/faq/multi-woker-for-windows.html @@@\r\n"); } - elseif(count(static::$_workers) <= 0) + elseif(\count(static::$_workers) <= 0) { exit("@@@no worker inited@@@\r\n\r\n"); } - reset(static::$_workers); + \reset(static::$_workers); /** @var Worker $worker */ $worker = current(static::$_workers); // Display UI. - static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad($worker->count, 10) . "[ok]\n"); + static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); @@ -1374,7 +1374,7 @@ public static function getStartFilesForWindows() { $files = array(); foreach($argv as $file) { - if(is_file($file)) + if(\is_file($file)) { $files[$file] = $file; } @@ -1389,8 +1389,8 @@ public static function getStartFilesForWindows() { */ public static function forkOneWorkerForWindows($start_file) { - $start_file = realpath($start_file); - $std_file = sys_get_temp_dir() . '/'.str_replace(array('/', "\\", ':'), '_', $start_file).'.out.txt'; + $start_file = \realpath($start_file); + $std_file = \sys_get_temp_dir() . '/'.\str_replace(array('/', "\\", ':'), '_', $start_file).'.out.txt'; $descriptorspec = array( 0 => array('pipe', 'a'), // stdin @@ -1400,9 +1400,9 @@ public static function forkOneWorkerForWindows($start_file) $pipes = array(); - $process = proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); - $std_handler = fopen($std_file, 'a+'); - stream_set_blocking($std_handler, 0); + $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); + $std_handler = \fopen($std_file, 'a+'); + \stream_set_blocking($std_handler, 0); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1410,7 +1410,7 @@ public static function forkOneWorkerForWindows($start_file) } $timer_id = Timer::add(0.1, function()use($std_handler) { - Worker::safeEcho(fread($std_handler, 65535)); + Worker::safeEcho(\fread($std_handler, 65535)); }); // 保存子进程句柄 @@ -1428,14 +1428,14 @@ public static function checkWorkerStatusForWindows() $process = $process_data[0]; $start_file = $process_data[1]; $timer_id = $process_data[2]; - $status = proc_get_status($process); + $status = \proc_get_status($process); if(isset($status['running'])) { if(!$status['running']) { static::safeEcho("process $start_file terminated and try to restart\n"); Timer::del($timer_id); - proc_close($process); + \proc_close($process); static::forkOneWorkerForWindows($start_file); } } @@ -1460,15 +1460,15 @@ protected static function forkOneWorkerForLinux($worker) if ($id === false) { return; } - $pid = pcntl_fork(); + $pid = \pcntl_fork(); // For master process. if ($pid > 0) { static::$_pidMap[$worker->workerId][$pid] = $pid; static::$_idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { - srand(); - mt_srand(); + \srand(); + \mt_srand(); if ($worker->reusePort) { $worker->listen(); } @@ -1506,7 +1506,7 @@ protected static function forkOneWorkerForLinux($worker) */ protected static function getId($worker_id, $pid) { - return array_search($pid, static::$_idMap[$worker_id]); + return \array_search($pid, static::$_idMap[$worker_id]); } /** @@ -1517,7 +1517,7 @@ protected static function getId($worker_id, $pid) public function setUserAndGroup() { // Get uid. - $user_info = posix_getpwnam($this->user); + $user_info = \posix_getpwnam($this->user); if (!$user_info) { static::log("Warning: User {$this->user} not exsits"); return; @@ -1525,7 +1525,7 @@ public function setUserAndGroup() $uid = $user_info['uid']; // Get gid. if ($this->group) { - $group_info = posix_getgrnam($this->group); + $group_info = \posix_getgrnam($this->group); if (!$group_info) { static::log("Warning: Group {$this->group} not exsits"); return; @@ -1536,8 +1536,8 @@ public function setUserAndGroup() } // Set uid and gid. - if ($uid != posix_getuid() || $gid != posix_getgid()) { - if (!posix_setgid($gid) || !posix_initgroups($user_info['name'], $gid) || !posix_setuid($uid)) { + if ($uid != \posix_getuid() || $gid != \posix_getgid()) { + if (!\posix_setgid($gid) || !\posix_initgroups($user_info['name'], $gid) || !\posix_setuid($uid)) { static::log("Warning: change gid or uid fail."); } } @@ -1551,15 +1551,15 @@ public function setUserAndGroup() */ protected static function setProcessTitle($title) { - set_error_handler(function(){}); + \set_error_handler(function(){}); // >=php 5.5 - if (function_exists('cli_set_process_title')) { - cli_set_process_title($title); + if (\function_exists('cli_set_process_title')) { + \cli_set_process_title($title); } // Need proctitle when php<=5.5 . - elseif (extension_loaded('proctitle') && function_exists('setproctitle')) { - setproctitle($title); + elseif (\extension_loaded('proctitle') && \function_exists('setproctitle')) { + \setproctitle($title); } - restore_error_handler(); + \restore_error_handler(); } /** @@ -1586,12 +1586,12 @@ protected static function monitorWorkersForLinux() static::$_status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. - pcntl_signal_dispatch(); + \pcntl_signal_dispatch(); // Suspends execution of the current process until a child has exited, or until a signal is delivered $status = 0; - $pid = pcntl_wait($status, WUNTRACED); + $pid = \pcntl_wait($status, WUNTRACED); // Calls signal handlers for pending signals again. - pcntl_signal_dispatch(); + \pcntl_signal_dispatch(); // If a child has already exited. if ($pid > 0) { // Find out witch worker process exited. @@ -1659,14 +1659,14 @@ protected static function exitAndClearAll() foreach (static::$_workers as $worker) { $socket_name = $worker->getSocketName(); if ($worker->transport === 'unix' && $socket_name) { - list(, $address) = explode(':', $socket_name, 2); - @unlink($address); + list(, $address) = \explode(':', $socket_name, 2); + @\unlink($address); } } - @unlink(static::$pidFile); - static::log("Workerman[" . basename(static::$_startFile) . "] has been stopped"); + @\unlink(static::$pidFile); + static::log("Workerman[" . \basename(static::$_startFile) . "] has been stopped"); if (static::$onMasterStop) { - call_user_func(static::$onMasterStop); + \call_user_func(static::$onMasterStop); } exit(0); } @@ -1679,15 +1679,15 @@ protected static function exitAndClearAll() protected static function reload() { // For master process. - if (static::$_masterPid === posix_getpid()) { + if (static::$_masterPid === \posix_getpid()) { // Set reloading state. if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) { - static::log("Workerman[" . basename(static::$_startFile) . "] reloading"); + static::log("Workerman[" . \basename(static::$_startFile) . "] reloading"); static::$_status = static::STATUS_RELOADING; // Try to emit onMasterReload callback. if (static::$onMasterReload) { try { - call_user_func(static::$onMasterReload); + \call_user_func(static::$onMasterReload); } catch (\Exception $e) { static::log($e); exit(250); @@ -1716,13 +1716,13 @@ protected static function reload() } else { foreach ($worker_pid_array as $pid) { // Send reload signal to a worker process which reloadable is false. - posix_kill($pid, $sig); + \posix_kill($pid, $sig); } } } // Get all pids that are waiting reload. - static::$_pidsToRestart = array_intersect(static::$_pidsToRestart, $reloadable_pid_array); + static::$_pidsToRestart = \array_intersect(static::$_pidsToRestart, $reloadable_pid_array); // Reload complete. if (empty(static::$_pidsToRestart)) { @@ -1732,21 +1732,21 @@ protected static function reload() return; } // Continue reload. - $one_worker_pid = current(static::$_pidsToRestart); + $one_worker_pid = \current(static::$_pidsToRestart); // Send reload signal to a worker process. - posix_kill($one_worker_pid, $sig); + \posix_kill($one_worker_pid, $sig); // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it. if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($one_worker_pid, SIGKILL), false); + Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, SIGKILL), false); } } // For child processes. else { - reset(static::$_workers); - $worker = current(static::$_workers); + \reset(static::$_workers); + $worker = \current(static::$_workers); // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { try { - call_user_func($worker->onWorkerReload, $worker); + \call_user_func($worker->onWorkerReload, $worker); } catch (\Exception $e) { static::log($e); exit(250); @@ -1771,8 +1771,8 @@ public static function stopAll() { static::$_status = static::STATUS_SHUTDOWN; // For master process. - if (static::$_masterPid === posix_getpid()) { - static::log("Workerman[" . basename(static::$_startFile) . "] stopping ..."); + if (static::$_masterPid === \posix_getpid()) { + static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ..."); $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. if (static::$_gracefulStop) { @@ -1781,15 +1781,15 @@ public static function stopAll() $sig = SIGINT; } foreach ($worker_pid_array as $worker_pid) { - posix_kill($worker_pid, $sig); + \posix_kill($worker_pid, $sig); if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, 'posix_kill', array($worker_pid, SIGKILL), false); + Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, SIGKILL), false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); // Remove statistics file. - if (is_file(static::$_statisticsFile)) { - @unlink(static::$_statisticsFile); + if (\is_file(static::$_statisticsFile)) { + @\unlink(static::$_statisticsFile); } } // For child processes. else { @@ -1817,7 +1817,7 @@ public static function checkIfChildRunning() { foreach (static::$_pidMap as $worker_id => $worker_pid_array) { foreach ($worker_pid_array as $pid => $worker_pid) { - if (!posix_kill($pid, 0)) { + if (!\posix_kill($pid, 0)) { unset(static::$_pidMap[$worker_id][$pid]); } } @@ -1852,7 +1852,7 @@ public static function getGracefulStop() protected static function writeStatisticsToStatusFile() { // For master process. - if (static::$_masterPid === posix_getpid()) { + if (static::$_masterPid === \posix_getpid()) { $all_worker_info = array(); foreach(static::$_pidMap as $worker_id => $pid_array) { /** @var /Workerman/Worker $worker */ @@ -1862,66 +1862,66 @@ protected static function writeStatisticsToStatusFile() } } - file_put_contents(static::$_statisticsFile, json_encode($all_worker_info)."\n", FILE_APPEND); - $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); - file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$_statisticsFile, \json_encode($all_worker_info)."\n", FILE_APPEND); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); + \file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$_statisticsFile, 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, 'start time:' . date('Y-m-d H:i:s', - static::$_globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", + \file_put_contents(static::$_statisticsFile, 'start time:' . \date('Y-m-d H:i:s', + static::$_globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); - $load_str = 'load average: ' . implode(", ", $loadavg); - file_put_contents(static::$_statisticsFile, - str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, - count(static::$_pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", + $load_str = 'load average: ' . \implode(", ", $loadavg); + \file_put_contents(static::$_statisticsFile, + \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + \count(static::$_pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, - str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (static::$_pidMap as $worker_id => $worker_pid_array) { $worker = static::$_workers[$worker_id]; if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) { foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { - file_put_contents(static::$_statisticsFile, - str_pad($worker->name, static::$_maxWorkerNameLength) . " " . str_pad($worker_exit_status, + \file_put_contents(static::$_statisticsFile, + \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad($worker_exit_status, 16) . " $worker_exit_count\n", FILE_APPEND); } } else { - file_put_contents(static::$_statisticsFile, - str_pad($worker->name, static::$_maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n", + \file_put_contents(static::$_statisticsFile, + \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", FILE_APPEND); } } - file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$_statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, - "pid\tmemory " . str_pad('listening', static::$_maxSocketNameLength) . " " . str_pad('worker_name', - static::$_maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " - . str_pad('timers', 8) . str_pad('total_request', 13) ." qps status\n", FILE_APPEND); + \file_put_contents(static::$_statisticsFile, + "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad('worker_name', + static::$_maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " + . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", FILE_APPEND); - chmod(static::$_statisticsFile, 0722); + \chmod(static::$_statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { - posix_kill($worker_pid, SIGUSR2); + \posix_kill($worker_pid, SIGUSR2); } return; } // For child processes. - reset(static::$_workers); + \reset(static::$_workers); /** @var \Workerman\Worker $worker */ $worker = current(static::$_workers); - $worker_status_str = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) - . " " . str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " + $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) + . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) . " "; - $worker_status_str .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) - . " " . str_pad(ConnectionInterface::$statistics['send_fail'], 9) - . " " . str_pad(static::$globalEvent->getTimerCount(), 7) - . " " . str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - file_put_contents(static::$_statisticsFile, $worker_status_str, FILE_APPEND); + $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) + . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) + . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) + . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; + \file_put_contents(static::$_statisticsFile, $worker_status_str, FILE_APPEND); } /** @@ -1932,12 +1932,12 @@ protected static function writeStatisticsToStatusFile() protected static function writeConnectionsStatisticsToStatusFile() { // For master process. - if (static::$_masterPid === posix_getpid()) { - file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); - chmod(static::$_statisticsFile, 0722); + if (static::$_masterPid === \posix_getpid()) { + \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + \file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + \chmod(static::$_statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { - posix_kill($worker_pid, SIGIO); + \posix_kill($worker_pid, SIGIO); } return; } @@ -1960,9 +1960,9 @@ protected static function writeConnectionsStatisticsToStatusFile() return $bytes."B"; }; - $pid = posix_getpid(); + $pid = \posix_getpid(); $str = ''; - reset(static::$_workers); + \reset(static::$_workers); $current_worker = current(static::$_workers); $default_worker_name = $current_worker->name; @@ -1974,31 +1974,31 @@ protected static function writeConnectionsStatisticsToStatusFile() $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; $recv_q = $bytes_format($connection->getRecvBufferQueueSize()); $send_q = $bytes_format($connection->getSendBufferQueueSize()); - $local_address = trim($connection->getLocalAddress()); - $remote_address = trim($connection->getRemoteAddress()); + $local_address = \trim($connection->getLocalAddress()); + $remote_address = \trim($connection->getRemoteAddress()); $state = $connection->getStatus(false); $bytes_read = $bytes_format($connection->bytesRead); $bytes_written = $bytes_format($connection->bytesWritten); $id = $connection->id; $protocol = $connection->protocol ? $connection->protocol : $connection->transport; - $pos = strrpos($protocol, '\\'); + $pos = \strrpos($protocol, '\\'); if ($pos) { - $protocol = substr($protocol, $pos+1); + $protocol = \substr($protocol, $pos+1); } - if (strlen($protocol) > 15) { - $protocol = substr($protocol, 0, 13) . '..'; + if (\strlen($protocol) > 15) { + $protocol = \substr($protocol, 0, 13) . '..'; } $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; - if (strlen($worker_name) > 14) { - $worker_name = substr($worker_name, 0, 12) . '..'; + if (\strlen($worker_name) > 14) { + $worker_name = \substr($worker_name, 0, 12) . '..'; } - $str .= str_pad($pid, 9) . str_pad($worker_name, 16) . str_pad($id, 10) . str_pad($transport, 8) - . str_pad($protocol, 16) . str_pad($ipv4, 7) . str_pad($ipv6, 7) . str_pad($recv_q, 13) - . str_pad($send_q, 13) . str_pad($bytes_read, 13) . str_pad($bytes_written, 13) . ' ' - . str_pad($state, 14) . ' ' . str_pad($local_address, 22) . ' ' . str_pad($remote_address, 22) ."\n"; + $str .= \str_pad($pid, 9) . \str_pad($worker_name, 16) . \str_pad($id, 10) . \str_pad($transport, 8) + . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recv_q, 13) + . \str_pad($send_q, 13) . \str_pad($bytes_read, 13) . \str_pad($bytes_written, 13) . ' ' + . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n"; } if ($str) { - file_put_contents(static::$_statisticsFile, $str, FILE_APPEND); + \file_put_contents(static::$_statisticsFile, $str, FILE_APPEND); } } @@ -2010,7 +2010,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN != static::$_status) { - $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. posix_getpid() .'] process terminated' : 'Worker process terminated'; + $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || $errors['type'] === E_PARSE || @@ -2079,8 +2079,8 @@ public static function log($msg) if (!static::$daemonize) { static::safeEcho($msg); } - file_put_contents((string)static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' - . (static::$_OS === OS_TYPE_LINUX ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); + \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' + . (static::$_OS === OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** @@ -2103,13 +2103,13 @@ public static function safeEcho($msg, $decorated = false) $green = "\033[32;40m"; $end = "\033[0m"; } - $msg = str_replace(array('', '', ''), array($line, $white, $green), $msg); - $msg = str_replace(array('', '', ''), $end, $msg); + $msg = \str_replace(array('', '', ''), array($line, $white, $green), $msg); + $msg = \str_replace(array('', '', '
'), $end, $msg); } elseif (!static::$_outputDecorated) { return false; } - fwrite($stream, $msg); - fflush($stream); + \fwrite($stream, $msg); + \fflush($stream); return true; } @@ -2122,18 +2122,18 @@ private static function outputStream($stream = null) if (!$stream) { $stream = static::$_outputStream ? static::$_outputStream : STDOUT; } - if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) { + if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { return false; } - $stat = fstat($stream); + $stat = \fstat($stream); if (($stat['mode'] & 0170000) === 0100000) { // file static::$_outputDecorated = false; } else { static::$_outputDecorated = static::$_OS === OS_TYPE_LINUX && - function_exists('posix_isatty') && - posix_isatty($stream); + \function_exists('posix_isatty') && + \posix_isatty($stream); } return static::$_outputStream = $stream; } @@ -2147,13 +2147,13 @@ function_exists('posix_isatty') && public function __construct($socket_name = '', $context_option = array()) { // Save all worker instances. - $this->workerId = spl_object_hash($this); + $this->workerId = \spl_object_hash($this); static::$_workers[$this->workerId] = $this; static::$_pidMap[$this->workerId] = array(); // Get autoload root path. - $backtrace = debug_backtrace(); - $this->_autoloadRootPath = dirname($backtrace[0]['file']); + $backtrace = \debug_backtrace(); + $this->_autoloadRootPath = \dirname($backtrace[0]['file']); // Context for socket. if ($socket_name) { @@ -2161,7 +2161,7 @@ public function __construct($socket_name = '', $context_option = array()) if (!isset($context_option['socket']['backlog'])) { $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } - $this->_context = stream_context_create($context_option); + $this->_context = \stream_context_create($context_option); } } @@ -2182,20 +2182,20 @@ public function listen() if (!$this->_mainSocket) { // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $this->_socketName, 2); + list($scheme, $address) = \explode(':', $this->_socketName, 2); // Check application layer protocol class. if (!isset(static::$_builtinTransports[$scheme])) { - $scheme = ucfirst($scheme); - $this->protocol = substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; - if (!class_exists($this->protocol)) { + $scheme = \ucfirst($scheme); + $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; + if (!\class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!class_exists($this->protocol)) { + if (!\class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } if (!isset(static::$_builtinTransports[$this->transport])) { - throw new \Exception('Bad worker->transport ' . var_export($this->transport, true)); + throw new \Exception('Bad worker->transport ' . \var_export($this->transport, true)); } } else { $this->transport = $scheme; @@ -2209,19 +2209,19 @@ public function listen() $errmsg = ''; // SO_REUSEPORT. if ($this->reusePort) { - stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); + \stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); } // Create an Internet or Unix domain server socket. - $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); + $this->_mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { throw new Exception($errmsg); } if ($this->transport === 'ssl') { - stream_socket_enable_crypto($this->_mainSocket, false); + \stream_socket_enable_crypto($this->_mainSocket, false); } elseif ($this->transport === 'unix') { - $socketFile = substr($address, 2); + $socketFile = \substr($address, 2); if ($this->user) { chown($socketFile, $this->user); } @@ -2231,16 +2231,16 @@ public function listen() } // Try to open keepalive for tcp and disable Nagle algorithm. - if (function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { - set_error_handler(function(){}); - $socket = socket_import_stream($this->_mainSocket); - socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); - socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); - restore_error_handler(); + if (\function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { + \set_error_handler(function(){}); + $socket = \socket_import_stream($this->_mainSocket); + \socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); + \socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + \restore_error_handler(); } // Non blocking. - stream_set_blocking($this->_mainSocket, 0); + \stream_set_blocking($this->_mainSocket, 0); } $this->resumeAccept(); @@ -2254,9 +2254,9 @@ public function listen() public function unlisten() { $this->pauseAccept(); if ($this->_mainSocket) { - set_error_handler(function(){}); - fclose($this->_mainSocket); - restore_error_handler(); + \set_error_handler(function(){}); + \fclose($this->_mainSocket); + \restore_error_handler(); $this->_mainSocket = null; } } @@ -2313,7 +2313,7 @@ public function run() static::$_status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); + \register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); // Set autoload root path. Autoloader::setRootPath($this->_autoloadRootPath); @@ -2336,12 +2336,12 @@ public function run() $this->onMessage = function () {}; } - restore_error_handler(); + \restore_error_handler(); // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { - call_user_func($this->onWorkerStart, $this); + \call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { static::log($e); // Avoid rapid infinite loop exit. @@ -2369,7 +2369,7 @@ public function stop() // Try to emit onWorkerStop callback. if ($this->onWorkerStop) { try { - call_user_func($this->onWorkerStop, $this); + \call_user_func($this->onWorkerStop, $this); } catch (\Exception $e) { static::log($e); exit(250); @@ -2399,9 +2399,9 @@ public function stop() public function acceptConnection($socket) { // Accept a connection on server socket. - set_error_handler(function(){}); + \set_error_handler(function(){}); $new_socket = stream_socket_accept($socket, 0, $remote_address); - restore_error_handler(); + \restore_error_handler(); // Thundering herd. if (!$new_socket) { @@ -2423,7 +2423,7 @@ public function acceptConnection($socket) // Try to emit onConnect callback. if ($this->onConnect) { try { - call_user_func($this->onConnect, $connection); + \call_user_func($this->onConnect, $connection); } catch (\Exception $e) { static::log($e); exit(250); @@ -2442,9 +2442,9 @@ public function acceptConnection($socket) */ public function acceptUdpConnection($socket) { - set_error_handler(function(){}); - $recv_buffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); - restore_error_handler(); + \set_error_handler(function(){}); + $recv_buffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + \restore_error_handler(); if (false === $recv_buffer || empty($remote_address)) { return false; } @@ -2456,27 +2456,27 @@ public function acceptUdpConnection($socket) if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ $parser = $this->protocol; - if(method_exists($parser,'input')){ + if(\method_exists($parser,'input')){ while($recv_buffer !== ''){ $len = $parser::input($recv_buffer, $connection); if($len == 0) return true; - $package = substr($recv_buffer,0,$len); - $recv_buffer = substr($recv_buffer,$len); + $package = \substr($recv_buffer,0,$len); + $recv_buffer = \substr($recv_buffer,$len); $data = $parser::decode($package,$connection); if ($data === false) continue; - call_user_func($this->onMessage, $connection, $data); + \call_user_func($this->onMessage, $connection, $data); } }else{ $data = $parser::decode($recv_buffer, $connection); // Discard bad packets. if ($data === false) return true; - call_user_func($this->onMessage, $connection, $data); + \call_user_func($this->onMessage, $connection, $data); } }else{ - call_user_func($this->onMessage, $connection, $recv_buffer); + \call_user_func($this->onMessage, $connection, $recv_buffer); } ConnectionInterface::$statistics['total_request']++; } catch (\Exception $e) { From c528197ef7b44e387e33f5cc0d9d2e0ee7bcf843 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 28 Aug 2019 17:36:14 +0800 Subject: [PATCH 0374/1216] turn reusePort on by default turn reusePort on by default for better performance --- Worker.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Worker.php b/Worker.php index 74ad43d03..0ac1f8f5a 100644 --- a/Worker.php +++ b/Worker.php @@ -2155,6 +2155,14 @@ public function __construct($socket_name = '', $context_option = array()) $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); + if (static::$_OS === OS_TYPE_LINUX && version_compare(PHP_VERSION,'7.0.0', 'ge')) { + $php_uname = strtolower(php_uname('s')); + // If not Mac OS then turn reusePort on. + if ($php_uname !== 'darwin') { + $this->reusePort = true; + } + } + // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; From 488f108f9e446f31bac4d689bb9f9fe3705862cf Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 6 Sep 2019 11:42:47 +0800 Subject: [PATCH 0375/1216] fix issue #445 fix issue #455 --- Worker.php | 63 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/Worker.php b/Worker.php index 0ac1f8f5a..838c5f98d 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.21'; + const VERSION = '3.5.22'; /** * Status starting. @@ -2166,6 +2166,7 @@ public function __construct($socket_name = '', $context_option = array()) // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; + $this->parseSocketAddress(); if (!isset($context_option['socket']['backlog'])) { $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } @@ -2189,27 +2190,8 @@ public function listen() Autoloader::setRootPath($this->_autoloadRootPath); if (!$this->_mainSocket) { - // Get the application layer communication protocol and listening address. - list($scheme, $address) = \explode(':', $this->_socketName, 2); - // Check application layer protocol class. - if (!isset(static::$_builtinTransports[$scheme])) { - $scheme = \ucfirst($scheme); - $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; - if (!\class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!\class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); - } - } - - if (!isset(static::$_builtinTransports[$this->transport])) { - throw new \Exception('Bad worker->transport ' . \var_export($this->transport, true)); - } - } else { - $this->transport = $scheme; - } - $local_socket = static::$_builtinTransports[$this->transport] . ":" . $address; + $local_socket = $this->parseSocketAddress(); // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; @@ -2229,12 +2211,12 @@ public function listen() if ($this->transport === 'ssl') { \stream_socket_enable_crypto($this->_mainSocket, false); } elseif ($this->transport === 'unix') { - $socketFile = \substr($address, 2); + $socket_file = \substr($local_socket, 7); if ($this->user) { - chown($socketFile, $this->user); + chown($socket_file, $this->user); } if ($this->group) { - chgrp($socketFile, $this->group); + chgrp($socket_file, $this->group); } } @@ -2269,6 +2251,39 @@ public function unlisten() { } } + /** + * Parse local socket address. + * + * @throws Exception + */ + protected function parseSocketAddress() { + if (!$this->_socketName) { + return; + } + // Get the application layer communication protocol and listening address. + list($scheme, $address) = \explode(':', $this->_socketName, 2); + // Check application layer protocol class. + if (!isset(static::$_builtinTransports[$scheme])) { + $scheme = \ucfirst($scheme); + $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; + if (!\class_exists($this->protocol)) { + $this->protocol = "\\Workerman\\Protocols\\$scheme"; + if (!\class_exists($this->protocol)) { + throw new Exception("class \\Protocols\\$scheme not exist"); + } + } + + if (!isset(static::$_builtinTransports[$this->transport])) { + throw new \Exception('Bad worker->transport ' . \var_export($this->transport, true)); + } + } else { + $this->transport = $scheme; + } + + $local_socket = static::$_builtinTransports[$this->transport] . ":" . $address; + return $local_socket; + } + /** * Pause accept new connections. * From b6456b53db3a7b09dbe3ba7f9bd8f0867f0a0443 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 00:58:17 +0200 Subject: [PATCH 0376/1216] Change phpdoc callback to callable --- Connection/AsyncTcpConnection.php | 2 +- Connection/AsyncUdpConnection.php | 4 ++-- Connection/ConnectionInterface.php | 6 +++--- Connection/TcpConnection.php | 10 +++++----- WebServer.php | 2 +- Worker.php | 22 +++++++++++----------- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 5dd64afe2..95ae4edaf 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -26,7 +26,7 @@ class AsyncTcpConnection extends TcpConnection /** * Emitted when socket connection is successfully established. * - * @var callback + * @var callable */ public $onConnect = null; diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 15b151f33..b8b25ddc5 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -25,14 +25,14 @@ class AsyncUdpConnection extends UdpConnection /** * Emitted when socket connection is successfully established. * - * @var callback + * @var callable */ public $onConnect = null; /** * Emitted when socket connection closed. * - * @var callback + * @var callable */ public $onClose = null; diff --git a/Connection/ConnectionInterface.php b/Connection/ConnectionInterface.php index 622862a5c..05954e2cc 100644 --- a/Connection/ConnectionInterface.php +++ b/Connection/ConnectionInterface.php @@ -33,21 +33,21 @@ abstract class ConnectionInterface /** * Emitted when data is received. * - * @var callback + * @var callable */ public $onMessage = null; /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callback + * @var callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callback + * @var callable */ public $onError = null; diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 4b0018f35..ceca00c4e 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -67,35 +67,35 @@ class TcpConnection extends ConnectionInterface /** * Emitted when data is received. * - * @var callback + * @var callable */ public $onMessage = null; /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callback + * @var callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callback + * @var callable */ public $onError = null; /** * Emitted when the send buffer becomes full. * - * @var callback + * @var callable */ public $onBufferFull = null; /** * Emitted when the send buffer becomes empty. * - * @var callback + * @var callable */ public $onBufferDrain = null; diff --git a/WebServer.php b/WebServer.php index e31de9083..a73d2f7df 100644 --- a/WebServer.php +++ b/WebServer.php @@ -39,7 +39,7 @@ class WebServer extends Worker /** * Used to save user OnWorkerStart callback settings. * - * @var callback + * @var callable */ protected $_onWorkerStart = null; diff --git a/Worker.php b/Worker.php index 838c5f98d..13078207f 100644 --- a/Worker.php +++ b/Worker.php @@ -143,63 +143,63 @@ class Worker /** * Emitted when worker processes start. * - * @var callback + * @var callable */ public $onWorkerStart = null; /** * Emitted when a socket connection is successfully established. * - * @var callback + * @var callable */ public $onConnect = null; /** * Emitted when data is received. * - * @var callback + * @var callable */ public $onMessage = null; /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callback + * @var callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callback + * @var callable */ public $onError = null; /** * Emitted when the send buffer becomes full. * - * @var callback + * @var callable */ public $onBufferFull = null; /** * Emitted when the send buffer becomes empty. * - * @var callback + * @var callable */ public $onBufferDrain = null; /** * Emitted when worker processes stoped. * - * @var callback + * @var callable */ public $onWorkerStop = null; /** * Emitted when worker processes get reload signal. * - * @var callback + * @var callable */ public $onWorkerReload = null; @@ -282,14 +282,14 @@ class Worker /** * Emitted when the master process get reload signal. * - * @var callback + * @var callable */ public static $onMasterReload = null; /** * Emitted when the master process terminated. * - * @var callback + * @var callable */ public static $onMasterStop = null; From a1af125b78154f91974c2159b0db51e91597c85b Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 01:41:08 +0200 Subject: [PATCH 0377/1216] Small performance change --- Connection/AsyncTcpConnection.php | 2 +- Events/Swoole.php | 4 ++-- WebServer.php | 2 +- Worker.php | 28 ++++++++++++++-------------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 5dd64afe2..1e5a84fb0 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -296,7 +296,7 @@ public function checkConnection() // Remove write listener. Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); - if ($this->_status != self::STATUS_CONNECTING) { + if ($this->_status !== self::STATUS_CONNECTING) { return; } diff --git a/Events/Swoole.php b/Events/Swoole.php index 26af419d5..f5b76e162 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -99,13 +99,13 @@ function ($timer_id = null) use ($func, $args, $mapId) { $fd_val = $this->_fd[$fd_key]; $res = true; if ($flag == self::EV_READ) { - if (($fd_val & SWOOLE_EVENT_READ) != SWOOLE_EVENT_READ) { + if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) { $res = Event::set($fd, $func, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); $this->_fd[$fd_key] |= SWOOLE_EVENT_READ; } } else { - if (($fd_val & SWOOLE_EVENT_WRITE) != SWOOLE_EVENT_WRITE) { + if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) { $res = Event::set($fd, null, $func, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE; diff --git a/WebServer.php b/WebServer.php index e31de9083..79bc18a7b 100644 --- a/WebServer.php +++ b/WebServer.php @@ -216,7 +216,7 @@ public function onMessage($connection) include $workerman_file; } catch (\Exception $e) { // Jump_exit? - if ($e->getMessage() != 'jump_exit') { + if ($e->getMessage() !== 'jump_exit') { Worker::safeEcho($e); } } diff --git a/Worker.php b/Worker.php index 838c5f98d..769a77f06 100644 --- a/Worker.php +++ b/Worker.php @@ -519,8 +519,8 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (\php_sapi_name() != "cli") { - exit("only run in command line mode \n"); + if (\php_sapi_name() !== 'cli') { + exit('only run in command line mode \n'); } if (DIRECTORY_SEPARATOR === '\\') { self::$_OS = OS_TYPE_WINDOWS; @@ -586,7 +586,7 @@ protected static function lock() { $fd = \fopen(static::$_startFile, 'r'); if (!$fd || !flock($fd, LOCK_EX)) { - static::log("Workerman[".static::$_startFile."] already running"); + static::log("Workerman[".static::$_startFile."] already running."); exit; } } @@ -622,7 +622,7 @@ protected static function initWorkers() if (empty($worker->user)) { $worker->user = static::getCurrentUser(); } else { - if (\posix_getuid() !== 0 && $worker->user != static::getCurrentUser()) { + if (\posix_getuid() !== 0 && $worker->user !== static::getCurrentUser()) { static::log('Warning: You must have the root privileges to change uid and gid.'); } } @@ -635,7 +635,7 @@ protected static function initWorkers() // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ - !isset($worker->{$prop}) && $worker->{$prop}= 'NNNN'; + !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; $prop_length = \strlen($worker->{$prop}); $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; static::$$key = \max(static::$$key, $prop_length); @@ -684,7 +684,7 @@ protected static function initId() { foreach (static::$_workers as $worker_id => $worker) { $new_id_map = array(); - $worker->count = $worker->count <= 0 ? 1 : $worker->count; + $worker->count = $worker->count < 1 ? 1 : $worker->count; for($key = 0; $key < $worker->count; $key++) { $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; } @@ -715,10 +715,10 @@ protected static function displayUI() return; } if (static::$_OS !== OS_TYPE_LINUX) { - static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. " PHP version:". PHP_VERSION. "\r\n"); - static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("worker listen processes status\r\n"); + static::safeEcho('----------------------- WORKERMAN -----------------------------\r\n'); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION. '\r\n'); + static::safeEcho('------------------------ WORKERS -------------------------------\r\n'); + static::safeEcho('worker listen processes status\r\n'); return; } @@ -759,7 +759,7 @@ protected static function displayUI() if (static::$daemonize) { static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); } else { - static::safeEcho("Press Ctrl+C to stop. Start success.\n"); + static::safeEcho('Press Ctrl+C to stop. Start success.\n'); } } @@ -852,7 +852,7 @@ protected static function parseCommand() // Get master process PID. $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0; - $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() != $master_pid; + $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() !== $master_pid; // Master is still alive? if ($master_is_alive) { if ($command === 'start') { @@ -1536,7 +1536,7 @@ public function setUserAndGroup() } // Set uid and gid. - if ($uid != \posix_getuid() || $gid != \posix_getgid()) { + if ($uid !== \posix_getuid() || $gid !== \posix_getgid()) { if (!\posix_setgid($gid) || !\posix_initgroups($user_info['name'], $gid) || !\posix_setuid($uid)) { static::log("Warning: change gid or uid fail."); } @@ -2009,7 +2009,7 @@ protected static function writeConnectionsStatisticsToStatusFile() */ public static function checkErrors() { - if (static::STATUS_SHUTDOWN != static::$_status) { + if (static::STATUS_SHUTDOWN !== static::$_status) { $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === E_ERROR || From 19b289eae99c1f478a8533d45f1b957ec14f1aa0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 01:46:51 +0200 Subject: [PATCH 0378/1216] Return; by default return null --- Connection/AsyncUdpConnection.php | 2 +- Connection/TcpConnection.php | 16 +++++++--------- Connection/UdpConnection.php | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 15b151f33..13c357812 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -121,7 +121,7 @@ public function send($send_buffer, $raw = false) $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { - return null; + return; } } if ($this->connected === false) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 4b0018f35..5312a6689 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -343,22 +343,20 @@ public function send($send_buffer, $raw = false) $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { - return null; + return; } } if ($this->_status !== self::STATUS_ESTABLISHED || ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) ) { - if ($this->_sendBuffer) { - if ($this->bufferIsFull()) { - self::$statistics['send_fail']++; - return false; - } + if ($this->_sendBuffer && $this->bufferIsFull()) { + self::$statistics['send_fail']++; + return false; } $this->_sendBuffer .= $send_buffer; $this->checkBufferWillFull(); - return null; + return; } // Attempt to send data directly. @@ -367,7 +365,7 @@ public function send($send_buffer, $raw = false) Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); $this->_sendBuffer = $send_buffer; $this->checkBufferWillFull(); - return null; + return; } \set_error_handler(function(){}); $len = \fwrite($this->_socket, $send_buffer); @@ -404,7 +402,7 @@ public function send($send_buffer, $raw = false) Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); // Check if the send buffer will be full. $this->checkBufferWillFull(); - return null; + return; } else { if ($this->bufferIsFull()) { self::$statistics['send_fail']++; diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index fba154ec4..ee0f2d365 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -65,7 +65,7 @@ public function send($send_buffer, $raw = false) $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { - return null; + return; } } return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); From ada24344f8b7352f668279ab2952fc12679ec9e9 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 02:22:51 +0200 Subject: [PATCH 0379/1216] Enforce type hints --- Connection/TcpConnection.php | 4 ++-- Protocols/Websocket.php | 4 ++-- Protocols/Ws.php | 15 ++++++++------- WebServer.php | 5 +++-- Worker.php | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 4b0018f35..ea245ea49 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -796,10 +796,10 @@ public function doSslHandshake($socket){ /** * This method pulls all the data out of a readable stream, and writes it to the supplied destination. * - * @param TcpConnection $dest + * @param self $dest * @return void */ - public function pipe($dest) + public function pipe(self $dest) { $source = $this; $this->onMessage = function ($source, $data) use ($dest) { diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index fd02116db..1bbdf5abb 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -336,10 +336,10 @@ public static function decode($buffer, ConnectionInterface $connection) * Websocket handshake. * * @param string $buffer - * @param \Workerman\Connection\TcpConnection $connection + * @param TcpConnection $connection * @return int */ - protected static function dealHandshake($buffer, $connection) + protected static function dealHandshake($buffer, TcpConnection $connection) { // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 211404866..8b5e084c2 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -16,6 +16,7 @@ use Workerman\Worker; use Workerman\Lib\Timer; use Workerman\Connection\TcpConnection; +use Workerman\Connection\ConnectionInterface; /** * Websocket protocol for client. @@ -43,7 +44,7 @@ class Ws * @param ConnectionInterface $connection * @return int */ - public static function input($buffer, $connection) + public static function input($buffer, ConnectionInterface $connection) { if (empty($connection->handshakeStep)) { Worker::safeEcho("recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"); @@ -227,7 +228,7 @@ public static function input($buffer, $connection) * @param ConnectionInterface $connection * @return string */ - public static function encode($payload, $connection) + public static function encode($payload, ConnectionInterface $connection) { if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; @@ -299,7 +300,7 @@ public static function encode($payload, $connection) * @param ConnectionInterface $connection * @return string */ - public static function decode($bytes, $connection) + public static function decode($bytes, ConnectionInterface $connection) { $data_length = \ord($bytes[1]); @@ -352,10 +353,10 @@ public static function onClose($connection) /** * Send websocket handshake. * - * @param \Workerman\Connection\TcpConnection $connection + * @param TcpConnection $connection * @return void */ - public static function sendHandshake($connection) + public static function sendHandshake(TcpConnection $connection) { if (!empty($connection->handshakeStep)) { return; @@ -397,10 +398,10 @@ public static function sendHandshake($connection) * Websocket handshake. * * @param string $buffer - * @param \Workerman\Connection\TcpConnection $connection + * @param TcpConnection $connection * @return int */ - public static function dealHandshake($buffer, $connection) + public static function dealHandshake($buffer, TcpConnection $connection) { $pos = \strpos($buffer, "\r\n\r\n"); if ($pos) { diff --git a/WebServer.php b/WebServer.php index e31de9083..2cb5795a7 100644 --- a/WebServer.php +++ b/WebServer.php @@ -15,6 +15,7 @@ use Workerman\Protocols\Http; use Workerman\Protocols\HttpCache; +use Workerman\Connection\TcpConnection; /** * WebServer. @@ -145,10 +146,10 @@ public function initMimeTypeMap() /** * Emit when http message coming. * - * @param Connection\TcpConnection $connection + * @param TcpConnection $connection * @return void */ - public function onMessage($connection) + public function onMessage(TcpConnection $connection) { // REQUEST_URI. $workerman_url_info = \parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); diff --git a/Worker.php b/Worker.php index 838c5f98d..eb022b64b 100644 --- a/Worker.php +++ b/Worker.php @@ -1450,10 +1450,10 @@ public static function checkWorkerStatusForWindows() /** * Fork one worker process. * - * @param \Workerman\Worker $worker + * @param self $worker * @throws Exception */ - protected static function forkOneWorkerForLinux($worker) + protected static function forkOneWorkerForLinux(self $worker) { // Get available worker id. $id = static::getId($worker->workerId, 0); From 41398f9a4fae6cc9c166b31efc5c65cf23e9fefe Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 04:06:07 +0200 Subject: [PATCH 0380/1216] Small performance --- Events/Ev.php | 2 +- Events/Swoole.php | 10 +++++----- Worker.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Events/Ev.php b/Events/Ev.php index 17010e151..522454299 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -72,7 +72,7 @@ public function add($fd, $flag, $func, $args = null) return true; case self::EV_TIMER: case self::EV_TIMER_ONCE: - $repeat = $flag == self::EV_TIMER_ONCE ? 0 : $fd; + $repeat = $flag === self::EV_TIMER_ONCE ? 0 : $fd; $param = array($func, (array)$args, $flag, $fd, self::$_timerId); $event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param); $this->_eventTimer[self::$_timerId] = $event; diff --git a/Events/Swoole.php b/Events/Swoole.php index f5b76e162..bbca83deb 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -56,7 +56,7 @@ function () { return $res; case self::EV_TIMER: case self::EV_TIMER_ONCE: - $method = self::EV_TIMER == $flag ? 'tick' : 'after'; + $method = self::EV_TIMER === $flag ? 'tick' : 'after'; if ($this->mapId > PHP_INT_MAX) { $this->mapId = 0; } @@ -74,7 +74,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { } } }); - if ($flag == self::EV_TIMER_ONCE) { + if ($flag === self::EV_TIMER_ONCE) { $this->_timerOnceMap[$mapId] = $timer_id; $this->_timer[$timer_id] = $mapId; } else { @@ -85,7 +85,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { case self::EV_WRITE: $fd_key = (int) $fd; if (! isset($this->_fd[$fd_key])) { - if ($flag == self::EV_READ) { + if ($flag === self::EV_READ) { $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); $fd_type = SWOOLE_EVENT_READ; } else { @@ -98,7 +98,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { } else { $fd_val = $this->_fd[$fd_key]; $res = true; - if ($flag == self::EV_READ) { + if ($flag === self::EV_READ) { if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) { $res = Event::set($fd, $func, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); @@ -147,7 +147,7 @@ public function del($fd, $flag) $fd_key = (int) $fd; if (isset($this->_fd[$fd_key])) { $fd_val = $this->_fd[$fd_key]; - if ($flag == self::EV_READ) { + if ($flag === self::EV_READ) { $flag_remove = ~ SWOOLE_EVENT_READ; } else { $flag_remove = ~ SWOOLE_EVENT_WRITE; diff --git a/Worker.php b/Worker.php index 769a77f06..eb11ddc53 100644 --- a/Worker.php +++ b/Worker.php @@ -735,7 +735,7 @@ protected static function displayUI() foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; //just keep compatible with listen name - $column_name == 'socket' && $column_name = 'listen'; + $column_name === 'socket' && $column_name = 'listen'; $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); } $title && static::safeEcho($title . PHP_EOL); @@ -2482,7 +2482,7 @@ public function acceptUdpConnection($socket) if(\method_exists($parser,'input')){ while($recv_buffer !== ''){ $len = $parser::input($recv_buffer, $connection); - if($len == 0) + if($len === 0) return true; $package = \substr($recv_buffer,0,$len); $recv_buffer = \substr($recv_buffer,$len); From a71e9bc19d800c1eb86171f73235d0428120f6b4 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 04:54:26 +0200 Subject: [PATCH 0381/1216] Another performance change --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 7dcfe5f1b..c0b6c596f 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -188,7 +188,7 @@ public static function decode($recv_buffer, TcpConnection $connection) } // Parse other HTTP action parameters - if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != "POST") { + if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== "POST") { $data = array(); if ($_SERVER['CONTENT_TYPE'] === "application/x-www-form-urlencoded") { \parse_str($http_body, $data); From 60c967bfecc8feb030ae3734d36bf1c9e66cee63 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 04:56:32 +0200 Subject: [PATCH 0382/1216] Faster cli sapi validation --- Protocols/Http.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index c0b6c596f..f173fd65d 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -278,7 +278,7 @@ public static function encode($content, TcpConnection $connection) */ public static function header($content, $replace = true, $http_response_code = 0) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return $http_response_code ? \header($content, $replace, $http_response_code) : \header($content, $replace); } if (\strpos($content, 'HTTP') === 0) { @@ -318,7 +318,7 @@ public static function header($content, $replace = true, $http_response_code = 0 */ public static function headerRemove($name) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { \header_remove($name); return; } @@ -346,7 +346,7 @@ public static function setcookie( $secure = false, $HTTPOnly = false ) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); } return self::header( @@ -378,7 +378,7 @@ public static function sessionCreateId() */ public static function sessionId($id = null) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return $id ? \session_id($id) : \session_id(); } if (static::sessionStarted() && HttpCache::$instance->sessionFile) { @@ -396,7 +396,7 @@ public static function sessionId($id = null) */ public static function sessionName($name = null) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return $name ? \session_name($name) : \session_name(); } $session_name = HttpCache::$sessionName; @@ -415,7 +415,7 @@ public static function sessionName($name = null) */ public static function sessionSavePath($path = null) { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return $path ? \session_save_path($path) : \session_save_path(); } if ($path && \is_dir($path) && \is_writable($path) && !static::sessionStarted()) { @@ -443,7 +443,7 @@ public static function sessionStarted() */ public static function sessionStart() { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { return \session_start(); } @@ -492,7 +492,7 @@ public static function sessionStart() */ public static function sessionWriteClose() { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { \session_write_close(); return true; } @@ -513,7 +513,7 @@ public static function sessionWriteClose() */ public static function end($msg = '') { - if (PHP_SAPI != 'cli') { + if (PHP_SAPI !== 'cli') { exit($msg); } if ($msg) { From d18273d3fb5cd2ab2849d98238d8bf4a224c11fe Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 05:33:23 +0200 Subject: [PATCH 0383/1216] Small performance change --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index f173fd65d..022b10e05 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -160,7 +160,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_SERVER['CONTENT_LENGTH'] = $value; break; case 'UPGRADE': - if($value=='websocket'){ + if($value === 'websocket'){ $connection->protocol = "\\Workerman\\Protocols\\Websocket"; return \Workerman\Protocols\Websocket::input($recv_buffer,$connection); } From 001d8b13d6127a38717987a0249e04cb0e0e7f88 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 05:40:16 +0200 Subject: [PATCH 0384/1216] Add REQUEST_TIME_FLOAT compatible with php 5.4 and useful for benchmarks --- Protocols/Http.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 7dcfe5f1b..691436c12 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -109,7 +109,8 @@ public static function decode($recv_buffer, TcpConnection $connection) 'CONTENT_TYPE' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', - 'REQUEST_TIME' => \time() + 'REQUEST_TIME' => \time(), + 'REQUEST_TIME_FLOAT' => \microtime(true) //compatible php5.4 ); // Parse headers. From 56bff584417a0573814b5bfa54b2789a1c6d29a6 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 12:40:04 +0200 Subject: [PATCH 0385/1216] Enforce array type hint --- Connection/AsyncTcpConnection.php | 2 +- Connection/TcpConnection.php | 2 +- WebServer.php | 2 +- Worker.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 95ae4edaf..26cfa3221 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -109,7 +109,7 @@ class AsyncTcpConnection extends TcpConnection * @param array $context_option * @throws Exception */ - public function __construct($remote_address, $context_option = null) + public function __construct($remote_address, array $context_option = null) { $address_info = \parse_url($remote_address); if (!$address_info) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 93597d7bd..a2cefe1b0 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -269,7 +269,7 @@ class TcpConnection extends ConnectionInterface * @param array $arguments * @return void */ - public function __call($name, $arguments) { + public function __call($name, array $arguments) { // Try to emit custom function within protocol if (\method_exists($this->protocol, $name)) { try { diff --git a/WebServer.php b/WebServer.php index b45fa7df4..d105f8e9c 100644 --- a/WebServer.php +++ b/WebServer.php @@ -65,7 +65,7 @@ public function addRoot($domain, $config) * @param string $socket_name * @param array $context_option */ - public function __construct($socket_name, $context_option = array()) + public function __construct($socket_name, array $context_option = array()) { list(, $address) = \explode(':', $socket_name, 2); parent::__construct('http:' . $address, $context_option); diff --git a/Worker.php b/Worker.php index 29cae2869..353424eb8 100644 --- a/Worker.php +++ b/Worker.php @@ -2144,7 +2144,7 @@ private static function outputStream($stream = null) * @param string $socket_name * @param array $context_option */ - public function __construct($socket_name = '', $context_option = array()) + public function __construct($socket_name = '', array $context_option = array()) { // Save all worker instances. $this->workerId = \spl_object_hash($this); From 9c598b5a1c738d78f6f9d2f71d51aed971163c80 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 12:41:11 +0200 Subject: [PATCH 0386/1216] Enforce type hints --- Events/React/Base.php | 8 +++++--- Lib/Timer.php | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Events/React/Base.php b/Events/React/Base.php index fac174cd5..a0a33ae12 100644 --- a/Events/React/Base.php +++ b/Events/React/Base.php @@ -12,14 +12,16 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman\Events\React; + use Workerman\Events\EventInterface; use React\EventLoop\TimerInterface; +use React\EventLoop\LoopInterface; /** * Class StreamSelectLoop * @package Workerman\Events\React */ -class Base implements \React\EventLoop\LoopInterface +class Base implements LoopInterface { /** * @var array @@ -37,7 +39,7 @@ class Base implements \React\EventLoop\LoopInterface protected $_signalHandlerMap = array(); /** - * @var \React\EventLoop\LoopInterface + * @var LoopInterface */ protected $_eventLoop = null; @@ -58,7 +60,7 @@ public function __construct() * @param array $args * @return bool */ - public function add($fd, $flag, $func, $args = array()) + public function add($fd, $flag, $func, array $args = array()) { $args = (array)$args; switch ($flag) { diff --git a/Lib/Timer.php b/Lib/Timer.php index c4d08295e..74e8b7d8c 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -40,17 +40,17 @@ class Timer /** * event * - * @var \Workerman\Events\EventInterface + * @var EventInterface */ protected static $_event = null; /** * Init. * - * @param \Workerman\Events\EventInterface $event + * @param EventInterface $event * @return void */ - public static function init($event = null) + public static function init(EventInterface $event = null) { if ($event) { self::$_event = $event; From 2b4e7b629e36cd1a23bb2f3934d461a139a3713f Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 12:41:39 +0200 Subject: [PATCH 0387/1216] Reorder @param --- Protocols/ProtocolInterface.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols/ProtocolInterface.php b/Protocols/ProtocolInterface.php index 9afe98498..4fea87d4c 100644 --- a/Protocols/ProtocolInterface.php +++ b/Protocols/ProtocolInterface.php @@ -26,8 +26,8 @@ interface ProtocolInterface * If length is unknow please return 0 that mean wating more data. * If the package has something wrong please return false the connection will be closed. * - * @param ConnectionInterface $connection * @param string $recv_buffer + * @param ConnectionInterface $connection * @return int|false */ public static function input($recv_buffer, ConnectionInterface $connection); @@ -35,17 +35,17 @@ public static function input($recv_buffer, ConnectionInterface $connection); /** * Decode package and emit onMessage($message) callback, $message is the result that decode returned. * - * @param ConnectionInterface $connection * @param string $recv_buffer + * @param ConnectionInterface $connection * @return mixed */ public static function decode($recv_buffer, ConnectionInterface $connection); /** * Encode package brefore sending to client. - * - * @param ConnectionInterface $connection + * * @param mixed $data + * @param ConnectionInterface $connection * @return string */ public static function encode($data, ConnectionInterface $connection); From 2a12a586f7f9be820267ca022c0d383a4bac90ee Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 13:21:02 +0200 Subject: [PATCH 0388/1216] Repair @return --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index 74e8b7d8c..b065c9594 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -81,7 +81,7 @@ public static function signalHandle() * @param callable $func * @param mixed $args * @param bool $persistent - * @return int/false + * @return int|false */ public static function add($time_interval, $func, $args = array(), $persistent = true) { From f9e8b2e4169b0d451b7b6cf6d097f65d4ae0d39d Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 14:01:33 +0200 Subject: [PATCH 0389/1216] Update type hints and default values --- Connection/AsyncTcpConnection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 26cfa3221..7170537d0 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -26,7 +26,7 @@ class AsyncTcpConnection extends TcpConnection /** * Emitted when socket connection is successfully established. * - * @var callable + * @var callable|null */ public $onConnect = null; @@ -61,7 +61,7 @@ class AsyncTcpConnection extends TcpConnection /** * Connect start time. * - * @var string + * @var float */ protected $_connectStartTime = 0; @@ -109,7 +109,7 @@ class AsyncTcpConnection extends TcpConnection * @param array $context_option * @throws Exception */ - public function __construct($remote_address, array $context_option = null) + public function __construct($remote_address, array $context_option = array()) { $address_info = \parse_url($remote_address); if (!$address_info) { @@ -303,7 +303,7 @@ public function checkConnection() // Check socket state. if ($address = \stream_socket_get_name($this->_socket, true)) { // Nonblocking. - \stream_set_blocking($this->_socket, 0); + \stream_set_blocking($this->_socket, false); // Compatible with hhvm if (\function_exists('stream_set_read_buffer')) { \stream_set_read_buffer($this->_socket, 0); From 053a6d01fde280d2a76971be2d73ccb1f1bd454e Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 14:36:58 +0200 Subject: [PATCH 0390/1216] Enforce type hint --- Events/Ev.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Events/Ev.php b/Events/Ev.php index 17010e151..ba79c277e 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -13,6 +13,7 @@ namespace Workerman\Events; use Workerman\Worker; +use EvWatcher; /** * ev eventloop @@ -126,9 +127,9 @@ public function del($fd, $flag) /** * Timer callback. * - * @param \EvWatcher $event + * @param EvWatcher $event */ - public function timerCallback($event) + public function timerCallback(EvWatcher $event) { $param = $event->data; $timer_id = $param[4]; From be2c9a1c2a5ad6d0ab7f2f3b4fbe712404b412ab Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 15:07:12 +0200 Subject: [PATCH 0391/1216] Change string to bool --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 353424eb8..e616695bc 100644 --- a/Worker.php +++ b/Worker.php @@ -473,7 +473,7 @@ class Worker /** * Graceful stop or not. * - * @var string + * @var bool */ protected static $_gracefulStop = false; From 7d959b41ec5109f954b966e169ee5e8618364224 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 15:10:21 +0200 Subject: [PATCH 0392/1216] Add string type --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index e616695bc..3970f8669 100644 --- a/Worker.php +++ b/Worker.php @@ -2085,8 +2085,8 @@ public static function log($msg) /** * Safe Echo. - * @param $msg - * @param bool $decorated + * @param string $msg + * @param bool $decorated * @return bool */ public static function safeEcho($msg, $decorated = false) From 76b90a4149413d84ac769d38d1f70970633d7e91 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 14 Sep 2019 15:44:02 +0200 Subject: [PATCH 0393/1216] Cange to bool --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 3970f8669..f1f377043 100644 --- a/Worker.php +++ b/Worker.php @@ -1402,7 +1402,7 @@ public static function forkOneWorkerForWindows($start_file) $pipes = array(); $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); $std_handler = \fopen($std_file, 'a+'); - \stream_set_blocking($std_handler, 0); + \stream_set_blocking($std_handler, false); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); From 79fda46a361a1f6d328443918aaca3b5bd421b02 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 12:37:43 +0200 Subject: [PATCH 0394/1216] Repair phpdoc --- Connection/UdpConnection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index fba154ec4..88f3cfcce 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -151,7 +151,7 @@ public function getLocalAddress() /** * Is ipv4. * - * return bool. + * @return bool. */ public function isIpV4() { @@ -164,7 +164,7 @@ public function isIpV4() /** * Is ipv6. * - * return bool. + * @return bool. */ public function isIpV6() { From 4d92ee1a36fe83c83d5b6da7723288e843f658af Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 12:38:00 +0200 Subject: [PATCH 0395/1216] Enforce bool --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index a2cefe1b0..4d0ba9c66 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -777,7 +777,7 @@ public function doSslHandshake($socket){ return false; } elseif (0 === $ret) { // There isn't enough data and should try again. - return 0; + return false; } if (isset($this->onSslHandshake)) { try { From 25d1b1caffd07c27c77441f7585d9d222e403be5 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 12:38:50 +0200 Subject: [PATCH 0396/1216] Enforce bool --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index f1f377043..52ac15270 100644 --- a/Worker.php +++ b/Worker.php @@ -2230,7 +2230,7 @@ public function listen() } // Non blocking. - \stream_set_blocking($this->_mainSocket, 0); + \stream_set_blocking($this->_mainSocket, false); } $this->resumeAccept(); From edadc095e43b86e69043aa7b92155834ad10998c Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 12:45:15 +0200 Subject: [PATCH 0397/1216] Delete unnecessary variable --- Worker.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 29cae2869..32644d1c9 100644 --- a/Worker.php +++ b/Worker.php @@ -773,7 +773,7 @@ protected static function displayUI() */ public static function getUiColumns() { - $column_map = array( + return array( 'proto' => 'transport', 'user' => 'user', 'worker' => 'name', @@ -781,8 +781,6 @@ public static function getUiColumns() 'processes' => 'count', 'status' => 'status', ); - - return $column_map; } /** From e868d6705c3d435091f5579d2a2e388f47ae6037 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 13:26:24 +0200 Subject: [PATCH 0398/1216] Delete unnecessary variable --- Worker.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 32644d1c9..6367f6e02 100644 --- a/Worker.php +++ b/Worker.php @@ -2277,9 +2277,8 @@ protected function parseSocketAddress() { } else { $this->transport = $scheme; } - - $local_socket = static::$_builtinTransports[$this->transport] . ":" . $address; - return $local_socket; + //local socket + return static::$_builtinTransports[$this->transport] . ":" . $address; } /** From d88d46039a0f4d6b7b30a913dd808886c855406d Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 16 Sep 2019 13:28:07 +0200 Subject: [PATCH 0399/1216] Consistency changes --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 6367f6e02..93ca76bde 100644 --- a/Worker.php +++ b/Worker.php @@ -1260,7 +1260,7 @@ protected static function getEventLoopName() static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; } } else { - static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface')? '\Workerman\Events\React\StreamSelectLoop':'\Workerman\Events\Select'; + static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface') ? '\Workerman\Events\React\StreamSelectLoop' : '\Workerman\Events\Select'; } return static::$eventLoopClass; } @@ -1835,7 +1835,7 @@ public static function getStatus() /** * If stop gracefully. * - * @return boolean + * @return bool */ public static function getGracefulStop() { From 240c15a44028fae82a4f977e44f7ce2e0b139195 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Sep 2019 14:39:55 +0800 Subject: [PATCH 0400/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 718b3ffb1..9f98319bc 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -775,7 +775,7 @@ public function doSslHandshake($socket){ return false; } elseif (0 === $ret) { // There isn't enough data and should try again. - return false; + return 0; } if (isset($this->onSslHandshake)) { try { From 3474a7436b8d3dd792bb91a8980ead8a2eaba724 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Sep 2019 14:48:57 +0800 Subject: [PATCH 0401/1216] Update Worker.php --- Worker.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Worker.php b/Worker.php index ea7e765d8..ebca0cc30 100644 --- a/Worker.php +++ b/Worker.php @@ -520,7 +520,7 @@ protected static function checkSapiEnv() { // Only for cli. if (\php_sapi_name() !== 'cli') { - exit('only run in command line mode \n'); + exit("only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { self::$_OS = OS_TYPE_WINDOWS; @@ -586,7 +586,7 @@ protected static function lock() { $fd = \fopen(static::$_startFile, 'r'); if (!$fd || !flock($fd, LOCK_EX)) { - static::log("Workerman[".static::$_startFile."] already running."); + static::log('Workerman['.static::$_startFile.'] already running.'); exit; } } @@ -715,10 +715,10 @@ protected static function displayUI() return; } if (static::$_OS !== OS_TYPE_LINUX) { - static::safeEcho('----------------------- WORKERMAN -----------------------------\r\n'); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION. '\r\n'); - static::safeEcho('------------------------ WORKERS -------------------------------\r\n'); - static::safeEcho('worker listen processes status\r\n'); + static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION. "\r\n"); + static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); + static::safeEcho("worker listen processes status\r\n"); return; } @@ -759,7 +759,7 @@ protected static function displayUI() if (static::$daemonize) { static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); } else { - static::safeEcho('Press Ctrl+C to stop. Start success.\n'); + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } } From 9f0322489d6cfe96327cff6a21f7833154f9ba93 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Sep 2019 14:50:33 +0800 Subject: [PATCH 0402/1216] version 3.5.23 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ebca0cc30..f64243345 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.22'; + const VERSION = '3.5.23'; /** * Status starting. From 5ccf24346fc9761d24333a4810a75dd7d6af46f3 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:30:49 +0200 Subject: [PATCH 0403/1216] Add phpdoc --- Protocols/Http.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 3a5515e24..0b470921e 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -274,6 +274,9 @@ public static function encode($content, TcpConnection $connection) /** * 设置http头 + * @param string $content + * @param bool $replace + * @param int $http_response_code * * @return bool|void */ From 103a8ed1235f9dff47d843e0346d6147f7ffcb7f Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:31:53 +0200 Subject: [PATCH 0404/1216] Unify $http_response_code = null the same that in header --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 0b470921e..0aa1112c2 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -280,7 +280,7 @@ public static function encode($content, TcpConnection $connection) * * @return bool|void */ - public static function header($content, $replace = true, $http_response_code = 0) + public static function header($content, $replace = true, $http_response_code = null) { if (PHP_SAPI !== 'cli') { return $http_response_code ? \header($content, $replace, $http_response_code) : \header($content, $replace); From c74b8346575641c464136ab503fd48baa560c1d0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:33:40 +0200 Subject: [PATCH 0405/1216] Delete validation as we use null Separate return, as return null. --- Protocols/Http.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 0aa1112c2..883e8fc6f 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -283,7 +283,8 @@ public static function encode($content, TcpConnection $connection) public static function header($content, $replace = true, $http_response_code = null) { if (PHP_SAPI !== 'cli') { - return $http_response_code ? \header($content, $replace, $http_response_code) : \header($content, $replace); + \header($content, $replace, $http_response_code); + return; } if (\strpos($content, 'HTTP') === 0) { $key = 'Http-Code'; From 19468bdcfcc00c9525f1854304383fc985be3967 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:35:05 +0200 Subject: [PATCH 0406/1216] Delete rerun method, now it is faster Changed directly the response code. --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 883e8fc6f..bfcf8f210 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -296,7 +296,7 @@ public static function header($content, $replace = true, $http_response_code = n } if ('location' === \strtolower($key) && !$http_response_code) { - return self::header($content, true, 302); + $http_response_code = 302; } if (isset(HttpCache::$codes[$http_response_code])) { From 15a47a07a787cd5900c67f3be066bbbfb8a22f22 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:36:31 +0200 Subject: [PATCH 0407/1216] Add response code validation before call isset in the large array --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index bfcf8f210..1136bcc49 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -299,7 +299,7 @@ public static function header($content, $replace = true, $http_response_code = n $http_response_code = 302; } - if (isset(HttpCache::$codes[$http_response_code])) { + if ($http_response_code && isset(HttpCache::$codes[$http_response_code])) { HttpCache::$header['Http-Code'] = "HTTP/1.1 $http_response_code " . HttpCache::$codes[$http_response_code]; if ($key === 'Http-Code') { return true; From f73ba219cb802b94765ab8daa819a95d8211286d Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 17 Sep 2019 18:37:39 +0200 Subject: [PATCH 0408/1216] Small changes --- Protocols/Http.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 1136bcc49..34bead667 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; use Workerman\Connection\TcpConnection; +use Workerman\Protocols\Websocket; use Workerman\Worker; /** @@ -50,10 +51,10 @@ public static function input($recv_buffer, TcpConnection $connection) if(\in_array($method, static::$methods)) { return static::getRequestSize($header, $method); - }else{ - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); - return 0; } + + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; } /** @@ -162,13 +163,13 @@ public static function decode($recv_buffer, TcpConnection $connection) break; case 'UPGRADE': if($value === 'websocket'){ - $connection->protocol = "\\Workerman\\Protocols\\Websocket"; - return \Workerman\Protocols\Websocket::input($recv_buffer,$connection); + $connection->protocol = '\Workerman\Protocols\Websocket'; + return Websocket::input($recv_buffer,$connection); } break; } } - if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE){ + if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false){ HttpCache::$gzip = true; } // Parse $_POST. @@ -277,7 +278,7 @@ public static function encode($content, TcpConnection $connection) * @param string $content * @param bool $replace * @param int $http_response_code - * + * * @return bool|void */ public static function header($content, $replace = true, $http_response_code = null) From e3ccf9c85799aacfa96bfb53ed2b2cdd4c3139e8 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Sep 2019 17:57:11 +0800 Subject: [PATCH 0409/1216] fix for #466 --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index b065c9594..68d2a72b8 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -50,7 +50,7 @@ class Timer * @param EventInterface $event * @return void */ - public static function init(EventInterface $event = null) + public static function init($event = null) { if ($event) { self::$_event = $event; From c296abc899a4d236bdcb94638021045f61a48dbf Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Sep 2019 10:03:23 +0800 Subject: [PATCH 0410/1216] Update mime.types --- Protocols/Http/mime.types | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Protocols/Http/mime.types b/Protocols/Http/mime.types index 8a218b22a..e6ccf0ab1 100644 --- a/Protocols/Http/mime.types +++ b/Protocols/Http/mime.types @@ -5,7 +5,7 @@ types { text/xml xml; image/gif gif; image/jpeg jpeg jpg; - application/x-javascript js; + application/javascript js; application/atom+xml atom; application/rss+xml rss; @@ -24,13 +24,17 @@ types { image/svg+xml svg svgz; image/webp webp; + application/font-woff woff; application/java-archive jar war ear; + application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; + application/vnd.apple.mpegurl m3u8; application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.wap.wmlc wmlc; application/vnd.google-earth.kml+xml kml; @@ -51,15 +55,19 @@ types { application/x-x509-ca-cert der pem crt; application/x-xpinstall xpi; application/xhtml+xml xhtml; + application/xspf+xml xspf; application/zip zip; application/octet-stream bin exe dll; application/octet-stream deb; application/octet-stream dmg; - application/octet-stream eot; application/octet-stream iso img; application/octet-stream msi msp msm; + application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; + application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; + audio/midi mid midi kar; audio/mpeg mp3; audio/ogg ogg; @@ -67,6 +75,7 @@ types { audio/x-realaudio ra; video/3gpp 3gpp 3gp; + video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; @@ -77,4 +86,5 @@ types { video/x-ms-asf asx asf; video/x-ms-wmv wmv; video/x-msvideo avi; + font/ttf ttf; } From 58f0492a3ea126e681010978b4181d57c70753cd Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 1 Oct 2019 11:45:24 +0200 Subject: [PATCH 0411/1216] Change getErrorType from switch() to array It's faster and easier to update. We use the constants and not numbers. --- Worker.php | 61 +++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/Worker.php b/Worker.php index f64243345..c2464ce09 100644 --- a/Worker.php +++ b/Worker.php @@ -470,6 +470,29 @@ class Worker 'ssl' => 'tcp' ); + /** + * PHP built-in error types. + * + * @var array + */ + protected static $_errorType = array( + E_ERROR => 'E_ERROR', // 1 + E_WARNING => 'E_WARNING', // 2 + E_PARSE => 'E_PARSE', // 4 + E_NOTICE => 'E_NOTICE', // 8 + E_CORE_ERROR => 'E_CORE_ERROR', // 16 + E_CORE_WARNING => 'E_CORE_WARNING', // 32 + E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 + E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 + E_USER_ERROR => 'E_USER_ERROR', // 256 + E_USER_WARNING => 'E_USER_WARNING', // 512 + E_USER_NOTICE => 'E_USER_NOTICE', // 1024 + E_STRICT => 'E_STRICT', // 2048 + E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 + E_DEPRECATED => 'E_DEPRECATED', // 8192 + E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + ); + /** * Graceful stop or not. * @@ -2030,39 +2053,11 @@ public static function checkErrors() */ protected static function getErrorType($type) { - switch ($type) { - case E_ERROR: // 1 // - return 'E_ERROR'; - case E_WARNING: // 2 // - return 'E_WARNING'; - case E_PARSE: // 4 // - return 'E_PARSE'; - case E_NOTICE: // 8 // - return 'E_NOTICE'; - case E_CORE_ERROR: // 16 // - return 'E_CORE_ERROR'; - case E_CORE_WARNING: // 32 // - return 'E_CORE_WARNING'; - case E_COMPILE_ERROR: // 64 // - return 'E_COMPILE_ERROR'; - case E_COMPILE_WARNING: // 128 // - return 'E_COMPILE_WARNING'; - case E_USER_ERROR: // 256 // - return 'E_USER_ERROR'; - case E_USER_WARNING: // 512 // - return 'E_USER_WARNING'; - case E_USER_NOTICE: // 1024 // - return 'E_USER_NOTICE'; - case E_STRICT: // 2048 // - return 'E_STRICT'; - case E_RECOVERABLE_ERROR: // 4096 // - return 'E_RECOVERABLE_ERROR'; - case E_DEPRECATED: // 8192 // - return 'E_DEPRECATED'; - case E_USER_DEPRECATED: // 16384 // - return 'E_USER_DEPRECATED'; - } - return ""; + if(isset(self::$_errorType[$type])) { + return self::$_errorType[$type]; + } + + return ''; } /** From f68815abe0521002ac7151007cefc7cd9368bfed Mon Sep 17 00:00:00 2001 From: Joanhey Date: Thu, 3 Oct 2019 11:52:44 +0200 Subject: [PATCH 0412/1216] Improve header creation --- Protocols/Http.php | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 34bead667..533670c28 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -236,18 +236,8 @@ public static function decode($recv_buffer, TcpConnection $connection) */ public static function encode($content, TcpConnection $connection) { - // Default http-code. - if (!isset(HttpCache::$header['Http-Code'])) { - $header = "HTTP/1.1 200 OK\r\n"; - } else { - $header = HttpCache::$header['Http-Code'] . "\r\n"; - unset(HttpCache::$header['Http-Code']); - } - - // Content-Type - if (!isset(HttpCache::$header['Content-Type'])) { - $header .= "Content-Type: text/html;charset=utf-8\r\n"; - } + // http-code status line. + $header = HttpCache::$status . "\r\n"; // other headers foreach (HttpCache::$header as $key => $item) { @@ -287,23 +277,23 @@ public static function header($content, $replace = true, $http_response_code = n \header($content, $replace, $http_response_code); return; } + if (\strpos($content, 'HTTP') === 0) { - $key = 'Http-Code'; - } else { + HttpCache::$status = $content; + return true; + } + $key = \strstr($content, ":", true); if (empty($key)) { return false; } - } - if ('location' === \strtolower($key) && !$http_response_code) { + if ('location' === \strtolower($key)) { + if (!$http_response_code) { $http_response_code = 302; } - - if ($http_response_code && isset(HttpCache::$codes[$http_response_code])) { - HttpCache::$header['Http-Code'] = "HTTP/1.1 $http_response_code " . HttpCache::$codes[$http_response_code]; - if ($key === 'Http-Code') { - return true; + if (isset(HttpCache::$codes[$http_response_code])) { + HttpCache::$status = "HTTP/1.1 $http_response_code " . HttpCache::$codes[$http_response_code]; } } @@ -667,7 +657,10 @@ class HttpCache * @var HttpCache */ public static $instance = null; - public static $header = array(); + public static $status = 'HTTP/1.1 200 OK'; // default status code + public static $header = array( + 'Content-Type' => 'text/html;charset=utf-8' // default Content-Type + ); public static $gzip = false; public static $sessionPath = ''; public static $sessionName = ''; From 6268bc8d831cd06090ccef087f9a09ddc040c6e6 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Thu, 3 Oct 2019 12:48:06 +0200 Subject: [PATCH 0413/1216] Add Http::responseCode() To add the code string for us. And used internally in Http::header() --- Protocols/Http.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 34bead667..e6beceedd 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -288,23 +288,20 @@ public static function header($content, $replace = true, $http_response_code = n return; } if (\strpos($content, 'HTTP') === 0) { - $key = 'Http-Code'; - } else { + HttpCache::$status = $content; + return true; + } + $key = \strstr($content, ":", true); if (empty($key)) { return false; } - } - if ('location' === \strtolower($key) && !$http_response_code) { + if ('location' === \strtolower($key)) { + if (!$http_response_code) { $http_response_code = 302; } - - if ($http_response_code && isset(HttpCache::$codes[$http_response_code])) { - HttpCache::$header['Http-Code'] = "HTTP/1.1 $http_response_code " . HttpCache::$codes[$http_response_code]; - if ($key === 'Http-Code') { - return true; - } + self::responseCode($http_response_code); } if ($key === 'Set-Cookie') { @@ -331,6 +328,18 @@ public static function headerRemove($name) unset(HttpCache::$header[$name]); } + /** + * Add response header (http_response_code). + * + * @param int $code + * @return void + */ + public static function responseCode($code) { + if (isset(HttpCache::$codes[$code])) { + HttpCache::$status = "HTTP/1.1 $code " . HttpCache::$codes[$code]; + } + } + /** * Set cookie. * From 3367e7632f578351e801e22c7f4e9104e126f029 Mon Sep 17 00:00:00 2001 From: jcheron Date: Sun, 6 Oct 2019 15:03:45 +0200 Subject: [PATCH 0414/1216] compliance with php http_response_code function --- Protocols/Http.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 26340e861..c8a06a585 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -320,15 +320,18 @@ public static function headerRemove($name) } /** - * Add response header (http_response_code). + * Sets the HTTP response status code. * - * @param int $code - * @return void + * @param int $code The response code + * @return mixed The valid status code or FALSE if code is not provided and it is not invoked in a web server environment */ - public static function responseCode($code) { + public static function responseCode($code) + { if (isset(HttpCache::$codes[$code])) { HttpCache::$status = "HTTP/1.1 $code " . HttpCache::$codes[$code]; + return $code; } + return false; } /** From 90077515af34cf3394d9f7429a582d49e89969c3 Mon Sep 17 00:00:00 2001 From: jcheron Date: Sun, 6 Oct 2019 15:09:29 +0200 Subject: [PATCH 0415/1216] more precision about return type --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index c8a06a585..6b0ecb655 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -323,7 +323,7 @@ public static function headerRemove($name) * Sets the HTTP response status code. * * @param int $code The response code - * @return mixed The valid status code or FALSE if code is not provided and it is not invoked in a web server environment + * @return boolean|int The valid status code or FALSE if code is not provided and it is not invoked in a web server environment */ public static function responseCode($code) { From 052d17f84fa2e78e0df87771a185547051ff6777 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 9 Oct 2019 03:20:43 +0200 Subject: [PATCH 0416/1216] Update headers defaults Now it's working --- Protocols/Http.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 6b0ecb655..4146ae343 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -41,7 +41,6 @@ public static function input($recv_buffer, TcpConnection $connection) // Judge whether the package length exceeds the limit. if (\strlen($recv_buffer) >= $connection->maxPackageSize) { $connection->close(); - return 0; } return 0; } @@ -90,7 +89,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. - HttpCache::$header = array('Connection' => 'Connection: keep-alive'); + HttpCache::$header = HttpCache::$default; HttpCache::$instance = new HttpCache(); // $_SERVER $_SERVER = array( @@ -237,7 +236,8 @@ public static function decode($recv_buffer, TcpConnection $connection) public static function encode($content, TcpConnection $connection) { // http-code status line. - $header = HttpCache::$status . "\r\n"; + $header = (HttpCache::$status ?: 'HTTP/1.1 200 OK') . "\r\n"; + HttpCache::$status = ''; // other headers foreach (HttpCache::$header as $key => $item) { @@ -254,7 +254,7 @@ public static function encode($content, TcpConnection $connection) $content = \gzencode($content,$connection->gzip); } // header - $header .= "Server: workerman/" . Worker::VERSION . "\r\nContent-Length: " . \strlen($content) . "\r\n\r\n"; + $header .= 'Content-Length: ' . \strlen($content) . "\r\n\r\n"; // save session self::sessionWriteClose(); @@ -284,8 +284,8 @@ public static function header($content, $replace = true, $http_response_code = n } $key = \strstr($content, ":", true); - if (empty($key)) { - return false; + if (empty($key)) { + return false; } if ('location' === \strtolower($key)) { @@ -666,14 +666,18 @@ class HttpCache 505 => 'HTTP Version Not Supported', ); + public static $default = array( + 'Content-Type' => 'Content-Type: text/html;charset=utf-8', + 'Connection' => 'Connection: keep-alive', + 'Server' => 'Server: workerman/' . Worker::VERSION + ); + /** * @var HttpCache */ public static $instance = null; - public static $status = 'HTTP/1.1 200 OK'; // default status code - public static $header = array( - 'Content-Type' => 'text/html;charset=utf-8' // default Content-Type - ); + public static $status = ''; + public static $header = array(); public static $gzip = false; public static $sessionPath = ''; public static $sessionName = ''; From 3edfb563f39df46d4352199f0b647090c3b767a2 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Thu, 10 Oct 2019 10:36:48 +0200 Subject: [PATCH 0417/1216] Simplify and faster headers from Set-Cookie --- Protocols/Http.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 6b0ecb655..c41c09660 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -242,9 +242,7 @@ public static function encode($content, TcpConnection $connection) // other headers foreach (HttpCache::$header as $key => $item) { if ('Set-Cookie' === $key && \is_array($item)) { - foreach ($item as $it) { - $header .= $it . "\r\n"; - } + $header .= \implode("\r\n", $item) . "\r\n"; } else { $header .= $item . "\r\n"; } From 255193ae6a1cd3b0f990bae72a807c327f71d757 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Fri, 11 Oct 2019 10:40:23 +0200 Subject: [PATCH 0418/1216] Separate Set-Cookie from headers for faster encode --- Protocols/Http.php | 52 ++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 4146ae343..7b504b5ca 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -90,6 +90,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. HttpCache::$header = HttpCache::$default; + HttpCache::$cookie = array(); HttpCache::$instance = new HttpCache(); // $_SERVER $_SERVER = array( @@ -239,16 +240,14 @@ public static function encode($content, TcpConnection $connection) $header = (HttpCache::$status ?: 'HTTP/1.1 200 OK') . "\r\n"; HttpCache::$status = ''; - // other headers - foreach (HttpCache::$header as $key => $item) { - if ('Set-Cookie' === $key && \is_array($item)) { - foreach ($item as $it) { - $header .= $it . "\r\n"; - } - } else { - $header .= $item . "\r\n"; - } + // Cookie headers + if(HttpCache::$cookie) { + $header .= \implode("\r\n", HttpCache::$cookie) . "\r\n"; } + + // other headers + $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; + if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ $header .= "Content-Encoding: gzip\r\n"; $content = \gzencode($content,$connection->gzip); @@ -264,7 +263,8 @@ public static function encode($content, TcpConnection $connection) } /** - * 设置http头 + * Send a raw HTTP header + * * @param string $content * @param bool $replace * @param int $http_response_code @@ -296,7 +296,7 @@ public static function header($content, $replace = true, $http_response_code = n } if ($key === 'Set-Cookie') { - HttpCache::$header[$key][] = $content; + HttpCache::$cookie[] = $content; } else { HttpCache::$header[$key] = $content; } @@ -305,7 +305,7 @@ public static function header($content, $replace = true, $http_response_code = n } /** - * Remove header. + * Remove previously set headers * * @param string $name * @return void @@ -358,13 +358,15 @@ public static function setcookie( if (PHP_SAPI !== 'cli') { return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); } - return self::header( - 'Set-Cookie: ' . $name . '=' . rawurlencode($value) - . (empty($domain) ? '' : '; Domain=' . $domain) - . (empty($maxage) ? '' : '; Max-Age=' . $maxage) - . (empty($path) ? '' : '; Path=' . $path) - . (!$secure ? '' : '; Secure') - . (!$HTTPOnly ? '' : '; HttpOnly'), false); + + HttpCache::$cookie[] = 'Set-Cookie: ' . $name . '=' . rawurlencode($value) + . (empty($domain) ? '' : '; Domain=' . $domain) + . (empty($maxage) ? '' : '; Max-Age=' . $maxage) + . (empty($path) ? '' : '; Path=' . $path) + . (!$secure ? '' : '; Secure') + . (!$HTTPOnly ? '' : '; HttpOnly'); + + return true; } /** @@ -379,7 +381,7 @@ public static function sessionCreateId() } /** - * sessionId + * Get and/or set the current session id * * @param string $id * @@ -397,7 +399,7 @@ public static function sessionId($id = null) } /** - * sessionName + * Get and/or set the current session name * * @param string $name * @@ -416,7 +418,7 @@ public static function sessionName($name = null) } /** - * sessionSavePath + * Get and/or set the current session save path * * @param string $path * @@ -508,7 +510,7 @@ public static function sessionWriteClose() if (!empty(HttpCache::$instance->sessionStarted) && !empty($_SESSION)) { $session_str = \serialize($_SESSION); if ($session_str && HttpCache::$instance->sessionFile) { - return \file_put_contents(HttpCache::$instance->sessionFile, $session_str); + return (bool) \file_put_contents(HttpCache::$instance->sessionFile, $session_str); } } return empty($_SESSION); @@ -606,9 +608,8 @@ public static function tryGcSessions() return; } - $time_now = \time(); foreach(glob(HttpCache::$sessionPath.'/ses*') as $file) { - if(\is_file($file) && $time_now - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { + if(\is_file($file) && \time() - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { \unlink($file); } } @@ -678,6 +679,7 @@ class HttpCache public static $instance = null; public static $status = ''; public static $header = array(); + public static $cookie = array(); public static $gzip = false; public static $sessionPath = ''; public static $sessionName = ''; From 68322257ef1c056e1454b22227c4f280daa01861 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Fri, 11 Oct 2019 11:09:44 +0200 Subject: [PATCH 0419/1216] Use PHP_SAPI constant instead of function --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c2464ce09..bb815156a 100644 --- a/Worker.php +++ b/Worker.php @@ -542,7 +542,7 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (\php_sapi_name() !== 'cli') { + if (PHP_SAPI !== 'cli') { exit("only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { From facf8ba008a7c14fb274b3a2285d57facfb1685d Mon Sep 17 00:00:00 2001 From: Joanhey Date: Fri, 11 Oct 2019 13:06:45 +0200 Subject: [PATCH 0420/1216] Revert change in $time_now --- Protocols/Http.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index ba592d0dc..b94ab24a1 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -248,10 +248,10 @@ public static function encode($content, TcpConnection $connection) // other headers $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; - if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ - $header .= "Content-Encoding: gzip\r\n"; - $content = \gzencode($content,$connection->gzip); - } + if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ + $header .= "Content-Encoding: gzip\r\n"; + $content = \gzencode($content,$connection->gzip); + } // header $header .= 'Content-Length: ' . \strlen($content) . "\r\n\r\n"; @@ -608,8 +608,9 @@ public static function tryGcSessions() return; } + $time_now = \time(); foreach(glob(HttpCache::$sessionPath.'/ses*') as $file) { - if(\is_file($file) && \time() - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { + if(\is_file($file) && $time_now - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { \unlink($file); } } From ae205665e5e3da4dfc26cbf73519f715236b8a22 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 14 Oct 2019 15:49:47 +0800 Subject: [PATCH 0421/1216] Compatible with PHP 5.3 --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 012c198a5..4f47bcb61 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -667,7 +667,7 @@ class HttpCache public static $default = array( 'Content-Type' => 'Content-Type: text/html;charset=utf-8', 'Connection' => 'Connection: keep-alive', - 'Server' => 'Server: workerman/' . Worker::VERSION + 'Server' => 'Server: workerman' ); /** From d3f97a6f468d6820fd8165518e255b87e752642c Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 10:20:32 +0200 Subject: [PATCH 0422/1216] Unify and faster CLI SAPI validation --- Lib/Constants.php | 2 ++ Protocols/Http.php | 18 +++++++++--------- Worker.php | 10 +++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 1b3561b11..dd1e1e4b4 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -31,6 +31,8 @@ define('OS_TYPE_LINUX', 'linux'); define('OS_TYPE_WINDOWS', 'windows'); +define('NO_CLI', PHP_SAPI !== 'cli'); + // Compatible with php7 if(!class_exists('Error')) { diff --git a/Protocols/Http.php b/Protocols/Http.php index 462d622e6..9217dcf10 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -273,7 +273,7 @@ public static function encode($content, TcpConnection $connection) */ public static function header($content, $replace = true, $http_response_code = null) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { \header($content, $replace, $http_response_code); return; } @@ -312,7 +312,7 @@ public static function header($content, $replace = true, $http_response_code = n */ public static function headerRemove($name) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { \header_remove($name); return; } @@ -355,7 +355,7 @@ public static function setcookie( $secure = false, $HTTPOnly = false ) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); } @@ -389,7 +389,7 @@ public static function sessionCreateId() */ public static function sessionId($id = null) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { return $id ? \session_id($id) : \session_id(); } if (static::sessionStarted() && HttpCache::$instance->sessionFile) { @@ -407,7 +407,7 @@ public static function sessionId($id = null) */ public static function sessionName($name = null) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { return $name ? \session_name($name) : \session_name(); } $session_name = HttpCache::$sessionName; @@ -426,7 +426,7 @@ public static function sessionName($name = null) */ public static function sessionSavePath($path = null) { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { return $path ? \session_save_path($path) : \session_save_path(); } if ($path && \is_dir($path) && \is_writable($path) && !static::sessionStarted()) { @@ -454,7 +454,7 @@ public static function sessionStarted() */ public static function sessionStart() { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { return \session_start(); } @@ -503,7 +503,7 @@ public static function sessionStart() */ public static function sessionWriteClose() { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { \session_write_close(); return true; } @@ -524,7 +524,7 @@ public static function sessionWriteClose() */ public static function end($msg = '') { - if (PHP_SAPI !== 'cli') { + if (NO_CLI) { exit($msg); } if ($msg) { diff --git a/Worker.php b/Worker.php index bb815156a..833c49ba6 100644 --- a/Worker.php +++ b/Worker.php @@ -542,8 +542,8 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (PHP_SAPI !== 'cli') { - exit("only run in command line mode \n"); + if (NO_CLI) { + exit("Only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { self::$_OS = OS_TYPE_WINDOWS; @@ -2150,10 +2150,10 @@ public function __construct($socket_name = '', array $context_option = array()) if (static::$_OS === OS_TYPE_LINUX && version_compare(PHP_VERSION,'7.0.0', 'ge')) { $php_uname = strtolower(php_uname('s')); - // If not Mac OS then turn reusePort on. + // If not Mac OS then turn reusePort on. if ($php_uname !== 'darwin') { - $this->reusePort = true; - } + $this->reusePort = true; + } } // Context for socket. From fd8ff791b159ad16a530ddaf62a9b5f479ace6cf Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 10:21:47 +0200 Subject: [PATCH 0423/1216] Add responseCode() without CLI --- Protocols/Http.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 9217dcf10..4f2e81896 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -327,6 +327,9 @@ public static function headerRemove($name) */ public static function responseCode($code) { + if (NO_CLI) { + return \http_response_code($code); + } if (isset(HttpCache::$codes[$code])) { HttpCache::$status = "HTTP/1.1 $code " . HttpCache::$codes[$code]; return $code; From 9342d945ba356a1d25a94c769810749d3eb62044 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 10:22:33 +0200 Subject: [PATCH 0424/1216] Join validations for Mac OS --- Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index 833c49ba6..3e2a5ea64 100644 --- a/Worker.php +++ b/Worker.php @@ -2148,13 +2148,13 @@ public function __construct($socket_name = '', array $context_option = array()) $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); - if (static::$_OS === OS_TYPE_LINUX && version_compare(PHP_VERSION,'7.0.0', 'ge')) { - $php_uname = strtolower(php_uname('s')); // If not Mac OS then turn reusePort on. - if ($php_uname !== 'darwin') { + if (static::$_OS === OS_TYPE_LINUX + && version_compare(PHP_VERSION,'7.0.0', 'ge') + && strtolower(php_uname('s')) !== 'darwin') { + $this->reusePort = true; } - } // Context for socket. if ($socket_name) { From 34d07c66c0b211aa66e97df176245b5bd765eb39 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 10:36:02 +0200 Subject: [PATCH 0425/1216] Unify HttpCache cleaning --- Protocols/Http.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 462d622e6..c8c0172a6 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -89,9 +89,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. - HttpCache::$header = HttpCache::$default; - HttpCache::$cookie = array(); - HttpCache::$instance = new HttpCache(); + HttpCache::reset(); // $_SERVER $_SERVER = array( 'QUERY_STRING' => '', @@ -237,8 +235,7 @@ public static function decode($recv_buffer, TcpConnection $connection) public static function encode($content, TcpConnection $connection) { // http-code status line. - $header = (HttpCache::$status ?: 'HTTP/1.1 200 OK') . "\r\n"; - HttpCache::$status = ''; + $header = HttpCache::$status . "\r\n"; // Cookie headers if(HttpCache::$cookie) { @@ -690,6 +687,14 @@ class HttpCache public $sessionStarted = false; public $sessionFile = ''; + public static function reset() + { + self::$status = 'HTTP/1.1 200 OK'; + self::$header = self::$default; + self::$cookie = array(); + self::$instance = new HttpCache(); + } + public static function init() { if (!self::$sessionName) { From c3378e878f31418ddf014ded4dda09b9104e5553 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 10:59:59 +0200 Subject: [PATCH 0426/1216] Move constant NO_CLI to Http As the constant file it's only used by the worker. --- Lib/Constants.php | 2 -- Protocols/Http.php | 2 ++ Worker.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index dd1e1e4b4..1b3561b11 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -31,8 +31,6 @@ define('OS_TYPE_LINUX', 'linux'); define('OS_TYPE_WINDOWS', 'windows'); -define('NO_CLI', PHP_SAPI !== 'cli'); - // Compatible with php7 if(!class_exists('Error')) { diff --git a/Protocols/Http.php b/Protocols/Http.php index 4f2e81896..c88f8c508 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -722,3 +722,5 @@ public static function init() } HttpCache::init(); + +define('NO_CLI', PHP_SAPI !== 'cli'); diff --git a/Worker.php b/Worker.php index 3e2a5ea64..3b50a092b 100644 --- a/Worker.php +++ b/Worker.php @@ -542,7 +542,7 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (NO_CLI) { + if (PHP_SAPI !== 'cli') { exit("Only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { From 96af7a811764344479dc24593564cfe8de0792ea Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 11:07:57 +0200 Subject: [PATCH 0427/1216] Update comments --- Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index 3b50a092b..71602bb56 100644 --- a/Worker.php +++ b/Worker.php @@ -2148,10 +2148,10 @@ public function __construct($socket_name = '', array $context_option = array()) $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); - // If not Mac OS then turn reusePort on. - if (static::$_OS === OS_TYPE_LINUX - && version_compare(PHP_VERSION,'7.0.0', 'ge') - && strtolower(php_uname('s')) !== 'darwin') { + // Turn reusePort on. + if (static::$_OS === OS_TYPE_LINUX // if linux + && version_compare(PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && strtolower(php_uname('s')) !== 'darwin') { // if not Mac OS $this->reusePort = true; } From daaae3287e1750a90831dfac437d076003483d74 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 14 Oct 2019 13:25:39 +0200 Subject: [PATCH 0428/1216] Clean reset --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index c8c0172a6..d8c593d87 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -689,8 +689,8 @@ class HttpCache public static function reset() { - self::$status = 'HTTP/1.1 200 OK'; - self::$header = self::$default; + self::$status = 'HTTP/1.1 200 OK'; + self::$header = self::$default; self::$cookie = array(); self::$instance = new HttpCache(); } From 2ed2bd736bcfb10f120405ab07bd341792417d84 Mon Sep 17 00:00:00 2001 From: zengzizhao Date: Tue, 15 Oct 2019 11:08:47 +0800 Subject: [PATCH 0429/1216] fix bug --- Lib/Timer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/Timer.php b/Lib/Timer.php index 68d2a72b8..cd0918da0 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -90,6 +90,10 @@ public static function add($time_interval, $func, $args = array(), $persistent = return false; } + if ($args === null) { + $args = []; + } + if (self::$_event) { return self::$_event->add($time_interval, $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); From ef96e6da3894b5cf9efeb9ab78d7613b13c38795 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 13:44:35 +0200 Subject: [PATCH 0430/1216] Use global Constant --- Protocols/Http.php | 2 +- Worker.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index c88f8c508..5dcabe7f5 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -723,4 +723,4 @@ public static function init() HttpCache::init(); -define('NO_CLI', PHP_SAPI !== 'cli'); +define('NO_CLI', \PHP_SAPI !== 'cli'); diff --git a/Worker.php b/Worker.php index 71602bb56..35aba103e 100644 --- a/Worker.php +++ b/Worker.php @@ -542,7 +542,7 @@ public static function runAll() protected static function checkSapiEnv() { // Only for cli. - if (PHP_SAPI !== 'cli') { + if (\PHP_SAPI !== 'cli') { exit("Only run in command line mode \n"); } if (DIRECTORY_SEPARATOR === '\\') { From 703511e81942f46bdce550eab2b52ce1e0c49a5f Mon Sep 17 00:00:00 2001 From: hk <764432054@qq.com> Date: Wed, 16 Oct 2019 23:05:40 +0800 Subject: [PATCH 0431/1216] =?UTF-8?q?=E5=8A=A0=E4=B8=80=E4=B8=AA=5FlocalSo?= =?UTF-8?q?cket=20=20=20=E5=9C=A8=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E9=87=8C=E6=8A=8AparseSocketAddress=E7=9A=84=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=9C=A8=5FlocalSocket=20=E7=9C=81=E5=BE=97?= =?UTF-8?q?=E5=9C=A8mater=E6=88=96=E8=80=85worker=E9=87=8Clisten()?= =?UTF-8?q?=E6=97=B6=E9=87=8D=E5=A4=8D=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Worker.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index bb815156a..ada5a873c 100644 --- a/Worker.php +++ b/Worker.php @@ -321,6 +321,13 @@ class Worker */ protected $_socketName = ''; + /** parse from _socketName avoid parse again in master or worker + * LocalSocket The format is like tcp://0.0.0.0:8080 + * @var string + */ + + protected $_localSocket=null; + /** * Context of socket. * @@ -2159,7 +2166,7 @@ public function __construct($socket_name = '', array $context_option = array()) // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; - $this->parseSocketAddress(); + $this->_localSocket = $this->parseSocketAddress(); if (!isset($context_option['socket']['backlog'])) { $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } @@ -2184,7 +2191,7 @@ public function listen() if (!$this->_mainSocket) { - $local_socket = $this->parseSocketAddress(); + $local_socket = !empty($this->_localSocket)?$this->_localSocket:$this->parseSocketAddress(); // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; From c2e940aa03ae20872e8332fa75476b34d27877a3 Mon Sep 17 00:00:00 2001 From: hk <764432054@qq.com> Date: Wed, 16 Oct 2019 23:08:10 +0800 Subject: [PATCH 0432/1216] =?UTF-8?q?format=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ada5a873c..c4daec307 100644 --- a/Worker.php +++ b/Worker.php @@ -2191,7 +2191,7 @@ public function listen() if (!$this->_mainSocket) { - $local_socket = !empty($this->_localSocket)?$this->_localSocket:$this->parseSocketAddress(); + $local_socket = !empty($this->_localSocket) ? $this->_localSocket : $this->parseSocketAddress(); // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; From d068d339958c6026c73991ac8c360bbf7c6a7af0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 18:43:20 +0200 Subject: [PATCH 0433/1216] Update Timer --- Lib/Timer.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index cd0918da0..44ee4edc8 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -50,14 +50,14 @@ class Timer * @param EventInterface $event * @return void */ - public static function init($event = null) + public static function init(EventInterface $event = null) { if ($event) { self::$_event = $event; - } else { - if (\function_exists('pcntl_signal')) { - \pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); - } + return; + } + if (\function_exists('pcntl_signal')) { + \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); } } @@ -91,7 +91,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = } if ($args === null) { - $args = []; + $args = array(); } if (self::$_event) { @@ -108,8 +108,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = \pcntl_alarm(1); } - $time_now = \time(); - $run_time = $time_now + $time_interval; + $run_time = \time() + $time_interval; if (!isset(self::$_tasks[$run_time])) { self::$_tasks[$run_time] = array(); } From f1718ae2903d01b2d279b456203fb318152ae822 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 18:46:15 +0200 Subject: [PATCH 0434/1216] Update WebSocket --- Protocols/Websocket.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 1bbdf5abb..d16656b38 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -233,7 +233,7 @@ public static function input($buffer, ConnectionInterface $connection) public static function encode($buffer, ConnectionInterface $connection) { if (!is_scalar($buffer)) { - throw new \Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to a string. "); + throw new \Exception("You can't send(" . \gettype($buffer) . ") to client, you need to convert it to a string. "); } $len = \strlen($buffer); if (empty($connection->websocketType)) { @@ -355,19 +355,19 @@ protected static function dealHandshake($buffer, TcpConnection $connection) if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n", + $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

Websocket


powered by workerman ".Worker::VERSION."
", true); $connection->close(); return 0; } // Calculation websocket key. - $new_key = \base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); + $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. - $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"; - $handshake_message .= "Upgrade: websocket\r\n"; - $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; - $handshake_message .= "Connection: Upgrade\r\n"; - $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n"; + $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n" + ."Upgrade: websocket\r\n" + ."Sec-WebSocket-Version: 13\r\n" + ."Connection: Upgrade\r\n" + ."Sec-WebSocket-Accept: " . $new_key . "\r\n"; // Websocket data buffer. $connection->websocketDataBuffer = ''; @@ -440,7 +440,7 @@ protected static function dealHandshake($buffer, TcpConnection $connection) return 0; } // Bad websocket handshake request. - $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n", + $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

Websocket


powered by workerman ".Worker::VERSION."
", true); $connection->close(); return 0; @@ -472,7 +472,7 @@ protected static function parseHttpHeader($buffer) continue; } list($key, $value) = \explode(':', $content, 2); - $key = \str_replace('-', '_', strtoupper($key)); + $key = \str_replace('-', '_', \strtoupper($key)); $value = \trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { @@ -492,7 +492,7 @@ protected static function parseHttpHeader($buffer) } // QUERY_STRING - $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); + $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET \parse_str($_SERVER['QUERY_STRING'], $_GET); From 2d438637e365e3845cb867202356572daa8662b0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 18:47:41 +0200 Subject: [PATCH 0435/1216] Update Ws --- Protocols/Ws.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 8b5e084c2..9f22d2e5e 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -47,7 +47,7 @@ class Ws public static function input($buffer, ConnectionInterface $connection) { if (empty($connection->handshakeStep)) { - Worker::safeEcho("recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"); + Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n"); return false; } // Recv handshake response @@ -365,7 +365,7 @@ public static function sendHandshake(TcpConnection $connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $connection->websocketSecKey = \base64_encode(md5(\mt_rand(), true)); + $connection->websocketSecKey = \base64_encode(\md5(\mt_rand(), true)); $user_header = isset($connection->headers) ? $connection->headers : (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); $user_header_str = ''; @@ -407,7 +407,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) if ($pos) { //checking Sec-WebSocket-Accept if (\preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { - if ($match[1] !== \base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { + if ($match[1] !== \base64_encode(\sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . \substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; @@ -466,7 +466,7 @@ public static function WSSetProtocol($connection, $params) { } public static function WSGetServerProtocol($connection) { - return (\property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null); + return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); } } From 1284bb134c6dcaf88eceead6abc1b5c2ac0bc454 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 18:55:45 +0200 Subject: [PATCH 0436/1216] Update Http --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 5dcabe7f5..fd03b9481 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -86,7 +86,7 @@ protected static function getRequestSize($header, $method) public static function decode($recv_buffer, TcpConnection $connection) { // Init. - $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); + $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. HttpCache::$header = HttpCache::$default; @@ -204,7 +204,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; // QUERY_STRING - $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); + $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET \parse_str($_SERVER['QUERY_STRING'], $_GET); From 2347b0ef5a6f0ea9bd19ceca8cf09326b2dfb2ec Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 18:58:02 +0200 Subject: [PATCH 0437/1216] Update TcpConnection --- Connection/TcpConnection.php | 41 +++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 9f98319bc..4e60a38ea 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -294,7 +294,7 @@ public function __construct($socket, $remote_address = '') { self::$statistics['connection_count']++; $this->id = $this->_id = self::$_idRecorder++; - if(self::$_idRecorder === PHP_INT_MAX){ + if(self::$_idRecorder === \PHP_INT_MAX){ self::$_idRecorder = 0; } $this->_socket = $socket; @@ -315,7 +315,7 @@ public function __construct($socket, $remote_address = '') * * @param bool $raw_output * - * @return int + * @return int|string */ public function getStatus($raw_output = true) { @@ -403,16 +403,16 @@ public function send($send_buffer, $raw = false) // Check if the send buffer will be full. $this->checkBufferWillFull(); return; - } else { - if ($this->bufferIsFull()) { - self::$statistics['send_fail']++; - return false; - } + } - $this->_sendBuffer .= $send_buffer; - // Check if the send buffer is full. - $this->checkBufferWillFull(); + if ($this->bufferIsFull()) { + self::$statistics['send_fail']++; + return false; } + + $this->_sendBuffer .= $send_buffer; + // Check if the send buffer is full. + $this->checkBufferWillFull(); } /** @@ -628,7 +628,7 @@ public function baseRead($socket, $check_eof = true) } } // Wrong package. else { - Worker::safeEcho('error package. package_length=' . var_export($this->_currentPackageLength, true)); + Worker::safeEcho('Error package. package_length=' . \var_export($this->_currentPackageLength, true)); $this->destroy(); return; } @@ -756,9 +756,9 @@ public function doSslHandshake($socket){ }*/ if($async){ - $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; }else{ - $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; + $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; } // Hidden error. @@ -838,14 +838,17 @@ public function close($data = null, $raw = false) $this->destroy(); return; } + if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { return; - } else { - if ($data !== null) { - $this->send($data, $raw); - } - $this->_status = self::STATUS_CLOSING; } + + if ($data !== null) { + $this->send($data, $raw); + } + + $this->_status = self::STATUS_CLOSING; + if ($this->_sendBuffer === '') { $this->destroy(); } else { @@ -988,7 +991,7 @@ public function __destruct() self::$statistics['connection_count']--; if (Worker::getGracefulStop()) { if (!isset($mod)) { - $mod = ceil((self::$statistics['connection_count'] + 1) / 3); + $mod = \ceil((self::$statistics['connection_count'] + 1) / 3); } if (0 === self::$statistics['connection_count'] % $mod) { From 5d4971002cc2034184801041e01d1d37b1b3ebd0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:01:19 +0200 Subject: [PATCH 0438/1216] Update AsyncTcpConnection --- Connection/AsyncTcpConnection.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 3ef78e8e6..8f2bc8e99 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -137,7 +137,7 @@ public function __construct($remote_address, array $context_option = array()) } $this->id = $this->_id = self::$_idRecorder++; - if(PHP_INT_MAX === self::$_idRecorder){ + if(\PHP_INT_MAX === self::$_idRecorder){ self::$_idRecorder = 0; } // Check application layer protocol class. @@ -179,14 +179,14 @@ public function connect() if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", - $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); + $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); } else { $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", - $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT); + $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT); } } else { $this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, - STREAM_CLIENT_ASYNC_CONNECT); + \STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. if (!$this->_socket || !\is_resource($this->_socket)) { @@ -202,7 +202,7 @@ public function connect() // Add socket to global event loop waiting connection is successfully established or faild. Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); // For windows. - if(DIRECTORY_SEPARATOR === '\\') { + if(\DIRECTORY_SEPARATOR === '\\') { Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection')); } } @@ -289,7 +289,7 @@ protected function emitError($code, $msg) public function checkConnection() { // Remove EV_EXPECT for windows. - if(DIRECTORY_SEPARATOR === '\\') { + if(\DIRECTORY_SEPARATOR === '\\') { Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT); } @@ -311,8 +311,8 @@ public function checkConnection() // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = \socket_import_stream($this->_socket); - \socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); - \socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); + \socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); + \socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1); } // SSL handshake. From f1105ed2a8e038644f45801a915855ef6901ec4c Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:01:37 +0200 Subject: [PATCH 0439/1216] Update AxyncUdpConnection --- Connection/AsyncUdpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index bc271e3b3..6c1116941 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -176,7 +176,7 @@ public function connect() if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, - 30, STREAM_CLIENT_CONNECT, $context); + 30, \STREAM_CLIENT_CONNECT, $context); } else { $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); } From 4f326c2e5c4bf9e60fee6cc6d9318e8a9b87f595 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:17:37 +0200 Subject: [PATCH 0440/1216] Update Swoole --- Events/Swoole.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index bbca83deb..1778ecd84 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -57,7 +57,7 @@ function () { case self::EV_TIMER: case self::EV_TIMER_ONCE: $method = self::EV_TIMER === $flag ? 'tick' : 'after'; - if ($this->mapId > PHP_INT_MAX) { + if ($this->mapId > \PHP_INT_MAX) { $this->mapId = 0; } $mapId = $this->mapId++; @@ -67,7 +67,7 @@ function ($timer_id = null) use ($func, $args, $mapId) { // EV_TIMER_ONCE if (! isset($timer_id)) { // may be deleted in $func - if (array_key_exists($mapId, $this->_timerOnceMap)) { + if (\array_key_exists($mapId, $this->_timerOnceMap)) { $timer_id = $this->_timerOnceMap[$mapId]; unset($this->_timer[$timer_id], $this->_timerOnceMap[$mapId]); From 1b3354d41ef012ef699ab4d99b9660aecb9327b1 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:17:50 +0200 Subject: [PATCH 0441/1216] Update Libevent --- Events/Libevent.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Events/Libevent.php b/Events/Libevent.php index e6652acc7..ac3427c77 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -54,7 +54,7 @@ class Libevent implements EventInterface */ public function __construct() { - $this->_eventBase = event_base_new(); + $this->_eventBase = \event_base_new(); } /** @@ -65,8 +65,8 @@ public function add($fd, $flag, $func, $args = array()) switch ($flag) { case self::EV_SIGNAL: $fd_key = (int)$fd; - $real_flag = EV_SIGNAL | EV_PERSIST; - $this->_eventSignal[$fd_key] = event_new(); + $real_flag = \EV_SIGNAL | \EV_PERSIST; + $this->_eventSignal[$fd_key] = \event_new(); if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { return false; } @@ -81,7 +81,7 @@ public function add($fd, $flag, $func, $args = array()) case self::EV_TIMER_ONCE: $event = \event_new(); $timer_id = (int)$event; - if (!\event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { + if (!\event_set($event, 0, \EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { return false; } @@ -98,7 +98,7 @@ public function add($fd, $flag, $func, $args = array()) default : $fd_key = (int)$fd; - $real_flag = $flag === self::EV_READ ? EV_READ | EV_PERSIST : EV_WRITE | EV_PERSIST; + $real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST; $event = \event_new(); From 3cb5c6043d0a200a89334a0afdef8dff138b27ea Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:18:30 +0200 Subject: [PATCH 0442/1216] Update Select --- Events/Select.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 8b82971b7..81f347e20 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -96,8 +96,8 @@ class Select implements EventInterface public function __construct() { // Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling. - $this->channel = \stream_socket_pair(DIRECTORY_SEPARATOR === '/' ? STREAM_PF_UNIX : STREAM_PF_INET, - STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); + $this->channel = \stream_socket_pair(\DIRECTORY_SEPARATOR === '/' ? \STREAM_PF_UNIX : \STREAM_PF_INET, + \STREAM_SOCK_STREAM, \STREAM_IPPROTO_IP); if($this->channel) { \stream_set_blocking($this->channel[0], 0); $this->_readFds[0] = $this->channel[0]; @@ -118,7 +118,7 @@ public function add($fd, $flag, $func, $args = array()) $count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; - } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } $fd_key = (int)$fd; @@ -136,7 +136,7 @@ public function add($fd, $flag, $func, $args = array()) break; case self::EV_SIGNAL: // Windows not support signal. - if(DIRECTORY_SEPARATOR !== '/') { + if(\DIRECTORY_SEPARATOR !== '/') { return false; } $fd_key = (int)$fd; @@ -196,7 +196,7 @@ public function del($fd, $flag) } return true; case self::EV_SIGNAL: - if(DIRECTORY_SEPARATOR !== '/') { + if(\DIRECTORY_SEPARATOR !== '/') { return false; } unset($this->_signalEvents[$fd_key]); @@ -263,7 +263,7 @@ public function clearAllTimer() public function loop() { while (1) { - if(DIRECTORY_SEPARATOR === '/') { + if(\DIRECTORY_SEPARATOR === '/') { // Calls signal handlers for pending signals \pcntl_signal_dispatch(); } From 588d2d45a333891adec7f763c98bc164067dcb29 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:20:49 +0200 Subject: [PATCH 0443/1216] Update WebServer --- WebServer.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/WebServer.php b/WebServer.php index 176946a3a..a9a750ae0 100644 --- a/WebServer.php +++ b/WebServer.php @@ -53,7 +53,7 @@ class WebServer extends Worker */ public function addRoot($domain, $config) { - if (is_string($config)) { + if (\is_string($config)) { $config = array('root' => $config); } $this->serverRoot[$domain] = $config; @@ -126,7 +126,7 @@ public function initMimeTypeMap() $this->log("$mime_file mime.type file not fond"); return; } - $items = \file($mime_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); if (!\is_array($items)) { $this->log("get $mime_file mime.type content fail"); return; @@ -172,7 +172,7 @@ public function onMessage(TcpConnection $connection) $workerman_file_extension = 'php'; } - $workerman_siteConfig = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : current($this->serverRoot); + $workerman_siteConfig = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : \current($this->serverRoot); $workerman_root_dir = $workerman_siteConfig['root']; $workerman_file = "$workerman_root_dir/$workerman_path"; if(isset($workerman_siteConfig['additionHeader'])){ @@ -205,7 +205,7 @@ public function onMessage(TcpConnection $connection) // Request php file. if ($workerman_file_extension === 'php') { - $workerman_cwd = getcwd(); + $workerman_cwd = \getcwd(); \chdir($workerman_root_dir); \ini_set('display_errors', 'off'); \ob_start(); @@ -237,7 +237,7 @@ public function onMessage(TcpConnection $connection) } else { // 404 Http::header("HTTP/1.1 404 Not Found"); - if(isset($workerman_siteConfig['custom404']) && file_exists($workerman_siteConfig['custom404'])){ + if(isset($workerman_siteConfig['custom404']) && \file_exists($workerman_siteConfig['custom404'])){ $html404 = \file_get_contents($workerman_siteConfig['custom404']); }else{ $html404 = '404 File not found

404 Not Found

'; @@ -254,7 +254,7 @@ public function onMessage(TcpConnection $connection) public static function sendFile($connection, $file_path) { // Check 304. - $info = stat($file_path); + $info = \stat($file_path); $modified_time = $info ? \date('D, d M Y H:i:s', $info['mtime']) . ' ' . \date_default_timezone_get() : ''; if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { // Http 304. @@ -283,12 +283,12 @@ public static function sendFile($connection, $file_path) if (isset(self::$mimeTypeMap[$extension])) { $header .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; } else { - $header .= "Content-Type: application/octet-stream\r\n"; - $header .= "Content-Disposition: attachment; filename=\"$file_name\"\r\n"; + $header .= "Content-Type: application/octet-stream\r\n" + ."Content-Disposition: attachment; filename=\"$file_name\"\r\n"; } - $header .= "Connection: keep-alive\r\n"; - $header .= $modified_time; - $header .= "Content-Length: $file_size\r\n\r\n"; + $header .= "Connection: keep-alive\r\n" + .$modified_time + ."Content-Length: $file_size\r\n\r\n"; $trunk_limit_size = 1024*1024; if ($file_size < $trunk_limit_size) { return $connection->send($header.\file_get_contents($file_path), true); From c48fb1822e326d040990e9a021f18442c89c7790 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 16 Oct 2019 19:21:23 +0200 Subject: [PATCH 0444/1216] Update Worker --- Worker.php | 215 +++++++++++++++++++++++++++-------------------------- 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/Worker.php b/Worker.php index 59f6bfe80..5d71a80f6 100644 --- a/Worker.php +++ b/Worker.php @@ -275,7 +275,7 @@ class Worker /** * Global event loop. * - * @var Events\EventInterface + * @var EventInterface */ public static $globalEvent = null; @@ -483,21 +483,21 @@ class Worker * @var array */ protected static $_errorType = array( - E_ERROR => 'E_ERROR', // 1 - E_WARNING => 'E_WARNING', // 2 - E_PARSE => 'E_PARSE', // 4 - E_NOTICE => 'E_NOTICE', // 8 - E_CORE_ERROR => 'E_CORE_ERROR', // 16 - E_CORE_WARNING => 'E_CORE_WARNING', // 32 - E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 - E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 - E_USER_ERROR => 'E_USER_ERROR', // 256 - E_USER_WARNING => 'E_USER_WARNING', // 512 - E_USER_NOTICE => 'E_USER_NOTICE', // 1024 - E_STRICT => 'E_STRICT', // 2048 - E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 - E_DEPRECATED => 'E_DEPRECATED', // 8192 - E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + \E_ERROR => 'E_ERROR', // 1 + \E_WARNING => 'E_WARNING', // 2 + \E_PARSE => 'E_PARSE', // 4 + \E_NOTICE => 'E_NOTICE', // 8 + \E_CORE_ERROR => 'E_CORE_ERROR', // 16 + \E_CORE_WARNING => 'E_CORE_WARNING', // 32 + \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 + \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 + \E_USER_ERROR => 'E_USER_ERROR', // 256 + \E_USER_WARNING => 'E_USER_WARNING', // 512 + \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 + \E_STRICT => 'E_STRICT', // 2048 + \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 + \E_DEPRECATED => 'E_DEPRECATED', // 8192 + \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 ); /** @@ -552,7 +552,7 @@ protected static function checkSapiEnv() if (\PHP_SAPI !== 'cli') { exit("Only run in command line mode \n"); } - if (DIRECTORY_SEPARATOR === '\\') { + if (\DIRECTORY_SEPARATOR === '\\') { self::$_OS = OS_TYPE_WINDOWS; } } @@ -629,7 +629,7 @@ protected static function lock() protected static function unlock() { $fd = \fopen(static::$_startFile, 'r'); - $fd && flock($fd, LOCK_UN); + $fd && flock($fd, \LOCK_UN); } /** @@ -746,18 +746,18 @@ protected static function displayUI() } if (static::$_OS !== OS_TYPE_LINUX) { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION. "\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; } //show version - $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', STR_PAD_LEFT) . PHP_VERSION . PHP_EOL; + $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \PHP_EOL; !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); $total_length = static::getSingleLineTotalLength(); - $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', STR_PAD_BOTH) . ''. PHP_EOL; - $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; + $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; + $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; static::safeEcho($line_one . $line_version . $line_two); //Show title @@ -768,7 +768,7 @@ protected static function displayUI() $column_name === 'socket' && $column_name = 'listen'; $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); } - $title && static::safeEcho($title . PHP_EOL); + $title && static::safeEcho($title . \PHP_EOL); //Show content foreach (static::$_workers as $worker) { @@ -779,11 +779,11 @@ protected static function displayUI() $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); } - $content && static::safeEcho($content . PHP_EOL); + $content && static::safeEcho($content . \PHP_EOL); } //Show last line - $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; + $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL; !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { @@ -929,19 +929,19 @@ protected static function parseCommand() // Waiting amoment. \usleep(500000); // Display statisitcs data from a disk file. - if(is_readable(static::$_statisticsFile)) { - readfile(static::$_statisticsFile); + if(\is_readable(static::$_statisticsFile)) { + \readfile(static::$_statisticsFile); } exit(0); case 'restart': case 'stop': if ($command2 === '-g') { static::$_gracefulStop = true; - $sig = SIGTERM; + $sig = \SIGTERM; static::log("Workerman[$start_file] is gracefully stopping ..."); } else { static::$_gracefulStop = false; - $sig = SIGINT; + $sig = \SIGINT; static::log("Workerman[$start_file] is stopping ..."); } // Send stop signal to master process. @@ -975,9 +975,9 @@ protected static function parseCommand() break; case 'reload': if($command2 === '-g'){ - $sig = SIGQUIT; + $sig = \SIGQUIT; }else{ - $sig = SIGUSR1; + $sig = \SIGUSR1; } \posix_kill($master_pid, $sig); exit; @@ -997,10 +997,10 @@ protected static function parseCommand() protected static function formatStatusData() { static $total_request_cache = array(); - if (!is_readable(static::$_statisticsFile)) { + if (!\is_readable(static::$_statisticsFile)) { return ''; } - $info = file(static::$_statisticsFile, FILE_IGNORE_NEW_LINES); + $info = \file(static::$_statisticsFile, \FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } @@ -1031,7 +1031,7 @@ protected static function formatStatusData() $pid = $pid_math[0]; $data_waiting_sort[$pid] = $value; if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $total_memory += \intval(str_ireplace('M','',$match[1])); + $total_memory += \intval(\str_ireplace('M','',$match[1])); $maxLen1 = \max($maxLen1,\strlen($match[2])); $maxLen2 = \max($maxLen2,\strlen($match[3])); $total_connections += \intval($match[4]); @@ -1083,19 +1083,19 @@ protected static function installSignal() return; } // stop - \pcntl_signal(SIGINT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGINT, array('\Workerman\Worker', 'signalHandler'), false); // graceful stop - \pcntl_signal(SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); // reload - \pcntl_signal(SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); // graceful reload - \pcntl_signal(SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); // status - \pcntl_signal(SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); // connection status - \pcntl_signal(SIGIO, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGIO, array('\Workerman\Worker', 'signalHandler'), false); // ignore - \pcntl_signal(SIGPIPE, SIG_IGN, false); + \pcntl_signal(\SIGPIPE, \SIG_IGN, false); } /** @@ -1109,29 +1109,29 @@ protected static function reinstallSignal() return; } // uninstall stop signal handler - \pcntl_signal(SIGINT, SIG_IGN, false); + \pcntl_signal(\SIGINT, \SIG_IGN, false); // uninstall graceful stop signal handler - \pcntl_signal(SIGTERM, SIG_IGN, false); + \pcntl_signal(\SIGTERM, \SIG_IGN, false); // uninstall reload signal handler - \pcntl_signal(SIGUSR1, SIG_IGN, false); + \pcntl_signal(\SIGUSR1, \SIG_IGN, false); // uninstall graceful reload signal handler - \pcntl_signal(SIGQUIT, SIG_IGN, false); + \pcntl_signal(\SIGQUIT, \SIG_IGN, false); // uninstall status signal handler - \pcntl_signal(SIGUSR2, SIG_IGN, false); + \pcntl_signal(\SIGUSR2, \SIG_IGN, false); // uninstall connections status signal handler - \pcntl_signal(SIGIO, SIG_IGN, false); + \pcntl_signal(\SIGIO, \SIG_IGN, false); // reinstall stop signal handler - static::$globalEvent->add(SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful stop signal handler - static::$globalEvent->add(SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall reload signal handler - static::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall graceful reload signal handler - static::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall status signal handler - static::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); // reinstall connection status signal handler - static::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); } /** @@ -1143,19 +1143,19 @@ public static function signalHandler($signal) { switch ($signal) { // Stop. - case SIGINT: + case \SIGINT: static::$_gracefulStop = false; static::stopAll(); break; // Graceful stop. - case SIGTERM: + case \SIGTERM: static::$_gracefulStop = true; static::stopAll(); break; // Reload. - case SIGQUIT: - case SIGUSR1: - if($signal === SIGQUIT){ + case \SIGQUIT: + case \SIGUSR1: + if($signal === \SIGQUIT){ static::$_gracefulStop = true; }else{ static::$_gracefulStop = false; @@ -1164,11 +1164,11 @@ public static function signalHandler($signal) static::reload(); break; // Show status. - case SIGUSR2: + case \SIGUSR2: static::writeStatisticsToStatusFile(); break; // Show connection status. - case SIGIO: + case \SIGIO: static::writeConnectionsStatisticsToStatusFile(); break; } @@ -1187,17 +1187,17 @@ protected static function daemonize() \umask(0); $pid = \pcntl_fork(); if (-1 === $pid) { - throw new Exception('fork fail'); + throw new Exception('Fork fail'); } elseif ($pid > 0) { exit(0); } if (-1 === \posix_setsid()) { - throw new Exception("setsid fail"); + throw new Exception("Setsid fail"); } // Fork again avoid SVR4 system regain the control of terminal. $pid = \pcntl_fork(); if (-1 === $pid) { - throw new Exception("fork fail"); + throw new Exception("Fork fail"); } elseif (0 !== $pid) { exit(0); } @@ -1220,17 +1220,18 @@ public static function resetStd() \set_error_handler(function(){}); \fclose($STDOUT); \fclose($STDERR); - \fclose(STDOUT); - \fclose(STDERR); + \fclose(\STDOUT); + \fclose(\STDERR); $STDOUT = \fopen(static::$stdoutFile, "a"); $STDERR = \fopen(static::$stdoutFile, "a"); // change output stream static::$_outputStream = null; static::outputStream($STDOUT); \restore_error_handler(); - } else { - throw new Exception('can not open stdoutFile ' . static::$stdoutFile); + return; } + + throw new Exception('Can not open stdoutFile ' . static::$stdoutFile); } /** @@ -1617,7 +1618,7 @@ protected static function monitorWorkersForLinux() \pcntl_signal_dispatch(); // Suspends execution of the current process until a child has exited, or until a signal is delivered $status = 0; - $pid = \pcntl_wait($status, WUNTRACED); + $pid = \pcntl_wait($status, \WUNTRACED); // Calls signal handlers for pending signals again. \pcntl_signal_dispatch(); // If a child has already exited. @@ -1728,9 +1729,9 @@ protected static function reload() } if (static::$_gracefulStop) { - $sig = SIGQUIT; + $sig = \SIGQUIT; } else { - $sig = SIGUSR1; + $sig = \SIGUSR1; } // Send reload signal to all child processes. @@ -1765,7 +1766,7 @@ protected static function reload() \posix_kill($one_worker_pid, $sig); // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it. if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, SIGKILL), false); + Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, \SIGKILL), false); } } // For child processes. else { @@ -1804,14 +1805,14 @@ public static function stopAll() $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. if (static::$_gracefulStop) { - $sig = SIGTERM; + $sig = \SIGTERM; } else { - $sig = SIGINT; + $sig = \SIGINT; } foreach ($worker_pid_array as $worker_pid) { \posix_kill($worker_pid, $sig); if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, SIGKILL), false); + Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, \SIGKILL), false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); @@ -1890,49 +1891,49 @@ protected static function writeStatisticsToStatusFile() } } - \file_put_contents(static::$_statisticsFile, \json_encode($all_worker_info)."\n", FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', sys_getloadavg(), array(2)) : array('-', '-', '-'); + \file_put_contents(static::$_statisticsFile, \json_encode($all_worker_info)."\n", \FILE_APPEND); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2)) : array('-', '-', '-'); \file_put_contents(static::$_statisticsFile, - "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); + "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, - 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); + 'Workerman version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, 'start time:' . \date('Y-m-d H:i:s', static::$_globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); $load_str = 'load average: ' . \implode(", ", $loadavg); \file_put_contents(static::$_statisticsFile, - \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); + \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, \count(static::$_pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", - FILE_APPEND); + \FILE_APPEND); \file_put_contents(static::$_statisticsFile, - \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); + \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); foreach (static::$_pidMap as $worker_id => $worker_pid_array) { $worker = static::$_workers[$worker_id]; if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) { foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { \file_put_contents(static::$_statisticsFile, \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad($worker_exit_status, - 16) . " $worker_exit_count\n", FILE_APPEND); + 16) . " $worker_exit_count\n", \FILE_APPEND); } } else { \file_put_contents(static::$_statisticsFile, \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", - FILE_APPEND); + \FILE_APPEND); } } \file_put_contents(static::$_statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", - FILE_APPEND); + \FILE_APPEND); \file_put_contents(static::$_statisticsFile, "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad('worker_name', static::$_maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " - . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", FILE_APPEND); + . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", \FILE_APPEND); \chmod(static::$_statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { - \posix_kill($worker_pid, SIGUSR2); + \posix_kill($worker_pid, \SIGUSR2); } return; } @@ -1943,13 +1944,13 @@ protected static function writeStatisticsToStatusFile() $worker = current(static::$_workers); $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " - . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) + . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) . " "; $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - \file_put_contents(static::$_statisticsFile, $worker_status_str, FILE_APPEND); + \file_put_contents(static::$_statisticsFile, $worker_status_str, \FILE_APPEND); } /** @@ -1961,11 +1962,11 @@ protected static function writeConnectionsStatisticsToStatusFile() { // For master process. if (static::$_masterPid === \posix_getpid()) { - \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - \file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); \chmod(static::$_statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { - \posix_kill($worker_pid, SIGIO); + \posix_kill($worker_pid, \SIGIO); } return; } @@ -2026,7 +2027,7 @@ protected static function writeConnectionsStatisticsToStatusFile() . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n"; } if ($str) { - \file_put_contents(static::$_statisticsFile, $str, FILE_APPEND); + \file_put_contents(static::$_statisticsFile, $str, \FILE_APPEND); } } @@ -2040,11 +2041,11 @@ public static function checkErrors() if (static::STATUS_SHUTDOWN !== static::$_status) { $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); - if ($errors && ($errors['type'] === E_ERROR || - $errors['type'] === E_PARSE || - $errors['type'] === E_CORE_ERROR || - $errors['type'] === E_COMPILE_ERROR || - $errors['type'] === E_RECOVERABLE_ERROR) + if ($errors && ($errors['type'] === \E_ERROR || + $errors['type'] === \E_PARSE || + $errors['type'] === \E_CORE_ERROR || + $errors['type'] === \E_COMPILE_ERROR || + $errors['type'] === \E_RECOVERABLE_ERROR) ) { $error_msg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } @@ -2080,7 +2081,7 @@ public static function log($msg) static::safeEcho($msg); } \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' - . (static::$_OS === OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); + . (static::$_OS === OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); } /** @@ -2120,7 +2121,7 @@ public static function safeEcho($msg, $decorated = false) private static function outputStream($stream = null) { if (!$stream) { - $stream = static::$_outputStream ? static::$_outputStream : STDOUT; + $stream = static::$_outputStream ? static::$_outputStream : \STDOUT; } if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { return false; @@ -2157,7 +2158,7 @@ public function __construct($socket_name = '', array $context_option = array()) // Turn reusePort on. if (static::$_OS === OS_TYPE_LINUX // if linux - && version_compare(PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && strtolower(php_uname('s')) !== 'darwin') { // if not Mac OS $this->reusePort = true; @@ -2194,7 +2195,7 @@ public function listen() $local_socket = !empty($this->_localSocket) ? $this->_localSocket : $this->parseSocketAddress(); // Flag. - $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; + $flags = $this->transport === 'udp' ? \STREAM_SERVER_BIND : \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN; $errno = 0; $errmsg = ''; // SO_REUSEPORT. @@ -2213,10 +2214,10 @@ public function listen() } elseif ($this->transport === 'unix') { $socket_file = \substr($local_socket, 7); if ($this->user) { - chown($socket_file, $this->user); + \chown($socket_file, $this->user); } if ($this->group) { - chgrp($socket_file, $this->group); + \chgrp($socket_file, $this->group); } } @@ -2224,8 +2225,8 @@ public function listen() if (\function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { \set_error_handler(function(){}); $socket = \socket_import_stream($this->_mainSocket); - \socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); - \socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); + \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1); \restore_error_handler(); } @@ -2321,7 +2322,7 @@ public function resumeAccept() */ public function getSocketName() { - return $this->_socketName ? lcfirst($this->_socketName) : 'none'; + return $this->_socketName ? \lcfirst($this->_socketName) : 'none'; } /** @@ -2422,7 +2423,7 @@ public function acceptConnection($socket) { // Accept a connection on server socket. \set_error_handler(function(){}); - $new_socket = stream_socket_accept($socket, 0, $remote_address); + $new_socket = \stream_socket_accept($socket, 0, $remote_address); \restore_error_handler(); // Thundering herd. From dab3e3f1412e0fa4b6669ee8f218b9c888f64fdf Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 17 Oct 2019 09:39:07 +0800 Subject: [PATCH 0445/1216] close with code 1000 #473 #468 --- Protocols/Websocket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 1bbdf5abb..d5183cd75 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -102,7 +102,7 @@ public static function input($buffer, ConnectionInterface $connection) } } // Close connection. else { - $connection->close("\x88\x02\x27\x10", true); + $connection->close("\x88\x02\x03\xe8", true); } return 0; // Ping package. From 2da7be6834fbd5bd6bf35083c87074a3fdf9de66 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 17 Oct 2019 09:41:47 +0800 Subject: [PATCH 0446/1216] work with php5.3 --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index cd0918da0..3e5ba55f9 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -91,7 +91,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = } if ($args === null) { - $args = []; + $args = array(); } if (self::$_event) { From bef23d17ea03ae6b21b4e47997f40ed055319bb8 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 21 Oct 2019 10:28:40 +0800 Subject: [PATCH 0447/1216] Update Worker.php --- Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Worker.php b/Worker.php index 59f6bfe80..5788d2c87 100644 --- a/Worker.php +++ b/Worker.php @@ -2154,6 +2154,7 @@ public function __construct($socket_name = '', array $context_option = array()) // Get autoload root path. $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); + Autoloader::setRootPath($this->_autoloadRootPath); // Turn reusePort on. if (static::$_OS === OS_TYPE_LINUX // if linux From fc18226f98d10d039f7e2834d1a05cb5c33c9a99 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 21 Oct 2019 21:04:28 +0200 Subject: [PATCH 0448/1216] More fully qualified name --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 5d71a80f6..5c8615e07 100644 --- a/Worker.php +++ b/Worker.php @@ -2158,8 +2158,8 @@ public function __construct($socket_name = '', array $context_option = array()) // Turn reusePort on. if (static::$_OS === OS_TYPE_LINUX // if linux - && version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 - && strtolower(php_uname('s')) !== 'darwin') { // if not Mac OS + && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && \strtolower(\php_uname('s')) !== 'darwin') { // if not Mac OS $this->reusePort = true; } From 9be54d4d226a7c5c649c93f2d11bde9c16fe23ee Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 22 Oct 2019 14:22:35 +0200 Subject: [PATCH 0449/1216] Add to Autoloader --- Autoloader.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Autoloader.php b/Autoloader.php index 2a2e59e15..7d760e948 100644 --- a/Autoloader.php +++ b/Autoloader.php @@ -44,15 +44,15 @@ public static function setRootPath($root_path) */ public static function loadByNamespace($name) { - $class_path = \str_replace('\\', DIRECTORY_SEPARATOR, $name); + $class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name); if (\strpos($name, 'Workerman\\') === 0) { $class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php'; } else { if (self::$_autoloadRootPath) { - $class_file = self::$_autoloadRootPath . DIRECTORY_SEPARATOR . $class_path . '.php'; + $class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php'; } if (empty($class_file) || !\is_file($class_file)) { - $class_file = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . "$class_path.php"; + $class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php"; } } From 982ed696089cc7a71336f78592a9f21302c954fe Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 22 Oct 2019 14:23:11 +0200 Subject: [PATCH 0450/1216] Fully qualified add to use --- Connection/AsyncTcpConnection.php | 2 +- Connection/AsyncUdpConnection.php | 2 +- Connection/TcpConnection.php | 2 +- Events/Ev.php | 2 +- Lib/Timer.php | 2 +- Worker.php | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 8f2bc8e99..c0b45d022 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -16,7 +16,7 @@ use Workerman\Events\EventInterface; use Workerman\Lib\Timer; use Workerman\Worker; -use Exception; +use \Exception; /** * AsyncTcpConnection. diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 6c1116941..a572df3f3 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -15,7 +15,7 @@ use Workerman\Events\EventInterface; use Workerman\Worker; -use Exception; +use \Exception; /** * AsyncTcpConnection. diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 4e60a38ea..bd3a20c8f 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -15,7 +15,7 @@ use Workerman\Events\EventInterface; use Workerman\Worker; -use Exception; +use \Exception; /** * TcpConnection. diff --git a/Events/Ev.php b/Events/Ev.php index ee114ea07..8dba8606e 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -13,7 +13,7 @@ namespace Workerman\Events; use Workerman\Worker; -use EvWatcher; +use \EvWatcher; /** * ev eventloop diff --git a/Lib/Timer.php b/Lib/Timer.php index 44ee4edc8..2fde4d123 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -15,7 +15,7 @@ use Workerman\Events\EventInterface; use Workerman\Worker; -use Exception; +use \Exception; /** * Timer. diff --git a/Worker.php b/Worker.php index 5c8615e07..51cb2f115 100644 --- a/Worker.php +++ b/Worker.php @@ -20,7 +20,7 @@ use Workerman\Connection\UdpConnection; use Workerman\Lib\Timer; use Workerman\Events\Select; -use Exception; +use \Exception; /** * Worker class @@ -2153,7 +2153,7 @@ public function __construct($socket_name = '', array $context_option = array()) static::$_pidMap[$this->workerId] = array(); // Get autoload root path. - $backtrace = \debug_backtrace(); + $backtrace = \debug_backtrace(); $this->_autoloadRootPath = \dirname($backtrace[0]['file']); // Turn reusePort on. @@ -2275,7 +2275,7 @@ protected function parseSocketAddress() { } if (!isset(static::$_builtinTransports[$this->transport])) { - throw new \Exception('Bad worker->transport ' . \var_export($this->transport, true)); + throw new Exception('Bad worker->transport ' . \var_export($this->transport, true)); } } else { $this->transport = $scheme; From b0f3ae59537368c920ddad928e7948b8481ace49 Mon Sep 17 00:00:00 2001 From: Setsusan Date: Fri, 25 Oct 2019 11:19:22 +0700 Subject: [PATCH 0451/1216] fix for #466 (regression) --- Lib/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Timer.php b/Lib/Timer.php index 2fde4d123..1bd3419ad 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -50,7 +50,7 @@ class Timer * @param EventInterface $event * @return void */ - public static function init(EventInterface $event = null) + public static function init($event = null) { if ($event) { self::$_event = $event; From 14c416d845aa893482ee86eb07bc3998fa1a83d2 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 11:25:29 +0100 Subject: [PATCH 0452/1216] Lib/constants.php are in the global namespace --- Connection/AsyncTcpConnection.php | 4 ++-- Connection/TcpConnection.php | 4 ++-- Protocols/Websocket.php | 2 +- Protocols/Ws.php | 2 +- Worker.php | 32 +++++++++++++++---------------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index c0b45d022..b54a371ae 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -190,7 +190,7 @@ public function connect() } // If failed attempt to emit onError callback. if (!$this->_socket || !\is_resource($this->_socket)) { - $this->emitError(WORKERMAN_CONNECT_FAIL, $errstr); + $this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } @@ -360,7 +360,7 @@ public function checkConnection() } } else { // Connection failed. - $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); + $this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index bd3a20c8f..40d3ba2e0 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -385,7 +385,7 @@ public function send($send_buffer, $raw = false) self::$statistics['send_fail']++; if ($this->onError) { try { - \call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'client closed'); + \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -899,7 +899,7 @@ protected function bufferIsFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { - \call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index f349734d0..ad9d0ac92 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -261,7 +261,7 @@ public static function encode($buffer, ConnectionInterface $connection) if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - \call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 9f22d2e5e..7372187cb 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -262,7 +262,7 @@ public static function encode($payload, ConnectionInterface $connection) if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - \call_user_func($connection->onError, $connection, WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { Worker::log($e); exit(250); diff --git a/Worker.php b/Worker.php index e7ad511be..580998667 100644 --- a/Worker.php +++ b/Worker.php @@ -434,7 +434,7 @@ class Worker * * @var string */ - protected static $_OS = OS_TYPE_LINUX; + protected static $_OS = \OS_TYPE_LINUX; /** * Processes for windows. @@ -553,7 +553,7 @@ protected static function checkSapiEnv() exit("Only run in command line mode \n"); } if (\DIRECTORY_SEPARATOR === '\\') { - self::$_OS = OS_TYPE_WINDOWS; + self::$_OS = \OS_TYPE_WINDOWS; } } @@ -639,7 +639,7 @@ protected static function unlock() */ protected static function initWorkers() { - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { return; } foreach (static::$_workers as $worker) { @@ -744,7 +744,7 @@ protected static function displayUI() if (\in_array('-q', $argv)) { return; } - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); @@ -841,7 +841,7 @@ public static function getSingleLineTotalLength() */ protected static function parseCommand() { - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { return; } global $argv; @@ -1079,7 +1079,7 @@ protected static function formatStatusData() */ protected static function installSignal() { - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { return; } // stop @@ -1105,7 +1105,7 @@ protected static function installSignal() */ protected static function reinstallSignal() { - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { return; } // uninstall stop signal handler @@ -1181,7 +1181,7 @@ public static function signalHandler($signal) */ protected static function daemonize() { - if (!static::$daemonize || static::$_OS !== OS_TYPE_LINUX) { + if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) { return; } \umask(0); @@ -1210,7 +1210,7 @@ protected static function daemonize() */ public static function resetStd() { - if (!static::$daemonize || static::$_OS !== OS_TYPE_LINUX) { + if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) { return; } global $STDOUT, $STDERR; @@ -1241,7 +1241,7 @@ public static function resetStd() */ protected static function saveMasterPid() { - if (static::$_OS !== OS_TYPE_LINUX) { + if (static::$_OS !== \OS_TYPE_LINUX) { return; } @@ -1319,7 +1319,7 @@ protected static function getAllWorkerPids() */ protected static function forkWorkers() { - if (static::$_OS === OS_TYPE_LINUX) { + if (static::$_OS === \OS_TYPE_LINUX) { static::forkWorkersForLinux(); } else { static::forkWorkersForWindows(); @@ -1598,7 +1598,7 @@ protected static function setProcessTitle($title) */ protected static function monitorWorkers() { - if (static::$_OS === OS_TYPE_LINUX) { + if (static::$_OS === \OS_TYPE_LINUX) { static::monitorWorkersForLinux(); } else { static::monitorWorkersForWindows(); @@ -2039,7 +2039,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN !== static::$_status) { - $error_msg = static::$_OS === OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; + $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === \E_ERROR || $errors['type'] === \E_PARSE || @@ -2081,7 +2081,7 @@ public static function log($msg) static::safeEcho($msg); } \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' - . (static::$_OS === OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); + . (static::$_OS === \OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); } /** @@ -2132,7 +2132,7 @@ private static function outputStream($stream = null) static::$_outputDecorated = false; } else { static::$_outputDecorated = - static::$_OS === OS_TYPE_LINUX && + static::$_OS === \OS_TYPE_LINUX && \function_exists('posix_isatty') && \posix_isatty($stream); } @@ -2158,7 +2158,7 @@ public function __construct($socket_name = '', array $context_option = array()) Autoloader::setRootPath($this->_autoloadRootPath); // Turn reusePort on. - if (static::$_OS === OS_TYPE_LINUX // if linux + if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && \strtolower(\php_uname('s')) !== 'darwin') { // if not Mac OS From bcf4febc4ad5e2a49e7b3dbdbcfd3008aef3b264 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 11:25:52 +0100 Subject: [PATCH 0453/1216] Update stream_select --- Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index 81f347e20..175f871d6 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -274,7 +274,7 @@ public function loop() // Waiting read/write/signal/timeout events. \set_error_handler(function(){}); - $ret = stream_select($read, $write, $except, 0, $this->_selectTimeout); + $ret = \stream_select($read, $write, $except, 0, $this->_selectTimeout); \restore_error_handler(); From 0aa38df237e92271ea94b221959361756c6a4b01 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 11:26:43 +0100 Subject: [PATCH 0454/1216] Use const instead of define() const are defined at compile time, define() at runtime --- Lib/Constants.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 1b3561b11..253616264 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -23,13 +23,13 @@ } // For onError callback. -define('WORKERMAN_CONNECT_FAIL', 1); +const WORKERMAN_CONNECT_FAIL = 1; // For onError callback. -define('WORKERMAN_SEND_FAIL', 2); +const WORKERMAN_SEND_FAIL = 2; // Define OS Type -define('OS_TYPE_LINUX', 'linux'); -define('OS_TYPE_WINDOWS', 'windows'); +const OS_TYPE_LINUX = 'linux'; +const OS_TYPE_WINDOWS = 'windows'; // Compatible with php7 if(!class_exists('Error')) From 26e00a5fa2a501829fa4bc09eed7f6d65c08154b Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 11:48:34 +0100 Subject: [PATCH 0455/1216] Call the static function directly --- Worker.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Worker.php b/Worker.php index e7ad511be..69fc6b567 100644 --- a/Worker.php +++ b/Worker.php @@ -1083,17 +1083,17 @@ protected static function installSignal() return; } // stop - \pcntl_signal(\SIGINT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGINT, '\Workerman\Worker::signalHandler', false); // graceful stop - \pcntl_signal(\SIGTERM, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGTERM, '\Workerman\Worker::signalHandler', false); // reload - \pcntl_signal(\SIGUSR1, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGUSR1, '\Workerman\Worker::signalHandler', false); // graceful reload - \pcntl_signal(\SIGQUIT, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGQUIT, '\Workerman\Worker::signalHandler', false); // status - \pcntl_signal(\SIGUSR2, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGUSR2, '\Workerman\Worker::signalHandler', false); // connection status - \pcntl_signal(\SIGIO, array('\Workerman\Worker', 'signalHandler'), false); + \pcntl_signal(\SIGIO, '\Workerman\Worker::signalHandler', false); // ignore \pcntl_signal(\SIGPIPE, \SIG_IGN, false); } @@ -1121,17 +1121,17 @@ protected static function reinstallSignal() // uninstall connections status signal handler \pcntl_signal(\SIGIO, \SIG_IGN, false); // reinstall stop signal handler - static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); // reinstall reload signal handler - static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); // reinstall graceful reload signal handler - static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); // reinstall status signal handler - static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); // reinstall connection status signal handler - static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler')); + static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); } /** From 225cddb3d9e29c515878fc2b3121835021948f51 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 11:53:22 +0100 Subject: [PATCH 0456/1216] Unify handler --- Worker.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Worker.php b/Worker.php index 69fc6b567..6cf7f7cd6 100644 --- a/Worker.php +++ b/Worker.php @@ -1082,18 +1082,19 @@ protected static function installSignal() if (static::$_OS !== OS_TYPE_LINUX) { return; } + $signalHandler = '\Workerman\Worker::signalHandler'; // stop - \pcntl_signal(\SIGINT, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGINT, $signalHandler, false); // graceful stop - \pcntl_signal(\SIGTERM, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGTERM, $signalHandler, false); // reload - \pcntl_signal(\SIGUSR1, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGUSR1, $signalHandler, false); // graceful reload - \pcntl_signal(\SIGQUIT, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGQUIT, $signalHandler, false); // status - \pcntl_signal(\SIGUSR2, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGUSR2, $signalHandler, false); // connection status - \pcntl_signal(\SIGIO, '\Workerman\Worker::signalHandler', false); + \pcntl_signal(\SIGIO, $signalHandler, false); // ignore \pcntl_signal(\SIGPIPE, \SIG_IGN, false); } @@ -1108,6 +1109,7 @@ protected static function reinstallSignal() if (static::$_OS !== OS_TYPE_LINUX) { return; } + $signalHandler = '\Workerman\Worker::signalHandler'; // uninstall stop signal handler \pcntl_signal(\SIGINT, \SIG_IGN, false); // uninstall graceful stop signal handler @@ -1121,17 +1123,17 @@ protected static function reinstallSignal() // uninstall connections status signal handler \pcntl_signal(\SIGIO, \SIG_IGN, false); // reinstall stop signal handler - static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, $signalHandler); // reinstall reload signal handler - static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful reload signal handler - static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall status signal handler - static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); // reinstall connection status signal handler - static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, '\Workerman\Worker::signalHandler'); + static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler); } /** From ac0cd8147b8c79b301e720c021ae51ca8d6b75a1 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 27 Oct 2019 12:08:33 +0100 Subject: [PATCH 0457/1216] Clean Constants.php --- Lib/Constants.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 253616264..c95549da1 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -8,8 +8,9 @@ * * @author walkor * @copyright walkor - * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License + * + * @link http://www.workerman.net/ */ // Display errors. @@ -28,12 +29,11 @@ const WORKERMAN_SEND_FAIL = 2; // Define OS Type -const OS_TYPE_LINUX = 'linux'; +const OS_TYPE_LINUX = 'linux'; const OS_TYPE_WINDOWS = 'windows'; // Compatible with php7 -if(!class_exists('Error')) -{ +if ( ! class_exists('Error')) { class Error extends Exception { } From 91b7ab0dc09610ef9e2de3061f5e65b8ecbb4463 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 2 Nov 2019 13:30:22 +0100 Subject: [PATCH 0458/1216] Delete isset() that evaluate always to true --- Protocols/Http.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index df9b2ea76..b087ed06a 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -167,12 +167,12 @@ public static function decode($recv_buffer, TcpConnection $connection) break; } } - if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false){ + if($_SERVER['HTTP_ACCEPT_ENCODING'] && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false){ HttpCache::$gzip = true; } // Parse $_POST. if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_SERVER['CONTENT_TYPE'])) { + if ($_SERVER['CONTENT_TYPE']) { switch ($_SERVER['CONTENT_TYPE']) { case 'multipart/form-data': self::parseUploadFiles($http_body, $http_post_boundary); @@ -245,7 +245,7 @@ public static function encode($content, TcpConnection $connection) // other headers $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; - if(HttpCache::$gzip && isset($connection->gzip) && $connection->gzip){ + if(HttpCache::$gzip && isset($connection->gzip)){ $header .= "Content-Encoding: gzip\r\n"; $content = \gzencode($content,$connection->gzip); } From e350aa06df386053d62d2592a1cf2d4790b965ef Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 2 Nov 2019 13:58:46 +0100 Subject: [PATCH 0459/1216] Join validations --- Protocols/Http.php | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index b087ed06a..456b2a013 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -171,19 +171,17 @@ public static function decode($recv_buffer, TcpConnection $connection) HttpCache::$gzip = true; } // Parse $_POST. - if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if ($_SERVER['CONTENT_TYPE']) { - switch ($_SERVER['CONTENT_TYPE']) { - case 'multipart/form-data': - self::parseUploadFiles($http_body, $http_post_boundary); - break; - case 'application/json': - $_POST = \json_decode($http_body, true); - break; - case 'application/x-www-form-urlencoded': - \parse_str($http_body, $_POST); - break; - } + if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['CONTENT_TYPE']) { + switch ($_SERVER['CONTENT_TYPE']) { + case 'multipart/form-data': + self::parseUploadFiles($http_body, $http_post_boundary); + break; + case 'application/json': + $_POST = \json_decode($http_body, true); + break; + case 'application/x-www-form-urlencoded': + \parse_str($http_body, $_POST); + break; } } @@ -245,7 +243,7 @@ public static function encode($content, TcpConnection $connection) // other headers $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; - if(HttpCache::$gzip && isset($connection->gzip)){ + if(HttpCache::$gzip && isset($connection->gzip)) { $header .= "Content-Encoding: gzip\r\n"; $content = \gzencode($content,$connection->gzip); } From 615a4be368ac7f7a7289db57b523dbaaf8f64743 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Nov 2019 10:36:36 +0800 Subject: [PATCH 0460/1216] turn off reusePort for unix socket --- Worker.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Worker.php b/Worker.php index fe02ed078..c475135e6 100644 --- a/Worker.php +++ b/Worker.php @@ -2159,14 +2159,6 @@ public function __construct($socket_name = '', array $context_option = array()) $this->_autoloadRootPath = \dirname($backtrace[0]['file']); Autoloader::setRootPath($this->_autoloadRootPath); - // Turn reusePort on. - if (static::$_OS === \OS_TYPE_LINUX // if linux - && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 - && \strtolower(\php_uname('s')) !== 'darwin') { // if not Mac OS - - $this->reusePort = true; - } - // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; @@ -2176,6 +2168,15 @@ public function __construct($socket_name = '', array $context_option = array()) } $this->_context = \stream_context_create($context_option); } + + // Turn reusePort on. + if (static::$_OS === \OS_TYPE_LINUX // if linux + && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS + && $this->transport != 'unix') { // if not unix socket + + $this->reusePort = true; + } } From e21c3c403d49f58182c5cb8ac31ea9d10f6c350d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 6 Nov 2019 11:06:51 +0800 Subject: [PATCH 0461/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c475135e6..4da0d82d5 100644 --- a/Worker.php +++ b/Worker.php @@ -2173,7 +2173,7 @@ public function __construct($socket_name = '', array $context_option = array()) if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && $this->transport != 'unix') { // if not unix socket + && $this->transport !== 'unix') { // if not unix socket $this->reusePort = true; } From 24165c7385090759899b53b9ff3812038b848a35 Mon Sep 17 00:00:00 2001 From: wangguoqing Date: Fri, 8 Nov 2019 15:33:53 +0800 Subject: [PATCH 0462/1216] Text Protocol support udp --- Protocols/Text.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Protocols/Text.php b/Protocols/Text.php index 8d6b2ec93..407ea2d1b 100644 --- a/Protocols/Text.php +++ b/Protocols/Text.php @@ -13,7 +13,7 @@ */ namespace Workerman\Protocols; -use Workerman\Connection\TcpConnection; +use Workerman\Connection\ConnectionInterface; /** * Text Protocol. @@ -24,13 +24,13 @@ class Text * Check the integrity of the package. * * @param string $buffer - * @param TcpConnection $connection + * @param ConnectionInterface $connection * @return int */ - public static function input($buffer, TcpConnection $connection) + public static function input($buffer, ConnectionInterface $connection) { // Judge whether the package length exceeds the limit. - if (\strlen($buffer) >= $connection->maxPackageSize) { + if (isset($connection->maxPackageSize) && \strlen($buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } @@ -67,4 +67,4 @@ public static function decode($buffer) // Remove "\n" return \rtrim($buffer, "\r\n"); } -} +} \ No newline at end of file From a29627168ae4c3ada957c6065df419aafe52bef7 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 11 Nov 2019 13:52:15 +0100 Subject: [PATCH 0463/1216] Use preincremet --- Connection/AsyncTcpConnection.php | 2 +- Connection/AsyncUdpConnection.php | 2 +- Connection/TcpConnection.php | 18 +++++++++--------- Protocols/Http.php | 4 ++-- Worker.php | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index b54a371ae..9b03904c1 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -155,7 +155,7 @@ public function __construct($remote_address, array $context_option = array()) } // For statistics. - self::$statistics['connection_count']++; + ++self::$statistics['connection_count']; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->_contextOption = $context_option; static::$connections[$this->_id] = $this; diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index a572df3f3..7df93ad12 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -94,7 +94,7 @@ public function baseRead($socket) $parser = $this->protocol; $recv_buffer = $parser::decode($recv_buffer, $this); } - ConnectionInterface::$statistics['total_request']++; + ++ConnectionInterface::$statistics['total_request']; try { \call_user_func($this->onMessage, $this, $recv_buffer); } catch (\Exception $e) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 40d3ba2e0..a5afbd1d8 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -292,7 +292,7 @@ public function __call($name, array $arguments) { */ public function __construct($socket, $remote_address = '') { - self::$statistics['connection_count']++; + ++self::$statistics['connection_count']; $this->id = $this->_id = self::$_idRecorder++; if(self::$_idRecorder === \PHP_INT_MAX){ self::$_idRecorder = 0; @@ -351,7 +351,7 @@ public function send($send_buffer, $raw = false) ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) ) { if ($this->_sendBuffer && $this->bufferIsFull()) { - self::$statistics['send_fail']++; + ++self::$statistics['send_fail']; return false; } $this->_sendBuffer .= $send_buffer; @@ -382,7 +382,7 @@ public function send($send_buffer, $raw = false) } else { // Connection closed? if (!\is_resource($this->_socket) || \feof($this->_socket)) { - self::$statistics['send_fail']++; + ++self::$statistics['send_fail']; if ($this->onError) { try { \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); @@ -406,7 +406,7 @@ public function send($send_buffer, $raw = false) } if ($this->bufferIsFull()) { - self::$statistics['send_fail']++; + ++self::$statistics['send_fail']; return false; } @@ -424,7 +424,7 @@ public function getRemoteIp() { $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return \substr($this->_remoteAddress, 0, $pos); + return (string) \substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -437,7 +437,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); + return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -635,7 +635,7 @@ public function baseRead($socket, $check_eof = true) } // The data is enough for a packet. - self::$statistics['total_request']++; + ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; @@ -670,7 +670,7 @@ public function baseRead($socket, $check_eof = true) } // Applications protocol is not set. - self::$statistics['total_request']++; + ++self::$statistics['total_request']; if (!$this->onMessage) { $this->_recvBuffer = ''; return; @@ -727,7 +727,7 @@ public function baseWrite() $this->bytesWritten += $len; $this->_sendBuffer = \substr($this->_sendBuffer, $len); } else { - self::$statistics['send_fail']++; + ++self::$statistics['send_fail']; $this->destroy(); } } diff --git a/Protocols/Http.php b/Protocols/Http.php index 456b2a013..895e67014 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -278,7 +278,7 @@ public static function header($content, $replace = true, $http_response_code = n return true; } - $key = \strstr($content, ":", true); + $key = \strstr($content, ':', true); if (empty($key)) { return false; } @@ -420,7 +420,7 @@ public static function sessionName($name = null) * * @param string $path * - * @return void + * @return string */ public static function sessionSavePath($path = null) { diff --git a/Worker.php b/Worker.php index 4da0d82d5..394873df2 100644 --- a/Worker.php +++ b/Worker.php @@ -1638,7 +1638,7 @@ protected static function monitorWorkersForLinux() if (!isset(static::$_globalStatistics['worker_exit_info'][$worker_id][$status])) { static::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0; } - static::$_globalStatistics['worker_exit_info'][$worker_id][$status]++; + ++static::$_globalStatistics['worker_exit_info'][$worker_id][$status]; // Clear process data. unset(static::$_pidMap[$worker_id][$pid]); @@ -2505,7 +2505,7 @@ public function acceptUdpConnection($socket) }else{ \call_user_func($this->onMessage, $connection, $recv_buffer); } - ConnectionInterface::$statistics['total_request']++; + ++ConnectionInterface::$statistics['total_request']; } catch (\Exception $e) { static::log($e); exit(250); From e287f99fde20a8a486399f77b064f06b23377171 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 21 Nov 2019 10:07:20 +0800 Subject: [PATCH 0464/1216] JIT is not stable, temporarily disabled. #452 --- Lib/Constants.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/Constants.php b/Lib/Constants.php index c95549da1..20821cd89 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -17,6 +17,8 @@ ini_set('display_errors', 'on'); // Reporting all. error_reporting(E_ALL); +// JIT is not stable, temporarily disabled. +ini_set('pcre.jit', 0); // Reset opcache. if (function_exists('opcache_reset')) { From 8efcc3ed19a26910d03cc5ffd49a3ec781ec32e5 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Fri, 22 Nov 2019 15:57:24 +0800 Subject: [PATCH 0465/1216] support reloading all worker instances gracefully when new start scripts added --- Worker.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 394873df2..55fa3bd39 100644 --- a/Worker.php +++ b/Worker.php @@ -678,6 +678,19 @@ protected static function initWorkers() } } + /** + * Reload all worker instances. + * + * @return void + */ + public static function reloadAllWorkers() + { + static::init(); + static::initWorkers(); + static::displayUI(); + static::$_status = static::STATUS_RELOADING; + } + /** * Get all worker instances. * @@ -697,7 +710,7 @@ public static function getEventLoop() { return static::$globalEvent; } - + /** * Get main socket resource * @return resource From f7e476156a23dcf7bd49cc3b1bfe4eed8b9103c2 Mon Sep 17 00:00:00 2001 From: ChrisLi0329 <39633377+ChrisLi0329@users.noreply.github.com> Date: Mon, 25 Nov 2019 16:03:24 -0800 Subject: [PATCH 0466/1216] Fix errors in README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 33869e560..2aac0f2b0 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ [![License](https://poser.pugx.org/workerman/workerman/license)](https://packagist.org/packages/workerman/workerman) ## What is it -Workerman is an asynchronous event driven PHP framework with high performance for easily building fast, scalable network applications. Supports HTTP, Websocket, SSL and other custom protocols. Supports libevent/event extension, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). +Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. +Workerman supports HTTP, Websocket, SSL and other custom protocols. +Workerman supports libevent/event extension, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). ## Requires PHP 5.3 or Higher From 5eb1b14f237f9cb0068cdb8324189c437379fd7b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 23 Dec 2019 13:05:39 +0800 Subject: [PATCH 0467/1216] Update Select.php --- Events/Select.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 175f871d6..8a9bc3821 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -272,10 +272,15 @@ public function loop() $write = $this->_writeFds; $except = $this->_exceptFds; - // Waiting read/write/signal/timeout events. - \set_error_handler(function(){}); - $ret = \stream_select($read, $write, $except, 0, $this->_selectTimeout); - \restore_error_handler(); + if ($read || $write || $except) { + // Waiting read/write/signal/timeout events. + set_error_handler(function(){}); + $ret = stream_select($read, $write, $except, 0, $this->_selectTimeout); + restore_error_handler(); + } else { + usleep($this->_selectTimeout); + $ret = false; + } if (!$this->_scheduler->isEmpty()) { From 416f864e4815bc8b1475793056520db4543e4455 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 23 Dec 2019 13:06:17 +0800 Subject: [PATCH 0468/1216] Update Select.php --- Events/Select.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 8a9bc3821..1939ed306 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -95,13 +95,6 @@ class Select implements EventInterface */ public function __construct() { - // Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling. - $this->channel = \stream_socket_pair(\DIRECTORY_SEPARATOR === '/' ? \STREAM_PF_UNIX : \STREAM_PF_INET, - \STREAM_SOCK_STREAM, \STREAM_IPPROTO_IP); - if($this->channel) { - \stream_set_blocking($this->channel[0], 0); - $this->_readFds[0] = $this->channel[0]; - } // Init SplPriorityQueue. $this->_scheduler = new \SplPriorityQueue(); $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); From 9e2a85e7e939cb234e1ae0c14773754ae8011abf Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Jan 2020 22:36:15 +0800 Subject: [PATCH 0469/1216] Update Worker.php --- Worker.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 55fa3bd39..74ac9b93d 100644 --- a/Worker.php +++ b/Worker.php @@ -615,7 +615,7 @@ protected static function init() protected static function lock() { $fd = \fopen(static::$_startFile, 'r'); - if (!$fd || !flock($fd, LOCK_EX)) { + if ($fd && !flock($fd, LOCK_EX)) { static::log('Workerman['.static::$_startFile.'] already running.'); exit; } @@ -2142,6 +2142,9 @@ private static function outputStream($stream = null) return false; } $stat = \fstat($stream); + if (!$stat) { + return false; + } if (($stat['mode'] & 0170000) === 0100000) { // file static::$_outputDecorated = false; From 058cd3eada3d4b302e903a09a7d3ce94e6a1fca2 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Jan 2020 22:36:47 +0800 Subject: [PATCH 0470/1216] v3.5.24 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 74ac9b93d..540cd7673 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.23'; + const VERSION = '3.5.24'; /** * Status starting. From 1e93403e5795924e15d21cd29470fe36902d220d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 8 Jan 2020 15:36:52 +0800 Subject: [PATCH 0471/1216] v3.5.25 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 540cd7673..55bfc0e40 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.24'; + const VERSION = '3.5.25'; /** * Status starting. From ebaf40ef203e4396d7421ffe1960cd91e8f57bb3 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sun, 12 Jan 2020 04:22:33 +0800 Subject: [PATCH 0472/1216] discard calling Worker property $_localSocket which may cause unexpected problem --- Worker.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 55bfc0e40..756789076 100644 --- a/Worker.php +++ b/Worker.php @@ -2178,7 +2178,6 @@ public function __construct($socket_name = '', array $context_option = array()) // Context for socket. if ($socket_name) { $this->_socketName = $socket_name; - $this->_localSocket = $this->parseSocketAddress(); if (!isset($context_option['socket']['backlog'])) { $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } @@ -2212,7 +2211,7 @@ public function listen() if (!$this->_mainSocket) { - $local_socket = !empty($this->_localSocket) ? $this->_localSocket : $this->parseSocketAddress(); + $local_socket = $this->parseSocketAddress(); // Flag. $flags = $this->transport === 'udp' ? \STREAM_SERVER_BIND : \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN; From 0b59a11f0fd66f95c795895d199ca10fbbf37ec8 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Jan 2020 14:54:59 +0800 Subject: [PATCH 0473/1216] performance optimization --- Protocols/Http.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 895e67014..f99fa3b89 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -28,6 +28,12 @@ class Http */ public static $methods = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'); + /** + * Cache. + * @var array + */ + protected static $_cache = []; + /** * Check the integrity of the package. * @@ -85,11 +91,25 @@ protected static function getRequestSize($header, $method) */ public static function decode($recv_buffer, TcpConnection $connection) { + $md5 = md5($recv_buffer); + if (isset(static::$_cache[$md5])) { + $cache = static::$_cache[$md5]; + $cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); + $cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; + $_SERVER = $cache['server']; + $_POST = $cache['post']; + $_GET = $cache['get']; + $_COOKIE = $cache['cookie']; + $_REQUEST = $cache['request']; + $GLOBALS['HTTP_RAW_POST_DATA'] = $GLOBALS['HTTP_RAW_REQUEST_DATA'] = ''; + return static::$_cache[$md5]; + } // Init. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. HttpCache::reset(); + $microtime = \microtime(true); // $_SERVER $_SERVER = array( 'QUERY_STRING' => '', @@ -108,8 +128,8 @@ public static function decode($recv_buffer, TcpConnection $connection) 'CONTENT_TYPE' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', - 'REQUEST_TIME' => \time(), - 'REQUEST_TIME_FLOAT' => \microtime(true) //compatible php5.4 + 'REQUEST_TIME' => (int)$microtime, + 'REQUEST_TIME_FLOAT' => $microtime //compatible php5.4 ); // Parse headers. @@ -219,8 +239,15 @@ public static function decode($recv_buffer, TcpConnection $connection) // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); + $ret = array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES, 'request'=>$_REQUEST); + if ($_SERVER['REQUEST_METHOD'] === 'GET') { + static::$_cache[$md5] = $ret; + if (\count(static::$_cache) > 256) { + \array_shift(static::$_cache); + } + } - return array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES); + return $ret; } /** From 135f420399bb71c6fcc3bdbd4d21400a845ce9c0 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 25 Jan 2020 18:28:23 +0800 Subject: [PATCH 0474/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 756789076..181b990fd 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.25'; + const VERSION = '3.5.26'; /** * Status starting. From 479578ef3e29ad485e1d5f43d223c8994a50031f Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 25 Jan 2020 22:57:24 +0800 Subject: [PATCH 0475/1216] optimization --- Connection/TcpConnection.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index a5afbd1d8..af394ed7c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -601,6 +601,7 @@ public function baseRead($socket, $check_eof = true) $this->_recvBuffer .= $buffer; } + $recv_len = \strlen($this->_recvBuffer); // If the application layer protocol has been set up. if ($this->protocol !== null) { $parser = $this->protocol; @@ -608,7 +609,7 @@ public function baseRead($socket, $check_eof = true) // The current packet length is known. if ($this->_currentPackageLength) { // Data is not enough for a package. - if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { + if ($this->_currentPackageLength > $recv_len) { break; } } else { @@ -623,7 +624,7 @@ public function baseRead($socket, $check_eof = true) break; } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. - if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { + if ($this->_currentPackageLength > $recv_len) { break; } } // Wrong package. @@ -637,7 +638,7 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { + if ($recv_len === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; $this->_recvBuffer = ''; } else { From eb917d10bf5dab49e876644b256334f610482649 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 00:05:08 +0800 Subject: [PATCH 0476/1216] Update Http.php --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index f99fa3b89..9398cfac5 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -243,7 +243,7 @@ public static function decode($recv_buffer, TcpConnection $connection) if ($_SERVER['REQUEST_METHOD'] === 'GET') { static::$_cache[$md5] = $ret; if (\count(static::$_cache) > 256) { - \array_shift(static::$_cache); + unset(static::$_cache[key(static::$_cache)]); } } From 85d6a802b75abf8306204571e9c38be870bc5780 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 00:17:17 +0800 Subject: [PATCH 0477/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 181b990fd..c18754dc5 100644 --- a/Worker.php +++ b/Worker.php @@ -1019,7 +1019,7 @@ protected static function formatStatusData() } $status_str = ''; $current_total_request = array(); - $worker_info = \json_decode($info[0], true); + $worker_info = \unserialize($info[0]); \ksort($worker_info, SORT_NUMERIC); unset($info[0]); $data_waiting_sort = array(); @@ -1906,7 +1906,7 @@ protected static function writeStatisticsToStatusFile() } } - \file_put_contents(static::$_statisticsFile, \json_encode($all_worker_info)."\n", \FILE_APPEND); + \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2)) : array('-', '-', '-'); \file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); From e8f8b7a7c2b6ffc3b8e22b14eb2e31c82e1934d6 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 16:28:03 +0800 Subject: [PATCH 0478/1216] ssl default port 443 --- Connection/AsyncTcpConnection.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9b03904c1..744b7aa56 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -119,7 +119,7 @@ public function __construct($remote_address, array $context_option = array()) } } else { if (!isset($address_info['port'])) { - $address_info['port'] = 80; + $address_info['port'] = 0; } if (!isset($address_info['path'])) { $address_info['path'] = '/'; @@ -175,6 +175,10 @@ public function connect() $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = \microtime(true); if ($this->transport !== 'unix') { + if (!$this->_remotePort) { + $this->_remotePort = $this->transport === 'ssl' ? 443 : 80; + $this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort; + } // Open socket connection asynchronously. if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); From 8f42b90074e86ddc73214829e19e64d2b5ed6f27 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 18:05:09 +0800 Subject: [PATCH 0479/1216] Update Http.php --- Protocols/Http.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 9398cfac5..5947b224d 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -93,6 +93,7 @@ public static function decode($recv_buffer, TcpConnection $connection) { $md5 = md5($recv_buffer); if (isset(static::$_cache[$md5])) { + HttpCache::reset(); $cache = static::$_cache[$md5]; $cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); $cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; From 638f6345c7b6064c5e49eb497c2e056192f7e8dc Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 19:33:58 +0800 Subject: [PATCH 0480/1216] Update Http.php --- Protocols/Http.php | 63 +++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 5947b224d..da6acf031 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -26,7 +26,7 @@ class Http * The supported HTTP methods * @var array */ - public static $methods = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'); + public static $methods = array('GET'=>'GET', 'POST'=>'POST', 'PUT'=>'PUT', 'DELETE'=>'DELETE', 'HEAD'=>'HEAD', 'OPTIONS'=>'OPTIONS'); /** * Cache. @@ -43,43 +43,34 @@ class Http */ public static function input($recv_buffer, TcpConnection $connection) { - if (!\strpos($recv_buffer, "\r\n\r\n")) { + $recv_len = \strlen($recv_buffer); + $crlf_post = \strpos($recv_buffer, "\r\n\r\n"); + if (!$crlf_post) { // Judge whether the package length exceeds the limit. - if (\strlen($recv_buffer) >= $connection->maxPackageSize) { + if ($recv_len >= $connection->maxPackageSize) { $connection->close(); } return 0; } - list($header,) = \explode("\r\n\r\n", $recv_buffer, 2); - $method = \substr($header, 0, \strpos($header, ' ')); - - if(\in_array($method, static::$methods)) { - return static::getRequestSize($header, $method); + $method = \substr($recv_buffer, 0, \strpos($recv_buffer, ' ')); + if (!isset(static::$methods[$method])) { + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); + $connection->consumeRecvBuffer($recv_len); + return 0; } - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); - return 0; - } - - /** - * Get whole size of the request - * includes the request headers and request body. - * @param string $header The request headers - * @param string $method The request method - * @return integer - */ - protected static function getRequestSize($header, $method) - { - if($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { - return \strlen($header) + 4; + if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { + return $recv_len; } + $match = array(); - if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) { + if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $recv_buffer, $match)) { $content_length = isset($match[1]) ? $match[1] : 0; - return $content_length + \strlen($header) + 4; + return $content_length + $crlf_post + 4; } - return $method === 'DELETE' ? \strlen($header) + 4 : 0; + + return $method === 'DELETE' ? $recv_len : 0; } /** @@ -188,9 +179,7 @@ public static function decode($recv_buffer, TcpConnection $connection) break; } } - if($_SERVER['HTTP_ACCEPT_ENCODING'] && \strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false){ - HttpCache::$gzip = true; - } + // Parse $_POST. if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['CONTENT_TYPE']) { switch ($_SERVER['CONTENT_TYPE']) { @@ -269,11 +258,13 @@ public static function encode($content, TcpConnection $connection) } // other headers - $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; + if (HttpCache::$header) { + $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; + } - if(HttpCache::$gzip && isset($connection->gzip)) { - $header .= "Content-Encoding: gzip\r\n"; - $content = \gzencode($content,$connection->gzip); + if(!empty($connection->gzip)) { + $header .= "Content-Encoding: gzip\r\n"; + $content = \gzencode($content,$connection->gzip); } // header $header .= 'Content-Length: ' . \strlen($content) . "\r\n\r\n"; @@ -707,7 +698,6 @@ class HttpCache public static $status = ''; public static $header = array(); public static $cookie = array(); - public static $gzip = false; public static $sessionPath = ''; public static $sessionName = ''; public static $sessionGcProbability = 1; @@ -721,7 +711,8 @@ public static function reset() self::$status = 'HTTP/1.1 200 OK'; self::$header = self::$default; self::$cookie = array(); - self::$instance = new HttpCache(); + self::$instance->sessionFile = ''; + self::$instance->sessionStarted = false; } public static function init() @@ -749,6 +740,8 @@ public static function init() if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { self::$sessionGcMaxLifeTime = $gc_max_life_time; } + + self::$instance = new HttpCache(); } } From f63892c1c9de31de11b5679cae7a7252e1802d31 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 20:13:38 +0800 Subject: [PATCH 0481/1216] performance optimization --- Protocols/Http.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index da6acf031..a23e37df1 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -82,26 +82,25 @@ public static function input($recv_buffer, TcpConnection $connection) */ public static function decode($recv_buffer, TcpConnection $connection) { - $md5 = md5($recv_buffer); - if (isset(static::$_cache[$md5])) { + if (isset(static::$_cache[$recv_buffer])) { HttpCache::reset(); - $cache = static::$_cache[$md5]; - $cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); - $cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; + $cache = static::$_cache[$recv_buffer]; + //$cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); + //$cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; $_SERVER = $cache['server']; $_POST = $cache['post']; $_GET = $cache['get']; $_COOKIE = $cache['cookie']; $_REQUEST = $cache['request']; $GLOBALS['HTTP_RAW_POST_DATA'] = $GLOBALS['HTTP_RAW_REQUEST_DATA'] = ''; - return static::$_cache[$md5]; + return static::$_cache[$recv_buffer]; } // Init. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. HttpCache::reset(); - $microtime = \microtime(true); + //$microtime = \microtime(true); // $_SERVER $_SERVER = array( 'QUERY_STRING' => '', @@ -120,8 +119,8 @@ public static function decode($recv_buffer, TcpConnection $connection) 'CONTENT_TYPE' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', - 'REQUEST_TIME' => (int)$microtime, - 'REQUEST_TIME_FLOAT' => $microtime //compatible php5.4 + //'REQUEST_TIME' => (int)$microtime, + //'REQUEST_TIME_FLOAT' => $microtime //compatible php5.4 ); // Parse headers. @@ -231,7 +230,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); $ret = array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES, 'request'=>$_REQUEST); if ($_SERVER['REQUEST_METHOD'] === 'GET') { - static::$_cache[$md5] = $ret; + static::$_cache[$recv_buffer] = $ret; if (\count(static::$_cache) > 256) { unset(static::$_cache[key(static::$_cache)]); } From 62e53d3f8da7c9baad2c7a54a8a1dfcdb611625e Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 26 Jan 2020 22:09:54 +0800 Subject: [PATCH 0482/1216] performance optimization --- Protocols/Http.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index a23e37df1..4fabe3a4c 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -43,6 +43,9 @@ class Http */ public static function input($recv_buffer, TcpConnection $connection) { + if (isset(static::$_cache[$recv_buffer]['input'])) { + return static::$_cache[$recv_buffer]['input']; + } $recv_len = \strlen($recv_buffer); $crlf_post = \strpos($recv_buffer, "\r\n\r\n"); if (!$crlf_post) { @@ -61,13 +64,16 @@ public static function input($recv_buffer, TcpConnection $connection) } if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { + static::$_cache[$recv_buffer]['input'] = $recv_len; return $recv_len; } $match = array(); if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $recv_buffer, $match)) { $content_length = isset($match[1]) ? $match[1] : 0; - return $content_length + $crlf_post + 4; + $total_length = $content_length + $crlf_post + 4; + static::$_cache[$recv_buffer]['input'] = $total_length; + return $total_length; } return $method === 'DELETE' ? $recv_len : 0; @@ -82,9 +88,9 @@ public static function input($recv_buffer, TcpConnection $connection) */ public static function decode($recv_buffer, TcpConnection $connection) { - if (isset(static::$_cache[$recv_buffer])) { + if (isset(static::$_cache[$recv_buffer]['decode'])) { HttpCache::reset(); - $cache = static::$_cache[$recv_buffer]; + $cache = static::$_cache[$recv_buffer]['decode']; //$cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); //$cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; $_SERVER = $cache['server']; @@ -93,7 +99,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_COOKIE = $cache['cookie']; $_REQUEST = $cache['request']; $GLOBALS['HTTP_RAW_POST_DATA'] = $GLOBALS['HTTP_RAW_REQUEST_DATA'] = ''; - return static::$_cache[$recv_buffer]; + return static::$_cache[$recv_buffer]['decode']; } // Init. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); @@ -230,7 +236,7 @@ public static function decode($recv_buffer, TcpConnection $connection) $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); $ret = array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES, 'request'=>$_REQUEST); if ($_SERVER['REQUEST_METHOD'] === 'GET') { - static::$_cache[$recv_buffer] = $ret; + static::$_cache[$recv_buffer]['decode'] = $ret; if (\count(static::$_cache) > 256) { unset(static::$_cache[key(static::$_cache)]); } From 1d1e184a5a6f1a84570dec6cfe9558d4657c0fa3 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 31 Jan 2020 12:57:41 +0800 Subject: [PATCH 0483/1216] version 3.5.27 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c18754dc5..65c881bbf 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.26'; + const VERSION = '3.5.27'; /** * Status starting. From c2d8c332cc58400345b68593584a5f8171446a5e Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 31 Jan 2020 13:05:18 +0800 Subject: [PATCH 0484/1216] Update Http.php --- Protocols/Http.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 4fabe3a4c..7a8f605b7 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -55,6 +55,7 @@ public static function input($recv_buffer, TcpConnection $connection) } return 0; } + $head_len = $crlf_post + 4; $method = \substr($recv_buffer, 0, \strpos($recv_buffer, ' ')); if (!isset(static::$methods[$method])) { @@ -64,19 +65,19 @@ public static function input($recv_buffer, TcpConnection $connection) } if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { - static::$_cache[$recv_buffer]['input'] = $recv_len; - return $recv_len; + static::$_cache[$recv_buffer]['input'] = $head_len; + return $head_len; } $match = array(); if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $recv_buffer, $match)) { $content_length = isset($match[1]) ? $match[1] : 0; - $total_length = $content_length + $crlf_post + 4; + $total_length = $content_length + $head_len; static::$_cache[$recv_buffer]['input'] = $total_length; return $total_length; } - return $method === 'DELETE' ? $recv_len : 0; + return $method === 'DELETE' ? $head_len : 0; } /** From 0ac3c84653364faeae5a5f7057d89e31e26d11f6 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 5 Feb 2020 10:23:36 +0800 Subject: [PATCH 0485/1216] support php5.3 --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 7a8f605b7..0cb5b2170 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -32,7 +32,7 @@ class Http * Cache. * @var array */ - protected static $_cache = []; + protected static $_cache = array(); /** * Check the integrity of the package. From 0bf353821d35a037f59ef3073721a858a950b0af Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 18 Feb 2020 20:40:16 +0800 Subject: [PATCH 0486/1216] Update Constants.php --- Lib/Constants.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index 20821cd89..1990b3824 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -20,11 +20,6 @@ // JIT is not stable, temporarily disabled. ini_set('pcre.jit', 0); -// Reset opcache. -if (function_exists('opcache_reset')) { - opcache_reset(); -} - // For onError callback. const WORKERMAN_CONNECT_FAIL = 1; // For onError callback. From c7373d0b663226c42a2f43ed0cd9891b31c5422c Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 24 Feb 2020 20:03:48 +0800 Subject: [PATCH 0487/1216] fix #517 fix #517 --- Connection/AsyncTcpConnection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 744b7aa56..1ee66fc4c 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -157,6 +157,7 @@ public function __construct($remote_address, array $context_option = array()) // For statistics. ++self::$statistics['connection_count']; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; $this->_contextOption = $context_option; static::$connections[$this->_id] = $this; } From db83b7db2601dac2829ff4949ff87f5ae422e6c7 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 24 Feb 2020 20:19:22 +0800 Subject: [PATCH 0488/1216] 3.5.28 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 65c881bbf..2cc809c89 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.27'; + const VERSION = '3.5.28'; /** * Status starting. From a00fa00ae425bec0575982cdbb4e9acb7c183a9b Mon Sep 17 00:00:00 2001 From: Abdullah AlShammari Date: Wed, 26 Feb 2020 22:13:41 +0300 Subject: [PATCH 0489/1216] Add a new static member called processTitle to allow changing default process title --- Worker.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Worker.php b/Worker.php index 2cc809c89..695a4d952 100644 --- a/Worker.php +++ b/Worker.php @@ -300,6 +300,13 @@ class Worker */ public static $eventLoopClass = ''; + /** + * Process title + * + * @var string + */ + public static $processTitle = 'WorkerMan'; + /** * The PID of master process. * @@ -461,7 +468,7 @@ class Worker protected static $_availableEventLoops = array( 'libevent' => '\Workerman\Events\Libevent', 'event' => '\Workerman\Events\Event' - // Temporarily removed swoole because it is not stable enough + // Temporarily removed swoole because it is not stable enough //'swoole' => '\Workerman\Events\Swoole' ); @@ -598,7 +605,7 @@ protected static function init() static::$_statisticsFile = \sys_get_temp_dir() . "/$unique_prefix.status"; // Process title. - static::setProcessTitle('WorkerMan: master process start_file=' . static::$_startFile); + static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$_startFile); // Init data for worker id. static::initId(); @@ -678,18 +685,18 @@ protected static function initWorkers() } } - /** + /** * Reload all worker instances. * * @return void */ public static function reloadAllWorkers() - { + { static::init(); static::initWorkers(); static::displayUI(); static::$_status = static::STATUS_RELOADING; - } + } /** * Get all worker instances. @@ -777,7 +784,7 @@ protected static function displayUI() $title = ''; foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - //just keep compatible with listen name + //just keep compatible with listen name $column_name === 'socket' && $column_name = 'listen'; $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); } @@ -1280,7 +1287,7 @@ protected static function getEventLoopName() if (!\class_exists('\Swoole\Event', false)) { unset(static::$_availableEventLoops['swoole']); } - + $loop_name = ''; foreach (static::$_availableEventLoops as $name=>$class) { if (\extension_loaded($name)) { @@ -1528,7 +1535,7 @@ protected static function forkOneWorkerForLinux(self $worker) } } Timer::delAll(); - static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); + static::setProcessTitle(self::$processTitle . ': worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); @@ -2183,7 +2190,7 @@ public function __construct($socket_name = '', array $context_option = array()) } $this->_context = \stream_context_create($context_option); } - + // Turn reusePort on. if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 @@ -2379,7 +2386,7 @@ public function run() } \restore_error_handler(); - + // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { From 859d7a2f9091bd14a55f8e4547dc0d14045b62de Mon Sep 17 00:00:00 2001 From: hk <764432054@qq.com> Date: Tue, 3 Mar 2020 23:32:51 +0800 Subject: [PATCH 0490/1216] comment spell error --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 695a4d952..532733262 100644 --- a/Worker.php +++ b/Worker.php @@ -1645,7 +1645,7 @@ protected static function monitorWorkersForLinux() \pcntl_signal_dispatch(); // If a child has already exited. if ($pid > 0) { - // Find out witch worker process exited. + // Find out which worker process exited. foreach (static::$_pidMap as $worker_id => $worker_pid_array) { if (isset($worker_pid_array[$pid])) { $worker = static::$_workers[$worker_id]; From ad7b0e7d37d8f2cfda2e95663a4f548e09669f00 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Mar 2020 19:07:19 +0800 Subject: [PATCH 0491/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index af394ed7c..e1c61a8b6 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -646,6 +646,7 @@ public function baseRead($socket, $check_eof = true) $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); // Remove the current package from the receive buffer. $this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength); + $recv_len = \strlen($this->_recvBuffer); } // Reset the current packet length to 0. $this->_currentPackageLength = 0; From eaf533eaa82f7f0237aa1d5502c6d0bced0919f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Mar 2020 19:08:04 +0800 Subject: [PATCH 0492/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 532733262..124ce82c8 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.28'; + const VERSION = '3.5.29'; /** * Status starting. From 8ad4acc5851e470cbd6ec96e6f804a004eea251b Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Mar 2020 18:04:23 +0800 Subject: [PATCH 0493/1216] v4.0.0 --- Lib/Constants.php | 13 +- Lib/Timer.php | 170 +--- Protocols/Http.php | 822 ++++-------------- Protocols/Http/Chunk.php | 48 + Protocols/Http/Request.php | 617 +++++++++++++ Protocols/Http/Response.php | 375 ++++++++ Protocols/Http/ServerSentEvents.php | 64 ++ Protocols/Http/Session.php | 359 ++++++++ Protocols/Http/Session/FileSessionHandler.php | 172 ++++ Protocols/Websocket.php | 2 +- Timer.php | 182 ++++ Worker.php | 2 +- 12 files changed, 2011 insertions(+), 815 deletions(-) create mode 100644 Protocols/Http/Chunk.php create mode 100644 Protocols/Http/Request.php create mode 100644 Protocols/Http/Response.php create mode 100644 Protocols/Http/ServerSentEvents.php create mode 100644 Protocols/Http/Session.php create mode 100644 Protocols/Http/Session/FileSessionHandler.php create mode 100644 Timer.php diff --git a/Lib/Constants.php b/Lib/Constants.php index 1990b3824..f82a781da 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -30,8 +30,19 @@ const OS_TYPE_WINDOWS = 'windows'; // Compatible with php7 -if ( ! class_exists('Error')) { +if (!class_exists('Error')) { class Error extends Exception { } } + +if (!interface_exists('SessionHandlerInterface')) { + interface SessionHandlerInterface { + public function close(); + public function destroy($session_id); + public function gc($maxlifetime); + public function open($save_path ,$session_name); + public function read($session_id); + public function write($session_id , $session_data); + } +} diff --git a/Lib/Timer.php b/Lib/Timer.php index 1bd3419ad..b1100510c 100644 --- a/Lib/Timer.php +++ b/Lib/Timer.php @@ -13,170 +13,10 @@ */ namespace Workerman\Lib; -use Workerman\Events\EventInterface; -use Workerman\Worker; -use \Exception; - /** - * Timer. - * - * example: - * Workerman\Lib\Timer::add($time_interval, callback, array($arg1, $arg2..)); + * Do not use Workerman\Lib\Timer. + * Please use Workerman\Timer. + * This class is only used for compatibility with workerman 3.* + * @package Workerman\Lib */ -class Timer -{ - /** - * Tasks that based on ALARM signal. - * [ - * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], - * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], - * .. - * ] - * - * @var array - */ - protected static $_tasks = array(); - - /** - * event - * - * @var EventInterface - */ - protected static $_event = null; - - /** - * Init. - * - * @param EventInterface $event - * @return void - */ - public static function init($event = null) - { - if ($event) { - self::$_event = $event; - return; - } - if (\function_exists('pcntl_signal')) { - \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); - } - } - - /** - * ALARM signal handler. - * - * @return void - */ - public static function signalHandle() - { - if (!self::$_event) { - \pcntl_alarm(1); - self::tick(); - } - } - - /** - * Add a timer. - * - * @param float $time_interval - * @param callable $func - * @param mixed $args - * @param bool $persistent - * @return int|false - */ - public static function add($time_interval, $func, $args = array(), $persistent = true) - { - if ($time_interval <= 0) { - Worker::safeEcho(new Exception("bad time_interval")); - return false; - } - - if ($args === null) { - $args = array(); - } - - if (self::$_event) { - return self::$_event->add($time_interval, - $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); - } - - if (!\is_callable($func)) { - Worker::safeEcho(new Exception("not callable")); - return false; - } - - if (empty(self::$_tasks)) { - \pcntl_alarm(1); - } - - $run_time = \time() + $time_interval; - if (!isset(self::$_tasks[$run_time])) { - self::$_tasks[$run_time] = array(); - } - self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); - return 1; - } - - - /** - * Tick. - * - * @return void - */ - public static function tick() - { - if (empty(self::$_tasks)) { - \pcntl_alarm(0); - return; - } - - $time_now = \time(); - foreach (self::$_tasks as $run_time => $task_data) { - if ($time_now >= $run_time) { - foreach ($task_data as $index => $one_task) { - $task_func = $one_task[0]; - $task_args = $one_task[1]; - $persistent = $one_task[2]; - $time_interval = $one_task[3]; - try { - \call_user_func_array($task_func, $task_args); - } catch (\Exception $e) { - Worker::safeEcho($e); - } - if ($persistent) { - self::add($time_interval, $task_func, $task_args); - } - } - unset(self::$_tasks[$run_time]); - } - } - } - - /** - * Remove a timer. - * - * @param mixed $timer_id - * @return bool - */ - public static function del($timer_id) - { - if (self::$_event) { - return self::$_event->del($timer_id, EventInterface::EV_TIMER); - } - - return false; - } - - /** - * Remove all timers. - * - * @return void - */ - public static function delAll() - { - self::$_tasks = array(); - \pcntl_alarm(0); - if (self::$_event) { - self::$_event->clearAllTimer(); - } - } -} +class Timer extends \Workerman\Timer {} \ No newline at end of file diff --git a/Protocols/Http.php b/Protocols/Http.php index 0cb5b2170..ac5965c4d 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -14,743 +14,271 @@ namespace Workerman\Protocols; use Workerman\Connection\TcpConnection; +use Workerman\Protocols\Http\Request; +use Workerman\Protocols\Http\Response; use Workerman\Protocols\Websocket; use Workerman\Worker; /** - * http protocol + * Class Http. + * @package Workerman\Protocols */ class Http { /** - * The supported HTTP methods - * @var array - */ - public static $methods = array('GET'=>'GET', 'POST'=>'POST', 'PUT'=>'PUT', 'DELETE'=>'DELETE', 'HEAD'=>'HEAD', 'OPTIONS'=>'OPTIONS'); - - /** - * Cache. - * @var array - */ - protected static $_cache = array(); - - /** - * Check the integrity of the package. + * Request class name. * - * @param string $recv_buffer - * @param TcpConnection $connection - * @return int + * @var string */ - public static function input($recv_buffer, TcpConnection $connection) - { - if (isset(static::$_cache[$recv_buffer]['input'])) { - return static::$_cache[$recv_buffer]['input']; - } - $recv_len = \strlen($recv_buffer); - $crlf_post = \strpos($recv_buffer, "\r\n\r\n"); - if (!$crlf_post) { - // Judge whether the package length exceeds the limit. - if ($recv_len >= $connection->maxPackageSize) { - $connection->close(); - } - return 0; - } - $head_len = $crlf_post + 4; - - $method = \substr($recv_buffer, 0, \strpos($recv_buffer, ' ')); - if (!isset(static::$methods[$method])) { - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); - $connection->consumeRecvBuffer($recv_len); - return 0; - } - - if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { - static::$_cache[$recv_buffer]['input'] = $head_len; - return $head_len; - } - - $match = array(); - if (\preg_match("/\r\nContent-Length: ?(\d+)/i", $recv_buffer, $match)) { - $content_length = isset($match[1]) ? $match[1] : 0; - $total_length = $content_length + $head_len; - static::$_cache[$recv_buffer]['input'] = $total_length; - return $total_length; - } - - return $method === 'DELETE' ? $head_len : 0; - } - - /** - * Parse $_POST、$_GET、$_COOKIE. - * - * @param string $recv_buffer - * @param TcpConnection $connection - * @return array - */ - public static function decode($recv_buffer, TcpConnection $connection) - { - if (isset(static::$_cache[$recv_buffer]['decode'])) { - HttpCache::reset(); - $cache = static::$_cache[$recv_buffer]['decode']; - //$cache['server']['REQUEST_TIME_FLOAT'] = \microtime(true); - //$cache['server']['REQUEST_TIME'] = (int)$cache['server']['REQUEST_TIME_FLOAT']; - $_SERVER = $cache['server']; - $_POST = $cache['post']; - $_GET = $cache['get']; - $_COOKIE = $cache['cookie']; - $_REQUEST = $cache['request']; - $GLOBALS['HTTP_RAW_POST_DATA'] = $GLOBALS['HTTP_RAW_REQUEST_DATA'] = ''; - return static::$_cache[$recv_buffer]['decode']; - } - // Init. - $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); - $GLOBALS['HTTP_RAW_POST_DATA'] = ''; - // Clear cache. - HttpCache::reset(); - //$microtime = \microtime(true); - // $_SERVER - $_SERVER = array( - 'QUERY_STRING' => '', - 'REQUEST_METHOD' => '', - 'REQUEST_URI' => '', - 'SERVER_PROTOCOL' => '', - 'SERVER_SOFTWARE' => 'workerman/'.Worker::VERSION, - 'SERVER_NAME' => '', - 'HTTP_HOST' => '', - 'HTTP_USER_AGENT' => '', - 'HTTP_ACCEPT' => '', - 'HTTP_ACCEPT_LANGUAGE' => '', - 'HTTP_ACCEPT_ENCODING' => '', - 'HTTP_COOKIE' => '', - 'HTTP_CONNECTION' => '', - 'CONTENT_TYPE' => '', - 'REMOTE_ADDR' => '', - 'REMOTE_PORT' => '0', - //'REQUEST_TIME' => (int)$microtime, - //'REQUEST_TIME_FLOAT' => $microtime //compatible php5.4 - ); - - // Parse headers. - list($http_header, $http_body) = \explode("\r\n\r\n", $recv_buffer, 2); - $header_data = \explode("\r\n", $http_header); - - list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ', - $header_data[0]); - - $http_post_boundary = ''; - unset($header_data[0]); - foreach ($header_data as $content) { - // \r\n\r\n - if (empty($content)) { - continue; - } - list($key, $value) = \explode(':', $content, 2); - $key = \str_replace('-', '_', strtoupper($key)); - $value = \trim($value); - $_SERVER['HTTP_' . $key] = $value; - switch ($key) { - // HTTP_HOST - case 'HOST': - $tmp = \explode(':', $value); - $_SERVER['SERVER_NAME'] = $tmp[0]; - if (isset($tmp[1])) { - $_SERVER['SERVER_PORT'] = $tmp[1]; - } - break; - // cookie - case 'COOKIE': - \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); - break; - // content-type - case 'CONTENT_TYPE': - if (!\preg_match('/boundary="?(\S+)"?/', $value, $match)) { - if ($pos = \strpos($value, ';')) { - $_SERVER['CONTENT_TYPE'] = \substr($value, 0, $pos); - } else { - $_SERVER['CONTENT_TYPE'] = $value; - } - } else { - $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; - $http_post_boundary = '--' . $match[1]; - } - break; - case 'CONTENT_LENGTH': - $_SERVER['CONTENT_LENGTH'] = $value; - break; - case 'UPGRADE': - if($value === 'websocket'){ - $connection->protocol = '\Workerman\Protocols\Websocket'; - return Websocket::input($recv_buffer,$connection); - } - break; - } - } - - // Parse $_POST. - if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['CONTENT_TYPE']) { - switch ($_SERVER['CONTENT_TYPE']) { - case 'multipart/form-data': - self::parseUploadFiles($http_body, $http_post_boundary); - break; - case 'application/json': - $_POST = \json_decode($http_body, true); - break; - case 'application/x-www-form-urlencoded': - \parse_str($http_body, $_POST); - break; - } - } - - // Parse other HTTP action parameters - if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== "POST") { - $data = array(); - if ($_SERVER['CONTENT_TYPE'] === "application/x-www-form-urlencoded") { - \parse_str($http_body, $data); - } elseif ($_SERVER['CONTENT_TYPE'] === "application/json") { - $data = \json_decode($http_body, true); - } - $_REQUEST = \array_merge($_REQUEST, $data); - } - - // HTTP_RAW_REQUEST_DATA HTTP_RAW_POST_DATA - $GLOBALS['HTTP_RAW_REQUEST_DATA'] = $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; - - // QUERY_STRING - $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY); - if ($_SERVER['QUERY_STRING']) { - // $GET - \parse_str($_SERVER['QUERY_STRING'], $_GET); - } else { - $_SERVER['QUERY_STRING'] = ''; - } - - if (\is_array($_POST)) { - // REQUEST - $_REQUEST = \array_merge($_GET, $_POST, $_REQUEST); - } else { - // REQUEST - $_REQUEST = \array_merge($_GET, $_REQUEST); - } - - // REMOTE_ADDR REMOTE_PORT - $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); - $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); - $ret = array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES, 'request'=>$_REQUEST); - if ($_SERVER['REQUEST_METHOD'] === 'GET') { - static::$_cache[$recv_buffer]['decode'] = $ret; - if (\count(static::$_cache) > 256) { - unset(static::$_cache[key(static::$_cache)]); - } - } - - return $ret; - } + protected static $_requestClass = 'Workerman\Protocols\Http\Request'; /** - * Http encode. + * Session name. * - * @param string $content - * @param TcpConnection $connection - * @return string + * @var string */ - public static function encode($content, TcpConnection $connection) - { - // http-code status line. - $header = HttpCache::$status . "\r\n"; - - // Cookie headers - if(HttpCache::$cookie) { - $header .= \implode("\r\n", HttpCache::$cookie) . "\r\n"; - } - - // other headers - if (HttpCache::$header) { - $header .= \implode("\r\n", HttpCache::$header) . "\r\n"; - } - - if(!empty($connection->gzip)) { - $header .= "Content-Encoding: gzip\r\n"; - $content = \gzencode($content,$connection->gzip); - } - // header - $header .= 'Content-Length: ' . \strlen($content) . "\r\n\r\n"; - - // save session - self::sessionWriteClose(); - - // the whole http package - return $header . $content; - } + protected static $_sessionName = 'PHPSID'; /** - * Send a raw HTTP header - * - * @param string $content - * @param bool $replace - * @param int $http_response_code - * - * @return bool|void - */ - public static function header($content, $replace = true, $http_response_code = null) - { - if (NO_CLI) { - \header($content, $replace, $http_response_code); - return; - } - - if (\strpos($content, 'HTTP') === 0) { - HttpCache::$status = $content; - return true; - } - - $key = \strstr($content, ':', true); - if (empty($key)) { - return false; - } - - if ('location' === \strtolower($key)) { - if (!$http_response_code) { - $http_response_code = 302; - } - self::responseCode($http_response_code); - } - - if ($key === 'Set-Cookie') { - HttpCache::$cookie[] = $content; - } else { - HttpCache::$header[$key] = $content; - } - - return true; - } - - /** - * Remove previously set headers + * Upload tmp dir. * - * @param string $name - * @return void + * @var string */ - public static function headerRemove($name) - { - if (NO_CLI) { - \header_remove($name); - return; - } - unset(HttpCache::$header[$name]); - } + protected static $_uploadTmpDir = ''; /** - * Sets the HTTP response status code. - * - * @param int $code The response code - * @return boolean|int The valid status code or FALSE if code is not provided and it is not invoked in a web server environment - */ - public static function responseCode($code) - { - if (NO_CLI) { - return \http_response_code($code); - } - if (isset(HttpCache::$codes[$code])) { - HttpCache::$status = "HTTP/1.1 $code " . HttpCache::$codes[$code]; - return $code; - } - return false; - } - - /** - * Set cookie. - * - * @param string $name - * @param string $value - * @param integer $maxage - * @param string $path - * @param string $domain - * @param bool $secure - * @param bool $HTTPOnly - * @return bool|void - */ - public static function setcookie( - $name, - $value = '', - $maxage = 0, - $path = '', - $domain = '', - $secure = false, - $HTTPOnly = false - ) { - if (NO_CLI) { - return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly); - } - - HttpCache::$cookie[] = 'Set-Cookie: ' . $name . '=' . rawurlencode($value) - . (empty($domain) ? '' : '; Domain=' . $domain) - . (empty($maxage) ? '' : '; Max-Age=' . $maxage) - . (empty($path) ? '' : '; Path=' . $path) - . (!$secure ? '' : '; Secure') - . (!$HTTPOnly ? '' : '; HttpOnly'); - - return true; - } - - /** - * sessionCreateId + * Cache. * - * @return string + * @var array */ - public static function sessionCreateId() - { - \mt_srand(); - return bin2hex(\pack('d', \microtime(true)) . \pack('N',\mt_rand(0, 2147483647))); - } + protected static $_cache = array(); /** - * Get and/or set the current session id - * - * @param string $id + * Open cache. * - * @return string|null + * @var bool. */ - public static function sessionId($id = null) - { - if (NO_CLI) { - return $id ? \session_id($id) : \session_id(); - } - if (static::sessionStarted() && HttpCache::$instance->sessionFile) { - return \str_replace('ses_', '', \basename(HttpCache::$instance->sessionFile)); - } - return ''; - } + public static $_enableCache = true; /** - * Get and/or set the current session name - * - * @param string $name + * Get or set session name. * + * @param null $name * @return string */ public static function sessionName($name = null) { - if (NO_CLI) { - return $name ? \session_name($name) : \session_name(); - } - $session_name = HttpCache::$sessionName; - if ($name && ! static::sessionStarted()) { - HttpCache::$sessionName = $name; + if ($name !== null && $name !== '') { + static::$_sessionName = (string)$name; } - return $session_name; + return static::$_sessionName; } /** - * Get and/or set the current session save path - * - * @param string $path + * Get or set the request class name. * + * @param null $class_name * @return string */ - public static function sessionSavePath($path = null) + public static function requestClass($class_name = null) { - if (NO_CLI) { - return $path ? \session_save_path($path) : \session_save_path(); - } - if ($path && \is_dir($path) && \is_writable($path) && !static::sessionStarted()) { - HttpCache::$sessionPath = $path; + if ($class_name) { + static::$_requestClass = $class_name; } - return HttpCache::$sessionPath; + return static::$_requestClass; } /** - * sessionStarted + * Enable or disable Cache. * - * @return bool + * @param $value */ - public static function sessionStarted() + public static function enableCache($value) { - if (!HttpCache::$instance) return false; - - return HttpCache::$instance->sessionStarted; + static::$_enableCache = (bool)$value; } /** - * sessionStart + * Check the integrity of the package. * - * @return bool + * @param string $recv_buffer + * @param TcpConnection $connection + * @return int */ - public static function sessionStart() + public static function input($recv_buffer, TcpConnection $connection) { - if (NO_CLI) { - return \session_start(); + $crlf_pos = \strpos($recv_buffer, "\r\n\r\n"); + if (false === $crlf_pos) { + // Judge whether the package length exceeds the limit. + if ($recv_len = \strlen($recv_buffer) >= 16384) { + $connection->send("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + $connection->consumeRecvBuffer($recv_len); + return 0; + } + return 0; } - self::tryGcSessions(); + $head_len = $crlf_pos + 4; + $method = \strstr($recv_buffer, ' ', true); - if (HttpCache::$instance->sessionStarted) { - Worker::safeEcho("already sessionStarted\n"); - return true; - } - HttpCache::$instance->sessionStarted = true; - // Generate a SID. - if (!isset($_COOKIE[HttpCache::$sessionName]) || !\is_file(HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName])) { - // Create a unique session_id and the associated file name. - while (true) { - $session_id = static::sessionCreateId(); - if (!\is_file($file_name = HttpCache::$sessionPath . '/ses_' . $session_id)) break; - } - HttpCache::$instance->sessionFile = $file_name; - return self::setcookie( - HttpCache::$sessionName - , $session_id - , \ini_get('session.cookie_lifetime') - , \ini_get('session.cookie_path') - , \ini_get('session.cookie_domain') - , \ini_get('session.cookie_secure') - , \ini_get('session.cookie_httponly') - ); - } - if (!HttpCache::$instance->sessionFile) { - HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/ses_' . $_COOKIE[HttpCache::$sessionName]; - } - // Read session from session file. - if (HttpCache::$instance->sessionFile) { - $raw = \file_get_contents(HttpCache::$instance->sessionFile); - if ($raw) { - $_SESSION = \unserialize($raw); - } + if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { + return $head_len; + } else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'DELETE') { + $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); + $connection->consumeRecvBuffer(\strlen($recv_buffer)); + return 0; } - return true; - } - /** - * Save session. - * - * @return bool - */ - public static function sessionWriteClose() - { - if (NO_CLI) { - \session_write_close(); - return true; - } - if (!empty(HttpCache::$instance->sessionStarted) && !empty($_SESSION)) { - $session_str = \serialize($_SESSION); - if ($session_str && HttpCache::$instance->sessionFile) { - return (bool) \file_put_contents(HttpCache::$instance->sessionFile, $session_str); - } + $header = \substr($recv_buffer, 0, $crlf_pos); + if ($pos = \strpos($header, "\r\nContent-Length: ")) { + return $head_len + (int)\substr($header, $pos + 18, 10); + } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { + return $head_len + $match[1]; } - return empty($_SESSION); + + return $method === 'DELETE' ? $head_len : 0; } /** - * End, like call exit in php-fpm. + * Http decode. * - * @param string $msg - * @throws \Exception + * @param string $recv_buffer + * @param TcpConnection $connection + * @return \Workerman\Protocols\Http\Request */ - public static function end($msg = '') + public static function decode($recv_buffer, TcpConnection $connection) { - if (NO_CLI) { - exit($msg); - } - if ($msg) { - echo $msg; + $cacheable = static::$_enableCache && \strlen($recv_buffer) < 512; + if (true === $cacheable && isset(static::$_cache[$recv_buffer])) { + $request = static::$_cache[$recv_buffer]; + $request->connection = $connection; + $connection->__request = $request; + $request->properties = array(); + return $request; + } + $request = new static::$_requestClass($recv_buffer); + $request->connection = $connection; + $connection->__request = $request; + if (true === $cacheable) { + static::$_cache[$recv_buffer] = $request; + if (\count(static::$_cache) > 512) { + unset(static::$_cache[key(static::$_cache)]); + } } - throw new \Exception('jump_exit'); + return $request; } /** - * Get mime types. + * Http encode. * + * @param string|Response $response + * @param TcpConnection $connection * @return string */ - public static function getMimeTypesFile() - { - return __DIR__ . '/Http/mime.types'; - } - - /** - * Parse $_FILES. - * - * @param string $http_body - * @param string $http_post_boundary - * @return void - */ - protected static function parseUploadFiles($http_body, $http_post_boundary) + public static function encode($response, TcpConnection $connection) { - $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); - $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); - if ($boundary_data_array[0] === '') { - unset($boundary_data_array[0]); - } - $key = -1; - foreach ($boundary_data_array as $boundary_data_buffer) { - list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); - // Remove \r\n from the end of buffer. - $boundary_value = \substr($boundary_value, 0, -2); - $key ++; - foreach (\explode("\r\n", $boundary_header_buffer) as $item) { - list($header_key, $header_value) = \explode(": ", $item); - $header_key = \strtolower($header_key); - switch ($header_key) { - case "content-disposition": - // Is file data. - if (\preg_match('/name="(.*?)"; filename="(.*?)"$/', $header_value, $match)) { - // Parse $_FILES. - $_FILES[$key] = array( - 'name' => $match[1], - 'file_name' => $match[2], - 'file_data' => $boundary_value, - 'file_size' => \strlen($boundary_value), - ); - break; - } // Is post field. - else { - // Parse $_POST. - if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { - $_POST[$match[1]] = $boundary_value; - } + if (isset($connection->__request)) { + $connection->__request->session = null; + $connection->__request->connection = null; + $connection->__request = null; + } + if (\is_scalar($response) || null === $response) { + $ext_header = ''; + if (isset($connection->__header)) { + foreach ($connection->__header as $name => $value) { + if (\is_array($value)) { + foreach ($value as $item) { + $ext_header = "$name: $item\r\n"; } - break; - case "content-type": - // add file_type - $_FILES[$key]['file_type'] = \trim($header_value); - break; + } else { + $ext_header = "$name: $value\r\n"; + } } + unset($connection->__header); } + $body_len = \strlen($response); + return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response"; } - } - /** - * Try GC sessions. - * - * @return void - */ - public static function tryGcSessions() - { - if (HttpCache::$sessionGcProbability <= 0 || - HttpCache::$sessionGcDivisor <= 0 || - \rand(1, HttpCache::$sessionGcDivisor) > HttpCache::$sessionGcProbability) { - return; + if (isset($connection->__header)) { + $response->withHeaders($connection->__header); + unset($connection->__header); } - $time_now = \time(); - foreach(glob(HttpCache::$sessionPath.'/ses*') as $file) { - if(\is_file($file) && $time_now - \filemtime($file) > HttpCache::$sessionGcMaxLifeTime) { - \unlink($file); + if (isset($response->file)) { + $file = $response->file; + $body_len = (int)\filesize($file); + $response->header('Content-Length', $body_len); + if ($body_len < 1024 * 1024) { + $connection->send((string)$response . file_get_contents($file, false, null, -1, $body_len), true); + return ''; + } + $handler = \fopen($file, 'r'); + if (false === $handler) { + $connection->close(new Response(403, null, '403 Forbidden')); + return ''; } + $connection->send((string)$response, true); + static::sendStream($connection, $handler); + return ''; } - } -} - -/** - * Http cache for the current http response. - */ -class HttpCache -{ - public static $codes = array( - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 306 => '(Unused)', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - ); - public static $default = array( - 'Content-Type' => 'Content-Type: text/html;charset=utf-8', - 'Connection' => 'Connection: keep-alive', - 'Server' => 'Server: workerman' - ); + return (string)$response; + } /** - * @var HttpCache + * Send remainder of a stream to client. + * + * @param TcpConnection $connection + * @param $handler */ - public static $instance = null; - public static $status = ''; - public static $header = array(); - public static $cookie = array(); - public static $sessionPath = ''; - public static $sessionName = ''; - public static $sessionGcProbability = 1; - public static $sessionGcDivisor = 1000; - public static $sessionGcMaxLifeTime = 1440; - public $sessionStarted = false; - public $sessionFile = ''; - - public static function reset() + protected static function sendStream(TcpConnection $connection, $handler) { - self::$status = 'HTTP/1.1 200 OK'; - self::$header = self::$default; - self::$cookie = array(); - self::$instance->sessionFile = ''; - self::$instance->sessionStarted = false; + $connection->bufferFull = false; + // Read file content from disk piece by piece and send to client. + $do_write = function () use ($connection, $handler) { + // Send buffer not full. + while ($connection->bufferFull === false) { + // Read from disk. + $buffer = \fread($handler, 8192); + // Read eof. + if ($buffer === '' || $buffer === false) { + fclose($handler); + $connection->onBufferDrain = null; + return; + } + $connection->send($buffer, true); + } + }; + // Send buffer full. + $connection->onBufferFull = function ($connection) { + $connection->bufferFull = true; + }; + // Send buffer drain. + $connection->onBufferDrain = function ($connection) use ($do_write) { + $connection->bufferFull = false; + $do_write(); + }; + $do_write(); } - public static function init() + /** + * Set or get uploadTmpDir. + * + * @return bool|string + */ + public static function uploadTmpDir($dir = null) { - if (!self::$sessionName) { - self::$sessionName = \ini_get('session.name'); - } - - if (!self::$sessionPath) { - self::$sessionPath = @\session_save_path(); - } - - if (!self::$sessionPath || \strpos(self::$sessionPath, 'tcp://') === 0) { - self::$sessionPath = \sys_get_temp_dir(); - } - - if ($gc_probability = \ini_get('session.gc_probability')) { - self::$sessionGcProbability = $gc_probability; - } - - if ($gc_divisor = \ini_get('session.gc_divisor')) { - self::$sessionGcDivisor = $gc_divisor; - } - - if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { - self::$sessionGcMaxLifeTime = $gc_max_life_time; + if (null !== $dir) { + static::$_uploadTmpDir = $dir; + } + if (static::$_uploadTmpDir === '') { + if ($upload_tmp_dir = \ini_get('upload_tmp_dir')) { + static::$_uploadTmpDir = $upload_tmp_dir; + } else if ($upload_tmp_dir = \sys_get_temp_dir()) { + static::$_uploadTmpDir = $upload_tmp_dir; + } } - - self::$instance = new HttpCache(); + static::$_uploadTmpDir; } -} - -HttpCache::init(); - -define('NO_CLI', \PHP_SAPI !== 'cli'); +} \ No newline at end of file diff --git a/Protocols/Http/Chunk.php b/Protocols/Http/Chunk.php new file mode 100644 index 000000000..00f3570ed --- /dev/null +++ b/Protocols/Http/Chunk.php @@ -0,0 +1,48 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http; + + +/** + * Class Chunk + * @package Workerman\Protocols\Http + */ +class Chunk +{ + /** + * Chunk buffer. + * + * @var string + */ + protected $_buffer = null; + + /** + * Chunk constructor. + * @param $buffer + */ + public function __construct($buffer) + { + $this->_buffer = $buffer; + } + + /** + * __toString + * + * @return string + */ + public function __toString() + { + return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n"; + } +} \ No newline at end of file diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php new file mode 100644 index 000000000..5eb3a8031 --- /dev/null +++ b/Protocols/Http/Request.php @@ -0,0 +1,617 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http; + +use Workerman\Connection\TcpConnection; +use Workerman\Protocols\Http\Session; +use Workerman\Protocols\Http; +use Workerman\Worker; + +/** + * Class Request + * @package Workerman\Protocols\Http + */ +class Request +{ + /** + * Connection. + * + * @var TcpConnection + */ + public $connection = null; + + /** + * Session instance. + * + * @var Session + */ + public $session = null; + + /** + * Properties. + * + * @var array + */ + public $properties = array(); + + /** + * Http buffer. + * + * @var string + */ + protected $_buffer = null; + + /** + * Request data. + * + * @var array + */ + protected $_data = null; + + /** + * Header cache. + * + * @var array + */ + protected static $_headerCache = array(); + + /** + * Get cache. + * + * @var array + */ + protected static $_getCache = array(); + + /** + * Post cache. + * + * @var array + */ + protected static $_postCache = array(); + + /** + * Enable cache. + * + * @var bool + */ + protected static $_enableCache = true; + + + /** + * Request constructor. + * + * @param $buffer + */ + public function __construct($buffer) + { + $this->_buffer = $buffer; + } + + /** + * $_GET. + * + * @param null $name + * @param null $default + * @return mixed|null + */ + public function get($name = null, $default = null) + { + if (!isset($this->_data['get'])) { + $this->parseGet(); + } + if (null === $name) { + return $this->_data['get']; + } + return isset($this->_data['get'][$name]) ? $this->_data['get'][$name] : $default; + } + + /** + * $_POST. + * + * @param $name + * @param null $default + * @return mixed|null + */ + public function post($name = null, $default = null) + { + if (!isset($this->_data['post'])) { + $this->parsePost(); + } + if (null === $name) { + return $this->_data['post']; + } + return isset($this->_data['post'][$name]) ? $this->_data['post'][$name] : $default; + } + + /** + * Get header item by name. + * + * @param null $name + * @param null $default + * @return string|null + */ + public function header($name = null, $default = null) + { + if (!isset($this->_data['headers'])) { + $this->parseHeaders(); + } + if (null === $name) { + return $this->_data['headers']; + } + $name = \strtolower($name); + return isset($this->_data['headers'][$name]) ? $this->_data['headers'][$name] : $default; + } + + /** + * Get cookie item by name. + * + * @param null $name + * @param null $default + * @return string|null + */ + public function cookie($name = null, $default = null) + { + if (!isset($this->_data['cookie'])) { + \parse_str(\str_replace('; ', '&', $this->header('cookie')), $this->_data['cookie']); + } + if ($name === null) { + return $this->_data['cookie']; + } + return isset($this->_data['cookie'][$name]) ? $this->_data['cookie'][$name] : $default; + } + + /** + * Get upload files. + * + * @param null $name + * @return array|null + */ + public function file($name = null) + { + if (!isset($this->_data['files'])) { + $this->parsePost(); + } + if (null === $name) { + return $this->_data['files']; + } + return isset($this->_data['files'][$name]) ? $this->_data['files'][$name] : null; + } + + /** + * Get method. + * + * @return string + */ + public function method() + { + if (!isset($this->_data['method'])) { + $this->parseHeadFirstLine(); + } + return $this->_data['method']; + } + + /** + * Get http protocol version. + * + * @return string. + */ + public function protocolVersion() + { + if (!isset($this->_data['protocolVersion'])) { + $this->parseProtocolVersion(); + } + return $this->_data['protocolVersion']; + } + + /** + * Get host. + * + * @param bool $without_port + * @return string + */ + public function host($without_port = false) + { + $host = $this->header('host'); + if ($without_port && $pos = \strpos($host, ':')) { + return \substr($host, 0, $pos); + } + return $host; + } + + /** + * Get uri. + * + * @return mixed + */ + public function uri() + { + if (!isset($this->_data['uri'])) { + $this->parseHeadFirstLine(); + } + return $this->_data['uri']; + } + + /** + * Get path. + * + * @return mixed + */ + public function path() + { + if (!isset($this->_data['path'])) { + $this->_data['path'] = \parse_url($this->uri(), PHP_URL_PATH); + } + return $this->_data['path']; + } + + /** + * Get query string. + * + * @return mixed + */ + public function queryString() + { + if (!isset($this->_data['query_string'])) { + $this->_data['query_string'] = \parse_url($this->uri(), PHP_URL_QUERY); + } + return $this->_data['query_string']; + } + + /** + * Get session. + * + * @return bool|\Workerman\Protocols\Http\Session + */ + public function session() + { + if ($this->session === null) { + $session_id = $this->sessionId(); + if ($session_id === false) { + return false; + } + $this->session = new Session($session_id); + } + return $this->session; + } + + /** + * Get session id. + * + * @return bool|mixed + */ + public function sessionId() + { + if (!isset($this->_data['sid'])) { + $session_name = Http::sessionName(); + $sid = $this->cookie($session_name); + if ($sid === '' || $sid === null) { + if ($this->connection === null) { + Worker::safeEcho('Request->session() fail, header already send'); + return false; + } + $sid = static::createSessionId(); + $cookie_params = \session_get_cookie_params(); + $this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid + . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) + . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . ($cookie_params['lifetime'] + \time())) + . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) + . (!$cookie_params['secure'] ? '' : '; Secure') + . (!$cookie_params['httponly'] ? '' : '; HttpOnly')); + } + $this->_data['sid'] = $sid; + } + return $this->_data['sid']; + } + + /** + * Get http raw head. + * + * @return string + */ + public function rawHead() + { + if (!isset($this->_data['head'])) { + $this->_data['head'] = \strstr($this->_buffer, "\r\n\r\n", true); + } + return $this->_data['head']; + } + + /** + * Get http raw body. + * + * @return string + */ + public function rawBody() + { + return \substr($this->_buffer, \strpos($this->_buffer, "\r\n\r\n") + 4); + } + + /** + * Get raw buffer. + * + * @return string + */ + public function rawBuffer() + { + return $this->_buffer; + } + + /** + * Enable or disable cache. + * + * @param $value + */ + public static function enableCache($value) + { + static::$_enableCache = (bool)$value; + } + + /** + * Parse first line of http header buffer. + * + * @return void + */ + protected function parseHeadFirstLine() + { + $first_line = \strstr($this->_buffer, "\r\n", true); + $tmp = \explode(' ', $first_line, 3); + $this->_data['method'] = $tmp[0]; + $this->_data['uri'] = isset($tmp[1]) ? $tmp[1] : '/'; + } + + /** + * Parse protocol version. + * + * @return void + */ + protected function parseProtocolVersion() + { + $first_line = \strstr($this->_buffer, "\r\n", true); + $protoco_version = substr(\strstr($first_line, 'HTTP/'), 5); + $this->_data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0'; + } + + /** + * Parse headers. + * + * @return void + */ + protected function parseHeaders() + { + $this->_data['headers'] = array(); + $raw_head = $this->rawHead(); + $head_buffer = \substr($raw_head, \strpos($raw_head, "\r\n") + 2); + $cacheable = static::$_enableCache && \strlen($head_buffer) < 2048; + if ($cacheable && isset(static::$_headerCache[$head_buffer])) { + $this->_data['headers'] = static::$_headerCache[$head_buffer]; + return; + } + $head_data = \explode("\r\n", $head_buffer); + foreach ($head_data as $content) { + if (false !== \strpos($content, ':')) { + list($key, $value) = \explode(':', $content, 2); + $this->_data['headers'][\strtolower($key)] = \ltrim($value); + } else { + $this->_data['headers'][\strtolower($content)] = ''; + } + } + if ($cacheable) { + static::$_headerCache[$head_buffer] = $this->_data['headers']; + if (\count(static::$_headerCache) > 128) { + unset(static::$_headerCache[key(static::$_headerCache)]); + } + } + } + + /** + * Parse head. + * + * @return void + */ + protected function parseGet() + { + $query_string = $this->queryString(); + $this->_data['get'] = array(); + if ($query_string === '') { + return; + } + $cacheable = static::$_enableCache && \strlen($query_string) < 1024; + if ($cacheable && isset(static::$_getCache[$query_string])) { + $this->_data['get'] = static::$_getCache[$query_string]; + return; + } + \parse_str($query_string, $this->_data['get']); + if ($cacheable) { + static::$_getCache[$query_string] = $this->_data['get']; + if (\count(static::$_getCache) > 256) { + unset(static::$_getCache[key(static::$_getCache)]); + } + } + } + + /** + * Parse post. + * + * @return void + */ + public function parsePost() + { + $body_buffer = $this->rawBody(); + $this->_data['post'] = $this->_data['files'] = array(); + if ($body_buffer === '') { + return; + } + $cacheable = static::$_enableCache && \strlen($body_buffer) < 1024; + if ($cacheable && isset(static::$_postCache[$body_buffer])) { + $this->_data['post'] = static::$_postCache[$body_buffer]; + return; + } + $content_type = $this->header('content-type'); + if ($content_type !== null && \preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { + $http_post_boundary = '--' . $match[1]; + $this->parseUploadFiles($http_post_boundary); + return; + } + \parse_str($body_buffer, $this->_data['post']); + if ($cacheable) { + static::$_postCache[$body_buffer] = $this->_data['post']; + if (\count(static::$_postCache) > 256) { + unset(static::$_postCache[key(static::$_postCache)]); + } + } + } + + /** + * Parse upload files. + * + * @param $http_post_boundary + * @return void + */ + protected function parseUploadFiles($http_post_boundary) + { + $http_body = $this->rawBody(); + $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); + $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); + if ($boundary_data_array[0] === '') { + unset($boundary_data_array[0]); + } + $key = -1; + $files = array(); + foreach ($boundary_data_array as $boundary_data_buffer) { + list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); + // Remove \r\n from the end of buffer. + $boundary_value = \substr($boundary_value, 0, -2); + $key++; + foreach (\explode("\r\n", $boundary_header_buffer) as $item) { + list($header_key, $header_value) = \explode(": ", $item); + $header_key = \strtolower($header_key); + switch ($header_key) { + case "content-disposition": + // Is file data. + if (\preg_match('/name="(.*?)"; filename="(.*?)"$/i', $header_value, $match)) { + $error = 0; + $tmp_file = ''; + $size = \strlen($boundary_value); + $tmp_upload_dir = HTTP::uploadTmpDir(); + if (!$tmp_upload_dir) { + $error = UPLOAD_ERR_NO_TMP_DIR; + } else { + $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.'); + if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) { + $error = UPLOAD_ERR_CANT_WRITE; + } + } + // Parse upload files. + $files[$key] = array( + 'key' => $match[1], + 'name' => $match[2], + 'tmp_name' => $tmp_file, + 'size' => $size, + 'error' => $error + ); + break; + } // Is post field. + else { + // Parse $_POST. + if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { + $this->_data['post'][$match[1]] = $boundary_value; + } + } + break; + case "content-type": + // add file_type + $files[$key]['type'] = \trim($header_value); + break; + } + } + } + + foreach ($files as $file) { + $key = $file['key']; + unset($file['key']); + $this->_data['files'][$key] = $file; + } + } + + /** + * Create session id. + * + * @return string + */ + protected static function createSessionId() + { + return \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand())); + } + + /** + * Setter. + * + * @param $name + * @param $value + * @return void + */ + public function __set($name, $value) + { + $this->properties[$name] = $value; + } + + /** + * Getter. + * + * @param $name + * @return mixed|null + */ + public function __get($name) + { + return isset($this->properties[$name]) ? $this->properties[$name] : null; + } + + /** + * Isset. + * + * @param $name + * @return bool + */ + public function __isset($name) + { + return isset($this->properties[$name]); + } + + /** + * Unset. + * + * @param $name + * @return void + */ + public function __unset($name) + { + unset($this->properties[$name]); + } + + /** + * __destruct. + * + * @return void + */ + public function __destruct() + { + if (isset($this->_data['files'])) { + foreach ($this->_data['files'] as $item) { + if (\is_file($item['tmp_name'])) { + \unlink($item['tmp_name']); + } + } + } + } +} \ No newline at end of file diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php new file mode 100644 index 000000000..2c3e1e378 --- /dev/null +++ b/Protocols/Http/Response.php @@ -0,0 +1,375 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http; + +/** + * Class Response + * @package Workerman\Protocols\Http + */ +class Response +{ + /** + * Header data. + * + * @var array + */ + protected $_header = null; + + /** + * Http status. + * + * @var int + */ + protected $_status = null; + + /** + * Http reason. + * + * @var string + */ + protected $_reason = null; + + /** + * Http version. + * + * @var string + */ + protected $_version = '1.1'; + + /** + * Http body. + * + * @var string + */ + protected $_body = null; + + /** + * Mine type map. + * @var array + */ + protected static $_mimeTypeMap = null; + + /** + * Phrases. + * + * @var array + */ + protected static $_phrases = array( + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-status', + 208 => 'Already Reported', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Switch Proxy', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Time-out', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Large', + 415 => 'Unsupported Media Type', + 416 => 'Requested range not satisfiable', + 417 => 'Expectation Failed', + 418 => 'I\'m a teapot', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Unordered Collection', + 426 => 'Upgrade Required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 451 => 'Unavailable For Legal Reasons', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Time-out', + 505 => 'HTTP Version not supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 511 => 'Network Authentication Required', + ); + + /** + * Init. + * + * @return void + */ + public static function init() { + static::initMimeTypeMap(); + } + + /** + * Response constructor. + * + * @param int $status + * @param array $headers + * @param string $body + */ + public function __construct( + $status = 200, + array $headers = array(), + $body = '' + ) { + $this->_status = $status; + $this->_header = $headers; + $this->_body = $body; + } + + /** + * Set header. + * + * @param $name + * @param $value + * @return $this + */ + public function header($name, $value) { + $this->_header[$name] = $value; + return $this; + } + + /** + * Set headers. + * + * @param $headers + * @return $this + */ + public function withHeaders($headers) { + $this->_header = \array_merge($this->_header, $headers); + return $this; + } + + /** + * Set status. + * + * @param $code + * @param null $reason_phrase + * @return $this + */ + public function withStatus($code, $reason_phrase = null) { + $this->_status = $code; + $this->_reason = $reason_phrase; + return $this; + } + + /** + * Set protocol version. + * + * @param $version + * @return $this + */ + public function withProtocolVersion($version) { + $this->_version = $version; + return $this; + } + + /** + * Set http body. + * + * @param $body + * @return $this + */ + public function withBody($body) { + $this->_body = $body; + return $this; + } + + /** + * Set file. + * + * @param $file + * @return $this + */ + public function withFile($file) { + if (!\is_file($file)) { + return $this->withStatus(404)->withBody('

404 Not Found

'); + } + $this->file = $file; + return $this; + } + + /** + * Set cookie. + * + * @param $name + * @param string $value + * @param int $maxage + * @param string $path + * @param string $domain + * @param bool $secure + * @param bool $http_only + * @return $this + */ + public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false) + { + $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) + . (empty($domain) ? '' : '; Domain=' . $domain) + . (empty($max_age) ? '' : '; Max-Age=' . $max_age) + . (empty($path) ? '' : '; Path=' . $path) + . (!$secure ? '' : '; Secure') + . (!$http_only ? '' : '; HttpOnly'); + return $this; + } + + /** + * Create header for file. + * + * @param $file + * @return string + */ + protected function createHeadForFile($file) + { + $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; + $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; + $headers = $this->_header; + if (!isset($headers['Server'])) { + $head .= "Server: workerman\r\n"; + } + foreach ($headers as $name => $value) { + if (\is_array($value)) { + foreach ($value as $item) { + $head .= "$name: $item\r\n"; + } + continue; + } + $head .= "$name: $value\r\n"; + } + + if (!isset($headers['Connection'])) { + $head .= "Connection: keep-alive\r\n"; + } + + $file_info = \pathinfo($file); + $extension = isset($file_info['extension']) ? $file_info['extension'] : ''; + $base_name = isset($file_info['basename']) ? $file_info['basename'] : 'unknown'; + if (!isset($headers['Content-Type'])) { + if (isset(self::$_mimeTypeMap[$extension])) { + $head .= "Content-Type: " . self::$_mimeTypeMap[$extension] . "\r\n"; + } else { + $head .= "Content-Type: application/octet-stream\r\n"; + } + } + + if (!isset($headers['Content-Disposition']) && !isset(self::$_mimeTypeMap[$extension])) { + $head .= "Content-Disposition: attachment; filename=\"$base_name\"\r\n"; + } + + if (!isset($headers['Last-Modified'])) { + if ($mtime = \filemtime($file)) { + $head .= 'Last-Modified: '.\date('D, d M Y H:i:s', $mtime) . ' ' . \date_default_timezone_get() ."\r\n"; + } + } + + return "{$head}\r\n"; + } + + /** + * __toString. + * + * @return string + */ + public function __toString() + { + if (isset($this->file)) { + return $this->createHeadForFile($this->file); + } + + $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; + $body_len = \strlen($this->_body); + if (empty($this->_header)) { + return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; + } + + $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; + $headers = $this->_header; + if (!isset($headers['Server'])) { + $head .= "Server: workerman\r\n"; + } + foreach ($headers as $name => $value) { + if (\is_array($value)) { + foreach ($value as $item) { + $head .= "$name: $item\r\n"; + } + continue; + } + $head .= "$name: $value\r\n"; + } + + if (!isset($headers['Connection'])) { + $head .= "Connection: keep-alive\r\n"; + } + + if (!isset($headers['Content-Type'])) { + $head .= "Content-Type: text/html;charset=utf-8\r\n"; + } else if ($headers['Content-Type'] === 'text/event-stream') { + return $head . $this->_body; + } + + if (!isset($headers['Transfer-Encoding'])) { + $head .= "Content-Length: $body_len\r\n\r\n"; + } else { + return "$head\r\n".dechex($body_len)."\r\n{$this->_body}\r\n"; + } + + // The whole http package + return $head . $this->_body; + } + + /** + * Init mime map. + * + * @return void + */ + public static function initMimeTypeMap() + { + $mime_file = __DIR__ . '/mime.types'; + $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); + foreach ($items as $content) { + if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { + $mime_type = $match[1]; + $extension_var = $match[2]; + $extension_array = \explode(' ', \substr($extension_var, 0, -1)); + foreach ($extension_array as $file_extension) { + static::$_mimeTypeMap[$file_extension] = $mime_type; + } + } + } + } +} +Response::init(); \ No newline at end of file diff --git a/Protocols/Http/ServerSentEvents.php b/Protocols/Http/ServerSentEvents.php new file mode 100644 index 000000000..7aeafc70d --- /dev/null +++ b/Protocols/Http/ServerSentEvents.php @@ -0,0 +1,64 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http; + +/** + * Class ServerSentEvents + * @package Workerman\Protocols\Http + */ +class ServerSentEvents +{ + /** + * Data. + * @var array + */ + protected $_data = null; + + /** + * ServerSentEvents constructor. + * $data for example ['event'=>'ping', 'data' => 'some thing', 'id' => 1000, 'retry' => 5000] + * @param array $data + */ + public function __construct(array $data) + { + $this->_data = $data; + } + + /** + * __toString. + * + * @return string + */ + public function __toString() + { + $buffer = ''; + $data = $this->_data; + if (isset($data[''])) { + $buffer = ": {$data['']}\n"; + } + if (isset($data['event'])) { + $buffer .= "event: {$data['event']}\n"; + } + if (isset($data['data'])) { + $buffer .= 'data: ' . \str_replace("\n", "\ndata: ", $data['data']) . "\n\n"; + } + if (isset($data['id'])) { + $buffer .= "id: {$data['id']}\n"; + } + if (isset($data['retry'])) { + $buffer .= "retry: {$data['retry']}\n"; + } + return $buffer; + } +} \ No newline at end of file diff --git a/Protocols/Http/Session.php b/Protocols/Http/Session.php new file mode 100644 index 000000000..91d5cf5d8 --- /dev/null +++ b/Protocols/Http/Session.php @@ -0,0 +1,359 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http; + + +/** + * Class Session + * @package Workerman\Protocols\Http + */ +class Session +{ + /** + * Session andler class which implements SessionHandlerInterface. + * + * @var string + */ + protected static $_handlerClass = 'Workerman\Protocols\Http\Session\FileSessionHandler'; + + /** + * Parameters of __constructor for session handler class. + * + * @var null + */ + protected static $_handlerConfig = null; + + /** + * Session.gc_probability + * + * @var int + */ + protected static $_sessionGcProbability = 1; + + /** + * Session.gc_divisor + * + * @var int + */ + protected static $_sessionGcDivisor = 1000; + + /** + * Session.gc_maxlifetime + * + * @var int + */ + protected static $_sessionGcMaxLifeTime = 1440; + + /** + * Session handler instance. + * + * @var \SessionHandlerInterface + */ + protected static $_handler = null; + + /** + * Session data. + * + * @var array + */ + protected $_data = array(); + + /** + * Session changed and need to save. + * + * @var bool + */ + protected $_needSave = false; + + /** + * Session id. + * + * @var null + */ + protected $_sessionId = null; + + /** + * Session constructor. + * + * @param $session_id + */ + public function __construct($session_id) + { + static::checkSessionId($session_id); + if (static::$_handler === null) { + static::initHandler(); + } + $this->_sessionId = $session_id; + if ($data = static::$_handler->read($session_id)) { + $this->_data = \unserialize($data); + } + } + + /** + * Get session id. + * + * @return string + */ + public function getId() + { + return $this->_sessionId; + } + + /** + * Get session. + * + * @param $name + * @param null $default + * @return mixed|null + */ + public function get($name, $default = null) + { + return isset($this->_data[$name]) ? $this->_data[$name] : $default; + } + + /** + * Store data in the session. + * + * @param $name + * @param $value + */ + public function set($name, $value) + { + $this->_data[$name] = $value; + $this->_needSave = true; + } + + /** + * Delete an item from the session. + * + * @param $name + */ + public function delete($name) + { + unset($this->_data[$name]); + $this->_needSave = true; + } + + /** + * Retrieve and delete an item from the session. + * + * @param $name + * @param null $default + * @return mixed|null + */ + public function pull($name, $default = null) + { + $value = $this->get($name, $default); + $this->delete($name); + return $value; + } + + /** + * Store data in the session. + * + * @param $key + * @param null $value + */ + public function put($key, $value = null) + { + if (!\is_array($key)) { + $this->set($key, $value); + return; + } + + foreach ($key as $k => $v) { + $this->_data[$k] = $v; + } + $this->_needSave = true; + } + + /** + * Remove a piece of data from the session. + * + * @param $name + */ + public function forget($name) + { + if (\is_scalar($name)) { + $this->delete($name); + return; + } + if (\is_array($name)) { + foreach ($name as $key) { + unset($this->_data[$key]); + } + } + $this->_needSave = true; + } + + /** + * Retrieve all the data in the session. + * + * @return array + */ + public function all() + { + return $this->_data; + } + + /** + * Remove all data from the session. + * + * @return void + */ + public function flush() + { + $this->_needSave = true; + $this->_data = array(); + } + + /** + * Determining If An Item Exists In The Session. + * + * @param $name + * @return bool + */ + public function has($name) + { + return isset($this->_data[$name]); + } + + /** + * To determine if an item is present in the session, even if its value is null. + * + * @param $name + * @return bool + */ + public function exists($name) + { + return \array_key_exists($name, $this->_data); + } + + /** + * Save session to store. + * + * @return void + */ + public function save() + { + if ($this->_needSave) { + if (empty($this->_data)) { + static::$_handler->destroy($this->_sessionId); + } else { + static::$_handler->write($this->_sessionId, \serialize($this->_data)); + } + } + $this->_needSave = false; + } + + /** + * Init. + * + * @return void + */ + public static function init() + { + if ($gc_probability = \ini_get('session.gc_probability')) { + self::$_sessionGcProbability = (int)$gc_probability; + } + + if ($gc_divisor = \ini_get('session.gc_divisor')) { + self::$_sessionGcDivisor = (int)$gc_divisor; + } + + if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { + self::$_sessionGcMaxLifeTime = (int)$gc_max_life_time; + } + } + + /** + * Set session handler class. + * + * @param null $class_name + * @param null $config + * @return string + */ + public static function handlerClass($class_name = null, $config = null) + { + if ($class_name) { + static::$_handlerClass = $class_name; + } + if ($config) { + static::$_handlerConfig = $config; + } + return static::$_handlerClass; + } + + /** + * Init handler. + * + * @return void + */ + protected static function initHandler() + { + if (static::$_handlerConfig === null) { + static::$_handler = new static::$_handlerClass(); + } else { + static::$_handler = new static::$_handlerClass(static::$_handlerConfig); + } + } + + /** + * Try GC sessions. + * + * @return void + */ + public function tryGcSessions() + { + if (\rand(1, static::$_sessionGcDivisor) > static::$_sessionGcProbability) { + return; + } + static::$_handler->gc(static::$_sessionGcMaxLifeTime); + } + + /** + * __destruct. + * + * @return void + */ + public function __destruct() + { + $this->save(); + $this->tryGcSessions(); + } + + /** + * Check session id. + * + * @param $session_id + */ + protected static function checkSessionId($session_id) + { + if (!\preg_match('/^[a-zA-Z0-9]+$/', $session_id)) { + throw new SessionException("session_id $session_id is invalid"); + } + } +} + +/** + * Class SessionException + * @package Workerman\Protocols\Http + */ +class SessionException extends \RuntimeException +{ + +} + +// Init session. +Session::init(); \ No newline at end of file diff --git a/Protocols/Http/Session/FileSessionHandler.php b/Protocols/Http/Session/FileSessionHandler.php new file mode 100644 index 000000000..3f6ba992f --- /dev/null +++ b/Protocols/Http/Session/FileSessionHandler.php @@ -0,0 +1,172 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http\Session; + +/** + * Class FileSessionHandler + * @package Workerman\Protocols\Http\Session + */ +class FileSessionHandler implements \SessionHandlerInterface +{ + /** + * Session save path. + * + * @var string + */ + protected static $_sessionSavePath = null; + + /** + * Session file prefix. + * + * @var string + */ + protected static $_sessionFilePrefix = 'session_'; + + /** + * Init. + */ + public static function init() { + $save_path = @\session_save_path(); + if (!$save_path || \strpos($save_path, 'tcp://') === 0) { + $save_path = \sys_get_temp_dir(); + } + static::sessionSavePath($save_path); + } + + /** + * FileSessionHandler constructor. + * @param array $config + */ + public function __construct($config = array()) { + if (isset($config['save_path'])) { + static::sessionSavePath($config['save_path']); + } + } + + /** + * Nothing. + * + * @param string $save_path + * @param string $name + * @return bool + */ + public function open($save_path, $name) + { + return true; + } + + /** + * Reads the session data from the session storage. + * + * @param string $session_id + * @return string + */ + public function read($session_id) + { + $session_file = static::sessionFile($session_id); + \clearstatcache(); + if (\is_file($session_file)) { + $data = \file_get_contents($session_file); + return $data ? $data : ''; + } + return ''; + } + + /** + * Writes the session data to the session storage. + * + * @param string $session_id + * @param string $session_data + * @return bool + */ + public function write($session_id, $session_data) + { + $temp_file = static::$_sessionSavePath.uniqid(mt_rand(), true); + if (!\file_put_contents($temp_file, $session_data)) { + return false; + } + return \rename($temp_file, static::sessionFile($session_id)); + } + + /** + * Nothing. + * + * @return bool + */ + public function close() + { + return true; + } + + /** + * Destroys a session. + * + * @param string $session_id + * @return bool + */ + public function destroy($session_id) + { + $session_file = static::sessionFile($session_id); + if (\is_file($session_file)) { + \unlink($session_file); + } + return true; + } + + /** + * Cleanup old sessions. + * + * @param int $maxlifetime + * @return void + */ + public function gc($maxlifetime) { + $time_now = \time(); + foreach (\glob(static::$_sessionSavePath . static::$_sessionFilePrefix . '*') as $file) { + if(\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { + \unlink($file); + } + } + } + + /** + * Get session file path. + * + * @param $session_id + * @return string + */ + protected static function sessionFile($session_id) { + return static::$_sessionSavePath.static::$_sessionFilePrefix.$session_id; + } + + /** + * Get or set session file path. + * + * @param $path + * @return string + */ + public static function sessionSavePath($path) { + if ($path) { + if ($path[\strlen($path)-1] !== DIRECTORY_SEPARATOR) { + $path .= DIRECTORY_SEPARATOR; + } + static::$_sessionSavePath = $path; + if (!\is_dir($path)) { + \mkdir($path, 0777, true); + } + } + return $path; + } +} + +FileSessionHandler::init(); \ No newline at end of file diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index ad9d0ac92..f00b14700 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -339,7 +339,7 @@ public static function decode($buffer, ConnectionInterface $connection) * @param TcpConnection $connection * @return int */ - protected static function dealHandshake($buffer, TcpConnection $connection) + public static function dealHandshake($buffer, TcpConnection $connection) { // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { diff --git a/Timer.php b/Timer.php new file mode 100644 index 000000000..6d52540a9 --- /dev/null +++ b/Timer.php @@ -0,0 +1,182 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman; + +use Workerman\Events\EventInterface; +use Workerman\Worker; +use \Exception; + +/** + * Timer. + * + * example: + * Workerman\Timer::add($time_interval, callback, array($arg1, $arg2..)); + */ +class Timer +{ + /** + * Tasks that based on ALARM signal. + * [ + * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], + * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], + * .. + * ] + * + * @var array + */ + protected static $_tasks = array(); + + /** + * event + * + * @var EventInterface + */ + protected static $_event = null; + + /** + * Init. + * + * @param EventInterface $event + * @return void + */ + public static function init($event = null) + { + if ($event) { + self::$_event = $event; + return; + } + if (\function_exists('pcntl_signal')) { + \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); + } + } + + /** + * ALARM signal handler. + * + * @return void + */ + public static function signalHandle() + { + if (!self::$_event) { + \pcntl_alarm(1); + self::tick(); + } + } + + /** + * Add a timer. + * + * @param float $time_interval + * @param callable $func + * @param mixed $args + * @param bool $persistent + * @return int|false + */ + public static function add($time_interval, $func, $args = array(), $persistent = true) + { + if ($time_interval <= 0) { + Worker::safeEcho(new Exception("bad time_interval")); + return false; + } + + if ($args === null) { + $args = array(); + } + + if (self::$_event) { + return self::$_event->add($time_interval, + $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); + } + + if (!\is_callable($func)) { + Worker::safeEcho(new Exception("not callable")); + return false; + } + + if (empty(self::$_tasks)) { + \pcntl_alarm(1); + } + + $run_time = \time() + $time_interval; + if (!isset(self::$_tasks[$run_time])) { + self::$_tasks[$run_time] = array(); + } + self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); + return 1; + } + + + /** + * Tick. + * + * @return void + */ + public static function tick() + { + if (empty(self::$_tasks)) { + \pcntl_alarm(0); + return; + } + + $time_now = \time(); + foreach (self::$_tasks as $run_time => $task_data) { + if ($time_now >= $run_time) { + foreach ($task_data as $index => $one_task) { + $task_func = $one_task[0]; + $task_args = $one_task[1]; + $persistent = $one_task[2]; + $time_interval = $one_task[3]; + try { + \call_user_func_array($task_func, $task_args); + } catch (\Exception $e) { + Worker::safeEcho($e); + } + if ($persistent) { + self::add($time_interval, $task_func, $task_args); + } + } + unset(self::$_tasks[$run_time]); + } + } + } + + /** + * Remove a timer. + * + * @param mixed $timer_id + * @return bool + */ + public static function del($timer_id) + { + if (self::$_event) { + return self::$_event->del($timer_id, EventInterface::EV_TIMER); + } + + return false; + } + + /** + * Remove all timers. + * + * @return void + */ + public static function delAll() + { + self::$_tasks = array(); + \pcntl_alarm(0); + if (self::$_event) { + self::$_event->clearAllTimer(); + } + } +} diff --git a/Worker.php b/Worker.php index 124ce82c8..913aa0b04 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '3.5.29'; + const VERSION = '4.0.0'; /** * Status starting. From ca926b7b8efbf583c16039f973f418e0d8321a77 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Mar 2020 18:11:32 +0800 Subject: [PATCH 0494/1216] Update README.md --- README.md | 226 +++--------------------------------------------------- 1 file changed, 12 insertions(+), 214 deletions(-) diff --git a/README.md b/README.md index 2aac0f2b0..23f38df6c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## What is it Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. Workerman supports HTTP, Websocket, SSL and other custom protocols. -Workerman supports libevent/event extension, [HHVM](https://github.com/facebook/hhvm) , [ReactPHP](https://github.com/reactphp/react). +Workerman supports event extension. ## Requires PHP 5.3 or Higher @@ -72,12 +72,18 @@ $http_worker = new Worker("http://0.0.0.0:2345"); $http_worker->count = 4; // Emitted when data received -$http_worker->onMessage = function($connection, $data) +$http_worker->onMessage = function($connection, $request) { - // $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER, $_FILES are available - var_dump($_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER, $_FILES); + //$request->get(); + //$request->post(); + //$request->header(); + //$request->cookie(); + //$requset->session(); + //$request->uri(); + //$request->path(); + //$request->method(); // send data to client - $connection->send("hello world \n"); + $connection->send("hello world"); }; // run all workers @@ -233,7 +239,7 @@ Worker::runAll(); ```php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; $task = new Worker(); $task->onWorkerStart = function($task) @@ -280,214 +286,6 @@ $worker->onWorkerStart = function() Worker::runAll(); ``` -### Async Mysql of ReactPHP -``` -composer require react/mysql -``` - -```php -onWorkerStart = function() { - global $mysql; - $loop = Worker::getEventLoop(); - $mysql = new React\MySQL\Connection($loop, array( - 'host' => '127.0.0.1', - 'dbname' => 'dbname', - 'user' => 'user', - 'passwd' => 'passwd', - )); - $mysql->on('error', function($e){ - echo $e; - }); - $mysql->connect(function ($e) { - if($e) { - echo $e; - } else { - echo "connect success\n"; - } - }); -}; -$worker->onMessage = function($connection, $data) { - global $mysql; - $mysql->query('show databases' /*trim($data)*/, function ($command, $mysql) use ($connection) { - if ($command->hasError()) { - $error = $command->getError(); - } else { - $results = $command->resultRows; - $fields = $command->resultFields; - $connection->send(json_encode($results)); - } - }); -}; -Worker::runAll(); -``` - -### Async Redis of ReactPHP -``` -composer require clue/redis-react -``` - -```php -onWorkerStart = function() { - global $factory; - $loop = Worker::getEventLoop(); - $factory = new Factory($loop); -}; - -$worker->onMessage = function($connection, $data) { - global $factory; - $factory->createClient('localhost:6379')->then(function (Client $client) use ($connection) { - $client->set('greeting', 'Hello world'); - $client->append('greeting', '!'); - - $client->get('greeting')->then(function ($greeting) use ($connection){ - // Hello world! - echo $greeting . PHP_EOL; - $connection->send($greeting); - }); - - $client->incr('invocation')->then(function ($n) use ($connection){ - echo 'This is invocation #' . $n . PHP_EOL; - $connection->send($n); - }); - }); -}; - -Worker::runAll(); -``` - -### Aysnc dns of ReactPHP -``` -composer require react/dns -``` - -```php -require_once __DIR__ . '/vendor/autoload.php'; -use Workerman\Worker; -$worker = new Worker('tcp://0.0.0.0:6161'); -$worker->onWorkerStart = function() { - global $dns; - // Get event-loop. - $loop = Worker::getEventLoop(); - $factory = new React\Dns\Resolver\Factory(); - $dns = $factory->create('8.8.8.8', $loop); -}; -$worker->onMessage = function($connection, $host) { - global $dns; - $host = trim($host); - $dns->resolve($host)->then(function($ip) use($host, $connection) { - $connection->send("$host: $ip"); - },function($e) use($host, $connection){ - $connection->send("$host: {$e->getMessage()}"); - }); -}; - -Worker::runAll(); -``` - -### Http client of ReactPHP -``` -composer require react/http-client -``` - -```php -onMessage = function($connection, $host) { - $loop = Worker::getEventLoop(); - $client = new \React\HttpClient\Client($loop); - $request = $client->request('GET', trim($host)); - $request->on('error', function(Exception $e) use ($connection) { - $connection->send($e); - }); - $request->on('response', function ($response) use ($connection) { - $response->on('data', function ($data) use ($connection) { - $connection->send($data); - }); - }); - $request->end(); -}; - -Worker::runAll(); -``` - -### ZMQ of ReactPHP -``` -composer require react/zmq -``` - -```php -onWorkerStart = function() { - global $pull; - $loop = Worker::getEventLoop(); - $context = new React\ZMQ\Context($loop); - $pull = $context->getSocket(ZMQ::SOCKET_PULL); - $pull->bind('tcp://127.0.0.1:5555'); - - $pull->on('error', function ($e) { - var_dump($e->getMessage()); - }); - - $pull->on('message', function ($msg) { - echo "Received: $msg\n"; - }); -}; - -Worker::runAll(); -``` - -### STOMP of ReactPHP -``` -composer require react/stomp -``` - -```php -onWorkerStart = function() { - global $client; - $loop = Worker::getEventLoop(); - $factory = new React\Stomp\Factory($loop); - $client = $factory->createClient(array('vhost' => '/', 'login' => 'guest', 'passcode' => 'guest')); - - $client - ->connect() - ->then(function ($client) use ($loop) { - $client->subscribe('/topic/foo', function ($frame) { - echo "Message received: {$frame->body}\n"; - }); - }); -}; - -Worker::runAll(); -``` - ## Available commands From e236c58fec35773d10d173556757f7801652cec0 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Mar 2020 18:12:48 +0800 Subject: [PATCH 0495/1216] Update README.md --- README.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/README.md b/README.md index 23f38df6c..64572a57f 100644 --- a/README.md +++ b/README.md @@ -90,25 +90,6 @@ $http_worker->onMessage = function($connection, $request) Worker::runAll(); ``` -### A WebServer -```php -require_once __DIR__ . '/vendor/autoload.php'; -use Workerman\WebServer; -use Workerman\Worker; - -// WebServer -$web = new WebServer("http://0.0.0.0:80"); - -// 4 processes -$web->count = 4; - -// Set the root of domains -$web->addRoot('www.your_domain.com', '/your/path/Web'); -$web->addRoot('www.another_domain.com', '/another/path/Web'); -// run all workers -Worker::runAll(); -``` - ### A tcp server ```php require_once __DIR__ . '/vendor/autoload.php'; From 0fd2e4601dd6933650c341ccc3712b438d3954cd Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Mar 2020 11:15:28 +0800 Subject: [PATCH 0496/1216] strlen optimization --- Protocols/Http.php | 2 +- Protocols/Http/Request.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index ac5965c4d..b903e4e79 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -148,7 +148,7 @@ public static function input($recv_buffer, TcpConnection $connection) */ public static function decode($recv_buffer, TcpConnection $connection) { - $cacheable = static::$_enableCache && \strlen($recv_buffer) < 512; + $cacheable = static::$_enableCache && !isset($recv_buffer[512]); if (true === $cacheable && isset(static::$_cache[$recv_buffer])) { $request = static::$_cache[$recv_buffer]; $request->connection = $connection; diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 5eb3a8031..37728d7e3 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -392,7 +392,7 @@ protected function parseHeaders() $this->_data['headers'] = array(); $raw_head = $this->rawHead(); $head_buffer = \substr($raw_head, \strpos($raw_head, "\r\n") + 2); - $cacheable = static::$_enableCache && \strlen($head_buffer) < 2048; + $cacheable = static::$_enableCache && !isset($head_buffer[2048]); if ($cacheable && isset(static::$_headerCache[$head_buffer])) { $this->_data['headers'] = static::$_headerCache[$head_buffer]; return; @@ -426,7 +426,7 @@ protected function parseGet() if ($query_string === '') { return; } - $cacheable = static::$_enableCache && \strlen($query_string) < 1024; + $cacheable = static::$_enableCache && !isset($query_string[1024]); if ($cacheable && isset(static::$_getCache[$query_string])) { $this->_data['get'] = static::$_getCache[$query_string]; return; @@ -452,7 +452,7 @@ public function parsePost() if ($body_buffer === '') { return; } - $cacheable = static::$_enableCache && \strlen($body_buffer) < 1024; + $cacheable = static::$_enableCache && !isset($body_buffer[1024]); if ($cacheable && isset(static::$_postCache[$body_buffer])) { $this->_data['post'] = static::$_postCache[$body_buffer]; return; From 2f48a7c54854caadcbe04c15738a2b84a6f6fb39 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Mar 2020 16:33:21 +0800 Subject: [PATCH 0497/1216] remove webserver --- Protocols/Http.php | 2 +- Protocols/Http/Request.php | 2 +- WebServer.php | 328 ------------------------------------- 3 files changed, 2 insertions(+), 330 deletions(-) delete mode 100644 WebServer.php diff --git a/Protocols/Http.php b/Protocols/Http.php index b903e4e79..841192b7f 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -210,7 +210,7 @@ public static function encode($response, TcpConnection $connection) $body_len = (int)\filesize($file); $response->header('Content-Length', $body_len); if ($body_len < 1024 * 1024) { - $connection->send((string)$response . file_get_contents($file, false, null, -1, $body_len), true); + $connection->send((string)$response . file_get_contents($file, false, null, 0, $body_len), true); return ''; } $handler = \fopen($file, 'r'); diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 37728d7e3..21b8edd00 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -445,7 +445,7 @@ protected function parseGet() * * @return void */ - public function parsePost() + protected function parsePost() { $body_buffer = $this->rawBody(); $this->_data['post'] = $this->_data['files'] = array(); diff --git a/WebServer.php b/WebServer.php deleted file mode 100644 index a9a750ae0..000000000 --- a/WebServer.php +++ /dev/null @@ -1,328 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman; - -use Workerman\Protocols\Http; -use Workerman\Protocols\HttpCache; -use Workerman\Connection\TcpConnection; - -/** - * WebServer. - */ -class WebServer extends Worker -{ - /** - * Virtual host to path mapping. - * - * @var array ['workerman.net'=>'/home', 'www.workerman.net'=>'home/www'] - */ - protected $serverRoot = array(); - - /** - * Mime mapping. - * - * @var array - */ - protected static $mimeTypeMap = array(); - - - /** - * Used to save user OnWorkerStart callback settings. - * - * @var callable - */ - protected $_onWorkerStart = null; - - /** - * Add virtual host. - * - * @param string $domain - * @param string $config - * @return void - */ - public function addRoot($domain, $config) - { - if (\is_string($config)) { - $config = array('root' => $config); - } - $this->serverRoot[$domain] = $config; - } - - /** - * Construct. - * - * @param string $socket_name - * @param array $context_option - */ - public function __construct($socket_name, array $context_option = array()) - { - list(, $address) = \explode(':', $socket_name, 2); - parent::__construct('http:' . $address, $context_option); - $this->name = 'WebServer'; - } - - /** - * Run webserver instance. - * - * @see Workerman.Worker::run() - */ - public function run() - { - $this->_onWorkerStart = $this->onWorkerStart; - $this->onWorkerStart = array($this, 'onWorkerStart'); - $this->onMessage = array($this, 'onMessage'); - parent::run(); - } - - /** - * Emit when process start. - * - * @throws \Exception - */ - public function onWorkerStart() - { - if (empty($this->serverRoot)) { - Worker::safeEcho(new \Exception('server root not set, please use WebServer::addRoot($domain, $root_path) to set server root path')); - exit(250); - } - - // Init mimeMap. - $this->initMimeTypeMap(); - - // Try to emit onWorkerStart callback. - if ($this->_onWorkerStart) { - try { - \call_user_func($this->_onWorkerStart, $this); - } catch (\Exception $e) { - self::log($e); - exit(250); - } catch (\Error $e) { - self::log($e); - exit(250); - } - } - } - - /** - * Init mime map. - * - * @return void - */ - public function initMimeTypeMap() - { - $mime_file = Http::getMimeTypesFile(); - if (!\is_file($mime_file)) { - $this->log("$mime_file mime.type file not fond"); - return; - } - $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); - if (!\is_array($items)) { - $this->log("get $mime_file mime.type content fail"); - return; - } - foreach ($items as $content) { - if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { - $mime_type = $match[1]; - $workerman_file_extension_var = $match[2]; - $workerman_file_extension_array = \explode(' ', \substr($workerman_file_extension_var, 0, -1)); - foreach ($workerman_file_extension_array as $workerman_file_extension) { - self::$mimeTypeMap[$workerman_file_extension] = $mime_type; - } - } - } - } - - /** - * Emit when http message coming. - * - * @param TcpConnection $connection - * @return void - */ - public function onMessage(TcpConnection $connection) - { - // REQUEST_URI. - $workerman_url_info = \parse_url('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); - if (!$workerman_url_info) { - Http::header('HTTP/1.1 400 Bad Request'); - if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { - $connection->send('

400 Bad Request

'); - } else { - $connection->close('

400 Bad Request

'); - } - return; - } - - $workerman_path = isset($workerman_url_info['path']) ? $workerman_url_info['path'] : '/'; - - $workerman_path_info = \pathinfo($workerman_path); - $workerman_file_extension = isset($workerman_path_info['extension']) ? $workerman_path_info['extension'] : ''; - if ($workerman_file_extension === '') { - $workerman_path = ($len = \strlen($workerman_path)) && $workerman_path[$len - 1] === '/' ? $workerman_path . 'index.php' : $workerman_path . '/index.php'; - $workerman_file_extension = 'php'; - } - - $workerman_siteConfig = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : \current($this->serverRoot); - $workerman_root_dir = $workerman_siteConfig['root']; - $workerman_file = "$workerman_root_dir/$workerman_path"; - if(isset($workerman_siteConfig['additionHeader'])){ - Http::header($workerman_siteConfig['additionHeader']); - } - if ($workerman_file_extension === 'php' && !\is_file($workerman_file)) { - $workerman_file = "$workerman_root_dir/index.php"; - if (!\is_file($workerman_file)) { - $workerman_file = "$workerman_root_dir/index.html"; - $workerman_file_extension = 'html'; - } - } - - // File exsits. - if (\is_file($workerman_file)) { - // Security check. - if ((!($workerman_request_realpath = \realpath($workerman_file)) || !($workerman_root_dir_realpath = \realpath($workerman_root_dir))) || 0 !== \strpos($workerman_request_realpath, - $workerman_root_dir_realpath) - ) { - Http::header('HTTP/1.1 400 Bad Request'); - if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { - $connection->send('

400 Bad Request

'); - } else { - $connection->close('

400 Bad Request

'); - } - return; - } - - $workerman_file = \realpath($workerman_file); - - // Request php file. - if ($workerman_file_extension === 'php') { - $workerman_cwd = \getcwd(); - \chdir($workerman_root_dir); - \ini_set('display_errors', 'off'); - \ob_start(); - // Try to include php file. - try { - // $_SERVER. - $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); - $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); - include $workerman_file; - } catch (\Exception $e) { - // Jump_exit? - if ($e->getMessage() !== 'jump_exit') { - Worker::safeEcho($e); - } - } - $content = \ob_get_clean(); - \ini_set('display_errors', 'on'); - if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { - $connection->send($content); - } else { - $connection->close($content); - } - \chdir($workerman_cwd); - return; - } - - // Send file to client. - return self::sendFile($connection, $workerman_file); - } else { - // 404 - Http::header("HTTP/1.1 404 Not Found"); - if(isset($workerman_siteConfig['custom404']) && \file_exists($workerman_siteConfig['custom404'])){ - $html404 = \file_get_contents($workerman_siteConfig['custom404']); - }else{ - $html404 = '404 File not found

404 Not Found

'; - } - if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { - $connection->send($html404); - } else { - $connection->close($html404); - } - return; - } - } - - public static function sendFile($connection, $file_path) - { - // Check 304. - $info = \stat($file_path); - $modified_time = $info ? \date('D, d M Y H:i:s', $info['mtime']) . ' ' . \date_default_timezone_get() : ''; - if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { - // Http 304. - if ($modified_time === $_SERVER['HTTP_IF_MODIFIED_SINCE']) { - // 304 - Http::header('HTTP/1.1 304 Not Modified'); - // Send nothing but http headers.. - if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { - $connection->send(''); - } else { - $connection->close(''); - } - return; - } - } - - // Http header. - if ($modified_time) { - $modified_time = "Last-Modified: $modified_time\r\n"; - } - $file_size = \filesize($file_path); - $file_info = \pathinfo($file_path); - $extension = isset($file_info['extension']) ? $file_info['extension'] : ''; - $file_name = isset($file_info['filename']) ? $file_info['filename'] : ''; - $header = "HTTP/1.1 200 OK\r\n"; - if (isset(self::$mimeTypeMap[$extension])) { - $header .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; - } else { - $header .= "Content-Type: application/octet-stream\r\n" - ."Content-Disposition: attachment; filename=\"$file_name\"\r\n"; - } - $header .= "Connection: keep-alive\r\n" - .$modified_time - ."Content-Length: $file_size\r\n\r\n"; - $trunk_limit_size = 1024*1024; - if ($file_size < $trunk_limit_size) { - return $connection->send($header.\file_get_contents($file_path), true); - } - $connection->send($header, true); - - // Read file content from disk piece by piece and send to client. - $connection->fileHandler = \fopen($file_path, 'r'); - $do_write = function()use($connection) - { - // Send buffer not full. - while(empty($connection->bufferFull)) - { - // Read from disk. - $buffer = \fread($connection->fileHandler, 8192); - // Read eof. - if($buffer === '' || $buffer === false) - { - return; - } - $connection->send($buffer, true); - } - }; - // Send buffer full. - $connection->onBufferFull = function($connection) - { - $connection->bufferFull = true; - }; - // Send buffer drain. - $connection->onBufferDrain = function($connection)use($do_write) - { - $connection->bufferFull = false; - $do_write(); - }; - $do_write(); - } -} From 2b563b164ae1cf5e0d8190b9480c87f0802a9ae9 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Mar 2020 16:36:50 +0800 Subject: [PATCH 0498/1216] v4.0.1 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 913aa0b04..5db522e3f 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.0'; + const VERSION = '4.0.1'; /** * Status starting. From c857768ca9c588ffdbe6bd02c16c693229f35783 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 10 Mar 2020 11:51:31 +0800 Subject: [PATCH 0499/1216] fix upload err 6 --- Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 841192b7f..1e4a49e9f 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -279,6 +279,6 @@ public static function uploadTmpDir($dir = null) static::$_uploadTmpDir = $upload_tmp_dir; } } - static::$_uploadTmpDir; + return static::$_uploadTmpDir; } -} \ No newline at end of file +} From 2e300a734c47444a46541c134c4c4669451e7938 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Mar 2020 16:13:31 +0800 Subject: [PATCH 0500/1216] RedisSessionHandler --- Protocols/Http/Session/FileSessionHandler.php | 31 +---- .../Http/Session/RedisSessionHandler.php | 119 ++++++++++++++++++ 2 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 Protocols/Http/Session/RedisSessionHandler.php diff --git a/Protocols/Http/Session/FileSessionHandler.php b/Protocols/Http/Session/FileSessionHandler.php index 3f6ba992f..9baa34fdc 100644 --- a/Protocols/Http/Session/FileSessionHandler.php +++ b/Protocols/Http/Session/FileSessionHandler.php @@ -55,11 +55,7 @@ public function __construct($config = array()) { } /** - * Nothing. - * - * @param string $save_path - * @param string $name - * @return bool + * {@inheritdoc} */ public function open($save_path, $name) { @@ -67,10 +63,7 @@ public function open($save_path, $name) } /** - * Reads the session data from the session storage. - * - * @param string $session_id - * @return string + * {@inheritdoc} */ public function read($session_id) { @@ -84,11 +77,7 @@ public function read($session_id) } /** - * Writes the session data to the session storage. - * - * @param string $session_id - * @param string $session_data - * @return bool + * {@inheritdoc} */ public function write($session_id, $session_data) { @@ -100,9 +89,7 @@ public function write($session_id, $session_data) } /** - * Nothing. - * - * @return bool + * {@inheritdoc} */ public function close() { @@ -110,10 +97,7 @@ public function close() } /** - * Destroys a session. - * - * @param string $session_id - * @return bool + * {@inheritdoc} */ public function destroy($session_id) { @@ -125,10 +109,7 @@ public function destroy($session_id) } /** - * Cleanup old sessions. - * - * @param int $maxlifetime - * @return void + * {@inheritdoc} */ public function gc($maxlifetime) { $time_now = \time(); diff --git a/Protocols/Http/Session/RedisSessionHandler.php b/Protocols/Http/Session/RedisSessionHandler.php new file mode 100644 index 000000000..4876ab708 --- /dev/null +++ b/Protocols/Http/Session/RedisSessionHandler.php @@ -0,0 +1,119 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http\Session; + +/** + * Class RedisSessionHandler + * @package Workerman\Protocols\Http\Session + */ +class RedisSessionHandler extends \SessionHandler +{ + + /** + * @var \Redis + */ + protected $_redis; + + /** + * @var int + */ + protected $_maxLifeTime; + + /** + * RedisSessionHandler constructor. + * @param $config = [ + * 'host' => '127.0.0.1', + * 'port' => 6379, + * 'timeout' => 2, + * 'auth' => '******', + * 'database' => 2, + * 'prefix' => 'redis_session_', + * ] + */ + public function __construct($config) + { + if (false === extension_loaded('redis')) { + throw new \RuntimeException('Please install redis extension.'); + } + $this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime'); + + if (!isset($config['timeout'])) { + $config['timeout'] = 2; + } + + $this->_redis = new \Redis(); + if (false === $this->_redis->connect($config['host'], $config['port'], $config['timeout'])) { + throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); + } + if (!empty($config['auth'])) { + $this->_redis->auth($config['auth']); + } + if (!empty($config['database'])) { + $this->_redis->select($config['database']); + } + if (empty($config['prefix'])) { + $config['prefix'] = 'redis_session_'; + } + $this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + } + + /** + * {@inheritdoc} + */ + public function open($save_path, $name) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function read($session_id) + { + return $this->_redis->get($session_id); + } + + /** + * {@inheritdoc} + */ + public function write($session_id, $session_data) + { + return true === $this->_redis->setex($session_id, $this->_maxLifeTime, $session_data); + } + + /** + * {@inheritdoc} + */ + public function destroy($session_id) + { + $this->_redis->del($session_id); + return true; + } + + /** + * {@inheritdoc} + */ + public function close() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function gc($maxlifetime) + { + return true; + } +} \ No newline at end of file From fa8bd8d9036d4d62d6ba34e26a0fc2f472dd38b9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Mar 2020 16:15:30 +0800 Subject: [PATCH 0501/1216] v4.0.2 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 5db522e3f..81a38e430 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.1'; + const VERSION = '4.0.2'; /** * Status starting. From 745c95bb9b79ffc6af66c8afadb7b115d9a1d843 Mon Sep 17 00:00:00 2001 From: Bagus Erlang P Date: Sat, 14 Mar 2020 11:52:06 +0800 Subject: [PATCH 0502/1216] Update README.md --- README.md | 143 +++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 64572a57f..135c69d63 100644 --- a/README.md +++ b/README.md @@ -28,31 +28,30 @@ composer require workerman/workerman ### A websocket server ```php count = 4; // Emitted when new connection come -$ws_worker->onConnect = function($connection) -{ +$ws_worker->onConnect = function ($connection) { echo "New connection\n"; - }; +}; // Emitted when data received -$ws_worker->onMessage = function($connection, $data) -{ +$ws_worker->onMessage = function ($connection, $data) { // Send hello $data - $connection->send('hello ' . $data); + $connection->send('Hello ' . $data); }; // Emitted when connection closed -$ws_worker->onClose = function($connection) -{ +$ws_worker->onClose = function ($connection) { echo "Connection closed\n"; }; @@ -62,18 +61,18 @@ Worker::runAll(); ### An http server ```php -require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; +require_once __DIR__ . '/vendor/autoload.php'; + // #### http worker #### -$http_worker = new Worker("http://0.0.0.0:2345"); +$http_worker = new Worker('http://0.0.0.0:2345'); // 4 processes $http_worker->count = 4; // Emitted when data received -$http_worker->onMessage = function($connection, $request) -{ +$http_worker->onMessage = function ($connection, $request) { //$request->get(); //$request->post(); //$request->header(); @@ -82,41 +81,40 @@ $http_worker->onMessage = function($connection, $request) //$request->uri(); //$request->path(); //$request->method(); - // send data to client - $connection->send("hello world"); + + // Send data to client + $connection->send("Hello World"); }; -// run all workers +// Run all workers Worker::runAll(); ``` ### A tcp server ```php -require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; +require_once __DIR__ . '/vendor/autoload.php'; + // #### create socket and listen 1234 port #### -$tcp_worker = new Worker("tcp://0.0.0.0:1234"); +$tcp_worker = new Worker('tcp://0.0.0.0:1234'); // 4 processes $tcp_worker->count = 4; // Emitted when new connection come -$tcp_worker->onConnect = function($connection) -{ +$tcp_worker->onConnect = function ($connection) { echo "New Connection\n"; }; // Emitted when data received -$tcp_worker->onMessage = function($connection, $data) -{ - // send data to client - $connection->send("hello $data \n"); +$tcp_worker->onMessage = function ($connection, $data) { + // Send data to client + $connection->send("Hello $data \n"); }; // Emitted when new connection come -$tcp_worker->onClose = function($connection) -{ +$tcp_worker->onClose = function ($connection) { echo "Connection closed\n"; }; @@ -126,9 +124,11 @@ Worker::runAll(); ### Enable SSL ```php array( @@ -139,16 +139,15 @@ $context = array( ); // Create a Websocket server with ssl context. -$ws_worker = new Worker("websocket://0.0.0.0:2346", $context); +$ws_worker = new Worker('websocket://0.0.0.0:2346', $context); // Enable SSL. WebSocket+SSL means that Secure WebSocket (wss://). // The similar approaches for Https etc. $ws_worker->transport = 'ssl'; -$ws_worker->onMessage = function($connection, $data) -{ +$ws_worker->onMessage = function ($connection, $data) { // Send hello $data - $connection->send('hello ' . $data); + $connection->send('Hello ' . $data); }; Worker::runAll(); @@ -157,7 +156,9 @@ Worker::runAll(); ### Custom protocol Protocols/MyTextProtocol.php ```php + namespace Protocols; + /** * User defined protocol * Format Text+"\n" @@ -168,11 +169,12 @@ class MyTextProtocol { // Find the position of the first occurrence of "\n" $pos = strpos($recv_buffer, "\n"); + // Not a complete package. Return 0 because the length of package can not be calculated - if($pos === false) - { + if ($pos === false) { return 0; } + // Return length of the package return $pos+1; } @@ -184,86 +186,84 @@ class MyTextProtocol public static function encode($data) { - return $data."\n"; + return $data . "\n"; } } ``` ```php -require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; +require_once __DIR__ . '/vendor/autoload.php'; + // #### MyTextProtocol worker #### -$text_worker = new Worker("MyTextProtocol://0.0.0.0:5678"); +$text_worker = new Worker('MyTextProtocol://0.0.0.0:5678'); -$text_worker->onConnect = function($connection) -{ +$text_worker->onConnect = function ($connection) { echo "New connection\n"; }; -$text_worker->onMessage = function($connection, $data) -{ - // send data to client - $connection->send("hello world \n"); +$text_worker->onMessage = function ($connection, $data) { + // Send data to client + $connection->send("Hello world\n"); }; -$text_worker->onClose = function($connection) -{ +$text_worker->onClose = function ($connection) { echo "Connection closed\n"; }; -// run all workers +// Run all workers Worker::runAll(); ``` ### Timer ```php -require_once __DIR__ . '/vendor/autoload.php'; + use Workerman\Worker; use Workerman\Timer; +require_once __DIR__ . '/vendor/autoload.php'; + $task = new Worker(); -$task->onWorkerStart = function($task) -{ +$task->onWorkerStart = function ($task) { // 2.5 seconds $time_interval = 2.5; - $timer_id = Timer::add($time_interval, - function() - { - echo "Timer run\n"; - } - ); + $timer_id = Timer::add($time_interval, function () { + echo "Timer run\n"; + }); }; -// run all workers +// Run all workers Worker::runAll(); ``` ### AsyncTcpConnection (tcp/ws/text/frame etc...) ```php -require_once __DIR__ . '/vendor/autoload.php'; + use Workerman\Worker; use Workerman\Connection\AsyncTcpConnection; +require_once __DIR__ . '/vendor/autoload.php'; + $worker = new Worker(); -$worker->onWorkerStart = function() -{ +$worker->onWorkerStart = function () { // Websocket protocol for client. - $ws_connection = new AsyncTcpConnection("ws://echo.websocket.org:80"); - $ws_connection->onConnect = function($connection){ - $connection->send('hello'); + $ws_connection = new AsyncTcpConnection('ws://echo.websocket.org:80'); + $ws_connection->onConnect = function ($connection) { + $connection->send('Hello'); }; - $ws_connection->onMessage = function($connection, $data){ - echo "recv: $data\n"; + $ws_connection->onMessage = function ($connection, $data) { + echo "Recv: $data\n"; }; - $ws_connection->onError = function($connection, $code, $msg){ - echo "error: $msg\n"; + $ws_connection->onError = function ($connection, $code, $msg) { + echo "Error: $msg\n"; }; - $ws_connection->onClose = function($connection){ - echo "connection closed\n"; + $ws_connection->onClose = function ($connection) { + echo "Connection closed\n"; }; $ws_connection->connect(); }; + Worker::runAll(); ``` @@ -301,12 +301,13 @@ PHP: 5.5.9 ```php count=3; -$worker->onMessage = function($connection, $data) -{ +$worker->count = 3; +$worker->onMessage = function ($connection, $data) { $connection->send("HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: workerman\r\nContent-Length: 5\r\n\r\nhello"); }; + Worker::runAll(); ``` **Result** From 2bd6e02e589ba2344b813a02d2df7fd8245427a8 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Mar 2020 17:04:59 +0800 Subject: [PATCH 0503/1216] v4.0.3 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 81a38e430..38e8a60a4 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.2'; + const VERSION = '4.0.3'; /** * Status starting. From 2416fe3db453b17be2ba8719b109e0b67d42826f Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Mar 2020 17:07:09 +0800 Subject: [PATCH 0504/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index e1c61a8b6..e4b211d34 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -971,6 +971,8 @@ public function destroy() } } $this->_sendBuffer = $this->_recvBuffer = ''; + $this->_currentPackageLength = 0; + $this->_isPaused = $this->_sslHandshakeCompleted = false; if ($this->_status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; From d96ec295da2022eb56cc7f632baf82339ea2f4ea Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 20 Mar 2020 17:39:44 +0800 Subject: [PATCH 0505/1216] response->withFile add offset length parameters --- Protocols/Http/Response.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 2c3e1e378..af0af4c66 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -211,16 +211,18 @@ public function withBody($body) { } /** - * Set file. + * Send file. * * @param $file + * @param int $offset + * @param int $length * @return $this */ - public function withFile($file) { + public function withFile($file, $offset = 0, $length = 0) { if (!\is_file($file)) { return $this->withStatus(404)->withBody('

404 Not Found

'); } - $this->file = $file; + $this->file = array('file' => $file, 'offset' => $offset, 'length' => $length); return $this; } @@ -253,8 +255,9 @@ public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = ' * @param $file * @return string */ - protected function createHeadForFile($file) + protected function createHeadForFile($file_info) { + $file = $file_info['file']; $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; $headers = $this->_header; @@ -372,4 +375,4 @@ public static function initMimeTypeMap() } } } -Response::init(); \ No newline at end of file +Response::init(); From 3c2a6531b9fa36b88639061dadd5e58f0de28de6 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 20 Mar 2020 17:42:25 +0800 Subject: [PATCH 0506/1216] response->withFile add offset length parameters --- Protocols/Http.php | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 1e4a49e9f..e608043c1 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -206,11 +206,21 @@ public static function encode($response, TcpConnection $connection) } if (isset($response->file)) { - $file = $response->file; - $body_len = (int)\filesize($file); - $response->header('Content-Length', $body_len); - if ($body_len < 1024 * 1024) { - $connection->send((string)$response . file_get_contents($file, false, null, 0, $body_len), true); + $file = $response->file['file']; + $offset = $response->file['offset']; + $length = $response->file['length']; + $file_size = (int)\filesize($file); + $body_len = $length > 0 ? $length : $file_size - $offset; + $response->withHeaders(array( + 'Content-Length' => $body_len, + 'Accept-Ranges' => 'bytes', + )); + if ($offset || $length) { + $offset_end = $offset + $body_len - 1; + $response->header('Content-Range', "bytes $offset-$offset_end/$file_size"); + } + if ($body_len < 2 * 1024 * 1024) { + $connection->send((string)$response . file_get_contents($file, false, null, $offset, $body_len), true); return ''; } $handler = \fopen($file, 'r'); @@ -219,7 +229,7 @@ public static function encode($response, TcpConnection $connection) return ''; } $connection->send((string)$response, true); - static::sendStream($connection, $handler); + static::sendStream($connection, $handler, $offset, $length); return ''; } @@ -231,16 +241,34 @@ public static function encode($response, TcpConnection $connection) * * @param TcpConnection $connection * @param $handler + * @param $offset + * @param $length */ - protected static function sendStream(TcpConnection $connection, $handler) + protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) { $connection->bufferFull = false; + if ($offset !== 0) { + \fseek($handler, $offset); + } + $offset_end = $offset + $length; // Read file content from disk piece by piece and send to client. - $do_write = function () use ($connection, $handler) { + $do_write = function () use ($connection, $handler, $length, $offset_end) { // Send buffer not full. while ($connection->bufferFull === false) { // Read from disk. - $buffer = \fread($handler, 8192); + $size = 1024 * 1024; + if ($length !== 0) { + $tell = \ftell($handler); + $remain_size = $offset_end - $tell; + if ($remain_size <= 0) { + fclose($handler); + $connection->onBufferDrain = null; + return; + } + $size = $remain_size > $size ? $size : $remain_size; + } + + $buffer = \fread($handler, $size); // Read eof. if ($buffer === '' || $buffer === false) { fclose($handler); From 74005a9bd181d8010014d18e2ffad35fd4b7b173 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Mar 2020 15:34:29 +0800 Subject: [PATCH 0507/1216] fix #527 fix https://github.com/walkor/Workerman/issues/527 --- Connection/TcpConnection.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index e4b211d34..0d4d6702e 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -601,7 +601,6 @@ public function baseRead($socket, $check_eof = true) $this->_recvBuffer .= $buffer; } - $recv_len = \strlen($this->_recvBuffer); // If the application layer protocol has been set up. if ($this->protocol !== null) { $parser = $this->protocol; @@ -609,7 +608,7 @@ public function baseRead($socket, $check_eof = true) // The current packet length is known. if ($this->_currentPackageLength) { // Data is not enough for a package. - if ($this->_currentPackageLength > $recv_len) { + if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { break; } } else { @@ -624,7 +623,7 @@ public function baseRead($socket, $check_eof = true) break; } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. - if ($this->_currentPackageLength > $recv_len) { + if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { break; } } // Wrong package. @@ -638,7 +637,7 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if ($recv_len === $this->_currentPackageLength) { + if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; $this->_recvBuffer = ''; } else { @@ -646,7 +645,6 @@ public function baseRead($socket, $check_eof = true) $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); // Remove the current package from the receive buffer. $this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength); - $recv_len = \strlen($this->_recvBuffer); } // Reset the current packet length to 0. $this->_currentPackageLength = 0; From c8f9f340e569d885ffa9e349677b32ea173dbafe Mon Sep 17 00:00:00 2001 From: blogdaren Date: Thu, 16 Apr 2020 01:25:30 +0800 Subject: [PATCH 0508/1216] Timer Optimization: make the master process timer API just work like the children process timer --- Timer.php | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/Timer.php b/Timer.php index 6d52540a9..a206d872e 100644 --- a/Timer.php +++ b/Timer.php @@ -44,6 +44,25 @@ class Timer */ protected static $_event = null; + /** + * timer id + * + * @var int + */ + protected static $_timerId = 0; + + /** + * timer status + * [ + * timer_id1 => bool, + * timer_id2 => bool, + * ...................., + * ] + * + * @var array + */ + protected static $_status = array(); + /** * Init. * @@ -81,9 +100,10 @@ public static function signalHandle() * @param callable $func * @param mixed $args * @param bool $persistent - * @return int|false + * @param int $persistent_timer_id + * @return int|bool */ - public static function add($time_interval, $func, $args = array(), $persistent = true) + public static function add($time_interval, $func, $args = array(), $persistent = true, $persistent_timer_id = 0) { if ($time_interval <= 0) { Worker::safeEcho(new Exception("bad time_interval")); @@ -112,8 +132,18 @@ public static function add($time_interval, $func, $args = array(), $persistent = if (!isset(self::$_tasks[$run_time])) { self::$_tasks[$run_time] = array(); } - self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); - return 1; + + if(true === $persistent && $persistent_timer_id > 0) { + self::$_timerId = $persistent_timer_id; + } else { + self::$_timerId++; + } + + self::$_timerId == \PHP_INT_MAX && self::$_timerId = 1; + self::$_status[self::$_timerId] = true; + self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval); + + return self::$_timerId; } @@ -142,8 +172,8 @@ public static function tick() } catch (\Exception $e) { Worker::safeEcho($e); } - if ($persistent) { - self::add($time_interval, $task_func, $task_args); + if($persistent && !empty(self::$_status[$index])) { + self::add($time_interval, $task_func, $task_args, true, $index); } } unset(self::$_tasks[$run_time]); @@ -163,7 +193,13 @@ public static function del($timer_id) return self::$_event->del($timer_id, EventInterface::EV_TIMER); } - return false; + foreach(self::$_tasks as $run_time => $task_data) + { + if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); + if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); + } + + return true; } /** @@ -174,6 +210,7 @@ public static function del($timer_id) public static function delAll() { self::$_tasks = array(); + self::$_status = array(); \pcntl_alarm(0); if (self::$_event) { self::$_event->clearAllTimer(); From 803e3274418760363adf656e1075ee84b463e909 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Apr 2020 10:16:18 +0800 Subject: [PATCH 0509/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 0d4d6702e..98332747c 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -367,9 +367,14 @@ public function send($send_buffer, $raw = false) $this->checkBufferWillFull(); return; } - \set_error_handler(function(){}); - $len = \fwrite($this->_socket, $send_buffer); - \restore_error_handler(); + $len = 0; + try { + $len = \fwrite($this->_socket, $send_buffer); + } catch (\Exception $e) { + Worker::log($e); + } catch (\Error $e) { + Worker::log($e); + } // send successful. if ($len === \strlen($send_buffer)) { $this->bytesWritten += $len; @@ -586,9 +591,10 @@ public function baseRead($socket, $check_eof = true) } } - \set_error_handler(function(){}); - $buffer = \fread($socket, self::READ_BUFFER_SIZE); - \restore_error_handler(); + $buffer = ''; + try { + $buffer = \fread($socket, self::READ_BUFFER_SIZE); + } catch (\Exception $e) {} catch (\Error $e) {} // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -613,11 +619,9 @@ public function baseRead($socket, $check_eof = true) } } else { // Get current package length. - \set_error_handler(function($code, $msg, $file, $line){ - Worker::safeEcho("$msg in file $file on line $line\n"); - }); - $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - \restore_error_handler(); + try { + $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); + } catch (\Exception $e){} // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -939,9 +943,9 @@ public function destroy() Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // Close socket. - \set_error_handler(function(){}); - \fclose($this->_socket); - \restore_error_handler(); + try { + \fclose($this->_socket); + } catch (\Exception $e) {} catch (\Error $e) {} $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. From 3069b184abdfa6865416bbf6eb930ed70703273b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Apr 2020 10:16:56 +0800 Subject: [PATCH 0510/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 38e8a60a4..b68c19214 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.3'; + const VERSION = '4.0.5'; /** * Status starting. From 64cd1d2af4f5f67128eeaaae3ec1e51fb0eb0045 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Apr 2020 10:17:46 +0800 Subject: [PATCH 0511/1216] v4.0.4 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index b68c19214..cbdd8ac66 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.5'; + const VERSION = '4.0.4'; /** * Status starting. From 88e518903d2f61d6cdfe1d381b40e03be2a9ef94 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Apr 2020 10:20:21 +0800 Subject: [PATCH 0512/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 98332747c..6b1be87dd 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -621,7 +621,7 @@ public function baseRead($socket, $check_eof = true) // Get current package length. try { $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - } catch (\Exception $e){} + } catch (\Exception $e) {} catch (\Error $e) {} // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; From 6c4ec92f271dcf887ab0c9f98129ac66bdf5f62c Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Apr 2020 10:36:28 +0800 Subject: [PATCH 0513/1216] Update Http.php --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index e608043c1..a4027bbc7 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -58,7 +58,7 @@ class Http * * @var bool. */ - public static $_enableCache = true; + protected static $_enableCache = true; /** * Get or set session name. From 03e557a39d8a2378131708279b27d777299ff7d6 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Wed, 22 Apr 2020 00:58:26 +0800 Subject: [PATCH 0514/1216] Timer Optimization: make the master process timer API just work like the children process timer --- Timer.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Timer.php b/Timer.php index a206d872e..4661aa094 100644 --- a/Timer.php +++ b/Timer.php @@ -100,10 +100,9 @@ public static function signalHandle() * @param callable $func * @param mixed $args * @param bool $persistent - * @param int $persistent_timer_id * @return int|bool */ - public static function add($time_interval, $func, $args = array(), $persistent = true, $persistent_timer_id = 0) + public static function add($time_interval, $func, $args = array(), $persistent = true) { if ($time_interval <= 0) { Worker::safeEcho(new Exception("bad time_interval")); @@ -133,8 +132,8 @@ public static function add($time_interval, $func, $args = array(), $persistent = self::$_tasks[$run_time] = array(); } - if(true === $persistent && $persistent_timer_id > 0) { - self::$_timerId = $persistent_timer_id; + if(true === $persistent && !empty($args['__PERSISTENT_TIMER_ID__'])){ + self::$_timerId = $args['__PERSISTENT_TIMER_ID__']; } else { self::$_timerId++; } @@ -173,7 +172,8 @@ public static function tick() Worker::safeEcho($e); } if($persistent && !empty(self::$_status[$index])) { - self::add($time_interval, $task_func, $task_args, true, $index); + $task_args['__PERSISTENT_TIMER_ID__'] = $index; + self::add($time_interval, $task_func, $task_args); } } unset(self::$_tasks[$run_time]); From 493cd1a4b14aa393a8753c70e926b20da353909d Mon Sep 17 00:00:00 2001 From: blogdaren Date: Wed, 22 Apr 2020 18:57:24 +0800 Subject: [PATCH 0515/1216] Timer Optimization: make the master process timer API just work like the children process timer --- Timer.php | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/Timer.php b/Timer.php index 4661aa094..348bb3a43 100644 --- a/Timer.php +++ b/Timer.php @@ -132,13 +132,7 @@ public static function add($time_interval, $func, $args = array(), $persistent = self::$_tasks[$run_time] = array(); } - if(true === $persistent && !empty($args['__PERSISTENT_TIMER_ID__'])){ - self::$_timerId = $args['__PERSISTENT_TIMER_ID__']; - } else { - self::$_timerId++; - } - - self::$_timerId == \PHP_INT_MAX && self::$_timerId = 1; + self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId; self::$_status[self::$_timerId] = true; self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval); @@ -157,7 +151,6 @@ public static function tick() \pcntl_alarm(0); return; } - $time_now = \time(); foreach (self::$_tasks as $run_time => $task_data) { if ($time_now >= $run_time) { @@ -172,8 +165,9 @@ public static function tick() Worker::safeEcho($e); } if($persistent && !empty(self::$_status[$index])) { - $task_args['__PERSISTENT_TIMER_ID__'] = $index; - self::add($time_interval, $task_func, $task_args); + $new_run_time = \time() + $time_interval; + if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array(); + self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval); } } unset(self::$_tasks[$run_time]); @@ -195,10 +189,11 @@ public static function del($timer_id) foreach(self::$_tasks as $run_time => $task_data) { - if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); - if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); + if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); } + if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); + return true; } @@ -209,8 +204,7 @@ public static function del($timer_id) */ public static function delAll() { - self::$_tasks = array(); - self::$_status = array(); + self::$_tasks = self::$_status = array(); \pcntl_alarm(0); if (self::$_event) { self::$_event->clearAllTimer(); From 55711e689d85a41859bd36d47fca3f05ebc51881 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 23 Apr 2020 15:34:12 +0800 Subject: [PATCH 0516/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 6b1be87dd..51cdb5ffd 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -369,7 +369,7 @@ public function send($send_buffer, $raw = false) } $len = 0; try { - $len = \fwrite($this->_socket, $send_buffer); + $len = @\fwrite($this->_socket, $send_buffer); } catch (\Exception $e) { Worker::log($e); } catch (\Error $e) { @@ -701,9 +701,9 @@ public function baseWrite() { \set_error_handler(function(){}); if ($this->transport === 'ssl') { - $len = \fwrite($this->_socket, $this->_sendBuffer, 8192); + $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); } else { - $len = \fwrite($this->_socket, $this->_sendBuffer); + $len = @\fwrite($this->_socket, $this->_sendBuffer); } \restore_error_handler(); if ($len === \strlen($this->_sendBuffer)) { From d9fa00979108191d11bc28eae674ce129698eaca Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 29 Apr 2020 11:45:29 +0800 Subject: [PATCH 0517/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 51cdb5ffd..06fd0fc25 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -369,7 +369,7 @@ public function send($send_buffer, $raw = false) } $len = 0; try { - $len = @\fwrite($this->_socket, $send_buffer); + $len = \fwrite($this->_socket, $send_buffer); } catch (\Exception $e) { Worker::log($e); } catch (\Error $e) { From ac0e8cd269ffd43516efda53efbc64caa6aee1d8 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 May 2020 21:07:42 +0800 Subject: [PATCH 0518/1216] Update Response.php --- Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index af0af4c66..7075818a8 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -144,7 +144,7 @@ public static function init() { */ public function __construct( $status = 200, - array $headers = array(), + $headers = array(), $body = '' ) { $this->_status = $status; From 6041872a6b10e7d97b29849265b0c90e5ee0418c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 May 2020 18:48:13 +0800 Subject: [PATCH 0519/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 06fd0fc25..51cdb5ffd 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -369,7 +369,7 @@ public function send($send_buffer, $raw = false) } $len = 0; try { - $len = \fwrite($this->_socket, $send_buffer); + $len = @\fwrite($this->_socket, $send_buffer); } catch (\Exception $e) { Worker::log($e); } catch (\Error $e) { From b1eeec9813a4458b99eb95dabaecfa9c80625135 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 16 May 2020 22:04:04 +0800 Subject: [PATCH 0520/1216] optimization --- Protocols/Http.php | 56 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index a4027bbc7..39c8b5ee4 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -46,13 +46,6 @@ class Http */ protected static $_uploadTmpDir = ''; - /** - * Cache. - * - * @var array - */ - protected static $_cache = array(); - /** * Open cache. * @@ -107,12 +100,15 @@ public static function enableCache($value) */ public static function input($recv_buffer, TcpConnection $connection) { + static $input = array(); + if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) { + return $input[$recv_buffer]; + } $crlf_pos = \strpos($recv_buffer, "\r\n\r\n"); if (false === $crlf_pos) { // Judge whether the package length exceeds the limit. if ($recv_len = \strlen($recv_buffer) >= 16384) { - $connection->send("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); - $connection->consumeRecvBuffer($recv_len); + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); return 0; } return 0; @@ -121,22 +117,39 @@ public static function input($recv_buffer, TcpConnection $connection) $head_len = $crlf_pos + 4; $method = \strstr($recv_buffer, ' ', true); - if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD') { + if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD' || $method === 'DELETE') { + if (!isset($recv_buffer[512])) { + $input[$recv_buffer] = $head_len; + if (\count($input) > 512) { + unset($input[key($input)]); + } + } return $head_len; - } else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'DELETE') { - $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true); - $connection->consumeRecvBuffer(\strlen($recv_buffer)); + } else if ($method !== 'POST' && $method !== 'PUT') { + $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } $header = \substr($recv_buffer, 0, $crlf_pos); + $length = false; if ($pos = \strpos($header, "\r\nContent-Length: ")) { - return $head_len + (int)\substr($header, $pos + 18, 10); + $length = $head_len + (int)\substr($header, $pos + 18, 10); } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { - return $head_len + $match[1]; + $length = $head_len + $match[1]; + } + + if ($length !== false) { + if (!isset($recv_buffer[512])) { + $input[$recv_buffer] = $length; + if (\count($input) > 512) { + unset($input[key($input)]); + } + } + return $length; } - return $method === 'DELETE' ? $head_len : 0; + $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; } /** @@ -148,9 +161,10 @@ public static function input($recv_buffer, TcpConnection $connection) */ public static function decode($recv_buffer, TcpConnection $connection) { + static $requests = array(); $cacheable = static::$_enableCache && !isset($recv_buffer[512]); - if (true === $cacheable && isset(static::$_cache[$recv_buffer])) { - $request = static::$_cache[$recv_buffer]; + if (true === $cacheable && isset($requests[$recv_buffer])) { + $request = $requests[$recv_buffer]; $request->connection = $connection; $connection->__request = $request; $request->properties = array(); @@ -160,9 +174,9 @@ public static function decode($recv_buffer, TcpConnection $connection) $request->connection = $connection; $connection->__request = $request; if (true === $cacheable) { - static::$_cache[$recv_buffer] = $request; - if (\count(static::$_cache) > 512) { - unset(static::$_cache[key(static::$_cache)]); + $requests[$recv_buffer] = $request; + if (\count($requests) > 512) { + unset($requests[key($requests)]); } } return $request; From 3558e4f590e941bddbc0dc6000f35800d22f79d9 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 19 May 2020 15:23:34 +0800 Subject: [PATCH 0521/1216] v4.0.5 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index cbdd8ac66..b68c19214 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.4'; + const VERSION = '4.0.5'; /** * Status starting. From 91d791446af1ccd2d3f8e3277557b5699942807e Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 23 May 2020 12:52:13 +0800 Subject: [PATCH 0522/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 51cdb5ffd..320dd3ab6 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -944,7 +944,7 @@ public function destroy() // Close socket. try { - \fclose($this->_socket); + @\fclose($this->_socket); } catch (\Exception $e) {} catch (\Error $e) {} $this->_status = self::STATUS_CLOSED; From 2094b5de07e5881cc9aae070496f7808922f2ef2 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 30 May 2020 15:49:24 +0800 Subject: [PATCH 0523/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 320dd3ab6..d20229724 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -593,7 +593,7 @@ public function baseRead($socket, $check_eof = true) $buffer = ''; try { - $buffer = \fread($socket, self::READ_BUFFER_SIZE); + $buffer = @\fread($socket, self::READ_BUFFER_SIZE); } catch (\Exception $e) {} catch (\Error $e) {} // Check connection closed. From 50d4c32c7346390e150ace0a89960d6e7bdff1fa Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 13 Jun 2020 00:13:21 +0800 Subject: [PATCH 0524/1216] v4.0.6 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index b68c19214..5fbb187bb 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.5'; + const VERSION = '4.0.6'; /** * Status starting. From 14964ed1f3655e10f8bd0bd45e78fb75104fc9cf Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 13 Jun 2020 00:21:56 +0800 Subject: [PATCH 0525/1216] optimization --- Events/Select.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 1939ed306..8b7e1af63 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -267,9 +267,10 @@ public function loop() if ($read || $write || $except) { // Waiting read/write/signal/timeout events. - set_error_handler(function(){}); - $ret = stream_select($read, $write, $except, 0, $this->_selectTimeout); - restore_error_handler(); + try { + $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); + } catch (\Exception $e) {} catch (\Error $e) {} + } else { usleep($this->_selectTimeout); $ret = false; From 82df10d6533fc9842faf47348014a0de9225f644 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 30 Jun 2020 17:33:59 +0800 Subject: [PATCH 0526/1216] for swoole --- Events/Swoole.php | 4 ++-- Worker.php | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index 1778ecd84..5118926e5 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -28,7 +28,7 @@ class Swoole implements EventInterface protected $_fd = array(); // milisecond - public static $signalDispatchInterval = 200; + public static $signalDispatchInterval = 500; protected $_hasSignal = false; @@ -205,7 +205,7 @@ public function loop() */ public function destroy() { - //Event::exit(); + Event::exit(); } /** diff --git a/Worker.php b/Worker.php index 5fbb187bb..d27618b01 100644 --- a/Worker.php +++ b/Worker.php @@ -1539,6 +1539,9 @@ protected static function forkOneWorkerForLinux(self $worker) $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); + if (strpos(static::$eventLoopClass, 'Workerman\Events\Swoole') !== false) { + exit(0); + } $err = new Exception('event-loop exited'); static::log($err); exit(250); @@ -1856,7 +1859,12 @@ public static function stopAll() if (static::$globalEvent) { static::$globalEvent->destroy(); } - exit(0); + + try { + exit(0); + } catch (Exception $e) { + + } } } } @@ -2292,9 +2300,9 @@ protected function parseSocketAddress() { // Check application layer protocol class. if (!isset(static::$_builtinTransports[$scheme])) { $scheme = \ucfirst($scheme); - $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : '\\Protocols\\' . $scheme; + $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : 'Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { - $this->protocol = "\\Workerman\\Protocols\\$scheme"; + $this->protocol = "Workerman\\Protocols\\$scheme"; if (!\class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } From d0290a30c0d42d74ff3801463d0df98be30f94fb Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 30 Jun 2020 17:37:08 +0800 Subject: [PATCH 0527/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index d27618b01..8254f923e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.6'; + const VERSION = '4.0.7'; /** * Status starting. From acc3b6bbe34f891179a0743d299d1014d5cb2611 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Jul 2020 20:02:40 +0800 Subject: [PATCH 0528/1216] clearstatecache for upload files #546 --- Protocols/Http/Request.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 21b8edd00..ba05809ff 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -607,6 +607,7 @@ public function __unset($name) public function __destruct() { if (isset($this->_data['files'])) { + \clearstatecache(); foreach ($this->_data['files'] as $item) { if (\is_file($item['tmp_name'])) { \unlink($item['tmp_name']); @@ -614,4 +615,4 @@ public function __destruct() } } } -} \ No newline at end of file +} From a473f620b74f3e55f5bb7f48c9195102a1118e72 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Jul 2020 20:57:31 +0800 Subject: [PATCH 0529/1216] fix mistyped --- Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index ba05809ff..6dbd8cf2f 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -607,7 +607,7 @@ public function __unset($name) public function __destruct() { if (isset($this->_data['files'])) { - \clearstatecache(); + \clearstatcache(); foreach ($this->_data['files'] as $item) { if (\is_file($item['tmp_name'])) { \unlink($item['tmp_name']); From af507c698e971a78a6cdec06ae691327a2ab06ff Mon Sep 17 00:00:00 2001 From: Mohamed Ettaki Talbi Date: Fri, 31 Jul 2020 12:11:24 +0200 Subject: [PATCH 0530/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 135c69d63..c0218baad 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ $tcp_worker->onMessage = function ($connection, $data) { $connection->send("Hello $data \n"); }; -// Emitted when new connection come +// Emitted when connection is closed $tcp_worker->onClose = function ($connection) { echo "Connection closed\n"; }; From 3ff3a54755cbb2e296c2bdb48e10a35c7ab3207d Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 4 Aug 2020 15:22:16 +0800 Subject: [PATCH 0531/1216] Update README.md --- README.md | 82 +------------------------------------------------------ 1 file changed, 1 insertion(+), 81 deletions(-) diff --git a/README.md b/README.md index c0218baad..81bc7ee9e 100644 --- a/README.md +++ b/README.md @@ -289,87 +289,7 @@ Worker::runAll(); Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/src/SUMMARY.md) # Benchmarks -``` -CPU: Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz and 4 processors totally -Memory: 8G -OS: Ubuntu 14.04 LTS -Software: ab -PHP: 5.5.9 -``` - -**Codes** -```php -count = 3; -$worker->onMessage = function ($connection, $data) { - $connection->send("HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: workerman\r\nContent-Length: 5\r\n\r\nhello"); -}; - -Worker::runAll(); -``` -**Result** - -```shell -ab -n1000000 -c100 -k http://127.0.0.1:1234/ -This is ApacheBench, Version 2.3 <$Revision: 1528965 $> -Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ -Licensed to The Apache Software Foundation, http://www.apache.org/ - -Benchmarking 127.0.0.1 (be patient) -Completed 100000 requests -Completed 200000 requests -Completed 300000 requests -Completed 400000 requests -Completed 500000 requests -Completed 600000 requests -Completed 700000 requests -Completed 800000 requests -Completed 900000 requests -Completed 1000000 requests -Finished 1000000 requests - - -Server Software: workerman/3.1.4 -Server Hostname: 127.0.0.1 -Server Port: 1234 - -Document Path: / -Document Length: 5 bytes - -Concurrency Level: 100 -Time taken for tests: 7.240 seconds -Complete requests: 1000000 -Failed requests: 0 -Keep-Alive requests: 1000000 -Total transferred: 73000000 bytes -HTML transferred: 5000000 bytes -Requests per second: 138124.14 [#/sec] (mean) -Time per request: 0.724 [ms] (mean) -Time per request: 0.007 [ms] (mean, across all concurrent requests) -Transfer rate: 9846.74 [Kbytes/sec] received - -Connection Times (ms) - min mean[+/-sd] median max -Connect: 0 0 0.0 0 5 -Processing: 0 1 0.2 1 9 -Waiting: 0 1 0.2 1 9 -Total: 0 1 0.2 1 9 - -Percentage of the requests served within a certain time (ms) - 50% 1 - 66% 1 - 75% 1 - 80% 1 - 90% 1 - 95% 1 - 98% 1 - 99% 1 - 100% 9 (longest request) - -``` +https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r ## Other links with workerman From 8241a0d2aa0f412e6131ee4024b493cd5a0f1dd5 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 10 Aug 2020 13:11:23 +0800 Subject: [PATCH 0532/1216] Update Swoole.php --- Events/Swoole.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Events/Swoole.php b/Events/Swoole.php index 5118926e5..ea828eb8d 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -206,6 +206,7 @@ public function loop() public function destroy() { Event::exit(); + posix_kill(posix_getpid(), SIGINT); } /** From db5b89365d9f5c1d98e0542108e1dae335ce2d7e Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 10 Aug 2020 13:16:58 +0800 Subject: [PATCH 0533/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 8254f923e..6e36e3454 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.7'; + const VERSION = '4.0.8'; /** * Status starting. From 1ed65cb8c7b82bbb5d8c32ed815e7c659b3b72c7 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 18 Aug 2020 15:30:10 +0800 Subject: [PATCH 0534/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index d20229724..5ab9f47fd 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -808,7 +808,7 @@ public function pipe(self $dest) $dest->send($data); }; $this->onClose = function ($source) use ($dest) { - $dest->destroy(); + $dest->close(); }; $dest->onBufferFull = function ($dest) use ($source) { $source->pauseRecv(); From 362f05a7ab09fef7b5f2717155b2badbb5b3f4eb Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 26 Aug 2020 10:05:04 +0800 Subject: [PATCH 0535/1216] fix #557 --- Protocols/Http/Request.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 6dbd8cf2f..8353ef54e 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -306,6 +306,7 @@ public function sessionId() . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . ($cookie_params['lifetime'] + \time())) . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) + . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite']) . (!$cookie_params['secure'] ? '' : '; Secure') . (!$cookie_params['httponly'] ? '' : '; HttpOnly')); } From 1bb4c31b3a4516327eb58935d0a28cb65e5d9733 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 28 Aug 2020 14:24:03 +0800 Subject: [PATCH 0536/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 6e36e3454..b48dec440 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.8'; + const VERSION = '4.0.9'; /** * Status starting. From 945f94834755b505ce92fe46d296a8813aaae352 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 31 Aug 2020 15:39:17 +0800 Subject: [PATCH 0537/1216] flock not work in nfs --- Worker.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index b48dec440..40dea78a0 100644 --- a/Worker.php +++ b/Worker.php @@ -466,10 +466,8 @@ class Worker * @var array */ protected static $_availableEventLoops = array( - 'libevent' => '\Workerman\Events\Libevent', - 'event' => '\Workerman\Events\Event' - // Temporarily removed swoole because it is not stable enough - //'swoole' => '\Workerman\Events\Swoole' + 'event' => '\Workerman\Events\Event', + 'libevent' => '\Workerman\Events\Libevent' ); /** @@ -535,13 +533,11 @@ public static function runAll() { static::checkSapiEnv(); static::init(); - static::lock(); static::parseCommand(); static::daemonize(); static::initWorkers(); static::installSignal(); static::saveMasterPid(); - static::unlock(); static::displayUI(); static::forkWorkers(); static::resetStd(); From 572ec1859b8e9420d873af052d5d4c0e025d2565 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 31 Aug 2020 15:46:47 +0800 Subject: [PATCH 0538/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 40dea78a0..66d9efa50 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.9'; + const VERSION = '4.0.10'; /** * Status starting. From 132a277b1836464c8fb99e9146ca161de8d7199f Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 15 Sep 2020 17:22:45 +0800 Subject: [PATCH 0539/1216] listen SIGTERM for docker --- Worker.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index 66d9efa50..6634432ec 100644 --- a/Worker.php +++ b/Worker.php @@ -953,7 +953,7 @@ protected static function parseCommand() case 'stop': if ($command2 === '-g') { static::$_gracefulStop = true; - $sig = \SIGTERM; + $sig = \SIGHUP; static::log("Workerman[$start_file] is gracefully stopping ..."); } else { static::$_gracefulStop = false; @@ -1101,8 +1101,10 @@ protected static function installSignal() $signalHandler = '\Workerman\Worker::signalHandler'; // stop \pcntl_signal(\SIGINT, $signalHandler, false); - // graceful stop + // stop \pcntl_signal(\SIGTERM, $signalHandler, false); + // graceful stop + \pcntl_signal(\SIGHUP, $signalHandler, false); // reload \pcntl_signal(\SIGUSR1, $signalHandler, false); // graceful reload @@ -1128,8 +1130,10 @@ protected static function reinstallSignal() $signalHandler = '\Workerman\Worker::signalHandler'; // uninstall stop signal handler \pcntl_signal(\SIGINT, \SIG_IGN, false); - // uninstall graceful stop signal handler + // uninstall stop signal handler \pcntl_signal(\SIGTERM, \SIG_IGN, false); + // uninstall graceful stop signal handler + \pcntl_signal(\SIGHUP, \SIG_IGN, false); // uninstall reload signal handler \pcntl_signal(\SIGUSR1, \SIG_IGN, false); // uninstall graceful reload signal handler @@ -1141,7 +1145,7 @@ protected static function reinstallSignal() // reinstall stop signal handler static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGTERM, EventInterface::EV_SIGNAL, $signalHandler); + static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler); // reinstall reload signal handler static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful reload signal handler @@ -1162,11 +1166,12 @@ public static function signalHandler($signal) switch ($signal) { // Stop. case \SIGINT: + case \SIGTERM: static::$_gracefulStop = false; static::stopAll(); break; // Graceful stop. - case \SIGTERM: + case \SIGHUP: static::$_gracefulStop = true; static::stopAll(); break; @@ -1826,7 +1831,7 @@ public static function stopAll() $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. if (static::$_gracefulStop) { - $sig = \SIGTERM; + $sig = \SIGHUP; } else { $sig = \SIGINT; } From 3c28c27418d7716c2074cb74447de9155db884d5 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 15 Sep 2020 17:31:04 +0800 Subject: [PATCH 0540/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 6634432ec..f7ebd3a00 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.10'; + const VERSION = '4.0.11'; /** * Status starting. From f8977b24472cfa4581962103fc3fcff689de963f Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 3 Oct 2020 10:46:43 +0800 Subject: [PATCH 0541/1216] Make commands more flexible. --- Worker.php | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/Worker.php b/Worker.php index f7ebd3a00..365ca92fc 100644 --- a/Worker.php +++ b/Worker.php @@ -756,7 +756,7 @@ protected static function getCurrentUser() */ protected static function displayUI() { - global $argv; + $argv = $_SERVER['argv']; if (\in_array('-q', $argv)) { return; } @@ -860,9 +860,10 @@ protected static function parseCommand() if (static::$_OS !== \OS_TYPE_LINUX) { return; } - global $argv; + $argv = $_SERVER['argv']; // Check argv; $start_file = $argv[0]; + $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; $available_commands = array( 'start', 'stop', @@ -871,28 +872,33 @@ protected static function parseCommand() 'status', 'connections', ); - $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; - if (!isset($argv[1]) || !\in_array($argv[1], $available_commands)) { - if (isset($argv[1])) { - static::safeEcho('Unknown command: ' . $argv[1] . "\n"); + $available_mode = array( + '-d', + '-g' + ); + $command = $mode = ''; + foreach ($argv as $value) { + if (\in_array($value, $available_commands)) { + $command = $value; + } elseif (\in_array($value, $available_mode)) { + $mode = $value; } - exit($usage); } - // Get command. - $command = \trim($argv[1]); - $command2 = isset($argv[2]) ? $argv[2] : ''; + if (!$command) { + exit($usage); + } // Start command. - $mode = ''; + $mode_str = ''; if ($command === 'start') { - if ($command2 === '-d' || static::$daemonize) { - $mode = 'in DAEMON mode'; + if ($mode === '-d' || static::$daemonize) { + $mode_str = 'in DAEMON mode'; } else { - $mode = 'in DEBUG mode'; + $mode_str = 'in DEBUG mode'; } } - static::log("Workerman[$start_file] $command $mode"); + static::log("Workerman[$start_file] $command $mode_str"); // Get master process PID. $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0; @@ -911,7 +917,7 @@ protected static function parseCommand() // execute command. switch ($command) { case 'start': - if ($command2 === '-d') { + if ($mode === '-d') { static::$daemonize = true; } break; @@ -925,12 +931,12 @@ protected static function parseCommand() // Sleep 1 second. \sleep(1); // Clear terminal. - if ($command2 === '-d') { + if ($mode === '-d') { static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. static::safeEcho(static::formatStatusData()); - if ($command2 !== '-d') { + if ($mode !== '-d') { exit(0); } static::safeEcho("\nPress Ctrl+C to quit.\n\n"); @@ -951,7 +957,7 @@ protected static function parseCommand() exit(0); case 'restart': case 'stop': - if ($command2 === '-g') { + if ($mode === '-g') { static::$_gracefulStop = true; $sig = \SIGHUP; static::log("Workerman[$start_file] is gracefully stopping ..."); @@ -983,14 +989,14 @@ protected static function parseCommand() if ($command === 'stop') { exit(0); } - if ($command2 === '-d') { + if ($mode === '-d') { static::$daemonize = true; } break; } break; case 'reload': - if($command2 === '-g'){ + if($mode === '-g'){ $sig = \SIGQUIT; }else{ $sig = \SIGUSR1; From 94a5b1ec6e3e76ff5366ed7ac775536772d04d17 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 3 Oct 2020 16:52:37 +0800 Subject: [PATCH 0542/1216] Correct the wrong stop info --- Worker.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 365ca92fc..de3a347d6 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.11'; + const VERSION = '4.0.12'; /** * Status starting. @@ -803,7 +803,14 @@ protected static function displayUI() !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { - static::safeEcho("Input \"php $argv[0] stop\" to stop. Start success.\n\n"); + foreach ($argv as $index => $value) { + if ($value == '-d') { + unset($argv[$index]); + } elseif ($value == 'start') { + $argv[$index] = 'stop'; + } + } + static::safeEcho("Input \"php ".implode($argv, ' ')."\" to stop. Start success.\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } From 49708bb40e16cccb91aa1ffa841e64a34677a264 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 3 Oct 2020 19:25:24 +0800 Subject: [PATCH 0543/1216] for #570 --- Worker.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Worker.php b/Worker.php index de3a347d6..2743eac10 100644 --- a/Worker.php +++ b/Worker.php @@ -1191,11 +1191,7 @@ public static function signalHandler($signal) // Reload. case \SIGQUIT: case \SIGUSR1: - if($signal === \SIGQUIT){ - static::$_gracefulStop = true; - }else{ - static::$_gracefulStop = false; - } + static::$_gracefulStop = $signal === \SIGQUIT; static::$_pidsToRestart = static::getAllWorkerPids(); static::reload(); break; From 34abfc8550d669965b8a157001fe23a9785fdefc Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 13 Oct 2020 18:06:55 +0800 Subject: [PATCH 0544/1216] For #572 --- Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Worker.php b/Worker.php index 2743eac10..631874eb7 100644 --- a/Worker.php +++ b/Worker.php @@ -2208,6 +2208,8 @@ public function __construct($socket_name = '', array $context_option = array()) } $this->_context = \stream_context_create($context_option); } + + $this->parseSocketAddress(); // Turn reusePort on. if (static::$_OS === \OS_TYPE_LINUX // if linux From 9202712f4969163cbb2925fe26aecd0381485819 Mon Sep 17 00:00:00 2001 From: Jack Cherng Date: Tue, 13 Oct 2020 19:42:09 +0800 Subject: [PATCH 0545/1216] Simplify codes Signed-off-by: Jack Cherng --- Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 8353ef54e..424d02acc 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -458,8 +458,8 @@ protected function parsePost() $this->_data['post'] = static::$_postCache[$body_buffer]; return; } - $content_type = $this->header('content-type'); - if ($content_type !== null && \preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { + $content_type = $this->header('content-type', ''); + if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { $http_post_boundary = '--' . $match[1]; $this->parseUploadFiles($http_post_boundary); return; From 7ba4aca4217c047f050a9a315d49ef40baf242ed Mon Sep 17 00:00:00 2001 From: Jack Cherng Date: Tue, 13 Oct 2020 19:43:51 +0800 Subject: [PATCH 0546/1216] Make Http Request supports application/json Signed-off-by: Jack Cherng --- Protocols/Http/Request.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 424d02acc..0484f21d4 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -464,7 +464,11 @@ protected function parsePost() $this->parseUploadFiles($http_post_boundary); return; } - \parse_str($body_buffer, $this->_data['post']); + if (\preg_match('/\bjson\b/i', $content_type)) { + $this->_data['post'] = (array) json_decode($body_buffer, true); + } else { + \parse_str($body_buffer, $this->_data['post']); + } if ($cacheable) { static::$_postCache[$body_buffer] = $this->_data['post']; if (\count(static::$_postCache) > 256) { From 538624c7d5c8ccdab97c9e4d597bc91ffc5814ae Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 16 Oct 2020 17:13:37 +0800 Subject: [PATCH 0547/1216] Fix notice --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 631874eb7..30c4f1d3c 100644 --- a/Worker.php +++ b/Worker.php @@ -806,11 +806,11 @@ protected static function displayUI() foreach ($argv as $index => $value) { if ($value == '-d') { unset($argv[$index]); - } elseif ($value == 'start') { + } elseif ($value == 'start' || $value == 'restart') { $argv[$index] = 'stop'; } } - static::safeEcho("Input \"php ".implode($argv, ' ')."\" to stop. Start success.\n\n"); + static::safeEcho("Input \"php ".implode(' ', $argv)."\" to stop. Start success.\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } From 66f5d2ecdba823482b3c16601e8826239c23b598 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 16 Oct 2020 17:14:20 +0800 Subject: [PATCH 0548/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 30c4f1d3c..9c3d33365 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.12'; + const VERSION = '4.0.13'; /** * Status starting. From d088636879ac9b3394ae689effa3e44a3e510798 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 16 Oct 2020 17:20:36 +0800 Subject: [PATCH 0549/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 9c3d33365..d6fdb902c 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.13'; + const VERSION = '4.0.14'; /** * Status starting. From f9a664de75fd03bffa7670bfae4f593dac7467ec Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 17 Oct 2020 12:17:15 +0800 Subject: [PATCH 0550/1216] Fix autoload --- Worker.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 9c3d33365..e5e97ccd5 100644 --- a/Worker.php +++ b/Worker.php @@ -2208,14 +2208,12 @@ public function __construct($socket_name = '', array $context_option = array()) } $this->_context = \stream_context_create($context_option); } - - $this->parseSocketAddress(); // Turn reusePort on. if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && $this->transport !== 'unix') { // if not unix socket + && strpos($socket_name,'unix') !== 0) { // if not unix socket $this->reusePort = true; } From c8369ed141a83ca0a968b26e3218b25c92d4c006 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 28 Oct 2020 11:36:15 +0800 Subject: [PATCH 0551/1216] fix TypeError for php8 --- Worker.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index b2cac1507..9e03d3b35 100644 --- a/Worker.php +++ b/Worker.php @@ -1250,8 +1250,12 @@ public static function resetStd() if ($handle) { unset($handle); \set_error_handler(function(){}); - \fclose($STDOUT); - \fclose($STDERR); + if ($STDOUT) { + \fclose($STDOUT); + } + if ($STDERR) { + \fclose($STDERR); + } \fclose(\STDOUT); \fclose(\STDERR); $STDOUT = \fopen(static::$stdoutFile, "a"); From 580c2476d77a707879332125fa79fedb0ec74e9d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 28 Oct 2020 11:37:31 +0800 Subject: [PATCH 0552/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 9e03d3b35..6cf02bc80 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.14'; + const VERSION = '4.0.15'; /** * Status starting. From 5ea330083d2824196914a3a27e9e98892226010e Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Nov 2020 10:48:15 +0800 Subject: [PATCH 0553/1216] parse command use $argv --- Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 6cf02bc80..17e385b01 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.15'; + const VERSION = '4.0.16'; /** * Status starting. @@ -756,7 +756,7 @@ protected static function getCurrentUser() */ protected static function displayUI() { - $argv = $_SERVER['argv']; + global $argv; if (\in_array('-q', $argv)) { return; } @@ -867,7 +867,7 @@ protected static function parseCommand() if (static::$_OS !== \OS_TYPE_LINUX) { return; } - $argv = $_SERVER['argv']; + global $argv; // Check argv; $start_file = $argv[0]; $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; From 3279230d09eb1e38e45b10e6b2a94334d4913fc2 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Nov 2020 12:11:52 +0800 Subject: [PATCH 0554/1216] Update Response.php Add withoutHeader getHeader rawBody method for response --- Protocols/Http/Response.php | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 7075818a8..414c4dbfc 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -164,6 +164,17 @@ public function header($name, $value) { return $this; } + /** + * Set header. + * + * @param $name + * @param $value + * @return Response + */ + public function withHeader($name, $value) { + return $this->header($name, $value); + } + /** * Set headers. * @@ -174,6 +185,39 @@ public function withHeaders($headers) { $this->_header = \array_merge($this->_header, $headers); return $this; } + + /** + * Remove headers. + * + * @param $name + * @return $this + */ + public function withoutHeader($name) { + unset($this->_header[$name]); + return $this; + } + + /** + * Get header. + * + * @param $name + * @return null|array|string + */ + public function getHeader($name) { + if (!isset($this->_header[$name])) { + return null; + } + return $this->_header[$name]; + } + + /** + * Get header. + * + * @return array + */ + public function getHeaders() { + return $this->_header; + } /** * Set status. @@ -210,6 +254,13 @@ public function withBody($body) { return $this; } + /** + * Get http raw body. + */ + public function rawBody() { + return $this->_body; + } + /** * Send file. * From d3d3f6897980813aa97ae84260701a0faa4f610b Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Nov 2020 12:13:24 +0800 Subject: [PATCH 0555/1216] Update Response.php --- Protocols/Http/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 414c4dbfc..1067baddd 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -187,7 +187,7 @@ public function withHeaders($headers) { } /** - * Remove headers. + * Remove header. * * @param $name * @return $this @@ -211,7 +211,7 @@ public function getHeader($name) { } /** - * Get header. + * Get headers. * * @return array */ From 2998940bb6a3a684842585a248ca1524143858f6 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Nov 2020 12:14:54 +0800 Subject: [PATCH 0556/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 17e385b01..d9873bda4 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.16'; + const VERSION = '4.0.17'; /** * Status starting. From 8b9e917009d6abf10dad84f4ff91acd097f1c27f Mon Sep 17 00:00:00 2001 From: PHP8SoAppetizing Date: Mon, 14 Dec 2020 18:37:10 +0800 Subject: [PATCH 0557/1216] Fix the method_exists "Uncaught Type Error" problem in PHP8 --- Connection/AsyncTcpConnection.php | 2 +- Connection/TcpConnection.php | 4 ++-- Worker.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 1ee66fc4c..e976d29d3 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -352,7 +352,7 @@ public function checkConnection() } } // Try to emit protocol::onConnect - if (\method_exists($this->protocol, 'onConnect')) { + if (\is_callable($this->protocol, 'onConnect')) { try { \call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 5ab9f47fd..51db8fc03 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -271,7 +271,7 @@ class TcpConnection extends ConnectionInterface */ public function __call($name, array $arguments) { // Try to emit custom function within protocol - if (\method_exists($this->protocol, $name)) { + if (\is_callable($this->protocol, $name)) { try { return \call_user_func(array($this->protocol, $name), $this, $arguments); } catch (\Exception $e) { @@ -961,7 +961,7 @@ public function destroy() } } // Try to emit protocol::onClose - if ($this->protocol && \method_exists($this->protocol, 'onClose')) { + if ($this->protocol && \is_callable($this->protocol, 'onClose')) { try { \call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { diff --git a/Worker.php b/Worker.php index d9873bda4..00435cc39 100644 --- a/Worker.php +++ b/Worker.php @@ -2527,7 +2527,7 @@ public function acceptUdpConnection($socket) if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ $parser = $this->protocol; - if(\method_exists($parser,'input')){ + if(\is_callable($parser,'input')){ while($recv_buffer !== ''){ $len = $parser::input($recv_buffer, $connection); if($len === 0) From d26129e8e863b7670670c1be3ea5721a93e0fd5f Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 15 Dec 2020 21:22:15 +0800 Subject: [PATCH 0558/1216] Update Http.php --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 39c8b5ee4..441e5e740 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -196,7 +196,7 @@ public static function encode($response, TcpConnection $connection) $connection->__request->connection = null; $connection->__request = null; } - if (\is_scalar($response) || null === $response) { + if (!\is_object($response)) { $ext_header = ''; if (isset($connection->__header)) { foreach ($connection->__header as $name => $value) { From 6b4c890ac4dbea7e14adde50e556bc8710dbaf85 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 16 Dec 2020 14:37:49 +0800 Subject: [PATCH 0559/1216] Update --- Connection/AsyncTcpConnection.php | 2 +- Connection/TcpConnection.php | 25 +------------------------ Worker.php | 18 +++++++++--------- 3 files changed, 11 insertions(+), 34 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index e976d29d3..6d0c3b53e 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -352,7 +352,7 @@ public function checkConnection() } } // Try to emit protocol::onConnect - if (\is_callable($this->protocol, 'onConnect')) { + if ($this->protocol && \method_exists($this->protocol, 'onConnect')) { try { \call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 51db8fc03..28d8a0203 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -261,29 +261,6 @@ class TcpConnection extends ConnectionInterface self::STATUS_CLOSED => 'CLOSED', ); - - /** - * Adding support of custom functions within protocols - * - * @param string $name - * @param array $arguments - * @return void - */ - public function __call($name, array $arguments) { - // Try to emit custom function within protocol - if (\is_callable($this->protocol, $name)) { - try { - return \call_user_func(array($this->protocol, $name), $this, $arguments); - } catch (\Exception $e) { - Worker::log($e); - exit(250); - } catch (\Error $e) { - Worker::log($e); - exit(250); - } - } - } - /** * Construct. * @@ -961,7 +938,7 @@ public function destroy() } } // Try to emit protocol::onClose - if ($this->protocol && \is_callable($this->protocol, 'onClose')) { + if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { \call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { diff --git a/Worker.php b/Worker.php index 00435cc39..ac2bc6b31 100644 --- a/Worker.php +++ b/Worker.php @@ -2526,27 +2526,27 @@ public function acceptUdpConnection($socket) try { if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ - $parser = $this->protocol; - if(\is_callable($parser,'input')){ - while($recv_buffer !== ''){ + $parser = $this->protocol; + if ($parser && \method_exists($parser, 'input')) { + while ($recv_buffer !== '') { $len = $parser::input($recv_buffer, $connection); - if($len === 0) + if ($len === 0) return true; - $package = \substr($recv_buffer,0,$len); - $recv_buffer = \substr($recv_buffer,$len); - $data = $parser::decode($package,$connection); + $package = \substr($recv_buffer, 0, $len); + $recv_buffer = \substr($recv_buffer, $len); + $data = $parser::decode($package, $connection); if ($data === false) continue; \call_user_func($this->onMessage, $connection, $data); } - }else{ + } else { $data = $parser::decode($recv_buffer, $connection); // Discard bad packets. if ($data === false) return true; \call_user_func($this->onMessage, $connection, $data); } - }else{ + } else { \call_user_func($this->onMessage, $connection, $recv_buffer); } ++ConnectionInterface::$statistics['total_request']; From 030db165cde19b7512618d1ae8d662812d3b423a Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 31 Dec 2020 20:45:32 +0800 Subject: [PATCH 0560/1216] add getReasonPhrase getReasonPhrase --- Protocols/Http/Response.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 1067baddd..14e8ac135 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -232,6 +232,24 @@ public function withStatus($code, $reason_phrase = null) { return $this; } + /** + * Get status code. + * + * @return int + */ + public function getStatusCode() { + return $this->_status; + } + + /** + * Get reason phrase. + * + * @return string + */ + public function getReasonPhrase() { + return $this->_reason; + } + /** * Set protocol version. * From 45ec8f73cd650aa0e60aa1a666410edb7f1075e2 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 2 Jan 2021 14:12:34 +0800 Subject: [PATCH 0561/1216] Update Event.php --- Events/Event.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Events/Event.php b/Events/Event.php index c7d7aa261..3e305a13a 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -202,9 +202,7 @@ public function loop() */ public function destroy() { - foreach ($this->_eventSignal as $event) { - $event->del(); - } + $this->_eventBase->exit(); } /** From 02930876526479c7e4123ef1dc8d23d509d40e72 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 2 Jan 2021 14:14:59 +0800 Subject: [PATCH 0562/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index ac2bc6b31..1109e309e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.17'; + const VERSION = '4.0.18'; /** * Status starting. From d6fe4d5fc8dbbe1ab127fb9597ca31758fe27315 Mon Sep 17 00:00:00 2001 From: ronalfei Date: Thu, 14 Jan 2021 15:30:43 +0800 Subject: [PATCH 0563/1216] Strictly, to support SO_REUSEPORT need linux kernel >=3.9 --- Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Worker.php b/Worker.php index 1109e309e..93d3b21a1 100644 --- a/Worker.php +++ b/Worker.php @@ -2216,6 +2216,7 @@ public function __construct($socket_name = '', array $context_option = array()) // Turn reusePort on. if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS && strpos($socket_name,'unix') !== 0) { // if not unix socket From bc4b90bdfb528ff34bb360386336ae12bb7360d5 Mon Sep 17 00:00:00 2001 From: ronalfei Date: Thu, 14 Jan 2021 15:35:30 +0800 Subject: [PATCH 0564/1216] Strictly, to support SO_REUSEPORT need linux kernel >=3.9 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 93d3b21a1..72e052edf 100644 --- a/Worker.php +++ b/Worker.php @@ -2216,7 +2216,7 @@ public function __construct($socket_name = '', array $context_option = array()) // Turn reusePort on. if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 - && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 + && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS && strpos($socket_name,'unix') !== 0) { // if not unix socket From f67b2a55c9f5e77dab059d7e2e33ac7791b18279 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 19 Jan 2021 20:21:29 +0800 Subject: [PATCH 0565/1216] fix #589 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81bc7ee9e..796cab8e9 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ $http_worker->onMessage = function ($connection, $request) { //$request->post(); //$request->header(); //$request->cookie(); - //$requset->session(); + //$request->session(); //$request->uri(); //$request->path(); //$request->method(); From 5aa54e0c7aaa8279dc666fff7237679abcf72b59 Mon Sep 17 00:00:00 2001 From: her-cat Date: Wed, 27 Jan 2021 13:14:35 +0800 Subject: [PATCH 0566/1216] Check master is alive --- Worker.php | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 72e052edf..576a56606 100644 --- a/Worker.php +++ b/Worker.php @@ -909,9 +909,8 @@ protected static function parseCommand() // Get master process PID. $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0; - $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() !== $master_pid; // Master is still alive? - if ($master_is_alive) { + if (static::checkMasterIsAlive($master_pid)) { if ($command === 'start') { static::log("Workerman[$start_file] already running"); exit; @@ -2561,4 +2560,29 @@ public function acceptUdpConnection($socket) } return true; } + + /** + * Check master process is alive + * + * @param $master_pid + * @return bool + */ + protected static function checkMasterIsAlive($master_pid) + { + if (empty($master_pid)) { + return false; + } + + $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() !== $master_pid; + if (!$master_is_alive) { + return false; + } + + // Master process will send SIGUSR2 signal to all child processes. + \posix_kill($master_pid, SIGUSR2); + // Sleep 1 second. + \sleep(1); + + return stripos(static::formatStatusData(), 'PROCESS STATUS') !== false; + } } From 7bf8f21b2d36538b78a2159669e9e8d492a0eaf3 Mon Sep 17 00:00:00 2001 From: her-cat Date: Wed, 27 Jan 2021 17:42:27 +0800 Subject: [PATCH 0567/1216] Judge whether it is wokerman by process information --- Worker.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Worker.php b/Worker.php index 576a56606..68087181b 100644 --- a/Worker.php +++ b/Worker.php @@ -2578,11 +2578,14 @@ protected static function checkMasterIsAlive($master_pid) return false; } - // Master process will send SIGUSR2 signal to all child processes. - \posix_kill($master_pid, SIGUSR2); - // Sleep 1 second. - \sleep(1); + $cmdline = "/proc/{$master_pid}/cmdline"; + if (!is_readable($cmdline)) { + return true; + } + + $pattern = sprintf('#%s#', preg_quote(static::$processTitle)); + $subject = file_get_contents($cmdline); - return stripos(static::formatStatusData(), 'PROCESS STATUS') !== false; + return preg_match($pattern, $subject) > 0; } } From 3044f4327f1f3b9d5de35b1f4bb5df607cffc157 Mon Sep 17 00:00:00 2001 From: her-cat Date: Wed, 27 Jan 2021 17:56:42 +0800 Subject: [PATCH 0568/1216] Optimize code --- Worker.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index 68087181b..c2c709cbc 100644 --- a/Worker.php +++ b/Worker.php @@ -2579,13 +2579,15 @@ protected static function checkMasterIsAlive($master_pid) } $cmdline = "/proc/{$master_pid}/cmdline"; - if (!is_readable($cmdline)) { + if (!is_readable($cmdline) || empty(static::$processTitle)) { return true; } - $pattern = sprintf('#%s#', preg_quote(static::$processTitle)); - $subject = file_get_contents($cmdline); + $content = file_get_contents($cmdline); + if (empty($content)) { + return true; + } - return preg_match($pattern, $subject) > 0; + return stripos($content, static::$processTitle) !== false; } } From 5dbf3339e8566ec37772933d2313f8cfab4466c8 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 27 Jan 2021 19:38:33 +0800 Subject: [PATCH 0569/1216] __toString for Response --- Protocols/Http/Request.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 0484f21d4..57d73fa9a 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -604,6 +604,14 @@ public function __unset($name) unset($this->properties[$name]); } + /** + * __toString. + */ + public function __toString() + { + return $this->_buffer; + } + /** * __destruct. * From d743111c69e2cd0b0f542e4d9d6473e0e196c5e3 Mon Sep 17 00:00:00 2001 From: "weiwei163@foxmail.com" Date: Fri, 29 Jan 2021 18:56:58 +0800 Subject: [PATCH 0570/1216] fixed: Upload file support Chinese name --- Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 57d73fa9a..e10423d8a 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -504,7 +504,7 @@ protected function parseUploadFiles($http_post_boundary) switch ($header_key) { case "content-disposition": // Is file data. - if (\preg_match('/name="(.*?)"; filename="(.*?)"$/i', $header_value, $match)) { + if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) { $error = 0; $tmp_file = ''; $size = \strlen($boundary_value); From 6b95d8356a944df37c160b7d34b11b6e257f522e Mon Sep 17 00:00:00 2001 From: Alex Pavlov Date: Sat, 30 Jan 2021 17:57:15 +0300 Subject: [PATCH 0571/1216] Fix `parseHeaders` for request without headers Fix for case without headers `GET / HTTP 1.1\r\n` --- Protocols/Http/Request.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index e10423d8a..7019e1cfe 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -392,7 +392,13 @@ protected function parseHeaders() { $this->_data['headers'] = array(); $raw_head = $this->rawHead(); - $head_buffer = \substr($raw_head, \strpos($raw_head, "\r\n") + 2); + + $endFirsLinePosition = \strpos($raw_head, "\r\n"); + if ($endFirsLinePosition === false) { + return; + } + + $head_buffer = \substr($raw_head, $endFirsLinePosition + 2); $cacheable = static::$_enableCache && !isset($head_buffer[2048]); if ($cacheable && isset(static::$_headerCache[$head_buffer])) { $this->_data['headers'] = static::$_headerCache[$head_buffer]; From 839c5802bf85770529ac2ed0f1dc083428f74eea Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 7 Feb 2021 19:49:45 +0800 Subject: [PATCH 0572/1216] Update Request.php --- Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 7019e1cfe..8f9e5e02b 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -393,8 +393,8 @@ protected function parseHeaders() $this->_data['headers'] = array(); $raw_head = $this->rawHead(); - $endFirsLinePosition = \strpos($raw_head, "\r\n"); - if ($endFirsLinePosition === false) { + $end_line_position = \strpos($raw_head, "\r\n"); + if ($end_line_position === false) { return; } From 4892b61f16f5b5961dc26d9c0c61976894cfab58 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 7 Feb 2021 20:25:10 +0800 Subject: [PATCH 0573/1216] Fix #600 --- Protocols/Http/Request.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 8f9e5e02b..18a20ed08 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -392,13 +392,11 @@ protected function parseHeaders() { $this->_data['headers'] = array(); $raw_head = $this->rawHead(); - $end_line_position = \strpos($raw_head, "\r\n"); if ($end_line_position === false) { return; } - - $head_buffer = \substr($raw_head, $endFirsLinePosition + 2); + $head_buffer = \substr($raw_head, $end_line_position + 2); $cacheable = static::$_enableCache && !isset($head_buffer[2048]); if ($cacheable && isset(static::$_headerCache[$head_buffer])) { $this->_data['headers'] = static::$_headerCache[$head_buffer]; @@ -408,9 +406,16 @@ protected function parseHeaders() foreach ($head_data as $content) { if (false !== \strpos($content, ':')) { list($key, $value) = \explode(':', $content, 2); - $this->_data['headers'][\strtolower($key)] = \ltrim($value); + $key = \strtolower($key); + $value = \ltrim($value); } else { - $this->_data['headers'][\strtolower($content)] = ''; + $key = \strtolower($content); + $value = ''; + } + if (isset($this->_data['headers'][$key])) { + $this->_data['headers'][$key] = "{$this->_data['headers'][$key]},$value"; + } else { + $this->_data['headers'][$key] = $value; } } if ($cacheable) { From a1e0cca1917a8a96c21ad972f760729fea4342b6 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Mar 2021 14:38:30 +0800 Subject: [PATCH 0574/1216] Update Swoole.php --- Events/Swoole.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Events/Swoole.php b/Events/Swoole.php index ea828eb8d..f19620ab0 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -61,7 +61,11 @@ function () { $this->mapId = 0; } $mapId = $this->mapId++; - $timer_id = Timer::$method($fd * 1000, + $t = (int)($fd * 1000); + if ($t < 1) { + $t = 1; + } + $timer_id = Timer::$method($t, function ($timer_id = null) use ($func, $args, $mapId) { \call_user_func_array($func, $args); // EV_TIMER_ONCE From fc365b5bd0466a83348c8714845116d6ac83a7fc Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Mar 2021 14:41:44 +0800 Subject: [PATCH 0575/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c2c709cbc..31d9d6776 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.18'; + const VERSION = '4.0.19'; /** * Status starting. From af6025976fba817eeb4d5fbf8d0c1059a5819da3 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 5 Mar 2021 14:44:28 +0800 Subject: [PATCH 0576/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 31d9d6776..33c68af90 100644 --- a/Worker.php +++ b/Worker.php @@ -2213,14 +2213,14 @@ public function __construct($socket_name = '', array $context_option = array()) } // Turn reusePort on. - if (static::$_OS === \OS_TYPE_LINUX // if linux + /*if (static::$_OS === \OS_TYPE_LINUX // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS && strpos($socket_name,'unix') !== 0) { // if not unix socket $this->reusePort = true; - } + }*/ } From 041f6c42422829802cbff87d4fa8b5acbf0b3be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=83=AD=E5=BF=83=E7=BD=91=E5=8F=8B?= Date: Mon, 8 Mar 2021 15:09:41 +0800 Subject: [PATCH 0577/1216] Http/Request method(header, cookie, protocolVersion) return parameter type correction --- Protocols/Http/Request.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 18a20ed08..6be5944ab 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -139,7 +139,7 @@ public function post($name = null, $default = null) * * @param null $name * @param null $default - * @return string|null + * @return array|string|null */ public function header($name = null, $default = null) { @@ -158,7 +158,7 @@ public function header($name = null, $default = null) * * @param null $name * @param null $default - * @return string|null + * @return array|string|null */ public function cookie($name = null, $default = null) { @@ -204,7 +204,7 @@ public function method() /** * Get http protocol version. * - * @return string. + * @return string */ public function protocolVersion() { From a0864998e3593354b8dc69fd43efda80e7996219 Mon Sep 17 00:00:00 2001 From: Yurun Date: Tue, 9 Mar 2021 13:45:26 +0800 Subject: [PATCH 0578/1216] Fix missing type declarations and properties --- Connection/ConnectionInterface.php | 2 +- Connection/TcpConnection.php | 2 +- Connection/UdpConnection.php | 7 ++++ Events/Event.php | 2 +- Events/React/Base.php | 6 +-- Protocols/Http.php | 12 +++--- Protocols/Http/Chunk.php | 2 +- Protocols/Http/Request.php | 34 ++++++++--------- Protocols/Http/Response.php | 37 ++++++++++++------- Protocols/Http/Session.php | 32 ++++++++-------- Protocols/Http/Session/FileSessionHandler.php | 4 +- .../Http/Session/RedisSessionHandler.php | 2 +- Protocols/Ws.php | 2 +- Worker.php | 4 +- 14 files changed, 82 insertions(+), 66 deletions(-) diff --git a/Connection/ConnectionInterface.php b/Connection/ConnectionInterface.php index 05954e2cc..4d3f5e102 100644 --- a/Connection/ConnectionInterface.php +++ b/Connection/ConnectionInterface.php @@ -118,7 +118,7 @@ abstract public function isIPv6(); /** * Close connection. * - * @param $data + * @param string|null $data * @return void */ abstract public function close($data = null); diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 28d8a0203..dd6253ca0 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -716,7 +716,7 @@ public function baseWrite() /** * SSL handshake. * - * @param $socket + * @param resource $socket * @return bool */ public function doSslHandshake($socket){ diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 48c00928b..53bbfcaa7 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -26,6 +26,13 @@ class UdpConnection extends ConnectionInterface */ public $protocol = null; + /** + * Transport layer protocol. + * + * @var string + */ + public $transport = 'udp'; + /** * Udp socket. * diff --git a/Events/Event.php b/Events/Event.php index 3e305a13a..a86f84f4b 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -150,7 +150,7 @@ public function del($fd, $flag) /** * Timer callback. - * @param null $fd + * @param int|null $fd * @param int $what * @param int $timer_id */ diff --git a/Events/React/Base.php b/Events/React/Base.php index a0a33ae12..bce4f7356 100644 --- a/Events/React/Base.php +++ b/Events/React/Base.php @@ -54,9 +54,9 @@ public function __construct() /** * Add event listener to event loop. * - * @param $fd - * @param $flag - * @param $func + * @param int $fd + * @param int $flag + * @param callable $func * @param array $args * @return bool */ diff --git a/Protocols/Http.php b/Protocols/Http.php index 441e5e740..2b1625b62 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -56,7 +56,7 @@ class Http /** * Get or set session name. * - * @param null $name + * @param string|null $name * @return string */ public static function sessionName($name = null) @@ -70,7 +70,7 @@ public static function sessionName($name = null) /** * Get or set the request class name. * - * @param null $class_name + * @param string|null $class_name * @return string */ public static function requestClass($class_name = null) @@ -84,7 +84,7 @@ public static function requestClass($class_name = null) /** * Enable or disable Cache. * - * @param $value + * @param mixed $value */ public static function enableCache($value) { @@ -254,9 +254,9 @@ public static function encode($response, TcpConnection $connection) * Send remainder of a stream to client. * * @param TcpConnection $connection - * @param $handler - * @param $offset - * @param $length + * @param resource $handler + * @param int $offset + * @param int $length */ protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) { diff --git a/Protocols/Http/Chunk.php b/Protocols/Http/Chunk.php index 00f3570ed..ab06a9c20 100644 --- a/Protocols/Http/Chunk.php +++ b/Protocols/Http/Chunk.php @@ -29,7 +29,7 @@ class Chunk /** * Chunk constructor. - * @param $buffer + * @param string $buffer */ public function __construct($buffer) { diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 18a20ed08..02ef72faa 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -91,7 +91,7 @@ class Request /** * Request constructor. * - * @param $buffer + * @param string $buffer */ public function __construct($buffer) { @@ -101,8 +101,8 @@ public function __construct($buffer) /** * $_GET. * - * @param null $name - * @param null $default + * @param string|null $name + * @param mixed|null $default * @return mixed|null */ public function get($name = null, $default = null) @@ -119,8 +119,8 @@ public function get($name = null, $default = null) /** * $_POST. * - * @param $name - * @param null $default + * @param string|null $name + * @param mixed|null $default * @return mixed|null */ public function post($name = null, $default = null) @@ -137,8 +137,8 @@ public function post($name = null, $default = null) /** * Get header item by name. * - * @param null $name - * @param null $default + * @param string|null $name + * @param mixed|null $default * @return string|null */ public function header($name = null, $default = null) @@ -156,8 +156,8 @@ public function header($name = null, $default = null) /** * Get cookie item by name. * - * @param null $name - * @param null $default + * @param string|null $name + * @param mixed|null $default * @return string|null */ public function cookie($name = null, $default = null) @@ -174,7 +174,7 @@ public function cookie($name = null, $default = null) /** * Get upload files. * - * @param null $name + * @param string|null $name * @return array|null */ public function file($name = null) @@ -351,7 +351,7 @@ public function rawBuffer() /** * Enable or disable cache. * - * @param $value + * @param mixed $value */ public static function enableCache($value) { @@ -491,7 +491,7 @@ protected function parsePost() /** * Parse upload files. * - * @param $http_post_boundary + * @param string $http_post_boundary * @return void */ protected function parseUploadFiles($http_post_boundary) @@ -573,8 +573,8 @@ protected static function createSessionId() /** * Setter. * - * @param $name - * @param $value + * @param string $name + * @param mixed $value * @return void */ public function __set($name, $value) @@ -585,7 +585,7 @@ public function __set($name, $value) /** * Getter. * - * @param $name + * @param string $name * @return mixed|null */ public function __get($name) @@ -596,7 +596,7 @@ public function __get($name) /** * Isset. * - * @param $name + * @param string $name * @return bool */ public function __isset($name) @@ -607,7 +607,7 @@ public function __isset($name) /** * Unset. * - * @param $name + * @param string $name * @return void */ public function __unset($name) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 14e8ac135..9fdb249d4 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -54,6 +54,13 @@ class Response */ protected $_body = null; + /** + * Send file info + * + * @var array + */ + protected $file = null; + /** * Mine type map. * @var array @@ -155,8 +162,8 @@ public function __construct( /** * Set header. * - * @param $name - * @param $value + * @param string $name + * @param string $value * @return $this */ public function header($name, $value) { @@ -167,8 +174,8 @@ public function header($name, $value) { /** * Set header. * - * @param $name - * @param $value + * @param string $name + * @param string $value * @return Response */ public function withHeader($name, $value) { @@ -178,7 +185,7 @@ public function withHeader($name, $value) { /** * Set headers. * - * @param $headers + * @param array $headers * @return $this */ public function withHeaders($headers) { @@ -189,7 +196,7 @@ public function withHeaders($headers) { /** * Remove header. * - * @param $name + * @param string $name * @return $this */ public function withoutHeader($name) { @@ -200,7 +207,7 @@ public function withoutHeader($name) { /** * Get header. * - * @param $name + * @param string $name * @return null|array|string */ public function getHeader($name) { @@ -222,8 +229,8 @@ public function getHeaders() { /** * Set status. * - * @param $code - * @param null $reason_phrase + * @param int $code + * @param string|null $reason_phrase * @return $this */ public function withStatus($code, $reason_phrase = null) { @@ -253,7 +260,7 @@ public function getReasonPhrase() { /** * Set protocol version. * - * @param $version + * @param int $version * @return $this */ public function withProtocolVersion($version) { @@ -264,7 +271,7 @@ public function withProtocolVersion($version) { /** * Set http body. * - * @param $body + * @param string $body * @return $this */ public function withBody($body) { @@ -274,6 +281,8 @@ public function withBody($body) { /** * Get http raw body. + * + * @return string */ public function rawBody() { return $this->_body; @@ -282,7 +291,7 @@ public function rawBody() { /** * Send file. * - * @param $file + * @param string $file * @param int $offset * @param int $length * @return $this @@ -298,7 +307,7 @@ public function withFile($file, $offset = 0, $length = 0) { /** * Set cookie. * - * @param $name + * @param string $name * @param string $value * @param int $maxage * @param string $path @@ -321,7 +330,7 @@ public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = ' /** * Create header for file. * - * @param $file + * @param array $file_info * @return string */ protected function createHeadForFile($file_info) diff --git a/Protocols/Http/Session.php b/Protocols/Http/Session.php index 91d5cf5d8..0181a8e34 100644 --- a/Protocols/Http/Session.php +++ b/Protocols/Http/Session.php @@ -86,7 +86,7 @@ class Session /** * Session constructor. * - * @param $session_id + * @param string $session_id */ public function __construct($session_id) { @@ -113,8 +113,8 @@ public function getId() /** * Get session. * - * @param $name - * @param null $default + * @param string $name + * @param mixed|null $default * @return mixed|null */ public function get($name, $default = null) @@ -125,8 +125,8 @@ public function get($name, $default = null) /** * Store data in the session. * - * @param $name - * @param $value + * @param string $name + * @param mixed $value */ public function set($name, $value) { @@ -137,7 +137,7 @@ public function set($name, $value) /** * Delete an item from the session. * - * @param $name + * @param string $name */ public function delete($name) { @@ -148,8 +148,8 @@ public function delete($name) /** * Retrieve and delete an item from the session. * - * @param $name - * @param null $default + * @param string $name + * @param mixed|null $default * @return mixed|null */ public function pull($name, $default = null) @@ -162,8 +162,8 @@ public function pull($name, $default = null) /** * Store data in the session. * - * @param $key - * @param null $value + * @param string $key + * @param mixed|null $value */ public function put($key, $value = null) { @@ -181,7 +181,7 @@ public function put($key, $value = null) /** * Remove a piece of data from the session. * - * @param $name + * @param string $name */ public function forget($name) { @@ -221,7 +221,7 @@ public function flush() /** * Determining If An Item Exists In The Session. * - * @param $name + * @param string $name * @return bool */ public function has($name) @@ -232,7 +232,7 @@ public function has($name) /** * To determine if an item is present in the session, even if its value is null. * - * @param $name + * @param string $name * @return bool */ public function exists($name) @@ -280,8 +280,8 @@ public static function init() /** * Set session handler class. * - * @param null $class_name - * @param null $config + * @param mixed|null $class_name + * @param mixed|null $config * @return string */ public static function handlerClass($class_name = null, $config = null) @@ -336,7 +336,7 @@ public function __destruct() /** * Check session id. * - * @param $session_id + * @param string $session_id */ protected static function checkSessionId($session_id) { diff --git a/Protocols/Http/Session/FileSessionHandler.php b/Protocols/Http/Session/FileSessionHandler.php index 9baa34fdc..fc9780fbd 100644 --- a/Protocols/Http/Session/FileSessionHandler.php +++ b/Protocols/Http/Session/FileSessionHandler.php @@ -123,7 +123,7 @@ public function gc($maxlifetime) { /** * Get session file path. * - * @param $session_id + * @param string $session_id * @return string */ protected static function sessionFile($session_id) { @@ -133,7 +133,7 @@ protected static function sessionFile($session_id) { /** * Get or set session file path. * - * @param $path + * @param string $path * @return string */ public static function sessionSavePath($path) { diff --git a/Protocols/Http/Session/RedisSessionHandler.php b/Protocols/Http/Session/RedisSessionHandler.php index 4876ab708..3d64392b4 100644 --- a/Protocols/Http/Session/RedisSessionHandler.php +++ b/Protocols/Http/Session/RedisSessionHandler.php @@ -32,7 +32,7 @@ class RedisSessionHandler extends \SessionHandler /** * RedisSessionHandler constructor. - * @param $config = [ + * @param array $config = [ * 'host' => '127.0.0.1', * 'port' => 6379, * 'timeout' => 2, diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 7372187cb..94c81a414 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -336,7 +336,7 @@ public static function onConnect($connection) /** * Clean * - * @param $connection + * @param TcpConnection $connection */ public static function onClose($connection) { diff --git a/Worker.php b/Worker.php index 33c68af90..68fb82b89 100644 --- a/Worker.php +++ b/Worker.php @@ -2158,7 +2158,7 @@ public static function safeEcho($msg, $decorated = false) } /** - * @param null $stream + * @param resource|null $stream * @return bool|resource */ private static function outputStream($stream = null) @@ -2564,7 +2564,7 @@ public function acceptUdpConnection($socket) /** * Check master process is alive * - * @param $master_pid + * @param int $master_pid * @return bool */ protected static function checkMasterIsAlive($master_pid) From 1dc52bc56446b3af31c993521178c0140854241b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 22 Mar 2021 17:41:28 +0800 Subject: [PATCH 0579/1216] Disable react/event-loop by default. --- Worker.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Worker.php b/Worker.php index 33c68af90..bb12309af 100644 --- a/Worker.php +++ b/Worker.php @@ -1310,7 +1310,7 @@ protected static function getEventLoopName() } if ($loop_name) { - if (\interface_exists('\React\EventLoop\LoopInterface')) { + /*if (\interface_exists('\React\EventLoop\LoopInterface')) { switch ($loop_name) { case 'libevent': static::$eventLoopClass = '\Workerman\Events\React\ExtLibEventLoop'; @@ -1322,12 +1322,12 @@ protected static function getEventLoopName() static::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop'; break; } - } else { + } else {*/ static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; - } - } else { + //} + }/* else { static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface') ? '\Workerman\Events\React\StreamSelectLoop' : '\Workerman\Events\Select'; - } + }*/ return static::$eventLoopClass; } From 116614cbea0d6b6cb79748b18319c27a425560e2 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 24 Mar 2021 09:29:22 +0800 Subject: [PATCH 0580/1216] Update Worker.php --- Worker.php | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/Worker.php b/Worker.php index bb12309af..87e286446 100644 --- a/Worker.php +++ b/Worker.php @@ -1310,24 +1310,10 @@ protected static function getEventLoopName() } if ($loop_name) { - /*if (\interface_exists('\React\EventLoop\LoopInterface')) { - switch ($loop_name) { - case 'libevent': - static::$eventLoopClass = '\Workerman\Events\React\ExtLibEventLoop'; - break; - case 'event': - static::$eventLoopClass = '\Workerman\Events\React\ExtEventLoop'; - break; - default : - static::$eventLoopClass = '\Workerman\Events\React\StreamSelectLoop'; - break; - } - } else {*/ - static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; - //} - }/* else { - static::$eventLoopClass = \interface_exists('\React\EventLoop\LoopInterface') ? '\Workerman\Events\React\StreamSelectLoop' : '\Workerman\Events\Select'; - }*/ + static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; + } else { + static::$eventLoopClass = '\Workerman\Events\Select'; + } return static::$eventLoopClass; } @@ -2591,3 +2577,4 @@ protected static function checkMasterIsAlive($master_pid) return stripos($content, static::$processTitle) !== false; } } + From a9a00833fd09c090304b40c4e5ddc3eda2ee4432 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 28 Mar 2021 15:51:26 +0800 Subject: [PATCH 0581/1216] reset stream_select return value --- Events/Select.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index 8b7e1af63..b61ba5f88 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -261,9 +261,10 @@ public function loop() \pcntl_signal_dispatch(); } - $read = $this->_readFds; - $write = $this->_writeFds; + $read = $this->_readFds; + $write = $this->_writeFds; $except = $this->_exceptFds; + $ret = false; if ($read || $write || $except) { // Waiting read/write/signal/timeout events. From 202ea7b4def5c7eef176b766e2423b90cad0d455 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 29 Mar 2021 11:13:51 +0800 Subject: [PATCH 0582/1216] avoid statistics file conflicts --- Worker.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Worker.php b/Worker.php index 87e286446..2e9245377 100644 --- a/Worker.php +++ b/Worker.php @@ -598,7 +598,6 @@ protected static function init() // For statistics. static::$_globalStatistics['start_timestamp'] = \time(); - static::$_statisticsFile = \sys_get_temp_dir() . "/$unique_prefix.status"; // Process title. static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$_startFile); @@ -645,6 +644,7 @@ protected static function initWorkers() if (static::$_OS !== \OS_TYPE_LINUX) { return; } + static::$_statisticsFile = \sys_get_temp_dir() . "/".posix_getpid().".status"; foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -920,6 +920,8 @@ protected static function parseCommand() exit; } + $statistics_file = \sys_get_temp_dir() . "/".$master_pid.".status";; + // execute command. switch ($command) { case 'start': @@ -929,8 +931,8 @@ protected static function parseCommand() break; case 'status': while (1) { - if (\is_file(static::$_statisticsFile)) { - @\unlink(static::$_statisticsFile); + if (\is_file($statistics_file)) { + @\unlink($statistics_file); } // Master process will send SIGUSR2 signal to all child processes. \posix_kill($master_pid, SIGUSR2); @@ -941,7 +943,7 @@ protected static function parseCommand() static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - static::safeEcho(static::formatStatusData()); + static::safeEcho(static::formatStatusData($statistics_file)); if ($mode !== '-d') { exit(0); } @@ -949,16 +951,16 @@ protected static function parseCommand() } exit(0); case 'connections': - if (\is_file(static::$_statisticsFile) && \is_writable(static::$_statisticsFile)) { - \unlink(static::$_statisticsFile); + if (\is_file($statistics_file) && \is_writable($statistics_file)) { + \unlink($statistics_file); } // Master process will send SIGIO signal to all child processes. \posix_kill($master_pid, SIGIO); // Waiting amoment. \usleep(500000); // Display statisitcs data from a disk file. - if(\is_readable(static::$_statisticsFile)) { - \readfile(static::$_statisticsFile); + if(\is_readable($statistics_file)) { + \readfile($statistics_file); } exit(0); case 'restart': @@ -1020,15 +1022,16 @@ protected static function parseCommand() /** * Format status data. * + * @param $statistics_file * @return string */ - protected static function formatStatusData() + protected static function formatStatusData($statistics_file) { static $total_request_cache = array(); - if (!\is_readable(static::$_statisticsFile)) { + if (!\is_readable($statistics_file)) { return ''; } - $info = \file(static::$_statisticsFile, \FILE_IGNORE_NEW_LINES); + $info = \file($statistics_file, \FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } From 90f9e654b91778f4471223b4f134f9d68ec9fd62 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 12 Apr 2021 21:00:30 +0800 Subject: [PATCH 0583/1216] response 413 when package reach max size --- Protocols/Http.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Protocols/Http.php b/Protocols/Http.php index 441e5e740..797d55002 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -145,6 +145,10 @@ public static function input($recv_buffer, TcpConnection $connection) unset($input[key($input)]); } } + if ($length > $connection->maxPackageSize) { + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + return 0; + } return $length; } From c4b743016109bd3aa75c7cb0dab45112be15bf42 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Apr 2021 15:15:36 +0800 Subject: [PATCH 0584/1216] Fix #614 --- Protocols/Http/Request.php | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index b972a6e3e..8457fe646 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -496,13 +496,14 @@ protected function parsePost() */ protected function parseUploadFiles($http_post_boundary) { - $http_body = $this->rawBody(); - $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); + $http_post_boundary = \trim($http_post_boundary, '"'); + $http_body = $this->rawBody(); + $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); - if ($boundary_data_array[0] === '') { + if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") { unset($boundary_data_array[0]); } - $key = -1; + $key = -1; $files = array(); foreach ($boundary_data_array as $boundary_data_buffer) { list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); @@ -516,9 +517,9 @@ protected function parseUploadFiles($http_post_boundary) case "content-disposition": // Is file data. if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) { - $error = 0; - $tmp_file = ''; - $size = \strlen($boundary_value); + $error = 0; + $tmp_file = ''; + $size = \strlen($boundary_value); $tmp_upload_dir = HTTP::uploadTmpDir(); if (!$tmp_upload_dir) { $error = UPLOAD_ERR_NO_TMP_DIR; @@ -528,13 +529,16 @@ protected function parseUploadFiles($http_post_boundary) $error = UPLOAD_ERR_CANT_WRITE; } } + if (!isset($files[$key])) { + $files[$key] = array(); + } // Parse upload files. - $files[$key] = array( - 'key' => $match[1], - 'name' => $match[2], + $files[$key] += array( + 'key' => $match[1], + 'name' => $match[2], 'tmp_name' => $tmp_file, - 'size' => $size, - 'error' => $error + 'size' => $size, + 'error' => $error ); break; } // Is post field. @@ -547,16 +551,20 @@ protected function parseUploadFiles($http_post_boundary) break; case "content-type": // add file_type + if (!isset($files[$key])) { + $files[$key] = array(); + } $files[$key]['type'] = \trim($header_value); break; } } } - foreach ($files as $file) { - $key = $file['key']; - unset($file['key']); - $this->_data['files'][$key] = $file; + if (isset($file['key'])) { + $key = $file['key']; + unset($file['key']); + $this->_data['files'][$key] = $file; + } } } From 6f8c15b4c0a02a2ecbf3e782bcfad8123d7d2321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=87=E5=B0=91=E6=B3=A2?= <756684177@qq.com> Date: Thu, 15 Apr 2021 15:35:48 +0800 Subject: [PATCH 0585/1216] php7.4 declare(strict_types=1); TypeError: posix_kill() expects parameter 1 to be int, string given --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index bf040c272..2c9ec39aa 100644 --- a/Worker.php +++ b/Worker.php @@ -981,7 +981,7 @@ protected static function parseCommand() $start_time = \time(); // Check master process is still alive? while (1) { - $master_is_alive = $master_pid && \posix_kill($master_pid, 0); + $master_is_alive = $master_pid && \posix_kill((int) $master_pid, 0); if ($master_is_alive) { // Timeout? if (!static::$_gracefulStop && \time() - $start_time >= $timeout) { @@ -2562,7 +2562,7 @@ protected static function checkMasterIsAlive($master_pid) return false; } - $master_is_alive = $master_pid && \posix_kill($master_pid, 0) && \posix_getpid() !== $master_pid; + $master_is_alive = $master_pid && \posix_kill((int) $master_pid, 0) && \posix_getpid() !== $master_pid; if (!$master_is_alive) { return false; } From 4d1e8da040cb6036cc1c0b1431e03a8a2a78eec6 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 May 2021 00:04:13 +0800 Subject: [PATCH 0586/1216] fix #619 --- Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 9fdb249d4..6f639ab14 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -59,7 +59,7 @@ class Response * * @var array */ - protected $file = null; + public $file = null; /** * Mine type map. From 6328f5c75b6cb9a367a66ee5e07b9b5f84ae9d6b Mon Sep 17 00:00:00 2001 From: latypoff Date: Fri, 28 May 2021 20:22:20 +0600 Subject: [PATCH 0587/1216] Fix security bug Session might be reused by third party client since $_data persists between requests when cache enabled (which is by default) --- Protocols/Http/Request.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 8457fe646..91ac46e0f 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -292,7 +292,7 @@ public function session() */ public function sessionId() { - if (!isset($this->_data['sid'])) { + if (!isset($this->sid)) { $session_name = Http::sessionName(); $sid = $this->cookie($session_name); if ($sid === '' || $sid === null) { @@ -310,9 +310,9 @@ public function sessionId() . (!$cookie_params['secure'] ? '' : '; Secure') . (!$cookie_params['httponly'] ? '' : '; HttpOnly')); } - $this->_data['sid'] = $sid; + $this->sid = $sid; } - return $this->_data['sid']; + return $this->sid; } /** From 7b3dc485e65b8bc64a0fde6b2a82a3c57ae790d7 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 8 Jun 2021 00:01:26 +0800 Subject: [PATCH 0588/1216] For #629 --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 2c9ec39aa..3cfb01857 100644 --- a/Worker.php +++ b/Worker.php @@ -644,7 +644,7 @@ protected static function initWorkers() if (static::$_OS !== \OS_TYPE_LINUX) { return; } - static::$_statisticsFile = \sys_get_temp_dir() . "/".posix_getpid().".status"; + static::$_statisticsFile = __DIR__ . '/../workerman-' .posix_getpid().'.status'; foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -920,7 +920,7 @@ protected static function parseCommand() exit; } - $statistics_file = \sys_get_temp_dir() . "/".$master_pid.".status";; + $statistics_file = __DIR__ . "/../workerman-$master_pid.status"; // execute command. switch ($command) { From 0032010fdc60a85e018ac98ecb3e1654a415fbcc Mon Sep 17 00:00:00 2001 From: gethin Date: Thu, 10 Jun 2021 16:42:13 +0800 Subject: [PATCH 0589/1216] intval --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 3cfb01857..c206b5574 100644 --- a/Worker.php +++ b/Worker.php @@ -908,7 +908,7 @@ protected static function parseCommand() static::log("Workerman[$start_file] $command $mode_str"); // Get master process PID. - $master_pid = \is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0; + $master_pid = intval(\is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0); // Master is still alive? if (static::checkMasterIsAlive($master_pid)) { if ($command === 'start') { From 9d026baf2c3ca389ca029e17f68081cbecd0b21e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Jun 2021 17:20:11 +0800 Subject: [PATCH 0590/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index c206b5574..a322c0d56 100644 --- a/Worker.php +++ b/Worker.php @@ -908,7 +908,7 @@ protected static function parseCommand() static::log("Workerman[$start_file] $command $mode_str"); // Get master process PID. - $master_pid = intval(\is_file(static::$pidFile) ? \file_get_contents(static::$pidFile) : 0); + $master_pid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0) // Master is still alive? if (static::checkMasterIsAlive($master_pid)) { if ($command === 'start') { From c202bbe441b3fe02f3d38de75dd9bbb64997afb8 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Jun 2021 18:01:43 +0800 Subject: [PATCH 0591/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a322c0d56..c2ae8cbc0 100644 --- a/Worker.php +++ b/Worker.php @@ -908,7 +908,7 @@ protected static function parseCommand() static::log("Workerman[$start_file] $command $mode_str"); // Get master process PID. - $master_pid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0) + $master_pid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; // Master is still alive? if (static::checkMasterIsAlive($master_pid)) { if ($command === 'start') { From cddba832f9376e67e116644a116a964cf1ab43ae Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Jun 2021 17:16:17 +0800 Subject: [PATCH 0592/1216] https://github.com/walkor/webman/issues/202 --- Protocols/Http/Request.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 91ac46e0f..9e365a81b 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -560,9 +560,13 @@ protected function parseUploadFiles($http_post_boundary) } } foreach ($files as $file) { - if (isset($file['key'])) { - $key = $file['key']; - unset($file['key']); + $key = $file['key']; + unset($file['key']); + // Multi files + if (\strlen($key) > 2 && \substr($key, -2) == '[]') { + $key = \substr($key, 0, -2); + $this->_data['files'][$key][] = $file; + } else { $this->_data['files'][$key] = $file; } } @@ -640,9 +644,14 @@ public function __destruct() { if (isset($this->_data['files'])) { \clearstatcache(); - foreach ($this->_data['files'] as $item) { - if (\is_file($item['tmp_name'])) { - \unlink($item['tmp_name']); + foreach ($this->_data['files'] as $items) { + if (!\is_array(\current($items))) { + $items = [$items]; + } + foreach ($items as $item) { + if (\is_file($item['tmp_name'])) { + \unlink($item['tmp_name']); + } } } } From 4a506c1baff5f9ee93aca1649afecdf50d162302 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Jun 2021 17:31:59 +0800 Subject: [PATCH 0593/1216] For #635 --- Protocols/Http/Response.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 6f639ab14..4d11608ab 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -307,23 +307,25 @@ public function withFile($file, $offset = 0, $length = 0) { /** * Set cookie. * - * @param string $name + * @param $name * @param string $value - * @param int $maxage + * @param int $max_age * @param string $path * @param string $domain * @param bool $secure * @param bool $http_only + * @param bool $same_site * @return $this */ - public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false) + public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) { $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) . (empty($max_age) ? '' : '; Max-Age=' . $max_age) . (empty($path) ? '' : '; Path=' . $path) . (!$secure ? '' : '; Secure') - . (!$http_only ? '' : '; HttpOnly'); + . (!$http_only ? '' : '; HttpOnly') + . (empty($same_site ) ? '' : '; SameSite=' . $same_site); return $this; } From 72163577429c3a39bee2c5729d5d32014eb6b2a6 Mon Sep 17 00:00:00 2001 From: Aleksandr <48223516+jarodtomsk@users.noreply.github.com> Date: Thu, 17 Jun 2021 14:09:43 +0700 Subject: [PATCH 0594/1216] Add support for PATCH HTTP method --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index 6a77a1b12..be3599fba 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -125,7 +125,7 @@ public static function input($recv_buffer, TcpConnection $connection) } } return $head_len; - } else if ($method !== 'POST' && $method !== 'PUT') { + } else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'PATCH') { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } From 36a25eb8bebe556335e7d907042ff0cc7a52ba51 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Sun, 18 Jul 2021 22:50:04 +0800 Subject: [PATCH 0595/1216] Add support the relative disk path for UNIX DOMAIN SOCKET --- Connection/AsyncTcpConnection.php | 7 ++++++- Worker.php | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 6d0c3b53e..9cdda9793 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -114,6 +114,9 @@ public function __construct($remote_address, array $context_option = array()) $address_info = \parse_url($remote_address); if (!$address_info) { list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2); + if('unix' === strtolower($scheme)) { + $this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); + } if (!$this->_remoteAddress) { Worker::safeEcho(new \Exception('bad remote_address')); } @@ -129,11 +132,13 @@ public function __construct($remote_address, array $context_option = array()) } else { $address_info['query'] = '?' . $address_info['query']; } - $this->_remoteAddress = "{$address_info['host']}:{$address_info['port']}"; $this->_remoteHost = $address_info['host']; $this->_remotePort = $address_info['port']; $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; + $this->_remoteAddress = 'unix' === strtolower($scheme) + ? substr($remote_address, strpos($remote_address, '/') + 2) + : $this->_remoteHost . ':' . $this->_remotePort; } $this->id = $this->_id = self::$_idRecorder++; diff --git a/Worker.php b/Worker.php index c2ae8cbc0..65e754aca 100644 --- a/Worker.php +++ b/Worker.php @@ -1716,6 +1716,7 @@ protected static function exitAndClearAll() $socket_name = $worker->getSocketName(); if ($worker->transport === 'unix' && $socket_name) { list(, $address) = \explode(':', $socket_name, 2); + $address = substr($address, strpos($address, '/') + 2); @\unlink($address); } } From f046a28ab2efc7d26e0d142588a31772de87a80a Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 23 Jul 2021 11:23:12 +0800 Subject: [PATCH 0596/1216] fix #646 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 65e754aca..35182eb4f 100644 --- a/Worker.php +++ b/Worker.php @@ -2578,7 +2578,7 @@ protected static function checkMasterIsAlive($master_pid) return true; } - return stripos($content, static::$processTitle) !== false; + return stripos($content, static::$processTitle) !== false || stripos($content, 'php') !== false; } } From 79bab10f84693954e69e37728af00fd812116b7e Mon Sep 17 00:00:00 2001 From: liujian Date: Mon, 26 Jul 2021 10:42:08 +0800 Subject: [PATCH 0597/1216] fix:last-modified:304 failure --- Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 4d11608ab..61a21266f 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -375,7 +375,7 @@ protected function createHeadForFile($file_info) if (!isset($headers['Last-Modified'])) { if ($mtime = \filemtime($file)) { - $head .= 'Last-Modified: '.\date('D, d M Y H:i:s', $mtime) . ' ' . \date_default_timezone_get() ."\r\n"; + $head .= 'Last-Modified: '. \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; } } From c5ec1f5a12cde1f00009c40f05e560c26e74f96b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Sep 2021 20:46:25 +0800 Subject: [PATCH 0598/1216] fix spelling error #655 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 35182eb4f..4e5200554 100644 --- a/Worker.php +++ b/Worker.php @@ -1209,7 +1209,7 @@ public static function signalHandler($signal) } /** - * Run as deamon mode. + * Run as daemon mode. * * @throws Exception */ From 70583984c977fbcf9663e9da943cae359df17463 Mon Sep 17 00:00:00 2001 From: mrchenzifan Date: Sun, 26 Sep 2021 17:17:48 +0800 Subject: [PATCH 0599/1216] Update Select.php update php8.1 Deprecated: Implicit conversion from float 9999.999 to int loses precision --- Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index b61ba5f88..cc0d98cdd 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -273,7 +273,7 @@ public function loop() } catch (\Exception $e) {} catch (\Error $e) {} } else { - usleep($this->_selectTimeout); + usleep((int)$this->_selectTimeout); $ret = false; } From 115fe66591ae5d221420d16cbcecda1125d1680a Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 27 Sep 2021 23:04:03 +0800 Subject: [PATCH 0600/1216] #653 --- Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Events/Select.php b/Events/Select.php index cc0d98cdd..1737b6682 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -273,7 +273,7 @@ public function loop() } catch (\Exception $e) {} catch (\Error $e) {} } else { - usleep((int)$this->_selectTimeout); + $this->_selectTimeout >= 1 && usleep((int)$this->_selectTimeout); $ret = false; } From dc6549905cdbb68485544b20a34649be9268bf94 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Oct 2021 10:58:08 +0800 Subject: [PATCH 0601/1216] fix close for onWebSocketConnect --- Protocols/Websocket.php | 49 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index f00b14700..260d5c99b 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -385,11 +385,34 @@ public static function dealHandshake($buffer, TcpConnection $connection) $has_server_header = false; + if (isset($connection->headers)) { + if (\is_array($connection->headers)) { + foreach ($connection->headers as $header) { + if (\strpos($header, 'Server:') === 0) { + $has_server_header = true; + } + $handshake_message .= "$header\r\n"; + } + } else { + $handshake_message .= "$connection->headers\r\n"; + } + } + if (!$has_server_header) { + $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; + } + $handshake_message .= "\r\n"; + // Send handshake response. + $connection->send($handshake_message, true); + // Mark handshake complete.. + $connection->websocketHandshake = true; + // Try to emit onWebSocketConnect callback. - if (isset($connection->onWebSocketConnect) || isset($connection->worker->onWebSocketConnect)) { + $on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect : + (isset($connection->worker->onWebSocketConnect) ? $connection->worker->onWebSocketConnect : false); + if ($on_websocket_connect) { static::parseHttpHeader($buffer); try { - \call_user_func(isset($connection->onWebSocketConnect)?$connection->onWebSocketConnect:$connection->worker->onWebSocketConnect, $connection, $buffer); + \call_user_func($on_websocket_connect, $connection, $buffer); } catch (\Exception $e) { Worker::log($e); exit(250); @@ -401,28 +424,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); - - if (isset($connection->headers)) { - if (\is_array($connection->headers)) { - foreach ($connection->headers as $header) { - if (\strpos($header, 'Server:') === 0) { - $has_server_header = true; - } - $handshake_message .= "$header\r\n"; - } - } else { - $handshake_message .= "$connection->headers\r\n"; - } - } - } - if (!$has_server_header) { - $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; } - $handshake_message .= "\r\n"; - // Send handshake response. - $connection->send($handshake_message, true); - // Mark handshake complete.. - $connection->websocketHandshake = true; + // There are data waiting to be sent. if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); From 3645c61ece467320f51f818ab8475377fa83b55b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Oct 2021 11:00:26 +0800 Subject: [PATCH 0602/1216] v4.0.20 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 4e5200554..7b1a271c9 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.19'; + const VERSION = '4.0.20'; /** * Status starting. From 1483692c5ecaa979f2d4dd92684bdad7e39c60cc Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Oct 2021 11:23:43 +0800 Subject: [PATCH 0603/1216] Update Websocket.php --- Protocols/Websocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 260d5c99b..2d14dbf6e 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -355,7 +355,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

Websocket


powered by workerman ".Worker::VERSION."
", + $connection->send("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", true); $connection->close(); return 0; @@ -443,7 +443,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } // Bad websocket handshake request. - $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

Websocket


powered by workerman ".Worker::VERSION."
", + $connection->send("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", true); $connection->close(); return 0; From 2ac7cef18303b0db0fc5cb2c3536f0209621b9fa Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Oct 2021 14:23:50 +0800 Subject: [PATCH 0604/1216] Remove forced display error For #442 --- Lib/Constants.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Lib/Constants.php b/Lib/Constants.php index f82a781da..f5e242411 100644 --- a/Lib/Constants.php +++ b/Lib/Constants.php @@ -13,11 +13,7 @@ * @link http://www.workerman.net/ */ -// Display errors. -ini_set('display_errors', 'on'); -// Reporting all. -error_reporting(E_ALL); -// JIT is not stable, temporarily disabled. +// Pcre.jit is not stable, temporarily disabled. ini_set('pcre.jit', 0); // For onError callback. From d19480d822e30317ff1e340c9aea8e08bd807108 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 11 Oct 2021 17:13:45 +0800 Subject: [PATCH 0605/1216] fix "Failed to invoke event callback" for php8 --- Connection/AsyncTcpConnection.php | 18 ++++------- Connection/AsyncUdpConnection.php | 18 ++++------- Connection/TcpConnection.php | 54 +++++++++++-------------------- Events/Ev.php | 12 +++---- Events/Event.php | 6 ++-- Events/EventInterface.php | 4 +-- Events/Libevent.php | 6 ++-- Events/Swoole.php | 14 +++++--- Protocols/Websocket.php | 36 +++++++-------------- Protocols/Ws.php | 36 +++++++-------------- Worker.php | 49 ++++++++++++---------------- 11 files changed, 94 insertions(+), 159 deletions(-) diff --git a/Connection/AsyncTcpConnection.php b/Connection/AsyncTcpConnection.php index 9cdda9793..600d700be 100644 --- a/Connection/AsyncTcpConnection.php +++ b/Connection/AsyncTcpConnection.php @@ -281,11 +281,9 @@ protected function emitError($code, $msg) try { \call_user_func($this->onError, $this, $code, $msg); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } @@ -349,11 +347,9 @@ public function checkConnection() try { \call_user_func($this->onConnect, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } // Try to emit protocol::onConnect @@ -361,11 +357,9 @@ public function checkConnection() try { \call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } else { diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index 7df93ad12..e8f2e7ce5 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -98,11 +98,9 @@ public function baseRead($socket) try { \call_user_func($this->onMessage, $this, $recv_buffer); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return true; @@ -152,11 +150,9 @@ public function close($data = null, $raw = false) try { \call_user_func($this->onClose, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } $this->onConnect = $this->onMessage = $this->onClose = null; @@ -197,11 +193,9 @@ public function connect() try { \call_user_func($this->onConnect, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index dd6253ca0..4e057a441 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -369,11 +369,9 @@ public function send($send_buffer, $raw = false) try { \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } $this->destroy(); @@ -636,11 +634,9 @@ public function baseRead($socket, $check_eof = true) // Decode request buffer before Emitting onMessage callback. \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return; @@ -659,11 +655,9 @@ public function baseRead($socket, $check_eof = true) try { \call_user_func($this->onMessage, $this, $this->_recvBuffer); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } // Clean receive buffer. $this->_recvBuffer = ''; @@ -692,11 +686,9 @@ public function baseWrite() try { \call_user_func($this->onBufferDrain, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } if ($this->_status === self::STATUS_CLOSING) { @@ -762,11 +754,9 @@ public function doSslHandshake($socket){ try { \call_user_func($this->onSslHandshake, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return true; @@ -859,11 +849,9 @@ protected function checkBufferWillFull() try { \call_user_func($this->onBufferFull, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } @@ -882,11 +870,9 @@ protected function bufferIsFull() try { \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return true; @@ -930,11 +916,9 @@ public function destroy() try { \call_user_func($this->onClose, $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } // Try to emit protocol::onClose @@ -942,11 +926,9 @@ public function destroy() try { \call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } $this->_sendBuffer = $this->_recvBuffer = ''; diff --git a/Events/Ev.php b/Events/Ev.php index 8dba8606e..82c9bdff6 100644 --- a/Events/Ev.php +++ b/Events/Ev.php @@ -59,11 +59,9 @@ public function add($fd, $flag, $func, $args = null) try { \call_user_func($func, $fd); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } }; switch ($flag) { @@ -140,11 +138,9 @@ public function timerCallback(EvWatcher $event) try { \call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } diff --git a/Events/Event.php b/Events/Event.php index a86f84f4b..9e25521c0 100644 --- a/Events/Event.php +++ b/Events/Event.php @@ -166,11 +166,9 @@ public function timerCallback($fd, $what, $param) try { \call_user_func_array($param[0], $param[1]); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } diff --git a/Events/EventInterface.php b/Events/EventInterface.php index 88f38f2a8..e6f59c649 100644 --- a/Events/EventInterface.php +++ b/Events/EventInterface.php @@ -63,10 +63,10 @@ interface EventInterface * @param mixed $fd * @param int $flag * @param callable $func - * @param mixed $args + * @param array $args * @return bool */ - public function add($fd, $flag, $func, $args = null); + public function add($fd, $flag, $func, $args = array()); /** * Remove event listener from event loop. diff --git a/Events/Libevent.php b/Events/Libevent.php index ac3427c77..5f61e9c2a 100644 --- a/Events/Libevent.php +++ b/Events/Libevent.php @@ -172,11 +172,9 @@ protected function timerCallback($_null1, $_null2, $timer_id) try { \call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { $this->del($timer_id, self::EV_TIMER_ONCE); diff --git a/Events/Swoole.php b/Events/Swoole.php index f19620ab0..fcd747238 100644 --- a/Events/Swoole.php +++ b/Events/Swoole.php @@ -13,6 +13,7 @@ */ namespace Workerman\Events; +use Workerman\Worker; use Swoole\Event; use Swoole\Timer; @@ -38,11 +39,8 @@ class Swoole implements EventInterface * * @see \Workerman\Events\EventInterface::add() */ - public function add($fd, $flag, $func, $args = null) + public function add($fd, $flag, $func, $args = array()) { - if (! isset($args)) { - $args = array(); - } switch ($flag) { case self::EV_SIGNAL: $res = \pcntl_signal($fd, $func, false); @@ -67,7 +65,13 @@ function () { } $timer_id = Timer::$method($t, function ($timer_id = null) use ($func, $args, $mapId) { - \call_user_func_array($func, $args); + try { + \call_user_func_array($func, (array)$args); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { + Worker::stopAll(250, $e); + } // EV_TIMER_ONCE if (! isset($timer_id)) { // may be deleted in $func diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index 2d14dbf6e..d32238435 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -94,11 +94,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } // Close connection. else { @@ -157,11 +155,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } else { $connection->send($ping_data); @@ -183,11 +179,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } $connection->websocketType = $tmp_connection_type; @@ -263,11 +257,9 @@ public static function encode($buffer, ConnectionInterface $connection) try { \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return ''; @@ -279,11 +271,9 @@ public static function encode($buffer, ConnectionInterface $connection) try { \call_user_func($connection->onBufferFull, $connection); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } @@ -414,11 +404,9 @@ public static function dealHandshake($buffer, TcpConnection $connection) try { \call_user_func($on_websocket_connect, $connection, $buffer); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) { $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); diff --git a/Protocols/Ws.php b/Protocols/Ws.php index 94c81a414..449a419d8 100644 --- a/Protocols/Ws.php +++ b/Protocols/Ws.php @@ -97,11 +97,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func($connection->onWebSocketClose, $connection); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } // Close connection. else { @@ -155,11 +153,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func($connection->onWebSocketPing, $connection, $ping_data); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } else { $connection->send($ping_data); @@ -182,11 +178,9 @@ public static function input($buffer, ConnectionInterface $connection) try { \call_user_func($connection->onWebSocketPong, $connection, $pong_data); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } $connection->websocketType = $tmp_connection_type; @@ -264,11 +258,9 @@ public static function encode($payload, ConnectionInterface $connection) try { \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } return ''; @@ -280,11 +272,9 @@ public static function encode($payload, ConnectionInterface $connection) try { \call_user_func($connection->onBufferFull, $connection); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } } @@ -432,11 +422,9 @@ public static function dealHandshake($buffer, TcpConnection $connection) try { \call_user_func($connection->onWebSocketConnect, $connection, \substr($buffer, 0, $handshake_response_length)); } catch (\Exception $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } catch (\Error $e) { - Worker::log($e); - exit(250); + Worker::stopAll(250, $e); } } // Headbeat. diff --git a/Worker.php b/Worker.php index 7b1a271c9..3406a2396 100644 --- a/Worker.php +++ b/Worker.php @@ -1746,11 +1746,9 @@ protected static function reload() try { \call_user_func(static::$onMasterReload); } catch (\Exception $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } static::initId(); } @@ -1805,11 +1803,9 @@ protected static function reload() try { \call_user_func($worker->onWorkerReload, $worker); } catch (\Exception $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } } @@ -1820,12 +1816,17 @@ protected static function reload() } /** - * Stop. + * Stop all. * - * @return void + * @param int $code + * @param string $log */ - public static function stopAll() + public static function stopAll($code = 0, $log = '') { + if ($log) { + static::log($log); + } + static::$_status = static::STATUS_SHUTDOWN; // For master process. if (static::$_masterPid === \posix_getpid()) { @@ -1864,7 +1865,7 @@ public static function stopAll() } try { - exit(0); + exit($code); } catch (Exception $e) { } @@ -2404,15 +2405,13 @@ public function run() try { \call_user_func($this->onWorkerStart, $this); } catch (\Exception $e) { - static::log($e); // Avoid rapid infinite loop exit. sleep(1); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); // Avoid rapid infinite loop exit. sleep(1); - exit(250); + static::stopAll(250, $e); } } @@ -2432,11 +2431,9 @@ public function stop() try { \call_user_func($this->onWorkerStop, $this); } catch (\Exception $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } } // Remove listener for server socket. @@ -2486,11 +2483,9 @@ public function acceptConnection($socket) try { \call_user_func($this->onConnect, $connection); } catch (\Exception $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } } } @@ -2541,11 +2536,9 @@ public function acceptUdpConnection($socket) } ++ConnectionInterface::$statistics['total_request']; } catch (\Exception $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } catch (\Error $e) { - static::log($e); - exit(250); + static::stopAll(250, $e); } } return true; From ab9a28b03c34549525fac1cc170f6e3b65e047e6 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 16 Oct 2021 21:22:23 +0800 Subject: [PATCH 0606/1216] Update TcpConnection.php --- Connection/TcpConnection.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Connection/TcpConnection.php b/Connection/TcpConnection.php index 4e057a441..4984a506a 100644 --- a/Connection/TcpConnection.php +++ b/Connection/TcpConnection.php @@ -469,6 +469,9 @@ public function getLocalPort() */ public function getLocalAddress() { + if (!\is_resource($this->_socket)) { + return ''; + } return (string)@\stream_socket_get_name($this->_socket, false); } From da3610a9340c013e8e5c7e61e4f8a522f34e304d Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 18 Oct 2021 15:10:01 +0800 Subject: [PATCH 0607/1216] Optimized for windows --- Worker.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Worker.php b/Worker.php index 3406a2396..01b84920c 100644 --- a/Worker.php +++ b/Worker.php @@ -1384,7 +1384,7 @@ protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; - if(\in_array('-q', $argv) || \count($files) === 1) + if(\in_array('-q', $argv)) { if(\count(static::$_workers) > 1) { @@ -1451,9 +1451,8 @@ public static function forkOneWorkerForWindows($start_file) 2 => array('file', $std_file, 'w') // stderr ); - $pipes = array(); - $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); + $process = \proc_open(PHP_BINARY . " \"$start_file\" -q", $descriptorspec, $pipes); $std_handler = \fopen($std_file, 'a+'); \stream_set_blocking($std_handler, false); From b0ef18278bcb2741d14e47815e838496a1b63ca3 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 19 Oct 2021 15:18:22 +0800 Subject: [PATCH 0608/1216] For #674 --- Protocols/Websocket.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Protocols/Websocket.php b/Protocols/Websocket.php index d32238435..2cc2fb7e7 100644 --- a/Protocols/Websocket.php +++ b/Protocols/Websocket.php @@ -345,9 +345,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->send("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", true); - $connection->close(); return 0; } // Calculation websocket key. @@ -431,9 +430,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } // Bad websocket handshake request. - $connection->send("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", true); - $connection->close(); return 0; } From f0d9106e0419094ea8edd3990999eb167b6e3233 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 22 Oct 2021 09:29:52 +0800 Subject: [PATCH 0609/1216] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 796cab8e9..5186b8a5e 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,6 @@ require_once __DIR__ . '/vendor/autoload.php'; // Create a Websocket server $ws_worker = new Worker('websocket://0.0.0.0:2346'); -// 4 processes -$ws_worker->count = 4; - // Emitted when new connection come $ws_worker->onConnect = function ($connection) { echo "New connection\n"; From 22dbd47be1f41a521c6aff85cae2fea2905e5309 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 26 Oct 2021 10:04:47 +0800 Subject: [PATCH 0610/1216] Update Worker.php #679 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 01b84920c..230b40211 100644 --- a/Worker.php +++ b/Worker.php @@ -1925,7 +1925,7 @@ protected static function writeStatisticsToStatusFile() } \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2)) : array('-', '-', '-'); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2,2,2)) : array('-', '-', '-'); \file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, From e2e615f497b92209c529be93c3e81d1a140151bd Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 26 Oct 2021 16:08:08 +0800 Subject: [PATCH 0611/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 230b40211..31d3aa12f 100644 --- a/Worker.php +++ b/Worker.php @@ -1452,7 +1452,7 @@ public static function forkOneWorkerForWindows($start_file) ); $pipes = array(); - $process = \proc_open(PHP_BINARY . " \"$start_file\" -q", $descriptorspec, $pipes); + $process = \proc_open('"'.PHP_BINARY . "\" \"$start_file\" -q", $descriptorspec, $pipes); $std_handler = \fopen($std_file, 'a+'); \stream_set_blocking($std_handler, false); From 30b100cc4a10d6e1103cddc568553ee04a5917ad Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 27 Oct 2021 14:11:46 +0800 Subject: [PATCH 0612/1216] v4.0.21 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 31d3aa12f..78128e872 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.20'; + const VERSION = '4.0.21'; /** * Status starting. From 7c727c3a86c56b01d6ad06ed8b972f93aaf72b3d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 27 Oct 2021 21:45:28 +0800 Subject: [PATCH 0613/1216] fix #680 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 78128e872..8b07b5d5d 100644 --- a/Worker.php +++ b/Worker.php @@ -1452,7 +1452,7 @@ public static function forkOneWorkerForWindows($start_file) ); $pipes = array(); - $process = \proc_open('"'.PHP_BINARY . "\" \"$start_file\" -q", $descriptorspec, $pipes); + $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); $std_handler = \fopen($std_file, 'a+'); \stream_set_blocking($std_handler, false); From 403e59778c79dc9e5fd664d8d32305f5b0c6e146 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Oct 2021 10:58:18 +0800 Subject: [PATCH 0614/1216] Update Worker.php #681 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 8b07b5d5d..2909d708f 100644 --- a/Worker.php +++ b/Worker.php @@ -1384,7 +1384,7 @@ protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); global $argv; - if(\in_array('-q', $argv)) + if(\in_array('-q', $argv) || \count($files) === 1) { if(\count(static::$_workers) > 1) { From df1a00d8f3ebd2d68527a048abb6d298fdc4941b Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Oct 2021 10:59:06 +0800 Subject: [PATCH 0615/1216] v 4.0.22 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 2909d708f..8ec488a84 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.21'; + const VERSION = '4.0.22'; /** * Status starting. From 1c3df6da1e58bcaa5a872cf8686508f60de914ee Mon Sep 17 00:00:00 2001 From: lvshuang Date: Tue, 2 Nov 2021 20:13:07 +0800 Subject: [PATCH 0616/1216] implement session updateTimestamp and refresh session expire time api Signed-off-by: lvshuang --- Protocols/Http/Session.php | 13 +++++++- Protocols/Http/Session/FileSessionHandler.php | 26 ++++++++++++++- .../Http/Session/RedisSessionHandler.php | 10 +++++- .../Http/Session/SessionHandlerInterface.php | 33 +++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 Protocols/Http/Session/SessionHandlerInterface.php diff --git a/Protocols/Http/Session.php b/Protocols/Http/Session.php index 0181a8e34..e1782e193 100644 --- a/Protocols/Http/Session.php +++ b/Protocols/Http/Session.php @@ -13,6 +13,7 @@ */ namespace Workerman\Protocols\Http; +use Workerman\Protocols\Http\Session\SessionHandlerInterface; /** * Class Session @@ -58,7 +59,7 @@ class Session /** * Session handler instance. * - * @var \SessionHandlerInterface + * @var SessionHandlerInterface */ protected static $_handler = null; @@ -257,6 +258,16 @@ public function save() $this->_needSave = false; } + /** + * Refresh session expire time. + * + * @return bool + */ + public function refresh() + { + static::$_handler->updateTimestamp($this->getId()); + } + /** * Init. * diff --git a/Protocols/Http/Session/FileSessionHandler.php b/Protocols/Http/Session/FileSessionHandler.php index fc9780fbd..5c862a5e5 100644 --- a/Protocols/Http/Session/FileSessionHandler.php +++ b/Protocols/Http/Session/FileSessionHandler.php @@ -17,7 +17,7 @@ * Class FileSessionHandler * @package Workerman\Protocols\Http\Session */ -class FileSessionHandler implements \SessionHandlerInterface +class FileSessionHandler implements SessionHandlerInterface { /** * Session save path. @@ -88,6 +88,30 @@ public function write($session_id, $session_data) return \rename($temp_file, static::sessionFile($session_id)); } + /** + * Update sesstion modify time. + * + * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php + * @see https://www.php.net/manual/zh/function.touch.php + * + * @param string $id Session id. + * @param string $data Session Data. + * + * @return bool + */ + public function updateTimestamp($id, $data = "") + { + $session_file = static::sessionFile($id); + if (!file_exists($session_file)) { + return false; + } + // set file modify time to current time + $set_modify_time = \touch($session_file); + // clear file stat cache + \clearstatcache(); + return $set_modify_time; + } + /** * {@inheritdoc} */ diff --git a/Protocols/Http/Session/RedisSessionHandler.php b/Protocols/Http/Session/RedisSessionHandler.php index 3d64392b4..bd6ee11f0 100644 --- a/Protocols/Http/Session/RedisSessionHandler.php +++ b/Protocols/Http/Session/RedisSessionHandler.php @@ -17,7 +17,7 @@ * Class RedisSessionHandler * @package Workerman\Protocols\Http\Session */ -class RedisSessionHandler extends \SessionHandler +class RedisSessionHandler extends \SessionHandler implements SessionHandlerInterface { /** @@ -92,6 +92,14 @@ public function write($session_id, $session_data) return true === $this->_redis->setex($session_id, $this->_maxLifeTime, $session_data); } + /** + * {@inheritdoc} + */ + public function updateTimestamp($id, $data = "") + { + return true === $this->_redis->expire($id, $this->_maxLifeTime); + } + /** * {@inheritdoc} */ diff --git a/Protocols/Http/Session/SessionHandlerInterface.php b/Protocols/Http/Session/SessionHandlerInterface.php new file mode 100644 index 000000000..3b7d0e14f --- /dev/null +++ b/Protocols/Http/Session/SessionHandlerInterface.php @@ -0,0 +1,33 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Protocols\Http\Session; + +use \SessionHandlerInterface as InternalSessionHandlerInterface; + +interface SessionHandlerInterface extends InternalSessionHandlerInterface +{ + + /** + * Update sesstion modify time. + * + * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php + * + * @param string $id Session id. + * @param string $data Session Data. + * + * @return bool + */ + public function updateTimestamp($id, $data = ""); + +} From 12f9367d02a0aadaf1439fc2ea67e9924842fd43 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 13 Nov 2021 21:17:29 +0800 Subject: [PATCH 0617/1216] fix for php8.1 --- Protocols/Http/Request.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 9e365a81b..c1052f6c9 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -163,7 +163,8 @@ public function header($name = null, $default = null) public function cookie($name = null, $default = null) { if (!isset($this->_data['cookie'])) { - \parse_str(\str_replace('; ', '&', $this->header('cookie')), $this->_data['cookie']); + $this->_data['cookie'] = array(); + \parse_str(\str_replace('; ', '&', $this->header('cookie', '')), $this->_data['cookie']); } if ($name === null) { return $this->_data['cookie']; From 6e16d283191e68297c96837f5eebfa356a030972 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Dec 2021 19:48:34 +0800 Subject: [PATCH 0618/1216] Compatible with php8.1 --- Protocols/Http/Response.php | 2 +- .../Http/Session/RedisSessionHandler.php | 2 +- .../Http/Session/SessionHandlerInterface.php | 87 ++++++++++++++++++- 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 61a21266f..9ebbb87c2 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -156,7 +156,7 @@ public function __construct( ) { $this->_status = $status; $this->_header = $headers; - $this->_body = $body; + $this->_body = (string)$body; } /** diff --git a/Protocols/Http/Session/RedisSessionHandler.php b/Protocols/Http/Session/RedisSessionHandler.php index bd6ee11f0..8cfe2cbbb 100644 --- a/Protocols/Http/Session/RedisSessionHandler.php +++ b/Protocols/Http/Session/RedisSessionHandler.php @@ -17,7 +17,7 @@ * Class RedisSessionHandler * @package Workerman\Protocols\Http\Session */ -class RedisSessionHandler extends \SessionHandler implements SessionHandlerInterface +class RedisSessionHandler implements SessionHandlerInterface { /** diff --git a/Protocols/Http/Session/SessionHandlerInterface.php b/Protocols/Http/Session/SessionHandlerInterface.php index 3b7d0e14f..23a47f2bb 100644 --- a/Protocols/Http/Session/SessionHandlerInterface.php +++ b/Protocols/Http/Session/SessionHandlerInterface.php @@ -13,10 +13,91 @@ */ namespace Workerman\Protocols\Http\Session; -use \SessionHandlerInterface as InternalSessionHandlerInterface; - -interface SessionHandlerInterface extends InternalSessionHandlerInterface +interface SessionHandlerInterface { + /** + * Close the session + * @link http://php.net/manual/en/sessionhandlerinterface.close.php + * @return bool

+ * The return value (usually TRUE on success, FALSE on failure). + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function close(); + + /** + * Destroy a session + * @link http://php.net/manual/en/sessionhandlerinterface.destroy.php + * @param string $session_id The session ID being destroyed. + * @return bool

+ * The return value (usually TRUE on success, FALSE on failure). + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function destroy($session_id); + + /** + * Cleanup old sessions + * @link http://php.net/manual/en/sessionhandlerinterface.gc.php + * @param int $maxlifetime

+ * Sessions that have not updated for + * the last maxlifetime seconds will be removed. + *

+ * @return bool

+ * The return value (usually TRUE on success, FALSE on failure). + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function gc($maxlifetime); + + /** + * Initialize session + * @link http://php.net/manual/en/sessionhandlerinterface.open.php + * @param string $save_path The path where to store/retrieve the session. + * @param string $name The session name. + * @return bool

+ * The return value (usually TRUE on success, FALSE on failure). + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function open($save_path, $name); + + + /** + * Read session data + * @link http://php.net/manual/en/sessionhandlerinterface.read.php + * @param string $session_id The session id to read data for. + * @return string

+ * Returns an encoded string of the read data. + * If nothing was read, it must return an empty string. + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function read($session_id); + + /** + * Write session data + * @link http://php.net/manual/en/sessionhandlerinterface.write.php + * @param string $session_id The session id. + * @param string $session_data

+ * The encoded session data. This data is the + * result of the PHP internally encoding + * the $_SESSION superglobal to a serialized + * string and passing it as this parameter. + * Please note sessions use an alternative serialization method. + *

+ * @return bool

+ * The return value (usually TRUE on success, FALSE on failure). + * Note this value is returned internally to PHP for processing. + *

+ * @since 5.4.0 + */ + public function write($session_id, $session_data); /** * Update sesstion modify time. From 561cc03f0cd1acd6034134f2acb8e7aa1a289a39 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Dec 2021 19:54:05 +0800 Subject: [PATCH 0619/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 8ec488a84..20c9da5ce 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.22'; + const VERSION = '4.0.23'; /** * Status starting. From 39a2a54bbc6ca93dd238008d114832d1b0e812c8 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Dec 2021 20:34:22 +0800 Subject: [PATCH 0620/1216] Support multipart/form-data post array https://github.com/walkor/webman/issues/256?notification_referrer_id=NT_kwDOAFysGLIyNzU5NjI2ODIxOjYwNzMzNjg --- Protocols/Http/Request.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index c1052f6c9..1103d2044 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -546,7 +546,13 @@ protected function parseUploadFiles($http_post_boundary) else { // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { - $this->_data['post'][$match[1]] = $boundary_value; + $key = $match[1]; + if (\strlen($key) > 2 && \substr($key, -2) == '[]') { + $key = \substr($key, 0, -2); + $this->_data['post'][$key][] = $boundary_value; + } else { + $this->_data['post'][$key] = $boundary_value; + } } } break; From 18763aaec1d0b31020191bf8b6c6343ecb636340 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Dec 2021 22:27:25 +0800 Subject: [PATCH 0621/1216] Update Request.php https://github.com/walkor/webman/issues/255#issuecomment-984675590 --- Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 1103d2044..76ee55b0f 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -251,7 +251,7 @@ public function uri() public function path() { if (!isset($this->_data['path'])) { - $this->_data['path'] = \parse_url($this->uri(), PHP_URL_PATH); + $this->_data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH); } return $this->_data['path']; } @@ -264,7 +264,7 @@ public function path() public function queryString() { if (!isset($this->_data['query_string'])) { - $this->_data['query_string'] = \parse_url($this->uri(), PHP_URL_QUERY); + $this->_data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY); } return $this->_data['query_string']; } From faf60794f0c456a6b170e8e99bbeea1f88356e48 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Dec 2021 22:29:41 +0800 Subject: [PATCH 0622/1216] v4.0.24 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 20c9da5ce..a19f48533 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.23'; + const VERSION = '4.0.24'; /** * Status starting. From 11f1433273ba5c264648d162da6e4cb0c79bf08c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Dec 2021 15:10:18 +0800 Subject: [PATCH 0623/1216] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5186b8a5e..e23517a1e 100644 --- a/README.md +++ b/README.md @@ -279,11 +279,11 @@ Worker::runAll(); ## Documentation -中文主页:[http://www.workerman.net](http://www.workerman.net) +中文主页:[http://www.workerman.net](https://www.workerman.net) -中文文档: [http://doc.workerman.net](http://doc.workerman.net) +中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/worekrman) -Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/src/SUMMARY.md) +Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) # Benchmarks https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r From 05a5f0fb48088e4dab2dadb3c750c3720da262b6 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 7 Dec 2021 15:10:56 +0800 Subject: [PATCH 0624/1216] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e23517a1e..d5b5a4c08 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,7 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= ## Other links with workerman +[webman](https://github.com/walkor/webman) [PHPSocket.IO](https://github.com/walkor/phpsocket.io) [php-socks5](https://github.com/walkor/php-socks5) [php-http-proxy](https://github.com/walkor/php-http-proxy) From fcd207f35bad4ced4b218a2c3215a5bdcd6e1586 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 10 Dec 2021 11:32:44 +0800 Subject: [PATCH 0625/1216] Update Request.php https://github.com/walkor/webman/issues/264 --- Protocols/Http/Request.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 76ee55b0f..683427489 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -506,6 +506,7 @@ protected function parseUploadFiles($http_post_boundary) } $key = -1; $files = array(); + $post_str = ''; foreach ($boundary_data_array as $boundary_data_buffer) { list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); // Remove \r\n from the end of buffer. @@ -547,12 +548,7 @@ protected function parseUploadFiles($http_post_boundary) // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { $key = $match[1]; - if (\strlen($key) > 2 && \substr($key, -2) == '[]') { - $key = \substr($key, 0, -2); - $this->_data['post'][$key][] = $boundary_value; - } else { - $this->_data['post'][$key] = $boundary_value; - } + $post_str .= \urlencode($key)."=".\urlencode($boundary_value).'&'; } } break; @@ -569,13 +565,16 @@ protected function parseUploadFiles($http_post_boundary) foreach ($files as $file) { $key = $file['key']; unset($file['key']); - // Multi files - if (\strlen($key) > 2 && \substr($key, -2) == '[]') { - $key = \substr($key, 0, -2); - $this->_data['files'][$key][] = $file; - } else { - $this->_data['files'][$key] = $file; - } + $str = \urlencode($key)."=1"; + $result = []; + \parse_str($str, $result); + \array_walk_recursive($result, function(&$value) use ($file) { + $value = $file; + }); + $this->_data['files'] = \array_merge($this->_data['files'], $result); + } + if ($post_str) { + parse_str($post_str, $this->_data['post']); } } From e344c9f2a4250dd688b7e7880cdd0bf720806a02 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 10 Dec 2021 11:33:58 +0800 Subject: [PATCH 0626/1216] v4.0.25 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a19f48533..a3a0b6f6e 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.24'; + const VERSION = '4.0.25'; /** * Status starting. From d6af94dc565876ee5be30ba21b778dfee9759267 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 10 Dec 2021 12:06:33 +0800 Subject: [PATCH 0627/1216] unlink upload files when request dustruct --- Protocols/Http/Request.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 683427489..5f0c75955 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -650,16 +650,13 @@ public function __destruct() { if (isset($this->_data['files'])) { \clearstatcache(); - foreach ($this->_data['files'] as $items) { - if (!\is_array(\current($items))) { - $items = [$items]; - } - foreach ($items as $item) { - if (\is_file($item['tmp_name'])) { - \unlink($item['tmp_name']); + \array_walk_recursive($this->_data['files'], function($value, $key){ + if ($key === 'tmp_name') { + if (\is_file($value)) { + \unlink($value); } } - } + }); } } } From 8d8d977893c8ee1a2ba176ee98a779d736b51d84 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 16 Dec 2021 10:00:31 +0800 Subject: [PATCH 0628/1216] Add getSocket #692 --- Connection/UdpConnection.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 53bbfcaa7..2974129e8 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -195,4 +195,14 @@ public function close($data = null, $raw = false) } return true; } + + /** + * Get the real socket. + * + * @return resource + */ + public function getSocket() + { + return $this->_socket; + } } From bd46d7a52922daca86dd6f8cc31ece7803fc8fad Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 16 Dec 2021 10:07:33 +0800 Subject: [PATCH 0629/1216] v4.0.26 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index a3a0b6f6e..3e785ff6f 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.25'; + const VERSION = '4.0.26'; /** * Status starting. From 416136d1821b8565c4657651a2837bf7079766cb Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Dec 2021 20:32:32 +0800 Subject: [PATCH 0630/1216] Create FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..aaf59739e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +open_collective: walkor From c4dd20c48726ef9f0bd9a7d235869cda4219e532 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Dec 2021 22:19:15 +0800 Subject: [PATCH 0631/1216] Update FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index aaf59739e..3d88b8d39 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ # These are supported funding model platforms open_collective: walkor +patreon: walkor From d819d12f8d035608b624b9b10f9a70f2eabcee92 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Dec 2021 10:40:52 +0800 Subject: [PATCH 0632/1216] # 696 --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d5b5a4c08..860869967 100644 --- a/README.md +++ b/README.md @@ -296,7 +296,12 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= [php-socks5](https://github.com/walkor/php-socks5) [php-http-proxy](https://github.com/walkor/php-http-proxy) +## Sponsors +[opencollective.com/walkor](https://opencollective.com/walkor) +[patreon.com/walkor](https://patreon.com/walkor) + ## Donate + ## LICENSE From 998b78d744a1c92a4a752446ea47baa4fcc2d84b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Dec 2021 10:41:23 +0800 Subject: [PATCH 0633/1216] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 860869967..92449dc1c 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,7 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= ## Sponsors [opencollective.com/walkor](https://opencollective.com/walkor) + [patreon.com/walkor](https://patreon.com/walkor) ## Donate From 073bff3d47c2f4b0a976bbbc0e74c9222d22944c Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Dec 2021 10:43:38 +0800 Subject: [PATCH 0634/1216] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 92449dc1c..33bd14123 100644 --- a/README.md +++ b/README.md @@ -286,15 +286,8 @@ Worker::runAll(); Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) # Benchmarks -https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r - - -## Other links with workerman - -[webman](https://github.com/walkor/webman) -[PHPSocket.IO](https://github.com/walkor/phpsocket.io) -[php-socks5](https://github.com/walkor/php-socks5) -[php-http-proxy](https://github.com/walkor/php-http-proxy) +https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=db&l=yyku7z-e7&a=2 +![image](https://user-images.githubusercontent.com/6073368/146704320-1559fe97-aa67-4ee3-95d6-61e341b3c93b.png) ## Sponsors [opencollective.com/walkor](https://opencollective.com/walkor) @@ -305,6 +298,13 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= +## Other links with workerman + +[webman](https://github.com/walkor/webman) +[PHPSocket.IO](https://github.com/walkor/phpsocket.io) +[php-socks5](https://github.com/walkor/php-socks5) +[php-http-proxy](https://github.com/walkor/php-http-proxy) + ## LICENSE Workerman is released under the [MIT license](https://github.com/walkor/workerman/blob/master/MIT-LICENSE.txt). From 27573e9f985f9ec0665b1f9924308d359bd0fdaa Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 21 Dec 2021 11:39:14 +0800 Subject: [PATCH 0635/1216] Fix cookie() fail when first time set session https://github.com/walkor/webman-framework/issues/22 --- Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Response.php b/Protocols/Http/Response.php index 9ebbb87c2..06b013ace 100644 --- a/Protocols/Http/Response.php +++ b/Protocols/Http/Response.php @@ -189,7 +189,7 @@ public function withHeader($name, $value) { * @return $this */ public function withHeaders($headers) { - $this->_header = \array_merge($this->_header, $headers); + $this->_header = \array_merge_recursive($this->_header, $headers); return $this; } From 88088eefed4ba90745a77ae5f090fc1027316e95 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 23 Dec 2021 14:38:44 +0800 Subject: [PATCH 0636/1216] Update Worker.php --- Worker.php | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Worker.php b/Worker.php index 3e785ff6f..508e7d96f 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.26'; + const VERSION = '4.0.27'; /** * Status starting. @@ -1443,30 +1443,21 @@ public static function getStartFilesForWindows() { public static function forkOneWorkerForWindows($start_file) { $start_file = \realpath($start_file); - $std_file = \sys_get_temp_dir() . '/'.\str_replace(array('/', "\\", ':'), '_', $start_file).'.out.txt'; $descriptorspec = array( - 0 => array('pipe', 'a'), // stdin - 1 => array('file', $std_file, 'w'), // stdout - 2 => array('file', $std_file, 'w') // stderr + STDIN, STDOUT, STDOUT ); $pipes = array(); $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); - $std_handler = \fopen($std_file, 'a+'); - \stream_set_blocking($std_handler, false); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); Timer::init(static::$globalEvent); } - $timer_id = Timer::add(0.1, function()use($std_handler) - { - Worker::safeEcho(\fread($std_handler, 65535)); - }); // 保存子进程句柄 - static::$_processForWindows[$start_file] = array($process, $start_file, $timer_id); + static::$_processForWindows[$start_file] = array($process, $start_file); } /** @@ -1479,14 +1470,12 @@ public static function checkWorkerStatusForWindows() { $process = $process_data[0]; $start_file = $process_data[1]; - $timer_id = $process_data[2]; $status = \proc_get_status($process); if(isset($status['running'])) { if(!$status['running']) { static::safeEcho("process $start_file terminated and try to restart\n"); - Timer::del($timer_id); \proc_close($process); static::forkOneWorkerForWindows($start_file); } From a68c3cf9f871f54e09cbadad26e60fea368997fc Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 23 Dec 2021 14:54:04 +0800 Subject: [PATCH 0637/1216] Update Select.php --- Events/Select.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Events/Select.php b/Events/Select.php index 1737b6682..aebb93696 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -143,6 +143,7 @@ public function add($fd, $flag, $func, $args = array()) $this->_scheduler->insert($timer_id, -$run_time); $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); $select_timeout = ($run_time - \microtime(true)) * 1000000; + $select_timeout = $select_timeout <= 0 ? 1 : $select_timeout; if( $this->_selectTimeout > $select_timeout ){ $this->_selectTimeout = $select_timeout; } From 864841beb7e8a99006e72c39af126755a1dcd68d Mon Sep 17 00:00:00 2001 From: Yurun Date: Sat, 25 Dec 2021 13:00:07 +0800 Subject: [PATCH 0638/1216] Fix Implicit conversion from float xxx to int loses precision --- Events/Select.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Events/Select.php b/Events/Select.php index aebb93696..069ab8b6d 100644 --- a/Events/Select.php +++ b/Events/Select.php @@ -145,7 +145,7 @@ public function add($fd, $flag, $func, $args = array()) $select_timeout = ($run_time - \microtime(true)) * 1000000; $select_timeout = $select_timeout <= 0 ? 1 : $select_timeout; if( $this->_selectTimeout > $select_timeout ){ - $this->_selectTimeout = $select_timeout; + $this->_selectTimeout = (int) $select_timeout; } return $timer_id; } @@ -216,7 +216,7 @@ protected function tick() $timer_id = $scheduler_data['data']; $next_run_time = -$scheduler_data['priority']; $time_now = \microtime(true); - $this->_selectTimeout = ($next_run_time - $time_now) * 1000000; + $this->_selectTimeout = (int) (($next_run_time - $time_now) * 1000000); if ($this->_selectTimeout <= 0) { $this->_scheduler->extract(); @@ -274,7 +274,7 @@ public function loop() } catch (\Exception $e) {} catch (\Error $e) {} } else { - $this->_selectTimeout >= 1 && usleep((int)$this->_selectTimeout); + $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); $ret = false; } From 7e2603ab5b742fc86f5eac364bc254694f6402ae Mon Sep 17 00:00:00 2001 From: liutao Date: Wed, 29 Dec 2021 10:36:04 +0800 Subject: [PATCH 0639/1216] update AsyncUdpConnection.php note --- Connection/AsyncUdpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/AsyncUdpConnection.php b/Connection/AsyncUdpConnection.php index e8f2e7ce5..745f06066 100644 --- a/Connection/AsyncUdpConnection.php +++ b/Connection/AsyncUdpConnection.php @@ -18,7 +18,7 @@ use \Exception; /** - * AsyncTcpConnection. + * AsyncUdpConnection. */ class AsyncUdpConnection extends UdpConnection { From 58636523cfcde90bebd2e16adfda3ce3cae1957d Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 31 Dec 2021 09:53:36 +0800 Subject: [PATCH 0640/1216] Do not modify the global variable $argv --- Worker.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Worker.php b/Worker.php index 508e7d96f..5895c679f 100644 --- a/Worker.php +++ b/Worker.php @@ -803,14 +803,15 @@ protected static function displayUI() !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { - foreach ($argv as $index => $value) { + $tmpArgv = $argv; + foreach ($tmpArgv as $index => $value) { if ($value == '-d') { - unset($argv[$index]); + unset($tmpArgv[$index]); } elseif ($value == 'start' || $value == 'restart') { - $argv[$index] = 'stop'; + $tmpArgv[$index] = 'stop'; } } - static::safeEcho("Input \"php ".implode(' ', $argv)."\" to stop. Start success.\n\n"); + static::safeEcho("Input \"php ".implode(' ', $tmpArgv)."\" to stop. Start success.\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } From f7c03dcdad4ae786e36d4d4770b45d5972e62b4d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 13 Jan 2022 22:21:38 +0800 Subject: [PATCH 0641/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33bd14123..856e02046 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ Worker::runAll(); 中文主页:[http://www.workerman.net](https://www.workerman.net) -中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/worekrman) +中文文档: [https://www.workerman.net/doc/workerman](https://www.workerman.net/doc/workerman) Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) From e89fb88aae6419da8a0e27f1f83d35da3fe1e89d Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Jan 2022 17:24:46 +0800 Subject: [PATCH 0642/1216] add UPLOAD_ERR_NO_FILE --- Protocols/Http/Request.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 5f0c75955..148e92062 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -525,6 +525,8 @@ protected function parseUploadFiles($http_post_boundary) $tmp_upload_dir = HTTP::uploadTmpDir(); if (!$tmp_upload_dir) { $error = UPLOAD_ERR_NO_TMP_DIR; + } else if ($boundary_value === '') { + $error = UPLOAD_ERR_NO_FILE; } else { $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.'); if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) { @@ -540,7 +542,8 @@ protected function parseUploadFiles($http_post_boundary) 'name' => $match[2], 'tmp_name' => $tmp_file, 'size' => $size, - 'error' => $error + 'error' => $error, + 'type' => null, ); break; } // Is post field. From 008f93eb6c20387b1e1dd6d67a28a47dc9236fd8 Mon Sep 17 00:00:00 2001 From: Fuzqing Date: Mon, 7 Feb 2022 17:15:46 +0800 Subject: [PATCH 0643/1216] Phar support. Add Worker::Class member variables $statisticsFileNamePrefix . Allow user-defined file paths to store master process status files. --- Worker.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 5895c679f..29b33b4b5 100644 --- a/Worker.php +++ b/Worker.php @@ -265,6 +265,15 @@ class Worker */ public static $pidFile = ''; + /** + * Phar support. + * The filename prefix used to store the master process status file. + * Allow user-defined file paths to store the master process status file. + * + * @var string + */ + public static $statisticsFileNamePrefix = ''; + /** * Log file. * @@ -644,7 +653,9 @@ protected static function initWorkers() if (static::$_OS !== \OS_TYPE_LINUX) { return; } - static::$_statisticsFile = __DIR__ . '/../workerman-' .posix_getpid().'.status'; + + static::$_statisticsFile = !empty(static::$statisticsFileNamePrefix) ? static::$statisticsFileNamePrefix . posix_getpid().'.status' : __DIR__ . '/../workerman-' .posix_getpid().'.status'; + foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -921,7 +932,7 @@ protected static function parseCommand() exit; } - $statistics_file = __DIR__ . "/../workerman-$master_pid.status"; + $statistics_file = !empty(static::$statisticsFileNamePrefix) ? static::$statisticsFileNamePrefix . "$master_pid.status" : __DIR__ . "/../workerman-$master_pid.status"; // execute command. switch ($command) { From a1251d58a78a7f119d15f6dda2b9f18daae5062b Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Feb 2022 21:55:37 +0800 Subject: [PATCH 0644/1216] Update Worker.php --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 5895c679f..03d0d45ad 100644 --- a/Worker.php +++ b/Worker.php @@ -764,7 +764,7 @@ protected static function displayUI() static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("worker listen processes status\r\n"); + static::safeEcho("worker listen processes status\r\n"); return; } @@ -1402,7 +1402,7 @@ protected static function forkWorkersForWindows() $worker = current(static::$_workers); // Display UI. - static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); + static::safeEcho(\str_pad($worker->name, 30) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); From b7127ab778bdf0657f943d6bcaedde548682684e Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Feb 2022 22:47:33 +0800 Subject: [PATCH 0645/1216] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 3d88b8d39..beae44f79 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # These are supported funding model platforms -open_collective: walkor +open_collective: workerman patreon: walkor From d2787647c2bca724248ae6d1e3bb717c2be69be4 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Feb 2022 22:20:14 +0800 Subject: [PATCH 0646/1216] statusFile --- Worker.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Worker.php b/Worker.php index 46695c24c..f6e2b6cc0 100644 --- a/Worker.php +++ b/Worker.php @@ -266,13 +266,11 @@ class Worker public static $pidFile = ''; /** - * Phar support. - * The filename prefix used to store the master process status file. - * Allow user-defined file paths to store the master process status file. + * The file used to store the master process status file. * * @var string */ - public static $statisticsFileNamePrefix = ''; + public static $statusFile = ''; /** * Log file. @@ -654,7 +652,7 @@ protected static function initWorkers() return; } - static::$_statisticsFile = !empty(static::$statisticsFileNamePrefix) ? static::$statisticsFileNamePrefix . posix_getpid().'.status' : __DIR__ . '/../workerman-' .posix_getpid().'.status'; + static::$_statisticsFile = static::$statusFile ? static::$statusFile : __DIR__ . '/../workerman-' .posix_getpid().'.status'; foreach (static::$_workers as $worker) { // Worker name. @@ -932,7 +930,7 @@ protected static function parseCommand() exit; } - $statistics_file = !empty(static::$statisticsFileNamePrefix) ? static::$statisticsFileNamePrefix . "$master_pid.status" : __DIR__ . "/../workerman-$master_pid.status"; + $statistics_file = static::$statusFile ? static::$statusFile : __DIR__ . "/../workerman-$master_pid.status"; // execute command. switch ($command) { From ed760b0eab2c92ab5204baec3a7e056f557af857 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Feb 2022 11:33:37 +0800 Subject: [PATCH 0647/1216] v4.0.28 --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index f6e2b6cc0..97a706061 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.27'; + const VERSION = '4.0.28'; /** * Status starting. @@ -1827,7 +1827,7 @@ public static function stopAll($code = 0, $log = '') static::$_status = static::STATUS_SHUTDOWN; // For master process. - if (static::$_masterPid === \posix_getpid()) { + if (\DIRECTORY_SEPARATOR === '/' && static::$_masterPid === \posix_getpid()) { static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ..."); $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. From 413e2a3eb96fb591b8456654b3fd2939f3a84cf1 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 18 Feb 2022 23:34:08 +0800 Subject: [PATCH 0648/1216] Update Request.php --- Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 148e92062..301c67a97 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -164,7 +164,7 @@ public function cookie($name = null, $default = null) { if (!isset($this->_data['cookie'])) { $this->_data['cookie'] = array(); - \parse_str(\str_replace('; ', '&', $this->header('cookie', '')), $this->_data['cookie']); + \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->_data['cookie']); } if ($name === null) { return $this->_data['cookie']; From 7370cfc9c09f58ab5f4e9593d23ac6069930a570 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 19 Feb 2022 18:21:50 +0800 Subject: [PATCH 0649/1216] v4.0.29 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 97a706061..6accb28cb 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.28'; + const VERSION = '4.0.29'; /** * Status starting. From 5f387d0f1eca647a4681c3cdcb9225c39131bcc3 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 24 Feb 2022 11:06:37 +0800 Subject: [PATCH 0650/1216] typo #718 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 6accb28cb..3f2b650f9 100644 --- a/Worker.php +++ b/Worker.php @@ -1553,7 +1553,7 @@ protected static function forkOneWorkerForLinux(self $worker) /** * Get worker id. * - * @param int $worker_id + * @param string $worker_id * @param int $pid * * @return integer From 34fa51d178ca620fbe00fc4b55645b876846886f Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Feb 2022 20:16:30 +0800 Subject: [PATCH 0651/1216] sinal change --- Worker.php | 62 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/Worker.php b/Worker.php index 3f2b650f9..29bcd327a 100644 --- a/Worker.php +++ b/Worker.php @@ -944,8 +944,8 @@ protected static function parseCommand() if (\is_file($statistics_file)) { @\unlink($statistics_file); } - // Master process will send SIGUSR2 signal to all child processes. - \posix_kill($master_pid, SIGUSR2); + // Master process will send SIGIOT signal to all child processes. + \posix_kill($master_pid, SIGIOT); // Sleep 1 second. \sleep(1); // Clear terminal. @@ -977,7 +977,7 @@ protected static function parseCommand() case 'stop': if ($mode === '-g') { static::$_gracefulStop = true; - $sig = \SIGHUP; + $sig = \SIGQUIT; static::log("Workerman[$start_file] is gracefully stopping ..."); } else { static::$_gracefulStop = false; @@ -1015,9 +1015,9 @@ protected static function parseCommand() break; case 'reload': if($mode === '-g'){ - $sig = \SIGQUIT; - }else{ $sig = \SIGUSR1; + }else{ + $sig = \SIGUSR2; } \posix_kill($master_pid, $sig); exit; @@ -1128,14 +1128,18 @@ protected static function installSignal() \pcntl_signal(\SIGINT, $signalHandler, false); // stop \pcntl_signal(\SIGTERM, $signalHandler, false); - // graceful stop + // stop \pcntl_signal(\SIGHUP, $signalHandler, false); + // stop + \pcntl_signal(\SIGTSTP, $signalHandler, false); + // graceful stop + \pcntl_signal(\SIGQUIT, $signalHandler, false); // reload - \pcntl_signal(\SIGUSR1, $signalHandler, false); + \pcntl_signal(\SIGUSR2, $signalHandler, false); // graceful reload - \pcntl_signal(\SIGQUIT, $signalHandler, false); + \pcntl_signal(\SIGUSR1, $signalHandler, false); // status - \pcntl_signal(\SIGUSR2, $signalHandler, false); + \pcntl_signal(\SIGIOT, $signalHandler, false); // connection status \pcntl_signal(\SIGIO, $signalHandler, false); // ignore @@ -1157,26 +1161,34 @@ protected static function reinstallSignal() \pcntl_signal(\SIGINT, \SIG_IGN, false); // uninstall stop signal handler \pcntl_signal(\SIGTERM, \SIG_IGN, false); - // uninstall graceful stop signal handler + // uninstall stop signal handler \pcntl_signal(\SIGHUP, \SIG_IGN, false); + // uninstall stop signal handler + \pcntl_signal(\SIGTSTP, \SIG_IGN, false); + // uninstall graceful stop signal handler + \pcntl_signal(\SIGQUIT, \SIG_IGN, false); // uninstall reload signal handler - \pcntl_signal(\SIGUSR1, \SIG_IGN, false); + \pcntl_signal(\SIGUSR2, \SIG_IGN, false); // uninstall graceful reload signal handler - \pcntl_signal(\SIGQUIT, \SIG_IGN, false); + \pcntl_signal(\SIGUSR1, \SIG_IGN, false); // uninstall status signal handler - \pcntl_signal(\SIGUSR2, \SIG_IGN, false); + \pcntl_signal(\SIGIOT, \SIG_IGN, false); // uninstall connections status signal handler \pcntl_signal(\SIGIO, \SIG_IGN, false); // reinstall stop signal handler static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful stop signal handler + static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler); + // reinstall graceful stop signal handler static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler); + // reinstall graceful stop signal handler + static::$globalEvent->add(\SIGTSTP, EventInterface::EV_SIGNAL, $signalHandler); // reinstall reload signal handler - static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); + static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); // reinstall graceful reload signal handler - static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler); + static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); // reinstall status signal handler - static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); + static::$globalEvent->add(\SIGIOT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall connection status signal handler static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler); } @@ -1192,23 +1204,25 @@ public static function signalHandler($signal) // Stop. case \SIGINT: case \SIGTERM: + case \SIGHUP: + case \SIGTSTP; static::$_gracefulStop = false; static::stopAll(); break; // Graceful stop. - case \SIGHUP: + case \SIGQUIT: static::$_gracefulStop = true; static::stopAll(); break; // Reload. - case \SIGQUIT: case \SIGUSR1: - static::$_gracefulStop = $signal === \SIGQUIT; + case \SIGUSR2: + static::$_gracefulStop = $signal === \SIGUSR1; static::$_pidsToRestart = static::getAllWorkerPids(); static::reload(); break; // Show status. - case \SIGUSR2: + case \SIGIOT: static::writeStatisticsToStatusFile(); break; // Show connection status. @@ -1753,9 +1767,9 @@ protected static function reload() } if (static::$_gracefulStop) { - $sig = \SIGQUIT; - } else { $sig = \SIGUSR1; + } else { + $sig = \SIGUSR2; } // Send reload signal to all child processes. @@ -1832,7 +1846,7 @@ public static function stopAll($code = 0, $log = '') $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. if (static::$_gracefulStop) { - $sig = \SIGHUP; + $sig = \SIGQUIT; } else { $sig = \SIGINT; } @@ -1965,7 +1979,7 @@ protected static function writeStatisticsToStatusFile() \chmod(static::$_statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { - \posix_kill($worker_pid, \SIGUSR2); + \posix_kill($worker_pid, \SIGIOT); } return; } From 6b04577be1d52545fa1b17cd4b4f3217e2e9c736 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Feb 2022 21:22:03 +0800 Subject: [PATCH 0652/1216] V4.0.30 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 29bcd327a..974296f80 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.29'; + const VERSION = '4.0.30'; /** * Status starting. From 510c220369ed3a8f982539db284a0a64e7224d8a Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 28 Feb 2022 18:08:18 +0800 Subject: [PATCH 0653/1216] Signal optimization --- Worker.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Worker.php b/Worker.php index 974296f80..6d27b6164 100644 --- a/Worker.php +++ b/Worker.php @@ -1015,9 +1015,9 @@ protected static function parseCommand() break; case 'reload': if($mode === '-g'){ - $sig = \SIGUSR1; - }else{ $sig = \SIGUSR2; + }else{ + $sig = \SIGUSR1; } \posix_kill($master_pid, $sig); exit; @@ -1135,9 +1135,9 @@ protected static function installSignal() // graceful stop \pcntl_signal(\SIGQUIT, $signalHandler, false); // reload - \pcntl_signal(\SIGUSR2, $signalHandler, false); - // graceful reload \pcntl_signal(\SIGUSR1, $signalHandler, false); + // graceful reload + \pcntl_signal(\SIGUSR2, $signalHandler, false); // status \pcntl_signal(\SIGIOT, $signalHandler, false); // connection status @@ -1168,9 +1168,9 @@ protected static function reinstallSignal() // uninstall graceful stop signal handler \pcntl_signal(\SIGQUIT, \SIG_IGN, false); // uninstall reload signal handler - \pcntl_signal(\SIGUSR2, \SIG_IGN, false); - // uninstall graceful reload signal handler \pcntl_signal(\SIGUSR1, \SIG_IGN, false); + // uninstall graceful reload signal handler + \pcntl_signal(\SIGUSR2, \SIG_IGN, false); // uninstall status signal handler \pcntl_signal(\SIGIOT, \SIG_IGN, false); // uninstall connections status signal handler @@ -1184,9 +1184,9 @@ protected static function reinstallSignal() // reinstall graceful stop signal handler static::$globalEvent->add(\SIGTSTP, EventInterface::EV_SIGNAL, $signalHandler); // reinstall reload signal handler - static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall graceful reload signal handler static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); + // reinstall graceful reload signal handler + static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); // reinstall status signal handler static::$globalEvent->add(\SIGIOT, EventInterface::EV_SIGNAL, $signalHandler); // reinstall connection status signal handler @@ -1215,9 +1215,9 @@ public static function signalHandler($signal) static::stopAll(); break; // Reload. - case \SIGUSR1: case \SIGUSR2: - static::$_gracefulStop = $signal === \SIGUSR1; + case \SIGUSR1: + static::$_gracefulStop = $signal === \SIGUSR2; static::$_pidsToRestart = static::getAllWorkerPids(); static::reload(); break; @@ -1767,9 +1767,9 @@ protected static function reload() } if (static::$_gracefulStop) { - $sig = \SIGUSR1; - } else { $sig = \SIGUSR2; + } else { + $sig = \SIGUSR1; } // Send reload signal to all child processes. From dd69dd89c1189e0960d5e376544437a9e1af6ba8 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 28 Feb 2022 18:16:48 +0800 Subject: [PATCH 0654/1216] V 4.0.31 --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 6d27b6164..6c6dccbc6 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.30'; + const VERSION = '4.0.31'; /** * Status starting. From 24c79f6677c28f7e46c8140fd997587a68dad37a Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 4 Mar 2022 12:00:13 +0800 Subject: [PATCH 0655/1216] Fix strlen(): Passing null --- Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http.php b/Protocols/Http.php index be3599fba..fae8094e0 100644 --- a/Protocols/Http.php +++ b/Protocols/Http.php @@ -214,7 +214,7 @@ public static function encode($response, TcpConnection $connection) } unset($connection->__header); } - $body_len = \strlen($response); + $body_len = \strlen((string)$response); return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response"; } From 36cf16fa001b5c151c66ff3afe5ce5f11a213a95 Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 4 Mar 2022 16:37:32 +0800 Subject: [PATCH 0656/1216] Fix TypeError: strlen() expects parameter 1 to be string, int given --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 6c6dccbc6..0bf2eede1 100644 --- a/Worker.php +++ b/Worker.php @@ -678,7 +678,7 @@ protected static function initWorkers() // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; - $prop_length = \strlen($worker->{$prop}); + $prop_length = \strlen((string) $worker->{$prop}); $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; static::$$key = \max(static::$$key, $prop_length); } From 2dbcdca40e037543608113d0fcc508cbb14c3fa0 Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 4 Mar 2022 16:58:08 +0800 Subject: [PATCH 0657/1216] Fix --- Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Worker.php b/Worker.php index 0bf2eede1..2f0d4e19e 100644 --- a/Worker.php +++ b/Worker.php @@ -800,9 +800,9 @@ protected static function displayUI() $content = ''; foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", (string) $worker->{$prop}, $matches); $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; - $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + $content .= \str_pad((string) $worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); } $content && static::safeEcho($content . \PHP_EOL); } From 01156b2b5603873f32f60b17afc4984f11027cf0 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 6 Mar 2022 13:34:51 +0800 Subject: [PATCH 0658/1216] fix cookie Max-Age --- Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 301c67a97..3ec327c7c 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -305,7 +305,7 @@ public function sessionId() $cookie_params = \session_get_cookie_params(); $this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) - . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . ($cookie_params['lifetime'] + \time())) + . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime']) . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite']) . (!$cookie_params['secure'] ? '' : '; Secure') From 284bd0b479dc0d2aa952b3591a396e603a6736a9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 11 Mar 2022 09:41:42 +0800 Subject: [PATCH 0659/1216] Udp server example For #731 --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 856e02046..d1502c9cf 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,28 @@ $tcp_worker->onClose = function ($connection) { Worker::runAll(); ``` +### A udp server + +```php +count = 4; + +// Emitted when data received +$worker->onMessage = function($connection, $data) +{ + $connection->send($data); +}; + +Worker::runAll(); +``` + ### Enable SSL ```php Date: Fri, 11 Mar 2022 09:43:11 +0800 Subject: [PATCH 0660/1216] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d1502c9cf..8cc115901 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ Worker::runAll(); ### An http server ```php + Date: Tue, 15 Mar 2022 22:32:05 +0800 Subject: [PATCH 0661/1216] fix ipv6 --- Connection/UdpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection/UdpConnection.php b/Connection/UdpConnection.php index 2974129e8..9cd95ba54 100644 --- a/Connection/UdpConnection.php +++ b/Connection/UdpConnection.php @@ -75,7 +75,7 @@ public function send($send_buffer, $raw = false) return; } } - return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); + return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->_remoteAddress); } /** From 39df5a1627345678e8b83ac86efabafdf31ca9d5 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Mar 2022 10:14:58 +0800 Subject: [PATCH 0662/1216] host --- Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols/Http/Request.php b/Protocols/Http/Request.php index 3ec327c7c..7c36974fb 100644 --- a/Protocols/Http/Request.php +++ b/Protocols/Http/Request.php @@ -224,7 +224,7 @@ public function protocolVersion() public function host($without_port = false) { $host = $this->header('host'); - if ($without_port && $pos = \strpos($host, ':')) { + if ($host && $without_port && $pos = \strpos($host, ':')) { return \substr($host, 0, $pos); } return $host; From 9803f48837b37797ba41b9fd868a15d907501b1c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Mar 2022 23:38:50 +0800 Subject: [PATCH 0663/1216] Update Worker.php --- Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Worker.php b/Worker.php index 2f0d4e19e..4fd5c4ca3 100644 --- a/Worker.php +++ b/Worker.php @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.31'; + const VERSION = '4.0.32'; /** * Status starting. From 0122a8701c692ffda728a5722abab48ab6cf240c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 23 Mar 2022 23:43:52 +0800 Subject: [PATCH 0664/1216] 5.x --- Autoloader.php | 69 ---- Events/Ev.php | 191 --------- Events/Event.php | 215 ---------- Events/EventInterface.php | 107 ----- Events/Libevent.php | 225 ----------- Events/React/Base.php | 264 ------------ Events/React/ExtEventLoop.php | 27 -- Events/React/ExtLibEventLoop.php | 27 -- Events/React/StreamSelectLoop.php | 26 -- Events/Select.php | 341 ---------------- Events/Swoole.php | 230 ----------- Lib/Constants.php | 44 -- Lib/Timer.php | 22 - README.md | 56 +-- composer.json | 4 +- .../Connection}/AsyncTcpConnection.php | 97 +++-- .../Connection}/AsyncUdpConnection.php | 46 +-- .../Connection}/ConnectionInterface.php | 34 +- .../Connection}/TcpConnection.php | 230 ++++++----- .../Connection}/UdpConnection.php | 13 +- src/Events/Ev.php | 203 ++++++++++ src/Events/Event.php | 255 ++++++++++++ src/Events/EventInterface.php | 111 ++++++ src/Events/Revolt.php | 240 +++++++++++ src/Events/Select.php | 375 ++++++++++++++++++ src/Events/Swoole.php | 200 ++++++++++ {Protocols => src/Protocols}/Frame.php | 3 +- {Protocols => src/Protocols}/Http.php | 27 +- {Protocols => src/Protocols}/Http/Chunk.php | 3 +- {Protocols => src/Protocols}/Http/Request.php | 113 ++++-- .../Protocols}/Http/Response.php | 71 ++-- .../Protocols}/Http/ServerSentEvents.php | 1 + {Protocols => src/Protocols}/Http/Session.php | 9 +- .../Http/Session/FileSessionHandler.php | 30 +- .../Http/Session/RedisSessionHandler.php | 1 + .../Http/Session/SessionHandlerInterface.php | 7 +- {Protocols => src/Protocols}/Http/mime.types | 0 .../Protocols}/ProtocolInterface.php | 9 +- {Protocols => src/Protocols}/Text.php | 3 +- {Protocols => src/Protocols}/Websocket.php | 160 +++----- {Protocols => src/Protocols}/Ws.php | 113 +++--- Timer.php => src/Timer.php | 50 ++- Worker.php => src/Worker.php | 362 +++++++---------- 43 files changed, 2058 insertions(+), 2556 deletions(-) delete mode 100644 Autoloader.php delete mode 100644 Events/Ev.php delete mode 100644 Events/Event.php delete mode 100644 Events/EventInterface.php delete mode 100644 Events/Libevent.php delete mode 100644 Events/React/Base.php delete mode 100644 Events/React/ExtEventLoop.php delete mode 100644 Events/React/ExtLibEventLoop.php delete mode 100644 Events/React/StreamSelectLoop.php delete mode 100644 Events/Select.php delete mode 100644 Events/Swoole.php delete mode 100644 Lib/Constants.php delete mode 100644 Lib/Timer.php rename {Connection => src/Connection}/AsyncTcpConnection.php (74%) rename {Connection => src/Connection}/AsyncUdpConnection.php (83%) rename {Connection => src/Connection}/ConnectionInterface.php (83%) rename {Connection => src/Connection}/TcpConnection.php (79%) rename {Connection => src/Connection}/UdpConnection.php (95%) create mode 100644 src/Events/Ev.php create mode 100644 src/Events/Event.php create mode 100644 src/Events/EventInterface.php create mode 100644 src/Events/Revolt.php create mode 100644 src/Events/Select.php create mode 100644 src/Events/Swoole.php rename {Protocols => src/Protocols}/Frame.php (97%) rename {Protocols => src/Protocols}/Http.php (94%) rename {Protocols => src/Protocols}/Http/Chunk.php (92%) rename {Protocols => src/Protocols}/Http/Request.php (83%) rename {Protocols => src/Protocols}/Http/Response.php (90%) rename {Protocols => src/Protocols}/Http/ServerSentEvents.php (99%) rename {Protocols => src/Protocols}/Http/Session.php (98%) rename {Protocols => src/Protocols}/Http/Session/FileSessionHandler.php (86%) rename {Protocols => src/Protocols}/Http/Session/RedisSessionHandler.php (99%) rename {Protocols => src/Protocols}/Http/Session/SessionHandlerInterface.php (99%) rename {Protocols => src/Protocols}/Http/mime.types (100%) rename {Protocols => src/Protocols}/ProtocolInterface.php (91%) rename {Protocols => src/Protocols}/Text.php (97%) rename {Protocols => src/Protocols}/Websocket.php (70%) rename {Protocols => src/Protocols}/Ws.php (79%) rename Timer.php => src/Timer.php (77%) rename Worker.php => src/Worker.php (87%) diff --git a/Autoloader.php b/Autoloader.php deleted file mode 100644 index 7d760e948..000000000 --- a/Autoloader.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman; - -/** - * Autoload. - */ -class Autoloader -{ - /** - * Autoload root path. - * - * @var string - */ - protected static $_autoloadRootPath = ''; - - /** - * Set autoload root path. - * - * @param string $root_path - * @return void - */ - public static function setRootPath($root_path) - { - self::$_autoloadRootPath = $root_path; - } - - /** - * Load files by namespace. - * - * @param string $name - * @return boolean - */ - public static function loadByNamespace($name) - { - $class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name); - if (\strpos($name, 'Workerman\\') === 0) { - $class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php'; - } else { - if (self::$_autoloadRootPath) { - $class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php'; - } - if (empty($class_file) || !\is_file($class_file)) { - $class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php"; - } - } - - if (\is_file($class_file)) { - require_once($class_file); - if (\class_exists($name, false)) { - return true; - } - } - return false; - } -} - -\spl_autoload_register('\Workerman\Autoloader::loadByNamespace'); \ No newline at end of file diff --git a/Events/Ev.php b/Events/Ev.php deleted file mode 100644 index 82c9bdff6..000000000 --- a/Events/Ev.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -use Workerman\Worker; -use \EvWatcher; - -/** - * ev eventloop - */ -class Ev implements EventInterface -{ - /** - * All listeners for read/write event. - * - * @var array - */ - protected $_allEvents = array(); - - /** - * Event listeners of signal. - * - * @var array - */ - protected $_eventSignal = array(); - - /** - * All timer event listeners. - * [func, args, event, flag, time_interval] - * - * @var array - */ - protected $_eventTimer = array(); - - /** - * Timer id. - * - * @var int - */ - protected static $_timerId = 1; - - /** - * Add a timer. - * {@inheritdoc} - */ - public function add($fd, $flag, $func, $args = null) - { - $callback = function ($event, $socket) use ($fd, $func) { - try { - \call_user_func($func, $fd); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { - Worker::stopAll(250, $e); - } - }; - switch ($flag) { - case self::EV_SIGNAL: - $event = new \EvSignal($fd, $callback); - $this->_eventSignal[$fd] = $event; - return true; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - $repeat = $flag === self::EV_TIMER_ONCE ? 0 : $fd; - $param = array($func, (array)$args, $flag, $fd, self::$_timerId); - $event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param); - $this->_eventTimer[self::$_timerId] = $event; - return self::$_timerId++; - default : - $fd_key = (int)$fd; - $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE; - $event = new \EvIo($fd, $real_flag, $callback); - $this->_allEvents[$fd_key][$flag] = $event; - return true; - } - - } - - /** - * Remove a timer. - * {@inheritdoc} - */ - public function del($fd, $flag) - { - switch ($flag) { - case self::EV_READ: - case self::EV_WRITE: - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][$flag])) { - $this->_allEvents[$fd_key][$flag]->stop(); - unset($this->_allEvents[$fd_key][$flag]); - } - if (empty($this->_allEvents[$fd_key])) { - unset($this->_allEvents[$fd_key]); - } - break; - case self::EV_SIGNAL: - $fd_key = (int)$fd; - if (isset($this->_eventSignal[$fd_key])) { - $this->_eventSignal[$fd_key]->stop(); - unset($this->_eventSignal[$fd_key]); - } - break; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - if (isset($this->_eventTimer[$fd])) { - $this->_eventTimer[$fd]->stop(); - unset($this->_eventTimer[$fd]); - } - break; - } - return true; - } - - /** - * Timer callback. - * - * @param EvWatcher $event - */ - public function timerCallback(EvWatcher $event) - { - $param = $event->data; - $timer_id = $param[4]; - if ($param[2] === self::EV_TIMER_ONCE) { - $this->_eventTimer[$timer_id]->stop(); - unset($this->_eventTimer[$timer_id]); - } - try { - \call_user_func_array($param[0], $param[1]); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { - Worker::stopAll(250, $e); - } - } - - /** - * Remove all timers. - * - * @return void - */ - public function clearAllTimer() - { - foreach ($this->_eventTimer as $event) { - $event->stop(); - } - $this->_eventTimer = array(); - } - - /** - * Main loop. - * - * @see EventInterface::loop() - */ - public function loop() - { - \Ev::run(); - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - foreach ($this->_allEvents as $event) { - $event->stop(); - } - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return \count($this->_eventTimer); - } -} diff --git a/Events/Event.php b/Events/Event.php deleted file mode 100644 index 9e25521c0..000000000 --- a/Events/Event.php +++ /dev/null @@ -1,215 +0,0 @@ - - * @copyright 有个鬼<42765633@qq.com> - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -use Workerman\Worker; - -/** - * libevent eventloop - */ -class Event implements EventInterface -{ - /** - * Event base. - * @var object - */ - protected $_eventBase = null; - - /** - * All listeners for read/write event. - * @var array - */ - protected $_allEvents = array(); - - /** - * Event listeners of signal. - * @var array - */ - protected $_eventSignal = array(); - - /** - * All timer event listeners. - * [func, args, event, flag, time_interval] - * @var array - */ - protected $_eventTimer = array(); - - /** - * Timer id. - * @var int - */ - protected static $_timerId = 1; - - /** - * construct - * @return void - */ - public function __construct() - { - if (\class_exists('\\\\EventBase', false)) { - $class_name = '\\\\EventBase'; - } else { - $class_name = '\EventBase'; - } - $this->_eventBase = new $class_name(); - } - - /** - * @see EventInterface::add() - */ - public function add($fd, $flag, $func, $args=array()) - { - if (\class_exists('\\\\Event', false)) { - $class_name = '\\\\Event'; - } else { - $class_name = '\Event'; - } - switch ($flag) { - case self::EV_SIGNAL: - - $fd_key = (int)$fd; - $event = $class_name::signal($this->_eventBase, $fd, $func); - if (!$event||!$event->add()) { - return false; - } - $this->_eventSignal[$fd_key] = $event; - return true; - - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - - $param = array($func, (array)$args, $flag, $fd, self::$_timerId); - $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT|$class_name::PERSIST, array($this, "timerCallback"), $param); - if (!$event||!$event->addTimer($fd)) { - return false; - } - $this->_eventTimer[self::$_timerId] = $event; - return self::$_timerId++; - - default : - $fd_key = (int)$fd; - $real_flag = $flag === self::EV_READ ? $class_name::READ | $class_name::PERSIST : $class_name::WRITE | $class_name::PERSIST; - $event = new $class_name($this->_eventBase, $fd, $real_flag, $func, $fd); - if (!$event||!$event->add()) { - return false; - } - $this->_allEvents[$fd_key][$flag] = $event; - return true; - } - } - - /** - * @see Events\EventInterface::del() - */ - public function del($fd, $flag) - { - switch ($flag) { - - case self::EV_READ: - case self::EV_WRITE: - - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][$flag])) { - $this->_allEvents[$fd_key][$flag]->del(); - unset($this->_allEvents[$fd_key][$flag]); - } - if (empty($this->_allEvents[$fd_key])) { - unset($this->_allEvents[$fd_key]); - } - break; - - case self::EV_SIGNAL: - $fd_key = (int)$fd; - if (isset($this->_eventSignal[$fd_key])) { - $this->_eventSignal[$fd_key]->del(); - unset($this->_eventSignal[$fd_key]); - } - break; - - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - if (isset($this->_eventTimer[$fd])) { - $this->_eventTimer[$fd]->del(); - unset($this->_eventTimer[$fd]); - } - break; - } - return true; - } - - /** - * Timer callback. - * @param int|null $fd - * @param int $what - * @param int $timer_id - */ - public function timerCallback($fd, $what, $param) - { - $timer_id = $param[4]; - - if ($param[2] === self::EV_TIMER_ONCE) { - $this->_eventTimer[$timer_id]->del(); - unset($this->_eventTimer[$timer_id]); - } - - try { - \call_user_func_array($param[0], $param[1]); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { - Worker::stopAll(250, $e); - } - } - - /** - * @see Events\EventInterface::clearAllTimer() - * @return void - */ - public function clearAllTimer() - { - foreach ($this->_eventTimer as $event) { - $event->del(); - } - $this->_eventTimer = array(); - } - - - /** - * @see EventInterface::loop() - */ - public function loop() - { - $this->_eventBase->loop(); - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - $this->_eventBase->exit(); - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return \count($this->_eventTimer); - } -} diff --git a/Events/EventInterface.php b/Events/EventInterface.php deleted file mode 100644 index e6f59c649..000000000 --- a/Events/EventInterface.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -interface EventInterface -{ - /** - * Read event. - * - * @var int - */ - const EV_READ = 1; - - /** - * Write event. - * - * @var int - */ - const EV_WRITE = 2; - - /** - * Except event - * - * @var int - */ - const EV_EXCEPT = 3; - - /** - * Signal event. - * - * @var int - */ - const EV_SIGNAL = 4; - - /** - * Timer event. - * - * @var int - */ - const EV_TIMER = 8; - - /** - * Timer once event. - * - * @var int - */ - const EV_TIMER_ONCE = 16; - - /** - * Add event listener to event loop. - * - * @param mixed $fd - * @param int $flag - * @param callable $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, $args = array()); - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag); - - /** - * Remove all timers. - * - * @return void - */ - public function clearAllTimer(); - - /** - * Main loop. - * - * @return void - */ - public function loop(); - - /** - * Destroy loop. - * - * @return mixed - */ - public function destroy(); - - /** - * Get Timer count. - * - * @return mixed - */ - public function getTimerCount(); -} diff --git a/Events/Libevent.php b/Events/Libevent.php deleted file mode 100644 index 5f61e9c2a..000000000 --- a/Events/Libevent.php +++ /dev/null @@ -1,225 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -use Workerman\Worker; - -/** - * libevent eventloop - */ -class Libevent implements EventInterface -{ - /** - * Event base. - * - * @var resource - */ - protected $_eventBase = null; - - /** - * All listeners for read/write event. - * - * @var array - */ - protected $_allEvents = array(); - - /** - * Event listeners of signal. - * - * @var array - */ - protected $_eventSignal = array(); - - /** - * All timer event listeners. - * [func, args, event, flag, time_interval] - * - * @var array - */ - protected $_eventTimer = array(); - - /** - * construct - */ - public function __construct() - { - $this->_eventBase = \event_base_new(); - } - - /** - * {@inheritdoc} - */ - public function add($fd, $flag, $func, $args = array()) - { - switch ($flag) { - case self::EV_SIGNAL: - $fd_key = (int)$fd; - $real_flag = \EV_SIGNAL | \EV_PERSIST; - $this->_eventSignal[$fd_key] = \event_new(); - if (!\event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { - return false; - } - if (!\event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { - return false; - } - if (!\event_add($this->_eventSignal[$fd_key])) { - return false; - } - return true; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - $event = \event_new(); - $timer_id = (int)$event; - if (!\event_set($event, 0, \EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { - return false; - } - - if (!\event_base_set($event, $this->_eventBase)) { - return false; - } - - $time_interval = $fd * 1000000; - if (!\event_add($event, $time_interval)) { - return false; - } - $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); - return $timer_id; - - default : - $fd_key = (int)$fd; - $real_flag = $flag === self::EV_READ ? \EV_READ | \EV_PERSIST : \EV_WRITE | \EV_PERSIST; - - $event = \event_new(); - - if (!\event_set($event, $fd, $real_flag, $func, null)) { - return false; - } - - if (!\event_base_set($event, $this->_eventBase)) { - return false; - } - - if (!\event_add($event)) { - return false; - } - - $this->_allEvents[$fd_key][$flag] = $event; - - return true; - } - - } - - /** - * {@inheritdoc} - */ - public function del($fd, $flag) - { - switch ($flag) { - case self::EV_READ: - case self::EV_WRITE: - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][$flag])) { - \event_del($this->_allEvents[$fd_key][$flag]); - unset($this->_allEvents[$fd_key][$flag]); - } - if (empty($this->_allEvents[$fd_key])) { - unset($this->_allEvents[$fd_key]); - } - break; - case self::EV_SIGNAL: - $fd_key = (int)$fd; - if (isset($this->_eventSignal[$fd_key])) { - \event_del($this->_eventSignal[$fd_key]); - unset($this->_eventSignal[$fd_key]); - } - break; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - // 这里 fd 为timerid - if (isset($this->_eventTimer[$fd])) { - \event_del($this->_eventTimer[$fd][2]); - unset($this->_eventTimer[$fd]); - } - break; - } - return true; - } - - /** - * Timer callback. - * - * @param mixed $_null1 - * @param int $_null2 - * @param mixed $timer_id - */ - protected function timerCallback($_null1, $_null2, $timer_id) - { - if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { - \event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); - } - try { - \call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { - Worker::stopAll(250, $e); - } - if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { - $this->del($timer_id, self::EV_TIMER_ONCE); - } - } - - /** - * {@inheritdoc} - */ - public function clearAllTimer() - { - foreach ($this->_eventTimer as $task_data) { - \event_del($task_data[2]); - } - $this->_eventTimer = array(); - } - - /** - * {@inheritdoc} - */ - public function loop() - { - \event_base_loop($this->_eventBase); - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - foreach ($this->_eventSignal as $event) { - \event_del($event); - } - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return \count($this->_eventTimer); - } -} - diff --git a/Events/React/Base.php b/Events/React/Base.php deleted file mode 100644 index bce4f7356..000000000 --- a/Events/React/Base.php +++ /dev/null @@ -1,264 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events\React; - -use Workerman\Events\EventInterface; -use React\EventLoop\TimerInterface; -use React\EventLoop\LoopInterface; - -/** - * Class StreamSelectLoop - * @package Workerman\Events\React - */ -class Base implements LoopInterface -{ - /** - * @var array - */ - protected $_timerIdMap = array(); - - /** - * @var int - */ - protected $_timerIdIndex = 0; - - /** - * @var array - */ - protected $_signalHandlerMap = array(); - - /** - * @var LoopInterface - */ - protected $_eventLoop = null; - - /** - * Base constructor. - */ - public function __construct() - { - $this->_eventLoop = new \React\EventLoop\StreamSelectLoop(); - } - - /** - * Add event listener to event loop. - * - * @param int $fd - * @param int $flag - * @param callable $func - * @param array $args - * @return bool - */ - public function add($fd, $flag, $func, array $args = array()) - { - $args = (array)$args; - switch ($flag) { - case EventInterface::EV_READ: - return $this->addReadStream($fd, $func); - case EventInterface::EV_WRITE: - return $this->addWriteStream($fd, $func); - case EventInterface::EV_SIGNAL: - if (isset($this->_signalHandlerMap[$fd])) { - $this->removeSignal($fd, $this->_signalHandlerMap[$fd]); - } - $this->_signalHandlerMap[$fd] = $func; - return $this->addSignal($fd, $func); - case EventInterface::EV_TIMER: - $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { - \call_user_func_array($func, $args); - }); - $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; - return $this->_timerIdIndex; - case EventInterface::EV_TIMER_ONCE: - $index = ++$this->_timerIdIndex; - $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { - $this->del($index,EventInterface::EV_TIMER_ONCE); - \call_user_func_array($func, $args); - }); - $this->_timerIdMap[$index] = $timer_obj; - return $this->_timerIdIndex; - } - return false; - } - - /** - * Remove event listener from event loop. - * - * @param mixed $fd - * @param int $flag - * @return bool - */ - public function del($fd, $flag) - { - switch ($flag) { - case EventInterface::EV_READ: - return $this->removeReadStream($fd); - case EventInterface::EV_WRITE: - return $this->removeWriteStream($fd); - case EventInterface::EV_SIGNAL: - if (!isset($this->_eventLoop[$fd])) { - return false; - } - $func = $this->_eventLoop[$fd]; - unset($this->_eventLoop[$fd]); - return $this->removeSignal($fd, $func); - - case EventInterface::EV_TIMER: - case EventInterface::EV_TIMER_ONCE: - if (isset($this->_timerIdMap[$fd])){ - $timer_obj = $this->_timerIdMap[$fd]; - unset($this->_timerIdMap[$fd]); - $this->cancelTimer($timer_obj); - return true; - } - } - return false; - } - - - /** - * Main loop. - * - * @return void - */ - public function loop() - { - $this->run(); - } - - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return \count($this->_timerIdMap); - } - - /** - * @param resource $stream - * @param callable $listener - */ - public function addReadStream($stream, $listener) - { - return $this->_eventLoop->addReadStream($stream, $listener); - } - - /** - * @param resource $stream - * @param callable $listener - */ - public function addWriteStream($stream, $listener) - { - return $this->_eventLoop->addWriteStream($stream, $listener); - } - - /** - * @param resource $stream - */ - public function removeReadStream($stream) - { - return $this->_eventLoop->removeReadStream($stream); - } - - /** - * @param resource $stream - */ - public function removeWriteStream($stream) - { - return $this->_eventLoop->removeWriteStream($stream); - } - - /** - * @param float|int $interval - * @param callable $callback - * @return \React\EventLoop\Timer\Timer|TimerInterface - */ - public function addTimer($interval, $callback) - { - return $this->_eventLoop->addTimer($interval, $callback); - } - - /** - * @param float|int $interval - * @param callable $callback - * @return \React\EventLoop\Timer\Timer|TimerInterface - */ - public function addPeriodicTimer($interval, $callback) - { - return $this->_eventLoop->addPeriodicTimer($interval, $callback); - } - - /** - * @param TimerInterface $timer - */ - public function cancelTimer(TimerInterface $timer) - { - return $this->_eventLoop->cancelTimer($timer); - } - - /** - * @param callable $listener - */ - public function futureTick($listener) - { - return $this->_eventLoop->futureTick($listener); - } - - /** - * @param int $signal - * @param callable $listener - */ - public function addSignal($signal, $listener) - { - return $this->_eventLoop->addSignal($signal, $listener); - } - - /** - * @param int $signal - * @param callable $listener - */ - public function removeSignal($signal, $listener) - { - return $this->_eventLoop->removeSignal($signal, $listener); - } - - /** - * Run. - */ - public function run() - { - return $this->_eventLoop->run(); - } - - /** - * Stop. - */ - public function stop() - { - return $this->_eventLoop->stop(); - } -} diff --git a/Events/React/ExtEventLoop.php b/Events/React/ExtEventLoop.php deleted file mode 100644 index 3dab25b9d..000000000 --- a/Events/React/ExtEventLoop.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events\React; - -/** - * Class ExtEventLoop - * @package Workerman\Events\React - */ -class ExtEventLoop extends Base -{ - - public function __construct() - { - $this->_eventLoop = new \React\EventLoop\ExtEventLoop(); - } -} diff --git a/Events/React/ExtLibEventLoop.php b/Events/React/ExtLibEventLoop.php deleted file mode 100644 index eb02b358e..000000000 --- a/Events/React/ExtLibEventLoop.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events\React; -use Workerman\Events\EventInterface; - -/** - * Class ExtLibEventLoop - * @package Workerman\Events\React - */ -class ExtLibEventLoop extends Base -{ - public function __construct() - { - $this->_eventLoop = new \React\EventLoop\ExtLibeventLoop(); - } -} diff --git a/Events/React/StreamSelectLoop.php b/Events/React/StreamSelectLoop.php deleted file mode 100644 index 7f5f94bda..000000000 --- a/Events/React/StreamSelectLoop.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events\React; - -/** - * Class StreamSelectLoop - * @package Workerman\Events\React - */ -class StreamSelectLoop extends Base -{ - public function __construct() - { - $this->_eventLoop = new \React\EventLoop\StreamSelectLoop(); - } -} diff --git a/Events/Select.php b/Events/Select.php deleted file mode 100644 index 069ab8b6d..000000000 --- a/Events/Select.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -/** - * select eventloop - */ -class Select implements EventInterface -{ - /** - * All listeners for read/write event. - * - * @var array - */ - public $_allEvents = array(); - - /** - * Event listeners of signal. - * - * @var array - */ - public $_signalEvents = array(); - - /** - * Fds waiting for read event. - * - * @var array - */ - protected $_readFds = array(); - - /** - * Fds waiting for write event. - * - * @var array - */ - protected $_writeFds = array(); - - /** - * Fds waiting for except event. - * - * @var array - */ - protected $_exceptFds = array(); - - /** - * Timer scheduler. - * {['data':timer_id, 'priority':run_timestamp], ..} - * - * @var \SplPriorityQueue - */ - protected $_scheduler = null; - - /** - * All timer event listeners. - * [[func, args, flag, timer_interval], ..] - * - * @var array - */ - protected $_eventTimer = array(); - - /** - * Timer id. - * - * @var int - */ - protected $_timerId = 1; - - /** - * Select timeout. - * - * @var int - */ - protected $_selectTimeout = 100000000; - - /** - * Paired socket channels - * - * @var array - */ - protected $channel = array(); - - /** - * Construct. - */ - public function __construct() - { - // Init SplPriorityQueue. - $this->_scheduler = new \SplPriorityQueue(); - $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); - } - - /** - * {@inheritdoc} - */ - public function add($fd, $flag, $func, $args = array()) - { - switch ($flag) { - case self::EV_READ: - case self::EV_WRITE: - $count = $flag === self::EV_READ ? \count($this->_readFds) : \count($this->_writeFds); - if ($count >= 1024) { - echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; - } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { - echo "Warning: system call select exceeded the maximum number of connections 256.\n"; - } - $fd_key = (int)$fd; - $this->_allEvents[$fd_key][$flag] = array($func, $fd); - if ($flag === self::EV_READ) { - $this->_readFds[$fd_key] = $fd; - } else { - $this->_writeFds[$fd_key] = $fd; - } - break; - case self::EV_EXCEPT: - $fd_key = (int)$fd; - $this->_allEvents[$fd_key][$flag] = array($func, $fd); - $this->_exceptFds[$fd_key] = $fd; - break; - case self::EV_SIGNAL: - // Windows not support signal. - if(\DIRECTORY_SEPARATOR !== '/') { - return false; - } - $fd_key = (int)$fd; - $this->_signalEvents[$fd_key][$flag] = array($func, $fd); - \pcntl_signal($fd, array($this, 'signalHandler')); - break; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - $timer_id = $this->_timerId++; - $run_time = \microtime(true) + $fd; - $this->_scheduler->insert($timer_id, -$run_time); - $this->_eventTimer[$timer_id] = array($func, (array)$args, $flag, $fd); - $select_timeout = ($run_time - \microtime(true)) * 1000000; - $select_timeout = $select_timeout <= 0 ? 1 : $select_timeout; - if( $this->_selectTimeout > $select_timeout ){ - $this->_selectTimeout = (int) $select_timeout; - } - return $timer_id; - } - - return true; - } - - /** - * Signal handler. - * - * @param int $signal - */ - public function signalHandler($signal) - { - \call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal)); - } - - /** - * {@inheritdoc} - */ - public function del($fd, $flag) - { - $fd_key = (int)$fd; - switch ($flag) { - case self::EV_READ: - unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]); - if (empty($this->_allEvents[$fd_key])) { - unset($this->_allEvents[$fd_key]); - } - return true; - case self::EV_WRITE: - unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]); - if (empty($this->_allEvents[$fd_key])) { - unset($this->_allEvents[$fd_key]); - } - return true; - case self::EV_EXCEPT: - unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]); - if(empty($this->_allEvents[$fd_key])) - { - unset($this->_allEvents[$fd_key]); - } - return true; - case self::EV_SIGNAL: - if(\DIRECTORY_SEPARATOR !== '/') { - return false; - } - unset($this->_signalEvents[$fd_key]); - \pcntl_signal($fd, SIG_IGN); - break; - case self::EV_TIMER: - case self::EV_TIMER_ONCE; - unset($this->_eventTimer[$fd_key]); - return true; - } - return false; - } - - /** - * Tick for timer. - * - * @return void - */ - protected function tick() - { - while (!$this->_scheduler->isEmpty()) { - $scheduler_data = $this->_scheduler->top(); - $timer_id = $scheduler_data['data']; - $next_run_time = -$scheduler_data['priority']; - $time_now = \microtime(true); - $this->_selectTimeout = (int) (($next_run_time - $time_now) * 1000000); - if ($this->_selectTimeout <= 0) { - $this->_scheduler->extract(); - - if (!isset($this->_eventTimer[$timer_id])) { - continue; - } - - // [func, args, flag, timer_interval] - $task_data = $this->_eventTimer[$timer_id]; - if ($task_data[2] === self::EV_TIMER) { - $next_run_time = $time_now + $task_data[3]; - $this->_scheduler->insert($timer_id, -$next_run_time); - } - \call_user_func_array($task_data[0], $task_data[1]); - if (isset($this->_eventTimer[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { - $this->del($timer_id, self::EV_TIMER_ONCE); - } - continue; - } - return; - } - $this->_selectTimeout = 100000000; - } - - /** - * {@inheritdoc} - */ - public function clearAllTimer() - { - $this->_scheduler = new \SplPriorityQueue(); - $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); - $this->_eventTimer = array(); - } - - /** - * {@inheritdoc} - */ - public function loop() - { - while (1) { - if(\DIRECTORY_SEPARATOR === '/') { - // Calls signal handlers for pending signals - \pcntl_signal_dispatch(); - } - - $read = $this->_readFds; - $write = $this->_writeFds; - $except = $this->_exceptFds; - $ret = false; - - if ($read || $write || $except) { - // Waiting read/write/signal/timeout events. - try { - $ret = @stream_select($read, $write, $except, 0, $this->_selectTimeout); - } catch (\Exception $e) {} catch (\Error $e) {} - - } else { - $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); - $ret = false; - } - - - if (!$this->_scheduler->isEmpty()) { - $this->tick(); - } - - if (!$ret) { - continue; - } - - if ($read) { - foreach ($read as $fd) { - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][self::EV_READ])) { - \call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], - array($this->_allEvents[$fd_key][self::EV_READ][1])); - } - } - } - - if ($write) { - foreach ($write as $fd) { - $fd_key = (int)$fd; - if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { - \call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], - array($this->_allEvents[$fd_key][self::EV_WRITE][1])); - } - } - } - - if($except) { - foreach($except as $fd) { - $fd_key = (int) $fd; - if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) { - \call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], - array($this->_allEvents[$fd_key][self::EV_EXCEPT][1])); - } - } - } - } - } - - /** - * Destroy loop. - * - * @return void - */ - public function destroy() - { - - } - - /** - * Get timer count. - * - * @return integer - */ - public function getTimerCount() - { - return \count($this->_eventTimer); - } -} diff --git a/Events/Swoole.php b/Events/Swoole.php deleted file mode 100644 index fcd747238..000000000 --- a/Events/Swoole.php +++ /dev/null @@ -1,230 +0,0 @@ - - * @link http://www.workerman.net/ - * @link https://github.com/ares333/Workerman - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Events; - -use Workerman\Worker; -use Swoole\Event; -use Swoole\Timer; - -class Swoole implements EventInterface -{ - - protected $_timer = array(); - - protected $_timerOnceMap = array(); - - protected $mapId = 0; - - protected $_fd = array(); - - // milisecond - public static $signalDispatchInterval = 500; - - protected $_hasSignal = false; - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::add() - */ - public function add($fd, $flag, $func, $args = array()) - { - switch ($flag) { - case self::EV_SIGNAL: - $res = \pcntl_signal($fd, $func, false); - if (! $this->_hasSignal && $res) { - Timer::tick(static::$signalDispatchInterval, - function () { - \pcntl_signal_dispatch(); - }); - $this->_hasSignal = true; - } - return $res; - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - $method = self::EV_TIMER === $flag ? 'tick' : 'after'; - if ($this->mapId > \PHP_INT_MAX) { - $this->mapId = 0; - } - $mapId = $this->mapId++; - $t = (int)($fd * 1000); - if ($t < 1) { - $t = 1; - } - $timer_id = Timer::$method($t, - function ($timer_id = null) use ($func, $args, $mapId) { - try { - \call_user_func_array($func, (array)$args); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { - Worker::stopAll(250, $e); - } - // EV_TIMER_ONCE - if (! isset($timer_id)) { - // may be deleted in $func - if (\array_key_exists($mapId, $this->_timerOnceMap)) { - $timer_id = $this->_timerOnceMap[$mapId]; - unset($this->_timer[$timer_id], - $this->_timerOnceMap[$mapId]); - } - } - }); - if ($flag === self::EV_TIMER_ONCE) { - $this->_timerOnceMap[$mapId] = $timer_id; - $this->_timer[$timer_id] = $mapId; - } else { - $this->_timer[$timer_id] = null; - } - return $timer_id; - case self::EV_READ: - case self::EV_WRITE: - $fd_key = (int) $fd; - if (! isset($this->_fd[$fd_key])) { - if ($flag === self::EV_READ) { - $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ); - $fd_type = SWOOLE_EVENT_READ; - } else { - $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE); - $fd_type = SWOOLE_EVENT_WRITE; - } - if ($res) { - $this->_fd[$fd_key] = $fd_type; - } - } else { - $fd_val = $this->_fd[$fd_key]; - $res = true; - if ($flag === self::EV_READ) { - if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) { - $res = Event::set($fd, $func, null, - SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); - $this->_fd[$fd_key] |= SWOOLE_EVENT_READ; - } - } else { - if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) { - $res = Event::set($fd, null, $func, - SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); - $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE; - } - } - } - return $res; - } - } - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::del() - */ - public function del($fd, $flag) - { - switch ($flag) { - case self::EV_SIGNAL: - return \pcntl_signal($fd, SIG_IGN, false); - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - // already remove in EV_TIMER_ONCE callback. - if (! \array_key_exists($fd, $this->_timer)) { - return true; - } - $res = Timer::clear($fd); - if ($res) { - $mapId = $this->_timer[$fd]; - if (isset($mapId)) { - unset($this->_timerOnceMap[$mapId]); - } - unset($this->_timer[$fd]); - } - return $res; - case self::EV_READ: - case self::EV_WRITE: - $fd_key = (int) $fd; - if (isset($this->_fd[$fd_key])) { - $fd_val = $this->_fd[$fd_key]; - if ($flag === self::EV_READ) { - $flag_remove = ~ SWOOLE_EVENT_READ; - } else { - $flag_remove = ~ SWOOLE_EVENT_WRITE; - } - $fd_val &= $flag_remove; - if (0 === $fd_val) { - $res = Event::del($fd); - if ($res) { - unset($this->_fd[$fd_key]); - } - } else { - $res = Event::set($fd, null, null, $fd_val); - if ($res) { - $this->_fd[$fd_key] = $fd_val; - } - } - } else { - $res = true; - } - return $res; - } - } - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::clearAllTimer() - */ - public function clearAllTimer() - { - foreach (array_keys($this->_timer) as $v) { - Timer::clear($v); - } - $this->_timer = array(); - $this->_timerOnceMap = array(); - } - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::loop() - */ - public function loop() - { - Event::wait(); - } - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::destroy() - */ - public function destroy() - { - Event::exit(); - posix_kill(posix_getpid(), SIGINT); - } - - /** - * - * {@inheritdoc} - * - * @see \Workerman\Events\EventInterface::getTimerCount() - */ - public function getTimerCount() - { - return \count($this->_timer); - } -} diff --git a/Lib/Constants.php b/Lib/Constants.php deleted file mode 100644 index f5e242411..000000000 --- a/Lib/Constants.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @copyright walkor - * @license http://www.opensource.org/licenses/mit-license.php MIT License - * - * @link http://www.workerman.net/ - */ - -// Pcre.jit is not stable, temporarily disabled. -ini_set('pcre.jit', 0); - -// For onError callback. -const WORKERMAN_CONNECT_FAIL = 1; -// For onError callback. -const WORKERMAN_SEND_FAIL = 2; - -// Define OS Type -const OS_TYPE_LINUX = 'linux'; -const OS_TYPE_WINDOWS = 'windows'; - -// Compatible with php7 -if (!class_exists('Error')) { - class Error extends Exception - { - } -} - -if (!interface_exists('SessionHandlerInterface')) { - interface SessionHandlerInterface { - public function close(); - public function destroy($session_id); - public function gc($maxlifetime); - public function open($save_path ,$session_name); - public function read($session_id); - public function write($session_id , $session_data); - } -} diff --git a/Lib/Timer.php b/Lib/Timer.php deleted file mode 100644 index b1100510c..000000000 --- a/Lib/Timer.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Lib; - -/** - * Do not use Workerman\Lib\Timer. - * Please use Workerman\Timer. - * This class is only used for compatibility with workerman 3.* - * @package Workerman\Lib - */ -class Timer extends \Workerman\Timer {} \ No newline at end of file diff --git a/README.md b/README.md index 8cc115901..f2fce987c 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,6 @@ Worker::runAll(); ### An http server ```php -onClose = function ($connection) { Worker::runAll(); ``` -### A udp server - -```php -count = 4; - -// Emitted when data received -$worker->onMessage = function($connection, $data) -{ - $connection->send($data); -}; - -Worker::runAll(); -``` - ### Enable SSL ```php array( +$context = [ + 'ssl' => [ 'local_cert' => '/your/path/of/server.pem', 'local_pk' => '/your/path/of/server.key', 'verify_peer' => false, - ) -); + ] +]; // Create a Websocket server with ssl context. $ws_worker = new Worker('websocket://0.0.0.0:2346', $context); @@ -180,7 +153,6 @@ Worker::runAll(); ### Custom protocol Protocols/MyTextProtocol.php ```php - ## Other links with workerman @@ -337,6 +296,9 @@ https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=db&l=yyku7z- [php-socks5](https://github.com/walkor/php-socks5) [php-http-proxy](https://github.com/walkor/php-http-proxy) +## Donate + + ## LICENSE Workerman is released under the [MIT license](https://github.com/walkor/workerman/blob/master/MIT-LICENSE.txt). diff --git a/composer.json b/composer.json index fdd4808a2..c1c60ada9 100644 --- a/composer.json +++ b/composer.json @@ -24,14 +24,14 @@ "source": "https://github.com/walkor/workerman" }, "require": { - "php": ">=5.3" + "php": ">=7.0" }, "suggest": { "ext-event": "For better performance. " }, "autoload": { "psr-4": { - "Workerman\\": "./" + "Workerman\\": "src" } }, "minimum-stability": "dev" diff --git a/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php similarity index 74% rename from Connection/AsyncTcpConnection.php rename to src/Connection/AsyncTcpConnection.php index 600d700be..d8f42e512 100644 --- a/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -11,10 +11,11 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; use Workerman\Events\EventInterface; -use Workerman\Lib\Timer; +use Workerman\Timer; use Workerman\Worker; use \Exception; @@ -92,15 +93,15 @@ class AsyncTcpConnection extends TcpConnection * * @var array */ - protected static $_builtinTransports = array( - 'tcp' => 'tcp', - 'udp' => 'udp', - 'unix' => 'unix', - 'ssl' => 'ssl', + protected static $_builtinTransports = [ + 'tcp' => 'tcp', + 'udp' => 'udp', + 'unix' => 'unix', + 'ssl' => 'ssl', 'sslv2' => 'sslv2', 'sslv3' => 'sslv3', - 'tls' => 'tls' - ); + 'tls' => 'tls' + ]; /** * Construct. @@ -109,12 +110,12 @@ class AsyncTcpConnection extends TcpConnection * @param array $context_option * @throws Exception */ - public function __construct($remote_address, array $context_option = array()) + public function __construct($remote_address, array $context_option = []) { $address_info = \parse_url($remote_address); if (!$address_info) { list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2); - if('unix' === strtolower($scheme)) { + if ('unix' === strtolower($scheme)) { $this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); } if (!$this->_remoteAddress) { @@ -132,22 +133,22 @@ public function __construct($remote_address, array $context_option = array()) } else { $address_info['query'] = '?' . $address_info['query']; } - $this->_remoteHost = $address_info['host']; - $this->_remotePort = $address_info['port']; - $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; - $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; - $this->_remoteAddress = 'unix' === strtolower($scheme) - ? substr($remote_address, strpos($remote_address, '/') + 2) - : $this->_remoteHost . ':' . $this->_remotePort; + $this->_remoteHost = $address_info['host']; + $this->_remotePort = $address_info['port']; + $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; + $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; + $this->_remoteAddress = 'unix' === strtolower($scheme) + ? substr($remote_address, strpos($remote_address, '/') + 2) + : $this->_remoteHost . ':' . $this->_remotePort; } $this->id = $this->_id = self::$_idRecorder++; - if(\PHP_INT_MAX === self::$_idRecorder){ + if (\PHP_INT_MAX === self::$_idRecorder) { self::$_idRecorder = 0; } // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { - $scheme = \ucfirst($scheme); + $scheme = \ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; @@ -161,9 +162,9 @@ public function __construct($remote_address, array $context_option = array()) // For statistics. ++self::$statistics['connection_count']; - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_contextOption = $context_option; + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; + $this->_contextOption = $context_option; static::$connections[$this->_id] = $this; } @@ -178,12 +179,12 @@ public function connect() $this->_status !== self::STATUS_CLOSED) { return; } - $this->_status = self::STATUS_CONNECTING; + $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = \microtime(true); if ($this->transport !== 'unix') { if (!$this->_remotePort) { $this->_remotePort = $this->transport === 'ssl' ? 443 : 80; - $this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort; + $this->_remoteAddress = $this->_remoteHost . ':' . $this->_remotePort; } // Open socket connection asynchronously. if ($this->_contextOption) { @@ -200,7 +201,7 @@ public function connect() } // If failed attempt to emit onError callback. if (!$this->_socket || !\is_resource($this->_socket)) { - $this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr); + $this->emitError(static::CONNECT_FAIL, $errstr); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } @@ -210,10 +211,10 @@ public function connect() return; } // Add socket to global event loop waiting connection is successfully established or faild. - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'checkConnection']); // For windows. - if(\DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection')); + if (\DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->onExcept($this->_socket, [$this, 'checkConnection']); } } @@ -225,13 +226,13 @@ public function connect() */ public function reconnect($after = 0) { - $this->_status = self::STATUS_INITIAL; + $this->_status = self::STATUS_INITIAL; static::$connections[$this->_id] = $this; if ($this->_reconnectTimer) { Timer::del($this->_reconnectTimer); } if ($after > 0) { - $this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false); + $this->_reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); return; } $this->connect(); @@ -270,7 +271,7 @@ public function getRemoteURI() /** * Try to emit onError callback. * - * @param int $code + * @param int $code * @param string $msg * @return void */ @@ -279,10 +280,8 @@ protected function emitError($code, $msg) $this->_status = self::STATUS_CLOSING; if ($this->onError) { try { - \call_user_func($this->onError, $this, $code, $msg); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onError)($this, $code, $msg); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -297,12 +296,12 @@ protected function emitError($code, $msg) public function checkConnection() { // Remove EV_EXPECT for windows. - if(\DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT); + if (\DIRECTORY_SEPARATOR === '\\') { + Worker::$globalEvent->offExcept($this->_socket); } // Remove write listener. - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + Worker::$globalEvent->offWritable($this->_socket); if ($this->_status !== self::STATUS_CONNECTING) { return; @@ -332,39 +331,35 @@ public function checkConnection() } else { // There are some data waiting to send. if ($this->_sendBuffer) { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); } } // Register a listener waiting read event. - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); - $this->_status = self::STATUS_ESTABLISHED; - $this->_remoteAddress = $address; + $this->_status = self::STATUS_ESTABLISHED; + $this->_remoteAddress = $address; // Try to emit onConnect callback. if ($this->onConnect) { try { - \call_user_func($this->onConnect, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onConnect)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Try to emit protocol::onConnect if ($this->protocol && \method_exists($this->protocol, 'onConnect')) { try { - \call_user_func(array($this->protocol, 'onConnect'), $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + [$this->protocol, 'onConnect']($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } } else { // Connection failed. - $this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); + $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } diff --git a/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php similarity index 83% rename from Connection/AsyncUdpConnection.php rename to src/Connection/AsyncUdpConnection.php index 745f06066..1da40a41f 100644 --- a/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; use Workerman\Events\EventInterface; @@ -62,7 +63,7 @@ public function __construct($remote_address, $context_option = null) list($scheme, $address) = \explode(':', $remote_address, 2); // Check application layer protocol class. if ($scheme !== 'udp') { - $scheme = \ucfirst($scheme); + $scheme = \ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; @@ -71,11 +72,11 @@ public function __construct($remote_address, $context_option = null) } } } - + $this->_remoteAddress = \substr($address, 2); $this->_contextOption = $context_option; } - + /** * For udp package. * @@ -88,18 +89,15 @@ public function baseRead($socket) if (false === $recv_buffer || empty($remote_address)) { return false; } - + if ($this->onMessage) { if ($this->protocol) { - $parser = $this->protocol; - $recv_buffer = $parser::decode($recv_buffer, $this); + $recv_buffer = $this->protocol::decode($recv_buffer, $this); } ++ConnectionInterface::$statistics['total_request']; try { - \call_user_func($this->onMessage, $this, $recv_buffer); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onMessage)($this, $recv_buffer); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -110,13 +108,13 @@ public function baseRead($socket) * Sends data on the connection. * * @param string $send_buffer - * @param bool $raw + * @param bool $raw * @return void|boolean */ public function send($send_buffer, $raw = false) { if (false === $raw && $this->protocol) { - $parser = $this->protocol; + $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { return; @@ -127,8 +125,8 @@ public function send($send_buffer, $raw = false) } return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0); } - - + + /** * Close connection. * @@ -142,16 +140,14 @@ public function close($data = null, $raw = false) if ($data !== null) { $this->send($data, $raw); } - Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); + Worker::$globalEvent->offReadable($this->_socket); \fclose($this->_socket); $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { try { - \call_user_func($this->onClose, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onClose)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -181,20 +177,18 @@ public function connect() Worker::safeEcho(new \Exception($errmsg)); return; } - + \stream_set_blocking($this->_socket, false); - + if ($this->onMessage) { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, [$this, 'baseRead']); } $this->connected = true; // Try to emit onConnect callback. if ($this->onConnect) { try { - \call_user_func($this->onConnect, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onConnect)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } diff --git a/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php similarity index 83% rename from Connection/ConnectionInterface.php rename to src/Connection/ConnectionInterface.php index 4d3f5e102..2295cb17b 100644 --- a/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -11,24 +11,39 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; /** * ConnectionInterface. */ -abstract class ConnectionInterface +abstract class ConnectionInterface { + /** + * Connect failed. + * + * @var int + */ + const CONNECT_FAIL = 1; + + /** + * Send failed. + * + * @var int + */ + const SEND_FAIL = 2; + /** * Statistics for status command. * * @var array */ - public static $statistics = array( + public static $statistics = [ 'connection_count' => 0, - 'total_request' => 0, - 'throw_exception' => 0, - 'send_fail' => 0, - ); + 'total_request' => 0, + 'throw_exception' => 0, + 'send_fail' => 0, + ]; /** * Emitted when data is received. @@ -51,6 +66,13 @@ abstract class ConnectionInterface */ public $onError = null; + /** + * Protocol context + * + * @var array + */ + public $protocolContext = []; + /** * Sends data on the connection. * diff --git a/Connection/TcpConnection.php b/src/Connection/TcpConnection.php similarity index 79% rename from Connection/TcpConnection.php rename to src/Connection/TcpConnection.php index 4984a506a..b190bfec3 100644 --- a/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -11,11 +11,12 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; use Workerman\Events\EventInterface; +use Workerman\Protocols\Http\Request; use Workerman\Worker; -use \Exception; /** * TcpConnection. @@ -27,7 +28,7 @@ class TcpConnection extends ConnectionInterface * * @var int */ - const READ_BUFFER_SIZE = 65535; + const READ_BUFFER_SIZE = 87380; /** * Status initial. @@ -170,7 +171,7 @@ class TcpConnection extends ConnectionInterface * @var int */ public $maxPackageSize = 1048576; - + /** * Default maximum acceptable packet size. * @@ -185,6 +186,13 @@ class TcpConnection extends ConnectionInterface */ protected static $_idRecorder = 1; + /** + * Cache. + * + * @var bool. + */ + protected static $_enableCache = true; + /** * Socket * @@ -246,32 +254,32 @@ class TcpConnection extends ConnectionInterface * * @var array */ - public static $connections = array(); + public static $connections = []; /** * Status to string. * * @var array */ - public static $_statusToString = array( - self::STATUS_INITIAL => 'INITIAL', - self::STATUS_CONNECTING => 'CONNECTING', + public static $_statusToString = [ + self::STATUS_INITIAL => 'INITIAL', + self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', - self::STATUS_CLOSING => 'CLOSING', - self::STATUS_CLOSED => 'CLOSED', - ); + self::STATUS_CLOSING => 'CLOSING', + self::STATUS_CLOSED => 'CLOSED', + ]; /** * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remote_address */ public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; $this->id = $this->_id = self::$_idRecorder++; - if(self::$_idRecorder === \PHP_INT_MAX){ + if (self::$_idRecorder === \PHP_INT_MAX) { self::$_idRecorder = 0; } $this->_socket = $socket; @@ -280,10 +288,10 @@ public function __construct($socket, $remote_address = '') if (\function_exists('stream_set_read_buffer')) { \stream_set_read_buffer($this->_socket, 0); } - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_remoteAddress = $remote_address; + Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; + $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; } @@ -306,7 +314,7 @@ public function getStatus($raw_output = true) * Sends data on the connection. * * @param mixed $send_buffer - * @param bool $raw + * @param bool $raw * @return bool|null */ public function send($send_buffer, $raw = false) @@ -317,8 +325,7 @@ public function send($send_buffer, $raw = false) // Try to call protocol::encode($send_buffer) before sending. if (false === $raw && $this->protocol !== null) { - $parser = $this->protocol; - $send_buffer = $parser::encode($send_buffer, $this); + $send_buffer = $this->protocol::encode($send_buffer, $this); if ($send_buffer === '') { return; } @@ -339,7 +346,7 @@ public function send($send_buffer, $raw = false) // Attempt to send data directly. if ($this->_sendBuffer === '') { if ($this->transport === 'ssl') { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); $this->_sendBuffer = $send_buffer; $this->checkBufferWillFull(); return; @@ -347,9 +354,7 @@ public function send($send_buffer, $raw = false) $len = 0; try { $len = @\fwrite($this->_socket, $send_buffer); - } catch (\Exception $e) { - Worker::log($e); - } catch (\Error $e) { + } catch (\Throwable $e) { Worker::log($e); } // send successful. @@ -367,10 +372,8 @@ public function send($send_buffer, $raw = false) ++self::$statistics['send_fail']; if ($this->onError) { try { - \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onError)($this, static::SEND_FAIL, 'client closed'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -379,7 +382,7 @@ public function send($send_buffer, $raw = false) } $this->_sendBuffer = $send_buffer; } - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); // Check if the send buffer will be full. $this->checkBufferWillFull(); return; @@ -404,7 +407,7 @@ public function getRemoteIp() { $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return (string) \substr($this->_remoteAddress, 0, $pos); + return (string)\substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -417,7 +420,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1); + return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -528,7 +531,7 @@ public function isIpV6() */ public function pauseRecv() { - Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); + Worker::$globalEvent->offReadable($this->_socket); $this->_isPaused = true; } @@ -540,14 +543,13 @@ public function pauseRecv() public function resumeRecv() { if ($this->_isPaused === true) { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); $this->_isPaused = false; $this->baseRead($this->_socket, false); } } - /** * Base read handler. * @@ -557,12 +559,13 @@ public function resumeRecv() */ public function baseRead($socket, $check_eof = true) { + static $requests = []; // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { if ($this->doSslHandshake($socket)) { $this->_sslHandshakeCompleted = true; if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']); } } else { return; @@ -572,7 +575,8 @@ public function baseRead($socket, $check_eof = true) $buffer = ''; try { $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (\Exception $e) {} catch (\Error $e) {} + } catch (\Throwable $e) { + } // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -582,12 +586,32 @@ public function baseRead($socket, $check_eof = true) } } else { $this->bytesRead += \strlen($buffer); - $this->_recvBuffer .= $buffer; + if ($this->_recvBuffer === '') { + if (static::$_enableCache && !isset($requests[512]) && isset($requests[$buffer])) { + ++self::$statistics['total_request']; + $request = $requests[$buffer]; + if ($request instanceof Request) { + $request = clone $request; + $requests[$buffer] = $request; + $request->connection = $this; + $this->__request = $request; + $request->properties = []; + } + try { + ($this->onMessage)($this, $request); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + return; + } + $this->_recvBuffer = $buffer; + } else { + $this->_recvBuffer .= $buffer; + } } // If the application layer protocol has been set up. if ($this->protocol !== null) { - $parser = $this->protocol; while ($this->_recvBuffer !== '' && !$this->_isPaused) { // The current packet length is known. if ($this->_currentPackageLength) { @@ -598,8 +622,9 @@ public function baseRead($socket, $check_eof = true) } else { // Get current package length. try { - $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - } catch (\Exception $e) {} catch (\Error $e) {} + $this->_currentPackageLength = $this->protocol::input($this->_recvBuffer, $this); + } catch (\Throwable $e) { + } // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -619,9 +644,9 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { + if ($one = \strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; - $this->_recvBuffer = ''; + $this->_recvBuffer = ''; } else { // Get a full package from the buffer. $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); @@ -630,15 +655,17 @@ public function baseRead($socket, $check_eof = true) } // Reset the current packet length to 0. $this->_currentPackageLength = 0; - if (!$this->onMessage) { - continue; - } try { // Decode request buffer before Emitting onMessage callback. - \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $request = $this->protocol::decode($one_request_buffer, $this); + if (static::$_enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { + $requests[$one_request_buffer] = $request; + if (\count($requests) > 512) { + unset($requests[\key($requests)]); + } + } + ($this->onMessage)($this, $request); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -651,15 +678,9 @@ public function baseRead($socket, $check_eof = true) // Applications protocol is not set. ++self::$statistics['total_request']; - if (!$this->onMessage) { - $this->_recvBuffer = ''; - return; - } try { - \call_user_func($this->onMessage, $this, $this->_recvBuffer); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onMessage)($this, $this->_recvBuffer); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } // Clean receive buffer. @@ -673,7 +694,8 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); if ($this->transport === 'ssl') { $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); } else { @@ -682,15 +704,13 @@ public function baseWrite() \restore_error_handler(); if ($len === \strlen($this->_sendBuffer)) { $this->bytesWritten += $len; - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + Worker::$globalEvent->offWritable($this->_socket); $this->_sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { - \call_user_func($this->onBufferDrain, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onBufferDrain)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -714,31 +734,32 @@ public function baseWrite() * @param resource $socket * @return bool */ - public function doSslHandshake($socket){ + public function doSslHandshake($socket) + { if (\feof($socket)) { $this->destroy(); return false; } $async = $this instanceof AsyncTcpConnection; - + /** - * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. - * You can enable ssl3 by the codes below. - */ + * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. + * You can enable ssl3 by the codes below. + */ /*if($async){ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT; }else{ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER; }*/ - - if($async){ + + if ($async) { $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; - }else{ + } else { $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - + // Hidden error. - \set_error_handler(function($errno, $errstr, $file){ + \set_error_handler(function ($errno, $errstr, $file) { if (!Worker::$daemonize) { Worker::safeEcho("SSL handshake error: $errstr \n"); } @@ -755,10 +776,8 @@ public function doSslHandshake($socket){ } if (isset($this->onSslHandshake)) { try { - \call_user_func($this->onSslHandshake, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onSslHandshake)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -773,14 +792,14 @@ public function doSslHandshake($socket){ */ public function pipe(self $dest) { - $source = $this; - $this->onMessage = function ($source, $data) use ($dest) { + $source = $this; + $this->onMessage = function ($source, $data) use ($dest) { $dest->send($data); }; - $this->onClose = function ($source) use ($dest) { + $this->onClose = function ($source) use ($dest) { $dest->close(); }; - $dest->onBufferFull = function ($dest) use ($source) { + $dest->onBufferFull = function ($dest) use ($source) { $source->pauseRecv(); }; $dest->onBufferDrain = function ($dest) use ($source) { @@ -808,7 +827,7 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { - if($this->_status === self::STATUS_CONNECTING){ + if ($this->_status === self::STATUS_CONNECTING) { $this->destroy(); return; } @@ -822,7 +841,7 @@ public function close($data = null, $raw = false) } $this->_status = self::STATUS_CLOSING; - + if ($this->_sendBuffer === '') { $this->destroy(); } else { @@ -850,10 +869,8 @@ protected function checkBufferWillFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onBufferFull) { try { - \call_user_func($this->onBufferFull, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onBufferFull)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -871,10 +888,8 @@ protected function bufferIsFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { - \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -882,7 +897,7 @@ protected function bufferIsFull() } return false; } - + /** * Whether send buffer is Empty. * @@ -890,7 +905,7 @@ protected function bufferIsFull() */ public function bufferIsEmpty() { - return empty($this->_sendBuffer); + return empty($this->_sendBuffer); } /** @@ -905,32 +920,29 @@ public function destroy() return; } // Remove event listener. - Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + Worker::$globalEvent->offReadable($this->_socket); + Worker::$globalEvent->offWritable($this->_socket); // Close socket. try { @\fclose($this->_socket); - } catch (\Exception $e) {} catch (\Error $e) {} + } catch (\Throwable $e) { + } $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { - \call_user_func($this->onClose, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onClose)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Try to emit protocol::onClose if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { - \call_user_func(array($this->protocol, 'onClose'), $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ([$this->protocol, 'onClose'])($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -948,6 +960,16 @@ public function destroy() } } + /** + * Enable or disable Cache. + * + * @param mixed $value + */ + public static function enableCache($value) + { + static::$_enableCache = (bool)$value; + } + /** * Destruct. * @@ -966,7 +988,7 @@ public function __destruct() Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } - if(0 === self::$statistics['connection_count']) { + if (0 === self::$statistics['connection_count']) { Worker::stopAll(); } } diff --git a/Connection/UdpConnection.php b/src/Connection/UdpConnection.php similarity index 95% rename from Connection/UdpConnection.php rename to src/Connection/UdpConnection.php index 9cd95ba54..7be400f40 100644 --- a/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; /** @@ -51,11 +52,11 @@ class UdpConnection extends ConnectionInterface * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remote_address */ public function __construct($socket, $remote_address) { - $this->_socket = $socket; + $this->_socket = $socket; $this->_remoteAddress = $remote_address; } @@ -63,13 +64,13 @@ public function __construct($socket, $remote_address) * Sends data on the connection. * * @param string $send_buffer - * @param bool $raw + * @param bool $raw * @return void|boolean */ public function send($send_buffer, $raw = false) { if (false === $raw && $this->protocol) { - $parser = $this->protocol; + $parser = $this->protocol; $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { return; @@ -185,7 +186,7 @@ public function isIpV6() * Close connection. * * @param mixed $data - * @param bool $raw + * @param bool $raw * @return bool */ public function close($data = null, $raw = false) @@ -195,7 +196,7 @@ public function close($data = null, $raw = false) } return true; } - + /** * Get the real socket. * diff --git a/src/Events/Ev.php b/src/Events/Ev.php new file mode 100644 index 000000000..2050fc5fc --- /dev/null +++ b/src/Events/Ev.php @@ -0,0 +1,203 @@ + + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Events; + +use Workerman\Worker; +use \EvWatcher; + +/** + * Ev eventloop + */ +class Ev implements EventInterface +{ + /** + * All listeners for read event. + * + * @var array + */ + protected $_readEvents = []; + + /** + * All listeners for write event. + * + * @var array + */ + protected $_writeEvents = []; + + /** + * Event listeners of signal. + * + * @var array + */ + protected $_eventSignal = []; + + /** + * All timer event listeners. + * + * @var array + */ + protected $_eventTimer = []; + + /** + * Timer id. + * + * @var int + */ + protected static $_timerId = 1; + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $timer_id = self::$_timerId; + $event = new \EvTimer($delay, 0, function () use ($func, $args, $timer_id) { + unset($this->_eventTimer[$timer_id]); + $func(...(array)$args); + }); + $this->_eventTimer[self::$_timerId] = $event; + return self::$_timerId++; + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + $this->_eventTimer[$timer_id]->stop(); + unset($this->_eventTimer[$timer_id]); + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $interval, $func, $args) + { + $event = new \EvTimer($interval, $interval, function () use ($func, $args) { + $func(...(array)$args); + }); + $this->_eventTimer[self::$_timerId] = $event; + return self::$_timerId++; + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + $fd_key = (int)$stream; + $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) { + $func($stream); + }); + $this->_readEvents[$fd_key] = $event; + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_readEvents[$fd_key])) { + $this->_readEvents[$fd_key]->stop(); + unset($this->_readEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + $fd_key = (int)$stream; + $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { + $func($stream); + }); + $this->_readEvents[$fd_key] = $event; + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_writeEvents[$fd_key])) { + $this->_writeEvents[$fd_key]->stop(); + unset($this->_writeEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + $event = new \EvSignal($signal, function () use ($func, $signal) { + $func($signal); + }); + $this->_eventSignal[$signal] = $event; + } + + /** + * {@inheritdoc} + */ + public function offSignal($signal) + { + if (isset($this->_eventSignal[$signal])) { + $this->_eventSignal[$signal]->stop(); + unset($this->_eventSignal[$signal]); + } + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + foreach ($this->_eventTimer as $event) { + $event->stop(); + } + $this->_eventTimer = []; + } + + /** + * {@inheritdoc} + */ + public function run() + { + \Ev::run(); + } + + /** + * {@inheritdoc} + */ + public function stop() + { + \Ev::stop(); + } + + /** + * {@inheritdoc} + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } + +} diff --git a/src/Events/Event.php b/src/Events/Event.php new file mode 100644 index 000000000..1937eda2f --- /dev/null +++ b/src/Events/Event.php @@ -0,0 +1,255 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Events; + +use Workerman\Worker; + +/** + * libevent eventloop + */ +class Event implements EventInterface +{ + /** + * Event base. + * @var object + */ + protected $_eventBase = null; + + /** + * All listeners for read event. + * @var array + */ + protected $_readEvents = []; + + /** + * All listeners for write event. + * @var array + */ + protected $_writeEvents = []; + + /** + * Event listeners of signal. + * @var array + */ + protected $_eventSignal = []; + + /** + * All timer event listeners. + * [func, args, event, flag, time_interval] + * @var array + */ + protected $_eventTimer = []; + + /** + * Timer id. + * @var int + */ + protected $_timerId = 1; + + /** + * Event class name. + * @var string + */ + protected $_eventClassName = ''; + + /** + * Construct. + * @return void + */ + public function __construct() + { + if (\class_exists('\\\\Event', false)) { + $class_name = '\\\\Event'; + } else { + $class_name = '\Event'; + } + $this->_eventClassName = $class_name; + if (\class_exists('\\\\EventBase', false)) { + $class_name = '\\\\EventBase'; + } else { + $class_name = '\EventBase'; + } + $this->_eventBase = new $class_name(); + } + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $class_name = $this->_eventClassName; + $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args) { + try { + $func(...$args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + }); + if (!$event || !$event->addTimer($delay)) { + return false; + } + $this->_eventTimer[$this->_timerId] = $event; + return $this->_timerId++; + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + $this->_eventTimer[$timer_id]->del(); + unset($this->_eventTimer[$timer_id]); + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $interval, $func, $args) + { + $class_name = $this->_eventClassName; + $event = new $this->_eventClassName($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { + try { + $func(...$args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + }); + if (!$event || !$event->addTimer($interval)) { + return false; + } + $this->_eventTimer[$this->_timerId] = $event; + return $this->_timerId++; + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + $class_name = $this->_eventClassName; + $fd_key = (int)$stream; + $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::READ | $class_name::PERSIST, $func, $stream); + if (!$event || !$event->add()) { + return false; + } + $this->_writeEvents[$fd_key] = $event; + return true; + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_readEvents[$fd_key])) { + $this->_readEvents[$fd_key]->del(); + unset($this->_readEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + $class_name = $this->_eventClassName; + $fd_key = (int)$stream; + $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::WRITE | $class_name::PERSIST, $func, $stream); + if (!$event || !$event->add()) { + return false; + } + $this->_readEvents[$fd_key] = $event; + return true; + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_writeEvents[$fd_key])) { + $this->_writeEvents[$fd_key]->del(); + unset($this->_writeEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + $class_name = $this->_eventClassName; + $fd_key = (int)$signal; + $event = $class_name::signal($this->_eventBase, $signal, $func); + if (!$event || !$event->add()) { + return false; + } + $this->_eventSignal[$fd_key] = $event; + return true; + } + + /** + * {@inheritdoc} + */ + public function offSignal($signal) + { + $fd_key = (int)$signal; + if (isset($this->_eventSignal[$fd_key])) { + $this->_eventSignal[$fd_key]->del(); + unset($this->_eventSignal[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + foreach ($this->_eventTimer as $event) { + $event->del(); + } + $this->_eventTimer = []; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->_eventBase->loop(); + } + + /** + * {@inheritdoc} + */ + public function stop() + { + $this->_eventBase->exit(); + } + + /** + * {@inheritdoc} + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } +} diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php new file mode 100644 index 000000000..5cbeda0b1 --- /dev/null +++ b/src/Events/EventInterface.php @@ -0,0 +1,111 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Events; + +interface EventInterface +{ + /** + * Delay the execution of a callback. + * @param float $delay + * @param $func + * @param $args + * @return string + */ + public function delay(float $delay, $func, $args); + + /** + * Repeatedly execute a callback. + * @param float $interval + * @param $func + * @param $args + * @return string + */ + public function repeat(float $interval, $func, $args); + + /** + * Delete a timer. + * @param $timer_id + * @return mixed + */ + public function deleteTimer($timer_id); + + /** + * Execute a callback when a stream resource becomes readable or is closed for reading. + * @param $stream + * @param $func + * @return void + */ + public function onReadable($stream, $func); + + /** + * Cancel a callback of stream readable. + * @param $stream + * @return void + */ + public function offReadable($stream); + + /** + * Execute a callback when a stream resource becomes writable or is closed for writing. + * @param $stream + * @param $func + * @return void + */ + public function onWritable($stream, $func); + + /** + * Cancel a callback of stream writable. + * @param $stream + * @return mixed + */ + public function offWritable($stream); + + /** + * Execute a callback when a signal is received. + * @param $signal + * @param $func + * @return void + */ + public function onSignal($signal, $func); + + /** + * Cancel a callback of signal. + * @param $signal + * @return void + */ + public function offSignal($signal); + + /** + * Delete all timer. + * @return void + */ + public function deleteAllTimer(); + + /** + * Run the event loop. + * @return void + */ + public function run(); + + /** + * Stop event loop. + * @return void + */ + public function stop(); + + /** + * + * @return void + */ + public function getTimerCount(); +} diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php new file mode 100644 index 000000000..a7b3c341f --- /dev/null +++ b/src/Events/Revolt.php @@ -0,0 +1,240 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Events; + +use Revolt\EventLoop\Driver; +use Revolt\EventLoop; + +/** + * Revolt eventloop + */ +class Revolt implements EventInterface +{ + /** + * @var Driver + */ + protected $_driver = null; + + /** + * All listeners for read event. + * @var array + */ + protected $_readEvents = []; + + /** + * All listeners for write event. + * @var array + */ + protected $_writeEvents = []; + + /** + * Event listeners of signal. + * @var array + */ + protected $_eventSignal = []; + + /** + * Event listeners of timer. + * @var array + */ + protected $_eventTimer = []; + + /** + * Timer id. + * @var int + */ + protected $_timerId = 1; + + /** + * Construct. + */ + public function __construct() + { + $this->_driver = EventLoop::getDriver(); + } + + /** + * {@inheritdoc} + */ + public function driver() + { + return $this->_driver; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->_driver->run(); + } + + /** + * {@inheritdoc} + */ + public function stop() + { + foreach ($this->_eventSignal as $cb_id) { + $this->_driver->cancel($cb_id); + } + $this->_driver->stop(); + pcntl_signal(SIGINT, SIG_IGN); + } + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $args = (array)$args; + $timer_id = $this->_timerId++; + $closure = function () use ($func, $args, $timer_id) { + unset($this->_eventTimer[$timer_id]); + $func(...$args); + }; + $cb_id = $this->_driver->delay($delay, $closure); + $this->_eventTimer[$timer_id] = $cb_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $interval, $func, $args) + { + $args = (array)$args; + $timer_id = $this->_timerId++; + $closure = function () use ($func, $args, $timer_id) { + $func(...$args); + }; + $cb_id = $this->_driver->repeat($interval, $closure); + $this->_eventTimer[$timer_id] = $cb_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + $fd_key = (int)$stream; + if (isset($this->_readEvents[$fd_key])) { + $this->_driver->cancel($this->_readEvents[$fd_key]); + unset($this->_readEvents[$fd_key]); + } + + $this->_readEvents[$fd_key] = $this->_driver->onReadable($stream, function () use ($stream, $func) { + $func($stream); + }); + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_readEvents[$fd_key])) { + $this->_driver->cancel($this->_readEvents[$fd_key]); + unset($this->_readEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + $fd_key = (int)$stream; + if (isset($this->_writeEvents[$fd_key])) { + $this->_driver->cancel($this->_writeEvents[$fd_key]); + unset($this->_writeEvents[$fd_key]); + } + $this->_writeEvents[$fd_key] = $this->_driver->onWritable($stream, function () use ($stream, $func) { + $func($stream); + }); + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream) + { + $fd_key = (int)$stream; + if (isset($this->_writeEvents[$fd_key])) { + $this->_driver->cancel($this->_writeEvents[$fd_key]); + unset($this->_writeEvents[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + $fd_key = (int)$signal; + if (isset($this->_eventSignal[$fd_key])) { + $this->_driver->cancel($this->_eventSignal[$fd_key]); + unset($this->_eventSignal[$fd_key]); + } + $this->_eventSignal[$fd_key] = $this->_driver->onSignal($signal, function () use ($signal, $func) { + $func($signal); + }); + } + + /** + * {@inheritdoc} + */ + public function offSignal($signal) + { + $fd_key = (int)$signal; + if (isset($this->_eventSignal[$fd_key])) { + $this->_driver->cancel($this->_eventSignal[$fd_key]); + unset($this->_eventSignal[$fd_key]); + } + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + $this->_driver->cancel($this->_eventTimer[$timer_id]); + unset($this->_eventTimer[$timer_id]); + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + foreach ($this->_eventTimer as $cb_id) { + $this->_driver->cancel($cb_id); + } + $this->_eventTimer = []; + } + + /** + * {@inheritdoc} + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } +} diff --git a/src/Events/Select.php b/src/Events/Select.php new file mode 100644 index 000000000..90a46f191 --- /dev/null +++ b/src/Events/Select.php @@ -0,0 +1,375 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Events; + +/** + * select eventloop + */ +class Select implements EventInterface +{ + /** + * All listeners for read/write event. + * + * @var array + */ + protected $_readEvents = []; + + /** + * All listeners for read/write event. + * + * @var array + */ + protected $_writeEvents = []; + + /** + * @var array + */ + protected $_exceptEvents = []; + + /** + * Event listeners of signal. + * + * @var array + */ + protected $_signalEvents = []; + + /** + * Fds waiting for read event. + * + * @var array + */ + protected $_readFds = []; + + /** + * Fds waiting for write event. + * + * @var array + */ + protected $_writeFds = []; + + /** + * Fds waiting for except event. + * + * @var array + */ + protected $_exceptFds = []; + + /** + * Timer scheduler. + * {['data':timer_id, 'priority':run_timestamp], ..} + * + * @var \SplPriorityQueue + */ + protected $_scheduler = null; + + /** + * All timer event listeners. + * [[func, args, flag, timer_interval], ..] + * + * @var array + */ + protected $_eventTimer = []; + + /** + * Timer id. + * + * @var int + */ + protected $_timerId = 1; + + /** + * Select timeout. + * + * @var int + */ + protected $_selectTimeout = 100000000; + + /** + * Construct. + */ + public function __construct() + { + // Init SplPriorityQueue. + $this->_scheduler = new \SplPriorityQueue(); + $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + } + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $timer_id = $this->_timerId++; + $run_time = \microtime(true) + $delay; + $this->_scheduler->insert($timer_id, -$run_time); + $this->_eventTimer[$timer_id] = [$func, (array)$args]; + $select_timeout = ($run_time - \microtime(true)) * 1000000; + $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; + if ($this->_selectTimeout > $select_timeout) { + $this->_selectTimeout = $select_timeout; + } + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $delay, $func, $args) + { + $timer_id = $this->_timerId++; + $run_time = \microtime(true) + $delay; + $this->_scheduler->insert($timer_id, -$run_time); + $this->_eventTimer[$timer_id] = [$func, (array)$args, $delay]; + $select_timeout = ($run_time - \microtime(true)) * 1000000; + if ($this->_selectTimeout > $select_timeout) { + $this->_selectTimeout = $select_timeout; + } + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + unset($this->_eventTimer[$timer_id]); + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + $count = \count($this->_readFds); + if ($count >= 1024) { + echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; + } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + echo "Warning: system call select exceeded the maximum number of connections 256.\n"; + } + $fd_key = (int)$stream; + $this->_readEvents[$fd_key] = $func; + $this->_readFds[$fd_key] = $stream; + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream) + { + $fd_key = (int)$stream; + unset($this->_readEvents[$fd_key], $this->_readFds[$fd_key]); + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + $count = \count($this->_writeFds); + if ($count >= 1024) { + echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; + } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + echo "Warning: system call select exceeded the maximum number of connections 256.\n"; + } + $fd_key = (int)$stream; + $this->_writeEvents[$fd_key] = $func; + $this->_writeFds[$fd_key] = $stream; + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream) + { + $fd_key = (int)$stream; + unset($this->_writeEvents[$fd_key], $this->_writeFds[$fd_key]); + } + + /** + * {@inheritdoc} + */ + public function onExcept($stream, $func) + { + $fd_key = (int)$stream; + $this->_exceptEvents[$fd_key] = $func; + $this->_exceptFds[$fd_key] = $stream; + } + + /** + * {@inheritdoc} + */ + public function offExcept($stream) + { + $fd_key = (int)$stream; + unset($this->_exceptEvents[$fd_key], $this->_exceptFds[$fd_key]); + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + if (\DIRECTORY_SEPARATOR !== '/') { + return null; + } + $this->_signalEvents[$signal] = $func; + \pcntl_signal($signal, [$this, 'signalHandler']); + } + + /** + * {@inheritdoc} + */ + public function offsignal($signal) + { + unset($this->_signalEvents[$signal]); + \pcntl_signal($signal, SIG_IGN); + } + + /** + * Signal handler. + * + * @param int $signal + */ + public function signalHandler($signal) + { + $this->_signalEvents[$signal]($signal); + } + + /** + * Tick for timer. + * + * @return void + */ + protected function tick() + { + while (!$this->_scheduler->isEmpty()) { + $scheduler_data = $this->_scheduler->top(); + $timer_id = $scheduler_data['data']; + $next_run_time = -$scheduler_data['priority']; + $time_now = \microtime(true); + $this->_selectTimeout = (int)($next_run_time - $time_now) * 1000000; + if ($this->_selectTimeout <= 0) { + $this->_scheduler->extract(); + + if (!isset($this->_eventTimer[$timer_id])) { + continue; + } + + // [func, args, timer_interval] + $task_data = $this->_eventTimer[$timer_id]; + if (isset($task_data[2])) { + $next_run_time = $time_now + $task_data[2]; + $this->_scheduler->insert($timer_id, -$next_run_time); + } else { + unset($this->_eventTimer[$timer_id]); + } + $task_data[0]($task_data[1]); + continue; + } + return; + } + $this->_selectTimeout = 100000000; + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + $this->_scheduler = new \SplPriorityQueue(); + $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->_eventTimer = []; + } + + /** + * {@inheritdoc} + */ + public function run() + { + while (1) { + if (\DIRECTORY_SEPARATOR === '/') { + // Calls signal handlers for pending signals + \pcntl_signal_dispatch(); + } + + $read = $this->_readFds; + $write = $this->_writeFds; + $except = $this->_exceptFds; + + if ($read || $write || $except) { + // Waiting read/write/signal/timeout events. + try { + @stream_select($read, $write, $except, 0, $this->_selectTimeout); + } catch (\Throwable $e) { + } + + } else { + $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); + $ret = false; + } + + if (!$this->_scheduler->isEmpty()) { + $this->tick(); + } + + foreach ($read as $fd) { + $fd_key = (int)$fd; + if (isset($this->_readEvents[$fd_key])) { + $this->_readEvents[$fd_key]($fd); + } + } + + foreach ($write as $fd) { + $fd_key = (int)$fd; + if (isset($this->_writeEvents[$fd_key])) { + $this->_writeEvents[$fd_key]($fd); + } + } + + foreach ($except as $fd) { + $fd_key = (int)$fd; + if (isset($this->_exceptEvents[$fd_key])) { + $this->_exceptEvents[$fd_key]($fd); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function stop() + { + $this->deleteAllTimer(); + foreach ($this->_signalEvents as $signal => $item) { + $this->offsignal($signal); + } + $this->_readFds = $this->_writeFds = $this->_exceptFds = $this->_readEvents + = $this->_writeEvents = $this->_exceptEvents = $this->_signalEvents = []; + } + + /** + * {@inheritdoc} + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } + +} diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php new file mode 100644 index 000000000..1f15ebdd1 --- /dev/null +++ b/src/Events/Swoole.php @@ -0,0 +1,200 @@ + + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Events; + +use Workerman\Worker; +use Swoole\Event; +use Swoole\Timer; +use Swoole\Process; + +class Swoole implements EventInterface +{ + /** + * All listeners for read timer + * @var array + */ + protected $_eventTimer = []; + + /** + * All listeners for read event. + * @var array + */ + protected $_readEvents = []; + + /** + * All listeners for write event. + * @var array + */ + protected $_writeEvents = []; + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $t = (int)($delay * 1000); + $t = $t < 1 ? 1 : $t; + $timer_id = Timer::after($t, function () use ($func, $args, &$timer_id) { + unset($this->_eventTimer[$timer_id]); + try { + $func(...(array)$args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + }); + $this->_eventTimer[$timer_id] = $timer_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + $res = Timer::clear($timer_id); + unset($this->_eventTimer[$timer_id]); + return $res; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $interval, $func, $args) + { + if ($this->mapId > \PHP_INT_MAX) { + $this->mapId = 0; + } + $t = (int)($interval * 1000); + $t = $t < 1 ? 1 : $t; + $timer_id = Timer::tick($t, function () use ($func, $args) { + try { + $func(...(array)$args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + }); + $this->_eventTimer[$timer_id] = $timer_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + $this->_readEvents[(int)$stream] = $stream; + return Event::add($stream, $func, null, \SWOOLE_EVENT_READ); + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream) + { + $fd = (int)$stream; + if (!isset($this->_readEvents[$fd])) { + return; + } + unset($this->_readEvents[$fd]); + if (!isset($this->_writeEvents[$fd])) { + return Event::del($stream); + } + return Event::set($stream, null, null, \SWOOLE_EVENT_READ); + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + $this->_writeEvents[(int)$stream] = $stream; + return Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE); + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream) + { + $fd = (int)$stream; + if (!isset($this->_writeEvents[$fd])) { + return; + } + unset($this->_writeEvents[$fd]); + if (!isset($this->_readEvents[$fd])) { + return Event::del($stream); + } + return Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + return Process::signal($signal, $func); + } + + /** + * {@inheritdoc} + */ + public function offSignal($signal) + { + return Process::signal($signal, function () { + }); + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + foreach ($this->_eventTimer as $timer_id) { + Timer::clear($timer_id); + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + Event::wait(); + } + + /** + * Destroy loop. + * + * @return void + */ + public function stop() + { + Event::exit(); + \posix_kill(posix_getpid(), SIGINT); + } + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } + +} diff --git a/Protocols/Frame.php b/src/Protocols/Frame.php similarity index 97% rename from Protocols/Frame.php rename to src/Protocols/Frame.php index 26b04de41..3678f8410 100644 --- a/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Connection\TcpConnection; @@ -23,7 +24,7 @@ class Frame /** * Check the integrity of the package. * - * @param string $buffer + * @param string $buffer * @param TcpConnection $connection * @return int */ diff --git a/Protocols/Http.php b/src/Protocols/Http.php similarity index 94% rename from Protocols/Http.php rename to src/Protocols/Http.php index fae8094e0..db0207fa6 100644 --- a/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -11,13 +11,12 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; -use Workerman\Protocols\Websocket; -use Workerman\Worker; /** * Class Http. @@ -30,7 +29,7 @@ class Http * * @var string */ - protected static $_requestClass = 'Workerman\Protocols\Http\Request'; + protected static $_requestClass = Request::class; /** * Session name. @@ -47,7 +46,7 @@ class Http protected static $_uploadTmpDir = ''; /** - * Open cache. + * Cache. * * @var bool. */ @@ -100,7 +99,7 @@ public static function enableCache($value) */ public static function input($recv_buffer, TcpConnection $connection) { - static $input = array(); + static $input = []; if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) { return $input[$recv_buffer]; } @@ -121,7 +120,7 @@ public static function input($recv_buffer, TcpConnection $connection) if (!isset($recv_buffer[512])) { $input[$recv_buffer] = $head_len; if (\count($input) > 512) { - unset($input[key($input)]); + unset($input[\key($input)]); } } return $head_len; @@ -142,7 +141,7 @@ public static function input($recv_buffer, TcpConnection $connection) if (!isset($recv_buffer[512])) { $input[$recv_buffer] = $length; if (\count($input) > 512) { - unset($input[key($input)]); + unset($input[\key($input)]); } } if ($length > $connection->maxPackageSize) { @@ -165,13 +164,13 @@ public static function input($recv_buffer, TcpConnection $connection) */ public static function decode($recv_buffer, TcpConnection $connection) { - static $requests = array(); + static $requests = []; $cacheable = static::$_enableCache && !isset($recv_buffer[512]); if (true === $cacheable && isset($requests[$recv_buffer])) { - $request = $requests[$recv_buffer]; + $request = clone $requests[$recv_buffer]; $request->connection = $connection; $connection->__request = $request; - $request->properties = array(); + $request->properties = []; return $request; } $request = new static::$_requestClass($recv_buffer); @@ -180,7 +179,7 @@ public static function decode($recv_buffer, TcpConnection $connection) if (true === $cacheable) { $requests[$recv_buffer] = $request; if (\count($requests) > 512) { - unset($requests[key($requests)]); + unset($requests[\key($requests)]); } } return $request; @@ -229,10 +228,10 @@ public static function encode($response, TcpConnection $connection) $length = $response->file['length']; $file_size = (int)\filesize($file); $body_len = $length > 0 ? $length : $file_size - $offset; - $response->withHeaders(array( + $response->withHeaders([ 'Content-Length' => $body_len, - 'Accept-Ranges' => 'bytes', - )); + 'Accept-Ranges' => 'bytes', + ]); if ($offset || $length) { $offset_end = $offset + $body_len - 1; $response->header('Content-Range', "bytes $offset-$offset_end/$file_size"); diff --git a/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php similarity index 92% rename from Protocols/Http/Chunk.php rename to src/Protocols/Http/Chunk.php index ab06a9c20..6fec54602 100644 --- a/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http; @@ -43,6 +44,6 @@ public function __construct($buffer) */ public function __toString() { - return \dechex(\strlen($this->_buffer))."\r\n$this->_buffer\r\n"; + return \dechex(\strlen($this->_buffer)) . "\r\n$this->_buffer\r\n"; } } \ No newline at end of file diff --git a/Protocols/Http/Request.php b/src/Protocols/Http/Request.php similarity index 83% rename from Protocols/Http/Request.php rename to src/Protocols/Http/Request.php index 7c36974fb..7d1b0778e 100644 --- a/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http; use Workerman\Connection\TcpConnection; @@ -43,7 +44,7 @@ class Request * * @var array */ - public $properties = array(); + public $properties = []; /** * Http buffer. @@ -64,21 +65,21 @@ class Request * * @var array */ - protected static $_headerCache = array(); + protected static $_headerCache = []; /** * Get cache. * * @var array */ - protected static $_getCache = array(); + protected static $_getCache = []; /** * Post cache. * * @var array */ - protected static $_postCache = array(); + protected static $_postCache = []; /** * Enable cache. @@ -163,7 +164,7 @@ public function header($name = null, $default = null) public function cookie($name = null, $default = null) { if (!isset($this->_data['cookie'])) { - $this->_data['cookie'] = array(); + $this->_data['cookie'] = []; \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->_data['cookie']); } if ($name === null) { @@ -291,8 +292,11 @@ public function session() * * @return bool|mixed */ - public function sessionId() + public function sessionId($session_id = null) { + if ($session_id !== null) { + $this->sid = $session_id; + } if (!isset($this->sid)) { $session_name = Http::sessionName(); $sid = $this->cookie($session_name); @@ -303,19 +307,33 @@ public function sessionId() } $sid = static::createSessionId(); $cookie_params = \session_get_cookie_params(); - $this->connection->__header['Set-Cookie'] = array($session_name . '=' . $sid - . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) - . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime']) - . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) - . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite']) - . (!$cookie_params['secure'] ? '' : '; Secure') - . (!$cookie_params['httponly'] ? '' : '; HttpOnly')); + $this->setSidCookie($session_name, $sid, $cookie_params); } $this->sid = $sid; } return $this->sid; } + /** + * Session regenerate id + * @param bool $delete_old_session + * @return void + */ + public function sessionRegenerateId($delete_old_session = false) + { + $session = $this->session(); + $session_data = $session->all(); + if ($delete_old_session) { + $session->flush(); + } + $new_sid = static::createSessionId(); + $session = new Session($new_sid); + $session->put($session_data); + $cookie_params = \session_get_cookie_params(); + $session_name = Http::sessionName(); + $this->setSidCookie($session_name, $new_sid, $cookie_params); + } + /** * Get http raw head. * @@ -391,7 +409,7 @@ protected function parseProtocolVersion() */ protected function parseHeaders() { - $this->_data['headers'] = array(); + $this->_data['headers'] = []; $raw_head = $this->rawHead(); $end_line_position = \strpos($raw_head, "\r\n"); if ($end_line_position === false) { @@ -435,7 +453,7 @@ protected function parseHeaders() protected function parseGet() { $query_string = $this->queryString(); - $this->_data['get'] = array(); + $this->_data['get'] = []; if ($query_string === '') { return; } @@ -461,7 +479,7 @@ protected function parseGet() protected function parsePost() { $body_buffer = $this->rawBody(); - $this->_data['post'] = $this->_data['files'] = array(); + $this->_data['post'] = $this->_data['files'] = []; if ($body_buffer === '') { return; } @@ -477,7 +495,7 @@ protected function parsePost() return; } if (\preg_match('/\bjson\b/i', $content_type)) { - $this->_data['post'] = (array) json_decode($body_buffer, true); + $this->_data['post'] = (array)\json_decode($body_buffer, true); } else { \parse_str($body_buffer, $this->_data['post']); } @@ -497,15 +515,15 @@ protected function parsePost() */ protected function parseUploadFiles($http_post_boundary) { - $http_post_boundary = \trim($http_post_boundary, '"'); - $http_body = $this->rawBody(); - $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); + $http_post_boundary = \trim($http_post_boundary, '"'); + $http_body = $this->rawBody(); + $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") { unset($boundary_data_array[0]); } - $key = -1; - $files = array(); + $key = -1; + $files = []; $post_str = ''; foreach ($boundary_data_array as $boundary_data_buffer) { list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); @@ -519,9 +537,9 @@ protected function parseUploadFiles($http_post_boundary) case "content-disposition": // Is file data. if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) { - $error = 0; - $tmp_file = ''; - $size = \strlen($boundary_value); + $error = 0; + $tmp_file = ''; + $size = \strlen($boundary_value); $tmp_upload_dir = HTTP::uploadTmpDir(); if (!$tmp_upload_dir) { $error = UPLOAD_ERR_NO_TMP_DIR; @@ -534,31 +552,31 @@ protected function parseUploadFiles($http_post_boundary) } } if (!isset($files[$key])) { - $files[$key] = array(); + $files[$key] = []; } // Parse upload files. - $files[$key] += array( - 'key' => $match[1], - 'name' => $match[2], + $files[$key] += [ + 'key' => $match[1], + 'name' => $match[2], 'tmp_name' => $tmp_file, - 'size' => $size, - 'error' => $error, - 'type' => null, - ); + 'size' => $size, + 'error' => $error, + 'type' => null, + ]; break; } // Is post field. else { // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { $key = $match[1]; - $post_str .= \urlencode($key)."=".\urlencode($boundary_value).'&'; + $post_str .= \urlencode($key) . "=" . \urlencode($boundary_value) . '&'; } } break; case "content-type": // add file_type if (!isset($files[$key])) { - $files[$key] = array(); + $files[$key] = []; } $files[$key]['type'] = \trim($header_value); break; @@ -568,10 +586,10 @@ protected function parseUploadFiles($http_post_boundary) foreach ($files as $file) { $key = $file['key']; unset($file['key']); - $str = \urlencode($key)."=1"; + $str = \urlencode($key) . "=1"; $result = []; \parse_str($str, $result); - \array_walk_recursive($result, function(&$value) use ($file) { + \array_walk_recursive($result, function (&$value) use ($file) { $value = $file; }); $this->_data['files'] = \array_merge($this->_data['files'], $result); @@ -586,7 +604,7 @@ protected function parseUploadFiles($http_post_boundary) * * @return string */ - protected static function createSessionId() + public static function createSessionId() { return \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand())); } @@ -653,7 +671,7 @@ public function __destruct() { if (isset($this->_data['files'])) { \clearstatcache(); - \array_walk_recursive($this->_data['files'], function($value, $key){ + \array_walk_recursive($this->_data['files'], function ($value, $key) { if ($key === 'tmp_name') { if (\is_file($value)) { \unlink($value); @@ -662,4 +680,21 @@ public function __destruct() }); } } + + /** + * @param string $session_name + * @param string $sid + * @param array $cookie_params + * @return void + */ + protected function setSidCookie(string $session_name, string $sid, array $cookie_params) + { + $this->connection->__header['Set-Cookie'] = [$session_name . '=' . $sid + . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) + . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime']) + . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) + . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite']) + . (!$cookie_params['secure'] ? '' : '; Secure') + . (!$cookie_params['httponly'] ? '' : '; HttpOnly')]; + } } diff --git a/Protocols/Http/Response.php b/src/Protocols/Http/Response.php similarity index 90% rename from Protocols/Http/Response.php rename to src/Protocols/Http/Response.php index 06b013ace..fc6a677fd 100644 --- a/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http; /** @@ -72,7 +73,7 @@ class Response * * @var array */ - protected static $_phrases = array( + protected static $_phrases = [ 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', @@ -131,14 +132,15 @@ class Response 507 => 'Insufficient Storage', 508 => 'Loop Detected', 511 => 'Network Authentication Required', - ); + ]; /** * Init. * * @return void */ - public static function init() { + public static function init() + { static::initMimeTypeMap(); } @@ -151,9 +153,10 @@ public static function init() { */ public function __construct( $status = 200, - $headers = array(), + $headers = [], $body = '' - ) { + ) + { $this->_status = $status; $this->_header = $headers; $this->_body = (string)$body; @@ -166,7 +169,8 @@ public function __construct( * @param string $value * @return $this */ - public function header($name, $value) { + public function header($name, $value) + { $this->_header[$name] = $value; return $this; } @@ -178,7 +182,8 @@ public function header($name, $value) { * @param string $value * @return Response */ - public function withHeader($name, $value) { + public function withHeader($name, $value) + { return $this->header($name, $value); } @@ -188,18 +193,20 @@ public function withHeader($name, $value) { * @param array $headers * @return $this */ - public function withHeaders($headers) { + public function withHeaders($headers) + { $this->_header = \array_merge_recursive($this->_header, $headers); return $this; } - + /** * Remove header. * * @param string $name * @return $this */ - public function withoutHeader($name) { + public function withoutHeader($name) + { unset($this->_header[$name]); return $this; } @@ -210,7 +217,8 @@ public function withoutHeader($name) { * @param string $name * @return null|array|string */ - public function getHeader($name) { + public function getHeader($name) + { if (!isset($this->_header[$name])) { return null; } @@ -222,7 +230,8 @@ public function getHeader($name) { * * @return array */ - public function getHeaders() { + public function getHeaders() + { return $this->_header; } @@ -233,7 +242,8 @@ public function getHeaders() { * @param string|null $reason_phrase * @return $this */ - public function withStatus($code, $reason_phrase = null) { + public function withStatus($code, $reason_phrase = null) + { $this->_status = $code; $this->_reason = $reason_phrase; return $this; @@ -244,7 +254,8 @@ public function withStatus($code, $reason_phrase = null) { * * @return int */ - public function getStatusCode() { + public function getStatusCode() + { return $this->_status; } @@ -253,7 +264,8 @@ public function getStatusCode() { * * @return string */ - public function getReasonPhrase() { + public function getReasonPhrase() + { return $this->_reason; } @@ -263,7 +275,8 @@ public function getReasonPhrase() { * @param int $version * @return $this */ - public function withProtocolVersion($version) { + public function withProtocolVersion($version) + { $this->_version = $version; return $this; } @@ -274,17 +287,19 @@ public function withProtocolVersion($version) { * @param string $body * @return $this */ - public function withBody($body) { + public function withBody($body) + { $this->_body = $body; return $this; } /** * Get http raw body. - * + * * @return string */ - public function rawBody() { + public function rawBody() + { return $this->_body; } @@ -296,11 +311,12 @@ public function rawBody() { * @param int $length * @return $this */ - public function withFile($file, $offset = 0, $length = 0) { + public function withFile($file, $offset = 0, $length = 0) + { if (!\is_file($file)) { return $this->withStatus(404)->withBody('

404 Not Found

'); } - $this->file = array('file' => $file, 'offset' => $offset, 'length' => $length); + $this->file = ['file' => $file, 'offset' => $offset, 'length' => $length]; return $this; } @@ -317,7 +333,7 @@ public function withFile($file, $offset = 0, $length = 0) { * @param bool $same_site * @return $this */ - public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) + public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) { $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) @@ -325,7 +341,7 @@ public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = ' . (empty($path) ? '' : '; Path=' . $path) . (!$secure ? '' : '; Secure') . (!$http_only ? '' : '; HttpOnly') - . (empty($same_site ) ? '' : '; SameSite=' . $same_site); + . (empty($same_site) ? '' : '; SameSite=' . $same_site); return $this; } @@ -375,7 +391,7 @@ protected function createHeadForFile($file_info) if (!isset($headers['Last-Modified'])) { if ($mtime = \filemtime($file)) { - $head .= 'Last-Modified: '. \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; + $head .= 'Last-Modified: ' . \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; } } @@ -427,7 +443,7 @@ public function __toString() if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $body_len\r\n\r\n"; } else { - return "$head\r\n".dechex($body_len)."\r\n{$this->_body}\r\n"; + return "$head\r\n" . dechex($body_len) . "\r\n{$this->_body}\r\n"; } // The whole http package @@ -445,8 +461,8 @@ public static function initMimeTypeMap() $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); foreach ($items as $content) { if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { - $mime_type = $match[1]; - $extension_var = $match[2]; + $mime_type = $match[1]; + $extension_var = $match[2]; $extension_array = \explode(' ', \substr($extension_var, 0, -1)); foreach ($extension_array as $file_extension) { static::$_mimeTypeMap[$file_extension] = $mime_type; @@ -455,4 +471,5 @@ public static function initMimeTypeMap() } } } + Response::init(); diff --git a/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php similarity index 99% rename from Protocols/Http/ServerSentEvents.php rename to src/Protocols/Http/ServerSentEvents.php index 7aeafc70d..db527c4bd 100644 --- a/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http; /** diff --git a/Protocols/Http/Session.php b/src/Protocols/Http/Session.php similarity index 98% rename from Protocols/Http/Session.php rename to src/Protocols/Http/Session.php index e1782e193..9453f60ea 100644 --- a/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -68,7 +69,7 @@ class Session * * @var array */ - protected $_data = array(); + protected $_data = []; /** * Session changed and need to save. @@ -163,7 +164,7 @@ public function pull($name, $default = null) /** * Store data in the session. * - * @param string $key + * @param string|array $key * @param mixed|null $value */ public function put($key, $value = null) @@ -216,7 +217,7 @@ public function all() public function flush() { $this->_needSave = true; - $this->_data = array(); + $this->_data = []; } /** @@ -260,7 +261,7 @@ public function save() /** * Refresh session expire time. - * + * * @return bool */ public function refresh() diff --git a/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php similarity index 86% rename from Protocols/Http/Session/FileSessionHandler.php rename to src/Protocols/Http/Session/FileSessionHandler.php index 5c862a5e5..e39caaa19 100644 --- a/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http\Session; /** @@ -36,7 +37,8 @@ class FileSessionHandler implements SessionHandlerInterface /** * Init. */ - public static function init() { + public static function init() + { $save_path = @\session_save_path(); if (!$save_path || \strpos($save_path, 'tcp://') === 0) { $save_path = \sys_get_temp_dir(); @@ -48,7 +50,8 @@ public static function init() { * FileSessionHandler constructor. * @param array $config */ - public function __construct($config = array()) { + public function __construct($config = []) + { if (isset($config['save_path'])) { static::sessionSavePath($config['save_path']); } @@ -81,7 +84,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - $temp_file = static::$_sessionSavePath.uniqid(mt_rand(), true); + $temp_file = static::$_sessionSavePath . uniqid(mt_rand(), true); if (!\file_put_contents($temp_file, $session_data)) { return false; } @@ -90,13 +93,13 @@ public function write($session_id, $session_data) /** * Update sesstion modify time. - * + * * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php * @see https://www.php.net/manual/zh/function.touch.php - * + * * @param string $id Session id. * @param string $data Session Data. - * + * * @return bool */ public function updateTimestamp($id, $data = "") @@ -135,10 +138,11 @@ public function destroy($session_id) /** * {@inheritdoc} */ - public function gc($maxlifetime) { + public function gc($maxlifetime) + { $time_now = \time(); foreach (\glob(static::$_sessionSavePath . static::$_sessionFilePrefix . '*') as $file) { - if(\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { + if (\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { \unlink($file); } } @@ -150,8 +154,9 @@ public function gc($maxlifetime) { * @param string $session_id * @return string */ - protected static function sessionFile($session_id) { - return static::$_sessionSavePath.static::$_sessionFilePrefix.$session_id; + protected static function sessionFile($session_id) + { + return static::$_sessionSavePath . static::$_sessionFilePrefix . $session_id; } /** @@ -160,9 +165,10 @@ protected static function sessionFile($session_id) { * @param string $path * @return string */ - public static function sessionSavePath($path) { + public static function sessionSavePath($path) + { if ($path) { - if ($path[\strlen($path)-1] !== DIRECTORY_SEPARATOR) { + if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) { $path .= DIRECTORY_SEPARATOR; } static::$_sessionSavePath = $path; diff --git a/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php similarity index 99% rename from Protocols/Http/Session/RedisSessionHandler.php rename to src/Protocols/Http/Session/RedisSessionHandler.php index 8cfe2cbbb..8ea3fba0c 100644 --- a/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http\Session; /** diff --git a/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php similarity index 99% rename from Protocols/Http/Session/SessionHandlerInterface.php rename to src/Protocols/Http/Session/SessionHandlerInterface.php index 23a47f2bb..c7ce4921d 100644 --- a/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http\Session; interface SessionHandlerInterface @@ -101,12 +102,12 @@ public function write($session_id, $session_data); /** * Update sesstion modify time. - * + * * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php - * + * * @param string $id Session id. * @param string $data Session Data. - * + * * @return bool */ public function updateTimestamp($id, $data = ""); diff --git a/Protocols/Http/mime.types b/src/Protocols/Http/mime.types similarity index 100% rename from Protocols/Http/mime.types rename to src/Protocols/Http/mime.types diff --git a/Protocols/ProtocolInterface.php b/src/Protocols/ProtocolInterface.php similarity index 91% rename from Protocols/ProtocolInterface.php rename to src/Protocols/ProtocolInterface.php index 4fea87d4c..9f5b58b19 100644 --- a/Protocols/ProtocolInterface.php +++ b/src/Protocols/ProtocolInterface.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; @@ -26,7 +27,7 @@ interface ProtocolInterface * If length is unknow please return 0 that mean wating more data. * If the package has something wrong please return false the connection will be closed. * - * @param string $recv_buffer + * @param string $recv_buffer * @param ConnectionInterface $connection * @return int|false */ @@ -35,7 +36,7 @@ public static function input($recv_buffer, ConnectionInterface $connection); /** * Decode package and emit onMessage($message) callback, $message is the result that decode returned. * - * @param string $recv_buffer + * @param string $recv_buffer * @param ConnectionInterface $connection * @return mixed */ @@ -43,8 +44,8 @@ public static function decode($recv_buffer, ConnectionInterface $connection); /** * Encode package brefore sending to client. - * - * @param mixed $data + * + * @param mixed $data * @param ConnectionInterface $connection * @return string */ diff --git a/Protocols/Text.php b/src/Protocols/Text.php similarity index 97% rename from Protocols/Text.php rename to src/Protocols/Text.php index 407ea2d1b..367e8e898 100644 --- a/Protocols/Text.php +++ b/src/Protocols/Text.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; @@ -23,7 +24,7 @@ class Text /** * Check the integrity of the package. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return int */ diff --git a/Protocols/Websocket.php b/src/Protocols/Websocket.php similarity index 70% rename from Protocols/Websocket.php rename to src/Protocols/Websocket.php index 2cc2fb7e7..585675bb2 100644 --- a/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -11,10 +11,12 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; +use Workerman\Protocols\Http\Request; use Workerman\Worker; /** @@ -39,7 +41,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface /** * Check the integrity of the package. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return int */ @@ -65,11 +67,11 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } } else { - $firstbyte = \ord($buffer[0]); - $secondbyte = \ord($buffer[1]); - $data_len = $secondbyte & 127; + $firstbyte = \ord($buffer[0]); + $secondbyte = \ord($buffer[1]); + $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; - $masked = $secondbyte >> 7; + $masked = $secondbyte >> 7; if (!$masked) { Worker::safeEcho("frame not masked so close the connection\n"); @@ -77,7 +79,7 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } - $opcode = $firstbyte & 0xf; + $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: break; @@ -90,12 +92,11 @@ public static function input($buffer, ConnectionInterface $connection) // Close package. case 0x8: // Try to emit onWebSocketClose callback. - if (isset($connection->onWebSocketClose) || isset($connection->worker->onWebSocketClose)) { + $close_cb = $connection->onWebSocketClose ?? $connection->worker->onWebSocketClose ?? false; + if ($close_cb) { try { - \call_user_func(isset($connection->onWebSocketClose)?$connection->onWebSocketClose:$connection->worker->onWebSocketClose, $connection); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $close_cb($connection); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Close connection. @@ -123,7 +124,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($head_len > $recv_len) { return 0; } - $pack = \unpack('nn/ntotal_len', $buffer); + $pack = \unpack('nn/ntotal_len', $buffer); $data_len = $pack['total_len']; } else { if ($data_len === 127) { @@ -131,8 +132,8 @@ public static function input($buffer, ConnectionInterface $connection) if ($head_len > $recv_len) { return 0; } - $arr = \unpack('n/N2c', $buffer); - $data_len = $arr['c1']*4294967296 + $arr['c2']; + $arr = \unpack('n/N2c', $buffer); + $data_len = $arr['c1'] * 4294967296 + $arr['c2']; } } $current_frame_length = $head_len + $data_len; @@ -151,12 +152,11 @@ public static function input($buffer, ConnectionInterface $connection) $connection->consumeRecvBuffer($current_frame_length); $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; - if (isset($connection->onWebSocketPing) || isset($connection->worker->onWebSocketPing)) { + $ping_cb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false; + if ($ping_cb) { try { - \call_user_func(isset($connection->onWebSocketPing)?$connection->onWebSocketPing:$connection->worker->onWebSocketPing, $connection, $ping_data); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $ping_cb($connection, $ping_data); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } else { @@ -175,12 +175,11 @@ public static function input($buffer, ConnectionInterface $connection) $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. - if (isset($connection->onWebSocketPong) || isset($connection->worker->onWebSocketPong)) { + $pong_cb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false; + if ($pong_cb) { try { - \call_user_func(isset($connection->onWebSocketPong)?$connection->onWebSocketPong:$connection->worker->onWebSocketPong, $connection, $pong_data); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $pong_cb($connection, $pong_data); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -207,7 +206,7 @@ public static function input($buffer, ConnectionInterface $connection) elseif ($connection->websocketCurrentFrameLength < $recv_len) { static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $current_frame_length = $connection->websocketCurrentFrameLength; + $current_frame_length = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. return static::input(\substr($buffer, $current_frame_length), $connection); @@ -220,7 +219,7 @@ public static function input($buffer, ConnectionInterface $connection) /** * Websocket encode. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return string */ @@ -255,10 +254,8 @@ public static function encode($buffer, ConnectionInterface $connection) if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -269,15 +266,12 @@ public static function encode($buffer, ConnectionInterface $connection) if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { if ($connection->onBufferFull) { try { - \call_user_func($connection->onBufferFull, $connection); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onBufferFull)($connection); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } } - // Return empty string. return ''; } @@ -288,7 +282,7 @@ public static function encode($buffer, ConnectionInterface $connection) /** * Websocket decode. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return string */ @@ -297,14 +291,14 @@ public static function decode($buffer, ConnectionInterface $connection) $len = \ord($buffer[1]) & 127; if ($len === 126) { $masks = \substr($buffer, 4, 4); - $data = \substr($buffer, 8); + $data = \substr($buffer, 8); } else { if ($len === 127) { $masks = \substr($buffer, 10, 4); - $data = \substr($buffer, 14); + $data = \substr($buffer, 14); } else { $masks = \substr($buffer, 2, 4); - $data = \substr($buffer, 6); + $data = \substr($buffer, 6); } } $dataLength = \strlen($data); @@ -315,7 +309,7 @@ public static function decode($buffer, ConnectionInterface $connection) return $connection->websocketDataBuffer; } else { if ($connection->websocketDataBuffer !== '') { - $decoded = $connection->websocketDataBuffer . $decoded; + $decoded = $connection->websocketDataBuffer . $decoded; $connection->websocketDataBuffer = ''; } return $decoded; @@ -325,7 +319,7 @@ public static function decode($buffer, ConnectionInterface $connection) /** * Websocket handshake. * - * @param string $buffer + * @param string $buffer * @param TcpConnection $connection * @return int */ @@ -345,7 +339,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { - $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", true); return 0; } @@ -353,10 +347,10 @@ public static function dealHandshake($buffer, TcpConnection $connection) $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n" - ."Upgrade: websocket\r\n" - ."Sec-WebSocket-Version: 13\r\n" - ."Connection: Upgrade\r\n" - ."Sec-WebSocket-Accept: " . $new_key . "\r\n"; + . "Upgrade: websocket\r\n" + . "Sec-WebSocket-Version: 13\r\n" + . "Connection: Upgrade\r\n" + . "Sec-WebSocket-Accept: " . $new_key . "\r\n"; // Websocket data buffer. $connection->websocketDataBuffer = ''; @@ -375,7 +369,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) $has_server_header = false; if (isset($connection->headers)) { - if (\is_array($connection->headers)) { + if (\is_array($connection->headers)) { foreach ($connection->headers as $header) { if (\strpos($header, 'Server:') === 0) { $has_server_header = true; @@ -387,7 +381,7 @@ public static function dealHandshake($buffer, TcpConnection $connection) } } if (!$has_server_header) { - $handshake_message .= "Server: workerman/".Worker::VERSION."\r\n"; + $handshake_message .= "Server: workerman/" . Worker::VERSION . "\r\n"; } $handshake_message .= "\r\n"; // Send handshake response. @@ -396,21 +390,13 @@ public static function dealHandshake($buffer, TcpConnection $connection) $connection->websocketHandshake = true; // Try to emit onWebSocketConnect callback. - $on_websocket_connect = isset($connection->onWebSocketConnect) ? $connection->onWebSocketConnect : - (isset($connection->worker->onWebSocketConnect) ? $connection->worker->onWebSocketConnect : false); + $on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; if ($on_websocket_connect) { - static::parseHttpHeader($buffer); try { - \call_user_func($on_websocket_connect, $connection, $buffer); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $on_websocket_connect($connection, new Request($buffer)); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } - if (!empty($_SESSION) && \class_exists('\GatewayWorker\Lib\Context')) { - $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); - } - $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); } // There are data waiting to be sent. @@ -430,63 +416,9 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } // Bad websocket handshake request. - $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n

WebSocket


workerman/".Worker::VERSION."
", + $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", true); return 0; } - /** - * Parse http header. - * - * @param string $buffer - * @return void - */ - protected static function parseHttpHeader($buffer) - { - // Parse headers. - list($http_header, ) = \explode("\r\n\r\n", $buffer, 2); - $header_data = \explode("\r\n", $http_header); - - if ($_SERVER) { - $_SERVER = array(); - } - - list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = \explode(' ', - $header_data[0]); - - unset($header_data[0]); - foreach ($header_data as $content) { - // \r\n\r\n - if (empty($content)) { - continue; - } - list($key, $value) = \explode(':', $content, 2); - $key = \str_replace('-', '_', \strtoupper($key)); - $value = \trim($value); - $_SERVER['HTTP_' . $key] = $value; - switch ($key) { - // HTTP_HOST - case 'HOST': - $tmp = \explode(':', $value); - $_SERVER['SERVER_NAME'] = $tmp[0]; - if (isset($tmp[1])) { - $_SERVER['SERVER_PORT'] = $tmp[1]; - } - break; - // cookie - case 'COOKIE': - \parse_str(\str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); - break; - } - } - - // QUERY_STRING - $_SERVER['QUERY_STRING'] = \parse_url($_SERVER['REQUEST_URI'], \PHP_URL_QUERY); - if ($_SERVER['QUERY_STRING']) { - // $GET - \parse_str($_SERVER['QUERY_STRING'], $_GET); - } else { - $_SERVER['QUERY_STRING'] = ''; - } - } } diff --git a/Protocols/Ws.php b/src/Protocols/Ws.php similarity index 79% rename from Protocols/Ws.php rename to src/Protocols/Ws.php index 449a419d8..d1d631d22 100644 --- a/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -11,10 +11,11 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; use Workerman\Connection\TcpConnection; use Workerman\Connection\ConnectionInterface; @@ -40,7 +41,7 @@ class Ws /** * Check the integrity of the package. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return int */ @@ -67,11 +68,11 @@ public static function input($buffer, ConnectionInterface $connection) } } else { - $firstbyte = \ord($buffer[0]); - $secondbyte = \ord($buffer[1]); - $data_len = $secondbyte & 127; + $firstbyte = \ord($buffer[0]); + $secondbyte = \ord($buffer[1]); + $data_len = $secondbyte & 127; $is_fin_frame = $firstbyte >> 7; - $masked = $secondbyte >> 7; + $masked = $secondbyte >> 7; if ($masked) { Worker::safeEcho("frame masked so close the connection\n"); @@ -79,7 +80,7 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } - $opcode = $firstbyte & 0xf; + $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: @@ -95,10 +96,8 @@ public static function input($buffer, ConnectionInterface $connection) // Try to emit onWebSocketClose callback. if (isset($connection->onWebSocketClose)) { try { - \call_user_func($connection->onWebSocketClose, $connection); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onWebSocketClose)($connection); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Close connection. @@ -130,7 +129,7 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } $arr = \unpack('n/N2c', $buffer); - $current_frame_length = $arr['c1']*4294967296 + $arr['c2'] + 10; + $current_frame_length = $arr['c1'] * 4294967296 + $arr['c2'] + 10; } else { $current_frame_length = $data_len + 2; } @@ -151,10 +150,8 @@ public static function input($buffer, ConnectionInterface $connection) $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing)) { try { - \call_user_func($connection->onWebSocketPing, $connection, $ping_data); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onWebSocketPing)($connection, $ping_data); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } else { @@ -176,10 +173,8 @@ public static function input($buffer, ConnectionInterface $connection) // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong)) { try { - \call_user_func($connection->onWebSocketPong, $connection, $pong_data); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onWebSocketPong)($connection, $pong_data); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -205,7 +200,7 @@ public static function input($buffer, ConnectionInterface $connection) elseif ($connection->websocketCurrentFrameLength < $recv_len) { self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $current_frame_length = $connection->websocketCurrentFrameLength; + $current_frame_length = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. return self::input(\substr($buffer, $current_frame_length), $connection); @@ -218,7 +213,7 @@ public static function input($buffer, ConnectionInterface $connection) /** * Websocket encode. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return string */ @@ -237,10 +232,10 @@ public static function encode($payload, ConnectionInterface $connection) $pack = ''; $length = $length_flag = \strlen($payload); if (65535 < $length) { - $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); + $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); $length_flag = 127; } else if (125 < $length) { - $pack = \pack('n*', $length); + $pack = \pack('n*', $length); $length_flag = 126; } @@ -256,10 +251,8 @@ public static function encode($payload, ConnectionInterface $connection) if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { - \call_user_func($connection->onError, $connection, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -270,10 +263,8 @@ public static function encode($payload, ConnectionInterface $connection) if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { if ($connection->onBufferFull) { try { - \call_user_func($connection->onBufferFull, $connection); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onBufferFull)($connection); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -286,7 +277,7 @@ public static function encode($payload, ConnectionInterface $connection) /** * Websocket decode. * - * @param string $buffer + * @param string $buffer * @param ConnectionInterface $connection * @return string */ @@ -306,7 +297,7 @@ public static function decode($bytes, ConnectionInterface $connection) return $connection->websocketDataBuffer; } else { if ($connection->websocketDataBuffer !== '') { - $decoded_data = $connection->websocketDataBuffer . $decoded_data; + $decoded_data = $connection->websocketDataBuffer . $decoded_data; $connection->websocketDataBuffer = ''; } return $decoded_data; @@ -330,10 +321,10 @@ public static function onConnect($connection) */ public static function onClose($connection) { - $connection->handshakeStep = null; + $connection->handshakeStep = null; $connection->websocketCurrentFrameLength = 0; - $connection->tmpWebsocketData = ''; - $connection->websocketDataBuffer = ''; + $connection->tmpWebsocketData = ''; + $connection->websocketDataBuffer = ''; if (!empty($connection->websocketPingTimer)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; @@ -360,34 +351,34 @@ public static function sendHandshake(TcpConnection $connection) (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); $user_header_str = ''; if (!empty($user_header)) { - if (\is_array($user_header)){ - foreach($user_header as $k=>$v){ + if (\is_array($user_header)) { + foreach ($user_header as $k => $v) { $user_header_str .= "$k: $v\r\n"; } } else { $user_header_str .= $user_header; } - $user_header_str = "\r\n".\trim($user_header_str); + $user_header_str = "\r\n" . \trim($user_header_str); } - $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n". - (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : ''). - "Connection: Upgrade\r\n". - "Upgrade: websocket\r\n". - (isset($connection->websocketOrigin) ? "Origin: ".$connection->websocketOrigin."\r\n":''). - (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":''). - "Sec-WebSocket-Version: 13\r\n". - "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; + $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" . + (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '') . + "Connection: Upgrade\r\n" . + "Upgrade: websocket\r\n" . + (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . + (isset($connection->WSClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->WSClientProtocol . "\r\n" : '') . + "Sec-WebSocket-Version: 13\r\n" . + "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; $connection->send($header, true); - $connection->handshakeStep = 1; + $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; - $connection->websocketDataBuffer = ''; - $connection->tmpWebsocketData = ''; + $connection->websocketDataBuffer = ''; + $connection->tmpWebsocketData = ''; } /** * Websocket handshake. * - * @param string $buffer + * @param string $buffer * @param TcpConnection $connection * @return int */ @@ -420,16 +411,14 @@ public static function dealHandshake($buffer, TcpConnection $connection) // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - \call_user_func($connection->onWebSocketConnect, $connection, \substr($buffer, 0, $handshake_response_length)); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshake_response_length)); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Headbeat. if (!empty($connection->websocketPingInterval)) { - $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function() use ($connection){ + $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) { if (false === $connection->send(\pack('H*', '898000000000'), true)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; @@ -449,12 +438,14 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } - public static function WSSetProtocol($connection, $params) { - $connection->WSClientProtocol = $params[0]; + public static function WSSetProtocol($connection, $params) + { + $connection->WSClientProtocol = $params[0]; } - public static function WSGetServerProtocol($connection) { - return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); + public static function WSGetServerProtocol($connection) + { + return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); } } diff --git a/Timer.php b/src/Timer.php similarity index 77% rename from Timer.php rename to src/Timer.php index 348bb3a43..2a632d873 100644 --- a/Timer.php +++ b/src/Timer.php @@ -14,14 +14,12 @@ namespace Workerman; use Workerman\Events\EventInterface; +use Workerman\Events\Select; use Workerman\Worker; use \Exception; /** * Timer. - * - * example: - * Workerman\Timer::add($time_interval, callback, array($arg1, $arg2..)); */ class Timer { @@ -35,12 +33,12 @@ class Timer * * @var array */ - protected static $_tasks = array(); + protected static $_tasks = []; /** * event * - * @var EventInterface + * @var Select */ protected static $_event = null; @@ -61,7 +59,7 @@ class Timer * * @var array */ - protected static $_status = array(); + protected static $_status = []; /** * Init. @@ -76,7 +74,7 @@ public static function init($event = null) return; } if (\function_exists('pcntl_signal')) { - \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); + \pcntl_signal(\SIGALRM, ['\Workerman\Timer', 'signalHandle'], false); } } @@ -102,20 +100,19 @@ public static function signalHandle() * @param bool $persistent * @return int|bool */ - public static function add($time_interval, $func, $args = array(), $persistent = true) + public static function add(float $time_interval, $func, $args = [], $persistent = true) { - if ($time_interval <= 0) { + if ($time_interval < 0) { Worker::safeEcho(new Exception("bad time_interval")); return false; } if ($args === null) { - $args = array(); + $args = []; } if (self::$_event) { - return self::$_event->add($time_interval, - $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); + return $persistent ? self::$_event->repeat($time_interval, $func, $args) : self::$_event->delay($time_interval, $func, $args); } if (!\is_callable($func)) { @@ -129,16 +126,27 @@ public static function add($time_interval, $func, $args = array(), $persistent = $run_time = \time() + $time_interval; if (!isset(self::$_tasks[$run_time])) { - self::$_tasks[$run_time] = array(); + self::$_tasks[$run_time] = []; } self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId; self::$_status[self::$_timerId] = true; - self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval); + self::$_tasks[$run_time][self::$_timerId] = [$func, (array)$args, $persistent, $time_interval]; return self::$_timerId; } + /** + * @param float $delay + * @param $func + * @param array $args + * @return bool|int + */ + public function delay(float $delay, $func, $args = []) + { + return $this->add($delay, $func, $args); + } + /** * Tick. @@ -160,14 +168,14 @@ public static function tick() $persistent = $one_task[2]; $time_interval = $one_task[3]; try { - \call_user_func_array($task_func, $task_args); - } catch (\Exception $e) { + $task_func(...$task_args); + } catch (\Throwable $e) { Worker::safeEcho($e); } if($persistent && !empty(self::$_status[$index])) { $new_run_time = \time() + $time_interval; - if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array(); - self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval); + if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = []; + self::$_tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval]; } } unset(self::$_tasks[$run_time]); @@ -184,7 +192,7 @@ public static function tick() public static function del($timer_id) { if (self::$_event) { - return self::$_event->del($timer_id, EventInterface::EV_TIMER); + return self::$_event->deleteTimer($timer_id); } foreach(self::$_tasks as $run_time => $task_data) @@ -204,10 +212,10 @@ public static function del($timer_id) */ public static function delAll() { - self::$_tasks = self::$_status = array(); + self::$_tasks = self::$_status = []; \pcntl_alarm(0); if (self::$_event) { - self::$_event->clearAllTimer(); + self::$_event->deleteAllTimer(); } } } diff --git a/Worker.php b/src/Worker.php similarity index 87% rename from Worker.php rename to src/Worker.php index 4fd5c4ca3..aca9652af 100644 --- a/Worker.php +++ b/src/Worker.php @@ -12,16 +12,16 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ namespace Workerman; -require_once __DIR__ . '/Lib/Constants.php'; use Workerman\Events\EventInterface; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; -use Workerman\Lib\Timer; +use Workerman\Timer; use Workerman\Events\Select; use \Exception; + /** * Worker class * A container for listening ports @@ -33,7 +33,7 @@ class Worker * * @var string */ - const VERSION = '4.0.32'; + const VERSION = '5.0.0'; /** * Status starting. @@ -63,14 +63,6 @@ class Worker */ const STATUS_RELOADING = 8; - /** - * After sending the restart command to the child process KILL_WORKER_TIMER_TIME seconds, - * if the process is still living then forced to kill. - * - * @var int - */ - const KILL_WORKER_TIMER_TIME = 2; - /** * Default backlog. Backlog is the maximum length of the queue of pending connections. * @@ -215,7 +207,7 @@ class Worker * * @var array */ - public $connections = array(); + public $connections = []; /** * Application layer protocol. @@ -224,13 +216,6 @@ class Worker */ public $protocol = null; - /** - * Root path for autoload. - * - * @var string - */ - protected $_autoloadRootPath = ''; - /** * Pause accept new connections or not. * @@ -271,7 +256,7 @@ class Worker * @var string */ public static $statusFile = ''; - + /** * Log file. * @@ -282,7 +267,7 @@ class Worker /** * Global event loop. * - * @var EventInterface + * @var Select */ public static $globalEvent = null; @@ -314,6 +299,20 @@ class Worker */ public static $processTitle = 'WorkerMan'; + /** + * After sending the stop command to the child process stopTimeout seconds, + * if the process is still living then forced to kill. + * + * @var int + */ + public static $stopTimeout = 2; + + /** + * Command + * @var string + */ + public static $command = ''; + /** * The PID of master process. * @@ -354,7 +353,7 @@ class Worker * * @var Worker[] */ - protected static $_workers = array(); + protected static $_workers = []; /** * All worker processes pid. @@ -362,7 +361,7 @@ class Worker * * @var array */ - protected static $_pidMap = array(); + protected static $_pidMap = []; /** * All worker processes waiting for restart. @@ -370,7 +369,7 @@ class Worker * * @var array */ - protected static $_pidsToRestart = array(); + protected static $_pidsToRestart = []; /** * Mapping from PID to worker process ID. @@ -378,7 +377,7 @@ class Worker * * @var array */ - protected static $_idMap = array(); + protected static $_idMap = []; /** * Current status. @@ -443,58 +442,51 @@ class Worker */ protected static $_startFile = ''; - /** - * OS. - * - * @var string - */ - protected static $_OS = \OS_TYPE_LINUX; - /** * Processes for windows. * * @var array */ - protected static $_processForWindows = array(); + protected static $_processForWindows = []; /** * Status info of current worker process. * * @var array */ - protected static $_globalStatistics = array( + protected static $_globalStatistics = [ 'start_timestamp' => 0, - 'worker_exit_info' => array() - ); + 'worker_exit_info' => [] + ]; /** * Available event loops. * * @var array */ - protected static $_availableEventLoops = array( + protected static $_availableEventLoops = [ 'event' => '\Workerman\Events\Event', 'libevent' => '\Workerman\Events\Libevent' - ); + ]; /** * PHP built-in protocols. * * @var array */ - protected static $_builtinTransports = array( + protected static $_builtinTransports = [ 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', 'ssl' => 'tcp' - ); + ]; /** * PHP built-in error types. * * @var array */ - protected static $_errorType = array( + protected static $_errorType = [ \E_ERROR => 'E_ERROR', // 1 \E_WARNING => 'E_WARNING', // 2 \E_PARSE => 'E_PARSE', // 4 @@ -510,7 +502,7 @@ class Worker \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 \E_DEPRECATED => 'E_DEPRECATED', // 8192 \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 - ); + ]; /** * Graceful stop or not. @@ -562,9 +554,6 @@ protected static function checkSapiEnv() if (\PHP_SAPI !== 'cli') { exit("Only run in command line mode \n"); } - if (\DIRECTORY_SEPARATOR === '\\') { - self::$_OS = \OS_TYPE_WINDOWS; - } } /** @@ -592,7 +581,7 @@ protected static function init() // Log file. if (empty(static::$logFile)) { - static::$logFile = __DIR__ . '/../workerman.log'; + static::$logFile = __DIR__ . '/../../workerman.log'; } $log_file = (string)static::$logFile; if (!\is_file($log_file)) { @@ -648,12 +637,10 @@ protected static function unlock() */ protected static function initWorkers() { - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { return; } - - static::$_statisticsFile = static::$statusFile ? static::$statusFile : __DIR__ . '/../workerman-' .posix_getpid().'.status'; - + static::$_statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' .posix_getpid().'.status'; foreach (static::$_workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -678,7 +665,7 @@ protected static function initWorkers() // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; - $prop_length = \strlen((string) $worker->{$prop}); + $prop_length = \strlen($worker->{$prop}); $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; static::$$key = \max(static::$$key, $prop_length); } @@ -716,7 +703,7 @@ public static function getAllWorkers() /** * Get global event-loop instance. * - * @return EventInterface + * @return Select */ public static function getEventLoop() { @@ -738,7 +725,7 @@ public function getMainSocket(){ protected static function initId() { foreach (static::$_workers as $worker_id => $worker) { - $new_id_map = array(); + $new_id_map = []; $worker->count = $worker->count < 1 ? 1 : $worker->count; for($key = 0; $key < $worker->count; $key++) { $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; @@ -765,20 +752,20 @@ protected static function getCurrentUser() */ protected static function displayUI() { - global $argv; - if (\in_array('-q', $argv)) { + $tmp_argv = static::getArgv(); + if (\in_array('-q', $tmp_argv)) { return; } - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("worker listen processes status\r\n"); + static::safeEcho("worker listen processes status\r\n"); return; } //show version - $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 22, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \PHP_EOL; + $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); $total_length = static::getSingleLineTotalLength(); $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; @@ -800,9 +787,9 @@ protected static function displayUI() $content = ''; foreach(static::getUiColumns() as $column_name => $prop){ $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", (string) $worker->{$prop}, $matches); + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; - $content .= \str_pad((string) $worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); } $content && static::safeEcho($content . \PHP_EOL); } @@ -812,15 +799,9 @@ protected static function displayUI() !empty($content) && static::safeEcho($line_last); if (static::$daemonize) { - $tmpArgv = $argv; - foreach ($tmpArgv as $index => $value) { - if ($value == '-d') { - unset($tmpArgv[$index]); - } elseif ($value == 'start' || $value == 'restart') { - $tmpArgv[$index] = 'stop'; - } - } - static::safeEcho("Input \"php ".implode(' ', $tmpArgv)."\" to stop. Start success.\n\n"); + global $argv; + $start_file = $argv[0]; + static::safeEcho('Input "php '. $start_file . ' stop" to stop. Start success.' . "\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } @@ -829,21 +810,21 @@ protected static function displayUI() /** * Get UI columns to be shown in terminal * - * 1. $column_map: array('ui_column_name' => 'clas_property_name') + * 1. $column_map: ['ui_column_name' => 'clas_property_name'] * 2. Consider move into configuration in future * * @return array */ public static function getUiColumns() { - return array( + return [ 'proto' => 'transport', 'user' => 'user', 'worker' => 'name', 'socket' => 'socket', 'processes' => 'count', 'status' => 'status', - ); + ]; } /** @@ -874,27 +855,27 @@ public static function getSingleLineTotalLength() */ protected static function parseCommand() { - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { return; } global $argv; // Check argv; $start_file = $argv[0]; $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; - $available_commands = array( + $available_commands = [ 'start', 'stop', 'restart', 'reload', 'status', 'connections', - ); - $available_mode = array( + ]; + $available_mode = [ '-d', '-g' - ); + ]; $command = $mode = ''; - foreach ($argv as $value) { + foreach (static::getArgv() as $value) { if (\in_array($value, $available_commands)) { $command = $value; } elseif (\in_array($value, $available_mode)) { @@ -930,7 +911,7 @@ protected static function parseCommand() exit; } - $statistics_file = static::$statusFile ? static::$statusFile : __DIR__ . "/../workerman-$master_pid.status"; + $statistics_file = static::$statusFile ?: __DIR__ . "/../workerman-$master_pid.status"; // execute command. switch ($command) { @@ -1029,6 +1010,12 @@ protected static function parseCommand() } } + public static function getArgv() + { + global $argv; + return isset($argv[1]) ? $argv : (static::$command ? \explode(' ', static::$command) : $argv); + } + /** * Format status data. * @@ -1037,7 +1024,7 @@ protected static function parseCommand() */ protected static function formatStatusData($statistics_file) { - static $total_request_cache = array(); + static $total_request_cache = []; if (!\is_readable($statistics_file)) { return ''; } @@ -1046,11 +1033,11 @@ protected static function formatStatusData($statistics_file) return ''; } $status_str = ''; - $current_total_request = array(); + $current_total_request = []; $worker_info = \unserialize($info[0]); \ksort($worker_info, SORT_NUMERIC); unset($info[0]); - $data_waiting_sort = array(); + $data_waiting_sort = []; $read_process_status = false; $total_requests = 0; $total_qps = 0; @@ -1120,28 +1107,13 @@ protected static function formatStatusData($statistics_file) */ protected static function installSignal() { - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { return; } - $signalHandler = '\Workerman\Worker::signalHandler'; - // stop - \pcntl_signal(\SIGINT, $signalHandler, false); - // stop - \pcntl_signal(\SIGTERM, $signalHandler, false); - // stop - \pcntl_signal(\SIGHUP, $signalHandler, false); - // stop - \pcntl_signal(\SIGTSTP, $signalHandler, false); - // graceful stop - \pcntl_signal(\SIGQUIT, $signalHandler, false); - // reload - \pcntl_signal(\SIGUSR1, $signalHandler, false); - // graceful reload - \pcntl_signal(\SIGUSR2, $signalHandler, false); - // status - \pcntl_signal(\SIGIOT, $signalHandler, false); - // connection status - \pcntl_signal(\SIGIO, $signalHandler, false); + $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; + foreach ($signals as $signal) { + \pcntl_signal($signal, [Worker::class, 'signalHandler'], false); + } // ignore \pcntl_signal(\SIGPIPE, \SIG_IGN, false); } @@ -1153,44 +1125,14 @@ protected static function installSignal() */ protected static function reinstallSignal() { - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { return; } - $signalHandler = '\Workerman\Worker::signalHandler'; - // uninstall stop signal handler - \pcntl_signal(\SIGINT, \SIG_IGN, false); - // uninstall stop signal handler - \pcntl_signal(\SIGTERM, \SIG_IGN, false); - // uninstall stop signal handler - \pcntl_signal(\SIGHUP, \SIG_IGN, false); - // uninstall stop signal handler - \pcntl_signal(\SIGTSTP, \SIG_IGN, false); - // uninstall graceful stop signal handler - \pcntl_signal(\SIGQUIT, \SIG_IGN, false); - // uninstall reload signal handler - \pcntl_signal(\SIGUSR1, \SIG_IGN, false); - // uninstall graceful reload signal handler - \pcntl_signal(\SIGUSR2, \SIG_IGN, false); - // uninstall status signal handler - \pcntl_signal(\SIGIOT, \SIG_IGN, false); - // uninstall connections status signal handler - \pcntl_signal(\SIGIO, \SIG_IGN, false); - // reinstall stop signal handler - static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall graceful stop signal handler - static::$globalEvent->add(\SIGTSTP, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall reload signal handler - static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall graceful reload signal handler - static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall status signal handler - static::$globalEvent->add(\SIGIOT, EventInterface::EV_SIGNAL, $signalHandler); - // reinstall connection status signal handler - static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler); + $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; + foreach ($signals as $signal) { + \pcntl_signal($signal, \SIG_IGN, false); + static::$globalEvent->onSignal($signal, '\Workerman\Worker::signalHandler'); + }; } /** @@ -1239,7 +1181,7 @@ public static function signalHandler($signal) */ protected static function daemonize() { - if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) { + if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; } \umask(0); @@ -1268,7 +1210,7 @@ protected static function daemonize() */ public static function resetStd() { - if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) { + if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; } global $STDOUT, $STDERR; @@ -1303,7 +1245,7 @@ public static function resetStd() */ protected static function saveMasterPid() { - if (static::$_OS !== \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR !== '/') { return; } @@ -1351,7 +1293,7 @@ protected static function getEventLoopName() */ protected static function getAllWorkerPids() { - $pid_array = array(); + $pid_array = []; foreach (static::$_pidMap as $worker_pid_array) { foreach ($worker_pid_array as $worker_pid) { $pid_array[$worker_pid] = $worker_pid; @@ -1367,7 +1309,7 @@ protected static function getAllWorkerPids() */ protected static function forkWorkers() { - if (static::$_OS === \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR === '/') { static::forkWorkersForLinux(); } else { static::forkWorkersForWindows(); @@ -1407,8 +1349,7 @@ protected static function forkWorkersForLinux() protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); - global $argv; - if(\in_array('-q', $argv) || \count($files) === 1) + if(\in_array('-q', static::getArgv()) || \count($files) === 1) { if(\count(static::$_workers) > 1) { @@ -1425,7 +1366,7 @@ protected static function forkWorkersForWindows() $worker = current(static::$_workers); // Display UI. - static::safeEcho(\str_pad($worker->name, 30) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); + static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); @@ -1447,9 +1388,8 @@ protected static function forkWorkersForWindows() * @return array */ public static function getStartFilesForWindows() { - global $argv; - $files = array(); - foreach($argv as $file) + $files = []; + foreach(static::getArgv() as $file) { if(\is_file($file)) { @@ -1540,7 +1480,7 @@ protected static function forkOneWorkerForLinux(self $worker) if (static::$_status === static::STATUS_STARTING) { static::resetStd(); } - static::$_pidMap = array(); + static::$_pidMap = []; // Remove other listener. foreach(static::$_workers as $key => $one_worker) { if ($one_worker->workerId !== $worker->workerId) { @@ -1620,13 +1560,7 @@ public function setUserAndGroup() protected static function setProcessTitle($title) { \set_error_handler(function(){}); - // >=php 5.5 - if (\function_exists('cli_set_process_title')) { - \cli_set_process_title($title); - } // Need proctitle when php<=5.5 . - elseif (\extension_loaded('proctitle') && \function_exists('setproctitle')) { - \setproctitle($title); - } + \cli_set_process_title($title); \restore_error_handler(); } @@ -1637,7 +1571,7 @@ protected static function setProcessTitle($title) */ protected static function monitorWorkers() { - if (static::$_OS === \OS_TYPE_LINUX) { + if (\DIRECTORY_SEPARATOR === '/') { static::monitorWorkersForLinux(); } else { static::monitorWorkersForWindows(); @@ -1714,7 +1648,7 @@ protected static function monitorWorkersForWindows() { Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows"); - static::$globalEvent->loop(); + static::$globalEvent->run(); } /** @@ -1757,9 +1691,7 @@ protected static function reload() if (static::$onMasterReload) { try { \call_user_func(static::$onMasterReload); - } catch (\Exception $e) { - static::stopAll(250, $e); - } catch (\Error $e) { + } catch (\Throwable $e) { static::stopAll(250, $e); } static::initId(); @@ -1773,7 +1705,7 @@ protected static function reload() } // Send reload signal to all child processes. - $reloadable_pid_array = array(); + $reloadable_pid_array = []; foreach (static::$_pidMap as $worker_id => $worker_pid_array) { $worker = static::$_workers[$worker_id]; if ($worker->reloadable) { @@ -1802,9 +1734,9 @@ protected static function reload() $one_worker_pid = \current(static::$_pidsToRestart); // Send reload signal to a worker process. \posix_kill($one_worker_pid, $sig); - // If the process does not exit after static::KILL_WORKER_TIMER_TIME seconds try to kill it. + // If the process does not exit after stopTimeout seconds try to kill it. if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, \SIGKILL), false); + Timer::add(static::$stopTimeout, '\posix_kill', [$one_worker_pid, \SIGKILL], false); } } // For child processes. else { @@ -1814,9 +1746,7 @@ protected static function reload() if ($worker->onWorkerReload) { try { \call_user_func($worker->onWorkerReload, $worker); - } catch (\Exception $e) { - static::stopAll(250, $e); - } catch (\Error $e) { + } catch (\Throwable $e) { static::stopAll(250, $e); } } @@ -1853,7 +1783,7 @@ public static function stopAll($code = 0, $log = '') foreach ($worker_pid_array as $worker_pid) { \posix_kill($worker_pid, $sig); if(!static::$_gracefulStop){ - Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, \SIGKILL), false); + Timer::add(static::$stopTimeout, '\posix_kill', [$worker_pid, \SIGKILL], false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); @@ -1871,9 +1801,9 @@ public static function stopAll($code = 0, $log = '') } } if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { - static::$_workers = array(); + static::$_workers = []; if (static::$globalEvent) { - static::$globalEvent->destroy(); + static::$globalEvent->stop(); } try { @@ -1928,17 +1858,17 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (static::$_masterPid === \posix_getpid()) { - $all_worker_info = array(); + $all_worker_info = []; foreach(static::$_pidMap as $worker_id => $pid_array) { /** @var /Workerman/Worker $worker */ $worker = static::$_workers[$worker_id]; foreach($pid_array as $pid) { - $all_worker_info[$pid] = array('name' => $worker->name, 'listen' => $worker->getSocketName()); + $all_worker_info[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), array(2,2,2)) : array('-', '-', '-'); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2,2,2]) : ['-', '-', '-']; \file_put_contents(static::$_statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$_statisticsFile, @@ -2085,7 +2015,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN !== static::$_status) { - $error_msg = static::$_OS === \OS_TYPE_LINUX ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; + $error_msg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === \E_ERROR || $errors['type'] === \E_PARSE || @@ -2127,7 +2057,7 @@ public static function log($msg) static::safeEcho($msg); } \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' - . (static::$_OS === \OS_TYPE_LINUX ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); + . (\DIRECTORY_SEPARATOR === '/' ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); } /** @@ -2150,8 +2080,8 @@ public static function safeEcho($msg, $decorated = false) $green = "\033[32;40m"; $end = "\033[0m"; } - $msg = \str_replace(array('', '', ''), array($line, $white, $green), $msg); - $msg = \str_replace(array('', '', ''), $end, $msg); + $msg = \str_replace(['', '', ''], [$line, $white, $green], $msg); + $msg = \str_replace(['', '', '
'], $end, $msg); } elseif (!static::$_outputDecorated) { return false; } @@ -2181,7 +2111,7 @@ private static function outputStream($stream = null) static::$_outputDecorated = false; } else { static::$_outputDecorated = - static::$_OS === \OS_TYPE_LINUX && + \DIRECTORY_SEPARATOR === '/' && \function_exists('posix_isatty') && \posix_isatty($stream); } @@ -2194,17 +2124,12 @@ private static function outputStream($stream = null) * @param string $socket_name * @param array $context_option */ - public function __construct($socket_name = '', array $context_option = array()) + public function __construct($socket_name = '', array $context_option = []) { // Save all worker instances. $this->workerId = \spl_object_hash($this); static::$_workers[$this->workerId] = $this; - static::$_pidMap[$this->workerId] = array(); - - // Get autoload root path. - $backtrace = \debug_backtrace(); - $this->_autoloadRootPath = \dirname($backtrace[0]['file']); - Autoloader::setRootPath($this->_autoloadRootPath); + static::$_pidMap[$this->workerId] = []; // Context for socket. if ($socket_name) { @@ -2216,7 +2141,7 @@ public function __construct($socket_name = '', array $context_option = array()) } // Turn reusePort on. - /*if (static::$_OS === \OS_TYPE_LINUX // if linux + /*if (\DIRECTORY_SEPARATOR === '/' // if linux && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS @@ -2238,9 +2163,6 @@ public function listen() return; } - // Autoload. - Autoloader::setRootPath($this->_autoloadRootPath); - if (!$this->_mainSocket) { $local_socket = $this->parseSocketAddress(); @@ -2329,7 +2251,9 @@ protected function parseSocketAddress() { throw new Exception('Bad worker->transport ' . \var_export($this->transport, true)); } } else { - $this->transport = $scheme; + if ($this->transport === 'tcp') { + $this->transport = $scheme; + } } //local socket return static::$_builtinTransports[$this->transport] . ":" . $address; @@ -2343,7 +2267,7 @@ protected function parseSocketAddress() { public function pauseAccept() { if (static::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) { - static::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ); + static::$globalEvent->offReadable($this->_mainSocket); $this->_pauseAccept = true; } } @@ -2358,9 +2282,9 @@ public function resumeAccept() // Register a listener to be notified when server socket is ready to read. if (static::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) { if ($this->transport !== 'udp') { - static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); + static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptTcpConnection']); } else { - static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); + static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptUdpConnection']); } $this->_pauseAccept = false; } @@ -2387,10 +2311,7 @@ public function run() static::$_status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - \register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors')); - - // Set autoload root path. - Autoloader::setRootPath($this->_autoloadRootPath); + \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); // Create a global event loop. if (!static::$globalEvent) { @@ -2415,12 +2336,8 @@ public function run() // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { - \call_user_func($this->onWorkerStart, $this); - } catch (\Exception $e) { - // Avoid rapid infinite loop exit. - sleep(1); - static::stopAll(250, $e); - } catch (\Error $e) { + ($this->onWorkerStart)($this); + } catch (\Throwable $e) { // Avoid rapid infinite loop exit. sleep(1); static::stopAll(250, $e); @@ -2428,7 +2345,7 @@ public function run() } // Main loop. - static::$globalEvent->loop(); + static::$globalEvent->run(); } /** @@ -2441,11 +2358,9 @@ public function stop() // Try to emit onWorkerStop callback. if ($this->onWorkerStop) { try { - \call_user_func($this->onWorkerStop, $this); - } catch (\Exception $e) { - static::stopAll(250, $e); - } catch (\Error $e) { - static::stopAll(250, $e); + ($this->onWorkerStop)($this); + } catch (\Throwable $e) { + Worker::log($e); } } // Remove listener for server socket. @@ -2466,7 +2381,7 @@ public function stop() * @param resource $socket * @return void */ - public function acceptConnection($socket) + public function acceptTcpConnection($socket) { // Accept a connection on server socket. \set_error_handler(function(){}); @@ -2493,10 +2408,8 @@ public function acceptConnection($socket) // Try to emit onConnect callback. if ($this->onConnect) { try { - \call_user_func($this->onConnect, $connection); - } catch (\Exception $e) { - static::stopAll(250, $e); - } catch (\Error $e) { + ($this->onConnect)($connection); + } catch (\Throwable $e) { static::stopAll(250, $e); } } @@ -2519,7 +2432,8 @@ public function acceptUdpConnection($socket) // UdpConnection. $connection = new UdpConnection($socket, $remote_address); $connection->protocol = $this->protocol; - if ($this->onMessage) { + $message_cb = $this->onMessage; + if ($message_cb) { try { if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ @@ -2532,24 +2446,24 @@ public function acceptUdpConnection($socket) $package = \substr($recv_buffer, 0, $len); $recv_buffer = \substr($recv_buffer, $len); $data = $parser::decode($package, $connection); - if ($data === false) + if ($data === false) { continue; - \call_user_func($this->onMessage, $connection, $data); + } + $message_cb($connection, $data); } } else { $data = $parser::decode($recv_buffer, $connection); // Discard bad packets. - if ($data === false) + if ($data === false) { return true; - \call_user_func($this->onMessage, $connection, $data); + } + $message_cb($connection, $data); } } else { - \call_user_func($this->onMessage, $connection, $recv_buffer); + $message_cb($connection, $recv_buffer); } ++ConnectionInterface::$statistics['total_request']; - } catch (\Exception $e) { - static::stopAll(250, $e); - } catch (\Error $e) { + } catch (\Throwable $e) { static::stopAll(250, $e); } } From 5d03a9ee0bb6c89593698a260d754e9de26acffb Mon Sep 17 00:00:00 2001 From: Ezzalddeen Ali Date: Thu, 24 Mar 2022 07:39:56 +0300 Subject: [PATCH 0665/1216] Update Request.php to allow array of files like name[0]=f1 name[1]=f2 --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 7d1b0778e..0fc7edecc 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -592,7 +592,7 @@ protected function parseUploadFiles($http_post_boundary) \array_walk_recursive($result, function (&$value) use ($file) { $value = $file; }); - $this->_data['files'] = \array_merge($this->_data['files'], $result); + $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result); } if ($post_str) { parse_str($post_str, $this->_data['post']); From 91b31b49ab9d22f90b7cb3d8b92229adfec5794b Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Thu, 24 Mar 2022 23:32:06 +0800 Subject: [PATCH 0666/1216] formatting --- src/Worker.php | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index aca9652af..bf2d4d551 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -17,9 +17,8 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; -use Workerman\Timer; use Workerman\Events\Select; -use \Exception; +use Exception; /** @@ -334,12 +333,12 @@ class Worker */ protected $_socketName = ''; - /** parse from _socketName avoid parse again in master or worker + /** + * parse from _socketName avoid parse again in master or worker * LocalSocket The format is like tcp://0.0.0.0:8080 * @var string */ - - protected $_localSocket=null; + protected $_localSocket = null; /** * Context of socket. @@ -726,9 +725,9 @@ protected static function initId() { foreach (static::$_workers as $worker_id => $worker) { $new_id_map = []; - $worker->count = $worker->count < 1 ? 1 : $worker->count; + $worker->count = max($worker->count, 1); for($key = 0; $key < $worker->count; $key++) { - $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0; + $new_id_map[$key] = static::$_idMap[$worker_id][$key] ?? 0; } static::$_idMap[$worker_id] = $new_id_map; } @@ -972,7 +971,7 @@ protected static function parseCommand() $start_time = \time(); // Check master process is still alive? while (1) { - $master_is_alive = $master_pid && \posix_kill((int) $master_pid, 0); + $master_is_alive = $master_pid && \posix_kill($master_pid, 0); if ($master_is_alive) { // Timeout? if (!static::$_gracefulStop && \time() - $start_time >= $timeout) { @@ -1003,9 +1002,7 @@ protected static function parseCommand() \posix_kill($master_pid, $sig); exit; default : - if (isset($command)) { - static::safeEcho('Unknown command: ' . $command . "\n"); - } + static::safeEcho('Unknown command: ' . $command . "\n"); exit($usage); } } @@ -1047,7 +1044,7 @@ protected static function formatStatusData($statistics_file) $total_timers = 0; $maxLen1 = static::$_maxSocketNameLength; $maxLen2 = static::$_maxWorkerNameLength; - foreach($info as $key => $value) { + foreach($info as $value) { if (!$read_process_status) { $status_str .= $value . "\n"; if (\preg_match('/^pid.*?memory.*?listening/', $value)) { @@ -1354,7 +1351,7 @@ protected static function forkWorkersForWindows() if(\count(static::$_workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); - static::safeEcho("@@@ See http://doc.workerman.net/faq/multi-woker-for-windows.html @@@\r\n"); + static::safeEcho("@@@ See https://www.workerman.net/doc/workerman/faq/multi-woker-for-windows.html @@@\r\n"); } elseif(\count(static::$_workers) <= 0) { @@ -1373,7 +1370,7 @@ protected static function forkWorkersForWindows() } else { - static::$globalEvent = new \Workerman\Events\Select(); + static::$globalEvent = new Select(); Timer::init(static::$globalEvent); foreach($files as $start_file) { @@ -1462,9 +1459,6 @@ protected static function forkOneWorkerForLinux(self $worker) { // Get available worker id. $id = static::getId($worker->workerId, 0); - if ($id === false) { - return; - } $pid = \pcntl_fork(); // For master process. if ($pid > 0) { From c5ca64b999d0161e6865720dbf561eefb3676dd8 Mon Sep 17 00:00:00 2001 From: Rodrigo Lucena Date: Thu, 24 Mar 2022 13:05:39 -0300 Subject: [PATCH 0667/1216] Fixed: PHP Deprecated: strlen() in Http:Response Correction in passing parameters to \strlen. Passing null for the string type parameter is deprecated. --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index fc6a677fd..f5635af9a 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -410,7 +410,7 @@ public function __toString() } $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; - $body_len = \strlen($this->_body); + $body_len = \strlen($this->_body ?? ""); if (empty($this->_header)) { return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; } From 9c8f0ed0751800cba41794d3525f4db93810087f Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Mar 2022 10:00:44 +0800 Subject: [PATCH 0668/1216] Optimizations --- src/Protocols/Http/Response.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index f5635af9a..cde0bba0a 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -289,7 +289,7 @@ public function withProtocolVersion($version) */ public function withBody($body) { - $this->_body = $body; + $this->_body = (string)$body; return $this; } @@ -354,7 +354,7 @@ public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = ' protected function createHeadForFile($file_info) { $file = $file_info['file']; - $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; + $reason = $this->_reason ?: static::$_phrases[$this->_status]; $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; $headers = $this->_header; if (!isset($headers['Server'])) { @@ -409,8 +409,8 @@ public function __toString() return $this->createHeadForFile($this->file); } - $reason = $this->_reason ? $this->_reason : static::$_phrases[$this->_status]; - $body_len = \strlen($this->_body ?? ""); + $reason = $this->_reason ?: static::$_phrases[$this->_status]; + $body_len = \strlen($this->_body); if (empty($this->_header)) { return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; } From 682ce9d193ef729776f84b105ad461ecf1390280 Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Fri, 25 Mar 2022 16:20:33 +0800 Subject: [PATCH 0669/1216] Update composer.json and README.md --- README.md | 8 ++++---- composer.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f2fce987c..486d07120 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Workerman supports HTTP, Websocket, SSL and other custom protocols. Workerman supports event extension. ## Requires -PHP 5.3 or Higher +PHP 7.0 or Higher A POSIX compatible operating system (Linux, OSX, BSD) POSIX and PCNTL extensions required Event extension recommended for better performance @@ -173,7 +173,7 @@ class MyTextProtocol } // Return length of the package - return $pos+1; + return $pos + 1; } public static function decode($recv_buffer) @@ -279,11 +279,11 @@ Worker::runAll(); ## Documentation -中文主页:[http://www.workerman.net](https://www.workerman.net) +中文主页: [http://www.workerman.net](https://www.workerman.net) 中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/worekrman) -Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) +Documentation: [https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) # Benchmarks https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r diff --git a/composer.json b/composer.json index c1c60ada9..59ac279bf 100644 --- a/composer.json +++ b/composer.json @@ -5,22 +5,22 @@ "event-loop", "asynchronous" ], - "homepage": "http://www.workerman.net", + "homepage": "https://www.workerman.net", "license": "MIT", "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", "authors": [ { "name": "walkor", "email": "walkor@workerman.net", - "homepage": "http://www.workerman.net", + "homepage": "https://www.workerman.net", "role": "Developer" } ], "support": { "email": "walkor@workerman.net", "issues": "https://github.com/walkor/workerman/issues", - "forum": "http://wenda.workerman.net/", - "wiki": "http://doc.workerman.net/", + "forum": "https://www.workerman.net/questions", + "wiki": "https://www.workerman.net/doc/workerman/", "source": "https://github.com/walkor/workerman" }, "require": { From 511e5058d98bb0ed77c00d313ba47f7a69b31c20 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Mar 2022 16:31:35 +0800 Subject: [PATCH 0670/1216] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 486d07120..80260a89e 100644 --- a/README.md +++ b/README.md @@ -269,9 +269,7 @@ Worker::runAll(); ## Available commands ```php start.php start ``` ```php start.php start -d ``` -![workerman start](http://www.workerman.net/img/workerman-start.png) ```php start.php status ``` -![workerman satus](http://www.workerman.net/img/workerman-status.png?a=123) ```php start.php connections``` ```php start.php stop ``` ```php start.php restart ``` From f36bea51e2535beb273ed4f0883118ea4b5e3513 Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Mon, 28 Mar 2022 20:48:55 +0800 Subject: [PATCH 0671/1216] fixed interface return type --- src/Events/EventInterface.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 5cbeda0b1..9a5c8bba8 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -20,7 +20,7 @@ interface EventInterface * @param float $delay * @param $func * @param $args - * @return string + * @return int|bool */ public function delay(float $delay, $func, $args); @@ -29,14 +29,14 @@ public function delay(float $delay, $func, $args); * @param float $interval * @param $func * @param $args - * @return string + * @return int|bool */ public function repeat(float $interval, $func, $args); /** * Delete a timer. * @param $timer_id - * @return mixed + * @return bool */ public function deleteTimer($timer_id); @@ -105,7 +105,7 @@ public function stop(); /** * - * @return void + * @return int */ public function getTimerCount(); } From e87204f460e03d28c28498a52492844b78733198 Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Wed, 30 Mar 2022 20:53:47 +0800 Subject: [PATCH 0672/1216] Update Worker.php --- src/Worker.php | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index bf2d4d551..a8f5a3579 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -13,6 +13,7 @@ */ namespace Workerman; +use Workerman\Events\Event; use Workerman\Events\EventInterface; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; @@ -461,11 +462,10 @@ class Worker /** * Available event loops. * - * @var array + * @var array */ protected static $_availableEventLoops = [ - 'event' => '\Workerman\Events\Event', - 'libevent' => '\Workerman\Events\Libevent' + "event" => Event::class, ]; /** @@ -522,6 +522,13 @@ class Worker */ protected static $_outputDecorated = null; + /** + * Worker object's hash id(unique identifier). + * + * @var string + */ + protected $workerId = null; + /** * Run all worker instances. * @@ -1257,18 +1264,18 @@ protected static function saveMasterPid() * * @return string */ - protected static function getEventLoopName() + protected static function getEventLoopName(): string { if (static::$eventLoopClass) { return static::$eventLoopClass; } - if (!\class_exists('\Swoole\Event', false)) { + if (!class_exists(\Swoole\Event::class, false)) { unset(static::$_availableEventLoops['swoole']); } $loop_name = ''; - foreach (static::$_availableEventLoops as $name=>$class) { + foreach (static::$_availableEventLoops as $name => $class) { if (\extension_loaded($name)) { $loop_name = $name; break; @@ -1278,7 +1285,7 @@ protected static function getEventLoopName() if ($loop_name) { static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; } else { - static::$eventLoopClass = '\Workerman\Events\Select'; + static::$eventLoopClass = Select::class; } return static::$eventLoopClass; } @@ -2113,17 +2120,17 @@ private static function outputStream($stream = null) } /** - * Construct. + * Constructor. * * @param string $socket_name - * @param array $context_option + * @param array $context_option */ - public function __construct($socket_name = '', array $context_option = []) + public function __construct(string $socket_name = '', array $context_option = []) { // Save all worker instances. - $this->workerId = \spl_object_hash($this); + $this->workerId = \spl_object_hash($this); static::$_workers[$this->workerId] = $this; - static::$_pidMap[$this->workerId] = []; + static::$_pidMap[$this->workerId] = []; // Context for socket. if ($socket_name) { @@ -2136,11 +2143,10 @@ public function __construct($socket_name = '', array $context_option = []) // Turn reusePort on. /*if (\DIRECTORY_SEPARATOR === '/' // if linux - && \version_compare(\PHP_VERSION,'7.0.0', 'ge') // if php >= 7.0.0 + && \version_compare(\PHP_VERSION, '7.0.0', 'ge') // if php >= 7.0.0 && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && strpos($socket_name,'unix') !== 0) { // if not unix socket - + && strpos($socket_name, 'unix') !== 0) { // if not unix socket $this->reusePort = true; }*/ } From dbccc310c54fd4a37ee31a6cfbc2d5c9c981e1d3 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 31 Mar 2022 10:56:05 +0800 Subject: [PATCH 0673/1216] Check redis went away --- .../Http/Session/RedisSessionHandler.php | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 8ea3fba0c..333f96ce8 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -11,9 +11,11 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ - namespace Workerman\Protocols\Http\Session; +use Workerman\Timer; +use RedisException; + /** * Class RedisSessionHandler * @package Workerman\Protocols\Http\Session @@ -31,6 +33,11 @@ class RedisSessionHandler implements SessionHandlerInterface */ protected $_maxLifeTime; + /** + * @var array + */ + protected $_config; + /** * RedisSessionHandler constructor. * @param array $config = [ @@ -40,6 +47,7 @@ class RedisSessionHandler implements SessionHandlerInterface * 'auth' => '******', * 'database' => 2, * 'prefix' => 'redis_session_', + * 'ping' => 55, * ] */ public function __construct($config) @@ -53,6 +61,19 @@ public function __construct($config) $config['timeout'] = 2; } + $this->_config = $config; + + $this->connect(); + + Timer::add($config['ping'] ?? 55, function () { + $this->_redis->get('ping'); + }); + } + + public function connect() + { + $config = $this->_config; + $this->_redis = new \Redis(); if (false === $this->_redis->connect($config['host'], $config['port'], $config['timeout'])) { throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); @@ -82,7 +103,17 @@ public function open($save_path, $name) */ public function read($session_id) { - return $this->_redis->get($session_id); + try { + return $this->_redis->get($session_id); + } catch (RedisException $e) { + $msg = strtolower($e->getMessage()); + if ($msg === 'connection lost' || strpos($msg, 'went away')) { + $this->connect(); + return $this->_redis->get($session_id); + } + throw $e; + } + } /** @@ -125,4 +156,4 @@ public function gc($maxlifetime) { return true; } -} \ No newline at end of file +} From 4990e1eba6109266d082ea10eca7b71cc8871f35 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 31 Mar 2022 11:57:12 +0800 Subject: [PATCH 0674/1216] RedisClusterSessionHandler --- .../Session/RedisClusterSessionHandler.php | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/Protocols/Http/Session/RedisClusterSessionHandler.php diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php new file mode 100644 index 000000000..127fc5b6d --- /dev/null +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -0,0 +1,45 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace Workerman\Protocols\Http\Session; + +class RedisClusterSessionHandler extends RedisSessionHandler +{ + public function __construct($config) + { + $this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime'); + $timeout = $config['timeout'] ?? 2; + $read_timeout = $config['read_timeout'] ?? $timeout; + $persistent = $config['persistent'] ?? false; + $auth = $config['auth'] ?? ''; + $args = [null, $config['host'], $timeout, $read_timeout, $persistent]; + if ($auth) { + $args[] = $auth; + } + $this->_redis = new \RedisCluster(...$args); + if (empty($config['prefix'])) { + $config['prefix'] = 'redis_session_'; + } + $this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + } + + /** + * {@inheritdoc} + */ + public function read($session_id) + { + return $this->_redis->get($session_id); + } + +} From 72e7fe6b426803ec9954fd65cb6e28dcdee3e239 Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Fri, 1 Apr 2022 22:41:24 +0800 Subject: [PATCH 0675/1216] Update Worker.php --- src/Worker.php | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index a8f5a3579..7ce6bb172 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -260,7 +260,7 @@ class Worker /** * Log file. * - * @var mixed + * @var string */ public static $logFile = ''; @@ -569,14 +569,13 @@ protected static function checkSapiEnv() */ protected static function init() { - \set_error_handler(function($code, $msg, $file, $line){ + \set_error_handler(function ($code, $msg, $file, $line) { Worker::safeEcho("$msg in file $file on line $line\n"); }); // Start file. - $backtrace = \debug_backtrace(); - static::$_startFile = $backtrace[\count($backtrace) - 1]['file']; - + $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + static::$_startFile = end($backtrace)['file']; $unique_prefix = \str_replace('/', '_', static::$_startFile); @@ -589,10 +588,10 @@ protected static function init() if (empty(static::$logFile)) { static::$logFile = __DIR__ . '/../../workerman.log'; } - $log_file = (string)static::$logFile; - if (!\is_file($log_file)) { - \touch($log_file); - \chmod($log_file, 0622); + + if (!\is_file(static::$logFile)) { + \touch(static::$logFile); + \chmod(static::$logFile, 0622); } // State. @@ -726,14 +725,15 @@ public function getMainSocket(){ /** * Init idMap. - * return void + * + * @return void */ protected static function initId() { foreach (static::$_workers as $worker_id => $worker) { $new_id_map = []; $worker->count = max($worker->count, 1); - for($key = 0; $key < $worker->count; $key++) { + for ($key = 0; $key < $worker->count; $key++) { $new_id_map[$key] = static::$_idMap[$worker_id][$key] ?? 0; } static::$_idMap[$worker_id] = $new_id_map; @@ -1558,7 +1558,7 @@ public function setUserAndGroup() * @param string $title * @return void */ - protected static function setProcessTitle($title) + protected static function setProcessTitle(string $title) { \set_error_handler(function(){}); \cli_set_process_title($title); @@ -2057,17 +2057,17 @@ public static function log($msg) if (!static::$daemonize) { static::safeEcho($msg); } - \file_put_contents((string)static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' + \file_put_contents(static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' . (\DIRECTORY_SEPARATOR === '/' ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); } /** * Safe Echo. * @param string $msg - * @param bool $decorated + * @param bool $decorated * @return bool */ - public static function safeEcho($msg, $decorated = false) + public static function safeEcho(string $msg, bool $decorated = false): bool { $stream = static::outputStream(); if (!$stream) { @@ -2092,13 +2092,15 @@ public static function safeEcho($msg, $decorated = false) } /** + * set and get output stream. + * * @param resource|null $stream - * @return bool|resource + * @return false|resource */ private static function outputStream($stream = null) { if (!$stream) { - $stream = static::$_outputStream ? static::$_outputStream : \STDOUT; + $stream = static::$_outputStream ?: \STDOUT; } if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { return false; @@ -2107,14 +2109,14 @@ private static function outputStream($stream = null) if (!$stat) { return false; } - if (($stat['mode'] & 0170000) === 0100000) { - // file + + if (($stat['mode'] & 0170000) === 0100000) { // whether is regular file static::$_outputDecorated = false; } else { static::$_outputDecorated = - \DIRECTORY_SEPARATOR === '/' && + \DIRECTORY_SEPARATOR === '/' && // linux or unix \function_exists('posix_isatty') && - \posix_isatty($stream); + \posix_isatty($stream); // whether is interactive terminal } return static::$_outputStream = $stream; } From 0dea94a468c2859ce1a04cbebd518ec5958de044 Mon Sep 17 00:00:00 2001 From: mowangjuanzi Date: Fri, 1 Apr 2022 22:50:47 +0800 Subject: [PATCH 0676/1216] fixed link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80260a89e..f877cc0dc 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ Worker::runAll(); 中文主页: [http://www.workerman.net](https://www.workerman.net) -中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/worekrman) +中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/workerman/) Documentation: [https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) From 1de34846957fbfe9df24bc402480bbc53ed472fa Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Apr 2022 15:30:48 +0800 Subject: [PATCH 0677/1216] Update Request.php --- src/Protocols/Http/Request.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 0fc7edecc..d61d94892 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -288,24 +288,25 @@ public function session() } /** - * Get session id. + * Get/Set session id. * - * @return bool|mixed + * @param $session_id + * @return string */ public function sessionId($session_id = null) { - if ($session_id !== null) { - $this->sid = $session_id; + if ($session_id) { + unset($this->sid); } if (!isset($this->sid)) { $session_name = Http::sessionName(); - $sid = $this->cookie($session_name); + $sid = $session_id ? '' : $this->cookie($session_name); if ($sid === '' || $sid === null) { if ($this->connection === null) { Worker::safeEcho('Request->session() fail, header already send'); return false; } - $sid = static::createSessionId(); + $sid = $session_id ?: static::createSessionId(); $cookie_params = \session_get_cookie_params(); $this->setSidCookie($session_name, $sid, $cookie_params); } From 74a1a34d71cec5583a3ae2e78d7eee1893024d79 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 6 Apr 2022 21:25:02 +0800 Subject: [PATCH 0678/1216] Update Worker.php --- src/Worker.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 7ce6bb172..857b4a4e8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2143,14 +2143,28 @@ public function __construct(string $socket_name = '', array $context_option = [] $this->_context = \stream_context_create($context_option); } - // Turn reusePort on. - /*if (\DIRECTORY_SEPARATOR === '/' // if linux - && \version_compare(\PHP_VERSION, '7.0.0', 'ge') // if php >= 7.0.0 + // Try to turn reusePort on. + if (\DIRECTORY_SEPARATOR === '/' // if linux + && $socket_name && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && strpos($socket_name, 'unix') !== 0) { // if not unix socket - $this->reusePort = true; - }*/ + && strpos($socket_name,'unix') !== 0 // if not unix socket + && strpos($socket_name,'udp') !== 0) { // if not udp socket + + $address = \parse_url($socket_name); + if (isset($address['host']) && isset($address['port'])) { + try { + \set_error_handler(function(){}); + // If address not in use, turn reusePort on automatically. + $server = stream_socket_server("tcp://{$address['host']}:{$address['port']}"); + if ($server) { + $this->reusePort = true; + fclose($server); + } + \restore_error_handler(); + } catch (\Throwable $e) {} + } + } } From e7daf00a45eeab027b7bf69e970f3462bf1166a7 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 12 Apr 2022 11:26:47 +0800 Subject: [PATCH 0679/1216] stopTimeout --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 857b4a4e8..76ba48371 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -974,7 +974,7 @@ protected static function parseCommand() // Send stop signal to master process. $master_pid && \posix_kill($master_pid, $sig); // Timeout. - $timeout = 5; + $timeout = static::$stopTimeout + 3; $start_time = \time(); // Check master process is still alive? while (1) { From 959ec2cabaf7f6061b20d4e9c5ee011ab5a27139 Mon Sep 17 00:00:00 2001 From: tricky <56504552+captainstdin@users.noreply.github.com> Date: Thu, 14 Apr 2022 17:12:49 +0800 Subject: [PATCH 0680/1216] Update Worker.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 防止在serverless部署中,因为runtime需要迁移到/tmp下时(serverless全局仅读,仅/tmp可写), runtime/logs 不存在时候的报错 touch(): Unable to create file /app/runtime/logs/workerman.log because No such file or directory in file /app/vendor/workerman/workerman/Worker.php on line 599 --- src/Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index 76ba48371..63a5cafcb 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -590,6 +590,10 @@ protected static function init() } if (!\is_file(static::$logFile)) { + // if /runtime/logs default folder not exists + if(!is_dir(dirname(static::$logFile))){ + @mkdir(dirname(static::$logFile),0777,true); + } \touch(static::$logFile); \chmod(static::$logFile, 0622); } From 598b17f2b9a3be3bd77e94fb71dc50e81a12809c Mon Sep 17 00:00:00 2001 From: Marcus Date: Fri, 15 Apr 2022 15:59:04 +0300 Subject: [PATCH 0681/1216] fixes for getting class name when we try to extend the `Worker` class, we cannot extend all the mechanisms of the class because the bindings use the original `Worker` class --- src/Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 76ba48371..a34c095e1 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1116,7 +1116,7 @@ protected static function installSignal() } $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; foreach ($signals as $signal) { - \pcntl_signal($signal, [Worker::class, 'signalHandler'], false); + \pcntl_signal($signal, [static::class, 'signalHandler'], false); } // ignore \pcntl_signal(\SIGPIPE, \SIG_IGN, false); @@ -1135,7 +1135,7 @@ protected static function reinstallSignal() $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; foreach ($signals as $signal) { \pcntl_signal($signal, \SIG_IGN, false); - static::$globalEvent->onSignal($signal, '\Workerman\Worker::signalHandler'); + static::$globalEvent->onSignal($signal, staitc::class . '::signalHandler'); }; } @@ -1917,7 +1917,7 @@ protected static function writeStatisticsToStatusFile() // For child processes. \reset(static::$_workers); - /** @var \Workerman\Worker $worker */ + /** @var static $worker */ $worker = current(static::$_workers); $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " @@ -1972,7 +1972,7 @@ protected static function writeConnectionsStatisticsToStatusFile() $current_worker = current(static::$_workers); $default_worker_name = $current_worker->name; - /** @var \Workerman\Worker $worker */ + /** @var static $worker */ foreach(TcpConnection::$connections as $connection) { /** @var \Workerman\Connection\TcpConnection $connection */ $transport = $connection->transport; From d6771b00d6b1eb8fb4bac33a213c8e2c089fe7ae Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 20 Apr 2022 22:11:37 +0800 Subject: [PATCH 0682/1216] Update Request.php --- src/Protocols/Http/Request.php | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index d61d94892..b08e544d0 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -523,14 +523,14 @@ protected function parseUploadFiles($http_post_boundary) if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") { unset($boundary_data_array[0]); } - $key = -1; + $index = -1; $files = []; $post_str = ''; foreach ($boundary_data_array as $boundary_data_buffer) { list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); // Remove \r\n from the end of buffer. $boundary_value = \substr($boundary_value, 0, -2); - $key++; + $index++; foreach (\explode("\r\n", $boundary_header_buffer) as $item) { list($header_key, $header_value) = \explode(": ", $item); $header_key = \strtolower($header_key); @@ -552,11 +552,11 @@ protected function parseUploadFiles($http_post_boundary) $error = UPLOAD_ERR_CANT_WRITE; } } - if (!isset($files[$key])) { - $files[$key] = []; + if (!isset($files[$index])) { + $files[$index] = []; } // Parse upload files. - $files[$key] += [ + $files[$index] += [ 'key' => $match[1], 'name' => $match[2], 'tmp_name' => $tmp_file, @@ -569,22 +569,30 @@ protected function parseUploadFiles($http_post_boundary) else { // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { - $key = $match[1]; - $post_str .= \urlencode($key) . "=" . \urlencode($boundary_value) . '&'; + $k = $match[1]; + $post_str .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; } } break; case "content-type": // add file_type - if (!isset($files[$key])) { - $files[$key] = []; + if (!isset($files[$index])) { + $files[$index] = []; } - $files[$key]['type'] = \trim($header_value); + $files[$index]['type'] = \trim($header_value); break; } } } - foreach ($files as $file) { + $files_unique = []; + foreach ($files as $index => $file) { + $key = $file['key']; + if (\substr($key, -2) === '[]') { + $key = $index; + } + $files_unique[$key] = $file; + } + foreach ($files_unique as $file) { $key = $file['key']; unset($file['key']); $str = \urlencode($key) . "=1"; From b12cc0156fe7ea517799d1134b8a36ffa0b201f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 20 Apr 2022 22:15:26 +0800 Subject: [PATCH 0683/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 0bc9b6c0c..c7e5a4027 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2131,7 +2131,7 @@ private static function outputStream($stream = null) * @param string $socket_name * @param array $context_option */ - public function __construct(string $socket_name = '', array $context_option = []) + public function __construct(string $socket_name = null, array $context_option = []) { // Save all worker instances. $this->workerId = \spl_object_hash($this); From 72d0fcdda58226c6df8761edd74e902dc058b8f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 20 Apr 2022 22:36:14 +0800 Subject: [PATCH 0684/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index c7e5a4027..5b7a877ee 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1139,7 +1139,7 @@ protected static function reinstallSignal() $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; foreach ($signals as $signal) { \pcntl_signal($signal, \SIG_IGN, false); - static::$globalEvent->onSignal($signal, staitc::class . '::signalHandler'); + static::$globalEvent->onSignal($signal, [static::class, 'signalHandler']); }; } From 9fc8d54eabe03e60e3fd83ae860a9122a19fc746 Mon Sep 17 00:00:00 2001 From: 1923998238 <1923998238@qq.com> Date: Sat, 23 Apr 2022 21:13:51 +0800 Subject: [PATCH 0685/1216] Signed-off-by: 1923998238 <1923998238@qq.com> Support the use of proxy --- test.php | 43 +++ vendor/autoload.php | 7 + vendor/composer/ClassLoader.php | 479 ++++++++++++++++++++++++ vendor/composer/InstalledVersions.php | 283 ++++++++++++++ vendor/composer/LICENSE | 21 ++ vendor/composer/autoload_classmap.php | 10 + vendor/composer/autoload_namespaces.php | 9 + vendor/composer/autoload_psr4.php | 10 + vendor/composer/autoload_real.php | 57 +++ vendor/composer/autoload_static.php | 36 ++ vendor/composer/installed.json | 5 + vendor/composer/installed.php | 24 ++ vendor/composer/platform_check.php | 26 ++ 13 files changed, 1010 insertions(+) create mode 100644 test.php create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php diff --git a/test.php b/test.php new file mode 100644 index 000000000..b0f7b0bc6 --- /dev/null +++ b/test.php @@ -0,0 +1,43 @@ +onWorkerStart = function($worker){ + echo '开始链接' . PHP_EOL; + $url = 'ws://stream.binance.com:9443/ws'; + $con = new AsyncTcpConnection($url); + $con->transport = 'ssl'; + $con->proxySocks5 = '127.0.0.1:1080'; +// $con->proxyHttp = '127.0.0.1:25378'; + + $con->onConnect = function(AsyncTcpConnection $con) { + $ww = [ + 'id' => 1, + 'method' => 'SUBSCRIBE', + 'params' => [ + "btcusdt@aggTrade", + "btcusdt@depth" + ] + ]; + echo '链接成功'; + $con->send(json_encode($ww)); + echo 'ok'; + }; + + $con->onMessage = function(AsyncTcpConnection $con, $data) { + echo $data; + }; + + $con->onClose = function (AsyncTcpConnection $con) { + echo 'onClose' . PHP_EOL; + }; + + $con->onError = function (AsyncTcpConnection $con, $code, $msg) { + echo "error [ $code ] $msg\n"; + }; + + $con->connect(); +}; +\Workerman\Worker::runAll(); diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 000000000..c0daf915c --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 000000000..2fbf4680f --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,283 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => 'workerman/workerman', + ), + 'versions' => + array ( + 'workerman/workerman' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + ), +); +private static $canGetVendors; +private static $installedByVendor = array(); + + + + + + + +public static function getInstalledPackages() +{ +$packages = array(); +foreach (self::getInstalled() as $installed) { +$packages[] = array_keys($installed['versions']); +} + + +if (1 === \count($packages)) { +return $packages[0]; +} + +return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (isset($installed['versions'][$packageName])) { +return true; +} +} + +return false; +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +$ranges = array(); +if (isset($installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = $installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['version'])) { +return null; +} + +return $installed['versions'][$packageName]['version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getPrettyVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return $installed['versions'][$packageName]['pretty_version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getReference($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['reference'])) { +return null; +} + +return $installed['versions'][$packageName]['reference']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getRootPackage() +{ +$installed = self::getInstalled(); + +return $installed[0]['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +self::$installedByVendor = array(); +} + + + + +private static function getInstalled() +{ +if (null === self::$canGetVendors) { +self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); +} + +$installed = array(); + +if (self::$canGetVendors) { +foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { +if (isset(self::$installedByVendor[$vendorDir])) { +$installed[] = self::$installedByVendor[$vendorDir]; +} elseif (is_file($vendorDir.'/composer/installed.php')) { +$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; +} +} +} + +$installed[] = self::$installed; + +return $installed; +} +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..b26f1b13b --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..b7fc0125d --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 000000000..8aae44991 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,57 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 000000000..143f9daff --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'Workerman\\' => 10, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Workerman\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 000000000..87fda747e --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,5 @@ +{ + "packages": [], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 000000000..afc0c785c --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,24 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => 'workerman/workerman', + ), + 'versions' => + array ( + 'workerman/workerman' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 000000000..f79e574be --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} From 46644d794958cc37c7ad2f5debf4b1fd05c1a3ad Mon Sep 17 00:00:00 2001 From: 1923998238 <1923998238@qq.com> Date: Sat, 23 Apr 2022 21:22:21 +0800 Subject: [PATCH 0686/1216] update --- README.md | 105 ++++++ src/Connection/AsyncTcpConnection.php | 38 +- test.php | 43 --- vendor/autoload.php | 7 - vendor/composer/ClassLoader.php | 479 ------------------------ vendor/composer/InstalledVersions.php | 283 -------------- vendor/composer/LICENSE | 21 -- vendor/composer/autoload_classmap.php | 10 - vendor/composer/autoload_namespaces.php | 9 - vendor/composer/autoload_psr4.php | 10 - vendor/composer/autoload_real.php | 57 --- vendor/composer/autoload_static.php | 36 -- vendor/composer/installed.json | 5 - vendor/composer/installed.php | 24 -- vendor/composer/platform_check.php | 26 -- 15 files changed, 139 insertions(+), 1014 deletions(-) delete mode 100644 test.php delete mode 100644 vendor/autoload.php delete mode 100644 vendor/composer/ClassLoader.php delete mode 100644 vendor/composer/InstalledVersions.php delete mode 100644 vendor/composer/LICENSE delete mode 100644 vendor/composer/autoload_classmap.php delete mode 100644 vendor/composer/autoload_namespaces.php delete mode 100644 vendor/composer/autoload_psr4.php delete mode 100644 vendor/composer/autoload_real.php delete mode 100644 vendor/composer/autoload_static.php delete mode 100644 vendor/composer/installed.json delete mode 100644 vendor/composer/installed.php delete mode 100644 vendor/composer/platform_check.php diff --git a/README.md b/README.md index f877cc0dc..4d5f66488 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,111 @@ Worker::runAll(); +#### Use HTTP proxy + +```php +onWorkerStart = function($worker){ + echo '开始链接' . PHP_EOL; + $url = 'ws://stream.binance.com:9443/ws'; + $con = new AsyncTcpConnection($url); + $con->transport = 'ssl'; +// $con->proxySocks5 = '127.0.0.1:1080'; + $con->proxyHttp = '127.0.0.1:25378'; + + $con->onConnect = function(AsyncTcpConnection $con) { + $ww = [ + 'id' => 1, + 'method' => 'SUBSCRIBE', + 'params' => [ + "btcusdt@aggTrade", + "btcusdt@depth" + ] + ]; + echo '链接成功'; + $con->send(json_encode($ww)); + echo 'ok'; + }; + + $con->onMessage = function(AsyncTcpConnection $con, $data) { + echo $data; + }; + + $con->onClose = function (AsyncTcpConnection $con) { + echo 'onClose' . PHP_EOL; + }; + + $con->onError = function (AsyncTcpConnection $con, $code, $msg) { + echo "error [ $code ] $msg\n"; + }; + + $con->connect(); +}; +\Workerman\Worker::runAll(); +``` + + + +#### Use Socks5 proxy + +```php +onWorkerStart = function($worker){ + echo '开始链接' . PHP_EOL; + $url = 'ws://stream.binance.com:9443/ws'; + $con = new AsyncTcpConnection($url); + $con->transport = 'ssl'; + $con->proxySocks5 = '127.0.0.1:1080'; +// $con->proxyHttp = '127.0.0.1:25378'; + + $con->onConnect = function(AsyncTcpConnection $con) { + $ww = [ + 'id' => 1, + 'method' => 'SUBSCRIBE', + 'params' => [ + "btcusdt@aggTrade", + "btcusdt@depth" + ] + ]; + echo '链接成功'; + $con->send(json_encode($ww)); + echo 'ok'; + }; + + $con->onMessage = function(AsyncTcpConnection $con, $data) { + echo $data; + }; + + $con->onClose = function (AsyncTcpConnection $con) { + echo 'onClose' . PHP_EOL; + }; + + $con->onError = function (AsyncTcpConnection $con, $code, $msg) { + echo "error [ $code ] $msg\n"; + }; + + $con->connect(); +}; +\Workerman\Worker::runAll(); + +``` + + + +proxy supports TLS1.3, no Sniproxy channel + + + ## Available commands ```php start.php start ``` ```php start.php start -d ``` diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index d8f42e512..59f4a87f6 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -38,6 +38,20 @@ class AsyncTcpConnection extends TcpConnection */ public $transport = 'tcp'; + /** + * Socks5 proxy + * + * @var string + */ + public $proxySocks5 = ''; + + /** + * Http proxy + * + * @var string + */ + public $proxyHttp = ''; + /** * Status. * @@ -179,6 +193,7 @@ public function connect() $this->_status !== self::STATUS_CLOSED) { return; } + $this->_status = self::STATUS_CONNECTING; $this->_connectStartTime = \microtime(true); if ($this->transport !== 'unix') { @@ -187,7 +202,24 @@ public function connect() $this->_remoteAddress = $this->_remoteHost . ':' . $this->_remotePort; } // Open socket connection asynchronously. - if ($this->_contextOption) { + if ($this->proxySocks5){ + $this->_contextOption['ssl']['peer_name'] = $this->_remoteHost; + $context = \stream_context_create($this->_contextOption); + $this->_socket = \stream_socket_client("tcp://{$this->proxySocks5}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + fwrite($this->_socket,chr(5) . chr(1) . chr(0)); + fread($this->_socket, 512); + fwrite($this->_socket,chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->_remoteHost)) . $this->_remoteHost . pack("n", $this->_remotePort)); + fread($this->_socket, 512); + }else if($this->proxyHttp){ + $this->_contextOption['ssl']['peer_name'] = $this->_remoteHost; + $context = \stream_context_create($this->_contextOption); + $this->_socket = \stream_socket_client("tcp://{$this->proxyHttp}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + $str = "CONNECT {$this->_remoteHost}:{$this->_remotePort} HTTP/1.1\n"; + $str .= "Host: {$this->_remoteHost}:{$this->_remotePort}\n"; + $str .= "Proxy-Connection: keep-alive\n"; + fwrite($this->_socket,$str); + fread($this->_socket, 512); + } else if ($this->_contextOption) { $context = \stream_context_create($this->_contextOption); $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); @@ -299,7 +331,6 @@ public function checkConnection() if (\DIRECTORY_SEPARATOR === '\\') { Worker::$globalEvent->offExcept($this->_socket); } - // Remove write listener. Worker::$globalEvent->offWritable($this->_socket); @@ -321,7 +352,6 @@ public function checkConnection() \socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); \socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1); } - // SSL handshake. if ($this->transport === 'ssl') { $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket); @@ -334,7 +364,6 @@ public function checkConnection() Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); } } - // Register a listener waiting read event. Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); @@ -367,5 +396,6 @@ public function checkConnection() $this->onConnect = null; } } + } } diff --git a/test.php b/test.php deleted file mode 100644 index b0f7b0bc6..000000000 --- a/test.php +++ /dev/null @@ -1,43 +0,0 @@ -onWorkerStart = function($worker){ - echo '开始链接' . PHP_EOL; - $url = 'ws://stream.binance.com:9443/ws'; - $con = new AsyncTcpConnection($url); - $con->transport = 'ssl'; - $con->proxySocks5 = '127.0.0.1:1080'; -// $con->proxyHttp = '127.0.0.1:25378'; - - $con->onConnect = function(AsyncTcpConnection $con) { - $ww = [ - 'id' => 1, - 'method' => 'SUBSCRIBE', - 'params' => [ - "btcusdt@aggTrade", - "btcusdt@depth" - ] - ]; - echo '链接成功'; - $con->send(json_encode($ww)); - echo 'ok'; - }; - - $con->onMessage = function(AsyncTcpConnection $con, $data) { - echo $data; - }; - - $con->onClose = function (AsyncTcpConnection $con) { - echo 'onClose' . PHP_EOL; - }; - - $con->onError = function (AsyncTcpConnection $con, $code, $msg) { - echo "error [ $code ] $msg\n"; - }; - - $con->connect(); -}; -\Workerman\Worker::runAll(); diff --git a/vendor/autoload.php b/vendor/autoload.php deleted file mode 100644 index c0daf915c..000000000 --- a/vendor/autoload.php +++ /dev/null @@ -1,7 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see https://www.php-fig.org/psr/psr-0/ - * @see https://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - private $vendorDir; - - // PSR-4 - private $prefixLengthsPsr4 = array(); - private $prefixDirsPsr4 = array(); - private $fallbackDirsPsr4 = array(); - - // PSR-0 - private $prefixesPsr0 = array(); - private $fallbackDirsPsr0 = array(); - - private $useIncludePath = false; - private $classMap = array(); - private $classMapAuthoritative = false; - private $missingClasses = array(); - private $apcuPrefix; - - private static $registeredLoaders = array(); - - public function __construct($vendorDir = null) - { - $this->vendorDir = $vendorDir; - } - - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); - } - - return array(); - } - - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - - if (null === $this->vendorDir) { - return; - } - - if ($prepend) { - self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; - } else { - unset(self::$registeredLoaders[$this->vendorDir]); - self::$registeredLoaders[$this->vendorDir] = $this; - } - } - - /** - * Unregisters this instance as an autoloader. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - - if (null !== $this->vendorDir) { - unset(self::$registeredLoaders[$this->vendorDir]); - } - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - includeFile($file); - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. - * - * @return self[] - */ - public static function getRegisteredLoaders() - { - return self::$registeredLoaders; - } - - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - $subPath = $class; - while (false !== $lastPos = strrpos($subPath, '\\')) { - $subPath = substr($subPath, 0, $lastPos); - $search = $subPath . '\\'; - if (isset($this->prefixDirsPsr4[$search])) { - $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); - foreach ($this->prefixDirsPsr4[$search] as $dir) { - if (file_exists($file = $dir . $pathEnd)) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } -} - -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; -} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php deleted file mode 100644 index 2fbf4680f..000000000 --- a/vendor/composer/InstalledVersions.php +++ /dev/null @@ -1,283 +0,0 @@ - - array ( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', - 'aliases' => - array ( - ), - 'reference' => NULL, - 'name' => 'workerman/workerman', - ), - 'versions' => - array ( - 'workerman/workerman' => - array ( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', - 'aliases' => - array ( - ), - 'reference' => NULL, - ), - ), -); -private static $canGetVendors; -private static $installedByVendor = array(); - - - - - - - -public static function getInstalledPackages() -{ -$packages = array(); -foreach (self::getInstalled() as $installed) { -$packages[] = array_keys($installed['versions']); -} - - -if (1 === \count($packages)) { -return $packages[0]; -} - -return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); -} - - - - - - - - - -public static function isInstalled($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (isset($installed['versions'][$packageName])) { -return true; -} -} - -return false; -} - - - - - - - - - - - - - - -public static function satisfies(VersionParser $parser, $packageName, $constraint) -{ -$constraint = $parser->parseConstraints($constraint); -$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - -return $provided->matches($constraint); -} - - - - - - - - - - -public static function getVersionRanges($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -$ranges = array(); -if (isset($installed['versions'][$packageName]['pretty_version'])) { -$ranges[] = $installed['versions'][$packageName]['pretty_version']; -} -if (array_key_exists('aliases', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); -} -if (array_key_exists('replaced', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); -} -if (array_key_exists('provided', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); -} - -return implode(' || ', $ranges); -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['version'])) { -return null; -} - -return $installed['versions'][$packageName]['version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getPrettyVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['pretty_version'])) { -return null; -} - -return $installed['versions'][$packageName]['pretty_version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getReference($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['reference'])) { -return null; -} - -return $installed['versions'][$packageName]['reference']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getRootPackage() -{ -$installed = self::getInstalled(); - -return $installed[0]['root']; -} - - - - - - - -public static function getRawData() -{ -return self::$installed; -} - - - - - - - - - - - - - - - - - - - -public static function reload($data) -{ -self::$installed = $data; -self::$installedByVendor = array(); -} - - - - -private static function getInstalled() -{ -if (null === self::$canGetVendors) { -self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); -} - -$installed = array(); - -if (self::$canGetVendors) { -foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { -if (isset(self::$installedByVendor[$vendorDir])) { -$installed[] = self::$installedByVendor[$vendorDir]; -} elseif (is_file($vendorDir.'/composer/installed.php')) { -$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; -} -} -} - -$installed[] = self::$installed; - -return $installed; -} -} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE deleted file mode 100644 index f27399a04..000000000 --- a/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) Nils Adermann, Jordi Boggiano - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php deleted file mode 100644 index b26f1b13b..000000000 --- a/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,10 +0,0 @@ - $vendorDir . '/composer/InstalledVersions.php', -); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php deleted file mode 100644 index b7fc0125d..000000000 --- a/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,9 +0,0 @@ - array($baseDir . '/src'), -); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php deleted file mode 100644 index 8aae44991..000000000 --- a/vendor/composer/autoload_real.php +++ /dev/null @@ -1,57 +0,0 @@ -= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - } - - $loader->register(true); - - return $loader; - } -} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php deleted file mode 100644 index 143f9daff..000000000 --- a/vendor/composer/autoload_static.php +++ /dev/null @@ -1,36 +0,0 @@ - - array ( - 'Workerman\\' => 10, - ), - ); - - public static $prefixDirsPsr4 = array ( - 'Workerman\\' => - array ( - 0 => __DIR__ . '/../..' . '/src', - ), - ); - - public static $classMap = array ( - 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInitbff22311a7c6b9f532280c2eb17b9d46::$classMap; - - }, null, ClassLoader::class); - } -} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json deleted file mode 100644 index 87fda747e..000000000 --- a/vendor/composer/installed.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packages": [], - "dev": true, - "dev-package-names": [] -} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php deleted file mode 100644 index afc0c785c..000000000 --- a/vendor/composer/installed.php +++ /dev/null @@ -1,24 +0,0 @@ - - array ( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', - 'aliases' => - array ( - ), - 'reference' => NULL, - 'name' => 'workerman/workerman', - ), - 'versions' => - array ( - 'workerman/workerman' => - array ( - 'pretty_version' => '1.0.0+no-version-set', - 'version' => '1.0.0.0', - 'aliases' => - array ( - ), - 'reference' => NULL, - ), - ), -); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php deleted file mode 100644 index f79e574be..000000000 --- a/vendor/composer/platform_check.php +++ /dev/null @@ -1,26 +0,0 @@ -= 70000)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.'; -} - -if ($issues) { - if (!headers_sent()) { - header('HTTP/1.1 500 Internal Server Error'); - } - if (!ini_get('display_errors')) { - if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { - fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); - } elseif (!headers_sent()) { - echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; - } - } - trigger_error( - 'Composer detected issues in your platform: ' . implode(' ', $issues), - E_USER_ERROR - ); -} From 4e774fe735c6a9c358f7246b0dcc2d516779cd84 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 23 Apr 2022 22:50:38 +0800 Subject: [PATCH 0687/1216] Session cookie params --- src/Protocols/Http/Request.php | 4 +- src/Protocols/Http/Session.php | 90 +++++++++++++++---- .../Session/RedisClusterSessionHandler.php | 4 +- .../Http/Session/RedisSessionHandler.php | 9 +- 4 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b08e544d0..1a0d672a4 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -307,7 +307,7 @@ public function sessionId($session_id = null) return false; } $sid = $session_id ?: static::createSessionId(); - $cookie_params = \session_get_cookie_params(); + $cookie_params = Session::getCookieParams(); $this->setSidCookie($session_name, $sid, $cookie_params); } $this->sid = $sid; @@ -330,7 +330,7 @@ public function sessionRegenerateId($delete_old_session = false) $new_sid = static::createSessionId(); $session = new Session($new_sid); $session->put($session_data); - $cookie_params = \session_get_cookie_params(); + $cookie_params = Session::getCookieParams(); $session_name = Http::sessionName(); $this->setSidCookie($session_name, $new_sid, $cookie_params); } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 9453f60ea..0b540bb02 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols\Http; +use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; /** @@ -27,7 +28,7 @@ class Session * * @var string */ - protected static $_handlerClass = 'Workerman\Protocols\Http\Session\FileSessionHandler'; + protected static $_handlerClass = FileSessionHandler::class; /** * Parameters of __constructor for session handler class. @@ -37,25 +38,60 @@ class Session protected static $_handlerConfig = null; /** - * Session.gc_probability + * Session lifetime. * * @var int */ - protected static $_sessionGcProbability = 1; + public static $lifetime = 1440; /** - * Session.gc_divisor + * Cookie lifetime. * * @var int */ - protected static $_sessionGcDivisor = 1000; + public static $cookieLifetime = 1440; /** - * Session.gc_maxlifetime + * Session cookie path. * - * @var int + * @var string + */ + public static $cookiePath = '/'; + + /** + * Session cookie domain. + * + * @var string + */ + public static $domain = ''; + + /** + * HTTPS only cookies. + * + * @var bool + */ + public static $secure = false; + + /** + * HTTP access only. + * + * @var bool + */ + public static $httpOnly = true; + + /** + * Same-site cookies. + * + * @var string */ - protected static $_sessionGcMaxLifeTime = 1440; + public static $sameSite = ''; + + /** + * Gc probability. + * + * @var int[] + */ + public static $gcProbability = [1, 1000]; /** * Session handler instance. @@ -276,17 +312,20 @@ public function refresh() */ public static function init() { - if ($gc_probability = \ini_get('session.gc_probability')) { - self::$_sessionGcProbability = (int)$gc_probability; - } - - if ($gc_divisor = \ini_get('session.gc_divisor')) { - self::$_sessionGcDivisor = (int)$gc_divisor; + if ($gc_probability = (int)\ini_get('session.gc_probability') && $gc_divisor = (int)\ini_get('session.gc_divisor')) { + static::$gcProbability = [$gc_probability, $gc_divisor]; } if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { - self::$_sessionGcMaxLifeTime = (int)$gc_max_life_time; + self::$lifetime = (int)$gc_max_life_time; } + + $session_cookie_params = \session_get_cookie_params(); + static::$cookieLifetime = $session_cookie_params['lifetime']; + static::$cookiePath = $session_cookie_params['path']; + static::$domain = $session_cookie_params['domain']; + static::$secure = $session_cookie_params['secure']; + static::$httpOnly = $session_cookie_params['httponly']; } /** @@ -307,6 +346,23 @@ public static function handlerClass($class_name = null, $config = null) return static::$_handlerClass; } + /** + * Get cookie params. + * + * @return array + */ + public static function getCookieParams() + { + return [ + 'lifetime' => static::$cookieLifetime, + 'path' => static::$cookiePath, + 'domain' => static::$domain, + 'secure' => static::$secure, + 'httponly' => static::$httpOnly, + 'samesite' => static::$sameSite, + ]; + } + /** * Init handler. * @@ -328,10 +384,10 @@ protected static function initHandler() */ public function tryGcSessions() { - if (\rand(1, static::$_sessionGcDivisor) > static::$_sessionGcProbability) { + if (\rand(1, static::$gcProbability[1]) > static::$gcProbability[0]) { return; } - static::$_handler->gc(static::$_sessionGcMaxLifeTime); + static::$_handler->gc(static::$lifetime); } /** diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 127fc5b6d..eb926e0c4 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -14,11 +14,13 @@ namespace Workerman\Protocols\Http\Session; +use Workerman\Protocols\Http\Session; + class RedisClusterSessionHandler extends RedisSessionHandler { public function __construct($config) { - $this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime'); + $this->_maxLifetime = (int)Session::$lifetime; $timeout = $config['timeout'] ?? 2; $read_timeout = $config['read_timeout'] ?? $timeout; $persistent = $config['persistent'] ?? false; diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 333f96ce8..c02e7fa60 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -13,6 +13,7 @@ */ namespace Workerman\Protocols\Http\Session; +use Workerman\Protocols\Http\Session; use Workerman\Timer; use RedisException; @@ -31,7 +32,7 @@ class RedisSessionHandler implements SessionHandlerInterface /** * @var int */ - protected $_maxLifeTime; + protected $_maxLifetime; /** * @var array @@ -55,7 +56,7 @@ public function __construct($config) if (false === extension_loaded('redis')) { throw new \RuntimeException('Please install redis extension.'); } - $this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime'); + $this->_maxLifetime = (int)Session::$lifetime; if (!isset($config['timeout'])) { $config['timeout'] = 2; @@ -121,7 +122,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - return true === $this->_redis->setex($session_id, $this->_maxLifeTime, $session_data); + return true === $this->_redis->setex($session_id, $this->_maxLifetime, $session_data); } /** @@ -129,7 +130,7 @@ public function write($session_id, $session_data) */ public function updateTimestamp($id, $data = "") { - return true === $this->_redis->expire($id, $this->_maxLifeTime); + return true === $this->_redis->expire($id, $this->_maxLifetime); } /** From 33a549e724b4135878395b8de1ed42ac18de00e3 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Apr 2022 22:25:44 +0800 Subject: [PATCH 0688/1216] Fix onWritable --- src/Events/Event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index 1937eda2f..e30305d0b 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -175,7 +175,7 @@ public function onWritable($stream, $func) if (!$event || !$event->add()) { return false; } - $this->_readEvents[$fd_key] = $event; + $this->_writeEvents[$fd_key] = $event; return true; } From 515ed41ac4fc51fc9955df332144b1574fd4a6a9 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Apr 2022 22:53:36 +0800 Subject: [PATCH 0689/1216] Turn reusePort off by default --- src/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 5b7a877ee..710a68f18 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2148,7 +2148,7 @@ public function __construct(string $socket_name = null, array $context_option = } // Try to turn reusePort on. - if (\DIRECTORY_SEPARATOR === '/' // if linux + /*if (\DIRECTORY_SEPARATOR === '/' // if linux && $socket_name && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS @@ -2168,7 +2168,7 @@ public function __construct(string $socket_name = null, array $context_option = \restore_error_handler(); } catch (\Throwable $e) {} } - } + }*/ } From d7b554cf51aa4ac8fd21520a12c344665cb89366 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Apr 2022 23:17:56 +0800 Subject: [PATCH 0690/1216] Fix #753 --- src/Events/Select.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 90a46f191..6541ed25c 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -133,6 +133,7 @@ public function repeat(float $delay, $func, $args) $this->_scheduler->insert($timer_id, -$run_time); $this->_eventTimer[$timer_id] = [$func, (array)$args, $delay]; $select_timeout = ($run_time - \microtime(true)) * 1000000; + $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; if ($this->_selectTimeout > $select_timeout) { $this->_selectTimeout = $select_timeout; } @@ -263,7 +264,7 @@ protected function tick() $timer_id = $scheduler_data['data']; $next_run_time = -$scheduler_data['priority']; $time_now = \microtime(true); - $this->_selectTimeout = (int)($next_run_time - $time_now) * 1000000; + $this->_selectTimeout = (int)(($next_run_time - $time_now) * 1000000); if ($this->_selectTimeout <= 0) { $this->_scheduler->extract(); From 958fb0ffe542571bce6252a5b35b239e2e61eb00 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Apr 2022 11:08:55 +0800 Subject: [PATCH 0691/1216] gc --- src/Worker.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index 710a68f18..bd43c5f7c 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1920,6 +1920,10 @@ protected static function writeStatisticsToStatusFile() } // For child processes. + \gc_collect_cycles(); + if (\function_exists('gc_mem_caches')) { + \gc_mem_caches(); + } \reset(static::$_workers); /** @var static $worker */ $worker = current(static::$_workers); From 252f70c11f660807edbfb06f0da2a8ba1fa5d01c Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Apr 2022 11:50:36 +0800 Subject: [PATCH 0692/1216] memory_get_usage(false) --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index bd43c5f7c..e350352af 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1927,7 +1927,7 @@ protected static function writeStatisticsToStatusFile() \reset(static::$_workers); /** @var static $worker */ $worker = current(static::$_workers); - $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) + $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) . " "; From 547f463d9c054fa8f603ee575e2f20b446b9b0f9 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 28 Apr 2022 22:19:33 +0800 Subject: [PATCH 0693/1216] Session::$name --- src/Protocols/Http.php | 21 --------------------- src/Protocols/Http/Request.php | 4 ++-- src/Protocols/Http/Session.php | 7 +++++++ 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index db0207fa6..cc5d4bbea 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -31,13 +31,6 @@ class Http */ protected static $_requestClass = Request::class; - /** - * Session name. - * - * @var string - */ - protected static $_sessionName = 'PHPSID'; - /** * Upload tmp dir. * @@ -52,20 +45,6 @@ class Http */ protected static $_enableCache = true; - /** - * Get or set session name. - * - * @param string|null $name - * @return string - */ - public static function sessionName($name = null) - { - if ($name !== null && $name !== '') { - static::$_sessionName = (string)$name; - } - return static::$_sessionName; - } - /** * Get or set the request class name. * diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 1a0d672a4..41a625036 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -299,7 +299,7 @@ public function sessionId($session_id = null) unset($this->sid); } if (!isset($this->sid)) { - $session_name = Http::sessionName(); + $session_name = Session::$name; $sid = $session_id ? '' : $this->cookie($session_name); if ($sid === '' || $sid === null) { if ($this->connection === null) { @@ -331,7 +331,7 @@ public function sessionRegenerateId($delete_old_session = false) $session = new Session($new_sid); $session->put($session_data); $cookie_params = Session::getCookieParams(); - $session_name = Http::sessionName(); + $session_name = Session::$name; $this->setSidCookie($session_name, $new_sid, $cookie_params); } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 0b540bb02..c18695017 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -37,6 +37,13 @@ class Session */ protected static $_handlerConfig = null; + /** + * Session name. + * + * @var string + */ + public static $name = 'PHPSID'; + /** * Session lifetime. * From ab813dbc1ea38e1fe56b31fe3c3c31865f561b93 Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:52:59 +0800 Subject: [PATCH 0694/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 264 ++++++++++++++++--------------- 1 file changed, 137 insertions(+), 127 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index b190bfec3..c5094265e 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1,4 +1,5 @@ 'INITIAL', - self::STATUS_CONNECTING => 'CONNECTING', + public static $_statusToString = array( + self::STATUS_INITIAL => 'INITIAL', + self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', - self::STATUS_CLOSING => 'CLOSING', - self::STATUS_CLOSED => 'CLOSED', - ]; + self::STATUS_CLOSING => 'CLOSING', + self::STATUS_CLOSED => 'CLOSED', + ); /** * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remote_address */ public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; $this->id = $this->_id = self::$_idRecorder++; - if (self::$_idRecorder === \PHP_INT_MAX) { + if(self::$_idRecorder === \PHP_INT_MAX){ self::$_idRecorder = 0; } $this->_socket = $socket; @@ -288,10 +283,10 @@ public function __construct($socket, $remote_address = '') if (\function_exists('stream_set_read_buffer')) { \stream_set_read_buffer($this->_socket, 0); } - Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_remoteAddress = $remote_address; + Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; + $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; } @@ -314,7 +309,7 @@ public function getStatus($raw_output = true) * Sends data on the connection. * * @param mixed $send_buffer - * @param bool $raw + * @param bool $raw * @return bool|null */ public function send($send_buffer, $raw = false) @@ -325,7 +320,8 @@ public function send($send_buffer, $raw = false) // Try to call protocol::encode($send_buffer) before sending. if (false === $raw && $this->protocol !== null) { - $send_buffer = $this->protocol::encode($send_buffer, $this); + $parser = $this->protocol; + $send_buffer = $parser::encode($send_buffer, $this); if ($send_buffer === '') { return; } @@ -346,7 +342,7 @@ public function send($send_buffer, $raw = false) // Attempt to send data directly. if ($this->_sendBuffer === '') { if ($this->transport === 'ssl') { - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); $this->_sendBuffer = $send_buffer; $this->checkBufferWillFull(); return; @@ -354,7 +350,9 @@ public function send($send_buffer, $raw = false) $len = 0; try { $len = @\fwrite($this->_socket, $send_buffer); - } catch (\Throwable $e) { + } catch (\Exception $e) { + Worker::log($e); + } catch (\Error $e) { Worker::log($e); } // send successful. @@ -372,8 +370,10 @@ public function send($send_buffer, $raw = false) ++self::$statistics['send_fail']; if ($this->onError) { try { - ($this->onError)($this, static::SEND_FAIL, 'client closed'); - } catch (\Throwable $e) { + \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -382,7 +382,7 @@ public function send($send_buffer, $raw = false) } $this->_sendBuffer = $send_buffer; } - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); // Check if the send buffer will be full. $this->checkBufferWillFull(); return; @@ -407,7 +407,7 @@ public function getRemoteIp() { $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return (string)\substr($this->_remoteAddress, 0, $pos); + return (string) \substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -420,7 +420,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); + return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -531,7 +531,7 @@ public function isIpV6() */ public function pauseRecv() { - Worker::$globalEvent->offReadable($this->_socket); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); $this->_isPaused = true; } @@ -543,13 +543,14 @@ public function pauseRecv() public function resumeRecv() { if ($this->_isPaused === true) { - Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); + Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); $this->_isPaused = false; $this->baseRead($this->_socket, false); } } + /** * Base read handler. * @@ -559,13 +560,12 @@ public function resumeRecv() */ public function baseRead($socket, $check_eof = true) { - static $requests = []; // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { if ($this->doSslHandshake($socket)) { $this->_sslHandshakeCompleted = true; if ($this->_sendBuffer) { - Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']); + Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } } else { return; @@ -575,8 +575,7 @@ public function baseRead($socket, $check_eof = true) $buffer = ''; try { $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (\Throwable $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -586,32 +585,12 @@ public function baseRead($socket, $check_eof = true) } } else { $this->bytesRead += \strlen($buffer); - if ($this->_recvBuffer === '') { - if (static::$_enableCache && !isset($requests[512]) && isset($requests[$buffer])) { - ++self::$statistics['total_request']; - $request = $requests[$buffer]; - if ($request instanceof Request) { - $request = clone $request; - $requests[$buffer] = $request; - $request->connection = $this; - $this->__request = $request; - $request->properties = []; - } - try { - ($this->onMessage)($this, $request); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); - } - return; - } - $this->_recvBuffer = $buffer; - } else { - $this->_recvBuffer .= $buffer; - } + $this->_recvBuffer .= $buffer; } // If the application layer protocol has been set up. if ($this->protocol !== null) { + $parser = $this->protocol; while ($this->_recvBuffer !== '' && !$this->_isPaused) { // The current packet length is known. if ($this->_currentPackageLength) { @@ -622,9 +601,8 @@ public function baseRead($socket, $check_eof = true) } else { // Get current package length. try { - $this->_currentPackageLength = $this->protocol::input($this->_recvBuffer, $this); - } catch (\Throwable $e) { - } + $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); + } catch (\Exception $e) {} catch (\Error $e) {} // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -644,9 +622,9 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if ($one = \strlen($this->_recvBuffer) === $this->_currentPackageLength) { + if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; - $this->_recvBuffer = ''; + $this->_recvBuffer = ''; } else { // Get a full package from the buffer. $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); @@ -655,17 +633,15 @@ public function baseRead($socket, $check_eof = true) } // Reset the current packet length to 0. $this->_currentPackageLength = 0; + if (!$this->onMessage) { + continue; + } try { // Decode request buffer before Emitting onMessage callback. - $request = $this->protocol::decode($one_request_buffer, $this); - if (static::$_enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { - $requests[$one_request_buffer] = $request; - if (\count($requests) > 512) { - unset($requests[\key($requests)]); - } - } - ($this->onMessage)($this, $request); - } catch (\Throwable $e) { + \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -678,9 +654,15 @@ public function baseRead($socket, $check_eof = true) // Applications protocol is not set. ++self::$statistics['total_request']; + if (!$this->onMessage) { + $this->_recvBuffer = ''; + return; + } try { - ($this->onMessage)($this, $this->_recvBuffer); - } catch (\Throwable $e) { + \call_user_func($this->onMessage, $this, $this->_recvBuffer); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } // Clean receive buffer. @@ -694,8 +676,7 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - \set_error_handler(function () { - }); + \set_error_handler(function(){}); if ($this->transport === 'ssl') { $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); } else { @@ -704,13 +685,15 @@ public function baseWrite() \restore_error_handler(); if ($len === \strlen($this->_sendBuffer)) { $this->bytesWritten += $len; - Worker::$globalEvent->offWritable($this->_socket); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); $this->_sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { - ($this->onBufferDrain)($this); - } catch (\Throwable $e) { + \call_user_func($this->onBufferDrain, $this); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -734,32 +717,31 @@ public function baseWrite() * @param resource $socket * @return bool */ - public function doSslHandshake($socket) - { + public function doSslHandshake($socket){ if (\feof($socket)) { $this->destroy(); return false; } $async = $this instanceof AsyncTcpConnection; - + /** - * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. - * You can enable ssl3 by the codes below. - */ + * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. + * You can enable ssl3 by the codes below. + */ /*if($async){ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT; }else{ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER; }*/ - - if ($async) { + + if($async){ $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; - } else { + }else{ $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - + // Hidden error. - \set_error_handler(function ($errno, $errstr, $file) { + \set_error_handler(function($errno, $errstr, $file){ if (!Worker::$daemonize) { Worker::safeEcho("SSL handshake error: $errstr \n"); } @@ -776,8 +758,10 @@ public function doSslHandshake($socket) } if (isset($this->onSslHandshake)) { try { - ($this->onSslHandshake)($this); - } catch (\Throwable $e) { + \call_user_func($this->onSslHandshake, $this); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -792,14 +776,14 @@ public function doSslHandshake($socket) */ public function pipe(self $dest) { - $source = $this; - $this->onMessage = function ($source, $data) use ($dest) { + $source = $this; + $this->onMessage = function ($source, $data) use ($dest) { $dest->send($data); }; - $this->onClose = function ($source) use ($dest) { + $this->onClose = function ($source) use ($dest) { $dest->close(); }; - $dest->onBufferFull = function ($dest) use ($source) { + $dest->onBufferFull = function ($dest) use ($source) { $source->pauseRecv(); }; $dest->onBufferDrain = function ($dest) use ($source) { @@ -827,7 +811,7 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { - if ($this->_status === self::STATUS_CONNECTING) { + if($this->_status === self::STATUS_CONNECTING){ $this->destroy(); return; } @@ -841,7 +825,7 @@ public function close($data = null, $raw = false) } $this->_status = self::STATUS_CLOSING; - + if ($this->_sendBuffer === '') { $this->destroy(); } else { @@ -869,8 +853,10 @@ protected function checkBufferWillFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onBufferFull) { try { - ($this->onBufferFull)($this); - } catch (\Throwable $e) { + \call_user_func($this->onBufferFull, $this); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -888,8 +874,10 @@ protected function bufferIsFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { - ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); - } catch (\Throwable $e) { + \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -897,7 +885,7 @@ protected function bufferIsFull() } return false; } - + /** * Whether send buffer is Empty. * @@ -905,7 +893,7 @@ protected function bufferIsFull() */ public function bufferIsEmpty() { - return empty($this->_sendBuffer); + return empty($this->_sendBuffer); } /** @@ -920,29 +908,32 @@ public function destroy() return; } // Remove event listener. - Worker::$globalEvent->offReadable($this->_socket); - Worker::$globalEvent->offWritable($this->_socket); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); + Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // Close socket. try { @\fclose($this->_socket); - } catch (\Throwable $e) { - } + } catch (\Exception $e) {} catch (\Error $e) {} $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { - ($this->onClose)($this); - } catch (\Throwable $e) { + \call_user_func($this->onClose, $this); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } // Try to emit protocol::onClose if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { - ([$this->protocol, 'onClose'])($this); - } catch (\Throwable $e) { + \call_user_func(array($this->protocol, 'onClose'), $this); + } catch (\Exception $e) { + Worker::stopAll(250, $e); + } catch (\Error $e) { Worker::stopAll(250, $e); } } @@ -960,16 +951,6 @@ public function destroy() } } - /** - * Enable or disable Cache. - * - * @param mixed $value - */ - public static function enableCache($value) - { - static::$_enableCache = (bool)$value; - } - /** * Destruct. * @@ -988,9 +969,38 @@ public function __destruct() Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } - if (0 === self::$statistics['connection_count']) { + if(0 === self::$statistics['connection_count']) { Worker::stopAll(); } } } + + public function jsonSerialize() + { + return [ + 'transport' => $this->transport, + 'id' => $this->id, + 'status' => $this->getStatus(), + 'getRemoteIp' => $this->getRemoteIp(), + 'remotePort' => $this->getRemotePort(), + 'getRemoteAddress' => $this->getRemoteAddress(), + 'getLocalIp' => $this->getLocalIp(), + 'getLocalPort' => $this->getLocalPort(), + 'getLocalAddress' => $this->getLocalAddress(), + 'isIpV4' => $this->isIpV4(), + 'isIpV6' => $this->isIpV6(), + ]; + } + + public function serialize() + { + return serialize($this->jsonSerialize()); + } + + public function unserialize(string $data) + { + // 仅仅打印信息,不做操作,进程数据不可进行改变 + var_export(sprintf("unserialize %s \n", get_class($this))); + var_export(unserialize($data)); + } } From 87f89bfa2a77cabea0cc4ccecd394527165d900a Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:55:30 +0800 Subject: [PATCH 0695/1216] Create SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/Connection/Traits/SerializeTrait.php diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php new file mode 100644 index 000000000..fe25bc0d1 --- /dev/null +++ b/src/Connection/Traits/SerializeTrait.php @@ -0,0 +1,47 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +namespace Workerman\Connection\Traits; + +trait +{ + public function jsonSerialize() + { + return [ + 'transport' => $this->transport, + 'id' => $this->id, + 'status' => $this->getStatus(), + 'getRemoteIp' => $this->getRemoteIp(), + 'remotePort' => $this->getRemotePort(), + 'getRemoteAddress' => $this->getRemoteAddress(), + 'getLocalIp' => $this->getLocalIp(), + 'getLocalPort' => $this->getLocalPort(), + 'getLocalAddress' => $this->getLocalAddress(), + 'isIpV4' => $this->isIpV4(), + 'isIpV6' => $this->isIpV6(), + ]; + } + + public function serialize() + { + return serialize($this->jsonSerialize()); + } + + public function unserialize(string $data) + { + // 仅仅打印信息,不做操作,进程数据不可进行改变 + var_export(sprintf("unserialize %s \n", get_class($this))); + var_export(unserialize($data)); + } +} From 2294337a56bd5f2e161744617a325ba27aaee2fe Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:56:24 +0800 Subject: [PATCH 0696/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index c5094265e..140b2cb7c 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -25,6 +25,8 @@ */ class TcpConnection extends ConnectionInterface implements JsonSerializable, Serializable { + use Traits\SerializeTrait; + /** * Read buffer size. * @@ -974,33 +976,4 @@ public function __destruct() } } } - - public function jsonSerialize() - { - return [ - 'transport' => $this->transport, - 'id' => $this->id, - 'status' => $this->getStatus(), - 'getRemoteIp' => $this->getRemoteIp(), - 'remotePort' => $this->getRemotePort(), - 'getRemoteAddress' => $this->getRemoteAddress(), - 'getLocalIp' => $this->getLocalIp(), - 'getLocalPort' => $this->getLocalPort(), - 'getLocalAddress' => $this->getLocalAddress(), - 'isIpV4' => $this->isIpV4(), - 'isIpV6' => $this->isIpV6(), - ]; - } - - public function serialize() - { - return serialize($this->jsonSerialize()); - } - - public function unserialize(string $data) - { - // 仅仅打印信息,不做操作,进程数据不可进行改变 - var_export(sprintf("unserialize %s \n", get_class($this))); - var_export(unserialize($data)); - } } From df95e831ceed7c0859718c8e26c056f15469d57e Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:57:35 +0800 Subject: [PATCH 0697/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 140b2cb7c..8727e2044 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1,5 +1,4 @@ Date: Mon, 2 May 2022 20:58:46 +0800 Subject: [PATCH 0698/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 8727e2044..e92238767 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -21,6 +21,8 @@ */ class TcpConnection extends ConnectionInterface implements \JsonSerializable, \Serializable { + use Traits\SerializeTrait; + /** * Read buffer size. * From d20950b9a169e0bbb8b1c64147d21defa9ab397a Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:59:11 +0800 Subject: [PATCH 0699/1216] Update UdpConnection.php --- src/Connection/UdpConnection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 7be400f40..35f4e0692 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -17,8 +17,10 @@ /** * UdpConnection. */ -class UdpConnection extends ConnectionInterface +class UdpConnection extends ConnectionInterface implements \JsonSerializable, \Serializable { + use Traits\SerializeTrait; + /** * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. From 7857e695312b740dac9818459f9b019690eefbae Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 20:59:40 +0800 Subject: [PATCH 0700/1216] Update AsyncUdpConnection.php --- src/Connection/AsyncUdpConnection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 1da40a41f..c4d152c75 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -21,8 +21,10 @@ /** * AsyncUdpConnection. */ -class AsyncUdpConnection extends UdpConnection +class AsyncUdpConnection extends UdpConnection implements \JsonSerializable, \Serializable { + use Traits\SerializeTrait; + /** * Emitted when socket connection is successfully established. * From ef47a806e201775df06d57506eceee704b3f879f Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 21:00:16 +0800 Subject: [PATCH 0701/1216] Update AsyncUdpConnection.php --- src/Connection/AsyncUdpConnection.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index c4d152c75..1da40a41f 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -21,10 +21,8 @@ /** * AsyncUdpConnection. */ -class AsyncUdpConnection extends UdpConnection implements \JsonSerializable, \Serializable +class AsyncUdpConnection extends UdpConnection { - use Traits\SerializeTrait; - /** * Emitted when socket connection is successfully established. * From 615980fed803164e8b8285228c00ee29423e350c Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 21:01:54 +0800 Subject: [PATCH 0702/1216] Update SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php index fe25bc0d1..3d69bcec5 100644 --- a/src/Connection/Traits/SerializeTrait.php +++ b/src/Connection/Traits/SerializeTrait.php @@ -14,7 +14,7 @@ */ namespace Workerman\Connection\Traits; -trait +trait SerializeTrait { public function jsonSerialize() { From bcb302abd33455b1345474ad8ab1d6a964bd3f5e Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 21:05:06 +0800 Subject: [PATCH 0703/1216] Update SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php index 3d69bcec5..4e259d377 100644 --- a/src/Connection/Traits/SerializeTrait.php +++ b/src/Connection/Traits/SerializeTrait.php @@ -18,10 +18,16 @@ trait SerializeTrait { public function jsonSerialize() { - return [ + $data = []; + if ($this->transport === 'tcp') { + $data = [ + 'id' => $this->id, + 'status' => $this->getStatus(), + ]; + } + + return $data + [ 'transport' => $this->transport, - 'id' => $this->id, - 'status' => $this->getStatus(), 'getRemoteIp' => $this->getRemoteIp(), 'remotePort' => $this->getRemotePort(), 'getRemoteAddress' => $this->getRemoteAddress(), From 2df35c9803d45b0e82033dda389a758bcabd5ec5 Mon Sep 17 00:00:00 2001 From: mouyong Date: Mon, 2 May 2022 21:12:11 +0800 Subject: [PATCH 0704/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 229 +++++++++++++++++-------------- 1 file changed, 126 insertions(+), 103 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index e92238767..fc1baf53d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -11,9 +11,11 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Connection; use Workerman\Events\EventInterface; +use Workerman\Protocols\Http\Request; use Workerman\Worker; /** @@ -28,7 +30,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable, \S * * @var int */ - const READ_BUFFER_SIZE = 65535; + const READ_BUFFER_SIZE = 87380; /** * Status initial. @@ -171,7 +173,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable, \S * @var int */ public $maxPackageSize = 1048576; - + /** * Default maximum acceptable packet size. * @@ -186,6 +188,13 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable, \S */ protected static $_idRecorder = 1; + /** + * Cache. + * + * @var bool. + */ + protected static $_enableCache = true; + /** * Socket * @@ -247,32 +256,32 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable, \S * * @var array */ - public static $connections = array(); + public static $connections = []; /** * Status to string. * * @var array */ - public static $_statusToString = array( - self::STATUS_INITIAL => 'INITIAL', - self::STATUS_CONNECTING => 'CONNECTING', + public static $_statusToString = [ + self::STATUS_INITIAL => 'INITIAL', + self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', - self::STATUS_CLOSING => 'CLOSING', - self::STATUS_CLOSED => 'CLOSED', - ); + self::STATUS_CLOSING => 'CLOSING', + self::STATUS_CLOSED => 'CLOSED', + ]; /** * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remote_address */ public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; $this->id = $this->_id = self::$_idRecorder++; - if(self::$_idRecorder === \PHP_INT_MAX){ + if (self::$_idRecorder === \PHP_INT_MAX) { self::$_idRecorder = 0; } $this->_socket = $socket; @@ -281,10 +290,10 @@ public function __construct($socket, $remote_address = '') if (\function_exists('stream_set_read_buffer')) { \stream_set_read_buffer($this->_socket, 0); } - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); - $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; - $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_remoteAddress = $remote_address; + Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); + $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; + $this->maxPackageSize = self::$defaultMaxPackageSize; + $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; } @@ -307,7 +316,7 @@ public function getStatus($raw_output = true) * Sends data on the connection. * * @param mixed $send_buffer - * @param bool $raw + * @param bool $raw * @return bool|null */ public function send($send_buffer, $raw = false) @@ -318,8 +327,7 @@ public function send($send_buffer, $raw = false) // Try to call protocol::encode($send_buffer) before sending. if (false === $raw && $this->protocol !== null) { - $parser = $this->protocol; - $send_buffer = $parser::encode($send_buffer, $this); + $send_buffer = $this->protocol::encode($send_buffer, $this); if ($send_buffer === '') { return; } @@ -340,7 +348,7 @@ public function send($send_buffer, $raw = false) // Attempt to send data directly. if ($this->_sendBuffer === '') { if ($this->transport === 'ssl') { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); $this->_sendBuffer = $send_buffer; $this->checkBufferWillFull(); return; @@ -348,9 +356,7 @@ public function send($send_buffer, $raw = false) $len = 0; try { $len = @\fwrite($this->_socket, $send_buffer); - } catch (\Exception $e) { - Worker::log($e); - } catch (\Error $e) { + } catch (\Throwable $e) { Worker::log($e); } // send successful. @@ -368,10 +374,8 @@ public function send($send_buffer, $raw = false) ++self::$statistics['send_fail']; if ($this->onError) { try { - \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'client closed'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onError)($this, static::SEND_FAIL, 'client closed'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -380,7 +384,7 @@ public function send($send_buffer, $raw = false) } $this->_sendBuffer = $send_buffer; } - Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); // Check if the send buffer will be full. $this->checkBufferWillFull(); return; @@ -405,7 +409,7 @@ public function getRemoteIp() { $pos = \strrpos($this->_remoteAddress, ':'); if ($pos) { - return (string) \substr($this->_remoteAddress, 0, $pos); + return (string)\substr($this->_remoteAddress, 0, $pos); } return ''; } @@ -418,7 +422,7 @@ public function getRemoteIp() public function getRemotePort() { if ($this->_remoteAddress) { - return (int) \substr(\strrchr($this->_remoteAddress, ':'), 1); + return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); } return 0; } @@ -529,7 +533,7 @@ public function isIpV6() */ public function pauseRecv() { - Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); + Worker::$globalEvent->offReadable($this->_socket); $this->_isPaused = true; } @@ -541,14 +545,13 @@ public function pauseRecv() public function resumeRecv() { if ($this->_isPaused === true) { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); + Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); $this->_isPaused = false; $this->baseRead($this->_socket, false); } } - /** * Base read handler. * @@ -558,12 +561,13 @@ public function resumeRecv() */ public function baseRead($socket, $check_eof = true) { + static $requests = []; // SSL handshake. if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { if ($this->doSslHandshake($socket)) { $this->_sslHandshakeCompleted = true; if ($this->_sendBuffer) { - Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); + Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']); } } else { return; @@ -573,7 +577,8 @@ public function baseRead($socket, $check_eof = true) $buffer = ''; try { $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (\Exception $e) {} catch (\Error $e) {} + } catch (\Throwable $e) { + } // Check connection closed. if ($buffer === '' || $buffer === false) { @@ -583,12 +588,32 @@ public function baseRead($socket, $check_eof = true) } } else { $this->bytesRead += \strlen($buffer); - $this->_recvBuffer .= $buffer; + if ($this->_recvBuffer === '') { + if (static::$_enableCache && !isset($requests[512]) && isset($requests[$buffer])) { + ++self::$statistics['total_request']; + $request = $requests[$buffer]; + if ($request instanceof Request) { + $request = clone $request; + $requests[$buffer] = $request; + $request->connection = $this; + $this->__request = $request; + $request->properties = []; + } + try { + ($this->onMessage)($this, $request); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + return; + } + $this->_recvBuffer = $buffer; + } else { + $this->_recvBuffer .= $buffer; + } } // If the application layer protocol has been set up. if ($this->protocol !== null) { - $parser = $this->protocol; while ($this->_recvBuffer !== '' && !$this->_isPaused) { // The current packet length is known. if ($this->_currentPackageLength) { @@ -599,8 +624,9 @@ public function baseRead($socket, $check_eof = true) } else { // Get current package length. try { - $this->_currentPackageLength = $parser::input($this->_recvBuffer, $this); - } catch (\Exception $e) {} catch (\Error $e) {} + $this->_currentPackageLength = $this->protocol::input($this->_recvBuffer, $this); + } catch (\Throwable $e) { + } // The packet length is unknown. if ($this->_currentPackageLength === 0) { break; @@ -620,9 +646,9 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if (\strlen($this->_recvBuffer) === $this->_currentPackageLength) { + if ($one = \strlen($this->_recvBuffer) === $this->_currentPackageLength) { $one_request_buffer = $this->_recvBuffer; - $this->_recvBuffer = ''; + $this->_recvBuffer = ''; } else { // Get a full package from the buffer. $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); @@ -631,15 +657,17 @@ public function baseRead($socket, $check_eof = true) } // Reset the current packet length to 0. $this->_currentPackageLength = 0; - if (!$this->onMessage) { - continue; - } try { // Decode request buffer before Emitting onMessage callback. - \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + $request = $this->protocol::decode($one_request_buffer, $this); + if (static::$_enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { + $requests[$one_request_buffer] = $request; + if (\count($requests) > 512) { + unset($requests[\key($requests)]); + } + } + ($this->onMessage)($this, $request); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -652,15 +680,9 @@ public function baseRead($socket, $check_eof = true) // Applications protocol is not set. ++self::$statistics['total_request']; - if (!$this->onMessage) { - $this->_recvBuffer = ''; - return; - } try { - \call_user_func($this->onMessage, $this, $this->_recvBuffer); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onMessage)($this, $this->_recvBuffer); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } // Clean receive buffer. @@ -674,7 +696,8 @@ public function baseRead($socket, $check_eof = true) */ public function baseWrite() { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); if ($this->transport === 'ssl') { $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); } else { @@ -683,15 +706,13 @@ public function baseWrite() \restore_error_handler(); if ($len === \strlen($this->_sendBuffer)) { $this->bytesWritten += $len; - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + Worker::$globalEvent->offWritable($this->_socket); $this->_sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { - \call_user_func($this->onBufferDrain, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onBufferDrain)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -715,31 +736,32 @@ public function baseWrite() * @param resource $socket * @return bool */ - public function doSslHandshake($socket){ + public function doSslHandshake($socket) + { if (\feof($socket)) { $this->destroy(); return false; } $async = $this instanceof AsyncTcpConnection; - + /** - * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. - * You can enable ssl3 by the codes below. - */ + * We disabled ssl3 because https://blog.qualys.com/ssllabs/2014/10/15/ssl-3-is-dead-killed-by-the-poodle-attack. + * You can enable ssl3 by the codes below. + */ /*if($async){ $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT | STREAM_CRYPTO_METHOD_SSLv3_CLIENT; }else{ $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER | STREAM_CRYPTO_METHOD_SSLv3_SERVER; }*/ - - if($async){ + + if ($async) { $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; - }else{ + } else { $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; } - + // Hidden error. - \set_error_handler(function($errno, $errstr, $file){ + \set_error_handler(function ($errno, $errstr, $file) { if (!Worker::$daemonize) { Worker::safeEcho("SSL handshake error: $errstr \n"); } @@ -756,10 +778,8 @@ public function doSslHandshake($socket){ } if (isset($this->onSslHandshake)) { try { - \call_user_func($this->onSslHandshake, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onSslHandshake)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -774,14 +794,14 @@ public function doSslHandshake($socket){ */ public function pipe(self $dest) { - $source = $this; - $this->onMessage = function ($source, $data) use ($dest) { + $source = $this; + $this->onMessage = function ($source, $data) use ($dest) { $dest->send($data); }; - $this->onClose = function ($source) use ($dest) { + $this->onClose = function ($source) use ($dest) { $dest->close(); }; - $dest->onBufferFull = function ($dest) use ($source) { + $dest->onBufferFull = function ($dest) use ($source) { $source->pauseRecv(); }; $dest->onBufferDrain = function ($dest) use ($source) { @@ -809,7 +829,7 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { - if($this->_status === self::STATUS_CONNECTING){ + if ($this->_status === self::STATUS_CONNECTING) { $this->destroy(); return; } @@ -823,7 +843,7 @@ public function close($data = null, $raw = false) } $this->_status = self::STATUS_CLOSING; - + if ($this->_sendBuffer === '') { $this->destroy(); } else { @@ -851,10 +871,8 @@ protected function checkBufferWillFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onBufferFull) { try { - \call_user_func($this->onBufferFull, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onBufferFull)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -872,10 +890,8 @@ protected function bufferIsFull() if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { if ($this->onError) { try { - \call_user_func($this->onError, $this, \WORKERMAN_SEND_FAIL, 'send buffer full and drop package'); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -883,7 +899,7 @@ protected function bufferIsFull() } return false; } - + /** * Whether send buffer is Empty. * @@ -891,7 +907,7 @@ protected function bufferIsFull() */ public function bufferIsEmpty() { - return empty($this->_sendBuffer); + return empty($this->_sendBuffer); } /** @@ -906,32 +922,29 @@ public function destroy() return; } // Remove event listener. - Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); - Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); + Worker::$globalEvent->offReadable($this->_socket); + Worker::$globalEvent->offWritable($this->_socket); // Close socket. try { @\fclose($this->_socket); - } catch (\Exception $e) {} catch (\Error $e) {} + } catch (\Throwable $e) { + } $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { - \call_user_func($this->onClose, $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ($this->onClose)($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } // Try to emit protocol::onClose if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { - \call_user_func(array($this->protocol, 'onClose'), $this); - } catch (\Exception $e) { - Worker::stopAll(250, $e); - } catch (\Error $e) { + ([$this->protocol, 'onClose'])($this); + } catch (\Throwable $e) { Worker::stopAll(250, $e); } } @@ -949,6 +962,16 @@ public function destroy() } } + /** + * Enable or disable Cache. + * + * @param mixed $value + */ + public static function enableCache($value) + { + static::$_enableCache = (bool)$value; + } + /** * Destruct. * @@ -967,7 +990,7 @@ public function __destruct() Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } - if(0 === self::$statistics['connection_count']) { + if (0 === self::$statistics['connection_count']) { Worker::stopAll(); } } From 94a433f37240b21dc79cbfdf99a9dce40ba91377 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 3 May 2022 17:25:18 +0800 Subject: [PATCH 0705/1216] reload resetStd --- src/Worker.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index e350352af..88fa5b635 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1214,9 +1214,11 @@ protected static function daemonize() /** * Redirect standard input and output. * + * @param bool $throw_exception + * @return void * @throws Exception */ - public static function resetStd() + public static function resetStd(bool $throw_exception = true) { if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; @@ -1242,8 +1244,9 @@ public static function resetStd() \restore_error_handler(); return; } - - throw new Exception('Can not open stdoutFile ' . static::$stdoutFile); + if ($throw_exception) { + throw new Exception('Can not open stdoutFile ' . static::$stdoutFile); + } } /** @@ -1692,6 +1695,8 @@ protected static function reload() if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) { static::log("Workerman[" . \basename(static::$_startFile) . "] reloading"); static::$_status = static::STATUS_RELOADING; + + static::resetStd(false); // Try to emit onMasterReload callback. if (static::$onMasterReload) { try { @@ -1758,6 +1763,8 @@ protected static function reload() if ($worker->reloadable) { static::stopAll(); + } else { + static::resetStd(false); } } } From 9d6c22890b844dc500af9e3e6f05e469cba3b2a4 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 4 May 2022 22:36:13 +0800 Subject: [PATCH 0706/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index b190bfec3..ea2b836bf 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -587,7 +587,7 @@ public function baseRead($socket, $check_eof = true) } else { $this->bytesRead += \strlen($buffer); if ($this->_recvBuffer === '') { - if (static::$_enableCache && !isset($requests[512]) && isset($requests[$buffer])) { + if (static::$_enableCache && !isset($buffer[512]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; $request = $requests[$buffer]; if ($request instanceof Request) { From ccfaa947f1fd8a5550db70ea18b521a6e544d5a4 Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 12:18:58 +0800 Subject: [PATCH 0707/1216] Update SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php index 4e259d377..e7af6931a 100644 --- a/src/Connection/Traits/SerializeTrait.php +++ b/src/Connection/Traits/SerializeTrait.php @@ -46,7 +46,7 @@ public function serialize() public function unserialize(string $data) { - // 仅仅打印信息,不做操作,进程数据不可进行改变 + // Only print information, do nothing, proccess data should not be changed. var_export(sprintf("unserialize %s \n", get_class($this))); var_export(unserialize($data)); } From af9c60df785acc34698be171cb9810a3ffd9456d Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 19:33:33 +0800 Subject: [PATCH 0708/1216] Update SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php index e7af6931a..369bf1e44 100644 --- a/src/Connection/Traits/SerializeTrait.php +++ b/src/Connection/Traits/SerializeTrait.php @@ -38,16 +38,4 @@ public function jsonSerialize() 'isIpV6' => $this->isIpV6(), ]; } - - public function serialize() - { - return serialize($this->jsonSerialize()); - } - - public function unserialize(string $data) - { - // Only print information, do nothing, proccess data should not be changed. - var_export(sprintf("unserialize %s \n", get_class($this))); - var_export(unserialize($data)); - } } From 169f6f96d5b0c1afb22bc85c9c701ac6521876b1 Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 19:34:43 +0800 Subject: [PATCH 0709/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index fc1baf53d..ff17c40e9 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -21,10 +21,8 @@ /** * TcpConnection. */ -class TcpConnection extends ConnectionInterface implements \JsonSerializable, \Serializable +class TcpConnection extends ConnectionInterface implements \JsonSerializable { - use Traits\SerializeTrait; - /** * Read buffer size. * @@ -971,6 +969,23 @@ public static function enableCache($value) { static::$_enableCache = (bool)$value; } + + public function jsonSerialize() + { + return [ + 'id' => $this->id, + 'status' => $this->getStatus(), + 'transport' => $this->transport, + 'getRemoteIp' => $this->getRemoteIp(), + 'remotePort' => $this->getRemotePort(), + 'getRemoteAddress' => $this->getRemoteAddress(), + 'getLocalIp' => $this->getLocalIp(), + 'getLocalPort' => $this->getLocalPort(), + 'getLocalAddress' => $this->getLocalAddress(), + 'isIpV4' => $this->isIpV4(), + 'isIpV6' => $this->isIpV6(), + ]; + } /** * Destruct. From 3e72d1774a325d659a6cd8e24327a15a4a3c7f07 Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 19:36:39 +0800 Subject: [PATCH 0710/1216] Update UdpConnection.php --- src/Connection/UdpConnection.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 35f4e0692..813b48cd6 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -17,10 +17,8 @@ /** * UdpConnection. */ -class UdpConnection extends ConnectionInterface implements \JsonSerializable, \Serializable +class UdpConnection extends ConnectionInterface implements \JsonSerializable { - use Traits\SerializeTrait; - /** * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. @@ -208,4 +206,24 @@ public function getSocket() { return $this->_socket; } + + /** + * Get the json_encode informattion. + * + * @return string + */ + public function jsonSerialize() + { + return [ + 'transport' => $this->transport, + 'getRemoteIp' => $this->getRemoteIp(), + 'remotePort' => $this->getRemotePort(), + 'getRemoteAddress' => $this->getRemoteAddress(), + 'getLocalIp' => $this->getLocalIp(), + 'getLocalPort' => $this->getLocalPort(), + 'getLocalAddress' => $this->getLocalAddress(), + 'isIpV4' => $this->isIpV4(), + 'isIpV6' => $this->isIpV6(), + ]; + } } From acb688e1e0003f10bc663e33058e507ae48c2e7d Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 19:37:04 +0800 Subject: [PATCH 0711/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index ff17c40e9..9b3c845ce 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -970,6 +970,11 @@ public static function enableCache($value) static::$_enableCache = (bool)$value; } + /** + * Get the json_encode informattion. + * + * @return string + */ public function jsonSerialize() { return [ From c14f192b0ebdf5fe32c818e92bc42d71537b204a Mon Sep 17 00:00:00 2001 From: mouyong Date: Sun, 8 May 2022 19:37:16 +0800 Subject: [PATCH 0712/1216] Delete SerializeTrait.php --- src/Connection/Traits/SerializeTrait.php | 41 ------------------------ 1 file changed, 41 deletions(-) delete mode 100644 src/Connection/Traits/SerializeTrait.php diff --git a/src/Connection/Traits/SerializeTrait.php b/src/Connection/Traits/SerializeTrait.php deleted file mode 100644 index 369bf1e44..000000000 --- a/src/Connection/Traits/SerializeTrait.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright walkor - * @link http://www.workerman.net/ - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -namespace Workerman\Connection\Traits; - -trait SerializeTrait -{ - public function jsonSerialize() - { - $data = []; - if ($this->transport === 'tcp') { - $data = [ - 'id' => $this->id, - 'status' => $this->getStatus(), - ]; - } - - return $data + [ - 'transport' => $this->transport, - 'getRemoteIp' => $this->getRemoteIp(), - 'remotePort' => $this->getRemotePort(), - 'getRemoteAddress' => $this->getRemoteAddress(), - 'getLocalIp' => $this->getLocalIp(), - 'getLocalPort' => $this->getLocalPort(), - 'getLocalAddress' => $this->getLocalAddress(), - 'isIpV4' => $this->isIpV4(), - 'isIpV6' => $this->isIpV6(), - ]; - } -} From f3dc0753299cdd8adc0d00a422339483e05f29d0 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 12 May 2022 22:36:00 +0800 Subject: [PATCH 0713/1216] fix Timer::delay --- src/Events/Event.php | 17 ++++++++++------- src/Timer.php | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index e30305d0b..9a40ecfbc 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -56,7 +56,7 @@ class Event implements EventInterface * Timer id. * @var int */ - protected $_timerId = 1; + protected $_timerId = 0; /** * Event class name. @@ -90,8 +90,10 @@ public function __construct() public function delay(float $delay, $func, $args) { $class_name = $this->_eventClassName; - $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args) { + $timer_id = $this->_timerId++; + $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args, $timer_id) { try { + $this->deleteTimer($timer_id); $func(...$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); @@ -100,8 +102,8 @@ public function delay(float $delay, $func, $args) if (!$event || !$event->addTimer($delay)) { return false; } - $this->_eventTimer[$this->_timerId] = $event; - return $this->_timerId++; + $this->_eventTimer[$timer_id] = $event; + return $timer_id; } /** @@ -123,7 +125,8 @@ public function deleteTimer($timer_id) public function repeat(float $interval, $func, $args) { $class_name = $this->_eventClassName; - $event = new $this->_eventClassName($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { + $timer_id = $this->_timerId++; + $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { try { $func(...$args); } catch (\Throwable $e) { @@ -133,8 +136,8 @@ public function repeat(float $interval, $func, $args) if (!$event || !$event->addTimer($interval)) { return false; } - $this->_eventTimer[$this->_timerId] = $event; - return $this->_timerId++; + $this->_eventTimer[$timer_id] = $event; + return $timer_id; } /** diff --git a/src/Timer.php b/src/Timer.php index 2a632d873..a42025cac 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -142,9 +142,9 @@ public static function add(float $time_interval, $func, $args = [], $persistent * @param array $args * @return bool|int */ - public function delay(float $delay, $func, $args = []) + public static function delay(float $delay, $func, $args = []) { - return $this->add($delay, $func, $args); + return static::add($delay, $func, $args, false); } From 7eeb62ee0648bb2aa19f8066a492bcd5efc96fd1 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 15 May 2022 22:18:30 +0800 Subject: [PATCH 0714/1216] Session::$autoUpdateTimestamp --- src/Protocols/Http/Session.php | 20 +++++++++++++------ .../Http/Session/FileSessionHandler.php | 8 +++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index c18695017..43bbf1874 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -44,6 +44,13 @@ class Session */ public static $name = 'PHPSID'; + /** + * Auto update timestamp. + * + * @var bool + */ + public static $autoUpdateTimestamp = false; + /** * Session lifetime. * @@ -298,6 +305,8 @@ public function save() } else { static::$_handler->write($this->_sessionId, \serialize($this->_data)); } + } elseif (static::$autoUpdateTimestamp) { + static::refresh(); } $this->_needSave = false; } @@ -385,15 +394,12 @@ protected static function initHandler() } /** - * Try GC sessions. + * GC sessions. * * @return void */ - public function tryGcSessions() + public function gc() { - if (\rand(1, static::$gcProbability[1]) > static::$gcProbability[0]) { - return; - } static::$_handler->gc(static::$lifetime); } @@ -405,7 +411,9 @@ public function tryGcSessions() public function __destruct() { $this->save(); - $this->tryGcSessions(); + if (\rand(1, static::$gcProbability[1]) >= static::$gcProbability[0]) { + $this->gc(); + } } /** diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index e39caaa19..0a8d9771e 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http\Session; +use Workerman\Protocols\Http\Session; + /** * Class FileSessionHandler * @package Workerman\Protocols\Http\Session @@ -73,8 +75,12 @@ public function read($session_id) $session_file = static::sessionFile($session_id); \clearstatcache(); if (\is_file($session_file)) { + if (\time() - \filemtime($session_file) > Session::$lifetime) { + \unlink($session_file); + return ''; + } $data = \file_get_contents($session_file); - return $data ? $data : ''; + return $data ?: ''; } return ''; } From 6652d4929dbbe9c29c422304d1a617fff6ce4c34 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 30 May 2022 21:28:22 +0800 Subject: [PATCH 0715/1216] Update Request.php --- src/Protocols/Http/Request.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 41a625036..74e9675e6 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -586,6 +586,10 @@ protected function parseUploadFiles($http_post_boundary) } $files_unique = []; foreach ($files as $index => $file) { + if (!isset($file['key'])) { + unset($files[$index]); + continue; + } $key = $file['key']; if (\substr($key, -2) === '[]') { $key = $index; From 41c45412c21cf9a84c2718b0d6b5a3858919f6b3 Mon Sep 17 00:00:00 2001 From: latypoff Date: Wed, 8 Jun 2022 21:42:17 +0600 Subject: [PATCH 0716/1216] Allow to change lifetime without application reload --- src/Protocols/Http/Session/RedisSessionHandler.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index c02e7fa60..e1f334aed 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman\Protocols\Http\Session; use Workerman\Protocols\Http\Session; @@ -29,11 +30,6 @@ class RedisSessionHandler implements SessionHandlerInterface */ protected $_redis; - /** - * @var int - */ - protected $_maxLifetime; - /** * @var array */ @@ -56,7 +52,6 @@ public function __construct($config) if (false === extension_loaded('redis')) { throw new \RuntimeException('Please install redis extension.'); } - $this->_maxLifetime = (int)Session::$lifetime; if (!isset($config['timeout'])) { $config['timeout'] = 2; @@ -114,7 +109,6 @@ public function read($session_id) } throw $e; } - } /** @@ -122,7 +116,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - return true === $this->_redis->setex($session_id, $this->_maxLifetime, $session_data); + return true === $this->_redis->setex($session_id, Session::$lifetime, $session_data); } /** @@ -130,7 +124,7 @@ public function write($session_id, $session_data) */ public function updateTimestamp($id, $data = "") { - return true === $this->_redis->expire($id, $this->_maxLifetime); + return true === $this->_redis->expire($id, Session::$lifetime); } /** From 700e72a214498ab1ace6750d01952f8b33875156 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 11 Jun 2022 11:00:21 +0800 Subject: [PATCH 0717/1216] Update Response.php --- src/Protocols/Http/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index cde0bba0a..ebfae85dd 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -333,11 +333,11 @@ public function withFile($file, $offset = 0, $length = 0) * @param bool $same_site * @return $this */ - public function cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) + public function cookie($name, $value = '', $max_age = null, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) { $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) - . (empty($max_age) ? '' : '; Max-Age=' . $max_age) + . ($max_age === null ? '' : '; Max-Age=' . $max_age) . (empty($path) ? '' : '; Path=' . $path) . (!$secure ? '' : '; Secure') . (!$http_only ? '' : '; HttpOnly') From 563765e8fb18afc5425c7b4d9c6f896cdaedc13b Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 11 Jun 2022 11:26:35 +0800 Subject: [PATCH 0718/1216] Update RedisClusterSessionHandler.php --- src/Protocols/Http/Session/RedisClusterSessionHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index eb926e0c4..805ef260c 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -20,7 +20,6 @@ class RedisClusterSessionHandler extends RedisSessionHandler { public function __construct($config) { - $this->_maxLifetime = (int)Session::$lifetime; $timeout = $config['timeout'] ?? 2; $read_timeout = $config['read_timeout'] ?? $timeout; $persistent = $config['persistent'] ?? false; From 4109aefdc3f3c639f627ff28ab23957b28ba1f9a Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Jun 2022 16:26:40 +0800 Subject: [PATCH 0719/1216] Update Timer.php --- src/Timer.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Timer.php b/src/Timer.php index a42025cac..503b03892 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -114,6 +114,12 @@ public static function add(float $time_interval, $func, $args = [], $persistent if (self::$_event) { return $persistent ? self::$_event->repeat($time_interval, $func, $args) : self::$_event->delay($time_interval, $func, $args); } + + // If not workerman runtime just return. + if (!Worker::getAllWorkers()) { + throw new \Exception(); + return; + } if (!\is_callable($func)) { Worker::safeEcho(new Exception("not callable")); From ae021260e6c166e92ca4a6f0c13985c7d9fa0c1b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Jun 2022 16:34:01 +0800 Subject: [PATCH 0720/1216] Update Timer.php --- src/Timer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index 503b03892..bdefedac2 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -117,7 +117,6 @@ public static function add(float $time_interval, $func, $args = [], $persistent // If not workerman runtime just return. if (!Worker::getAllWorkers()) { - throw new \Exception(); return; } From d169b69cb52e992494f92bb308abed87d2a8e08b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 16 Jun 2022 22:10:29 +0800 Subject: [PATCH 0721/1216] Update Session.php --- src/Protocols/Http/Session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 43bbf1874..0b414772f 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -411,7 +411,7 @@ public function gc() public function __destruct() { $this->save(); - if (\rand(1, static::$gcProbability[1]) >= static::$gcProbability[0]) { + if (\rand(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { $this->gc(); } } @@ -439,4 +439,4 @@ class SessionException extends \RuntimeException } // Init session. -Session::init(); \ No newline at end of file +Session::init(); From a7b18972ae3367a9b4abe320e53621bd0ac10e53 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 16 Jun 2022 22:34:44 +0800 Subject: [PATCH 0722/1216] Update Websocket.php --- src/Protocols/Websocket.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 585675bb2..54e8241c7 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -371,12 +371,15 @@ public static function dealHandshake($buffer, TcpConnection $connection) if (isset($connection->headers)) { if (\is_array($connection->headers)) { foreach ($connection->headers as $header) { - if (\strpos($header, 'Server:') === 0) { + if (\stripos($header, 'Server:') === 0) { $has_server_header = true; } $handshake_message .= "$header\r\n"; } } else { + if (\stripos($connection->headers, 'Server:') !== false) { + $has_server_header = true; + } $handshake_message .= "$connection->headers\r\n"; } } From 2d69399f17b1aeca7bb061edffb43dff23f4e5ab Mon Sep 17 00:00:00 2001 From: twomiao <995200452> Date: Mon, 20 Jun 2022 10:31:22 +0800 Subject: [PATCH 0723/1216] Worker code optimization --- README.md | 3 +++ src/Protocols/Websocket.php | 6 +++--- src/Worker.php | 15 ++++----------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f877cc0dc..d6db0f552 100644 --- a/README.md +++ b/README.md @@ -270,10 +270,13 @@ Worker::runAll(); ```php start.php start ``` ```php start.php start -d ``` ```php start.php status ``` +```php start.php status -d ``` ```php start.php connections``` ```php start.php stop ``` +```php start.php stop -g ``` ```php start.php restart ``` ```php start.php reload ``` +```php start.php reload -g ``` ## Documentation diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 54e8241c7..5b45b4043 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -328,11 +328,11 @@ public static function dealHandshake($buffer, TcpConnection $connection) // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { // Find \r\n\r\n. - $heder_end_pos = \strpos($buffer, "\r\n\r\n"); - if (!$heder_end_pos) { + $header_end_pos = \strpos($buffer, "\r\n\r\n"); + if (!$header_end_pos) { return 0; } - $header_length = $heder_end_pos + 4; + $header_length = $header_end_pos + 4; // Get Sec-WebSocket-Key. $Sec_WebSocket_Key = ''; diff --git a/src/Worker.php b/src/Worker.php index 88fa5b635..e522c172f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1488,7 +1488,7 @@ protected static function forkOneWorkerForLinux(self $worker) if (static::$_status === static::STATUS_STARTING) { static::resetStd(); } - static::$_pidMap = []; + static::$_pidsToRestart = static::$_pidMap = []; // Remove other listener. foreach(static::$_workers as $key => $one_worker) { if ($one_worker->workerId !== $worker->workerId) { @@ -1708,11 +1708,7 @@ protected static function reload() } } - if (static::$_gracefulStop) { - $sig = \SIGUSR2; - } else { - $sig = \SIGUSR1; - } + $sig = static::$_gracefulStop ? \SIGUSR2 : \SIGUSR1; // Send reload signal to all child processes. $reloadable_pid_array = []; @@ -1787,11 +1783,8 @@ public static function stopAll($code = 0, $log = '') static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ..."); $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. - if (static::$_gracefulStop) { - $sig = \SIGQUIT; - } else { - $sig = \SIGINT; - } + $sig = static::$_gracefulStop ? \SIGQUIT : \SIGINT; + foreach ($worker_pid_array as $worker_pid) { \posix_kill($worker_pid, $sig); if(!static::$_gracefulStop){ From e05f3a6ea59e530e686c8b8d9f5014e9fc459efe Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 21 Jun 2022 15:54:31 +0800 Subject: [PATCH 0724/1216] Fix #777 --- src/Connection/TcpConnection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 8f8071016..cc490bec6 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -971,10 +971,11 @@ public static function enableCache($value) } /** - * Get the json_encode informattion. + * Get the json_encode information. * - * @return string + * @return mixed */ + #[\ReturnTypeWillChange] public function jsonSerialize() { return [ From 3286cd61167b1d652c175eac7b63d9bd13877f10 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 22 Jun 2022 09:58:52 +0800 Subject: [PATCH 0725/1216] Create SECURITY.md For #778 --- SECURITY.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..c910997e6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +# Security Policy + + +## Reporting a Vulnerability + +Please contact by email walkor@workerman.net From c2dde2e04a8f973818b4fdbc124a3be8e8945094 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 22 Jun 2022 21:57:23 +0800 Subject: [PATCH 0726/1216] use safer random functions --- src/Protocols/Http/Request.php | 2 +- src/Protocols/Http/Session.php | 2 +- src/Protocols/Http/Session/FileSessionHandler.php | 2 +- src/Protocols/Ws.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 74e9675e6..d7f076de9 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -619,7 +619,7 @@ protected function parseUploadFiles($http_post_boundary) */ public static function createSessionId() { - return \bin2hex(\pack('d', \microtime(true)) . \pack('N', \mt_rand())); + return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8)); } /** diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 0b414772f..86bd1338b 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -411,7 +411,7 @@ public function gc() public function __destruct() { $this->save(); - if (\rand(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { + if (\random_int(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { $this->gc(); } } diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index 0a8d9771e..234afd70e 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -90,7 +90,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - $temp_file = static::$_sessionSavePath . uniqid(mt_rand(), true); + $temp_file = static::$_sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); if (!\file_put_contents($temp_file, $session_data)) { return false; } diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index d1d631d22..158765769 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -346,7 +346,7 @@ public static function sendHandshake(TcpConnection $connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $connection->websocketSecKey = \base64_encode(\md5(\mt_rand(), true)); + $connection->websocketSecKey = \base64_encode(random_bytes(16)); $user_header = isset($connection->headers) ? $connection->headers : (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); $user_header_str = ''; From a77916699808597cc4e822d265a326e2bcc22983 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 23 Jun 2022 21:40:10 +0800 Subject: [PATCH 0727/1216] Update Request.php --- src/Protocols/Http/Request.php | 247 ++++++++++++++++----------------- 1 file changed, 118 insertions(+), 129 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index d7f076de9..956f03af4 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -46,6 +46,11 @@ class Request */ public $properties = []; + /** + * @var int + */ + public static $maxFileUploads = 1024; + /** * Http buffer. * @@ -60,27 +65,6 @@ class Request */ protected $_data = null; - /** - * Header cache. - * - * @var array - */ - protected static $_headerCache = []; - - /** - * Get cache. - * - * @var array - */ - protected static $_getCache = []; - - /** - * Post cache. - * - * @var array - */ - protected static $_postCache = []; - /** * Enable cache. * @@ -410,6 +394,7 @@ protected function parseProtocolVersion() */ protected function parseHeaders() { + static $cache = []; $this->_data['headers'] = []; $raw_head = $this->rawHead(); $end_line_position = \strpos($raw_head, "\r\n"); @@ -418,8 +403,8 @@ protected function parseHeaders() } $head_buffer = \substr($raw_head, $end_line_position + 2); $cacheable = static::$_enableCache && !isset($head_buffer[2048]); - if ($cacheable && isset(static::$_headerCache[$head_buffer])) { - $this->_data['headers'] = static::$_headerCache[$head_buffer]; + if ($cacheable && isset($cache[$head_buffer])) { + $this->_data['headers'] = $cache[$head_buffer]; return; } $head_data = \explode("\r\n", $head_buffer); @@ -439,9 +424,9 @@ protected function parseHeaders() } } if ($cacheable) { - static::$_headerCache[$head_buffer] = $this->_data['headers']; - if (\count(static::$_headerCache) > 128) { - unset(static::$_headerCache[key(static::$_headerCache)]); + $cache[$head_buffer] = $this->_data['headers']; + if (\count($cache) > 128) { + unset($cache[key($cache)]); } } } @@ -453,21 +438,22 @@ protected function parseHeaders() */ protected function parseGet() { + static $cache = []; $query_string = $this->queryString(); $this->_data['get'] = []; if ($query_string === '') { return; } $cacheable = static::$_enableCache && !isset($query_string[1024]); - if ($cacheable && isset(static::$_getCache[$query_string])) { - $this->_data['get'] = static::$_getCache[$query_string]; + if ($cacheable && isset($cache[$query_string])) { + $this->_data['get'] = $cache[$query_string]; return; } \parse_str($query_string, $this->_data['get']); if ($cacheable) { - static::$_getCache[$query_string] = $this->_data['get']; - if (\count(static::$_getCache) > 256) { - unset(static::$_getCache[key(static::$_getCache)]); + $cache[$query_string] = $this->_data['get']; + if (\count($cache) > 256) { + unset($cache[key($cache)]); } } } @@ -479,31 +465,32 @@ protected function parseGet() */ protected function parsePost() { - $body_buffer = $this->rawBody(); + static $cache = []; $this->_data['post'] = $this->_data['files'] = []; - if ($body_buffer === '') { - return; - } - $cacheable = static::$_enableCache && !isset($body_buffer[1024]); - if ($cacheable && isset(static::$_postCache[$body_buffer])) { - $this->_data['post'] = static::$_postCache[$body_buffer]; - return; - } $content_type = $this->header('content-type', ''); if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { $http_post_boundary = '--' . $match[1]; $this->parseUploadFiles($http_post_boundary); return; } + $body_buffer = $this->rawBody(); + if ($body_buffer === '') { + return; + } + $cacheable = static::$_enableCache && !isset($body_buffer[1024]); + if ($cacheable && isset($cache[$body_buffer])) { + $this->_data['post'] = $cache[$body_buffer]; + return; + } if (\preg_match('/\bjson\b/i', $content_type)) { $this->_data['post'] = (array)\json_decode($body_buffer, true); } else { \parse_str($body_buffer, $this->_data['post']); } if ($cacheable) { - static::$_postCache[$body_buffer] = $this->_data['post']; - if (\count(static::$_postCache) > 256) { - unset(static::$_postCache[key(static::$_postCache)]); + $cache[$body_buffer] = $this->_data['post']; + if (\count($cache) > 256) { + unset($cache[key($cache)]); } } } @@ -517,99 +504,101 @@ protected function parsePost() protected function parseUploadFiles($http_post_boundary) { $http_post_boundary = \trim($http_post_boundary, '"'); - $http_body = $this->rawBody(); - $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4)); - $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body); - if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") { - unset($boundary_data_array[0]); - } - $index = -1; - $files = []; - $post_str = ''; - foreach ($boundary_data_array as $boundary_data_buffer) { - list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2); - // Remove \r\n from the end of buffer. - $boundary_value = \substr($boundary_value, 0, -2); - $index++; - foreach (\explode("\r\n", $boundary_header_buffer) as $item) { - list($header_key, $header_value) = \explode(": ", $item); - $header_key = \strtolower($header_key); - switch ($header_key) { - case "content-disposition": - // Is file data. - if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) { - $error = 0; - $tmp_file = ''; - $size = \strlen($boundary_value); - $tmp_upload_dir = HTTP::uploadTmpDir(); - if (!$tmp_upload_dir) { - $error = UPLOAD_ERR_NO_TMP_DIR; - } else if ($boundary_value === '') { - $error = UPLOAD_ERR_NO_FILE; - } else { - $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.'); - if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) { - $error = UPLOAD_ERR_CANT_WRITE; - } - } - if (!isset($files[$index])) { - $files[$index] = []; - } - // Parse upload files. - $files[$index] += [ - 'key' => $match[1], - 'name' => $match[2], - 'tmp_name' => $tmp_file, - 'size' => $size, - 'error' => $error, - 'type' => null, - ]; - break; - } // Is post field. - else { - // Parse $_POST. - if (\preg_match('/name="(.*?)"$/', $header_value, $match)) { - $k = $match[1]; - $post_str .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; + $buffer = $this->_buffer; + $boday_position = strpos($buffer, "\r\n\r\n") + 4; + $offset = $boday_position + strlen($http_post_boundary) + 2; + $max_count = static::$maxFileUploads; + while ($max_count-- > 0 && $offset) { + $offset = $this->parseUploadFile($http_post_boundary, $offset); + } + } + + /** + * @param $boundary + * @param $section_start_offset + * @return int + */ + protected function parseUploadFile($boundary, $section_start_offset) + { + $file = []; + $boundary = "\r\n$boundary"; + $section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset); + if (!$section_end_offset) { + return 0; + } + $content_lines_end_offset = \strpos($this->_buffer, "\r\n\r\n", $section_start_offset); + if (!$content_lines_end_offset || $content_lines_end_offset + 4 > $section_end_offset) { + return 0; + } + $content_lines_str = \substr($this->_buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset); + $content_lines = \explode("\r\n", trim($content_lines_str . "\r\n")); + $boundary_value = \substr($this->_buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4); + $upload_key = false; + foreach ($content_lines as $content_line) { + if (!\strpos($content_line, ': ')) { + return 0; + } + [$key, $value] = \explode(': ', $content_line); + switch (strtolower($key)) { + case "content-disposition": + // Is file data. + if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { + $error = 0; + $tmp_file = ''; + $size = \strlen($boundary_value); + $tmp_upload_dir = HTTP::uploadTmpDir(); + if (!$tmp_upload_dir) { + $error = UPLOAD_ERR_NO_TMP_DIR; + } else if ($boundary_value === '') { + $error = UPLOAD_ERR_NO_FILE; + } else { + $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.'); + if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) { + $error = UPLOAD_ERR_CANT_WRITE; } } + $upload_key = $match[1]; + // Parse upload files. + $file = [ + 'name' => $match[2], + 'tmp_name' => $tmp_file, + 'size' => $size, + 'error' => $error, + 'type' => null, + ]; break; - case "content-type": - // add file_type - if (!isset($files[$index])) { - $files[$index] = []; + } // Is post field. + else { + // Parse $_POST. + if (\preg_match('/name="(.*?)"$/', $value, $match)) { + $k = $match[1]; + $post_str = \urlencode($k) . "=" . \urlencode($boundary_value); + $post = []; + parse_str($post_str, $post); + if ($post) { + $this->_data['post'] = \array_merge_recursive($this->_data['post'], $post); + } } - $files[$index]['type'] = \trim($header_value); - break; - } - } - } - $files_unique = []; - foreach ($files as $index => $file) { - if (!isset($file['key'])) { - unset($files[$index]); - continue; - } - $key = $file['key']; - if (\substr($key, -2) === '[]') { - $key = $index; + return $section_end_offset + \strlen($boundary) + 2; + } + break; + case "content-type": + $file['type'] = \trim($value); + break; } - $files_unique[$key] = $file; - } - foreach ($files_unique as $file) { - $key = $file['key']; - unset($file['key']); - $str = \urlencode($key) . "=1"; - $result = []; - \parse_str($str, $result); - \array_walk_recursive($result, function (&$value) use ($file) { - $value = $file; - }); - $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result); } - if ($post_str) { - parse_str($post_str, $this->_data['post']); + if ($upload_key === false) { + return 0; } + $str = \urlencode($upload_key) . "=1"; + $result = []; + \parse_str($str, $result); + \array_walk_recursive($result, function (&$value) use ($file) { + $value = $file; + }); + $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result); + + return $section_end_offset + \strlen($boundary) + 2; } /** From 99b24a3eb76f63a6249c7fb22c59daa5a3f4e123 Mon Sep 17 00:00:00 2001 From: chengyao <64066545+topyao@users.noreply.github.com> Date: Fri, 24 Jun 2022 22:37:08 +0800 Subject: [PATCH 0728/1216] =?UTF-8?q?=E4=BF=AE=E5=A4=8DPHP=20Warning:=20?= =?UTF-8?q?=20Undefined=20array=20key=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index ebfae85dd..69686cc4a 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -409,7 +409,7 @@ public function __toString() return $this->createHeadForFile($this->file); } - $reason = $this->_reason ?: static::$_phrases[$this->_status]; + $reason = $this->_reason ?: static::$_phrases[$this->_status] ?? ''; $body_len = \strlen($this->_body); if (empty($this->_header)) { return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; From 1a1b76f71a4b7520b335901ac6af06318398eeeb Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 18 Jul 2022 21:19:37 +0800 Subject: [PATCH 0729/1216] Update Session.php --- src/Protocols/Http/Session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 86bd1338b..2302b7157 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -328,7 +328,7 @@ public function refresh() */ public static function init() { - if ($gc_probability = (int)\ini_get('session.gc_probability') && $gc_divisor = (int)\ini_get('session.gc_divisor')) { + if (($gc_probability = (int)\ini_get('session.gc_probability')) && ($gc_divisor = (int)\ini_get('session.gc_divisor'))) { static::$gcProbability = [$gc_probability, $gc_divisor]; } From 7ea14aceb35bf8a26b388c4387e58fd211b2d754 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 19 Jul 2022 15:51:33 +0800 Subject: [PATCH 0730/1216] fix php8.1.8 stdout redirect bug --- src/Worker.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index e522c172f..f05e8bf27 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -13,13 +13,12 @@ */ namespace Workerman; -use Workerman\Events\Event; -use Workerman\Events\EventInterface; +use Exception; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; +use Workerman\Events\Event; use Workerman\Events\Select; -use Exception; /** @@ -1234,10 +1233,20 @@ public static function resetStd(bool $throw_exception = true) if ($STDERR) { \fclose($STDERR); } - \fclose(\STDOUT); - \fclose(\STDERR); + if (\is_resource(\STDOUT)) { + \fclose(\STDOUT); + } + if (\is_resource(\STDERR)) { + \fclose(\STDERR); + } $STDOUT = \fopen(static::$stdoutFile, "a"); $STDERR = \fopen(static::$stdoutFile, "a"); + // Fix standard output cannot redirect of PHP 8.1.8's bug + if (\posix_isatty(2)) { + \ob_start(function ($string) { + \file_put_contents(static::$stdoutFile, $string, FILE_APPEND); + }, 1); + } // change output stream static::$_outputStream = null; static::outputStream($STDOUT); From 9ef1ef1288be8a1f5a5773daf71d5b4b14635e92 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 26 Jul 2022 16:50:32 +0800 Subject: [PATCH 0731/1216] onWorkerExit --- src/Worker.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index f05e8bf27..a95db3790 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -181,7 +181,7 @@ class Worker public $onBufferDrain = null; /** - * Emitted when worker processes stoped. + * Emitted when worker processes stopped. * * @var callable */ @@ -194,6 +194,13 @@ class Worker */ public $onWorkerReload = null; + /** + * Emitted when worker processes exited. + * + * @var callable + */ + public $onWorkerExit = null; + /** * Transport layer protocol. * @@ -1619,7 +1626,16 @@ protected static function monitorWorkersForLinux() $worker = static::$_workers[$worker_id]; // Exit status. if ($status !== 0) { - static::log("worker[" . $worker->name . ":$pid] exit with status $status"); + static::log("worker[{$worker->name}:$pid] exit with status $status"); + } + + // onWorkerExit + if ($worker->onWorkerExit) { + try { + ($worker->onWorkerExit)($worker, $status, $pid); + } catch (\Throwable $exception) { + static::log("worker[{$worker->name}] onWorkerExit $exception"); + } } // For Statistics. From 17d785758c2cbbf87edfae2bc6ef8091df13ea3a Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 26 Jul 2022 16:52:18 +0800 Subject: [PATCH 0732/1216] Throwable namespace --- src/Worker.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index a95db3790..cc111c725 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -14,6 +14,7 @@ namespace Workerman; use Exception; +use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; @@ -1633,7 +1634,7 @@ protected static function monitorWorkersForLinux() if ($worker->onWorkerExit) { try { ($worker->onWorkerExit)($worker, $status, $pid); - } catch (\Throwable $exception) { + } catch (Throwable $exception) { static::log("worker[{$worker->name}] onWorkerExit $exception"); } } @@ -1726,7 +1727,7 @@ protected static function reload() if (static::$onMasterReload) { try { \call_user_func(static::$onMasterReload); - } catch (\Throwable $e) { + } catch (Throwable $e) { static::stopAll(250, $e); } static::initId(); @@ -1777,7 +1778,7 @@ protected static function reload() if ($worker->onWorkerReload) { try { \call_user_func($worker->onWorkerReload, $worker); - } catch (\Throwable $e) { + } catch (Throwable $e) { static::stopAll(250, $e); } } @@ -2386,7 +2387,7 @@ public function run() if ($this->onWorkerStart) { try { ($this->onWorkerStart)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { // Avoid rapid infinite loop exit. sleep(1); static::stopAll(250, $e); @@ -2408,7 +2409,7 @@ public function stop() if ($this->onWorkerStop) { try { ($this->onWorkerStop)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::log($e); } } @@ -2458,7 +2459,7 @@ public function acceptTcpConnection($socket) if ($this->onConnect) { try { ($this->onConnect)($connection); - } catch (\Throwable $e) { + } catch (Throwable $e) { static::stopAll(250, $e); } } @@ -2512,7 +2513,7 @@ public function acceptUdpConnection($socket) $message_cb($connection, $recv_buffer); } ++ConnectionInterface::$statistics['total_request']; - } catch (\Throwable $e) { + } catch (Throwable $e) { static::stopAll(250, $e); } } From bb07319ae0713ddd6ed24329c92cdc757aba1754 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Jul 2022 11:10:32 +0800 Subject: [PATCH 0733/1216] Update Http.php --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index cc5d4bbea..4bd89b511 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -86,7 +86,7 @@ public static function input($recv_buffer, TcpConnection $connection) if (false === $crlf_pos) { // Judge whether the package length exceeds the limit. if ($recv_len = \strlen($recv_buffer) >= 16384) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } return 0; From 00283b15424c14c5a07524d2bc3bdec2452743c7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Jul 2022 11:13:50 +0800 Subject: [PATCH 0734/1216] Update Http.php --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 4bd89b511..47aa5e08d 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -124,7 +124,7 @@ public static function input($recv_buffer, TcpConnection $connection) } } if ($length > $connection->maxPackageSize) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n"); + $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } return $length; From 81c34d64cb47807a82b23e4b9789e48604873266 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 29 Jul 2022 16:42:17 +0800 Subject: [PATCH 0735/1216] Update Request.php --- src/Protocols/Http/Request.php | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 956f03af4..a22b30b2d 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -505,11 +505,24 @@ protected function parseUploadFiles($http_post_boundary) { $http_post_boundary = \trim($http_post_boundary, '"'); $buffer = $this->_buffer; + $post_encode_string = ''; + $files_encode_string = ''; + $files = []; $boday_position = strpos($buffer, "\r\n\r\n") + 4; $offset = $boday_position + strlen($http_post_boundary) + 2; $max_count = static::$maxFileUploads; while ($max_count-- > 0 && $offset) { - $offset = $this->parseUploadFile($http_post_boundary, $offset); + $offset = $this->parseUploadFile($http_post_boundary, $offset, $post_encode_string, $files_encode_string, $files); + } + if ($post_encode_string) { + parse_str($post_encode_string, $this->_data['post']); + } + + if ($files_encode_string) { + parse_str($files_encode_string, $this->_data['files']); + \array_walk_recursive($this->_data['files'], function (&$value) use ($files) { + $value = $files[$value]; + }); } } @@ -518,7 +531,7 @@ protected function parseUploadFiles($http_post_boundary) * @param $section_start_offset * @return int */ - protected function parseUploadFile($boundary, $section_start_offset) + protected function parseUploadFile($boundary, $section_start_offset, &$post_encode_string, &$files_encode_str, &$files) { $file = []; $boundary = "\r\n$boundary"; @@ -572,12 +585,7 @@ protected function parseUploadFile($boundary, $section_start_offset) // Parse $_POST. if (\preg_match('/name="(.*?)"$/', $value, $match)) { $k = $match[1]; - $post_str = \urlencode($k) . "=" . \urlencode($boundary_value); - $post = []; - parse_str($post_str, $post); - if ($post) { - $this->_data['post'] = \array_merge_recursive($this->_data['post'], $post); - } + $post_encode_string .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; } return $section_end_offset + \strlen($boundary) + 2; } @@ -590,13 +598,8 @@ protected function parseUploadFile($boundary, $section_start_offset) if ($upload_key === false) { return 0; } - $str = \urlencode($upload_key) . "=1"; - $result = []; - \parse_str($str, $result); - \array_walk_recursive($result, function (&$value) use ($file) { - $value = $file; - }); - $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result); + $files_encode_str .= \urlencode($upload_key) . '=' . \count($files) . '&'; + $files[] = $file; return $section_end_offset + \strlen($boundary) + 2; } From cddfe86ec2bf31a4379d0e4386c63d01fc542bc7 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 31 Jul 2022 19:21:36 +0800 Subject: [PATCH 0736/1216] commit --- src/Events/Select.php | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 6541ed25c..1fc4fc9af 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -14,6 +14,9 @@ namespace Workerman\Events; +use Throwable; +use Workerman\Worker; + /** * select eventloop */ @@ -259,6 +262,7 @@ public function signalHandler($signal) */ protected function tick() { + $tasks_to_insert = []; while (!$this->_scheduler->isEmpty()) { $scheduler_data = $this->_scheduler->top(); $timer_id = $scheduler_data['data']; @@ -276,13 +280,27 @@ protected function tick() $task_data = $this->_eventTimer[$timer_id]; if (isset($task_data[2])) { $next_run_time = $time_now + $task_data[2]; - $this->_scheduler->insert($timer_id, -$next_run_time); + $tasks_to_insert[] = [$timer_id, -$next_run_time]; } else { unset($this->_eventTimer[$timer_id]); } - $task_data[0]($task_data[1]); - continue; + try { + $task_data[0]($task_data[1]); + } catch (Throwable $e) { + Worker::stopAll(250, $e); + } + } else { + break; } + } + foreach ($tasks_to_insert as $item) { + $this->_scheduler->insert($item[0], $item[1]); + } + if (!$this->_scheduler->isEmpty()) { + $scheduler_data = $this->_scheduler->top(); + $next_run_time = -$scheduler_data['priority']; + $time_now = \microtime(true); + $this->_selectTimeout = \max((int)(($next_run_time - $time_now) * 1000000), 0); return; } $this->_selectTimeout = 100000000; @@ -317,12 +335,11 @@ public function run() // Waiting read/write/signal/timeout events. try { @stream_select($read, $write, $except, 0, $this->_selectTimeout); - } catch (\Throwable $e) { + } catch (Throwable $e) { } } else { $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); - $ret = false; } if (!$this->_scheduler->isEmpty()) { From 1731457a26857935220f4a94da6028cf344eec92 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Sun, 31 Jul 2022 14:38:23 +0300 Subject: [PATCH 0737/1216] Add .gitattributes, exclude tests from archive --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..f948e41e0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +/.gitattributes export-ignore +/.github export-ignore +/.gitignore export-ignore From d73f172d74aaa513472ee0f377133affa4713d3c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 13 Sep 2022 21:57:06 +0800 Subject: [PATCH 0738/1216] Update Worker.php --- src/Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index cc111c725..bd6caa994 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -545,11 +545,13 @@ public static function runAll() { static::checkSapiEnv(); static::init(); + static::lock(); static::parseCommand(); static::daemonize(); static::initWorkers(); static::installSignal(); static::saveMasterPid(); + static::unlock(); static::displayUI(); static::forkWorkers(); static::resetStd(); @@ -628,7 +630,7 @@ protected static function init() */ protected static function lock() { - $fd = \fopen(static::$_startFile, 'r'); + $fd = \fopen(static::$_startFile, 'a+'); if ($fd && !flock($fd, LOCK_EX)) { static::log('Workerman['.static::$_startFile.'] already running.'); exit; From fbdf67f22a9d2b5fb60d1e7fbf0c798834d24c54 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Sep 2022 09:39:31 +0800 Subject: [PATCH 0739/1216] lock --- src/Worker.php | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index bd6caa994..63924cd89 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -551,7 +551,7 @@ public static function runAll() static::initWorkers(); static::installSignal(); static::saveMasterPid(); - static::unlock(); + static::lock(\LOCK_UN); static::displayUI(); static::forkWorkers(); static::resetStd(); @@ -628,26 +628,15 @@ protected static function init() * * @return void */ - protected static function lock() + protected static function lock($flag = \LOCK_EX) { - $fd = \fopen(static::$_startFile, 'a+'); - if ($fd && !flock($fd, LOCK_EX)) { - static::log('Workerman['.static::$_startFile.'] already running.'); - exit; + static $fd; + $fd = $fd ?: \fopen(static::$_startFile, 'a+'); + if ($fd) { + flock($fd, $flag); } } - /** - * Unlock. - * - * @return void - */ - protected static function unlock() - { - $fd = \fopen(static::$_startFile, 'r'); - $fd && flock($fd, \LOCK_UN); - } - /** * Init All worker instances. * From 27dd1268d09f810fd6fb1fa4bbe2acf4c5d11bdb Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 14 Sep 2022 19:23:17 +0800 Subject: [PATCH 0740/1216] clearstatcache for filesize --- src/Protocols/Http.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 47aa5e08d..a443a6fab 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -205,6 +205,7 @@ public static function encode($response, TcpConnection $connection) $file = $response->file['file']; $offset = $response->file['offset']; $length = $response->file['length']; + \clearstatcache(); $file_size = (int)\filesize($file); $body_len = $length > 0 ? $length : $file_size - $offset; $response->withHeaders([ From 9a29d1677f3747c39dfb805a0e6397c43339862b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Sep 2022 12:13:58 +0800 Subject: [PATCH 0741/1216] Support body for GET OPTIONS HEAD DELETE --- src/Protocols/Http.php | 44 +++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index a443a6fab..8c51d8ab5 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -85,53 +85,49 @@ public static function input($recv_buffer, TcpConnection $connection) $crlf_pos = \strpos($recv_buffer, "\r\n\r\n"); if (false === $crlf_pos) { // Judge whether the package length exceeds the limit. - if ($recv_len = \strlen($recv_buffer) >= 16384) { + if (\strlen($recv_buffer) >= 16384) { $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } return 0; } - $head_len = $crlf_pos + 4; + $length = $crlf_pos + 4; $method = \strstr($recv_buffer, ' ', true); - if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD' || $method === 'DELETE') { - if (!isset($recv_buffer[512])) { - $input[$recv_buffer] = $head_len; - if (\count($input) > 512) { - unset($input[\key($input)]); - } - } - return $head_len; - } else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'PATCH') { + if (!\in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } $header = \substr($recv_buffer, 0, $crlf_pos); - $length = false; + $has_content_length = false; if ($pos = \strpos($header, "\r\nContent-Length: ")) { - $length = $head_len + (int)\substr($header, $pos + 18, 10); + $length = $length + (int)\substr($header, $pos + 18, 10); + $has_content_length = true; } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { - $length = $head_len + $match[1]; + $length = $length + $match[1]; + $has_content_length = true; } - if ($length !== false) { - if (!isset($recv_buffer[512])) { - $input[$recv_buffer] = $length; - if (\count($input) > 512) { - unset($input[\key($input)]); - } - } + if ($has_content_length) { if ($length > $connection->maxPackageSize) { $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } - return $length; + } elseif (\in_array($method, ['POST', 'PUT', 'PATCH'])) { + $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; + } + + if (!isset($recv_buffer[512])) { + $input[$recv_buffer] = $length; + if (\count($input) > 512) { + unset($input[key($input)]); + } } - $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); - return 0; + return $length; } /** From aa9c58b02e3aef7b83b96c31524a8141398dae37 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Sep 2022 12:16:33 +0800 Subject: [PATCH 0742/1216] Check offset --- src/Protocols/Http/Request.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index a22b30b2d..9509b5f07 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -535,6 +535,9 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco { $file = []; $boundary = "\r\n$boundary"; + if (\strlen($this->_buffer) < $section_start_offset) { + return 0; + } $section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset); if (!$section_end_offset) { return 0; From b7c5da2a45fa6e50559bb125a3db85f5d7a58b31 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 20 Sep 2022 17:20:38 +0800 Subject: [PATCH 0743/1216] fix #808 #809 #810 --- src/Connection/AsyncUdpConnection.php | 2 +- src/Connection/UdpConnection.php | 2 +- src/Protocols/Http/Session.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 1da40a41f..bf58cfe65 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -181,7 +181,7 @@ public function connect() \stream_set_blocking($this->_socket, false); if ($this->onMessage) { - Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, [$this, 'baseRead']); + Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseRead']); } $this->connected = true; // Try to emit onConnect callback. diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 813b48cd6..f55149383 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -210,7 +210,7 @@ public function getSocket() /** * Get the json_encode informattion. * - * @return string + * @return array */ public function jsonSerialize() { diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 2302b7157..113e78ce8 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -318,7 +318,7 @@ public function save() */ public function refresh() { - static::$_handler->updateTimestamp($this->getId()); + return static::$_handler->updateTimestamp($this->getId()); } /** From dc6d96b3e8814ce4d8a91d8610bcf58d27daa51f Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Sep 2022 10:17:25 +0800 Subject: [PATCH 0744/1216] content-length --- src/Protocols/Http.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 8c51d8ab5..57fffe9e3 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -76,7 +76,7 @@ public static function enableCache($value) * @param TcpConnection $connection * @return int */ - public static function input($recv_buffer, TcpConnection $connection) + public static function input(string $recv_buffer, TcpConnection $connection) { static $input = []; if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) { @@ -101,13 +101,18 @@ public static function input($recv_buffer, TcpConnection $connection) } $header = \substr($recv_buffer, 0, $crlf_pos); - $has_content_length = false; if ($pos = \strpos($header, "\r\nContent-Length: ")) { $length = $length + (int)\substr($header, $pos + 18, 10); $has_content_length = true; } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { $length = $length + $match[1]; $has_content_length = true; + } else { + $has_content_length = false; + if (false !== stripos($header, "\r\nTransfer-Encoding:")) { + $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; + } } if ($has_content_length) { @@ -115,9 +120,6 @@ public static function input($recv_buffer, TcpConnection $connection) $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); return 0; } - } elseif (\in_array($method, ['POST', 'PUT', 'PATCH'])) { - $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); - return 0; } if (!isset($recv_buffer[512])) { From 6ffe8caca0c6ea63f72d619790817abda39572ff Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 22 Sep 2022 10:18:36 +0800 Subject: [PATCH 0745/1216] lock optimizations --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 63924cd89..11ded1a9d 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -631,7 +631,7 @@ protected static function init() protected static function lock($flag = \LOCK_EX) { static $fd; - $fd = $fd ?: \fopen(static::$_startFile, 'a+'); + $fd = $fd ?: \fopen(static::$pidFile . '.lock', 'a+'); if ($fd) { flock($fd, $flag); } From c5aa97b6377bd4d337ae2330f15456c0bb73d2e1 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 23 Sep 2022 21:55:06 +0800 Subject: [PATCH 0746/1216] fix lock for windows --- src/Worker.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index 11ded1a9d..b8af07632 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -631,6 +631,9 @@ protected static function init() protected static function lock($flag = \LOCK_EX) { static $fd; + if (\DIRECTORY_SEPARATOR !== '/') { + return; + } $fd = $fd ?: \fopen(static::$pidFile . '.lock', 'a+'); if ($fd) { flock($fd, $flag); From b0857b5c39ea4ac9a0f48d241507edfcc26dd72f Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 30 Sep 2022 19:24:56 +0800 Subject: [PATCH 0747/1216] remove lock file --- src/Worker.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index b8af07632..1e58357c2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -634,9 +634,18 @@ protected static function lock($flag = \LOCK_EX) if (\DIRECTORY_SEPARATOR !== '/') { return; } - $fd = $fd ?: \fopen(static::$pidFile . '.lock', 'a+'); + $lock_file = static::$pidFile . '.lock'; + $fd = $fd ?: \fopen($lock_file, 'a+'); if ($fd) { flock($fd, $flag); + if ($flag === \LOCK_UN) { + fclose($fd); + $fd = null; + clearstatcache(); + if (\is_file($lock_file)) { + unlink($lock_file); + } + } } } From 634d56c4b4e8e19b093e882ca88bd2f875f2e95d Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 11 Oct 2022 17:11:38 +0800 Subject: [PATCH 0748/1216] connection->context --- src/Protocols/Websocket.php | 97 ++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 5b45b4043..4e3402c8e 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -55,14 +55,14 @@ public static function input($buffer, ConnectionInterface $connection) } // Has not yet completed the handshake. - if (empty($connection->websocketHandshake)) { + if (empty($connection->context->websocketHandshake)) { return static::dealHandshake($buffer, $connection); } // Buffer websocket frame data. - if ($connection->websocketCurrentFrameLength) { + if ($connection->context->websocketCurrentFrameLength) { // We need more frame data. - if ($connection->websocketCurrentFrameLength > $recv_len) { + if ($connection->context->websocketCurrentFrameLength > $recv_len) { // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1. return 0; } @@ -110,7 +110,7 @@ public static function input($buffer, ConnectionInterface $connection) // Pong package. case 0xa: break; - // Wrong opcode. + // Wrong opcode. default : Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"); $connection->close(); @@ -138,7 +138,7 @@ public static function input($buffer, ConnectionInterface $connection) } $current_frame_length = $head_len + $data_len; - $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length; + $total_package_size = \strlen($connection->context->websocketDataBuffer) + $current_frame_length; if ($total_package_size > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$total_package_size\n"); $connection->close(); @@ -192,22 +192,22 @@ public static function input($buffer, ConnectionInterface $connection) } return $current_frame_length; } else { - $connection->websocketCurrentFrameLength = $current_frame_length; + $connection->context->websocketCurrentFrameLength = $current_frame_length; } } // Received just a frame length data. - if ($connection->websocketCurrentFrameLength === $recv_len) { + if ($connection->context->websocketCurrentFrameLength === $recv_len) { static::decode($buffer, $connection); - $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $connection->websocketCurrentFrameLength = 0; + $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); + $connection->context->websocketCurrentFrameLength = 0; return 0; } // The length of the received data is greater than the length of a frame. - elseif ($connection->websocketCurrentFrameLength < $recv_len) { - static::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); - $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $current_frame_length = $connection->websocketCurrentFrameLength; - $connection->websocketCurrentFrameLength = 0; + elseif ($connection->context->websocketCurrentFrameLength < $recv_len) { + static::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); + $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); + $current_frame_length = $connection->context->websocketCurrentFrameLength; + $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. return static::input(\substr($buffer, $current_frame_length), $connection); } // The length of the received data is less than the length of a frame. @@ -246,12 +246,12 @@ public static function encode($buffer, ConnectionInterface $connection) } // Handshake not completed so temporary buffer websocket data waiting for send. - if (empty($connection->websocketHandshake)) { - if (empty($connection->tmpWebsocketData)) { - $connection->tmpWebsocketData = ''; + if (empty($connection->context->websocketHandshake)) { + if (empty($connection->context->tmpWebsocketData)) { + $connection->context->tmpWebsocketData = ''; } // If buffer has already full then discard the current package. - if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (\strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); @@ -261,9 +261,9 @@ public static function encode($buffer, ConnectionInterface $connection) } return ''; } - $connection->tmpWebsocketData .= $encode_buffer; + $connection->context->tmpWebsocketData .= $encode_buffer; // Check buffer is full. - if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) { if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); @@ -288,7 +288,10 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $len = \ord($buffer[1]) & 127; + $first_byte = \ord($buffer[1]); + $len = $first_byte & 127; + $rsv1 = $first_byte & 64; + if ($len === 126) { $masks = \substr($buffer, 4, 4); $data = \substr($buffer, 8); @@ -304,13 +307,13 @@ public static function decode($buffer, ConnectionInterface $connection) $dataLength = \strlen($data); $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4); $decoded = $data ^ $masks; - if ($connection->websocketCurrentFrameLength) { - $connection->websocketDataBuffer .= $decoded; - return $connection->websocketDataBuffer; + if ($connection->context->websocketCurrentFrameLength) { + $connection->context->websocketDataBuffer .= $decoded; + return $connection->context->websocketDataBuffer; } else { - if ($connection->websocketDataBuffer !== '') { - $decoded = $connection->websocketDataBuffer . $decoded; - $connection->websocketDataBuffer = ''; + if ($connection->context->websocketDataBuffer !== '') { + $decoded = $connection->context->websocketDataBuffer . $decoded; + $connection->context->websocketDataBuffer = ''; } return $decoded; } @@ -353,14 +356,24 @@ public static function dealHandshake($buffer, TcpConnection $connection) . "Sec-WebSocket-Accept: " . $new_key . "\r\n"; // Websocket data buffer. - $connection->websocketDataBuffer = ''; + $connection->context->websocketDataBuffer = ''; // Current websocket frame length. - $connection->websocketCurrentFrameLength = 0; + $connection->context->websocketCurrentFrameLength = 0; // Current websocket frame data. - $connection->websocketCurrentFrameBuffer = ''; + $connection->context->websocketCurrentFrameBuffer = ''; // Consume handshake data. $connection->consumeRecvBuffer($header_length); + // Try to emit onWebSocketConnect callback. + $on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; + if ($on_websocket_connect) { + try { + $on_websocket_connect($connection, new Request($buffer)); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + } + // blob or arraybuffer if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; @@ -390,33 +403,17 @@ public static function dealHandshake($buffer, TcpConnection $connection) // Send handshake response. $connection->send($handshake_message, true); // Mark handshake complete.. - $connection->websocketHandshake = true; - - // Try to emit onWebSocketConnect callback. - $on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; - if ($on_websocket_connect) { - try { - $on_websocket_connect($connection, new Request($buffer)); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); - } - } + $connection->context->websocketHandshake = true; // There are data waiting to be sent. - if (!empty($connection->tmpWebsocketData)) { - $connection->send($connection->tmpWebsocketData, true); - $connection->tmpWebsocketData = ''; + if (!empty($connection->context->tmpWebsocketData)) { + $connection->send($connection->context->tmpWebsocketData, true); + $connection->context->tmpWebsocketData = ''; } if (\strlen($buffer) > $header_length) { return static::input(\substr($buffer, $header_length), $connection); } return 0; - } // Is flash policy-file-request. - elseif (0 === \strpos($buffer, 'send($policy_xml, true); - $connection->consumeRecvBuffer(\strlen($buffer)); - return 0; } // Bad websocket handshake request. $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", From 87e2d4e10956c5f3fee80c16bd2fac0024f134a2 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 11 Oct 2022 17:13:56 +0800 Subject: [PATCH 0749/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index cc490bec6..f90e33af7 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -157,6 +157,13 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * @var int */ public $maxSendBufferSize = 1048576; + + /** + * Context. + * + * @var array + */ + public $context = null; /** * Default send buffer size. @@ -293,6 +300,7 @@ public function __construct($socket, $remote_address = '') $this->maxPackageSize = self::$defaultMaxPackageSize; $this->_remoteAddress = $remote_address; static::$connections[$this->id] = $this; + $this->context = new \stdClass; } /** From d4142e716b9203be7d22a55c8aaa874335dd8b7e Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 12 Oct 2022 21:23:48 +0800 Subject: [PATCH 0750/1216] Update Worker.php --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index 1e58357c2..16956f207 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -26,6 +26,7 @@ * Worker class * A container for listening ports */ +#[\AllowDynamicProperties] class Worker { /** From ca1fcff511edbd30cd77467fdcc41a730d3d3a34 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 12 Oct 2022 21:24:14 +0800 Subject: [PATCH 0751/1216] Update ConnectionInterface.php --- src/Connection/ConnectionInterface.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 2295cb17b..2a0c41528 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -17,6 +17,7 @@ /** * ConnectionInterface. */ +#[\AllowDynamicProperties] abstract class ConnectionInterface { /** From a39c6192356461f3aa0244a4d9d4f6b09b9e33fb Mon Sep 17 00:00:00 2001 From: rexpl <75545403+rexpl@users.noreply.github.com> Date: Sat, 15 Oct 2022 19:09:47 +0200 Subject: [PATCH 0752/1216] Verify if host header is set in http1.1 --- src/Protocols/Http.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 57fffe9e3..2730cad2b 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -93,14 +93,21 @@ public static function input(string $recv_buffer, TcpConnection $connection) } $length = $crlf_pos + 4; - $method = \strstr($recv_buffer, ' ', true); + $firstLine = \explode(" ", \strstr($recv_buffer, "\r\n", true), 3); - if (!\in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { + if (!\in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } $header = \substr($recv_buffer, 0, $crlf_pos); + $hostHeaderPosition = \strpos($header, "\r\nHost: "); + + if (false === $hostHeaderPosition && $firstLine[2] !== "HTTP/1.1") { + $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + return 0; + } + if ($pos = \strpos($header, "\r\nContent-Length: ")) { $length = $length + (int)\substr($header, $pos + 18, 10); $has_content_length = true; From 106a98b9080aef6253467a237593daa4976aeafc Mon Sep 17 00:00:00 2001 From: rexpl <75545403+rexpl@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:03:56 +0200 Subject: [PATCH 0753/1216] Fixed "=" --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 2730cad2b..2182b8435 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -103,7 +103,7 @@ public static function input(string $recv_buffer, TcpConnection $connection) $header = \substr($recv_buffer, 0, $crlf_pos); $hostHeaderPosition = \strpos($header, "\r\nHost: "); - if (false === $hostHeaderPosition && $firstLine[2] !== "HTTP/1.1") { + if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } From 5865c8f07657d51fe71de215f1ecf2557caa0382 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 14:28:19 +0200 Subject: [PATCH 0754/1216] Use constants in phrases responses --- src/Protocols/Http/Response.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 69686cc4a..6ce2987b8 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -71,9 +71,9 @@ class Response /** * Phrases. * - * @var array + * @var array */ - protected static $_phrases = [ + const PHRASES = [ 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', @@ -354,7 +354,7 @@ public function cookie($name, $value = '', $max_age = null, $path = '', $domain protected function createHeadForFile($file_info) { $file = $file_info['file']; - $reason = $this->_reason ?: static::$_phrases[$this->_status]; + $reason = $this->_reason ?: static::PHRASES[$this->_status]; $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; $headers = $this->_header; if (!isset($headers['Server'])) { @@ -409,7 +409,7 @@ public function __toString() return $this->createHeadForFile($this->file); } - $reason = $this->_reason ?: static::$_phrases[$this->_status] ?? ''; + $reason = $this->_reason ?: static::PHRASES[$this->_status] ?? ''; $body_len = \strlen($this->_body); if (empty($this->_header)) { return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; From d90465cd13c2f0dfb9e8a239d9f03a66624bf1ca Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 14:33:35 +0200 Subject: [PATCH 0755/1216] Now we can use self, it's faster than static --- src/Protocols/Http/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 6ce2987b8..8681ede7a 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -354,7 +354,7 @@ public function cookie($name, $value = '', $max_age = null, $path = '', $domain protected function createHeadForFile($file_info) { $file = $file_info['file']; - $reason = $this->_reason ?: static::PHRASES[$this->_status]; + $reason = $this->_reason ?: self::PHRASES[$this->_status]; $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; $headers = $this->_header; if (!isset($headers['Server'])) { @@ -409,7 +409,7 @@ public function __toString() return $this->createHeadForFile($this->file); } - $reason = $this->_reason ?: static::PHRASES[$this->_status] ?? ''; + $reason = $this->_reason ?: self::PHRASES[$this->_status] ?? ''; $body_len = \strlen($this->_body); if (empty($this->_header)) { return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; From 5043f9f4875509b696768b9fd712854e42670fe1 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 14:37:31 +0200 Subject: [PATCH 0756/1216] Updated codes and with more info https://en.wikipedia.org/wiki/List_of_HTTP_status_codes --- src/Protocols/Http/Response.php | 75 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 8681ede7a..be88f5287 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -76,62 +76,71 @@ class Response const PHRASES = [ 100 => 'Continue', 101 => 'Switching Protocols', - 102 => 'Processing', + 102 => 'Processing', // WebDAV; RFC 2518 + 103 => 'Early Hints', // RFC 8297 + 200 => 'OK', 201 => 'Created', 202 => 'Accepted', - 203 => 'Non-Authoritative Information', + 203 => 'Non-Authoritative Information', // since HTTP/1.1 204 => 'No Content', 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-status', - 208 => 'Already Reported', + 206 => 'Partial Content', // RFC 7233 + 207 => 'Multi-Status', // WebDAV; RFC 4918 + 208 => 'Already Reported', // WebDAV; RFC 5842 + 226 => 'IM Used', // RFC 3229 + 300 => 'Multiple Choices', 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', + 302 => 'Found', // Previously "Moved temporarily" + 303 => 'See Other', // since HTTP/1.1 + 304 => 'Not Modified', // RFC 7232 + 305 => 'Use Proxy', // since HTTP/1.1 306 => 'Switch Proxy', - 307 => 'Temporary Redirect', + 307 => 'Temporary Redirect', // since HTTP/1.1 + 308 => 'Permanent Redirect', // RFC 7538 + 400 => 'Bad Request', - 401 => 'Unauthorized', + 401 => 'Unauthorized', // RFC 7235 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Time-out', + 407 => 'Proxy Authentication Required', // RFC 7235 + 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', - 415 => 'Unsupported Media Type', - 416 => 'Requested range not satisfiable', + 412 => 'Precondition Failed', // RFC 7232 + 413 => 'Payload Too Large', // RFC 7231 + 414 => 'URI Too Long', // RFC 7231 + 415 => 'Unsupported Media Type', // RFC 7231 + 416 => 'Range Not Satisfiable', // RFC 7233 417 => 'Expectation Failed', - 418 => 'I\'m a teapot', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 424 => 'Failed Dependency', - 425 => 'Unordered Collection', + 418 => 'I\'m a teapot', // RFC 2324, RFC 7168 + 421 => 'Misdirected Request', // RFC 7540 + 422 => 'Unprocessable Entity', // WebDAV; RFC 4918 + 423 => 'Locked', // WebDAV; RFC 4918 + 424 => 'Failed Dependency', // WebDAV; RFC 4918 + 425 => 'Too Early', // RFC 8470 426 => 'Upgrade Required', - 428 => 'Precondition Required', - 429 => 'Too Many Requests', - 431 => 'Request Header Fields Too Large', - 451 => 'Unavailable For Legal Reasons', + 428 => 'Precondition Required', // RFC 6585 + 429 => 'Too Many Requests', // RFC 6585 + 431 => 'Request Header Fields Too Large', // RFC 6585 + 451 => 'Unavailable For Legal Reasons', // RFC 7725 + 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', - 504 => 'Gateway Time-out', - 505 => 'HTTP Version not supported', - 506 => 'Variant Also Negotiates', - 507 => 'Insufficient Storage', - 508 => 'Loop Detected', - 511 => 'Network Authentication Required', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', // RFC 2295 + 507 => 'Insufficient Storage', // WebDAV; RFC 4918 + 508 => 'Loop Detected', // WebDAV; RFC 5842 + 510 => 'Not Extended', // RFC 2774 + 511 => 'Network Authentication Required', // RFC 6585 ]; /** From 9451981b9f856661f3d7b59db8f82fe9146d6de7 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 15:03:22 +0200 Subject: [PATCH 0757/1216] Add @link to wikipedia --- src/Protocols/Http/Response.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index be88f5287..1d47cefad 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -72,6 +72,8 @@ class Response * Phrases. * * @var array + * + * @link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ const PHRASES = [ 100 => 'Continue', From a1891de40e4e1556371d73636484d625f9bd4468 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 16:30:00 +0200 Subject: [PATCH 0758/1216] Use constant for error type --- src/Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 16956f207..d53c618b3 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -491,9 +491,9 @@ class Worker /** * PHP built-in error types. * - * @var array + * @var array */ - protected static $_errorType = [ + const ERROR_TYPE = [ \E_ERROR => 'E_ERROR', // 1 \E_WARNING => 'E_WARNING', // 2 \E_PARSE => 'E_PARSE', // 4 @@ -2076,8 +2076,8 @@ public static function checkErrors() */ protected static function getErrorType($type) { - if(isset(self::$_errorType[$type])) { - return self::$_errorType[$type]; + if(isset(self::ERROR_TYPE[$type])) { + return self::ERROR_TYPE[$type]; } return ''; From f921d3d01e72a1ad35f9dac0a72760bc15949b64 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 16:32:20 +0200 Subject: [PATCH 0759/1216] Use Null Coalesce Operator --- src/Worker.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index d53c618b3..2171fb1d1 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2076,11 +2076,8 @@ public static function checkErrors() */ protected static function getErrorType($type) { - if(isset(self::ERROR_TYPE[$type])) { - return self::ERROR_TYPE[$type]; - } - return ''; + return self::ERROR_TYPE[$type] ?? ''; } /** From efeaa77dabe71cac49d4b298243070f9495df2b6 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 17:07:00 +0200 Subject: [PATCH 0760/1216] Use constant for built in transports --- src/Worker.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 16956f207..b75589257 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -479,9 +479,9 @@ class Worker /** * PHP built-in protocols. * - * @var array + * @var array */ - protected static $_builtinTransports = [ + const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', @@ -2249,7 +2249,7 @@ public function listen() } // Try to open keepalive for tcp and disable Nagle algorithm. - if (\function_exists('socket_import_stream') && static::$_builtinTransports[$this->transport] === 'tcp') { + if (\function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { \set_error_handler(function(){}); $socket = \socket_import_stream($this->_mainSocket); \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); @@ -2291,7 +2291,7 @@ protected function parseSocketAddress() { // Get the application layer communication protocol and listening address. list($scheme, $address) = \explode(':', $this->_socketName, 2); // Check application layer protocol class. - if (!isset(static::$_builtinTransports[$scheme])) { + if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { $scheme = \ucfirst($scheme); $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : 'Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { @@ -2301,7 +2301,7 @@ protected function parseSocketAddress() { } } - if (!isset(static::$_builtinTransports[$this->transport])) { + if (!isset(self::BUILD_IN_TRANSPORTS[$this->transport])) { throw new Exception('Bad worker->transport ' . \var_export($this->transport, true)); } } else { @@ -2310,7 +2310,7 @@ protected function parseSocketAddress() { } } //local socket - return static::$_builtinTransports[$this->transport] . ":" . $address; + return self::BUILD_IN_TRANSPORTS[$this->transport] . ":" . $address; } /** From 60bf9aa0a122cccd15affb6c844168f694c337ea Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 17:13:50 +0200 Subject: [PATCH 0761/1216] Use constant in async tcp connection transports --- src/Connection/AsyncTcpConnection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index d8f42e512..ea26ef5eb 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -91,9 +91,9 @@ class AsyncTcpConnection extends TcpConnection /** * PHP built-in protocols. * - * @var array + * @var array */ - protected static $_builtinTransports = [ + const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', @@ -147,7 +147,7 @@ public function __construct($remote_address, array $context_option = []) self::$_idRecorder = 0; } // Check application layer protocol class. - if (!isset(self::$_builtinTransports[$scheme])) { + if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { $scheme = \ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { @@ -157,7 +157,7 @@ public function __construct($remote_address, array $context_option = []) } } } else { - $this->transport = self::$_builtinTransports[$scheme]; + $this->transport = self::BUILD_IN_TRANSPORTS[$scheme]; } // For statistics. From c86fc33fe01cdfa8064e6495bfa06137465aabb4 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 19:05:44 +0200 Subject: [PATCH 0762/1216] Use Null Coalesce Operator --- src/Connection/AsyncTcpConnection.php | 2 +- src/Protocols/Http/Request.php | 14 +++++++------- src/Protocols/Http/Response.php | 10 ++++------ src/Protocols/Http/Session.php | 2 +- src/Protocols/Websocket.php | 4 ++-- src/Protocols/Ws.php | 3 +-- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index d8f42e512..98c5ea4d0 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -136,7 +136,7 @@ public function __construct($remote_address, array $context_option = []) $this->_remoteHost = $address_info['host']; $this->_remotePort = $address_info['port']; $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; - $scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp'; + $scheme = $address_info['scheme'] ?? 'tcp'; $this->_remoteAddress = 'unix' === strtolower($scheme) ? substr($remote_address, strpos($remote_address, '/') + 2) : $this->_remoteHost . ':' . $this->_remotePort; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 9509b5f07..fa67753b3 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -98,7 +98,7 @@ public function get($name = null, $default = null) if (null === $name) { return $this->_data['get']; } - return isset($this->_data['get'][$name]) ? $this->_data['get'][$name] : $default; + return $this->_data['get'][$name] ?? $default; } /** @@ -116,7 +116,7 @@ public function post($name = null, $default = null) if (null === $name) { return $this->_data['post']; } - return isset($this->_data['post'][$name]) ? $this->_data['post'][$name] : $default; + return $this->_data['post'][$name] ?? $default; } /** @@ -135,7 +135,7 @@ public function header($name = null, $default = null) return $this->_data['headers']; } $name = \strtolower($name); - return isset($this->_data['headers'][$name]) ? $this->_data['headers'][$name] : $default; + return $this->_data['headers'][$name] ?? $default; } /** @@ -154,7 +154,7 @@ public function cookie($name = null, $default = null) if ($name === null) { return $this->_data['cookie']; } - return isset($this->_data['cookie'][$name]) ? $this->_data['cookie'][$name] : $default; + return $this->_data['cookie'][$name] ?? $default; } /** @@ -171,7 +171,7 @@ public function file($name = null) if (null === $name) { return $this->_data['files']; } - return isset($this->_data['files'][$name]) ? $this->_data['files'][$name] : null; + return $this->_data['files'][$name] ?? null; } /** @@ -372,7 +372,7 @@ protected function parseHeadFirstLine() $first_line = \strstr($this->_buffer, "\r\n", true); $tmp = \explode(' ', $first_line, 3); $this->_data['method'] = $tmp[0]; - $this->_data['uri'] = isset($tmp[1]) ? $tmp[1] : '/'; + $this->_data['uri'] = $tmp[1] ?? '/'; } /** @@ -637,7 +637,7 @@ public function __set($name, $value) */ public function __get($name) { - return isset($this->properties[$name]) ? $this->properties[$name] : null; + return $this->properties[$name] ?? null; } /** diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 69686cc4a..f0e549b90 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -219,10 +219,8 @@ public function withoutHeader($name) */ public function getHeader($name) { - if (!isset($this->_header[$name])) { - return null; - } - return $this->_header[$name]; + + return $this->_header[$name] ?? null; } /** @@ -375,8 +373,8 @@ protected function createHeadForFile($file_info) } $file_info = \pathinfo($file); - $extension = isset($file_info['extension']) ? $file_info['extension'] : ''; - $base_name = isset($file_info['basename']) ? $file_info['basename'] : 'unknown'; + $extension = $file_info['extension'] ?? ''; + $base_name = $file_info['basename'] ?? 'unknown'; if (!isset($headers['Content-Type'])) { if (isset(self::$_mimeTypeMap[$extension])) { $head .= "Content-Type: " . self::$_mimeTypeMap[$extension] . "\r\n"; diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 113e78ce8..24ca56a59 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -171,7 +171,7 @@ public function getId() */ public function get($name, $default = null) { - return isset($this->_data[$name]) ? $this->_data[$name] : $default; + return $this->_data[$name] ?? $default; } /** diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 4e3402c8e..3e33d9d0d 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -150,7 +150,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($recv_len >= $current_frame_length) { $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $tmp_connection_type = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; $ping_cb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false; if ($ping_cb) { @@ -172,7 +172,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($recv_len >= $current_frame_length) { $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $tmp_connection_type = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. $pong_cb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false; diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 158765769..d1be0b884 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -347,8 +347,7 @@ public static function sendHandshake(TcpConnection $connection) $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->websocketSecKey = \base64_encode(random_bytes(16)); - $user_header = isset($connection->headers) ? $connection->headers : - (isset($connection->wsHttpHeader) ? $connection->wsHttpHeader : null); + $user_header = $connection->headers ?? $connection->wsHttpHeader ?? null; $user_header_str = ''; if (!empty($user_header)) { if (\is_array($user_header)) { From f2ed06c50a186836c5f9d6dfff5fedb44b9f17a7 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 19 Oct 2022 20:47:30 +0200 Subject: [PATCH 0763/1216] Change phrase to 413 status code --- src/Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 57fffe9e3..ce5c3948b 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -86,7 +86,7 @@ public static function input(string $recv_buffer, TcpConnection $connection) if (false === $crlf_pos) { // Judge whether the package length exceeds the limit. if (\strlen($recv_buffer) >= 16384) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); + $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } return 0; @@ -117,7 +117,7 @@ public static function input(string $recv_buffer, TcpConnection $connection) if ($has_content_length) { if ($length > $connection->maxPackageSize) { - $connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true); + $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } } From 0dd6d5406d803c2445137ad9ed6b8a21faad54e9 Mon Sep 17 00:00:00 2001 From: tianyiw Date: Sun, 30 Oct 2022 16:04:40 +0800 Subject: [PATCH 0764/1216] Fixed: Worker::getAllWorkers() >> @return Worker[] --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 2bfbc8503..0dcc2eaec 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -713,7 +713,7 @@ public static function reloadAllWorkers() /** * Get all worker instances. * - * @return array + * @return Worker[] */ public static function getAllWorkers() { From 7d79d55a70d2688bd5b66f939e87ff0093219244 Mon Sep 17 00:00:00 2001 From: tianyiw Date: Tue, 1 Nov 2022 21:47:43 +0800 Subject: [PATCH 0765/1216] `@var object|null` public $context; `$this->context = new \stdClass;` --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f90e33af7..67ec14bb7 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -161,7 +161,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable /** * Context. * - * @var array + * @var object|null */ public $context = null; From 97c3d43ff0327e4f1636bccf65d0c07d3bb947c7 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 4 Nov 2022 14:18:55 +0800 Subject: [PATCH 0766/1216] Update Timer.php --- src/Timer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index bdefedac2..7c1d55012 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -218,7 +218,9 @@ public static function del($timer_id) public static function delAll() { self::$_tasks = self::$_status = []; - \pcntl_alarm(0); + if (\function_exists('pcntl_alarm')) { + \pcntl_alarm(0); + } if (self::$_event) { self::$_event->deleteAllTimer(); } From e965791e219941d0b68a20c351b59dce61552922 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Nov 2022 14:41:05 +0800 Subject: [PATCH 0767/1216] support php 7.0 --- src/Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index fa67753b3..69aabc985 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -554,7 +554,7 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco if (!\strpos($content_line, ': ')) { return 0; } - [$key, $value] = \explode(': ', $content_line); + list($key, $value) = \explode(': ', $content_line); switch (strtolower($key)) { case "content-disposition": // Is file data. @@ -580,7 +580,7 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco 'tmp_name' => $tmp_file, 'size' => $size, 'error' => $error, - 'type' => null, + 'type' => '', ]; break; } // Is post field. From 623e600f9f66114d2594bd7df50701cd2ef290fd Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 9 Dec 2022 19:23:48 +0800 Subject: [PATCH 0768/1216] fix typo #854 --- src/Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 0dcc2eaec..963438379 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1166,7 +1166,7 @@ public static function signalHandler($signal) case \SIGINT: case \SIGTERM: case \SIGHUP: - case \SIGTSTP; + case \SIGTSTP: static::$_gracefulStop = false; static::stopAll(); break; @@ -1556,7 +1556,7 @@ public function setUserAndGroup() // Get uid. $user_info = \posix_getpwnam($this->user); if (!$user_info) { - static::log("Warning: User {$this->user} not exsits"); + static::log("Warning: User {$this->user} not exists"); return; } $uid = $user_info['uid']; @@ -1564,7 +1564,7 @@ public function setUserAndGroup() if ($this->group) { $group_info = \posix_getgrnam($this->group); if (!$group_info) { - static::log("Warning: Group {$this->group} not exsits"); + static::log("Warning: Group {$this->group} not exists"); return; } $gid = $group_info['gid']; From 0804734f08c99a6f33fcd048c1983392e0ef1d4d Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 13 Dec 2022 17:08:54 +0800 Subject: [PATCH 0769/1216] check posix_isatty callable --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 963438379..2a82f4bd2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1254,7 +1254,7 @@ public static function resetStd(bool $throw_exception = true) $STDOUT = \fopen(static::$stdoutFile, "a"); $STDERR = \fopen(static::$stdoutFile, "a"); // Fix standard output cannot redirect of PHP 8.1.8's bug - if (\posix_isatty(2)) { + if (\function_exists('posix_isatty') && \posix_isatty(2)) { \ob_start(function ($string) { \file_put_contents(static::$stdoutFile, $string, FILE_APPEND); }, 1); From 136c50ade96431c9310aaa46f024a71c65878ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=A3=E8=A8=80=E5=B0=B1=E6=98=AFSiam?= <59419979@qq.com> Date: Tue, 3 Jan 2023 15:52:52 +0800 Subject: [PATCH 0770/1216] Swow Event --- src/Events/Swow.php | 320 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 src/Events/Swow.php diff --git a/src/Events/Swow.php b/src/Events/Swow.php new file mode 100644 index 000000000..7628113f6 --- /dev/null +++ b/src/Events/Swow.php @@ -0,0 +1,320 @@ + + */ + protected $_readEvents = []; + + /** + * All listeners for write event. + * @var array + */ + protected $_writeEvents = []; + + /** + * All listeners for signal. + * @var array + */ + protected $_signalListener = []; + + /** + * Get timer count. + * + * @return integer + */ + public function getTimerCount() + { + return \count($this->_eventTimer); + } + + /** + * {@inheritdoc} + */ + public function delay(float $delay, $func, $args) + { + $t = (int) ($delay * 1000); + $t = max($t, 1); + $coroutine = Coroutine::run(function () use ($t, $func, $args): void { + msleep($t); + unset($this->_eventTimer[Coroutine::getCurrent()->getId()]); + try { + $func(...(array) $args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + }); + $timer_id = $coroutine->getId(); + $this->_eventTimer[$timer_id] = $timer_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function repeat(float $interval, $func, $args) + { + $t = (int) ($interval * 1000); + $t = max($t, 1); + $coroutine = Coroutine::run(static function () use ($t, $func, $args): void { + while (true) { + msleep($t); + try { + $func(...(array) $args); + } catch (\Throwable $e) { + Worker::stopAll(250, $e); + } + } + }); + $timer_id = $coroutine->getId(); + $this->_eventTimer[$timer_id] = $timer_id; + return $timer_id; + } + + /** + * {@inheritdoc} + */ + public function deleteTimer($timer_id) + { + if (isset($this->_eventTimer[$timer_id])) { + try { + (Coroutine::getAll()[$timer_id])->kill(); + return true; + } finally { + unset($this->_eventTimer[$timer_id]); + } + } + return false; + } + + /** + * {@inheritdoc} + */ + public function deleteAllTimer() + { + foreach ($this->_eventTimer as $timer_id) { + $this->deleteTimer($timer_id); + } + } + + /** + * {@inheritdoc} + */ + public function onReadable($stream, $func) + { + if (isset($this->_readEvents[(int) $stream])) { + $this->offReadable($stream); + } + $this->_readEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + try { + while (true) { + $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP); + if ($rEvent !== STREAM_POLLNONE) { + $func($stream); + } + if ($rEvent !== STREAM_POLLIN) { + $this->offReadable($stream, bySelf: true); + break; + } + } + } catch (RuntimeException) { + $this->offReadable($stream, bySelf: true); + } + }); + return true; + } + + /** + * {@inheritdoc} + */ + public function offReadable($stream, bool $bySelf = false) + { + $fd = (int) $stream; + if (!isset($this->_readEvents[$fd])) { + return; + } + if (!$bySelf) { + $coroutine = $this->_readEvents[$fd]; + if (!$coroutine->isExecuting()) { + return; + } + $coroutine->kill(); + } + unset($this->_readEvents[$fd]); + } + + /** + * {@inheritdoc} + */ + public function onWritable($stream, $func) + { + if (isset($this->_writeEvents[(int) $stream])) { + $this->offWritable($stream); + } + $this->_writeEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + try { + while (true) { + $rEvent = stream_poll_one($stream, STREAM_POLLOUT | STREAM_POLLHUP); + if ($rEvent !== STREAM_POLLNONE) { + $func($stream); + } + if ($rEvent !== STREAM_POLLOUT) { + $this->offWritable($stream, bySelf: true); + break; + } + } + } catch (RuntimeException) { + $this->offWritable($stream, bySelf: true); + } + }); + return true; + } + + /** + * {@inheritdoc} + */ + public function offWritable($stream, bool $bySelf = false) + { + $fd = (int) $stream; + if (!isset($this->_writeEvents[$fd])) { + return; + } + if (!$bySelf) { + $coroutine = $this->_writeEvents[$fd]; + if (!$coroutine->isExecuting()) { + return; + } + $coroutine->kill(); + } + unset($this->_writeEvents[$fd]); + } + + /** + * {@inheritdoc} + */ + public function onSignal($signal, $func) + { + if (isset($this->_signalListener[$signal])) { + return false; + } + $coroutine = Coroutine::run(static function () use ($signal, $func): void { + try { + Signal::wait($signal); + $func($signal); + } catch (SignalException) { + } + }); + $this->_signalListener[$signal] = $coroutine; + return true; + } + + /** + * {@inheritdoc} + */ + public function offSignal($signal) + { + if (!isset($this->_signalListener[$signal])) { + return false; + } + $this->_signalListener[$signal]->kill(); + unset($this->_signalListener[$signal]); + return true; + } + + /** + * {@inheritdoc} + */ + public function run() + { + waitAll(); + } + + /** + * Destroy loop. + * + * @return void + */ + public function stop() + { + Coroutine::getMain()->kill(); + Signal::kill(getmypid(), Signal::INT); + } + + public function destroy() + { + $this->stop(); + } + + public function add($fd, $flag, $func, $args = []) + { + switch ($flag) { + case self::EV_SIGNAL: + return $this->onSignal($fd, $func); + case self::EV_TIMER: + case self::EV_TIMER_ONCE: + $method = self::EV_TIMER === $flag ? 'tick' : 'after'; + if ($method === 'tick') { + return $this->repeat($fd, $func, $args); + } else { + return $this->delay($fd, $func, $args); + } + case self::EV_READ: + return $this->onReadable($fd, $func); + case self::EV_WRITE: + return $this->onWritable($fd, $func); + } + } + + public function del($fd, $flag) + { + switch ($flag) { + case self::EV_SIGNAL: + return $this->offSignal($fd); + case self::EV_TIMER: + case self::EV_TIMER_ONCE: + return $this->deleteTimer($fd); + case self::EV_READ: + case self::EV_WRITE: + if ($flag === self::EV_READ) { + $this->offReadable($fd); + } else { + $this->offWritable($fd); + } + } + } + + public function clearAllTimer() + { + $this->deleteAllTimer(); + } + + public function loop() + { + waitAll(); + } +} \ No newline at end of file From 9f0e17ad7ca4c82e35dc36c09929e61eaca06b0e Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 6 Jan 2023 10:23:12 +0800 Subject: [PATCH 0771/1216] Update Worker.php --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index 2a82f4bd2..f59d44c0d 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1503,6 +1503,7 @@ protected static function forkOneWorkerForLinux(self $worker) elseif (0 === $pid) { \srand(); \mt_srand(); + static::$_gracefulStop = false; if ($worker->reusePort) { $worker->listen(); } From 887f0cdc9758d0ed0573f099a9fae2dc2622b660 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Jan 2023 22:16:45 +0800 Subject: [PATCH 0772/1216] Update Worker.php --- src/Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index f59d44c0d..f6101e1db 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1815,7 +1815,8 @@ public static function stopAll($code = 0, $log = '') $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. $sig = static::$_gracefulStop ? \SIGQUIT : \SIGINT; - + // Fix exit with status 2 + usleep(50000); foreach ($worker_pid_array as $worker_pid) { \posix_kill($worker_pid, $sig); if(!static::$_gracefulStop){ From 62ef49ddf0ad08f6b9eafcf1d292ee95d6161db5 Mon Sep 17 00:00:00 2001 From: landso Date: Mon, 9 Jan 2023 06:40:43 +0000 Subject: [PATCH 0773/1216] Fix connection closed before file send completed --- src/Connection/TcpConnection.php | 3 +++ src/Protocols/Http.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 67ec14bb7..5c49a981e 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -723,6 +723,9 @@ public function baseWrite() } } if ($this->_status === self::STATUS_CLOSING) { + if ($this->__streamSending) { + return true; + } $this->destroy(); } return true; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 5123c25cf..043e70e08 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -249,6 +249,7 @@ public static function encode($response, TcpConnection $connection) protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) { $connection->bufferFull = false; + $connection->__streamSending = true; if ($offset !== 0) { \fseek($handler, $offset); } @@ -275,6 +276,7 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse if ($buffer === '' || $buffer === false) { fclose($handler); $connection->onBufferDrain = null; + $connection->__streamSending = false; return; } $connection->send($buffer, true); From 956a5d89b5740b8b4e16dff57f24ee46f5a5ecf2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Jan 2023 17:21:45 +0800 Subject: [PATCH 0774/1216] format --- src/Connection/TcpConnection.php | 2 +- src/Protocols/Http.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 5c49a981e..f125d84b4 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -723,7 +723,7 @@ public function baseWrite() } } if ($this->_status === self::STATUS_CLOSING) { - if ($this->__streamSending) { + if ($this->context->streamSending) { return true; } $this->destroy(); diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 043e70e08..af7ce2e48 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -249,7 +249,7 @@ public static function encode($response, TcpConnection $connection) protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) { $connection->bufferFull = false; - $connection->__streamSending = true; + $connection->context->streamSending = true; if ($offset !== 0) { \fseek($handler, $offset); } @@ -276,7 +276,7 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse if ($buffer === '' || $buffer === false) { fclose($handler); $connection->onBufferDrain = null; - $connection->__streamSending = false; + $connection->context->streamSending = false; return; } $connection->send($buffer, true); From f4dc20104b08333f2616f96d08485f365681c2d8 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Jan 2023 14:16:30 +0800 Subject: [PATCH 0775/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index f6101e1db..f93090370 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -546,8 +546,8 @@ public static function runAll() { static::checkSapiEnv(); static::init(); - static::lock(); static::parseCommand(); + static::lock(); static::daemonize(); static::initWorkers(); static::installSignal(); From 71e6177b40534d23e672565236c1ca3aceb6fc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=A3=E8=A8=80=E5=B0=B1=E6=98=AFSiam?= <59419979@qq.com> Date: Fri, 13 Jan 2023 15:01:24 +0800 Subject: [PATCH 0776/1216] Set ext-swow conflict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit swow预览版本没有Event驱动中所需的特性函数 --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 59ac279bf..7b21da910 100644 --- a/composer.json +++ b/composer.json @@ -34,5 +34,8 @@ "Workerman\\": "src" } }, - "minimum-stability": "dev" + "minimum-stability": "dev", + "conflict": { + "ext-swow": " Date: Mon, 16 Jan 2023 17:06:07 +0800 Subject: [PATCH 0777/1216] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 07e40c2fa..093df03cb 100644 --- a/README.md +++ b/README.md @@ -398,9 +398,7 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= ## Other links with workerman [webman](https://github.com/walkor/webman) -[PHPSocket.IO](https://github.com/walkor/phpsocket.io) -[php-socks5](https://github.com/walkor/php-socks5) -[php-http-proxy](https://github.com/walkor/php-http-proxy) +[AdapterMan](https://github.com/joanhey/AdapterMan) ## Donate From 7268ae91cf9d0c5eb45e8983437e90d899a38ebd Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 18:34:42 +0800 Subject: [PATCH 0778/1216] _id => realId --- src/Connection/AsyncTcpConnection.php | 6 +++--- src/Connection/TcpConnection.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 4f099320d..9c49b4fca 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -156,7 +156,7 @@ public function __construct($remote_address, array $context_option = []) : $this->_remoteHost . ':' . $this->_remotePort; } - $this->id = $this->_id = self::$_idRecorder++; + $this->id = $this->realId = self::$_idRecorder++; if (\PHP_INT_MAX === self::$_idRecorder) { self::$_idRecorder = 0; } @@ -179,7 +179,7 @@ public function __construct($remote_address, array $context_option = []) $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; $this->_contextOption = $context_option; - static::$connections[$this->_id] = $this; + static::$connections[$this->realId] = $this; } /** @@ -259,7 +259,7 @@ public function connect() public function reconnect($after = 0) { $this->_status = self::STATUS_INITIAL; - static::$connections[$this->_id] = $this; + static::$connections[$this->realId] = $this; if ($this->_reconnectTimer) { Timer::del($this->_reconnectTimer); } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f125d84b4..6c6ce8e4e 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -285,7 +285,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; - $this->id = $this->_id = self::$_idRecorder++; + $this->id = $this->realId = self::$_idRecorder++; if (self::$_idRecorder === \PHP_INT_MAX) { self::$_idRecorder = 0; } @@ -965,9 +965,9 @@ public function destroy() $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; // Remove from worker->connections. if ($this->worker) { - unset($this->worker->connections[$this->_id]); + unset($this->worker->connections[$this->realId]); } - unset(static::$connections[$this->_id]); + unset(static::$connections[$this->realId]); } } From 7cf8b19c2d3622bc7cd525212a584fe0edb818ec Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 18:44:22 +0800 Subject: [PATCH 0779/1216] Remove prefix of protection properties --- src/Connection/AsyncTcpConnection.php | 152 +++---- src/Connection/AsyncUdpConnection.php | 26 +- src/Connection/TcpConnection.php | 206 ++++----- src/Connection/UdpConnection.php | 24 +- src/Events/Ev.php | 58 +-- src/Events/Event.php | 86 ++-- src/Events/Revolt.php | 94 ++--- src/Events/Select.php | 142 +++---- src/Events/Swoole.php | 36 +- src/Events/Swow.php | 52 +-- src/Protocols/Http.php | 50 +-- src/Protocols/Http/Chunk.php | 6 +- src/Protocols/Http/Request.php | 156 +++---- src/Protocols/Http/Response.php | 76 ++-- src/Protocols/Http/ServerSentEvents.php | 6 +- src/Protocols/Http/Session.php | 76 ++-- .../Http/Session/FileSessionHandler.php | 12 +- .../Session/RedisClusterSessionHandler.php | 6 +- .../Http/Session/RedisSessionHandler.php | 30 +- .../Http/Session/SessionHandlerInterface.php | 2 +- src/Timer.php | 58 +-- src/Worker.php | 396 +++++++++--------- 22 files changed, 875 insertions(+), 875 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 9c49b4fca..df800d3e3 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -57,49 +57,49 @@ class AsyncTcpConnection extends TcpConnection * * @var int */ - protected $_status = self::STATUS_INITIAL; + protected $status = self::STATUS_INITIAL; /** * Remote host. * * @var string */ - protected $_remoteHost = ''; + protected $remoteHost = ''; /** * Remote port. * * @var int */ - protected $_remotePort = 80; + protected $remotePort = 80; /** * Connect start time. * * @var float */ - protected $_connectStartTime = 0; + protected $connectStartTime = 0; /** * Remote URI. * * @var string */ - protected $_remoteURI = ''; + protected $remoteURI = ''; /** * Context option. * * @var array */ - protected $_contextOption = null; + protected $contextOption = null; /** * Reconnect timer. * * @var int */ - protected $_reconnectTimer = null; + protected $reconnectTimer = null; /** @@ -128,11 +128,11 @@ public function __construct($remote_address, array $context_option = []) { $address_info = \parse_url($remote_address); if (!$address_info) { - list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2); + list($scheme, $this->remoteAddress) = \explode(':', $remote_address, 2); if ('unix' === strtolower($scheme)) { - $this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); + $this->remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); } - if (!$this->_remoteAddress) { + if (!$this->remoteAddress) { Worker::safeEcho(new \Exception('bad remote_address')); } } else { @@ -147,18 +147,18 @@ public function __construct($remote_address, array $context_option = []) } else { $address_info['query'] = '?' . $address_info['query']; } - $this->_remoteHost = $address_info['host']; - $this->_remotePort = $address_info['port']; - $this->_remoteURI = "{$address_info['path']}{$address_info['query']}"; + $this->remoteHost = $address_info['host']; + $this->remotePort = $address_info['port']; + $this->remoteURI = "{$address_info['path']}{$address_info['query']}"; $scheme = $address_info['scheme'] ?? 'tcp'; - $this->_remoteAddress = 'unix' === strtolower($scheme) + $this->remoteAddress = 'unix' === strtolower($scheme) ? substr($remote_address, strpos($remote_address, '/') + 2) - : $this->_remoteHost . ':' . $this->_remotePort; + : $this->remoteHost . ':' . $this->remotePort; } - $this->id = $this->realId = self::$_idRecorder++; - if (\PHP_INT_MAX === self::$_idRecorder) { - self::$_idRecorder = 0; + $this->id = $this->realId = self::$idRecorder++; + if (\PHP_INT_MAX === self::$idRecorder) { + self::$idRecorder = 0; } // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { @@ -178,7 +178,7 @@ public function __construct($remote_address, array $context_option = []) ++self::$statistics['connection_count']; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_contextOption = $context_option; + $this->contextOption = $context_option; static::$connections[$this->realId] = $this; } @@ -189,64 +189,64 @@ public function __construct($remote_address, array $context_option = []) */ public function connect() { - if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING && - $this->_status !== self::STATUS_CLOSED) { + if ($this->status !== self::STATUS_INITIAL && $this->status !== self::STATUS_CLOSING && + $this->status !== self::STATUS_CLOSED) { return; } - $this->_status = self::STATUS_CONNECTING; - $this->_connectStartTime = \microtime(true); + $this->status = self::STATUS_CONNECTING; + $this->connectStartTime = \microtime(true); if ($this->transport !== 'unix') { - if (!$this->_remotePort) { - $this->_remotePort = $this->transport === 'ssl' ? 443 : 80; - $this->_remoteAddress = $this->_remoteHost . ':' . $this->_remotePort; + if (!$this->remotePort) { + $this->remotePort = $this->transport === 'ssl' ? 443 : 80; + $this->remoteAddress = $this->remoteHost . ':' . $this->remotePort; } // Open socket connection asynchronously. if ($this->proxySocks5){ - $this->_contextOption['ssl']['peer_name'] = $this->_remoteHost; - $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client("tcp://{$this->proxySocks5}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); - fwrite($this->_socket,chr(5) . chr(1) . chr(0)); - fread($this->_socket, 512); - fwrite($this->_socket,chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->_remoteHost)) . $this->_remoteHost . pack("n", $this->_remotePort)); - fread($this->_socket, 512); + $this->contextOption['ssl']['peer_name'] = $this->remoteHost; + $context = \stream_context_create($this->contextOption); + $this->socket = \stream_socket_client("tcp://{$this->proxySocks5}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + fwrite($this->socket,chr(5) . chr(1) . chr(0)); + fread($this->socket, 512); + fwrite($this->socket,chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); + fread($this->socket, 512); }else if($this->proxyHttp){ - $this->_contextOption['ssl']['peer_name'] = $this->_remoteHost; - $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client("tcp://{$this->proxyHttp}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); - $str = "CONNECT {$this->_remoteHost}:{$this->_remotePort} HTTP/1.1\n"; - $str .= "Host: {$this->_remoteHost}:{$this->_remotePort}\n"; + $this->contextOption['ssl']['peer_name'] = $this->remoteHost; + $context = \stream_context_create($this->contextOption); + $this->socket = \stream_socket_client("tcp://{$this->proxyHttp}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + $str = "CONNECT {$this->remoteHost}:{$this->remotePort} HTTP/1.1\n"; + $str .= "Host: {$this->remoteHost}:{$this->remotePort}\n"; $str .= "Proxy-Connection: keep-alive\n"; - fwrite($this->_socket,$str); - fread($this->_socket, 512); - } else if ($this->_contextOption) { - $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + fwrite($this->socket,$str); + fread($this->socket, 512); + } else if ($this->contextOption) { + $context = \stream_context_create($this->contextOption); + $this->socket = \stream_socket_client("tcp://{$this->remoteHost}:{$this->remotePort}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}", + $this->socket = \stream_socket_client("tcp://{$this->remoteHost}:{$this->remotePort}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT); } } else { - $this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0, + $this->socket = \stream_socket_client("{$this->transport}://{$this->remoteAddress}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. - if (!$this->_socket || !\is_resource($this->_socket)) { + if (!$this->socket || !\is_resource($this->socket)) { $this->emitError(static::CONNECT_FAIL, $errstr); - if ($this->_status === self::STATUS_CLOSING) { + if ($this->status === self::STATUS_CLOSING) { $this->destroy(); } - if ($this->_status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_CLOSED) { $this->onConnect = null; } return; } // Add socket to global event loop waiting connection is successfully established or faild. - Worker::$globalEvent->onWritable($this->_socket, [$this, 'checkConnection']); + Worker::$globalEvent->onWritable($this->socket, [$this, 'checkConnection']); // For windows. if (\DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->onExcept($this->_socket, [$this, 'checkConnection']); + Worker::$globalEvent->onExcept($this->socket, [$this, 'checkConnection']); } } @@ -258,13 +258,13 @@ public function connect() */ public function reconnect($after = 0) { - $this->_status = self::STATUS_INITIAL; + $this->status = self::STATUS_INITIAL; static::$connections[$this->realId] = $this; - if ($this->_reconnectTimer) { - Timer::del($this->_reconnectTimer); + if ($this->reconnectTimer) { + Timer::del($this->reconnectTimer); } if ($after > 0) { - $this->_reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); + $this->reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); return; } $this->connect(); @@ -275,8 +275,8 @@ public function reconnect($after = 0) */ public function cancelReconnect() { - if ($this->_reconnectTimer) { - Timer::del($this->_reconnectTimer); + if ($this->reconnectTimer) { + Timer::del($this->reconnectTimer); } } @@ -287,7 +287,7 @@ public function cancelReconnect() */ public function getRemoteHost() { - return $this->_remoteHost; + return $this->remoteHost; } /** @@ -297,7 +297,7 @@ public function getRemoteHost() */ public function getRemoteURI() { - return $this->_remoteURI; + return $this->remoteURI; } /** @@ -309,7 +309,7 @@ public function getRemoteURI() */ protected function emitError($code, $msg) { - $this->_status = self::STATUS_CLOSING; + $this->status = self::STATUS_CLOSING; if ($this->onError) { try { ($this->onError)($this, $code, $msg); @@ -329,46 +329,46 @@ public function checkConnection() { // Remove EV_EXPECT for windows. if (\DIRECTORY_SEPARATOR === '\\') { - Worker::$globalEvent->offExcept($this->_socket); + Worker::$globalEvent->offExcept($this->socket); } // Remove write listener. - Worker::$globalEvent->offWritable($this->_socket); + Worker::$globalEvent->offWritable($this->socket); - if ($this->_status !== self::STATUS_CONNECTING) { + if ($this->status !== self::STATUS_CONNECTING) { return; } // Check socket state. - if ($address = \stream_socket_get_name($this->_socket, true)) { + if ($address = \stream_socket_get_name($this->socket, true)) { // Nonblocking. - \stream_set_blocking($this->_socket, false); + \stream_set_blocking($this->socket, false); // Compatible with hhvm if (\function_exists('stream_set_read_buffer')) { - \stream_set_read_buffer($this->_socket, 0); + \stream_set_read_buffer($this->socket, 0); } // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && $this->transport === 'tcp') { - $raw_socket = \socket_import_stream($this->_socket); + $raw_socket = \socket_import_stream($this->socket); \socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); \socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1); } // SSL handshake. if ($this->transport === 'ssl') { - $this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket); - if ($this->_sslHandshakeCompleted === false) { + $this->sslHandshakeCompleted = $this->doSslHandshake($this->socket); + if ($this->sslHandshakeCompleted === false) { return; } } else { // There are some data waiting to send. - if ($this->_sendBuffer) { - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); + if ($this->sendBuffer) { + Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); } } // Register a listener waiting read event. - Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); + Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); - $this->_status = self::STATUS_ESTABLISHED; - $this->_remoteAddress = $address; + $this->status = self::STATUS_ESTABLISHED; + $this->remoteAddress = $address; // Try to emit onConnect callback. if ($this->onConnect) { @@ -388,11 +388,11 @@ public function checkConnection() } } else { // Connection failed. - $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds'); - if ($this->_status === self::STATUS_CLOSING) { + $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(\microtime(true) - $this->connectStartTime, 4) . ' seconds'); + if ($this->status === self::STATUS_CLOSING) { $this->destroy(); } - if ($this->_status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_CLOSED) { $this->onConnect = null; } } diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index bf58cfe65..c32fc013c 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -49,7 +49,7 @@ class AsyncUdpConnection extends UdpConnection * * @var array */ - protected $_contextOption = null; + protected $contextOption = null; /** * Construct. @@ -73,8 +73,8 @@ public function __construct($remote_address, $context_option = null) } } - $this->_remoteAddress = \substr($address, 2); - $this->_contextOption = $context_option; + $this->remoteAddress = \substr($address, 2); + $this->contextOption = $context_option; } /** @@ -123,7 +123,7 @@ public function send($send_buffer, $raw = false) if ($this->connected === false) { $this->connect(); } - return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0); + return \strlen($send_buffer) === \stream_socket_sendto($this->socket, $send_buffer, 0); } @@ -140,8 +140,8 @@ public function close($data = null, $raw = false) if ($data !== null) { $this->send($data, $raw); } - Worker::$globalEvent->offReadable($this->_socket); - \fclose($this->_socket); + Worker::$globalEvent->offReadable($this->socket); + \fclose($this->socket); $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { @@ -165,23 +165,23 @@ public function connect() if ($this->connected === true) { return; } - if ($this->_contextOption) { - $context = \stream_context_create($this->_contextOption); - $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg, + if ($this->contextOption) { + $context = \stream_context_create($this->contextOption); + $this->socket = \stream_socket_client("udp://{$this->remoteAddress}", $errno, $errmsg, 30, \STREAM_CLIENT_CONNECT, $context); } else { - $this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg); + $this->socket = \stream_socket_client("udp://{$this->remoteAddress}", $errno, $errmsg); } - if (!$this->_socket) { + if (!$this->socket) { Worker::safeEcho(new \Exception($errmsg)); return; } - \stream_set_blocking($this->_socket, false); + \stream_set_blocking($this->socket, false); if ($this->onMessage) { - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseRead']); + Worker::$globalEvent->onWritable($this->socket, [$this, 'baseRead']); } $this->connected = true; // Try to emit onConnect callback. diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 6c6ce8e4e..ff93829e0 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -148,7 +148,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * * @var int */ - protected $_id = 0; + protected $realId = 0; /** * Sets the maximum send buffer size for the current connection. @@ -191,70 +191,70 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * * @var int */ - protected static $_idRecorder = 1; + protected static $idRecorder = 1; /** * Cache. * * @var bool. */ - protected static $_enableCache = true; + protected static $enableCache = true; /** * Socket * * @var resource */ - protected $_socket = null; + protected $socket = null; /** * Send buffer. * * @var string */ - protected $_sendBuffer = ''; + protected $sendBuffer = ''; /** * Receive buffer. * * @var string */ - protected $_recvBuffer = ''; + protected $recvBuffer = ''; /** * Current package length. * * @var int */ - protected $_currentPackageLength = 0; + protected $currentPackageLength = 0; /** * Connection status. * * @var int */ - protected $_status = self::STATUS_ESTABLISHED; + protected $status = self::STATUS_ESTABLISHED; /** * Remote address. * * @var string */ - protected $_remoteAddress = ''; + protected $remoteAddress = ''; /** * Is paused. * * @var bool */ - protected $_isPaused = false; + protected $isPaused = false; /** * SSL handshake completed or not. * * @var bool */ - protected $_sslHandshakeCompleted = false; + protected $sslHandshakeCompleted = false; /** * All connection instances. @@ -268,7 +268,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * * @var array */ - public static $_statusToString = [ + public static $statusToString = [ self::STATUS_INITIAL => 'INITIAL', self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', @@ -285,20 +285,20 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable public function __construct($socket, $remote_address = '') { ++self::$statistics['connection_count']; - $this->id = $this->realId = self::$_idRecorder++; - if (self::$_idRecorder === \PHP_INT_MAX) { - self::$_idRecorder = 0; + $this->id = $this->realId = self::$idRecorder++; + if (self::$idRecorder === \PHP_INT_MAX) { + self::$idRecorder = 0; } - $this->_socket = $socket; - \stream_set_blocking($this->_socket, 0); + $this->socket = $socket; + \stream_set_blocking($this->socket, 0); // Compatible with hhvm if (\function_exists('stream_set_read_buffer')) { - \stream_set_read_buffer($this->_socket, 0); + \stream_set_read_buffer($this->socket, 0); } - Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); + Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->_remoteAddress = $remote_address; + $this->remoteAddress = $remote_address; static::$connections[$this->id] = $this; $this->context = new \stdClass; } @@ -313,9 +313,9 @@ public function __construct($socket, $remote_address = '') public function getStatus($raw_output = true) { if ($raw_output) { - return $this->_status; + return $this->status; } - return self::$_statusToString[$this->_status]; + return self::$statusToString[$this->status]; } /** @@ -327,7 +327,7 @@ public function getStatus($raw_output = true) */ public function send($send_buffer, $raw = false) { - if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return false; } @@ -339,29 +339,29 @@ public function send($send_buffer, $raw = false) } } - if ($this->_status !== self::STATUS_ESTABLISHED || - ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) + if ($this->status !== self::STATUS_ESTABLISHED || + ($this->transport === 'ssl' && $this->sslHandshakeCompleted !== true) ) { - if ($this->_sendBuffer && $this->bufferIsFull()) { + if ($this->sendBuffer && $this->bufferIsFull()) { ++self::$statistics['send_fail']; return false; } - $this->_sendBuffer .= $send_buffer; + $this->sendBuffer .= $send_buffer; $this->checkBufferWillFull(); return; } // Attempt to send data directly. - if ($this->_sendBuffer === '') { + if ($this->sendBuffer === '') { if ($this->transport === 'ssl') { - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); - $this->_sendBuffer = $send_buffer; + Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); + $this->sendBuffer = $send_buffer; $this->checkBufferWillFull(); return; } $len = 0; try { - $len = @\fwrite($this->_socket, $send_buffer); + $len = @\fwrite($this->socket, $send_buffer); } catch (\Throwable $e) { Worker::log($e); } @@ -372,11 +372,11 @@ public function send($send_buffer, $raw = false) } // Send only part of the data. if ($len > 0) { - $this->_sendBuffer = \substr($send_buffer, $len); + $this->sendBuffer = \substr($send_buffer, $len); $this->bytesWritten += $len; } else { // Connection closed? - if (!\is_resource($this->_socket) || \feof($this->_socket)) { + if (!\is_resource($this->socket) || \feof($this->socket)) { ++self::$statistics['send_fail']; if ($this->onError) { try { @@ -388,9 +388,9 @@ public function send($send_buffer, $raw = false) $this->destroy(); return false; } - $this->_sendBuffer = $send_buffer; + $this->sendBuffer = $send_buffer; } - Worker::$globalEvent->onWritable($this->_socket, [$this, 'baseWrite']); + Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); // Check if the send buffer will be full. $this->checkBufferWillFull(); return; @@ -401,7 +401,7 @@ public function send($send_buffer, $raw = false) return false; } - $this->_sendBuffer .= $send_buffer; + $this->sendBuffer .= $send_buffer; // Check if the send buffer is full. $this->checkBufferWillFull(); } @@ -413,9 +413,9 @@ public function send($send_buffer, $raw = false) */ public function getRemoteIp() { - $pos = \strrpos($this->_remoteAddress, ':'); + $pos = \strrpos($this->remoteAddress, ':'); if ($pos) { - return (string)\substr($this->_remoteAddress, 0, $pos); + return (string)\substr($this->remoteAddress, 0, $pos); } return ''; } @@ -427,8 +427,8 @@ public function getRemoteIp() */ public function getRemotePort() { - if ($this->_remoteAddress) { - return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); + if ($this->remoteAddress) { + return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); } return 0; } @@ -440,7 +440,7 @@ public function getRemotePort() */ public function getRemoteAddress() { - return $this->_remoteAddress; + return $this->remoteAddress; } /** @@ -480,10 +480,10 @@ public function getLocalPort() */ public function getLocalAddress() { - if (!\is_resource($this->_socket)) { + if (!\is_resource($this->socket)) { return ''; } - return (string)@\stream_socket_get_name($this->_socket, false); + return (string)@\stream_socket_get_name($this->socket, false); } /** @@ -493,7 +493,7 @@ public function getLocalAddress() */ public function getSendBufferQueueSize() { - return \strlen($this->_sendBuffer); + return \strlen($this->sendBuffer); } /** @@ -503,7 +503,7 @@ public function getSendBufferQueueSize() */ public function getRecvBufferQueueSize() { - return \strlen($this->_recvBuffer); + return \strlen($this->recvBuffer); } /** @@ -539,8 +539,8 @@ public function isIpV6() */ public function pauseRecv() { - Worker::$globalEvent->offReadable($this->_socket); - $this->_isPaused = true; + Worker::$globalEvent->offReadable($this->socket); + $this->isPaused = true; } /** @@ -550,10 +550,10 @@ public function pauseRecv() */ public function resumeRecv() { - if ($this->_isPaused === true) { - Worker::$globalEvent->onReadable($this->_socket, [$this, 'baseRead']); - $this->_isPaused = false; - $this->baseRead($this->_socket, false); + if ($this->isPaused === true) { + Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); + $this->isPaused = false; + $this->baseRead($this->socket, false); } } @@ -569,10 +569,10 @@ public function baseRead($socket, $check_eof = true) { static $requests = []; // SSL handshake. - if ($this->transport === 'ssl' && $this->_sslHandshakeCompleted !== true) { + if ($this->transport === 'ssl' && $this->sslHandshakeCompleted !== true) { if ($this->doSslHandshake($socket)) { - $this->_sslHandshakeCompleted = true; - if ($this->_sendBuffer) { + $this->sslHandshakeCompleted = true; + if ($this->sendBuffer) { Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']); } } else { @@ -594,15 +594,15 @@ public function baseRead($socket, $check_eof = true) } } else { $this->bytesRead += \strlen($buffer); - if ($this->_recvBuffer === '') { - if (static::$_enableCache && !isset($buffer[512]) && isset($requests[$buffer])) { + if ($this->recvBuffer === '') { + if (static::$enableCache && !isset($buffer[512]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; $request = $requests[$buffer]; if ($request instanceof Request) { $request = clone $request; $requests[$buffer] = $request; $request->connection = $this; - $this->__request = $request; + $this->request = $request; $request->properties = []; } try { @@ -612,38 +612,38 @@ public function baseRead($socket, $check_eof = true) } return; } - $this->_recvBuffer = $buffer; + $this->recvBuffer = $buffer; } else { - $this->_recvBuffer .= $buffer; + $this->recvBuffer .= $buffer; } } // If the application layer protocol has been set up. if ($this->protocol !== null) { - while ($this->_recvBuffer !== '' && !$this->_isPaused) { + while ($this->recvBuffer !== '' && !$this->isPaused) { // The current packet length is known. - if ($this->_currentPackageLength) { + if ($this->currentPackageLength) { // Data is not enough for a package. - if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { + if ($this->currentPackageLength > \strlen($this->recvBuffer)) { break; } } else { // Get current package length. try { - $this->_currentPackageLength = $this->protocol::input($this->_recvBuffer, $this); + $this->currentPackageLength = $this->protocol::input($this->recvBuffer, $this); } catch (\Throwable $e) { } // The packet length is unknown. - if ($this->_currentPackageLength === 0) { + if ($this->currentPackageLength === 0) { break; - } elseif ($this->_currentPackageLength > 0 && $this->_currentPackageLength <= $this->maxPackageSize) { + } elseif ($this->currentPackageLength > 0 && $this->currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. - if ($this->_currentPackageLength > \strlen($this->_recvBuffer)) { + if ($this->currentPackageLength > \strlen($this->recvBuffer)) { break; } } // Wrong package. else { - Worker::safeEcho('Error package. package_length=' . \var_export($this->_currentPackageLength, true)); + Worker::safeEcho('Error package. package_length=' . \var_export($this->currentPackageLength, true)); $this->destroy(); return; } @@ -652,21 +652,21 @@ public function baseRead($socket, $check_eof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if ($one = \strlen($this->_recvBuffer) === $this->_currentPackageLength) { - $one_request_buffer = $this->_recvBuffer; - $this->_recvBuffer = ''; + if ($one = \strlen($this->recvBuffer) === $this->currentPackageLength) { + $one_request_buffer = $this->recvBuffer; + $this->recvBuffer = ''; } else { // Get a full package from the buffer. - $one_request_buffer = \substr($this->_recvBuffer, 0, $this->_currentPackageLength); + $one_request_buffer = \substr($this->recvBuffer, 0, $this->currentPackageLength); // Remove the current package from the receive buffer. - $this->_recvBuffer = \substr($this->_recvBuffer, $this->_currentPackageLength); + $this->recvBuffer = \substr($this->recvBuffer, $this->currentPackageLength); } // Reset the current packet length to 0. - $this->_currentPackageLength = 0; + $this->currentPackageLength = 0; try { // Decode request buffer before Emitting onMessage callback. $request = $this->protocol::decode($one_request_buffer, $this); - if (static::$_enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { + if (static::$enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { $requests[$one_request_buffer] = $request; if (\count($requests) > 512) { unset($requests[\key($requests)]); @@ -680,19 +680,19 @@ public function baseRead($socket, $check_eof = true) return; } - if ($this->_recvBuffer === '' || $this->_isPaused) { + if ($this->recvBuffer === '' || $this->isPaused) { return; } // Applications protocol is not set. ++self::$statistics['total_request']; try { - ($this->onMessage)($this, $this->_recvBuffer); + ($this->onMessage)($this, $this->recvBuffer); } catch (\Throwable $e) { Worker::stopAll(250, $e); } // Clean receive buffer. - $this->_recvBuffer = ''; + $this->recvBuffer = ''; } /** @@ -705,15 +705,15 @@ public function baseWrite() \set_error_handler(function () { }); if ($this->transport === 'ssl') { - $len = @\fwrite($this->_socket, $this->_sendBuffer, 8192); + $len = @\fwrite($this->socket, $this->sendBuffer, 8192); } else { - $len = @\fwrite($this->_socket, $this->_sendBuffer); + $len = @\fwrite($this->socket, $this->sendBuffer); } \restore_error_handler(); - if ($len === \strlen($this->_sendBuffer)) { + if ($len === \strlen($this->sendBuffer)) { $this->bytesWritten += $len; - Worker::$globalEvent->offWritable($this->_socket); - $this->_sendBuffer = ''; + Worker::$globalEvent->offWritable($this->socket); + $this->sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { @@ -722,7 +722,7 @@ public function baseWrite() Worker::stopAll(250, $e); } } - if ($this->_status === self::STATUS_CLOSING) { + if ($this->status === self::STATUS_CLOSING) { if ($this->context->streamSending) { return true; } @@ -732,7 +732,7 @@ public function baseWrite() } if ($len > 0) { $this->bytesWritten += $len; - $this->_sendBuffer = \substr($this->_sendBuffer, $len); + $this->sendBuffer = \substr($this->sendBuffer, $len); } else { ++self::$statistics['send_fail']; $this->destroy(); @@ -826,7 +826,7 @@ public function pipe(self $dest) */ public function consumeRecvBuffer($length) { - $this->_recvBuffer = \substr($this->_recvBuffer, $length); + $this->recvBuffer = \substr($this->recvBuffer, $length); } /** @@ -838,12 +838,12 @@ public function consumeRecvBuffer($length) */ public function close($data = null, $raw = false) { - if ($this->_status === self::STATUS_CONNECTING) { + if ($this->status === self::STATUS_CONNECTING) { $this->destroy(); return; } - if ($this->_status === self::STATUS_CLOSING || $this->_status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return; } @@ -851,9 +851,9 @@ public function close($data = null, $raw = false) $this->send($data, $raw); } - $this->_status = self::STATUS_CLOSING; + $this->status = self::STATUS_CLOSING; - if ($this->_sendBuffer === '') { + if ($this->sendBuffer === '') { $this->destroy(); } else { $this->pauseRecv(); @@ -867,7 +867,7 @@ public function close($data = null, $raw = false) */ public function getSocket() { - return $this->_socket; + return $this->socket; } /** @@ -877,7 +877,7 @@ public function getSocket() */ protected function checkBufferWillFull() { - if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { + if ($this->maxSendBufferSize <= \strlen($this->sendBuffer)) { if ($this->onBufferFull) { try { ($this->onBufferFull)($this); @@ -896,7 +896,7 @@ protected function checkBufferWillFull() protected function bufferIsFull() { // Buffer has been marked as full but still has data to send then the packet is discarded. - if ($this->maxSendBufferSize <= \strlen($this->_sendBuffer)) { + if ($this->maxSendBufferSize <= \strlen($this->sendBuffer)) { if ($this->onError) { try { ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); @@ -916,7 +916,7 @@ protected function bufferIsFull() */ public function bufferIsEmpty() { - return empty($this->_sendBuffer); + return empty($this->sendBuffer); } /** @@ -927,20 +927,20 @@ public function bufferIsEmpty() public function destroy() { // Avoid repeated calls. - if ($this->_status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_CLOSED) { return; } // Remove event listener. - Worker::$globalEvent->offReadable($this->_socket); - Worker::$globalEvent->offWritable($this->_socket); + Worker::$globalEvent->offReadable($this->socket); + Worker::$globalEvent->offWritable($this->socket); // Close socket. try { - @\fclose($this->_socket); + @\fclose($this->socket); } catch (\Throwable $e) { } - $this->_status = self::STATUS_CLOSED; + $this->status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { @@ -957,10 +957,10 @@ public function destroy() Worker::stopAll(250, $e); } } - $this->_sendBuffer = $this->_recvBuffer = ''; - $this->_currentPackageLength = 0; - $this->_isPaused = $this->_sslHandshakeCompleted = false; - if ($this->_status === self::STATUS_CLOSED) { + $this->sendBuffer = $this->recvBuffer = ''; + $this->currentPackageLength = 0; + $this->isPaused = $this->sslHandshakeCompleted = false; + if ($this->status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; // Remove from worker->connections. @@ -978,7 +978,7 @@ public function destroy() */ public static function enableCache($value) { - static::$_enableCache = (bool)$value; + static::$enableCache = (bool)$value; } /** diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index f55149383..3191e589d 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -39,14 +39,14 @@ class UdpConnection extends ConnectionInterface implements \JsonSerializable * * @var resource */ - protected $_socket = null; + protected $socket = null; /** * Remote address. * * @var string */ - protected $_remoteAddress = ''; + protected $remoteAddress = ''; /** * Construct. @@ -56,8 +56,8 @@ class UdpConnection extends ConnectionInterface implements \JsonSerializable */ public function __construct($socket, $remote_address) { - $this->_socket = $socket; - $this->_remoteAddress = $remote_address; + $this->socket = $socket; + $this->remoteAddress = $remote_address; } /** @@ -76,7 +76,7 @@ public function send($send_buffer, $raw = false) return; } } - return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->_remoteAddress); + return \strlen($send_buffer) === \stream_socket_sendto($this->socket, $send_buffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); } /** @@ -86,9 +86,9 @@ public function send($send_buffer, $raw = false) */ public function getRemoteIp() { - $pos = \strrpos($this->_remoteAddress, ':'); + $pos = \strrpos($this->remoteAddress, ':'); if ($pos) { - return \trim(\substr($this->_remoteAddress, 0, $pos), '[]'); + return \trim(\substr($this->remoteAddress, 0, $pos), '[]'); } return ''; } @@ -100,8 +100,8 @@ public function getRemoteIp() */ public function getRemotePort() { - if ($this->_remoteAddress) { - return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1); + if ($this->remoteAddress) { + return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); } return 0; } @@ -113,7 +113,7 @@ public function getRemotePort() */ public function getRemoteAddress() { - return $this->_remoteAddress; + return $this->remoteAddress; } /** @@ -153,7 +153,7 @@ public function getLocalPort() */ public function getLocalAddress() { - return (string)@\stream_socket_get_name($this->_socket, false); + return (string)@\stream_socket_get_name($this->socket, false); } /** @@ -204,7 +204,7 @@ public function close($data = null, $raw = false) */ public function getSocket() { - return $this->_socket; + return $this->socket; } /** diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 2050fc5fc..8fc99e762 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -26,48 +26,48 @@ class Ev implements EventInterface * * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for write event. * * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * Event listeners of signal. * * @var array */ - protected $_eventSignal = []; + protected $eventSignal = []; /** * All timer event listeners. * * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * Timer id. * * @var int */ - protected static $_timerId = 1; + protected static $timerId = 1; /** * {@inheritdoc} */ public function delay(float $delay, $func, $args) { - $timer_id = self::$_timerId; + $timer_id = self::$timerId; $event = new \EvTimer($delay, 0, function () use ($func, $args, $timer_id) { - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); $func(...(array)$args); }); - $this->_eventTimer[self::$_timerId] = $event; - return self::$_timerId++; + $this->eventTimer[self::$timerId] = $event; + return self::$timerId++; } /** @@ -75,9 +75,9 @@ public function delay(float $delay, $func, $args) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { - $this->_eventTimer[$timer_id]->stop(); - unset($this->_eventTimer[$timer_id]); + if (isset($this->eventTimer[$timer_id])) { + $this->eventTimer[$timer_id]->stop(); + unset($this->eventTimer[$timer_id]); return true; } return false; @@ -91,8 +91,8 @@ public function repeat(float $interval, $func, $args) $event = new \EvTimer($interval, $interval, function () use ($func, $args) { $func(...(array)$args); }); - $this->_eventTimer[self::$_timerId] = $event; - return self::$_timerId++; + $this->eventTimer[self::$timerId] = $event; + return self::$timerId++; } /** @@ -104,7 +104,7 @@ public function onReadable($stream, $func) $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) { $func($stream); }); - $this->_readEvents[$fd_key] = $event; + $this->readEvents[$fd_key] = $event; } /** @@ -113,9 +113,9 @@ public function onReadable($stream, $func) public function offReadable($stream) { $fd_key = (int)$stream; - if (isset($this->_readEvents[$fd_key])) { - $this->_readEvents[$fd_key]->stop(); - unset($this->_readEvents[$fd_key]); + if (isset($this->readEvents[$fd_key])) { + $this->readEvents[$fd_key]->stop(); + unset($this->readEvents[$fd_key]); } } @@ -128,7 +128,7 @@ public function onWritable($stream, $func) $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { $func($stream); }); - $this->_readEvents[$fd_key] = $event; + $this->readEvents[$fd_key] = $event; } /** @@ -137,9 +137,9 @@ public function onWritable($stream, $func) public function offWritable($stream) { $fd_key = (int)$stream; - if (isset($this->_writeEvents[$fd_key])) { - $this->_writeEvents[$fd_key]->stop(); - unset($this->_writeEvents[$fd_key]); + if (isset($this->writeEvents[$fd_key])) { + $this->writeEvents[$fd_key]->stop(); + unset($this->writeEvents[$fd_key]); } } @@ -151,7 +151,7 @@ public function onSignal($signal, $func) $event = new \EvSignal($signal, function () use ($func, $signal) { $func($signal); }); - $this->_eventSignal[$signal] = $event; + $this->eventSignal[$signal] = $event; } /** @@ -159,9 +159,9 @@ public function onSignal($signal, $func) */ public function offSignal($signal) { - if (isset($this->_eventSignal[$signal])) { - $this->_eventSignal[$signal]->stop(); - unset($this->_eventSignal[$signal]); + if (isset($this->eventSignal[$signal])) { + $this->eventSignal[$signal]->stop(); + unset($this->eventSignal[$signal]); } } @@ -170,10 +170,10 @@ public function offSignal($signal) */ public function deleteAllTimer() { - foreach ($this->_eventTimer as $event) { + foreach ($this->eventTimer as $event) { $event->stop(); } - $this->_eventTimer = []; + $this->eventTimer = []; } /** @@ -197,7 +197,7 @@ public function stop() */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } } diff --git a/src/Events/Event.php b/src/Events/Event.php index 9a40ecfbc..cd21f1a97 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -25,44 +25,44 @@ class Event implements EventInterface * Event base. * @var object */ - protected $_eventBase = null; + protected $eventBase = null; /** * All listeners for read event. * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for write event. * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * Event listeners of signal. * @var array */ - protected $_eventSignal = []; + protected $eventSignal = []; /** * All timer event listeners. * [func, args, event, flag, time_interval] * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * Timer id. * @var int */ - protected $_timerId = 0; + protected $timerId = 0; /** * Event class name. * @var string */ - protected $_eventClassName = ''; + protected $eventClassName = ''; /** * Construct. @@ -75,13 +75,13 @@ public function __construct() } else { $class_name = '\Event'; } - $this->_eventClassName = $class_name; + $this->eventClassName = $class_name; if (\class_exists('\\\\EventBase', false)) { $class_name = '\\\\EventBase'; } else { $class_name = '\EventBase'; } - $this->_eventBase = new $class_name(); + $this->eventBase = new $class_name(); } /** @@ -89,9 +89,9 @@ public function __construct() */ public function delay(float $delay, $func, $args) { - $class_name = $this->_eventClassName; - $timer_id = $this->_timerId++; - $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args, $timer_id) { + $class_name = $this->eventClassName; + $timer_id = $this->timerId++; + $event = new $class_name($this->eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args, $timer_id) { try { $this->deleteTimer($timer_id); $func(...$args); @@ -102,7 +102,7 @@ public function delay(float $delay, $func, $args) if (!$event || !$event->addTimer($delay)) { return false; } - $this->_eventTimer[$timer_id] = $event; + $this->eventTimer[$timer_id] = $event; return $timer_id; } @@ -111,9 +111,9 @@ public function delay(float $delay, $func, $args) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { - $this->_eventTimer[$timer_id]->del(); - unset($this->_eventTimer[$timer_id]); + if (isset($this->eventTimer[$timer_id])) { + $this->eventTimer[$timer_id]->del(); + unset($this->eventTimer[$timer_id]); return true; } return false; @@ -124,9 +124,9 @@ public function deleteTimer($timer_id) */ public function repeat(float $interval, $func, $args) { - $class_name = $this->_eventClassName; - $timer_id = $this->_timerId++; - $event = new $class_name($this->_eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { + $class_name = $this->eventClassName; + $timer_id = $this->timerId++; + $event = new $class_name($this->eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { try { $func(...$args); } catch (\Throwable $e) { @@ -136,7 +136,7 @@ public function repeat(float $interval, $func, $args) if (!$event || !$event->addTimer($interval)) { return false; } - $this->_eventTimer[$timer_id] = $event; + $this->eventTimer[$timer_id] = $event; return $timer_id; } @@ -145,13 +145,13 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $class_name = $this->_eventClassName; + $class_name = $this->eventClassName; $fd_key = (int)$stream; - $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::READ | $class_name::PERSIST, $func, $stream); + $event = new $this->eventClassName($this->eventBase, $stream, $class_name::READ | $class_name::PERSIST, $func, $stream); if (!$event || !$event->add()) { return false; } - $this->_writeEvents[$fd_key] = $event; + $this->writeEvents[$fd_key] = $event; return true; } @@ -161,9 +161,9 @@ public function onReadable($stream, $func) public function offReadable($stream) { $fd_key = (int)$stream; - if (isset($this->_readEvents[$fd_key])) { - $this->_readEvents[$fd_key]->del(); - unset($this->_readEvents[$fd_key]); + if (isset($this->readEvents[$fd_key])) { + $this->readEvents[$fd_key]->del(); + unset($this->readEvents[$fd_key]); } } @@ -172,13 +172,13 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $class_name = $this->_eventClassName; + $class_name = $this->eventClassName; $fd_key = (int)$stream; - $event = new $this->_eventClassName($this->_eventBase, $stream, $class_name::WRITE | $class_name::PERSIST, $func, $stream); + $event = new $this->eventClassName($this->eventBase, $stream, $class_name::WRITE | $class_name::PERSIST, $func, $stream); if (!$event || !$event->add()) { return false; } - $this->_writeEvents[$fd_key] = $event; + $this->writeEvents[$fd_key] = $event; return true; } @@ -188,9 +188,9 @@ public function onWritable($stream, $func) public function offWritable($stream) { $fd_key = (int)$stream; - if (isset($this->_writeEvents[$fd_key])) { - $this->_writeEvents[$fd_key]->del(); - unset($this->_writeEvents[$fd_key]); + if (isset($this->writeEvents[$fd_key])) { + $this->writeEvents[$fd_key]->del(); + unset($this->writeEvents[$fd_key]); } } @@ -199,13 +199,13 @@ public function offWritable($stream) */ public function onSignal($signal, $func) { - $class_name = $this->_eventClassName; + $class_name = $this->eventClassName; $fd_key = (int)$signal; - $event = $class_name::signal($this->_eventBase, $signal, $func); + $event = $class_name::signal($this->eventBase, $signal, $func); if (!$event || !$event->add()) { return false; } - $this->_eventSignal[$fd_key] = $event; + $this->eventSignal[$fd_key] = $event; return true; } @@ -215,9 +215,9 @@ public function onSignal($signal, $func) public function offSignal($signal) { $fd_key = (int)$signal; - if (isset($this->_eventSignal[$fd_key])) { - $this->_eventSignal[$fd_key]->del(); - unset($this->_eventSignal[$fd_key]); + if (isset($this->eventSignal[$fd_key])) { + $this->eventSignal[$fd_key]->del(); + unset($this->eventSignal[$fd_key]); } } @@ -226,10 +226,10 @@ public function offSignal($signal) */ public function deleteAllTimer() { - foreach ($this->_eventTimer as $event) { + foreach ($this->eventTimer as $event) { $event->del(); } - $this->_eventTimer = []; + $this->eventTimer = []; } /** @@ -237,7 +237,7 @@ public function deleteAllTimer() */ public function run() { - $this->_eventBase->loop(); + $this->eventBase->loop(); } /** @@ -245,7 +245,7 @@ public function run() */ public function stop() { - $this->_eventBase->exit(); + $this->eventBase->exit(); } /** @@ -253,6 +253,6 @@ public function stop() */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } } diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index a7b3c341f..62dee9c5d 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -25,44 +25,44 @@ class Revolt implements EventInterface /** * @var Driver */ - protected $_driver = null; + protected $driver = null; /** * All listeners for read event. * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for write event. * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * Event listeners of signal. * @var array */ - protected $_eventSignal = []; + protected $eventSignal = []; /** * Event listeners of timer. * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * Timer id. * @var int */ - protected $_timerId = 1; + protected $timerId = 1; /** * Construct. */ public function __construct() { - $this->_driver = EventLoop::getDriver(); + $this->driver = EventLoop::getDriver(); } /** @@ -70,7 +70,7 @@ public function __construct() */ public function driver() { - return $this->_driver; + return $this->driver; } /** @@ -78,7 +78,7 @@ public function driver() */ public function run() { - $this->_driver->run(); + $this->driver->run(); } /** @@ -86,10 +86,10 @@ public function run() */ public function stop() { - foreach ($this->_eventSignal as $cb_id) { - $this->_driver->cancel($cb_id); + foreach ($this->eventSignal as $cb_id) { + $this->driver->cancel($cb_id); } - $this->_driver->stop(); + $this->driver->stop(); pcntl_signal(SIGINT, SIG_IGN); } @@ -99,13 +99,13 @@ public function stop() public function delay(float $delay, $func, $args) { $args = (array)$args; - $timer_id = $this->_timerId++; + $timer_id = $this->timerId++; $closure = function () use ($func, $args, $timer_id) { - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); $func(...$args); }; - $cb_id = $this->_driver->delay($delay, $closure); - $this->_eventTimer[$timer_id] = $cb_id; + $cb_id = $this->driver->delay($delay, $closure); + $this->eventTimer[$timer_id] = $cb_id; return $timer_id; } @@ -115,12 +115,12 @@ public function delay(float $delay, $func, $args) public function repeat(float $interval, $func, $args) { $args = (array)$args; - $timer_id = $this->_timerId++; + $timer_id = $this->timerId++; $closure = function () use ($func, $args, $timer_id) { $func(...$args); }; - $cb_id = $this->_driver->repeat($interval, $closure); - $this->_eventTimer[$timer_id] = $cb_id; + $cb_id = $this->driver->repeat($interval, $closure); + $this->eventTimer[$timer_id] = $cb_id; return $timer_id; } @@ -130,12 +130,12 @@ public function repeat(float $interval, $func, $args) public function onReadable($stream, $func) { $fd_key = (int)$stream; - if (isset($this->_readEvents[$fd_key])) { - $this->_driver->cancel($this->_readEvents[$fd_key]); - unset($this->_readEvents[$fd_key]); + if (isset($this->readEvents[$fd_key])) { + $this->driver->cancel($this->readEvents[$fd_key]); + unset($this->readEvents[$fd_key]); } - $this->_readEvents[$fd_key] = $this->_driver->onReadable($stream, function () use ($stream, $func) { + $this->readEvents[$fd_key] = $this->driver->onReadable($stream, function () use ($stream, $func) { $func($stream); }); } @@ -146,9 +146,9 @@ public function onReadable($stream, $func) public function offReadable($stream) { $fd_key = (int)$stream; - if (isset($this->_readEvents[$fd_key])) { - $this->_driver->cancel($this->_readEvents[$fd_key]); - unset($this->_readEvents[$fd_key]); + if (isset($this->readEvents[$fd_key])) { + $this->driver->cancel($this->readEvents[$fd_key]); + unset($this->readEvents[$fd_key]); } } @@ -158,11 +158,11 @@ public function offReadable($stream) public function onWritable($stream, $func) { $fd_key = (int)$stream; - if (isset($this->_writeEvents[$fd_key])) { - $this->_driver->cancel($this->_writeEvents[$fd_key]); - unset($this->_writeEvents[$fd_key]); + if (isset($this->writeEvents[$fd_key])) { + $this->driver->cancel($this->writeEvents[$fd_key]); + unset($this->writeEvents[$fd_key]); } - $this->_writeEvents[$fd_key] = $this->_driver->onWritable($stream, function () use ($stream, $func) { + $this->writeEvents[$fd_key] = $this->driver->onWritable($stream, function () use ($stream, $func) { $func($stream); }); } @@ -173,9 +173,9 @@ public function onWritable($stream, $func) public function offWritable($stream) { $fd_key = (int)$stream; - if (isset($this->_writeEvents[$fd_key])) { - $this->_driver->cancel($this->_writeEvents[$fd_key]); - unset($this->_writeEvents[$fd_key]); + if (isset($this->writeEvents[$fd_key])) { + $this->driver->cancel($this->writeEvents[$fd_key]); + unset($this->writeEvents[$fd_key]); } } @@ -185,11 +185,11 @@ public function offWritable($stream) public function onSignal($signal, $func) { $fd_key = (int)$signal; - if (isset($this->_eventSignal[$fd_key])) { - $this->_driver->cancel($this->_eventSignal[$fd_key]); - unset($this->_eventSignal[$fd_key]); + if (isset($this->eventSignal[$fd_key])) { + $this->driver->cancel($this->eventSignal[$fd_key]); + unset($this->eventSignal[$fd_key]); } - $this->_eventSignal[$fd_key] = $this->_driver->onSignal($signal, function () use ($signal, $func) { + $this->eventSignal[$fd_key] = $this->driver->onSignal($signal, function () use ($signal, $func) { $func($signal); }); } @@ -200,9 +200,9 @@ public function onSignal($signal, $func) public function offSignal($signal) { $fd_key = (int)$signal; - if (isset($this->_eventSignal[$fd_key])) { - $this->_driver->cancel($this->_eventSignal[$fd_key]); - unset($this->_eventSignal[$fd_key]); + if (isset($this->eventSignal[$fd_key])) { + $this->driver->cancel($this->eventSignal[$fd_key]); + unset($this->eventSignal[$fd_key]); } } @@ -211,9 +211,9 @@ public function offSignal($signal) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { - $this->_driver->cancel($this->_eventTimer[$timer_id]); - unset($this->_eventTimer[$timer_id]); + if (isset($this->eventTimer[$timer_id])) { + $this->driver->cancel($this->eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); return true; } return false; @@ -224,10 +224,10 @@ public function deleteTimer($timer_id) */ public function deleteAllTimer() { - foreach ($this->_eventTimer as $cb_id) { - $this->_driver->cancel($cb_id); + foreach ($this->eventTimer as $cb_id) { + $this->driver->cancel($cb_id); } - $this->_eventTimer = []; + $this->eventTimer = []; } /** @@ -235,6 +235,6 @@ public function deleteAllTimer() */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } } diff --git a/src/Events/Select.php b/src/Events/Select.php index 1fc4fc9af..1b8c67f2f 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -27,47 +27,47 @@ class Select implements EventInterface * * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for read/write event. * * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * @var array */ - protected $_exceptEvents = []; + protected $exceptEvents = []; /** * Event listeners of signal. * * @var array */ - protected $_signalEvents = []; + protected $signalEvents = []; /** * Fds waiting for read event. * * @var array */ - protected $_readFds = []; + protected $readFds = []; /** * Fds waiting for write event. * * @var array */ - protected $_writeFds = []; + protected $writeFds = []; /** * Fds waiting for except event. * * @var array */ - protected $_exceptFds = []; + protected $exceptFds = []; /** * Timer scheduler. @@ -75,7 +75,7 @@ class Select implements EventInterface * * @var \SplPriorityQueue */ - protected $_scheduler = null; + protected $scheduler = null; /** * All timer event listeners. @@ -83,21 +83,21 @@ class Select implements EventInterface * * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * Timer id. * * @var int */ - protected $_timerId = 1; + protected $timerId = 1; /** * Select timeout. * * @var int */ - protected $_selectTimeout = 100000000; + protected $selectTimeout = 100000000; /** * Construct. @@ -105,8 +105,8 @@ class Select implements EventInterface public function __construct() { // Init SplPriorityQueue. - $this->_scheduler = new \SplPriorityQueue(); - $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new \SplPriorityQueue(); + $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); } /** @@ -114,14 +114,14 @@ public function __construct() */ public function delay(float $delay, $func, $args) { - $timer_id = $this->_timerId++; + $timer_id = $this->timerId++; $run_time = \microtime(true) + $delay; - $this->_scheduler->insert($timer_id, -$run_time); - $this->_eventTimer[$timer_id] = [$func, (array)$args]; + $this->scheduler->insert($timer_id, -$run_time); + $this->eventTimer[$timer_id] = [$func, (array)$args]; $select_timeout = ($run_time - \microtime(true)) * 1000000; $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; - if ($this->_selectTimeout > $select_timeout) { - $this->_selectTimeout = $select_timeout; + if ($this->selectTimeout > $select_timeout) { + $this->selectTimeout = $select_timeout; } return $timer_id; } @@ -131,14 +131,14 @@ public function delay(float $delay, $func, $args) */ public function repeat(float $delay, $func, $args) { - $timer_id = $this->_timerId++; + $timer_id = $this->timerId++; $run_time = \microtime(true) + $delay; - $this->_scheduler->insert($timer_id, -$run_time); - $this->_eventTimer[$timer_id] = [$func, (array)$args, $delay]; + $this->scheduler->insert($timer_id, -$run_time); + $this->eventTimer[$timer_id] = [$func, (array)$args, $delay]; $select_timeout = ($run_time - \microtime(true)) * 1000000; $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; - if ($this->_selectTimeout > $select_timeout) { - $this->_selectTimeout = $select_timeout; + if ($this->selectTimeout > $select_timeout) { + $this->selectTimeout = $select_timeout; } return $timer_id; } @@ -148,8 +148,8 @@ public function repeat(float $delay, $func, $args) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { - unset($this->_eventTimer[$timer_id]); + if (isset($this->eventTimer[$timer_id])) { + unset($this->eventTimer[$timer_id]); return true; } return false; @@ -160,15 +160,15 @@ public function deleteTimer($timer_id) */ public function onReadable($stream, $func) { - $count = \count($this->_readFds); + $count = \count($this->readFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } $fd_key = (int)$stream; - $this->_readEvents[$fd_key] = $func; - $this->_readFds[$fd_key] = $stream; + $this->readEvents[$fd_key] = $func; + $this->readFds[$fd_key] = $stream; } /** @@ -177,7 +177,7 @@ public function onReadable($stream, $func) public function offReadable($stream) { $fd_key = (int)$stream; - unset($this->_readEvents[$fd_key], $this->_readFds[$fd_key]); + unset($this->readEvents[$fd_key], $this->readFds[$fd_key]); } /** @@ -185,15 +185,15 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $count = \count($this->_writeFds); + $count = \count($this->writeFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } $fd_key = (int)$stream; - $this->_writeEvents[$fd_key] = $func; - $this->_writeFds[$fd_key] = $stream; + $this->writeEvents[$fd_key] = $func; + $this->writeFds[$fd_key] = $stream; } /** @@ -202,7 +202,7 @@ public function onWritable($stream, $func) public function offWritable($stream) { $fd_key = (int)$stream; - unset($this->_writeEvents[$fd_key], $this->_writeFds[$fd_key]); + unset($this->writeEvents[$fd_key], $this->writeFds[$fd_key]); } /** @@ -211,8 +211,8 @@ public function offWritable($stream) public function onExcept($stream, $func) { $fd_key = (int)$stream; - $this->_exceptEvents[$fd_key] = $func; - $this->_exceptFds[$fd_key] = $stream; + $this->exceptEvents[$fd_key] = $func; + $this->exceptFds[$fd_key] = $stream; } /** @@ -221,7 +221,7 @@ public function onExcept($stream, $func) public function offExcept($stream) { $fd_key = (int)$stream; - unset($this->_exceptEvents[$fd_key], $this->_exceptFds[$fd_key]); + unset($this->exceptEvents[$fd_key], $this->exceptFds[$fd_key]); } /** @@ -232,7 +232,7 @@ public function onSignal($signal, $func) if (\DIRECTORY_SEPARATOR !== '/') { return null; } - $this->_signalEvents[$signal] = $func; + $this->signalEvents[$signal] = $func; \pcntl_signal($signal, [$this, 'signalHandler']); } @@ -241,7 +241,7 @@ public function onSignal($signal, $func) */ public function offsignal($signal) { - unset($this->_signalEvents[$signal]); + unset($this->signalEvents[$signal]); \pcntl_signal($signal, SIG_IGN); } @@ -252,7 +252,7 @@ public function offsignal($signal) */ public function signalHandler($signal) { - $this->_signalEvents[$signal]($signal); + $this->signalEvents[$signal]($signal); } /** @@ -263,26 +263,26 @@ public function signalHandler($signal) protected function tick() { $tasks_to_insert = []; - while (!$this->_scheduler->isEmpty()) { - $scheduler_data = $this->_scheduler->top(); + while (!$this->scheduler->isEmpty()) { + $scheduler_data = $this->scheduler->top(); $timer_id = $scheduler_data['data']; $next_run_time = -$scheduler_data['priority']; $time_now = \microtime(true); - $this->_selectTimeout = (int)(($next_run_time - $time_now) * 1000000); - if ($this->_selectTimeout <= 0) { - $this->_scheduler->extract(); + $this->selectTimeout = (int)(($next_run_time - $time_now) * 1000000); + if ($this->selectTimeout <= 0) { + $this->scheduler->extract(); - if (!isset($this->_eventTimer[$timer_id])) { + if (!isset($this->eventTimer[$timer_id])) { continue; } // [func, args, timer_interval] - $task_data = $this->_eventTimer[$timer_id]; + $task_data = $this->eventTimer[$timer_id]; if (isset($task_data[2])) { $next_run_time = $time_now + $task_data[2]; $tasks_to_insert[] = [$timer_id, -$next_run_time]; } else { - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); } try { $task_data[0]($task_data[1]); @@ -294,16 +294,16 @@ protected function tick() } } foreach ($tasks_to_insert as $item) { - $this->_scheduler->insert($item[0], $item[1]); + $this->scheduler->insert($item[0], $item[1]); } - if (!$this->_scheduler->isEmpty()) { - $scheduler_data = $this->_scheduler->top(); + if (!$this->scheduler->isEmpty()) { + $scheduler_data = $this->scheduler->top(); $next_run_time = -$scheduler_data['priority']; $time_now = \microtime(true); - $this->_selectTimeout = \max((int)(($next_run_time - $time_now) * 1000000), 0); + $this->selectTimeout = \max((int)(($next_run_time - $time_now) * 1000000), 0); return; } - $this->_selectTimeout = 100000000; + $this->selectTimeout = 100000000; } /** @@ -311,9 +311,9 @@ protected function tick() */ public function deleteAllTimer() { - $this->_scheduler = new \SplPriorityQueue(); - $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); - $this->_eventTimer = []; + $this->scheduler = new \SplPriorityQueue(); + $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->eventTimer = []; } /** @@ -327,43 +327,43 @@ public function run() \pcntl_signal_dispatch(); } - $read = $this->_readFds; - $write = $this->_writeFds; - $except = $this->_exceptFds; + $read = $this->readFds; + $write = $this->writeFds; + $except = $this->exceptFds; if ($read || $write || $except) { // Waiting read/write/signal/timeout events. try { - @stream_select($read, $write, $except, 0, $this->_selectTimeout); + @stream_select($read, $write, $except, 0, $this->selectTimeout); } catch (Throwable $e) { } } else { - $this->_selectTimeout >= 1 && usleep($this->_selectTimeout); + $this->selectTimeout >= 1 && usleep($this->selectTimeout); } - if (!$this->_scheduler->isEmpty()) { + if (!$this->scheduler->isEmpty()) { $this->tick(); } foreach ($read as $fd) { $fd_key = (int)$fd; - if (isset($this->_readEvents[$fd_key])) { - $this->_readEvents[$fd_key]($fd); + if (isset($this->readEvents[$fd_key])) { + $this->readEvents[$fd_key]($fd); } } foreach ($write as $fd) { $fd_key = (int)$fd; - if (isset($this->_writeEvents[$fd_key])) { - $this->_writeEvents[$fd_key]($fd); + if (isset($this->writeEvents[$fd_key])) { + $this->writeEvents[$fd_key]($fd); } } foreach ($except as $fd) { $fd_key = (int)$fd; - if (isset($this->_exceptEvents[$fd_key])) { - $this->_exceptEvents[$fd_key]($fd); + if (isset($this->exceptEvents[$fd_key])) { + $this->exceptEvents[$fd_key]($fd); } } } @@ -375,11 +375,11 @@ public function run() public function stop() { $this->deleteAllTimer(); - foreach ($this->_signalEvents as $signal => $item) { + foreach ($this->signalEvents as $signal => $item) { $this->offsignal($signal); } - $this->_readFds = $this->_writeFds = $this->_exceptFds = $this->_readEvents - = $this->_writeEvents = $this->_exceptEvents = $this->_signalEvents = []; + $this->readFds = $this->writeFds = $this->exceptFds = $this->readEvents + = $this->writeEvents = $this->exceptEvents = $this->signalEvents = []; } /** @@ -387,7 +387,7 @@ public function stop() */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 1f15ebdd1..3a8187281 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -24,19 +24,19 @@ class Swoole implements EventInterface * All listeners for read timer * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * All listeners for read event. * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for write event. * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * {@inheritdoc} @@ -46,14 +46,14 @@ public function delay(float $delay, $func, $args) $t = (int)($delay * 1000); $t = $t < 1 ? 1 : $t; $timer_id = Timer::after($t, function () use ($func, $args, &$timer_id) { - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); try { $func(...(array)$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); } }); - $this->_eventTimer[$timer_id] = $timer_id; + $this->eventTimer[$timer_id] = $timer_id; return $timer_id; } @@ -62,9 +62,9 @@ public function delay(float $delay, $func, $args) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { + if (isset($this->eventTimer[$timer_id])) { $res = Timer::clear($timer_id); - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); return $res; } return false; @@ -87,7 +87,7 @@ public function repeat(float $interval, $func, $args) Worker::stopAll(250, $e); } }); - $this->_eventTimer[$timer_id] = $timer_id; + $this->eventTimer[$timer_id] = $timer_id; return $timer_id; } @@ -96,7 +96,7 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $this->_readEvents[(int)$stream] = $stream; + $this->readEvents[(int)$stream] = $stream; return Event::add($stream, $func, null, \SWOOLE_EVENT_READ); } @@ -106,11 +106,11 @@ public function onReadable($stream, $func) public function offReadable($stream) { $fd = (int)$stream; - if (!isset($this->_readEvents[$fd])) { + if (!isset($this->readEvents[$fd])) { return; } - unset($this->_readEvents[$fd]); - if (!isset($this->_writeEvents[$fd])) { + unset($this->readEvents[$fd]); + if (!isset($this->writeEvents[$fd])) { return Event::del($stream); } return Event::set($stream, null, null, \SWOOLE_EVENT_READ); @@ -121,7 +121,7 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $this->_writeEvents[(int)$stream] = $stream; + $this->writeEvents[(int)$stream] = $stream; return Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE); } @@ -131,11 +131,11 @@ public function onWritable($stream, $func) public function offWritable($stream) { $fd = (int)$stream; - if (!isset($this->_writeEvents[$fd])) { + if (!isset($this->writeEvents[$fd])) { return; } - unset($this->_writeEvents[$fd]); - if (!isset($this->_readEvents[$fd])) { + unset($this->writeEvents[$fd]); + if (!isset($this->readEvents[$fd])) { return Event::del($stream); } return Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); @@ -163,7 +163,7 @@ public function offSignal($signal) */ public function deleteAllTimer() { - foreach ($this->_eventTimer as $timer_id) { + foreach ($this->eventTimer as $timer_id) { Timer::clear($timer_id); } } @@ -194,7 +194,7 @@ public function stop() */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 7628113f6..52f2629f4 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -23,25 +23,25 @@ class Swow implements EventInterface * All listeners for read timer * @var array */ - protected $_eventTimer = []; + protected $eventTimer = []; /** * All listeners for read event. * @var array */ - protected $_readEvents = []; + protected $readEvents = []; /** * All listeners for write event. * @var array */ - protected $_writeEvents = []; + protected $writeEvents = []; /** * All listeners for signal. * @var array */ - protected $_signalListener = []; + protected $signalListener = []; /** * Get timer count. @@ -50,7 +50,7 @@ class Swow implements EventInterface */ public function getTimerCount() { - return \count($this->_eventTimer); + return \count($this->eventTimer); } /** @@ -62,7 +62,7 @@ public function delay(float $delay, $func, $args) $t = max($t, 1); $coroutine = Coroutine::run(function () use ($t, $func, $args): void { msleep($t); - unset($this->_eventTimer[Coroutine::getCurrent()->getId()]); + unset($this->eventTimer[Coroutine::getCurrent()->getId()]); try { $func(...(array) $args); } catch (\Throwable $e) { @@ -70,7 +70,7 @@ public function delay(float $delay, $func, $args) } }); $timer_id = $coroutine->getId(); - $this->_eventTimer[$timer_id] = $timer_id; + $this->eventTimer[$timer_id] = $timer_id; return $timer_id; } @@ -92,7 +92,7 @@ public function repeat(float $interval, $func, $args) } }); $timer_id = $coroutine->getId(); - $this->_eventTimer[$timer_id] = $timer_id; + $this->eventTimer[$timer_id] = $timer_id; return $timer_id; } @@ -101,12 +101,12 @@ public function repeat(float $interval, $func, $args) */ public function deleteTimer($timer_id) { - if (isset($this->_eventTimer[$timer_id])) { + if (isset($this->eventTimer[$timer_id])) { try { (Coroutine::getAll()[$timer_id])->kill(); return true; } finally { - unset($this->_eventTimer[$timer_id]); + unset($this->eventTimer[$timer_id]); } } return false; @@ -117,7 +117,7 @@ public function deleteTimer($timer_id) */ public function deleteAllTimer() { - foreach ($this->_eventTimer as $timer_id) { + foreach ($this->eventTimer as $timer_id) { $this->deleteTimer($timer_id); } } @@ -127,10 +127,10 @@ public function deleteAllTimer() */ public function onReadable($stream, $func) { - if (isset($this->_readEvents[(int) $stream])) { + if (isset($this->readEvents[(int) $stream])) { $this->offReadable($stream); } - $this->_readEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + $this->readEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { try { while (true) { $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP); @@ -155,17 +155,17 @@ public function onReadable($stream, $func) public function offReadable($stream, bool $bySelf = false) { $fd = (int) $stream; - if (!isset($this->_readEvents[$fd])) { + if (!isset($this->readEvents[$fd])) { return; } if (!$bySelf) { - $coroutine = $this->_readEvents[$fd]; + $coroutine = $this->readEvents[$fd]; if (!$coroutine->isExecuting()) { return; } $coroutine->kill(); } - unset($this->_readEvents[$fd]); + unset($this->readEvents[$fd]); } /** @@ -173,10 +173,10 @@ public function offReadable($stream, bool $bySelf = false) */ public function onWritable($stream, $func) { - if (isset($this->_writeEvents[(int) $stream])) { + if (isset($this->writeEvents[(int) $stream])) { $this->offWritable($stream); } - $this->_writeEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + $this->writeEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { try { while (true) { $rEvent = stream_poll_one($stream, STREAM_POLLOUT | STREAM_POLLHUP); @@ -201,17 +201,17 @@ public function onWritable($stream, $func) public function offWritable($stream, bool $bySelf = false) { $fd = (int) $stream; - if (!isset($this->_writeEvents[$fd])) { + if (!isset($this->writeEvents[$fd])) { return; } if (!$bySelf) { - $coroutine = $this->_writeEvents[$fd]; + $coroutine = $this->writeEvents[$fd]; if (!$coroutine->isExecuting()) { return; } $coroutine->kill(); } - unset($this->_writeEvents[$fd]); + unset($this->writeEvents[$fd]); } /** @@ -219,7 +219,7 @@ public function offWritable($stream, bool $bySelf = false) */ public function onSignal($signal, $func) { - if (isset($this->_signalListener[$signal])) { + if (isset($this->signalListener[$signal])) { return false; } $coroutine = Coroutine::run(static function () use ($signal, $func): void { @@ -229,7 +229,7 @@ public function onSignal($signal, $func) } catch (SignalException) { } }); - $this->_signalListener[$signal] = $coroutine; + $this->signalListener[$signal] = $coroutine; return true; } @@ -238,11 +238,11 @@ public function onSignal($signal, $func) */ public function offSignal($signal) { - if (!isset($this->_signalListener[$signal])) { + if (!isset($this->signalListener[$signal])) { return false; } - $this->_signalListener[$signal]->kill(); - unset($this->_signalListener[$signal]); + $this->signalListener[$signal]->kill(); + unset($this->signalListener[$signal]); return true; } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index af7ce2e48..bf2c939d1 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -29,21 +29,21 @@ class Http * * @var string */ - protected static $_requestClass = Request::class; + protected static $requestClass = Request::class; /** * Upload tmp dir. * * @var string */ - protected static $_uploadTmpDir = ''; + protected static $uploadTmpDir = ''; /** * Cache. * * @var bool. */ - protected static $_enableCache = true; + protected static $enableCache = true; /** * Get or set the request class name. @@ -54,9 +54,9 @@ class Http public static function requestClass($class_name = null) { if ($class_name) { - static::$_requestClass = $class_name; + static::$requestClass = $class_name; } - return static::$_requestClass; + return static::$requestClass; } /** @@ -66,7 +66,7 @@ public static function requestClass($class_name = null) */ public static function enableCache($value) { - static::$_enableCache = (bool)$value; + static::$enableCache = (bool)$value; } /** @@ -149,17 +149,17 @@ public static function input(string $recv_buffer, TcpConnection $connection) public static function decode($recv_buffer, TcpConnection $connection) { static $requests = []; - $cacheable = static::$_enableCache && !isset($recv_buffer[512]); + $cacheable = static::$enableCache && !isset($recv_buffer[512]); if (true === $cacheable && isset($requests[$recv_buffer])) { $request = clone $requests[$recv_buffer]; $request->connection = $connection; - $connection->__request = $request; + $connection->request = $request; $request->properties = []; return $request; } - $request = new static::$_requestClass($recv_buffer); + $request = new static::$requestClass($recv_buffer); $request->connection = $connection; - $connection->__request = $request; + $connection->request = $request; if (true === $cacheable) { $requests[$recv_buffer] = $request; if (\count($requests) > 512) { @@ -178,15 +178,15 @@ public static function decode($recv_buffer, TcpConnection $connection) */ public static function encode($response, TcpConnection $connection) { - if (isset($connection->__request)) { - $connection->__request->session = null; - $connection->__request->connection = null; - $connection->__request = null; + if (isset($connection->request)) { + $connection->request->session = null; + $connection->request->connection = null; + $connection->request = null; } if (!\is_object($response)) { $ext_header = ''; - if (isset($connection->__header)) { - foreach ($connection->__header as $name => $value) { + if (isset($connection->header)) { + foreach ($connection->header as $name => $value) { if (\is_array($value)) { foreach ($value as $item) { $ext_header = "$name: $item\r\n"; @@ -195,15 +195,15 @@ public static function encode($response, TcpConnection $connection) $ext_header = "$name: $value\r\n"; } } - unset($connection->__header); + unset($connection->header); } $body_len = \strlen((string)$response); return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response"; } - if (isset($connection->__header)) { - $response->withHeaders($connection->__header); - unset($connection->__header); + if (isset($connection->header)) { + $response->withHeaders($connection->header); + unset($connection->header); } if (isset($response->file)) { @@ -302,15 +302,15 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse public static function uploadTmpDir($dir = null) { if (null !== $dir) { - static::$_uploadTmpDir = $dir; + static::$uploadTmpDir = $dir; } - if (static::$_uploadTmpDir === '') { + if (static::$uploadTmpDir === '') { if ($upload_tmp_dir = \ini_get('upload_tmp_dir')) { - static::$_uploadTmpDir = $upload_tmp_dir; + static::$uploadTmpDir = $upload_tmp_dir; } else if ($upload_tmp_dir = \sys_get_temp_dir()) { - static::$_uploadTmpDir = $upload_tmp_dir; + static::$uploadTmpDir = $upload_tmp_dir; } } - return static::$_uploadTmpDir; + return static::$uploadTmpDir; } } diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 6fec54602..44f73607a 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -26,7 +26,7 @@ class Chunk * * @var string */ - protected $_buffer = null; + protected $buffer = null; /** * Chunk constructor. @@ -34,7 +34,7 @@ class Chunk */ public function __construct($buffer) { - $this->_buffer = $buffer; + $this->buffer = $buffer; } /** @@ -44,6 +44,6 @@ public function __construct($buffer) */ public function __toString() { - return \dechex(\strlen($this->_buffer)) . "\r\n$this->_buffer\r\n"; + return \dechex(\strlen($this->buffer)) . "\r\n$this->buffer\r\n"; } } \ No newline at end of file diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 69aabc985..1886540d9 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -56,21 +56,21 @@ class Request * * @var string */ - protected $_buffer = null; + protected $buffer = null; /** * Request data. * * @var array */ - protected $_data = null; + protected $data = null; /** * Enable cache. * * @var bool */ - protected static $_enableCache = true; + protected static $enableCache = true; /** @@ -80,11 +80,11 @@ class Request */ public function __construct($buffer) { - $this->_buffer = $buffer; + $this->buffer = $buffer; } /** - * $_GET. + * $GET. * * @param string|null $name * @param mixed|null $default @@ -92,17 +92,17 @@ public function __construct($buffer) */ public function get($name = null, $default = null) { - if (!isset($this->_data['get'])) { + if (!isset($this->data['get'])) { $this->parseGet(); } if (null === $name) { - return $this->_data['get']; + return $this->data['get']; } - return $this->_data['get'][$name] ?? $default; + return $this->data['get'][$name] ?? $default; } /** - * $_POST. + * $POST. * * @param string|null $name * @param mixed|null $default @@ -110,13 +110,13 @@ public function get($name = null, $default = null) */ public function post($name = null, $default = null) { - if (!isset($this->_data['post'])) { + if (!isset($this->data['post'])) { $this->parsePost(); } if (null === $name) { - return $this->_data['post']; + return $this->data['post']; } - return $this->_data['post'][$name] ?? $default; + return $this->data['post'][$name] ?? $default; } /** @@ -128,14 +128,14 @@ public function post($name = null, $default = null) */ public function header($name = null, $default = null) { - if (!isset($this->_data['headers'])) { + if (!isset($this->data['headers'])) { $this->parseHeaders(); } if (null === $name) { - return $this->_data['headers']; + return $this->data['headers']; } $name = \strtolower($name); - return $this->_data['headers'][$name] ?? $default; + return $this->data['headers'][$name] ?? $default; } /** @@ -147,14 +147,14 @@ public function header($name = null, $default = null) */ public function cookie($name = null, $default = null) { - if (!isset($this->_data['cookie'])) { - $this->_data['cookie'] = []; - \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->_data['cookie']); + if (!isset($this->data['cookie'])) { + $this->data['cookie'] = []; + \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); } if ($name === null) { - return $this->_data['cookie']; + return $this->data['cookie']; } - return $this->_data['cookie'][$name] ?? $default; + return $this->data['cookie'][$name] ?? $default; } /** @@ -165,13 +165,13 @@ public function cookie($name = null, $default = null) */ public function file($name = null) { - if (!isset($this->_data['files'])) { + if (!isset($this->data['files'])) { $this->parsePost(); } if (null === $name) { - return $this->_data['files']; + return $this->data['files']; } - return $this->_data['files'][$name] ?? null; + return $this->data['files'][$name] ?? null; } /** @@ -181,10 +181,10 @@ public function file($name = null) */ public function method() { - if (!isset($this->_data['method'])) { + if (!isset($this->data['method'])) { $this->parseHeadFirstLine(); } - return $this->_data['method']; + return $this->data['method']; } /** @@ -194,10 +194,10 @@ public function method() */ public function protocolVersion() { - if (!isset($this->_data['protocolVersion'])) { + if (!isset($this->data['protocolVersion'])) { $this->parseProtocolVersion(); } - return $this->_data['protocolVersion']; + return $this->data['protocolVersion']; } /** @@ -222,10 +222,10 @@ public function host($without_port = false) */ public function uri() { - if (!isset($this->_data['uri'])) { + if (!isset($this->data['uri'])) { $this->parseHeadFirstLine(); } - return $this->_data['uri']; + return $this->data['uri']; } /** @@ -235,10 +235,10 @@ public function uri() */ public function path() { - if (!isset($this->_data['path'])) { - $this->_data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH); + if (!isset($this->data['path'])) { + $this->data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH); } - return $this->_data['path']; + return $this->data['path']; } /** @@ -248,10 +248,10 @@ public function path() */ public function queryString() { - if (!isset($this->_data['query_string'])) { - $this->_data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY); + if (!isset($this->data['query_string'])) { + $this->data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY); } - return $this->_data['query_string']; + return $this->data['query_string']; } /** @@ -326,10 +326,10 @@ public function sessionRegenerateId($delete_old_session = false) */ public function rawHead() { - if (!isset($this->_data['head'])) { - $this->_data['head'] = \strstr($this->_buffer, "\r\n\r\n", true); + if (!isset($this->data['head'])) { + $this->data['head'] = \strstr($this->buffer, "\r\n\r\n", true); } - return $this->_data['head']; + return $this->data['head']; } /** @@ -339,7 +339,7 @@ public function rawHead() */ public function rawBody() { - return \substr($this->_buffer, \strpos($this->_buffer, "\r\n\r\n") + 4); + return \substr($this->buffer, \strpos($this->buffer, "\r\n\r\n") + 4); } /** @@ -349,7 +349,7 @@ public function rawBody() */ public function rawBuffer() { - return $this->_buffer; + return $this->buffer; } /** @@ -359,7 +359,7 @@ public function rawBuffer() */ public static function enableCache($value) { - static::$_enableCache = (bool)$value; + static::$enableCache = (bool)$value; } /** @@ -369,10 +369,10 @@ public static function enableCache($value) */ protected function parseHeadFirstLine() { - $first_line = \strstr($this->_buffer, "\r\n", true); + $first_line = \strstr($this->buffer, "\r\n", true); $tmp = \explode(' ', $first_line, 3); - $this->_data['method'] = $tmp[0]; - $this->_data['uri'] = $tmp[1] ?? '/'; + $this->data['method'] = $tmp[0]; + $this->data['uri'] = $tmp[1] ?? '/'; } /** @@ -382,9 +382,9 @@ protected function parseHeadFirstLine() */ protected function parseProtocolVersion() { - $first_line = \strstr($this->_buffer, "\r\n", true); + $first_line = \strstr($this->buffer, "\r\n", true); $protoco_version = substr(\strstr($first_line, 'HTTP/'), 5); - $this->_data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0'; + $this->data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0'; } /** @@ -395,16 +395,16 @@ protected function parseProtocolVersion() protected function parseHeaders() { static $cache = []; - $this->_data['headers'] = []; + $this->data['headers'] = []; $raw_head = $this->rawHead(); $end_line_position = \strpos($raw_head, "\r\n"); if ($end_line_position === false) { return; } $head_buffer = \substr($raw_head, $end_line_position + 2); - $cacheable = static::$_enableCache && !isset($head_buffer[2048]); + $cacheable = static::$enableCache && !isset($head_buffer[2048]); if ($cacheable && isset($cache[$head_buffer])) { - $this->_data['headers'] = $cache[$head_buffer]; + $this->data['headers'] = $cache[$head_buffer]; return; } $head_data = \explode("\r\n", $head_buffer); @@ -417,14 +417,14 @@ protected function parseHeaders() $key = \strtolower($content); $value = ''; } - if (isset($this->_data['headers'][$key])) { - $this->_data['headers'][$key] = "{$this->_data['headers'][$key]},$value"; + if (isset($this->data['headers'][$key])) { + $this->data['headers'][$key] = "{$this->data['headers'][$key]},$value"; } else { - $this->_data['headers'][$key] = $value; + $this->data['headers'][$key] = $value; } } if ($cacheable) { - $cache[$head_buffer] = $this->_data['headers']; + $cache[$head_buffer] = $this->data['headers']; if (\count($cache) > 128) { unset($cache[key($cache)]); } @@ -440,18 +440,18 @@ protected function parseGet() { static $cache = []; $query_string = $this->queryString(); - $this->_data['get'] = []; + $this->data['get'] = []; if ($query_string === '') { return; } - $cacheable = static::$_enableCache && !isset($query_string[1024]); + $cacheable = static::$enableCache && !isset($query_string[1024]); if ($cacheable && isset($cache[$query_string])) { - $this->_data['get'] = $cache[$query_string]; + $this->data['get'] = $cache[$query_string]; return; } - \parse_str($query_string, $this->_data['get']); + \parse_str($query_string, $this->data['get']); if ($cacheable) { - $cache[$query_string] = $this->_data['get']; + $cache[$query_string] = $this->data['get']; if (\count($cache) > 256) { unset($cache[key($cache)]); } @@ -466,7 +466,7 @@ protected function parseGet() protected function parsePost() { static $cache = []; - $this->_data['post'] = $this->_data['files'] = []; + $this->data['post'] = $this->data['files'] = []; $content_type = $this->header('content-type', ''); if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { $http_post_boundary = '--' . $match[1]; @@ -477,18 +477,18 @@ protected function parsePost() if ($body_buffer === '') { return; } - $cacheable = static::$_enableCache && !isset($body_buffer[1024]); + $cacheable = static::$enableCache && !isset($body_buffer[1024]); if ($cacheable && isset($cache[$body_buffer])) { - $this->_data['post'] = $cache[$body_buffer]; + $this->data['post'] = $cache[$body_buffer]; return; } if (\preg_match('/\bjson\b/i', $content_type)) { - $this->_data['post'] = (array)\json_decode($body_buffer, true); + $this->data['post'] = (array)\json_decode($body_buffer, true); } else { - \parse_str($body_buffer, $this->_data['post']); + \parse_str($body_buffer, $this->data['post']); } if ($cacheable) { - $cache[$body_buffer] = $this->_data['post']; + $cache[$body_buffer] = $this->data['post']; if (\count($cache) > 256) { unset($cache[key($cache)]); } @@ -504,7 +504,7 @@ protected function parsePost() protected function parseUploadFiles($http_post_boundary) { $http_post_boundary = \trim($http_post_boundary, '"'); - $buffer = $this->_buffer; + $buffer = $this->buffer; $post_encode_string = ''; $files_encode_string = ''; $files = []; @@ -515,12 +515,12 @@ protected function parseUploadFiles($http_post_boundary) $offset = $this->parseUploadFile($http_post_boundary, $offset, $post_encode_string, $files_encode_string, $files); } if ($post_encode_string) { - parse_str($post_encode_string, $this->_data['post']); + parse_str($post_encode_string, $this->data['post']); } if ($files_encode_string) { - parse_str($files_encode_string, $this->_data['files']); - \array_walk_recursive($this->_data['files'], function (&$value) use ($files) { + parse_str($files_encode_string, $this->data['files']); + \array_walk_recursive($this->data['files'], function (&$value) use ($files) { $value = $files[$value]; }); } @@ -535,20 +535,20 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco { $file = []; $boundary = "\r\n$boundary"; - if (\strlen($this->_buffer) < $section_start_offset) { + if (\strlen($this->buffer) < $section_start_offset) { return 0; } - $section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset); + $section_end_offset = \strpos($this->buffer, $boundary, $section_start_offset); if (!$section_end_offset) { return 0; } - $content_lines_end_offset = \strpos($this->_buffer, "\r\n\r\n", $section_start_offset); + $content_lines_end_offset = \strpos($this->buffer, "\r\n\r\n", $section_start_offset); if (!$content_lines_end_offset || $content_lines_end_offset + 4 > $section_end_offset) { return 0; } - $content_lines_str = \substr($this->_buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset); + $content_lines_str = \substr($this->buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset); $content_lines = \explode("\r\n", trim($content_lines_str . "\r\n")); - $boundary_value = \substr($this->_buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4); + $boundary_value = \substr($this->buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4); $upload_key = false; foreach ($content_lines as $content_line) { if (!\strpos($content_line, ': ')) { @@ -585,7 +585,7 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco break; } // Is post field. else { - // Parse $_POST. + // Parse $POST. if (\preg_match('/name="(.*?)"$/', $value, $match)) { $k = $match[1]; $post_encode_string .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; @@ -667,7 +667,7 @@ public function __unset($name) */ public function __toString() { - return $this->_buffer; + return $this->buffer; } /** @@ -677,9 +677,9 @@ public function __toString() */ public function __destruct() { - if (isset($this->_data['files'])) { + if (isset($this->data['files'])) { \clearstatcache(); - \array_walk_recursive($this->_data['files'], function ($value, $key) { + \array_walk_recursive($this->data['files'], function ($value, $key) { if ($key === 'tmp_name') { if (\is_file($value)) { \unlink($value); @@ -697,7 +697,7 @@ public function __destruct() */ protected function setSidCookie(string $session_name, string $sid, array $cookie_params) { - $this->connection->__header['Set-Cookie'] = [$session_name . '=' . $sid + $this->connection->header['Set-Cookie'] = [$session_name . '=' . $sid . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime']) . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index ac446acc2..aa0e487c3 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -25,35 +25,35 @@ class Response * * @var array */ - protected $_header = null; + protected $header = null; /** * Http status. * * @var int */ - protected $_status = null; + protected $status = null; /** * Http reason. * * @var string */ - protected $_reason = null; + protected $reason = null; /** * Http version. * * @var string */ - protected $_version = '1.1'; + protected $version = '1.1'; /** * Http body. * * @var string */ - protected $_body = null; + protected $body = null; /** * Send file info @@ -66,7 +66,7 @@ class Response * Mine type map. * @var array */ - protected static $_mimeTypeMap = null; + protected static $mimeTypeMap = null; /** * Phrases. @@ -168,9 +168,9 @@ public function __construct( $body = '' ) { - $this->_status = $status; - $this->_header = $headers; - $this->_body = (string)$body; + $this->status = $status; + $this->header = $headers; + $this->body = (string)$body; } /** @@ -182,7 +182,7 @@ public function __construct( */ public function header($name, $value) { - $this->_header[$name] = $value; + $this->header[$name] = $value; return $this; } @@ -206,7 +206,7 @@ public function withHeader($name, $value) */ public function withHeaders($headers) { - $this->_header = \array_merge_recursive($this->_header, $headers); + $this->header = \array_merge_recursive($this->header, $headers); return $this; } @@ -218,7 +218,7 @@ public function withHeaders($headers) */ public function withoutHeader($name) { - unset($this->_header[$name]); + unset($this->header[$name]); return $this; } @@ -231,7 +231,7 @@ public function withoutHeader($name) public function getHeader($name) { - return $this->_header[$name] ?? null; + return $this->header[$name] ?? null; } /** @@ -241,7 +241,7 @@ public function getHeader($name) */ public function getHeaders() { - return $this->_header; + return $this->header; } /** @@ -253,8 +253,8 @@ public function getHeaders() */ public function withStatus($code, $reason_phrase = null) { - $this->_status = $code; - $this->_reason = $reason_phrase; + $this->status = $code; + $this->reason = $reason_phrase; return $this; } @@ -265,7 +265,7 @@ public function withStatus($code, $reason_phrase = null) */ public function getStatusCode() { - return $this->_status; + return $this->status; } /** @@ -275,7 +275,7 @@ public function getStatusCode() */ public function getReasonPhrase() { - return $this->_reason; + return $this->reason; } /** @@ -286,7 +286,7 @@ public function getReasonPhrase() */ public function withProtocolVersion($version) { - $this->_version = $version; + $this->version = $version; return $this; } @@ -298,7 +298,7 @@ public function withProtocolVersion($version) */ public function withBody($body) { - $this->_body = (string)$body; + $this->body = (string)$body; return $this; } @@ -309,7 +309,7 @@ public function withBody($body) */ public function rawBody() { - return $this->_body; + return $this->body; } /** @@ -344,7 +344,7 @@ public function withFile($file, $offset = 0, $length = 0) */ public function cookie($name, $value = '', $max_age = null, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) { - $this->_header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) + $this->header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) . ($max_age === null ? '' : '; Max-Age=' . $max_age) . (empty($path) ? '' : '; Path=' . $path) @@ -363,9 +363,9 @@ public function cookie($name, $value = '', $max_age = null, $path = '', $domain protected function createHeadForFile($file_info) { $file = $file_info['file']; - $reason = $this->_reason ?: self::PHRASES[$this->_status]; - $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; - $headers = $this->_header; + $reason = $this->reason ?: self::PHRASES[$this->status]; + $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; + $headers = $this->header; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } @@ -387,14 +387,14 @@ protected function createHeadForFile($file_info) $extension = $file_info['extension'] ?? ''; $base_name = $file_info['basename'] ?? 'unknown'; if (!isset($headers['Content-Type'])) { - if (isset(self::$_mimeTypeMap[$extension])) { - $head .= "Content-Type: " . self::$_mimeTypeMap[$extension] . "\r\n"; + if (isset(self::$mimeTypeMap[$extension])) { + $head .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; } else { $head .= "Content-Type: application/octet-stream\r\n"; } } - if (!isset($headers['Content-Disposition']) && !isset(self::$_mimeTypeMap[$extension])) { + if (!isset($headers['Content-Disposition']) && !isset(self::$mimeTypeMap[$extension])) { $head .= "Content-Disposition: attachment; filename=\"$base_name\"\r\n"; } @@ -418,14 +418,14 @@ public function __toString() return $this->createHeadForFile($this->file); } - $reason = $this->_reason ?: self::PHRASES[$this->_status] ?? ''; - $body_len = \strlen($this->_body); - if (empty($this->_header)) { - return "HTTP/{$this->_version} {$this->_status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->_body}"; + $reason = $this->reason ?: self::PHRASES[$this->status] ?? ''; + $body_len = \strlen($this->body); + if (empty($this->header)) { + return "HTTP/{$this->version} {$this->status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->body}"; } - $head = "HTTP/{$this->_version} {$this->_status} $reason\r\n"; - $headers = $this->_header; + $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; + $headers = $this->header; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } @@ -446,17 +446,17 @@ public function __toString() if (!isset($headers['Content-Type'])) { $head .= "Content-Type: text/html;charset=utf-8\r\n"; } else if ($headers['Content-Type'] === 'text/event-stream') { - return $head . $this->_body; + return $head . $this->body; } if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $body_len\r\n\r\n"; } else { - return "$head\r\n" . dechex($body_len) . "\r\n{$this->_body}\r\n"; + return "$head\r\n" . dechex($body_len) . "\r\n{$this->body}\r\n"; } // The whole http package - return $head . $this->_body; + return $head . $this->body; } /** @@ -474,7 +474,7 @@ public static function initMimeTypeMap() $extension_var = $match[2]; $extension_array = \explode(' ', \substr($extension_var, 0, -1)); foreach ($extension_array as $file_extension) { - static::$_mimeTypeMap[$file_extension] = $mime_type; + static::$mimeTypeMap[$file_extension] = $mime_type; } } } diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index db527c4bd..64f02815a 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -24,7 +24,7 @@ class ServerSentEvents * Data. * @var array */ - protected $_data = null; + protected $data = null; /** * ServerSentEvents constructor. @@ -33,7 +33,7 @@ class ServerSentEvents */ public function __construct(array $data) { - $this->_data = $data; + $this->data = $data; } /** @@ -44,7 +44,7 @@ public function __construct(array $data) public function __toString() { $buffer = ''; - $data = $this->_data; + $data = $this->data; if (isset($data[''])) { $buffer = ": {$data['']}\n"; } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 24ca56a59..12d92c46f 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -28,14 +28,14 @@ class Session * * @var string */ - protected static $_handlerClass = FileSessionHandler::class; + protected static $handlerClass = FileSessionHandler::class; /** * Parameters of __constructor for session handler class. * * @var null */ - protected static $_handlerConfig = null; + protected static $handlerConfig = null; /** * Session name. @@ -112,28 +112,28 @@ class Session * * @var SessionHandlerInterface */ - protected static $_handler = null; + protected static $handler = null; /** * Session data. * * @var array */ - protected $_data = []; + protected $data = []; /** * Session changed and need to save. * * @var bool */ - protected $_needSave = false; + protected $needSave = false; /** * Session id. * * @var null */ - protected $_sessionId = null; + protected $sessionId = null; /** * Session constructor. @@ -143,12 +143,12 @@ class Session public function __construct($session_id) { static::checkSessionId($session_id); - if (static::$_handler === null) { + if (static::$handler === null) { static::initHandler(); } - $this->_sessionId = $session_id; - if ($data = static::$_handler->read($session_id)) { - $this->_data = \unserialize($data); + $this->sessionId = $session_id; + if ($data = static::$handler->read($session_id)) { + $this->data = \unserialize($data); } } @@ -159,7 +159,7 @@ public function __construct($session_id) */ public function getId() { - return $this->_sessionId; + return $this->sessionId; } /** @@ -171,7 +171,7 @@ public function getId() */ public function get($name, $default = null) { - return $this->_data[$name] ?? $default; + return $this->data[$name] ?? $default; } /** @@ -182,8 +182,8 @@ public function get($name, $default = null) */ public function set($name, $value) { - $this->_data[$name] = $value; - $this->_needSave = true; + $this->data[$name] = $value; + $this->needSave = true; } /** @@ -193,8 +193,8 @@ public function set($name, $value) */ public function delete($name) { - unset($this->_data[$name]); - $this->_needSave = true; + unset($this->data[$name]); + $this->needSave = true; } /** @@ -225,9 +225,9 @@ public function put($key, $value = null) } foreach ($key as $k => $v) { - $this->_data[$k] = $v; + $this->data[$k] = $v; } - $this->_needSave = true; + $this->needSave = true; } /** @@ -243,10 +243,10 @@ public function forget($name) } if (\is_array($name)) { foreach ($name as $key) { - unset($this->_data[$key]); + unset($this->data[$key]); } } - $this->_needSave = true; + $this->needSave = true; } /** @@ -256,7 +256,7 @@ public function forget($name) */ public function all() { - return $this->_data; + return $this->data; } /** @@ -266,8 +266,8 @@ public function all() */ public function flush() { - $this->_needSave = true; - $this->_data = []; + $this->needSave = true; + $this->data = []; } /** @@ -278,7 +278,7 @@ public function flush() */ public function has($name) { - return isset($this->_data[$name]); + return isset($this->data[$name]); } /** @@ -289,7 +289,7 @@ public function has($name) */ public function exists($name) { - return \array_key_exists($name, $this->_data); + return \array_key_exists($name, $this->data); } /** @@ -299,16 +299,16 @@ public function exists($name) */ public function save() { - if ($this->_needSave) { - if (empty($this->_data)) { - static::$_handler->destroy($this->_sessionId); + if ($this->needSave) { + if (empty($this->data)) { + static::$handler->destroy($this->sessionId); } else { - static::$_handler->write($this->_sessionId, \serialize($this->_data)); + static::$handler->write($this->sessionId, \serialize($this->data)); } } elseif (static::$autoUpdateTimestamp) { static::refresh(); } - $this->_needSave = false; + $this->needSave = false; } /** @@ -318,7 +318,7 @@ public function save() */ public function refresh() { - return static::$_handler->updateTimestamp($this->getId()); + return static::$handler->updateTimestamp($this->getId()); } /** @@ -354,12 +354,12 @@ public static function init() public static function handlerClass($class_name = null, $config = null) { if ($class_name) { - static::$_handlerClass = $class_name; + static::$handlerClass = $class_name; } if ($config) { - static::$_handlerConfig = $config; + static::$handlerConfig = $config; } - return static::$_handlerClass; + return static::$handlerClass; } /** @@ -386,10 +386,10 @@ public static function getCookieParams() */ protected static function initHandler() { - if (static::$_handlerConfig === null) { - static::$_handler = new static::$_handlerClass(); + if (static::$handlerConfig === null) { + static::$handler = new static::$handlerClass(); } else { - static::$_handler = new static::$_handlerClass(static::$_handlerConfig); + static::$handler = new static::$handlerClass(static::$handlerConfig); } } @@ -400,7 +400,7 @@ protected static function initHandler() */ public function gc() { - static::$_handler->gc(static::$lifetime); + static::$handler->gc(static::$lifetime); } /** diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index 234afd70e..7dd72d792 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -27,14 +27,14 @@ class FileSessionHandler implements SessionHandlerInterface * * @var string */ - protected static $_sessionSavePath = null; + protected static $sessionSavePath = null; /** * Session file prefix. * * @var string */ - protected static $_sessionFilePrefix = 'session_'; + protected static $sessionFilePrefix = 'session_'; /** * Init. @@ -90,7 +90,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - $temp_file = static::$_sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); + $temp_file = static::$sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); if (!\file_put_contents($temp_file, $session_data)) { return false; } @@ -147,7 +147,7 @@ public function destroy($session_id) public function gc($maxlifetime) { $time_now = \time(); - foreach (\glob(static::$_sessionSavePath . static::$_sessionFilePrefix . '*') as $file) { + foreach (\glob(static::$sessionSavePath . static::$sessionFilePrefix . '*') as $file) { if (\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { \unlink($file); } @@ -162,7 +162,7 @@ public function gc($maxlifetime) */ protected static function sessionFile($session_id) { - return static::$_sessionSavePath . static::$_sessionFilePrefix . $session_id; + return static::$sessionSavePath . static::$sessionFilePrefix . $session_id; } /** @@ -177,7 +177,7 @@ public static function sessionSavePath($path) if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) { $path .= DIRECTORY_SEPARATOR; } - static::$_sessionSavePath = $path; + static::$sessionSavePath = $path; if (!\is_dir($path)) { \mkdir($path, 0777, true); } diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 805ef260c..351e58621 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -28,11 +28,11 @@ public function __construct($config) if ($auth) { $args[] = $auth; } - $this->_redis = new \RedisCluster(...$args); + $this->redis = new \RedisCluster(...$args); if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + $this->redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); } /** @@ -40,7 +40,7 @@ public function __construct($config) */ public function read($session_id) { - return $this->_redis->get($session_id); + return $this->redis->get($session_id); } } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index e1f334aed..62d2ee439 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -28,12 +28,12 @@ class RedisSessionHandler implements SessionHandlerInterface /** * @var \Redis */ - protected $_redis; + protected $redis; /** * @var array */ - protected $_config; + protected $config; /** * RedisSessionHandler constructor. @@ -57,33 +57,33 @@ public function __construct($config) $config['timeout'] = 2; } - $this->_config = $config; + $this->config = $config; $this->connect(); Timer::add($config['ping'] ?? 55, function () { - $this->_redis->get('ping'); + $this->redis->get('ping'); }); } public function connect() { - $config = $this->_config; + $config = $this->config; - $this->_redis = new \Redis(); - if (false === $this->_redis->connect($config['host'], $config['port'], $config['timeout'])) { + $this->redis = new \Redis(); + if (false === $this->redis->connect($config['host'], $config['port'], $config['timeout'])) { throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); } if (!empty($config['auth'])) { - $this->_redis->auth($config['auth']); + $this->redis->auth($config['auth']); } if (!empty($config['database'])) { - $this->_redis->select($config['database']); + $this->redis->select($config['database']); } if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + $this->redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); } /** @@ -100,12 +100,12 @@ public function open($save_path, $name) public function read($session_id) { try { - return $this->_redis->get($session_id); + return $this->redis->get($session_id); } catch (RedisException $e) { $msg = strtolower($e->getMessage()); if ($msg === 'connection lost' || strpos($msg, 'went away')) { $this->connect(); - return $this->_redis->get($session_id); + return $this->redis->get($session_id); } throw $e; } @@ -116,7 +116,7 @@ public function read($session_id) */ public function write($session_id, $session_data) { - return true === $this->_redis->setex($session_id, Session::$lifetime, $session_data); + return true === $this->redis->setex($session_id, Session::$lifetime, $session_data); } /** @@ -124,7 +124,7 @@ public function write($session_id, $session_data) */ public function updateTimestamp($id, $data = "") { - return true === $this->_redis->expire($id, Session::$lifetime); + return true === $this->redis->expire($id, Session::$lifetime); } /** @@ -132,7 +132,7 @@ public function updateTimestamp($id, $data = "") */ public function destroy($session_id) { - $this->_redis->del($session_id); + $this->redis->del($session_id); return true; } diff --git a/src/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php index c7ce4921d..792487e0d 100644 --- a/src/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -88,7 +88,7 @@ public function read($session_id); * @param string $session_data

* The encoded session data. This data is the * result of the PHP internally encoding - * the $_SESSION superglobal to a serialized + * the $SESSION superglobal to a serialized * string and passing it as this parameter. * Please note sessions use an alternative serialization method. *

diff --git a/src/Timer.php b/src/Timer.php index 7c1d55012..3f5f0236c 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -33,21 +33,21 @@ class Timer * * @var array */ - protected static $_tasks = []; + protected static $tasks = []; /** * event * * @var Select */ - protected static $_event = null; + protected static $event = null; /** * timer id * * @var int */ - protected static $_timerId = 0; + protected static $timerId = 0; /** * timer status @@ -59,7 +59,7 @@ class Timer * * @var array */ - protected static $_status = []; + protected static $status = []; /** * Init. @@ -70,7 +70,7 @@ class Timer public static function init($event = null) { if ($event) { - self::$_event = $event; + self::$event = $event; return; } if (\function_exists('pcntl_signal')) { @@ -85,7 +85,7 @@ public static function init($event = null) */ public static function signalHandle() { - if (!self::$_event) { + if (!self::$event) { \pcntl_alarm(1); self::tick(); } @@ -111,8 +111,8 @@ public static function add(float $time_interval, $func, $args = [], $persistent $args = []; } - if (self::$_event) { - return $persistent ? self::$_event->repeat($time_interval, $func, $args) : self::$_event->delay($time_interval, $func, $args); + if (self::$event) { + return $persistent ? self::$event->repeat($time_interval, $func, $args) : self::$event->delay($time_interval, $func, $args); } // If not workerman runtime just return. @@ -125,20 +125,20 @@ public static function add(float $time_interval, $func, $args = [], $persistent return false; } - if (empty(self::$_tasks)) { + if (empty(self::$tasks)) { \pcntl_alarm(1); } $run_time = \time() + $time_interval; - if (!isset(self::$_tasks[$run_time])) { - self::$_tasks[$run_time] = []; + if (!isset(self::$tasks[$run_time])) { + self::$tasks[$run_time] = []; } - self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId; - self::$_status[self::$_timerId] = true; - self::$_tasks[$run_time][self::$_timerId] = [$func, (array)$args, $persistent, $time_interval]; + self::$timerId = self::$timerId == \PHP_INT_MAX ? 1 : ++self::$timerId; + self::$status[self::$timerId] = true; + self::$tasks[$run_time][self::$timerId] = [$func, (array)$args, $persistent, $time_interval]; - return self::$_timerId; + return self::$timerId; } /** @@ -160,12 +160,12 @@ public static function delay(float $delay, $func, $args = []) */ public static function tick() { - if (empty(self::$_tasks)) { + if (empty(self::$tasks)) { \pcntl_alarm(0); return; } $time_now = \time(); - foreach (self::$_tasks as $run_time => $task_data) { + foreach (self::$tasks as $run_time => $task_data) { if ($time_now >= $run_time) { foreach ($task_data as $index => $one_task) { $task_func = $one_task[0]; @@ -177,13 +177,13 @@ public static function tick() } catch (\Throwable $e) { Worker::safeEcho($e); } - if($persistent && !empty(self::$_status[$index])) { + if($persistent && !empty(self::$status[$index])) { $new_run_time = \time() + $time_interval; - if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = []; - self::$_tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval]; + if(!isset(self::$tasks[$new_run_time])) self::$tasks[$new_run_time] = []; + self::$tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval]; } } - unset(self::$_tasks[$run_time]); + unset(self::$tasks[$run_time]); } } } @@ -196,16 +196,16 @@ public static function tick() */ public static function del($timer_id) { - if (self::$_event) { - return self::$_event->deleteTimer($timer_id); + if (self::$event) { + return self::$event->deleteTimer($timer_id); } - foreach(self::$_tasks as $run_time => $task_data) + foreach(self::$tasks as $run_time => $task_data) { - if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]); + if(array_key_exists($timer_id, $task_data)) unset(self::$tasks[$run_time][$timer_id]); } - if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]); + if(array_key_exists($timer_id, self::$status)) unset(self::$status[$timer_id]); return true; } @@ -217,12 +217,12 @@ public static function del($timer_id) */ public static function delAll() { - self::$_tasks = self::$_status = []; + self::$tasks = self::$status = []; if (\function_exists('pcntl_alarm')) { \pcntl_alarm(0); } - if (self::$_event) { - self::$_event->deleteAllTimer(); + if (self::$event) { + self::$event->deleteAllTimer(); } } } diff --git a/src/Worker.php b/src/Worker.php index f93090370..98c4878e7 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -229,7 +229,7 @@ class Worker * * @var bool */ - protected $_pauseAccept = true; + protected $pauseAccept = true; /** * Is worker stopping ? @@ -326,42 +326,42 @@ class Worker * * @var int */ - protected static $_masterPid = 0; + protected static $masterPid = 0; /** * Listening socket. * * @var resource */ - protected $_mainSocket = null; + protected $mainSocket = null; /** * Socket name. The format is like this http://0.0.0.0:80 . * * @var string */ - protected $_socketName = ''; + protected $socketName = ''; /** * parse from _socketName avoid parse again in master or worker * LocalSocket The format is like tcp://0.0.0.0:8080 * @var string */ - protected $_localSocket = null; + protected $localSocket = null; /** * Context of socket. * * @var resource */ - protected $_context = null; + protected $context = null; /** * All worker instances. * * @var Worker[] */ - protected static $_workers = []; + protected static $workers = []; /** * All worker processes pid. @@ -369,7 +369,7 @@ class Worker * * @var array */ - protected static $_pidMap = []; + protected static $pidMap = []; /** * All worker processes waiting for restart. @@ -377,7 +377,7 @@ class Worker * * @var array */ - protected static $_pidsToRestart = []; + protected static $pidsToRestart = []; /** * Mapping from PID to worker process ID. @@ -385,84 +385,84 @@ class Worker * * @var array */ - protected static $_idMap = []; + protected static $idMap = []; /** * Current status. * * @var int */ - protected static $_status = self::STATUS_STARTING; + protected static $status = self::STATUS_STARTING; /** * Maximum length of the worker names. * * @var int */ - protected static $_maxWorkerNameLength = 12; + protected static $maxWorkerNameLength = 12; /** * Maximum length of the socket names. * * @var int */ - protected static $_maxSocketNameLength = 12; + protected static $maxSocketNameLength = 12; /** * Maximum length of the process user names. * * @var int */ - protected static $_maxUserNameLength = 12; + protected static $maxUserNameLength = 12; /** * Maximum length of the Proto names. * * @var int */ - protected static $_maxProtoNameLength = 4; + protected static $maxProtoNameLength = 4; /** * Maximum length of the Processes names. * * @var int */ - protected static $_maxProcessesNameLength = 9; + protected static $maxProcessesNameLength = 9; /** - * Maximum length of the Status names. + * Maximum length of the state names. * * @var int */ - protected static $_maxStatusNameLength = 1; + protected static $maxStateNameLength = 1; /** * The file to store status info of current worker process. * * @var string */ - protected static $_statisticsFile = ''; + protected static $statisticsFile = ''; /** * Start file. * * @var string */ - protected static $_startFile = ''; + protected static $startFile = ''; /** * Processes for windows. * * @var array */ - protected static $_processForWindows = []; + protected static $processForWindows = []; /** * Status info of current worker process. * * @var array */ - protected static $_globalStatistics = [ + protected static $globalStatistics = [ 'start_timestamp' => 0, 'worker_exit_info' => [] ]; @@ -472,7 +472,7 @@ class Worker * * @var array */ - protected static $_availableEventLoops = [ + protected static $availableEventLoops = [ "event" => Event::class, ]; @@ -516,19 +516,19 @@ class Worker * * @var bool */ - protected static $_gracefulStop = false; + protected static $gracefulStop = false; /** * Standard output stream * @var resource */ - protected static $_outputStream = null; + protected static $outputStream = null; /** * If $outputStream support decorated * @var bool */ - protected static $_outputDecorated = null; + protected static $outputDecorated = null; /** * Worker object's hash id(unique identifier). @@ -585,9 +585,9 @@ protected static function init() // Start file. $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - static::$_startFile = end($backtrace)['file']; + static::$startFile = end($backtrace)['file']; - $unique_prefix = \str_replace('/', '_', static::$_startFile); + $unique_prefix = \str_replace('/', '_', static::$startFile); // Pid file. if (empty(static::$pidFile)) { @@ -609,13 +609,13 @@ protected static function init() } // State. - static::$_status = static::STATUS_STARTING; + static::$status = static::STATUS_STARTING; // For statistics. - static::$_globalStatistics['start_timestamp'] = \time(); + static::$globalStatistics['start_timestamp'] = \time(); // Process title. - static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$_startFile); + static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$startFile); // Init data for worker id. static::initId(); @@ -660,8 +660,8 @@ protected static function initWorkers() if (\DIRECTORY_SEPARATOR !== '/') { return; } - static::$_statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' .posix_getpid().'.status'; - foreach (static::$_workers as $worker) { + static::$statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' .posix_getpid().'.status'; + foreach (static::$workers as $worker) { // Worker name. if (empty($worker->name)) { $worker->name = 'none'; @@ -680,13 +680,13 @@ protected static function initWorkers() $worker->socket = $worker->getSocketName(); // Status name. - $worker->status = ' [OK] '; + $worker->sate = ' [OK] '; // Get column mapping for UI foreach(static::getUiColumns() as $column_name => $prop){ !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; $prop_length = \strlen($worker->{$prop}); - $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; static::$$key = \max(static::$$key, $prop_length); } @@ -707,7 +707,7 @@ public static function reloadAllWorkers() static::init(); static::initWorkers(); static::displayUI(); - static::$_status = static::STATUS_RELOADING; + static::$status = static::STATUS_RELOADING; } /** @@ -717,7 +717,7 @@ public static function reloadAllWorkers() */ public static function getAllWorkers() { - return static::$_workers; + return static::$workers; } /** @@ -735,7 +735,7 @@ public static function getEventLoop() * @return resource */ public function getMainSocket(){ - return $this->_mainSocket; + return $this->mainSocket; } /** @@ -745,13 +745,13 @@ public function getMainSocket(){ */ protected static function initId() { - foreach (static::$_workers as $worker_id => $worker) { + foreach (static::$workers as $worker_id => $worker) { $new_id_map = []; $worker->count = max($worker->count, 1); for ($key = 0; $key < $worker->count; $key++) { - $new_id_map[$key] = static::$_idMap[$worker_id][$key] ?? 0; + $new_id_map[$key] = static::$idMap[$worker_id][$key] ?? 0; } - static::$_idMap[$worker_id] = $new_id_map; + static::$idMap[$worker_id] = $new_id_map; } } @@ -796,7 +796,7 @@ protected static function displayUI() //Show title $title = ''; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; //just keep compatible with listen name $column_name === 'socket' && $column_name = 'listen'; $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); @@ -804,10 +804,10 @@ protected static function displayUI() $title && static::safeEcho($title . \PHP_EOL); //Show content - foreach (static::$_workers as $worker) { + foreach (static::$workers as $worker) { $content = ''; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); @@ -844,7 +844,7 @@ public static function getUiColumns() 'worker' => 'name', 'socket' => 'socket', 'processes' => 'count', - 'status' => 'status', + 'state' => 'state', ]; } @@ -858,7 +858,7 @@ public static function getSingleLineTotalLength() $total_length = 0; foreach(static::getUiColumns() as $column_name => $prop){ - $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; $total_length += static::$$key + static::UI_SAFE_LENGTH; } @@ -978,11 +978,11 @@ protected static function parseCommand() case 'restart': case 'stop': if ($mode === '-g') { - static::$_gracefulStop = true; + static::$gracefulStop = true; $sig = \SIGQUIT; static::log("Workerman[$start_file] is gracefully stopping ..."); } else { - static::$_gracefulStop = false; + static::$gracefulStop = false; $sig = \SIGINT; static::log("Workerman[$start_file] is stopping ..."); } @@ -996,7 +996,7 @@ protected static function parseCommand() $master_is_alive = $master_pid && \posix_kill($master_pid, 0); if ($master_is_alive) { // Timeout? - if (!static::$_gracefulStop && \time() - $start_time >= $timeout) { + if (!static::$gracefulStop && \time() - $start_time >= $timeout) { static::log("Workerman[$start_file] stop fail"); exit; } @@ -1064,8 +1064,8 @@ protected static function formatStatusData($statistics_file) $total_fails = 0; $total_memory = 0; $total_timers = 0; - $maxLen1 = static::$_maxSocketNameLength; - $maxLen2 = static::$_maxWorkerNameLength; + $maxLen1 = static::$maxSocketNameLength; + $maxLen2 = static::$maxWorkerNameLength; foreach($info as $value) { if (!$read_process_status) { $status_str .= $value . "\n"; @@ -1092,8 +1092,8 @@ protected static function formatStatusData($statistics_file) foreach($worker_info as $pid => $info) { if (!isset($data_waiting_sort[$pid])) { $status_str .= "$pid\t" . \str_pad('N/A', 7) . " " - . \str_pad($info['listen'], static::$_maxSocketNameLength) . " " - . \str_pad($info['name'], static::$_maxWorkerNameLength) . " " + . \str_pad($info['listen'], static::$maxSocketNameLength) . " " + . \str_pad($info['name'], static::$maxWorkerNameLength) . " " . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; continue; @@ -1167,19 +1167,19 @@ public static function signalHandler($signal) case \SIGTERM: case \SIGHUP: case \SIGTSTP: - static::$_gracefulStop = false; + static::$gracefulStop = false; static::stopAll(); break; // Graceful stop. case \SIGQUIT: - static::$_gracefulStop = true; + static::$gracefulStop = true; static::stopAll(); break; // Reload. case \SIGUSR2: case \SIGUSR1: - static::$_gracefulStop = $signal === \SIGUSR2; - static::$_pidsToRestart = static::getAllWorkerPids(); + static::$gracefulStop = $signal === \SIGUSR2; + static::$pidsToRestart = static::getAllWorkerPids(); static::reload(); break; // Show status. @@ -1260,7 +1260,7 @@ public static function resetStd(bool $throw_exception = true) }, 1); } // change output stream - static::$_outputStream = null; + static::$outputStream = null; static::outputStream($STDOUT); \restore_error_handler(); return; @@ -1281,8 +1281,8 @@ protected static function saveMasterPid() return; } - static::$_masterPid = \posix_getpid(); - if (false === \file_put_contents(static::$pidFile, static::$_masterPid)) { + static::$masterPid = \posix_getpid(); + if (false === \file_put_contents(static::$pidFile, static::$masterPid)) { throw new Exception('can not save pid to ' . static::$pidFile); } } @@ -1299,11 +1299,11 @@ protected static function getEventLoopName(): string } if (!class_exists(\Swoole\Event::class, false)) { - unset(static::$_availableEventLoops['swoole']); + unset(static::$availableEventLoops['swoole']); } $loop_name = ''; - foreach (static::$_availableEventLoops as $name => $class) { + foreach (static::$availableEventLoops as $name => $class) { if (\extension_loaded($name)) { $loop_name = $name; break; @@ -1311,7 +1311,7 @@ protected static function getEventLoopName(): string } if ($loop_name) { - static::$eventLoopClass = static::$_availableEventLoops[$loop_name]; + static::$eventLoopClass = static::$availableEventLoops[$loop_name]; } else { static::$eventLoopClass = Select::class; } @@ -1326,7 +1326,7 @@ protected static function getEventLoopName(): string protected static function getAllWorkerPids() { $pid_array = []; - foreach (static::$_pidMap as $worker_pid_array) { + foreach (static::$pidMap as $worker_pid_array) { foreach ($worker_pid_array as $worker_pid) { $pid_array[$worker_pid] = $worker_pid; } @@ -1356,18 +1356,18 @@ protected static function forkWorkers() protected static function forkWorkersForLinux() { - foreach (static::$_workers as $worker) { - if (static::$_status === static::STATUS_STARTING) { + foreach (static::$workers as $worker) { + if (static::$status === static::STATUS_STARTING) { if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } $worker_name_length = \strlen($worker->name); - if (static::$_maxWorkerNameLength < $worker_name_length) { - static::$_maxWorkerNameLength = $worker_name_length; + if (static::$maxWorkerNameLength < $worker_name_length) { + static::$maxWorkerNameLength = $worker_name_length; } } - while (\count(static::$_pidMap[$worker->workerId]) < $worker->count) { + while (\count(static::$pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorkerForLinux($worker); } } @@ -1383,19 +1383,19 @@ protected static function forkWorkersForWindows() $files = static::getStartFilesForWindows(); if(\in_array('-q', static::getArgv()) || \count($files) === 1) { - if(\count(static::$_workers) > 1) + if(\count(static::$workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); static::safeEcho("@@@ See https://www.workerman.net/doc/workerman/faq/multi-woker-for-windows.html @@@\r\n"); } - elseif(\count(static::$_workers) <= 0) + elseif(\count(static::$workers) <= 0) { exit("@@@no worker inited@@@\r\n\r\n"); } - \reset(static::$_workers); + \reset(static::$workers); /** @var Worker $worker */ - $worker = current(static::$_workers); + $worker = current(static::$workers); // Display UI. static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); @@ -1453,7 +1453,7 @@ public static function forkOneWorkerForWindows($start_file) } // 保存子进程句柄 - static::$_processForWindows[$start_file] = array($process, $start_file); + static::$processForWindows[$start_file] = array($process, $start_file); } /** @@ -1462,7 +1462,7 @@ public static function forkOneWorkerForWindows($start_file) */ public static function checkWorkerStatusForWindows() { - foreach(static::$_processForWindows as $process_data) + foreach(static::$processForWindows as $process_data) { $process = $process_data[0]; $start_file = $process_data[1]; @@ -1497,25 +1497,25 @@ protected static function forkOneWorkerForLinux(self $worker) $pid = \pcntl_fork(); // For master process. if ($pid > 0) { - static::$_pidMap[$worker->workerId][$pid] = $pid; - static::$_idMap[$worker->workerId][$id] = $pid; + static::$pidMap[$worker->workerId][$pid] = $pid; + static::$idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { \srand(); \mt_srand(); - static::$_gracefulStop = false; + static::$gracefulStop = false; if ($worker->reusePort) { $worker->listen(); } - if (static::$_status === static::STATUS_STARTING) { + if (static::$status === static::STATUS_STARTING) { static::resetStd(); } - static::$_pidsToRestart = static::$_pidMap = []; + static::$pidsToRestart = static::$pidMap = []; // Remove other listener. - foreach(static::$_workers as $key => $one_worker) { + foreach(static::$workers as $key => $one_worker) { if ($one_worker->workerId !== $worker->workerId) { $one_worker->unlisten(); - unset(static::$_workers[$key]); + unset(static::$workers[$key]); } } Timer::delAll(); @@ -1544,7 +1544,7 @@ protected static function forkOneWorkerForLinux(self $worker) */ protected static function getId($worker_id, $pid) { - return \array_search($pid, static::$_idMap[$worker_id]); + return \array_search($pid, static::$idMap[$worker_id]); } /** @@ -1615,7 +1615,7 @@ protected static function monitorWorkers() */ protected static function monitorWorkersForLinux() { - static::$_status = static::STATUS_RUNNING; + static::$status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. \pcntl_signal_dispatch(); @@ -1627,9 +1627,9 @@ protected static function monitorWorkersForLinux() // If a child has already exited. if ($pid > 0) { // Find out which worker process exited. - foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + foreach (static::$pidMap as $worker_id => $worker_pid_array) { if (isset($worker_pid_array[$pid])) { - $worker = static::$_workers[$worker_id]; + $worker = static::$workers[$worker_id]; // Exit status. if ($status !== 0) { static::log("worker[{$worker->name}:$pid] exit with status $status"); @@ -1645,34 +1645,34 @@ protected static function monitorWorkersForLinux() } // For Statistics. - if (!isset(static::$_globalStatistics['worker_exit_info'][$worker_id][$status])) { - static::$_globalStatistics['worker_exit_info'][$worker_id][$status] = 0; + if (!isset(static::$globalStatistics['worker_exit_info'][$worker_id][$status])) { + static::$globalStatistics['worker_exit_info'][$worker_id][$status] = 0; } - ++static::$_globalStatistics['worker_exit_info'][$worker_id][$status]; + ++static::$globalStatistics['worker_exit_info'][$worker_id][$status]; // Clear process data. - unset(static::$_pidMap[$worker_id][$pid]); + unset(static::$pidMap[$worker_id][$pid]); // Mark id is available. $id = static::getId($worker_id, $pid); - static::$_idMap[$worker_id][$id] = 0; + static::$idMap[$worker_id][$id] = 0; break; } } // Is still running state then fork a new worker process. - if (static::$_status !== static::STATUS_SHUTDOWN) { + if (static::$status !== static::STATUS_SHUTDOWN) { static::forkWorkers(); // If reloading continue. - if (isset(static::$_pidsToRestart[$pid])) { - unset(static::$_pidsToRestart[$pid]); + if (isset(static::$pidsToRestart[$pid])) { + unset(static::$pidsToRestart[$pid]); static::reload(); } } } // If shutdown state and all child processes exited then master process exit. - if (static::$_status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + if (static::$status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { static::exitAndClearAll(); } } @@ -1697,7 +1697,7 @@ protected static function monitorWorkersForWindows() */ protected static function exitAndClearAll() { - foreach (static::$_workers as $worker) { + foreach (static::$workers as $worker) { $socket_name = $worker->getSocketName(); if ($worker->transport === 'unix' && $socket_name) { list(, $address) = \explode(':', $socket_name, 2); @@ -1706,7 +1706,7 @@ protected static function exitAndClearAll() } } @\unlink(static::$pidFile); - static::log("Workerman[" . \basename(static::$_startFile) . "] has been stopped"); + static::log("Workerman[" . \basename(static::$startFile) . "] has been stopped"); if (static::$onMasterStop) { \call_user_func(static::$onMasterStop); } @@ -1721,11 +1721,11 @@ protected static function exitAndClearAll() protected static function reload() { // For master process. - if (static::$_masterPid === \posix_getpid()) { + if (static::$masterPid === \posix_getpid()) { // Set reloading state. - if (static::$_status !== static::STATUS_RELOADING && static::$_status !== static::STATUS_SHUTDOWN) { - static::log("Workerman[" . \basename(static::$_startFile) . "] reloading"); - static::$_status = static::STATUS_RELOADING; + if (static::$status !== static::STATUS_RELOADING && static::$status !== static::STATUS_SHUTDOWN) { + static::log("Workerman[" . \basename(static::$startFile) . "] reloading"); + static::$status = static::STATUS_RELOADING; static::resetStd(false); // Try to emit onMasterReload callback. @@ -1739,12 +1739,12 @@ protected static function reload() } } - $sig = static::$_gracefulStop ? \SIGUSR2 : \SIGUSR1; + $sig = static::$gracefulStop ? \SIGUSR2 : \SIGUSR1; // Send reload signal to all child processes. $reloadable_pid_array = []; - foreach (static::$_pidMap as $worker_id => $worker_pid_array) { - $worker = static::$_workers[$worker_id]; + foreach (static::$pidMap as $worker_id => $worker_pid_array) { + $worker = static::$workers[$worker_id]; if ($worker->reloadable) { foreach ($worker_pid_array as $pid) { $reloadable_pid_array[$pid] = $pid; @@ -1758,27 +1758,27 @@ protected static function reload() } // Get all pids that are waiting reload. - static::$_pidsToRestart = \array_intersect(static::$_pidsToRestart, $reloadable_pid_array); + static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadable_pid_array); // Reload complete. - if (empty(static::$_pidsToRestart)) { - if (static::$_status !== static::STATUS_SHUTDOWN) { - static::$_status = static::STATUS_RUNNING; + if (empty(static::$pidsToRestart)) { + if (static::$status !== static::STATUS_SHUTDOWN) { + static::$status = static::STATUS_RUNNING; } return; } // Continue reload. - $one_worker_pid = \current(static::$_pidsToRestart); + $one_worker_pid = \current(static::$pidsToRestart); // Send reload signal to a worker process. \posix_kill($one_worker_pid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. - if(!static::$_gracefulStop){ + if(!static::$gracefulStop){ Timer::add(static::$stopTimeout, '\posix_kill', [$one_worker_pid, \SIGKILL], false); } } // For child processes. else { - \reset(static::$_workers); - $worker = \current(static::$_workers); + \reset(static::$workers); + $worker = \current(static::$workers); // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { try { @@ -1808,37 +1808,37 @@ public static function stopAll($code = 0, $log = '') static::log($log); } - static::$_status = static::STATUS_SHUTDOWN; + static::$status = static::STATUS_SHUTDOWN; // For master process. - if (\DIRECTORY_SEPARATOR === '/' && static::$_masterPid === \posix_getpid()) { - static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ..."); + if (\DIRECTORY_SEPARATOR === '/' && static::$masterPid === \posix_getpid()) { + static::log("Workerman[" . \basename(static::$startFile) . "] stopping ..."); $worker_pid_array = static::getAllWorkerPids(); // Send stop signal to all child processes. - $sig = static::$_gracefulStop ? \SIGQUIT : \SIGINT; + $sig = static::$gracefulStop ? \SIGQUIT : \SIGINT; // Fix exit with status 2 usleep(50000); foreach ($worker_pid_array as $worker_pid) { \posix_kill($worker_pid, $sig); - if(!static::$_gracefulStop){ + if(!static::$gracefulStop){ Timer::add(static::$stopTimeout, '\posix_kill', [$worker_pid, \SIGKILL], false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); // Remove statistics file. - if (\is_file(static::$_statisticsFile)) { - @\unlink(static::$_statisticsFile); + if (\is_file(static::$statisticsFile)) { + @\unlink(static::$statisticsFile); } } // For child processes. else { // Execute exit. - foreach (static::$_workers as $worker) { + foreach (static::$workers as $worker) { if(!$worker->stopping){ $worker->stop(); $worker->stopping = true; } } - if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { - static::$_workers = []; + if (!static::$gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { + static::$workers = []; if (static::$globalEvent) { static::$globalEvent->stop(); } @@ -1857,10 +1857,10 @@ public static function stopAll($code = 0, $log = '') */ public static function checkIfChildRunning() { - foreach (static::$_pidMap as $worker_id => $worker_pid_array) { + foreach (static::$pidMap as $worker_id => $worker_pid_array) { foreach ($worker_pid_array as $pid => $worker_pid) { if (!\posix_kill($pid, 0)) { - unset(static::$_pidMap[$worker_id][$pid]); + unset(static::$pidMap[$worker_id][$pid]); } } } @@ -1873,7 +1873,7 @@ public static function checkIfChildRunning() */ public static function getStatus() { - return static::$_status; + return static::$status; } /** @@ -1883,7 +1883,7 @@ public static function getStatus() */ public static function getGracefulStop() { - return static::$_gracefulStop; + return static::$gracefulStop; } /** @@ -1894,56 +1894,56 @@ public static function getGracefulStop() protected static function writeStatisticsToStatusFile() { // For master process. - if (static::$_masterPid === \posix_getpid()) { + if (static::$masterPid === \posix_getpid()) { $all_worker_info = []; - foreach(static::$_pidMap as $worker_id => $pid_array) { + foreach(static::$pidMap as $worker_id => $pid_array) { /** @var /Workerman/Worker $worker */ - $worker = static::$_workers[$worker_id]; + $worker = static::$workers[$worker_id]; foreach($pid_array as $pid) { $all_worker_info[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } - \file_put_contents(static::$_statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); + \file_put_contents(static::$statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2,2,2]) : ['-', '-', '-']; - \file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$statisticsFile, 'Workerman version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, 'start time:' . \date('Y-m-d H:i:s', - static::$_globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$_globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", + \file_put_contents(static::$statisticsFile, 'start time:' . \date('Y-m-d H:i:s', + static::$globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); $load_str = 'load average: ' . \implode(", ", $loadavg); - \file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$statisticsFile, \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, - \count(static::$_pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", + \file_put_contents(static::$statisticsFile, + \count(static::$pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, - \str_pad('worker_name', static::$_maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); - foreach (static::$_pidMap as $worker_id => $worker_pid_array) { - $worker = static::$_workers[$worker_id]; - if (isset(static::$_globalStatistics['worker_exit_info'][$worker_id])) { - foreach (static::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { - \file_put_contents(static::$_statisticsFile, - \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad($worker_exit_status, + \file_put_contents(static::$statisticsFile, + \str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); + foreach (static::$pidMap as $worker_id => $worker_pid_array) { + $worker = static::$workers[$worker_id]; + if (isset(static::$globalStatistics['worker_exit_info'][$worker_id])) { + foreach (static::$globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { + \file_put_contents(static::$statisticsFile, + \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad($worker_exit_status, 16) . " $worker_exit_count\n", \FILE_APPEND); } } else { - \file_put_contents(static::$_statisticsFile, - \str_pad($worker->name, static::$_maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", + \file_put_contents(static::$statisticsFile, + \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", \FILE_APPEND); } } - \file_put_contents(static::$_statisticsFile, + \file_put_contents(static::$statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, - "pid\tmemory " . \str_pad('listening', static::$_maxSocketNameLength) . " " . \str_pad('worker_name', - static::$_maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " + \file_put_contents(static::$statisticsFile, + "pid\tmemory " . \str_pad('listening', static::$maxSocketNameLength) . " " . \str_pad('worker_name', + static::$maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", \FILE_APPEND); - \chmod(static::$_statisticsFile, 0722); + \chmod(static::$statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { \posix_kill($worker_pid, \SIGIOT); @@ -1956,18 +1956,18 @@ protected static function writeStatisticsToStatusFile() if (\function_exists('gc_mem_caches')) { \gc_mem_caches(); } - \reset(static::$_workers); + \reset(static::$workers); /** @var static $worker */ - $worker = current(static::$_workers); + $worker = current(static::$workers); $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) - . " " . \str_pad($worker->getSocketName(), static::$_maxSocketNameLength) . " " - . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$_maxWorkerNameLength) + . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " + . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - \file_put_contents(static::$_statisticsFile, $worker_status_str, \FILE_APPEND); + \file_put_contents(static::$statisticsFile, $worker_status_str, \FILE_APPEND); } /** @@ -1978,10 +1978,10 @@ protected static function writeStatisticsToStatusFile() protected static function writeConnectionsStatisticsToStatusFile() { // For master process. - if (static::$_masterPid === \posix_getpid()) { - \file_put_contents(static::$_statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); - \file_put_contents(static::$_statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); - \chmod(static::$_statisticsFile, 0722); + if (static::$masterPid === \posix_getpid()) { + \file_put_contents(static::$statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); + \file_put_contents(static::$statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); + \chmod(static::$statisticsFile, 0722); foreach (static::getAllWorkerPids() as $worker_pid) { \posix_kill($worker_pid, \SIGIO); } @@ -2008,8 +2008,8 @@ protected static function writeConnectionsStatisticsToStatusFile() $pid = \posix_getpid(); $str = ''; - \reset(static::$_workers); - $current_worker = current(static::$_workers); + \reset(static::$workers); + $current_worker = current(static::$workers); $default_worker_name = $current_worker->name; /** @var static $worker */ @@ -2044,7 +2044,7 @@ protected static function writeConnectionsStatisticsToStatusFile() . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n"; } if ($str) { - \file_put_contents(static::$_statisticsFile, $str, \FILE_APPEND); + \file_put_contents(static::$statisticsFile, $str, \FILE_APPEND); } } @@ -2055,7 +2055,7 @@ protected static function writeConnectionsStatisticsToStatusFile() */ public static function checkErrors() { - if (static::STATUS_SHUTDOWN !== static::$_status) { + if (static::STATUS_SHUTDOWN !== static::$status) { $error_msg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === \E_ERROR || @@ -2112,7 +2112,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool } if (!$decorated) { $line = $white = $green = $end = ''; - if (static::$_outputDecorated) { + if (static::$outputDecorated) { $line = "\033[1A\n\033[K"; $white = "\033[47;30m"; $green = "\033[32;40m"; @@ -2120,7 +2120,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool } $msg = \str_replace(['', '', ''], [$line, $white, $green], $msg); $msg = \str_replace(['', '', '
'], $end, $msg); - } elseif (!static::$_outputDecorated) { + } elseif (!static::$outputDecorated) { return false; } \fwrite($stream, $msg); @@ -2137,7 +2137,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool private static function outputStream($stream = null) { if (!$stream) { - $stream = static::$_outputStream ?: \STDOUT; + $stream = static::$outputStream ?: \STDOUT; } if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { return false; @@ -2148,14 +2148,14 @@ private static function outputStream($stream = null) } if (($stat['mode'] & 0170000) === 0100000) { // whether is regular file - static::$_outputDecorated = false; + static::$outputDecorated = false; } else { - static::$_outputDecorated = + static::$outputDecorated = \DIRECTORY_SEPARATOR === '/' && // linux or unix \function_exists('posix_isatty') && \posix_isatty($stream); // whether is interactive terminal } - return static::$_outputStream = $stream; + return static::$outputStream = $stream; } /** @@ -2168,16 +2168,16 @@ public function __construct(string $socket_name = null, array $context_option = { // Save all worker instances. $this->workerId = \spl_object_hash($this); - static::$_workers[$this->workerId] = $this; - static::$_pidMap[$this->workerId] = []; + static::$workers[$this->workerId] = $this; + static::$pidMap[$this->workerId] = []; // Context for socket. if ($socket_name) { - $this->_socketName = $socket_name; + $this->socketName = $socket_name; if (!isset($context_option['socket']['backlog'])) { $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; } - $this->_context = \stream_context_create($context_option); + $this->context = \stream_context_create($context_option); } // Try to turn reusePort on. @@ -2212,11 +2212,11 @@ public function __construct(string $socket_name = null, array $context_option = */ public function listen() { - if (!$this->_socketName) { + if (!$this->socketName) { return; } - if (!$this->_mainSocket) { + if (!$this->mainSocket) { $local_socket = $this->parseSocketAddress(); @@ -2226,17 +2226,17 @@ public function listen() $errmsg = ''; // SO_REUSEPORT. if ($this->reusePort) { - \stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); + \stream_context_set_option($this->context, 'socket', 'so_reuseport', 1); } // Create an Internet or Unix domain server socket. - $this->_mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); - if (!$this->_mainSocket) { + $this->mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->context); + if (!$this->mainSocket) { throw new Exception($errmsg); } if ($this->transport === 'ssl') { - \stream_socket_enable_crypto($this->_mainSocket, false); + \stream_socket_enable_crypto($this->mainSocket, false); } elseif ($this->transport === 'unix') { $socket_file = \substr($local_socket, 7); if ($this->user) { @@ -2250,14 +2250,14 @@ public function listen() // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { \set_error_handler(function(){}); - $socket = \socket_import_stream($this->_mainSocket); + $socket = \socket_import_stream($this->mainSocket); \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1); \restore_error_handler(); } // Non blocking. - \stream_set_blocking($this->_mainSocket, false); + \stream_set_blocking($this->mainSocket, false); } $this->resumeAccept(); @@ -2270,11 +2270,11 @@ public function listen() */ public function unlisten() { $this->pauseAccept(); - if ($this->_mainSocket) { + if ($this->mainSocket) { \set_error_handler(function(){}); - \fclose($this->_mainSocket); + \fclose($this->mainSocket); \restore_error_handler(); - $this->_mainSocket = null; + $this->mainSocket = null; } } @@ -2284,11 +2284,11 @@ public function unlisten() { * @throws Exception */ protected function parseSocketAddress() { - if (!$this->_socketName) { + if (!$this->socketName) { return; } // Get the application layer communication protocol and listening address. - list($scheme, $address) = \explode(':', $this->_socketName, 2); + list($scheme, $address) = \explode(':', $this->socketName, 2); // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { $scheme = \ucfirst($scheme); @@ -2319,9 +2319,9 @@ protected function parseSocketAddress() { */ public function pauseAccept() { - if (static::$globalEvent && false === $this->_pauseAccept && $this->_mainSocket) { - static::$globalEvent->offReadable($this->_mainSocket); - $this->_pauseAccept = true; + if (static::$globalEvent && false === $this->pauseAccept && $this->mainSocket) { + static::$globalEvent->offReadable($this->mainSocket); + $this->pauseAccept = true; } } @@ -2333,13 +2333,13 @@ public function pauseAccept() public function resumeAccept() { // Register a listener to be notified when server socket is ready to read. - if (static::$globalEvent && true === $this->_pauseAccept && $this->_mainSocket) { + if (static::$globalEvent && true === $this->pauseAccept && $this->mainSocket) { if ($this->transport !== 'udp') { - static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptTcpConnection']); + static::$globalEvent->onReadable($this->mainSocket, [$this, 'acceptTcpConnection']); } else { - static::$globalEvent->onReadable($this->_mainSocket, [$this, 'acceptUdpConnection']); + static::$globalEvent->onReadable($this->mainSocket, [$this, 'acceptUdpConnection']); } - $this->_pauseAccept = false; + $this->pauseAccept = false; } } @@ -2350,7 +2350,7 @@ public function resumeAccept() */ public function getSocketName() { - return $this->_socketName ? \lcfirst($this->_socketName) : 'none'; + return $this->socketName ? \lcfirst($this->socketName) : 'none'; } /** @@ -2361,7 +2361,7 @@ public function getSocketName() public function run() { //Update process state. - static::$_status = static::STATUS_RUNNING; + static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); @@ -2419,7 +2419,7 @@ public function stop() // Remove listener for server socket. $this->unlisten(); // Close all connections for the worker. - if (!static::$_gracefulStop) { + if (!static::$gracefulStop) { foreach ($this->connections as $connection) { $connection->close(); } From c229f936dc16f11bb767a779c0120a9f7bb57736 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 18:58:53 +0800 Subject: [PATCH 0780/1216] Variable use camel --- src/Connection/AsyncTcpConnection.php | 46 +- src/Connection/AsyncUdpConnection.php | 26 +- src/Connection/ConnectionInterface.php | 4 +- src/Connection/TcpConnection.php | 52 +- src/Connection/UdpConnection.php | 16 +- src/Events/Ev.php | 38 +- src/Events/Event.php | 90 +-- src/Events/EventInterface.php | 4 +- src/Events/Revolt.php | 92 +-- src/Events/Select.php | 126 ++-- src/Events/Swoole.php | 26 +- src/Events/Swow.php | 24 +- src/Protocols/Frame.php | 8 +- src/Protocols/Http.php | 102 ++-- src/Protocols/Http/Request.php | 222 +++---- src/Protocols/Http/Response.php | 56 +- src/Protocols/Http/Session.php | 46 +- .../Http/Session/FileSessionHandler.php | 56 +- .../Session/RedisClusterSessionHandler.php | 8 +- .../Http/Session/RedisSessionHandler.php | 16 +- .../Http/Session/SessionHandlerInterface.php | 18 +- src/Protocols/ProtocolInterface.php | 8 +- src/Protocols/Websocket.php | 162 +++--- src/Protocols/Ws.php | 138 ++--- src/Timer.php | 54 +- src/Worker.php | 542 +++++++++--------- 26 files changed, 990 insertions(+), 990 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index df800d3e3..2df5baf54 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -120,39 +120,39 @@ class AsyncTcpConnection extends TcpConnection /** * Construct. * - * @param string $remote_address - * @param array $context_option + * @param string $remoteAddress + * @param array $contextOption * @throws Exception */ - public function __construct($remote_address, array $context_option = []) + public function __construct($remoteAddress, array $contextOption = []) { - $address_info = \parse_url($remote_address); - if (!$address_info) { - list($scheme, $this->remoteAddress) = \explode(':', $remote_address, 2); + $addressInfo = \parse_url($remoteAddress); + if (!$addressInfo) { + list($scheme, $this->remoteAddress) = \explode(':', $remoteAddress, 2); if ('unix' === strtolower($scheme)) { - $this->remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2); + $this->remoteAddress = substr($remoteAddress, strpos($remoteAddress, '/') + 2); } if (!$this->remoteAddress) { Worker::safeEcho(new \Exception('bad remote_address')); } } else { - if (!isset($address_info['port'])) { - $address_info['port'] = 0; + if (!isset($addressInfo['port'])) { + $addressInfo['port'] = 0; } - if (!isset($address_info['path'])) { - $address_info['path'] = '/'; + if (!isset($addressInfo['path'])) { + $addressInfo['path'] = '/'; } - if (!isset($address_info['query'])) { - $address_info['query'] = ''; + if (!isset($addressInfo['query'])) { + $addressInfo['query'] = ''; } else { - $address_info['query'] = '?' . $address_info['query']; + $addressInfo['query'] = '?' . $addressInfo['query']; } - $this->remoteHost = $address_info['host']; - $this->remotePort = $address_info['port']; - $this->remoteURI = "{$address_info['path']}{$address_info['query']}"; - $scheme = $address_info['scheme'] ?? 'tcp'; + $this->remoteHost = $addressInfo['host']; + $this->remotePort = $addressInfo['port']; + $this->remoteURI = "{$addressInfo['path']}{$addressInfo['query']}"; + $scheme = $addressInfo['scheme'] ?? 'tcp'; $this->remoteAddress = 'unix' === strtolower($scheme) - ? substr($remote_address, strpos($remote_address, '/') + 2) + ? substr($remoteAddress, strpos($remoteAddress, '/') + 2) : $this->remoteHost . ':' . $this->remotePort; } @@ -178,7 +178,7 @@ public function __construct($remote_address, array $context_option = []) ++self::$statistics['connection_count']; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->contextOption = $context_option; + $this->contextOption = $contextOption; static::$connections[$this->realId] = $this; } @@ -348,9 +348,9 @@ public function checkConnection() } // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && $this->transport === 'tcp') { - $raw_socket = \socket_import_stream($this->socket); - \socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); - \socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1); + $rawSocket = \socket_import_stream($this->socket); + \socket_set_option($rawSocket, \SOL_SOCKET, \SO_KEEPALIVE, 1); + \socket_set_option($rawSocket, \SOL_TCP, \TCP_NODELAY, 1); } // SSL handshake. if ($this->transport === 'ssl') { diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index c32fc013c..be619b817 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -54,13 +54,13 @@ class AsyncUdpConnection extends UdpConnection /** * Construct. * - * @param string $remote_address + * @param string $remoteAddress * @throws Exception */ - public function __construct($remote_address, $context_option = null) + public function __construct($remoteAddress, $contextOption = null) { // Get the application layer communication protocol and listening address. - list($scheme, $address) = \explode(':', $remote_address, 2); + list($scheme, $address) = \explode(':', $remoteAddress, 2); // Check application layer protocol class. if ($scheme !== 'udp') { $scheme = \ucfirst($scheme); @@ -74,7 +74,7 @@ public function __construct($remote_address, $context_option = null) } $this->remoteAddress = \substr($address, 2); - $this->contextOption = $context_option; + $this->contextOption = $contextOption; } /** @@ -85,18 +85,18 @@ public function __construct($remote_address, $context_option = null) */ public function baseRead($socket) { - $recv_buffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); - if (false === $recv_buffer || empty($remote_address)) { + $recvBuffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); + if (false === $recvBuffer || empty($remoteAddress)) { return false; } if ($this->onMessage) { if ($this->protocol) { - $recv_buffer = $this->protocol::decode($recv_buffer, $this); + $recvBuffer = $this->protocol::decode($recvBuffer, $this); } ++ConnectionInterface::$statistics['total_request']; try { - ($this->onMessage)($this, $recv_buffer); + ($this->onMessage)($this, $recvBuffer); } catch (\Throwable $e) { Worker::stopAll(250, $e); } @@ -107,23 +107,23 @@ public function baseRead($socket) /** * Sends data on the connection. * - * @param string $send_buffer + * @param string $sendBuffer * @param bool $raw * @return void|boolean */ - public function send($send_buffer, $raw = false) + public function send($sendBuffer, $raw = false) { if (false === $raw && $this->protocol) { $parser = $this->protocol; - $send_buffer = $parser::encode($send_buffer, $this); - if ($send_buffer === '') { + $sendBuffer = $parser::encode($sendBuffer, $this); + if ($sendBuffer === '') { return; } } if ($this->connected === false) { $this->connect(); } - return \strlen($send_buffer) === \stream_socket_sendto($this->socket, $send_buffer, 0); + return \strlen($sendBuffer) === \stream_socket_sendto($this->socket, $sendBuffer, 0); } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 2a0c41528..865ff586e 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -77,10 +77,10 @@ abstract class ConnectionInterface /** * Sends data on the connection. * - * @param mixed $send_buffer + * @param mixed $sendBuffer * @return void|boolean */ - abstract public function send($send_buffer); + abstract public function send($sendBuffer); /** * Get remote IP. diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index ff93829e0..7fb4c69b0 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -280,9 +280,9 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remoteAddress */ - public function __construct($socket, $remote_address = '') + public function __construct($socket, $remoteAddress = '') { ++self::$statistics['connection_count']; $this->id = $this->realId = self::$idRecorder++; @@ -298,7 +298,7 @@ public function __construct($socket, $remote_address = '') Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->remoteAddress = $remote_address; + $this->remoteAddress = $remoteAddress; static::$connections[$this->id] = $this; $this->context = new \stdClass; } @@ -306,13 +306,13 @@ public function __construct($socket, $remote_address = '') /** * Get status. * - * @param bool $raw_output + * @param bool $rawOutput * * @return int|string */ - public function getStatus($raw_output = true) + public function getStatus($rawOutput = true) { - if ($raw_output) { + if ($rawOutput) { return $this->status; } return self::$statusToString[$this->status]; @@ -321,20 +321,20 @@ public function getStatus($raw_output = true) /** * Sends data on the connection. * - * @param mixed $send_buffer + * @param mixed $sendBuffer * @param bool $raw * @return bool|null */ - public function send($send_buffer, $raw = false) + public function send($sendBuffer, $raw = false) { if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return false; } - // Try to call protocol::encode($send_buffer) before sending. + // Try to call protocol::encode($sendBuffer) before sending. if (false === $raw && $this->protocol !== null) { - $send_buffer = $this->protocol::encode($send_buffer, $this); - if ($send_buffer === '') { + $sendBuffer = $this->protocol::encode($sendBuffer, $this); + if ($sendBuffer === '') { return; } } @@ -346,7 +346,7 @@ public function send($send_buffer, $raw = false) ++self::$statistics['send_fail']; return false; } - $this->sendBuffer .= $send_buffer; + $this->sendBuffer .= $sendBuffer; $this->checkBufferWillFull(); return; } @@ -355,24 +355,24 @@ public function send($send_buffer, $raw = false) if ($this->sendBuffer === '') { if ($this->transport === 'ssl') { Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); - $this->sendBuffer = $send_buffer; + $this->sendBuffer = $sendBuffer; $this->checkBufferWillFull(); return; } $len = 0; try { - $len = @\fwrite($this->socket, $send_buffer); + $len = @\fwrite($this->socket, $sendBuffer); } catch (\Throwable $e) { Worker::log($e); } // send successful. - if ($len === \strlen($send_buffer)) { + if ($len === \strlen($sendBuffer)) { $this->bytesWritten += $len; return true; } // Send only part of the data. if ($len > 0) { - $this->sendBuffer = \substr($send_buffer, $len); + $this->sendBuffer = \substr($sendBuffer, $len); $this->bytesWritten += $len; } else { // Connection closed? @@ -388,7 +388,7 @@ public function send($send_buffer, $raw = false) $this->destroy(); return false; } - $this->sendBuffer = $send_buffer; + $this->sendBuffer = $sendBuffer; } Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); // Check if the send buffer will be full. @@ -401,7 +401,7 @@ public function send($send_buffer, $raw = false) return false; } - $this->sendBuffer .= $send_buffer; + $this->sendBuffer .= $sendBuffer; // Check if the send buffer is full. $this->checkBufferWillFull(); } @@ -562,10 +562,10 @@ public function resumeRecv() * Base read handler. * * @param resource $socket - * @param bool $check_eof + * @param bool $checkEof * @return void */ - public function baseRead($socket, $check_eof = true) + public function baseRead($socket, $checkEof = true) { static $requests = []; // SSL handshake. @@ -588,7 +588,7 @@ public function baseRead($socket, $check_eof = true) // Check connection closed. if ($buffer === '' || $buffer === false) { - if ($check_eof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) { + if ($checkEof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) { $this->destroy(); return; } @@ -653,11 +653,11 @@ public function baseRead($socket, $check_eof = true) ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. if ($one = \strlen($this->recvBuffer) === $this->currentPackageLength) { - $one_request_buffer = $this->recvBuffer; + $oneRequestBuffer = $this->recvBuffer; $this->recvBuffer = ''; } else { // Get a full package from the buffer. - $one_request_buffer = \substr($this->recvBuffer, 0, $this->currentPackageLength); + $oneRequestBuffer = \substr($this->recvBuffer, 0, $this->currentPackageLength); // Remove the current package from the receive buffer. $this->recvBuffer = \substr($this->recvBuffer, $this->currentPackageLength); } @@ -665,9 +665,9 @@ public function baseRead($socket, $check_eof = true) $this->currentPackageLength = 0; try { // Decode request buffer before Emitting onMessage callback. - $request = $this->protocol::decode($one_request_buffer, $this); - if (static::$enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($one_request_buffer[512])) { - $requests[$one_request_buffer] = $request; + $request = $this->protocol::decode($oneRequestBuffer, $this); + if (static::$enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) { + $requests[$oneRequestBuffer] = $request; if (\count($requests) > 512) { unset($requests[\key($requests)]); } diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 3191e589d..6a1994dc8 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -52,31 +52,31 @@ class UdpConnection extends ConnectionInterface implements \JsonSerializable * Construct. * * @param resource $socket - * @param string $remote_address + * @param string $remoteAddress */ - public function __construct($socket, $remote_address) + public function __construct($socket, $remoteAddress) { $this->socket = $socket; - $this->remoteAddress = $remote_address; + $this->remoteAddress = $remoteAddress; } /** * Sends data on the connection. * - * @param string $send_buffer + * @param string $sendBuffer * @param bool $raw * @return void|boolean */ - public function send($send_buffer, $raw = false) + public function send($sendBuffer, $raw = false) { if (false === $raw && $this->protocol) { $parser = $this->protocol; - $send_buffer = $parser::encode($send_buffer, $this); - if ($send_buffer === '') { + $sendBuffer = $parser::encode($sendBuffer, $this); + if ($sendBuffer === '') { return; } } - return \strlen($send_buffer) === \stream_socket_sendto($this->socket, $send_buffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); + return \strlen($sendBuffer) === \stream_socket_sendto($this->socket, $sendBuffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); } /** diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 8fc99e762..0d0488e82 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -61,9 +61,9 @@ class Ev implements EventInterface */ public function delay(float $delay, $func, $args) { - $timer_id = self::$timerId; - $event = new \EvTimer($delay, 0, function () use ($func, $args, $timer_id) { - unset($this->eventTimer[$timer_id]); + $timerId = self::$timerId; + $event = new \EvTimer($delay, 0, function () use ($func, $args, $timerId) { + unset($this->eventTimer[$timerId]); $func(...(array)$args); }); $this->eventTimer[self::$timerId] = $event; @@ -73,11 +73,11 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { - $this->eventTimer[$timer_id]->stop(); - unset($this->eventTimer[$timer_id]); + if (isset($this->eventTimer[$timerId])) { + $this->eventTimer[$timerId]->stop(); + unset($this->eventTimer[$timerId]); return true; } return false; @@ -100,11 +100,11 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $fd_key = (int)$stream; + $fdKey = (int)$stream; $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) { $func($stream); }); - $this->readEvents[$fd_key] = $event; + $this->readEvents[$fdKey] = $event; } /** @@ -112,10 +112,10 @@ public function onReadable($stream, $func) */ public function offReadable($stream) { - $fd_key = (int)$stream; - if (isset($this->readEvents[$fd_key])) { - $this->readEvents[$fd_key]->stop(); - unset($this->readEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->readEvents[$fdKey])) { + $this->readEvents[$fdKey]->stop(); + unset($this->readEvents[$fdKey]); } } @@ -124,11 +124,11 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $fd_key = (int)$stream; + $fdKey = (int)$stream; $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { $func($stream); }); - $this->readEvents[$fd_key] = $event; + $this->readEvents[$fdKey] = $event; } /** @@ -136,10 +136,10 @@ public function onWritable($stream, $func) */ public function offWritable($stream) { - $fd_key = (int)$stream; - if (isset($this->writeEvents[$fd_key])) { - $this->writeEvents[$fd_key]->stop(); - unset($this->writeEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->writeEvents[$fdKey])) { + $this->writeEvents[$fdKey]->stop(); + unset($this->writeEvents[$fdKey]); } } diff --git a/src/Events/Event.php b/src/Events/Event.php index cd21f1a97..338ebe64a 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -71,17 +71,17 @@ class Event implements EventInterface public function __construct() { if (\class_exists('\\\\Event', false)) { - $class_name = '\\\\Event'; + $className = '\\\\Event'; } else { - $class_name = '\Event'; + $className = '\Event'; } - $this->eventClassName = $class_name; + $this->eventClassName = $className; if (\class_exists('\\\\EventBase', false)) { - $class_name = '\\\\EventBase'; + $className = '\\\\EventBase'; } else { - $class_name = '\EventBase'; + $className = '\EventBase'; } - $this->eventBase = new $class_name(); + $this->eventBase = new $className(); } /** @@ -89,11 +89,11 @@ public function __construct() */ public function delay(float $delay, $func, $args) { - $class_name = $this->eventClassName; - $timer_id = $this->timerId++; - $event = new $class_name($this->eventBase, -1, $class_name::TIMEOUT, function () use ($func, $args, $timer_id) { + $className = $this->eventClassName; + $timerId = $this->timerId++; + $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args, $timerId) { try { - $this->deleteTimer($timer_id); + $this->deleteTimer($timerId); $func(...$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); @@ -102,18 +102,18 @@ public function delay(float $delay, $func, $args) if (!$event || !$event->addTimer($delay)) { return false; } - $this->eventTimer[$timer_id] = $event; - return $timer_id; + $this->eventTimer[$timerId] = $event; + return $timerId; } /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { - $this->eventTimer[$timer_id]->del(); - unset($this->eventTimer[$timer_id]); + if (isset($this->eventTimer[$timerId])) { + $this->eventTimer[$timerId]->del(); + unset($this->eventTimer[$timerId]); return true; } return false; @@ -124,9 +124,9 @@ public function deleteTimer($timer_id) */ public function repeat(float $interval, $func, $args) { - $class_name = $this->eventClassName; - $timer_id = $this->timerId++; - $event = new $class_name($this->eventBase, -1, $class_name::TIMEOUT | $class_name::PERSIST, function () use ($func, $args) { + $className = $this->eventClassName; + $timerId = $this->timerId++; + $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, function () use ($func, $args) { try { $func(...$args); } catch (\Throwable $e) { @@ -136,8 +136,8 @@ public function repeat(float $interval, $func, $args) if (!$event || !$event->addTimer($interval)) { return false; } - $this->eventTimer[$timer_id] = $event; - return $timer_id; + $this->eventTimer[$timerId] = $event; + return $timerId; } /** @@ -145,13 +145,13 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $class_name = $this->eventClassName; - $fd_key = (int)$stream; - $event = new $this->eventClassName($this->eventBase, $stream, $class_name::READ | $class_name::PERSIST, $func, $stream); + $className = $this->eventClassName; + $fdKey = (int)$stream; + $event = new $this->eventClassName($this->eventBase, $stream, $className::READ | $className::PERSIST, $func, $stream); if (!$event || !$event->add()) { return false; } - $this->writeEvents[$fd_key] = $event; + $this->writeEvents[$fdKey] = $event; return true; } @@ -160,10 +160,10 @@ public function onReadable($stream, $func) */ public function offReadable($stream) { - $fd_key = (int)$stream; - if (isset($this->readEvents[$fd_key])) { - $this->readEvents[$fd_key]->del(); - unset($this->readEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->readEvents[$fdKey])) { + $this->readEvents[$fdKey]->del(); + unset($this->readEvents[$fdKey]); } } @@ -172,13 +172,13 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $class_name = $this->eventClassName; - $fd_key = (int)$stream; - $event = new $this->eventClassName($this->eventBase, $stream, $class_name::WRITE | $class_name::PERSIST, $func, $stream); + $className = $this->eventClassName; + $fdKey = (int)$stream; + $event = new $this->eventClassName($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func, $stream); if (!$event || !$event->add()) { return false; } - $this->writeEvents[$fd_key] = $event; + $this->writeEvents[$fdKey] = $event; return true; } @@ -187,10 +187,10 @@ public function onWritable($stream, $func) */ public function offWritable($stream) { - $fd_key = (int)$stream; - if (isset($this->writeEvents[$fd_key])) { - $this->writeEvents[$fd_key]->del(); - unset($this->writeEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->writeEvents[$fdKey])) { + $this->writeEvents[$fdKey]->del(); + unset($this->writeEvents[$fdKey]); } } @@ -199,13 +199,13 @@ public function offWritable($stream) */ public function onSignal($signal, $func) { - $class_name = $this->eventClassName; - $fd_key = (int)$signal; - $event = $class_name::signal($this->eventBase, $signal, $func); + $className = $this->eventClassName; + $fdKey = (int)$signal; + $event = $className::signal($this->eventBase, $signal, $func); if (!$event || !$event->add()) { return false; } - $this->eventSignal[$fd_key] = $event; + $this->eventSignal[$fdKey] = $event; return true; } @@ -214,10 +214,10 @@ public function onSignal($signal, $func) */ public function offSignal($signal) { - $fd_key = (int)$signal; - if (isset($this->eventSignal[$fd_key])) { - $this->eventSignal[$fd_key]->del(); - unset($this->eventSignal[$fd_key]); + $fdKey = (int)$signal; + if (isset($this->eventSignal[$fdKey])) { + $this->eventSignal[$fdKey]->del(); + unset($this->eventSignal[$fdKey]); } } diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 9a5c8bba8..63f27890e 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -35,10 +35,10 @@ public function repeat(float $interval, $func, $args); /** * Delete a timer. - * @param $timer_id + * @param $timerId * @return bool */ - public function deleteTimer($timer_id); + public function deleteTimer($timerId); /** * Execute a callback when a stream resource becomes readable or is closed for reading. diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 62dee9c5d..3bf74bfc9 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -86,8 +86,8 @@ public function run() */ public function stop() { - foreach ($this->eventSignal as $cb_id) { - $this->driver->cancel($cb_id); + foreach ($this->eventSignal as $cbId) { + $this->driver->cancel($cbId); } $this->driver->stop(); pcntl_signal(SIGINT, SIG_IGN); @@ -99,14 +99,14 @@ public function stop() public function delay(float $delay, $func, $args) { $args = (array)$args; - $timer_id = $this->timerId++; - $closure = function () use ($func, $args, $timer_id) { - unset($this->eventTimer[$timer_id]); + $timerId = $this->timerId++; + $closure = function () use ($func, $args, $timerId) { + unset($this->eventTimer[$timerId]); $func(...$args); }; - $cb_id = $this->driver->delay($delay, $closure); - $this->eventTimer[$timer_id] = $cb_id; - return $timer_id; + $cbId = $this->driver->delay($delay, $closure); + $this->eventTimer[$timerId] = $cbId; + return $timerId; } /** @@ -115,13 +115,13 @@ public function delay(float $delay, $func, $args) public function repeat(float $interval, $func, $args) { $args = (array)$args; - $timer_id = $this->timerId++; - $closure = function () use ($func, $args, $timer_id) { + $timerId = $this->timerId++; + $closure = function () use ($func, $args, $timerId) { $func(...$args); }; - $cb_id = $this->driver->repeat($interval, $closure); - $this->eventTimer[$timer_id] = $cb_id; - return $timer_id; + $cbId = $this->driver->repeat($interval, $closure); + $this->eventTimer[$timerId] = $cbId; + return $timerId; } /** @@ -129,13 +129,13 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $fd_key = (int)$stream; - if (isset($this->readEvents[$fd_key])) { - $this->driver->cancel($this->readEvents[$fd_key]); - unset($this->readEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->readEvents[$fdKey])) { + $this->driver->cancel($this->readEvents[$fdKey]); + unset($this->readEvents[$fdKey]); } - $this->readEvents[$fd_key] = $this->driver->onReadable($stream, function () use ($stream, $func) { + $this->readEvents[$fdKey] = $this->driver->onReadable($stream, function () use ($stream, $func) { $func($stream); }); } @@ -145,10 +145,10 @@ public function onReadable($stream, $func) */ public function offReadable($stream) { - $fd_key = (int)$stream; - if (isset($this->readEvents[$fd_key])) { - $this->driver->cancel($this->readEvents[$fd_key]); - unset($this->readEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->readEvents[$fdKey])) { + $this->driver->cancel($this->readEvents[$fdKey]); + unset($this->readEvents[$fdKey]); } } @@ -157,12 +157,12 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $fd_key = (int)$stream; - if (isset($this->writeEvents[$fd_key])) { - $this->driver->cancel($this->writeEvents[$fd_key]); - unset($this->writeEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->writeEvents[$fdKey])) { + $this->driver->cancel($this->writeEvents[$fdKey]); + unset($this->writeEvents[$fdKey]); } - $this->writeEvents[$fd_key] = $this->driver->onWritable($stream, function () use ($stream, $func) { + $this->writeEvents[$fdKey] = $this->driver->onWritable($stream, function () use ($stream, $func) { $func($stream); }); } @@ -172,10 +172,10 @@ public function onWritable($stream, $func) */ public function offWritable($stream) { - $fd_key = (int)$stream; - if (isset($this->writeEvents[$fd_key])) { - $this->driver->cancel($this->writeEvents[$fd_key]); - unset($this->writeEvents[$fd_key]); + $fdKey = (int)$stream; + if (isset($this->writeEvents[$fdKey])) { + $this->driver->cancel($this->writeEvents[$fdKey]); + unset($this->writeEvents[$fdKey]); } } @@ -184,12 +184,12 @@ public function offWritable($stream) */ public function onSignal($signal, $func) { - $fd_key = (int)$signal; - if (isset($this->eventSignal[$fd_key])) { - $this->driver->cancel($this->eventSignal[$fd_key]); - unset($this->eventSignal[$fd_key]); + $fdKey = (int)$signal; + if (isset($this->eventSignal[$fdKey])) { + $this->driver->cancel($this->eventSignal[$fdKey]); + unset($this->eventSignal[$fdKey]); } - $this->eventSignal[$fd_key] = $this->driver->onSignal($signal, function () use ($signal, $func) { + $this->eventSignal[$fdKey] = $this->driver->onSignal($signal, function () use ($signal, $func) { $func($signal); }); } @@ -199,21 +199,21 @@ public function onSignal($signal, $func) */ public function offSignal($signal) { - $fd_key = (int)$signal; - if (isset($this->eventSignal[$fd_key])) { - $this->driver->cancel($this->eventSignal[$fd_key]); - unset($this->eventSignal[$fd_key]); + $fdKey = (int)$signal; + if (isset($this->eventSignal[$fdKey])) { + $this->driver->cancel($this->eventSignal[$fdKey]); + unset($this->eventSignal[$fdKey]); } } /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { - $this->driver->cancel($this->eventTimer[$timer_id]); - unset($this->eventTimer[$timer_id]); + if (isset($this->eventTimer[$timerId])) { + $this->driver->cancel($this->eventTimer[$timerId]); + unset($this->eventTimer[$timerId]); return true; } return false; @@ -224,8 +224,8 @@ public function deleteTimer($timer_id) */ public function deleteAllTimer() { - foreach ($this->eventTimer as $cb_id) { - $this->driver->cancel($cb_id); + foreach ($this->eventTimer as $cbId) { + $this->driver->cancel($cbId); } $this->eventTimer = []; } diff --git a/src/Events/Select.php b/src/Events/Select.php index 1b8c67f2f..3e89a1824 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -114,16 +114,16 @@ public function __construct() */ public function delay(float $delay, $func, $args) { - $timer_id = $this->timerId++; - $run_time = \microtime(true) + $delay; - $this->scheduler->insert($timer_id, -$run_time); - $this->eventTimer[$timer_id] = [$func, (array)$args]; - $select_timeout = ($run_time - \microtime(true)) * 1000000; - $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; - if ($this->selectTimeout > $select_timeout) { - $this->selectTimeout = $select_timeout; + $timerId = $this->timerId++; + $runTime = \microtime(true) + $delay; + $this->scheduler->insert($timerId, -$runTime); + $this->eventTimer[$timerId] = [$func, (array)$args]; + $selectTimeout = ($runTime - \microtime(true)) * 1000000; + $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; + if ($this->selectTimeout > $selectTimeout) { + $this->selectTimeout = $selectTimeout; } - return $timer_id; + return $timerId; } /** @@ -131,25 +131,25 @@ public function delay(float $delay, $func, $args) */ public function repeat(float $delay, $func, $args) { - $timer_id = $this->timerId++; - $run_time = \microtime(true) + $delay; - $this->scheduler->insert($timer_id, -$run_time); - $this->eventTimer[$timer_id] = [$func, (array)$args, $delay]; - $select_timeout = ($run_time - \microtime(true)) * 1000000; - $select_timeout = $select_timeout <= 0 ? 1 : (int)$select_timeout; - if ($this->selectTimeout > $select_timeout) { - $this->selectTimeout = $select_timeout; + $timerId = $this->timerId++; + $runTime = \microtime(true) + $delay; + $this->scheduler->insert($timerId, -$runTime); + $this->eventTimer[$timerId] = [$func, (array)$args, $delay]; + $selectTimeout = ($runTime - \microtime(true)) * 1000000; + $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; + if ($this->selectTimeout > $selectTimeout) { + $this->selectTimeout = $selectTimeout; } - return $timer_id; + return $timerId; } /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { - unset($this->eventTimer[$timer_id]); + if (isset($this->eventTimer[$timerId])) { + unset($this->eventTimer[$timerId]); return true; } return false; @@ -166,9 +166,9 @@ public function onReadable($stream, $func) } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } - $fd_key = (int)$stream; - $this->readEvents[$fd_key] = $func; - $this->readFds[$fd_key] = $stream; + $fdKey = (int)$stream; + $this->readEvents[$fdKey] = $func; + $this->readFds[$fdKey] = $stream; } /** @@ -176,8 +176,8 @@ public function onReadable($stream, $func) */ public function offReadable($stream) { - $fd_key = (int)$stream; - unset($this->readEvents[$fd_key], $this->readFds[$fd_key]); + $fdKey = (int)$stream; + unset($this->readEvents[$fdKey], $this->readFds[$fdKey]); } /** @@ -191,9 +191,9 @@ public function onWritable($stream, $func) } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } - $fd_key = (int)$stream; - $this->writeEvents[$fd_key] = $func; - $this->writeFds[$fd_key] = $stream; + $fdKey = (int)$stream; + $this->writeEvents[$fdKey] = $func; + $this->writeFds[$fdKey] = $stream; } /** @@ -201,8 +201,8 @@ public function onWritable($stream, $func) */ public function offWritable($stream) { - $fd_key = (int)$stream; - unset($this->writeEvents[$fd_key], $this->writeFds[$fd_key]); + $fdKey = (int)$stream; + unset($this->writeEvents[$fdKey], $this->writeFds[$fdKey]); } /** @@ -210,9 +210,9 @@ public function offWritable($stream) */ public function onExcept($stream, $func) { - $fd_key = (int)$stream; - $this->exceptEvents[$fd_key] = $func; - $this->exceptFds[$fd_key] = $stream; + $fdKey = (int)$stream; + $this->exceptEvents[$fdKey] = $func; + $this->exceptFds[$fdKey] = $stream; } /** @@ -220,8 +220,8 @@ public function onExcept($stream, $func) */ public function offExcept($stream) { - $fd_key = (int)$stream; - unset($this->exceptEvents[$fd_key], $this->exceptFds[$fd_key]); + $fdKey = (int)$stream; + unset($this->exceptEvents[$fdKey], $this->exceptFds[$fdKey]); } /** @@ -262,30 +262,30 @@ public function signalHandler($signal) */ protected function tick() { - $tasks_to_insert = []; + $tasksToInsert = []; while (!$this->scheduler->isEmpty()) { - $scheduler_data = $this->scheduler->top(); - $timer_id = $scheduler_data['data']; - $next_run_time = -$scheduler_data['priority']; - $time_now = \microtime(true); - $this->selectTimeout = (int)(($next_run_time - $time_now) * 1000000); + $schedulerData = $this->scheduler->top(); + $timerId = $schedulerData['data']; + $nextRunTime = -$schedulerData['priority']; + $timeNow = \microtime(true); + $this->selectTimeout = (int)(($nextRunTime - $timeNow) * 1000000); if ($this->selectTimeout <= 0) { $this->scheduler->extract(); - if (!isset($this->eventTimer[$timer_id])) { + if (!isset($this->eventTimer[$timerId])) { continue; } // [func, args, timer_interval] - $task_data = $this->eventTimer[$timer_id]; - if (isset($task_data[2])) { - $next_run_time = $time_now + $task_data[2]; - $tasks_to_insert[] = [$timer_id, -$next_run_time]; + $taskData = $this->eventTimer[$timerId]; + if (isset($taskData[2])) { + $nextRunTime = $timeNow + $taskData[2]; + $tasksToInsert[] = [$timerId, -$nextRunTime]; } else { - unset($this->eventTimer[$timer_id]); + unset($this->eventTimer[$timerId]); } try { - $task_data[0]($task_data[1]); + $taskData[0]($taskData[1]); } catch (Throwable $e) { Worker::stopAll(250, $e); } @@ -293,14 +293,14 @@ protected function tick() break; } } - foreach ($tasks_to_insert as $item) { + foreach ($tasksToInsert as $item) { $this->scheduler->insert($item[0], $item[1]); } if (!$this->scheduler->isEmpty()) { - $scheduler_data = $this->scheduler->top(); - $next_run_time = -$scheduler_data['priority']; - $time_now = \microtime(true); - $this->selectTimeout = \max((int)(($next_run_time - $time_now) * 1000000), 0); + $schedulerData = $this->scheduler->top(); + $nextRunTime = -$schedulerData['priority']; + $timeNow = \microtime(true); + $this->selectTimeout = \max((int)(($nextRunTime - $timeNow) * 1000000), 0); return; } $this->selectTimeout = 100000000; @@ -347,23 +347,23 @@ public function run() } foreach ($read as $fd) { - $fd_key = (int)$fd; - if (isset($this->readEvents[$fd_key])) { - $this->readEvents[$fd_key]($fd); + $fdKey = (int)$fd; + if (isset($this->readEvents[$fdKey])) { + $this->readEvents[$fdKey]($fd); } } foreach ($write as $fd) { - $fd_key = (int)$fd; - if (isset($this->writeEvents[$fd_key])) { - $this->writeEvents[$fd_key]($fd); + $fdKey = (int)$fd; + if (isset($this->writeEvents[$fdKey])) { + $this->writeEvents[$fdKey]($fd); } } foreach ($except as $fd) { - $fd_key = (int)$fd; - if (isset($this->exceptEvents[$fd_key])) { - $this->exceptEvents[$fd_key]($fd); + $fdKey = (int)$fd; + if (isset($this->exceptEvents[$fdKey])) { + $this->exceptEvents[$fdKey]($fd); } } } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 3a8187281..d4d3a3c44 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -45,26 +45,26 @@ public function delay(float $delay, $func, $args) { $t = (int)($delay * 1000); $t = $t < 1 ? 1 : $t; - $timer_id = Timer::after($t, function () use ($func, $args, &$timer_id) { - unset($this->eventTimer[$timer_id]); + $timerId = Timer::after($t, function () use ($func, $args, &$timerId) { + unset($this->eventTimer[$timerId]); try { $func(...(array)$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); } }); - $this->eventTimer[$timer_id] = $timer_id; - return $timer_id; + $this->eventTimer[$timerId] = $timerId; + return $timerId; } /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { - $res = Timer::clear($timer_id); - unset($this->eventTimer[$timer_id]); + if (isset($this->eventTimer[$timerId])) { + $res = Timer::clear($timerId); + unset($this->eventTimer[$timerId]); return $res; } return false; @@ -80,15 +80,15 @@ public function repeat(float $interval, $func, $args) } $t = (int)($interval * 1000); $t = $t < 1 ? 1 : $t; - $timer_id = Timer::tick($t, function () use ($func, $args) { + $timerId = Timer::tick($t, function () use ($func, $args) { try { $func(...(array)$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); } }); - $this->eventTimer[$timer_id] = $timer_id; - return $timer_id; + $this->eventTimer[$timerId] = $timerId; + return $timerId; } /** @@ -163,8 +163,8 @@ public function offSignal($signal) */ public function deleteAllTimer() { - foreach ($this->eventTimer as $timer_id) { - Timer::clear($timer_id); + foreach ($this->eventTimer as $timerId) { + Timer::clear($timerId); } } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 52f2629f4..a5b053100 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -69,9 +69,9 @@ public function delay(float $delay, $func, $args) Worker::stopAll(250, $e); } }); - $timer_id = $coroutine->getId(); - $this->eventTimer[$timer_id] = $timer_id; - return $timer_id; + $timerId = $coroutine->getId(); + $this->eventTimer[$timerId] = $timerId; + return $timerId; } /** @@ -91,22 +91,22 @@ public function repeat(float $interval, $func, $args) } } }); - $timer_id = $coroutine->getId(); - $this->eventTimer[$timer_id] = $timer_id; - return $timer_id; + $timerId = $coroutine->getId(); + $this->eventTimer[$timerId] = $timerId; + return $timerId; } /** * {@inheritdoc} */ - public function deleteTimer($timer_id) + public function deleteTimer($timerId) { - if (isset($this->eventTimer[$timer_id])) { + if (isset($this->eventTimer[$timerId])) { try { - (Coroutine::getAll()[$timer_id])->kill(); + (Coroutine::getAll()[$timerId])->kill(); return true; } finally { - unset($this->eventTimer[$timer_id]); + unset($this->eventTimer[$timerId]); } } return false; @@ -117,8 +117,8 @@ public function deleteTimer($timer_id) */ public function deleteAllTimer() { - foreach ($this->eventTimer as $timer_id) { - $this->deleteTimer($timer_id); + foreach ($this->eventTimer as $timerId) { + $this->deleteTimer($timerId); } } diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index 3678f8410..ba77b0956 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -33,8 +33,8 @@ public static function input($buffer, TcpConnection $connection) if (\strlen($buffer) < 4) { return 0; } - $unpack_data = \unpack('Ntotal_length', $buffer); - return $unpack_data['total_length']; + $unpackData = \unpack('Ntotal_length', $buffer); + return $unpackData['total_length']; } /** @@ -56,7 +56,7 @@ public static function decode($buffer) */ public static function encode($buffer) { - $total_length = 4 + \strlen($buffer); - return \pack('N', $total_length) . $buffer; + $totalLength = 4 + \strlen($buffer); + return \pack('N', $totalLength) . $buffer; } } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index bf2c939d1..d21760749 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -48,13 +48,13 @@ class Http /** * Get or set the request class name. * - * @param string|null $class_name + * @param string|null $className * @return string */ - public static function requestClass($class_name = null) + public static function requestClass($className = null) { - if ($class_name) { - static::$requestClass = $class_name; + if ($className) { + static::$requestClass = $className; } return static::$requestClass; } @@ -72,35 +72,35 @@ public static function enableCache($value) /** * Check the integrity of the package. * - * @param string $recv_buffer + * @param string $recvBuffer * @param TcpConnection $connection * @return int */ - public static function input(string $recv_buffer, TcpConnection $connection) + public static function input(string $recvBuffer, TcpConnection $connection) { static $input = []; - if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) { - return $input[$recv_buffer]; + if (!isset($recvBuffer[512]) && isset($input[$recvBuffer])) { + return $input[$recvBuffer]; } - $crlf_pos = \strpos($recv_buffer, "\r\n\r\n"); - if (false === $crlf_pos) { + $crlfPos = \strpos($recvBuffer, "\r\n\r\n"); + if (false === $crlfPos) { // Judge whether the package length exceeds the limit. - if (\strlen($recv_buffer) >= 16384) { + if (\strlen($recvBuffer) >= 16384) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } return 0; } - $length = $crlf_pos + 4; - $firstLine = \explode(" ", \strstr($recv_buffer, "\r\n", true), 3); + $length = $crlfPos + 4; + $firstLine = \explode(" ", \strstr($recvBuffer, "\r\n", true), 3); if (!\in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } - $header = \substr($recv_buffer, 0, $crlf_pos); + $header = \substr($recvBuffer, 0, $crlfPos); $hostHeaderPosition = \strpos($header, "\r\nHost: "); if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { @@ -110,27 +110,27 @@ public static function input(string $recv_buffer, TcpConnection $connection) if ($pos = \strpos($header, "\r\nContent-Length: ")) { $length = $length + (int)\substr($header, $pos + 18, 10); - $has_content_length = true; + $hasContentLength = true; } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { $length = $length + $match[1]; - $has_content_length = true; + $hasContentLength = true; } else { - $has_content_length = false; + $hasContentLength = false; if (false !== stripos($header, "\r\nTransfer-Encoding:")) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } } - if ($has_content_length) { + if ($hasContentLength) { if ($length > $connection->maxPackageSize) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } } - if (!isset($recv_buffer[512])) { - $input[$recv_buffer] = $length; + if (!isset($recvBuffer[512])) { + $input[$recvBuffer] = $length; if (\count($input) > 512) { unset($input[key($input)]); } @@ -142,26 +142,26 @@ public static function input(string $recv_buffer, TcpConnection $connection) /** * Http decode. * - * @param string $recv_buffer + * @param string $recvBuffer * @param TcpConnection $connection * @return \Workerman\Protocols\Http\Request */ - public static function decode($recv_buffer, TcpConnection $connection) + public static function decode($recvBuffer, TcpConnection $connection) { static $requests = []; - $cacheable = static::$enableCache && !isset($recv_buffer[512]); - if (true === $cacheable && isset($requests[$recv_buffer])) { - $request = clone $requests[$recv_buffer]; + $cacheable = static::$enableCache && !isset($recvBuffer[512]); + if (true === $cacheable && isset($requests[$recvBuffer])) { + $request = clone $requests[$recvBuffer]; $request->connection = $connection; $connection->request = $request; $request->properties = []; return $request; } - $request = new static::$requestClass($recv_buffer); + $request = new static::$requestClass($recvBuffer); $request->connection = $connection; $connection->request = $request; if (true === $cacheable) { - $requests[$recv_buffer] = $request; + $requests[$recvBuffer] = $request; if (\count($requests) > 512) { unset($requests[\key($requests)]); } @@ -184,21 +184,21 @@ public static function encode($response, TcpConnection $connection) $connection->request = null; } if (!\is_object($response)) { - $ext_header = ''; + $extHeader = ''; if (isset($connection->header)) { foreach ($connection->header as $name => $value) { if (\is_array($value)) { foreach ($value as $item) { - $ext_header = "$name: $item\r\n"; + $extHeader = "$name: $item\r\n"; } } else { - $ext_header = "$name: $value\r\n"; + $extHeader = "$name: $value\r\n"; } } unset($connection->header); } - $body_len = \strlen((string)$response); - return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$ext_header}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\n\r\n$response"; + $bodyLen = \strlen((string)$response); + return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; } if (isset($connection->header)) { @@ -211,18 +211,18 @@ public static function encode($response, TcpConnection $connection) $offset = $response->file['offset']; $length = $response->file['length']; \clearstatcache(); - $file_size = (int)\filesize($file); - $body_len = $length > 0 ? $length : $file_size - $offset; + $fileSize = (int)\filesize($file); + $bodyLen = $length > 0 ? $length : $fileSize - $offset; $response->withHeaders([ - 'Content-Length' => $body_len, + 'Content-Length' => $bodyLen, 'Accept-Ranges' => 'bytes', ]); if ($offset || $length) { - $offset_end = $offset + $body_len - 1; - $response->header('Content-Range', "bytes $offset-$offset_end/$file_size"); + $offsetEnd = $offset + $bodyLen - 1; + $response->header('Content-Range', "bytes $offset-$offsetEnd/$fileSize"); } - if ($body_len < 2 * 1024 * 1024) { - $connection->send((string)$response . file_get_contents($file, false, null, $offset, $body_len), true); + if ($bodyLen < 2 * 1024 * 1024) { + $connection->send((string)$response . file_get_contents($file, false, null, $offset, $bodyLen), true); return ''; } $handler = \fopen($file, 'r'); @@ -253,22 +253,22 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse if ($offset !== 0) { \fseek($handler, $offset); } - $offset_end = $offset + $length; + $offsetEnd = $offset + $length; // Read file content from disk piece by piece and send to client. - $do_write = function () use ($connection, $handler, $length, $offset_end) { + $doWrite = function () use ($connection, $handler, $length, $offsetEnd) { // Send buffer not full. while ($connection->bufferFull === false) { // Read from disk. $size = 1024 * 1024; if ($length !== 0) { $tell = \ftell($handler); - $remain_size = $offset_end - $tell; - if ($remain_size <= 0) { + $remainSize = $offsetEnd - $tell; + if ($remainSize <= 0) { fclose($handler); $connection->onBufferDrain = null; return; } - $size = $remain_size > $size ? $size : $remain_size; + $size = $remainSize > $size ? $size : $remainSize; } $buffer = \fread($handler, $size); @@ -287,11 +287,11 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse $connection->bufferFull = true; }; // Send buffer drain. - $connection->onBufferDrain = function ($connection) use ($do_write) { + $connection->onBufferDrain = function ($connection) use ($doWrite) { $connection->bufferFull = false; - $do_write(); + $doWrite(); }; - $do_write(); + $doWrite(); } /** @@ -305,10 +305,10 @@ public static function uploadTmpDir($dir = null) static::$uploadTmpDir = $dir; } if (static::$uploadTmpDir === '') { - if ($upload_tmp_dir = \ini_get('upload_tmp_dir')) { - static::$uploadTmpDir = $upload_tmp_dir; - } else if ($upload_tmp_dir = \sys_get_temp_dir()) { - static::$uploadTmpDir = $upload_tmp_dir; + if ($uploadTmpDir = \ini_get('upload_tmp_dir')) { + static::$uploadTmpDir = $uploadTmpDir; + } else if ($uploadTmpDir = \sys_get_temp_dir()) { + static::$uploadTmpDir = $uploadTmpDir; } } return static::$uploadTmpDir; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 1886540d9..3dc70396d 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -203,13 +203,13 @@ public function protocolVersion() /** * Get host. * - * @param bool $without_port + * @param bool $withoutPort * @return string */ - public function host($without_port = false) + public function host($withoutPort = false) { $host = $this->header('host'); - if ($host && $without_port && $pos = \strpos($host, ':')) { + if ($host && $withoutPort && $pos = \strpos($host, ':')) { return \substr($host, 0, $pos); } return $host; @@ -262,11 +262,11 @@ public function queryString() public function session() { if ($this->session === null) { - $session_id = $this->sessionId(); - if ($session_id === false) { + $sessionId = $this->sessionId(); + if ($sessionId === false) { return false; } - $this->session = new Session($session_id); + $this->session = new Session($sessionId); } return $this->session; } @@ -274,25 +274,25 @@ public function session() /** * Get/Set session id. * - * @param $session_id + * @param $sessionId * @return string */ - public function sessionId($session_id = null) + public function sessionId($sessionId = null) { - if ($session_id) { + if ($sessionId) { unset($this->sid); } if (!isset($this->sid)) { - $session_name = Session::$name; - $sid = $session_id ? '' : $this->cookie($session_name); + $sessionName = Session::$name; + $sid = $sessionId ? '' : $this->cookie($sessionName); if ($sid === '' || $sid === null) { if ($this->connection === null) { Worker::safeEcho('Request->session() fail, header already send'); return false; } - $sid = $session_id ?: static::createSessionId(); - $cookie_params = Session::getCookieParams(); - $this->setSidCookie($session_name, $sid, $cookie_params); + $sid = $sessionId ?: static::createSessionId(); + $cookieParams = Session::getCookieParams(); + $this->setSidCookie($sessionName, $sid, $cookieParams); } $this->sid = $sid; } @@ -301,22 +301,22 @@ public function sessionId($session_id = null) /** * Session regenerate id - * @param bool $delete_old_session + * @param bool $deleteOldSession * @return void */ - public function sessionRegenerateId($delete_old_session = false) + public function sessionRegenerateId($deleteOldSession = false) { $session = $this->session(); - $session_data = $session->all(); - if ($delete_old_session) { + $sessionData = $session->all(); + if ($deleteOldSession) { $session->flush(); } - $new_sid = static::createSessionId(); - $session = new Session($new_sid); - $session->put($session_data); - $cookie_params = Session::getCookieParams(); - $session_name = Session::$name; - $this->setSidCookie($session_name, $new_sid, $cookie_params); + $newSid = static::createSessionId(); + $session = new Session($newSid); + $session->put($sessionData); + $cookieParams = Session::getCookieParams(); + $sessionName = Session::$name; + $this->setSidCookie($sessionName, $newSid, $cookieParams); } /** @@ -369,8 +369,8 @@ public static function enableCache($value) */ protected function parseHeadFirstLine() { - $first_line = \strstr($this->buffer, "\r\n", true); - $tmp = \explode(' ', $first_line, 3); + $firstLine = \strstr($this->buffer, "\r\n", true); + $tmp = \explode(' ', $firstLine, 3); $this->data['method'] = $tmp[0]; $this->data['uri'] = $tmp[1] ?? '/'; } @@ -382,9 +382,9 @@ protected function parseHeadFirstLine() */ protected function parseProtocolVersion() { - $first_line = \strstr($this->buffer, "\r\n", true); - $protoco_version = substr(\strstr($first_line, 'HTTP/'), 5); - $this->data['protocolVersion'] = $protoco_version ? $protoco_version : '1.0'; + $firstLine = \strstr($this->buffer, "\r\n", true); + $protocoVersion = substr(\strstr($firstLine, 'HTTP/'), 5); + $this->data['protocolVersion'] = $protocoVersion ? $protocoVersion : '1.0'; } /** @@ -396,19 +396,19 @@ protected function parseHeaders() { static $cache = []; $this->data['headers'] = []; - $raw_head = $this->rawHead(); - $end_line_position = \strpos($raw_head, "\r\n"); - if ($end_line_position === false) { + $rawHead = $this->rawHead(); + $endLinePosition = \strpos($rawHead, "\r\n"); + if ($endLinePosition === false) { return; } - $head_buffer = \substr($raw_head, $end_line_position + 2); - $cacheable = static::$enableCache && !isset($head_buffer[2048]); - if ($cacheable && isset($cache[$head_buffer])) { - $this->data['headers'] = $cache[$head_buffer]; + $headBuffer = \substr($rawHead, $endLinePosition + 2); + $cacheable = static::$enableCache && !isset($headBuffer[2048]); + if ($cacheable && isset($cache[$headBuffer])) { + $this->data['headers'] = $cache[$headBuffer]; return; } - $head_data = \explode("\r\n", $head_buffer); - foreach ($head_data as $content) { + $headData = \explode("\r\n", $headBuffer); + foreach ($headData as $content) { if (false !== \strpos($content, ':')) { list($key, $value) = \explode(':', $content, 2); $key = \strtolower($key); @@ -424,7 +424,7 @@ protected function parseHeaders() } } if ($cacheable) { - $cache[$head_buffer] = $this->data['headers']; + $cache[$headBuffer] = $this->data['headers']; if (\count($cache) > 128) { unset($cache[key($cache)]); } @@ -439,19 +439,19 @@ protected function parseHeaders() protected function parseGet() { static $cache = []; - $query_string = $this->queryString(); + $queryString = $this->queryString(); $this->data['get'] = []; - if ($query_string === '') { + if ($queryString === '') { return; } - $cacheable = static::$enableCache && !isset($query_string[1024]); - if ($cacheable && isset($cache[$query_string])) { - $this->data['get'] = $cache[$query_string]; + $cacheable = static::$enableCache && !isset($queryString[1024]); + if ($cacheable && isset($cache[$queryString])) { + $this->data['get'] = $cache[$queryString]; return; } - \parse_str($query_string, $this->data['get']); + \parse_str($queryString, $this->data['get']); if ($cacheable) { - $cache[$query_string] = $this->data['get']; + $cache[$queryString] = $this->data['get']; if (\count($cache) > 256) { unset($cache[key($cache)]); } @@ -467,28 +467,28 @@ protected function parsePost() { static $cache = []; $this->data['post'] = $this->data['files'] = []; - $content_type = $this->header('content-type', ''); - if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) { - $http_post_boundary = '--' . $match[1]; - $this->parseUploadFiles($http_post_boundary); + $contentType = $this->header('content-type', ''); + if (\preg_match('/boundary="?(\S+)"?/', $contentType, $match)) { + $httpPostBoundary = '--' . $match[1]; + $this->parseUploadFiles($httpPostBoundary); return; } - $body_buffer = $this->rawBody(); - if ($body_buffer === '') { + $bodyBuffer = $this->rawBody(); + if ($bodyBuffer === '') { return; } - $cacheable = static::$enableCache && !isset($body_buffer[1024]); - if ($cacheable && isset($cache[$body_buffer])) { - $this->data['post'] = $cache[$body_buffer]; + $cacheable = static::$enableCache && !isset($bodyBuffer[1024]); + if ($cacheable && isset($cache[$bodyBuffer])) { + $this->data['post'] = $cache[$bodyBuffer]; return; } - if (\preg_match('/\bjson\b/i', $content_type)) { - $this->data['post'] = (array)\json_decode($body_buffer, true); + if (\preg_match('/\bjson\b/i', $contentType)) { + $this->data['post'] = (array)\json_decode($bodyBuffer, true); } else { - \parse_str($body_buffer, $this->data['post']); + \parse_str($bodyBuffer, $this->data['post']); } if ($cacheable) { - $cache[$body_buffer] = $this->data['post']; + $cache[$bodyBuffer] = $this->data['post']; if (\count($cache) > 256) { unset($cache[key($cache)]); } @@ -498,28 +498,28 @@ protected function parsePost() /** * Parse upload files. * - * @param string $http_post_boundary + * @param string $httpPostBoundary * @return void */ - protected function parseUploadFiles($http_post_boundary) + protected function parseUploadFiles($httpPostBoundary) { - $http_post_boundary = \trim($http_post_boundary, '"'); + $httpPostBoundary = \trim($httpPostBoundary, '"'); $buffer = $this->buffer; - $post_encode_string = ''; - $files_encode_string = ''; + $postEncodeString = ''; + $filesEncodeString = ''; $files = []; - $boday_position = strpos($buffer, "\r\n\r\n") + 4; - $offset = $boday_position + strlen($http_post_boundary) + 2; - $max_count = static::$maxFileUploads; - while ($max_count-- > 0 && $offset) { - $offset = $this->parseUploadFile($http_post_boundary, $offset, $post_encode_string, $files_encode_string, $files); + $bodayPosition = strpos($buffer, "\r\n\r\n") + 4; + $offset = $bodayPosition + strlen($httpPostBoundary) + 2; + $maxCount = static::$maxFileUploads; + while ($maxCount-- > 0 && $offset) { + $offset = $this->parseUploadFile($httpPostBoundary, $offset, $postEncodeString, $filesEncodeString, $files); } - if ($post_encode_string) { - parse_str($post_encode_string, $this->data['post']); + if ($postEncodeString) { + parse_str($postEncodeString, $this->data['post']); } - if ($files_encode_string) { - parse_str($files_encode_string, $this->data['files']); + if ($filesEncodeString) { + parse_str($filesEncodeString, $this->data['files']); \array_walk_recursive($this->data['files'], function (&$value) use ($files) { $value = $files[$value]; }); @@ -528,56 +528,56 @@ protected function parseUploadFiles($http_post_boundary) /** * @param $boundary - * @param $section_start_offset + * @param $sectionStartOffset * @return int */ - protected function parseUploadFile($boundary, $section_start_offset, &$post_encode_string, &$files_encode_str, &$files) + protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeString, &$filesEncodeStr, &$files) { $file = []; $boundary = "\r\n$boundary"; - if (\strlen($this->buffer) < $section_start_offset) { + if (\strlen($this->buffer) < $sectionStartOffset) { return 0; } - $section_end_offset = \strpos($this->buffer, $boundary, $section_start_offset); - if (!$section_end_offset) { + $sectionEndOffset = \strpos($this->buffer, $boundary, $sectionStartOffset); + if (!$sectionEndOffset) { return 0; } - $content_lines_end_offset = \strpos($this->buffer, "\r\n\r\n", $section_start_offset); - if (!$content_lines_end_offset || $content_lines_end_offset + 4 > $section_end_offset) { + $contentLinesEndOffset = \strpos($this->buffer, "\r\n\r\n", $sectionStartOffset); + if (!$contentLinesEndOffset || $contentLinesEndOffset + 4 > $sectionEndOffset) { return 0; } - $content_lines_str = \substr($this->buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset); - $content_lines = \explode("\r\n", trim($content_lines_str . "\r\n")); - $boundary_value = \substr($this->buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4); - $upload_key = false; - foreach ($content_lines as $content_line) { - if (!\strpos($content_line, ': ')) { + $contentLinesStr = \substr($this->buffer, $sectionStartOffset, $contentLinesEndOffset - $sectionStartOffset); + $contentLines = \explode("\r\n", trim($contentLinesStr . "\r\n")); + $boundaryValue = \substr($this->buffer, $contentLinesEndOffset + 4, $sectionEndOffset - $contentLinesEndOffset - 4); + $uploadKey = false; + foreach ($contentLines as $contentLine) { + if (!\strpos($contentLine, ': ')) { return 0; } - list($key, $value) = \explode(': ', $content_line); + list($key, $value) = \explode(': ', $contentLine); switch (strtolower($key)) { case "content-disposition": // Is file data. if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { $error = 0; - $tmp_file = ''; - $size = \strlen($boundary_value); - $tmp_upload_dir = HTTP::uploadTmpDir(); - if (!$tmp_upload_dir) { + $tmpFile = ''; + $size = \strlen($boundaryValue); + $tmpUploadDir = HTTP::uploadTmpDir(); + if (!$tmpUploadDir) { $error = UPLOAD_ERR_NO_TMP_DIR; - } else if ($boundary_value === '') { + } else if ($boundaryValue === '') { $error = UPLOAD_ERR_NO_FILE; } else { - $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.'); - if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) { + $tmpFile = \tempnam($tmpUploadDir, 'workerman.upload.'); + if ($tmpFile === false || false == \file_put_contents($tmpFile, $boundaryValue)) { $error = UPLOAD_ERR_CANT_WRITE; } } - $upload_key = $match[1]; + $uploadKey = $match[1]; // Parse upload files. $file = [ 'name' => $match[2], - 'tmp_name' => $tmp_file, + 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error, 'type' => '', @@ -588,9 +588,9 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco // Parse $POST. if (\preg_match('/name="(.*?)"$/', $value, $match)) { $k = $match[1]; - $post_encode_string .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&'; + $postEncodeString .= \urlencode($k) . "=" . \urlencode($boundaryValue) . '&'; } - return $section_end_offset + \strlen($boundary) + 2; + return $sectionEndOffset + \strlen($boundary) + 2; } break; case "content-type": @@ -598,13 +598,13 @@ protected function parseUploadFile($boundary, $section_start_offset, &$post_enco break; } } - if ($upload_key === false) { + if ($uploadKey === false) { return 0; } - $files_encode_str .= \urlencode($upload_key) . '=' . \count($files) . '&'; + $filesEncodeStr .= \urlencode($uploadKey) . '=' . \count($files) . '&'; $files[] = $file; - return $section_end_offset + \strlen($boundary) + 2; + return $sectionEndOffset + \strlen($boundary) + 2; } /** @@ -690,19 +690,19 @@ public function __destruct() } /** - * @param string $session_name + * @param string $sessionName * @param string $sid - * @param array $cookie_params + * @param array $cookieParams * @return void */ - protected function setSidCookie(string $session_name, string $sid, array $cookie_params) + protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) { - $this->connection->header['Set-Cookie'] = [$session_name . '=' . $sid - . (empty($cookie_params['domain']) ? '' : '; Domain=' . $cookie_params['domain']) - . (empty($cookie_params['lifetime']) ? '' : '; Max-Age=' . $cookie_params['lifetime']) - . (empty($cookie_params['path']) ? '' : '; Path=' . $cookie_params['path']) - . (empty($cookie_params['samesite']) ? '' : '; SameSite=' . $cookie_params['samesite']) - . (!$cookie_params['secure'] ? '' : '; Secure') - . (!$cookie_params['httponly'] ? '' : '; HttpOnly')]; + $this->connection->header['Set-Cookie'] = [$sessionName . '=' . $sid + . (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain']) + . (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime']) + . (empty($cookieParams['path']) ? '' : '; Path=' . $cookieParams['path']) + . (empty($cookieParams['samesite']) ? '' : '; SameSite=' . $cookieParams['samesite']) + . (!$cookieParams['secure'] ? '' : '; Secure') + . (!$cookieParams['httponly'] ? '' : '; HttpOnly')]; } } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index aa0e487c3..f780619c7 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -248,13 +248,13 @@ public function getHeaders() * Set status. * * @param int $code - * @param string|null $reason_phrase + * @param string|null $reasonPhrase * @return $this */ - public function withStatus($code, $reason_phrase = null) + public function withStatus($code, $reasonPhrase = null) { $this->status = $code; - $this->reason = $reason_phrase; + $this->reason = $reasonPhrase; return $this; } @@ -334,35 +334,35 @@ public function withFile($file, $offset = 0, $length = 0) * * @param $name * @param string $value - * @param int $max_age + * @param int $maxAge * @param string $path * @param string $domain * @param bool $secure - * @param bool $http_only - * @param bool $same_site + * @param bool $httpOnly + * @param bool $sameSite * @return $this */ - public function cookie($name, $value = '', $max_age = null, $path = '', $domain = '', $secure = false, $http_only = false, $same_site = false) + public function cookie($name, $value = '', $maxAge = null, $path = '', $domain = '', $secure = false, $httpOnly = false, $sameSite = false) { $this->header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) - . ($max_age === null ? '' : '; Max-Age=' . $max_age) + . ($maxAge === null ? '' : '; Max-Age=' . $maxAge) . (empty($path) ? '' : '; Path=' . $path) . (!$secure ? '' : '; Secure') - . (!$http_only ? '' : '; HttpOnly') - . (empty($same_site) ? '' : '; SameSite=' . $same_site); + . (!$httpOnly ? '' : '; HttpOnly') + . (empty($sameSite) ? '' : '; SameSite=' . $sameSite); return $this; } /** * Create header for file. * - * @param array $file_info + * @param array $fileInfo * @return string */ - protected function createHeadForFile($file_info) + protected function createHeadForFile($fileInfo) { - $file = $file_info['file']; + $file = $fileInfo['file']; $reason = $this->reason ?: self::PHRASES[$this->status]; $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; $headers = $this->header; @@ -383,9 +383,9 @@ protected function createHeadForFile($file_info) $head .= "Connection: keep-alive\r\n"; } - $file_info = \pathinfo($file); - $extension = $file_info['extension'] ?? ''; - $base_name = $file_info['basename'] ?? 'unknown'; + $fileInfo = \pathinfo($file); + $extension = $fileInfo['extension'] ?? ''; + $baseName = $fileInfo['basename'] ?? 'unknown'; if (!isset($headers['Content-Type'])) { if (isset(self::$mimeTypeMap[$extension])) { $head .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; @@ -395,7 +395,7 @@ protected function createHeadForFile($file_info) } if (!isset($headers['Content-Disposition']) && !isset(self::$mimeTypeMap[$extension])) { - $head .= "Content-Disposition: attachment; filename=\"$base_name\"\r\n"; + $head .= "Content-Disposition: attachment; filename=\"$baseName\"\r\n"; } if (!isset($headers['Last-Modified'])) { @@ -419,9 +419,9 @@ public function __toString() } $reason = $this->reason ?: self::PHRASES[$this->status] ?? ''; - $body_len = \strlen($this->body); + $bodyLen = \strlen($this->body); if (empty($this->header)) { - return "HTTP/{$this->version} {$this->status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $body_len\r\nConnection: keep-alive\r\n\r\n{$this->body}"; + return "HTTP/{$this->version} {$this->status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\nConnection: keep-alive\r\n\r\n{$this->body}"; } $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; @@ -450,9 +450,9 @@ public function __toString() } if (!isset($headers['Transfer-Encoding'])) { - $head .= "Content-Length: $body_len\r\n\r\n"; + $head .= "Content-Length: $bodyLen\r\n\r\n"; } else { - return "$head\r\n" . dechex($body_len) . "\r\n{$this->body}\r\n"; + return "$head\r\n" . dechex($bodyLen) . "\r\n{$this->body}\r\n"; } // The whole http package @@ -466,15 +466,15 @@ public function __toString() */ public static function initMimeTypeMap() { - $mime_file = __DIR__ . '/mime.types'; - $items = \file($mime_file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); + $mimeFile = __DIR__ . '/mime.types'; + $items = \file($mimeFile, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); foreach ($items as $content) { if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { - $mime_type = $match[1]; - $extension_var = $match[2]; - $extension_array = \explode(' ', \substr($extension_var, 0, -1)); - foreach ($extension_array as $file_extension) { - static::$mimeTypeMap[$file_extension] = $mime_type; + $mimeType = $match[1]; + $extensionVar = $match[2]; + $extensionArray = \explode(' ', \substr($extensionVar, 0, -1)); + foreach ($extensionArray as $fileExtension) { + static::$mimeTypeMap[$fileExtension] = $mimeType; } } } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 12d92c46f..13343445e 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -138,16 +138,16 @@ class Session /** * Session constructor. * - * @param string $session_id + * @param string $sessionId */ - public function __construct($session_id) + public function __construct($sessionId) { - static::checkSessionId($session_id); + static::checkSessionId($sessionId); if (static::$handler === null) { static::initHandler(); } - $this->sessionId = $session_id; - if ($data = static::$handler->read($session_id)) { + $this->sessionId = $sessionId; + if ($data = static::$handler->read($sessionId)) { $this->data = \unserialize($data); } } @@ -328,33 +328,33 @@ public function refresh() */ public static function init() { - if (($gc_probability = (int)\ini_get('session.gc_probability')) && ($gc_divisor = (int)\ini_get('session.gc_divisor'))) { - static::$gcProbability = [$gc_probability, $gc_divisor]; + if (($gcProbability = (int)\ini_get('session.gc_probability')) && ($gcDivisor = (int)\ini_get('session.gc_divisor'))) { + static::$gcProbability = [$gcProbability, $gcDivisor]; } - if ($gc_max_life_time = \ini_get('session.gc_maxlifetime')) { - self::$lifetime = (int)$gc_max_life_time; + if ($gcMaxLifeTime = \ini_get('session.gc_maxlifetime')) { + self::$lifetime = (int)$gcMaxLifeTime; } - $session_cookie_params = \session_get_cookie_params(); - static::$cookieLifetime = $session_cookie_params['lifetime']; - static::$cookiePath = $session_cookie_params['path']; - static::$domain = $session_cookie_params['domain']; - static::$secure = $session_cookie_params['secure']; - static::$httpOnly = $session_cookie_params['httponly']; + $sessionCookieParams = \session_get_cookie_params(); + static::$cookieLifetime = $sessionCookieParams['lifetime']; + static::$cookiePath = $sessionCookieParams['path']; + static::$domain = $sessionCookieParams['domain']; + static::$secure = $sessionCookieParams['secure']; + static::$httpOnly = $sessionCookieParams['httponly']; } /** * Set session handler class. * - * @param mixed|null $class_name + * @param mixed|null $className * @param mixed|null $config * @return string */ - public static function handlerClass($class_name = null, $config = null) + public static function handlerClass($className = null, $config = null) { - if ($class_name) { - static::$handlerClass = $class_name; + if ($className) { + static::$handlerClass = $className; } if ($config) { static::$handlerConfig = $config; @@ -419,12 +419,12 @@ public function __destruct() /** * Check session id. * - * @param string $session_id + * @param string $sessionId */ - protected static function checkSessionId($session_id) + protected static function checkSessionId($sessionId) { - if (!\preg_match('/^[a-zA-Z0-9]+$/', $session_id)) { - throw new SessionException("session_id $session_id is invalid"); + if (!\preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { + throw new SessionException("session_id $sessionId is invalid"); } } } diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index 7dd72d792..e5115f528 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -41,11 +41,11 @@ class FileSessionHandler implements SessionHandlerInterface */ public static function init() { - $save_path = @\session_save_path(); - if (!$save_path || \strpos($save_path, 'tcp://') === 0) { - $save_path = \sys_get_temp_dir(); + $savePath = @\session_save_path(); + if (!$savePath || \strpos($savePath, 'tcp://') === 0) { + $savePath = \sys_get_temp_dir(); } - static::sessionSavePath($save_path); + static::sessionSavePath($savePath); } /** @@ -62,7 +62,7 @@ public function __construct($config = []) /** * {@inheritdoc} */ - public function open($save_path, $name) + public function open($savePath, $name) { return true; } @@ -70,16 +70,16 @@ public function open($save_path, $name) /** * {@inheritdoc} */ - public function read($session_id) + public function read($sessionId) { - $session_file = static::sessionFile($session_id); + $sessionFile = static::sessionFile($sessionId); \clearstatcache(); - if (\is_file($session_file)) { - if (\time() - \filemtime($session_file) > Session::$lifetime) { - \unlink($session_file); + if (\is_file($sessionFile)) { + if (\time() - \filemtime($sessionFile) > Session::$lifetime) { + \unlink($sessionFile); return ''; } - $data = \file_get_contents($session_file); + $data = \file_get_contents($sessionFile); return $data ?: ''; } return ''; @@ -88,13 +88,13 @@ public function read($session_id) /** * {@inheritdoc} */ - public function write($session_id, $session_data) + public function write($sessionId, $sessionData) { - $temp_file = static::$sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); - if (!\file_put_contents($temp_file, $session_data)) { + $tempFile = static::$sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); + if (!\file_put_contents($tempFile, $sessionData)) { return false; } - return \rename($temp_file, static::sessionFile($session_id)); + return \rename($tempFile, static::sessionFile($sessionId)); } /** @@ -110,15 +110,15 @@ public function write($session_id, $session_data) */ public function updateTimestamp($id, $data = "") { - $session_file = static::sessionFile($id); - if (!file_exists($session_file)) { + $sessionFile = static::sessionFile($id); + if (!file_exists($sessionFile)) { return false; } // set file modify time to current time - $set_modify_time = \touch($session_file); + $setModifyTime = \touch($sessionFile); // clear file stat cache \clearstatcache(); - return $set_modify_time; + return $setModifyTime; } /** @@ -132,11 +132,11 @@ public function close() /** * {@inheritdoc} */ - public function destroy($session_id) + public function destroy($sessionId) { - $session_file = static::sessionFile($session_id); - if (\is_file($session_file)) { - \unlink($session_file); + $sessionFile = static::sessionFile($sessionId); + if (\is_file($sessionFile)) { + \unlink($sessionFile); } return true; } @@ -146,9 +146,9 @@ public function destroy($session_id) */ public function gc($maxlifetime) { - $time_now = \time(); + $timeNow = \time(); foreach (\glob(static::$sessionSavePath . static::$sessionFilePrefix . '*') as $file) { - if (\is_file($file) && $time_now - \filemtime($file) > $maxlifetime) { + if (\is_file($file) && $timeNow - \filemtime($file) > $maxlifetime) { \unlink($file); } } @@ -157,12 +157,12 @@ public function gc($maxlifetime) /** * Get session file path. * - * @param string $session_id + * @param string $sessionId * @return string */ - protected static function sessionFile($session_id) + protected static function sessionFile($sessionId) { - return static::$sessionSavePath . static::$sessionFilePrefix . $session_id; + return static::$sessionSavePath . static::$sessionFilePrefix . $sessionId; } /** diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 351e58621..b938a8237 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -21,10 +21,10 @@ class RedisClusterSessionHandler extends RedisSessionHandler public function __construct($config) { $timeout = $config['timeout'] ?? 2; - $read_timeout = $config['read_timeout'] ?? $timeout; + $readTimeout = $config['read_timeout'] ?? $timeout; $persistent = $config['persistent'] ?? false; $auth = $config['auth'] ?? ''; - $args = [null, $config['host'], $timeout, $read_timeout, $persistent]; + $args = [null, $config['host'], $timeout, $readTimeout, $persistent]; if ($auth) { $args[] = $auth; } @@ -38,9 +38,9 @@ public function __construct($config) /** * {@inheritdoc} */ - public function read($session_id) + public function read($sessionId) { - return $this->redis->get($session_id); + return $this->redis->get($sessionId); } } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 62d2ee439..d7f36bdf9 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -89,7 +89,7 @@ public function connect() /** * {@inheritdoc} */ - public function open($save_path, $name) + public function open($savePath, $name) { return true; } @@ -97,15 +97,15 @@ public function open($save_path, $name) /** * {@inheritdoc} */ - public function read($session_id) + public function read($sessionId) { try { - return $this->redis->get($session_id); + return $this->redis->get($sessionId); } catch (RedisException $e) { $msg = strtolower($e->getMessage()); if ($msg === 'connection lost' || strpos($msg, 'went away')) { $this->connect(); - return $this->redis->get($session_id); + return $this->redis->get($sessionId); } throw $e; } @@ -114,9 +114,9 @@ public function read($session_id) /** * {@inheritdoc} */ - public function write($session_id, $session_data) + public function write($sessionId, $sessionData) { - return true === $this->redis->setex($session_id, Session::$lifetime, $session_data); + return true === $this->redis->setex($sessionId, Session::$lifetime, $sessionData); } /** @@ -130,9 +130,9 @@ public function updateTimestamp($id, $data = "") /** * {@inheritdoc} */ - public function destroy($session_id) + public function destroy($sessionId) { - $this->redis->del($session_id); + $this->redis->del($sessionId); return true; } diff --git a/src/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php index 792487e0d..f1033ec2e 100644 --- a/src/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -30,14 +30,14 @@ public function close(); /** * Destroy a session * @link http://php.net/manual/en/sessionhandlerinterface.destroy.php - * @param string $session_id The session ID being destroyed. + * @param string $sessionId The session ID being destroyed. * @return bool

* The return value (usually TRUE on success, FALSE on failure). * Note this value is returned internally to PHP for processing. *

* @since 5.4.0 */ - public function destroy($session_id); + public function destroy($sessionId); /** * Cleanup old sessions @@ -57,7 +57,7 @@ public function gc($maxlifetime); /** * Initialize session * @link http://php.net/manual/en/sessionhandlerinterface.open.php - * @param string $save_path The path where to store/retrieve the session. + * @param string $savePath The path where to store/retrieve the session. * @param string $name The session name. * @return bool

* The return value (usually TRUE on success, FALSE on failure). @@ -65,13 +65,13 @@ public function gc($maxlifetime); *

* @since 5.4.0 */ - public function open($save_path, $name); + public function open($savePath, $name); /** * Read session data * @link http://php.net/manual/en/sessionhandlerinterface.read.php - * @param string $session_id The session id to read data for. + * @param string $sessionId The session id to read data for. * @return string

* Returns an encoded string of the read data. * If nothing was read, it must return an empty string. @@ -79,13 +79,13 @@ public function open($save_path, $name); *

* @since 5.4.0 */ - public function read($session_id); + public function read($sessionId); /** * Write session data * @link http://php.net/manual/en/sessionhandlerinterface.write.php - * @param string $session_id The session id. - * @param string $session_data

+ * @param string $sessionId The session id. + * @param string $sessionData

* The encoded session data. This data is the * result of the PHP internally encoding * the $SESSION superglobal to a serialized @@ -98,7 +98,7 @@ public function read($session_id); *

* @since 5.4.0 */ - public function write($session_id, $session_data); + public function write($sessionId, $sessionData); /** * Update sesstion modify time. diff --git a/src/Protocols/ProtocolInterface.php b/src/Protocols/ProtocolInterface.php index 9f5b58b19..0d3365311 100644 --- a/src/Protocols/ProtocolInterface.php +++ b/src/Protocols/ProtocolInterface.php @@ -27,20 +27,20 @@ interface ProtocolInterface * If length is unknow please return 0 that mean wating more data. * If the package has something wrong please return false the connection will be closed. * - * @param string $recv_buffer + * @param string $recvBuffer * @param ConnectionInterface $connection * @return int|false */ - public static function input($recv_buffer, ConnectionInterface $connection); + public static function input($recvBuffer, ConnectionInterface $connection); /** * Decode package and emit onMessage($message) callback, $message is the result that decode returned. * - * @param string $recv_buffer + * @param string $recvBuffer * @param ConnectionInterface $connection * @return mixed */ - public static function decode($recv_buffer, ConnectionInterface $connection); + public static function decode($recvBuffer, ConnectionInterface $connection); /** * Encode package brefore sending to client. diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 3e33d9d0d..8e8320662 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -48,9 +48,9 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface public static function input($buffer, ConnectionInterface $connection) { // Receive length. - $recv_len = \strlen($buffer); + $recvLen = \strlen($buffer); // We need more data. - if ($recv_len < 6) { + if ($recvLen < 6) { return 0; } @@ -62,15 +62,15 @@ public static function input($buffer, ConnectionInterface $connection) // Buffer websocket frame data. if ($connection->context->websocketCurrentFrameLength) { // We need more frame data. - if ($connection->context->websocketCurrentFrameLength > $recv_len) { + if ($connection->context->websocketCurrentFrameLength > $recvLen) { // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1. return 0; } } else { $firstbyte = \ord($buffer[0]); $secondbyte = \ord($buffer[1]); - $data_len = $secondbyte & 127; - $is_fin_frame = $firstbyte >> 7; + $dataLen = $secondbyte & 127; + $isFinFrame = $firstbyte >> 7; $masked = $secondbyte >> 7; if (!$masked) { @@ -92,10 +92,10 @@ public static function input($buffer, ConnectionInterface $connection) // Close package. case 0x8: // Try to emit onWebSocketClose callback. - $close_cb = $connection->onWebSocketClose ?? $connection->worker->onWebSocketClose ?? false; - if ($close_cb) { + $closeCb = $connection->onWebSocketClose ?? $connection->worker->onWebSocketClose ?? false; + if ($closeCb) { try { - $close_cb($connection); + $closeCb($connection); } catch (\Throwable $e) { Worker::stopAll(250, $e); } @@ -118,98 +118,98 @@ public static function input($buffer, ConnectionInterface $connection) } // Calculate packet length. - $head_len = 6; - if ($data_len === 126) { - $head_len = 8; - if ($head_len > $recv_len) { + $headLen = 6; + if ($dataLen === 126) { + $headLen = 8; + if ($headLen > $recvLen) { return 0; } $pack = \unpack('nn/ntotal_len', $buffer); - $data_len = $pack['total_len']; + $dataLen = $pack['total_len']; } else { - if ($data_len === 127) { - $head_len = 14; - if ($head_len > $recv_len) { + if ($dataLen === 127) { + $headLen = 14; + if ($headLen > $recvLen) { return 0; } $arr = \unpack('n/N2c', $buffer); - $data_len = $arr['c1'] * 4294967296 + $arr['c2']; + $dataLen = $arr['c1'] * 4294967296 + $arr['c2']; } } - $current_frame_length = $head_len + $data_len; + $currentFrameLength = $headLen + $dataLen; - $total_package_size = \strlen($connection->context->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > $connection->maxPackageSize) { - Worker::safeEcho("error package. package_length=$total_package_size\n"); + $totalPackageSize = \strlen($connection->context->websocketDataBuffer) + $currentFrameLength; + if ($totalPackageSize > $connection->maxPackageSize) { + Worker::safeEcho("error package. package_length=$totalPackageSize\n"); $connection->close(); return 0; } - if ($is_fin_frame) { + if ($isFinFrame) { if ($opcode === 0x9) { - if ($recv_len >= $current_frame_length) { - $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); - $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = $connection->websocketType ?? static::BINARY_TYPE_BLOB; + if ($recvLen >= $currentFrameLength) { + $pingData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $connection->consumeRecvBuffer($currentFrameLength); + $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; - $ping_cb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false; - if ($ping_cb) { + $pingCb = $connection->onWebSocketPing ?? $connection->worker->onWebSocketPing ?? false; + if ($pingCb) { try { - $ping_cb($connection, $ping_data); + $pingCb($connection, $pingData); } catch (\Throwable $e) { Worker::stopAll(250, $e); } } else { - $connection->send($ping_data); + $connection->send($pingData); } - $connection->websocketType = $tmp_connection_type; - if ($recv_len > $current_frame_length) { - return static::input(\substr($buffer, $current_frame_length), $connection); + $connection->websocketType = $tmpConnectionType; + if ($recvLen > $currentFrameLength) { + return static::input(\substr($buffer, $currentFrameLength), $connection); } } return 0; } else if ($opcode === 0xa) { - if ($recv_len >= $current_frame_length) { - $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); - $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = $connection->websocketType ?? static::BINARY_TYPE_BLOB; + if ($recvLen >= $currentFrameLength) { + $pongData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $connection->consumeRecvBuffer($currentFrameLength); + $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. - $pong_cb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false; - if ($pong_cb) { + $pongCb = $connection->onWebSocketPong ?? $connection->worker->onWebSocketPong ?? false; + if ($pongCb) { try { - $pong_cb($connection, $pong_data); + $pongCb($connection, $pongData); } catch (\Throwable $e) { Worker::stopAll(250, $e); } } - $connection->websocketType = $tmp_connection_type; - if ($recv_len > $current_frame_length) { - return static::input(\substr($buffer, $current_frame_length), $connection); + $connection->websocketType = $tmpConnectionType; + if ($recvLen > $currentFrameLength) { + return static::input(\substr($buffer, $currentFrameLength), $connection); } } return 0; } - return $current_frame_length; + return $currentFrameLength; } else { - $connection->context->websocketCurrentFrameLength = $current_frame_length; + $connection->context->websocketCurrentFrameLength = $currentFrameLength; } } // Received just a frame length data. - if ($connection->context->websocketCurrentFrameLength === $recv_len) { + if ($connection->context->websocketCurrentFrameLength === $recvLen) { static::decode($buffer, $connection); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); $connection->context->websocketCurrentFrameLength = 0; return 0; } // The length of the received data is greater than the length of a frame. - elseif ($connection->context->websocketCurrentFrameLength < $recv_len) { + elseif ($connection->context->websocketCurrentFrameLength < $recvLen) { static::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); - $current_frame_length = $connection->context->websocketCurrentFrameLength; + $currentFrameLength = $connection->context->websocketCurrentFrameLength; $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. - return static::input(\substr($buffer, $current_frame_length), $connection); + return static::input(\substr($buffer, $currentFrameLength), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -233,15 +233,15 @@ public static function encode($buffer, ConnectionInterface $connection) $connection->websocketType = static::BINARY_TYPE_BLOB; } - $first_byte = $connection->websocketType; + $firstByte = $connection->websocketType; if ($len <= 125) { - $encode_buffer = $first_byte . \chr($len) . $buffer; + $encodeBuffer = $firstByte . \chr($len) . $buffer; } else { if ($len <= 65535) { - $encode_buffer = $first_byte . \chr(126) . \pack("n", $len) . $buffer; + $encodeBuffer = $firstByte . \chr(126) . \pack("n", $len) . $buffer; } else { - $encode_buffer = $first_byte . \chr(127) . \pack("xxxxN", $len) . $buffer; + $encodeBuffer = $firstByte . \chr(127) . \pack("xxxxN", $len) . $buffer; } } @@ -261,7 +261,7 @@ public static function encode($buffer, ConnectionInterface $connection) } return ''; } - $connection->context->tmpWebsocketData .= $encode_buffer; + $connection->context->tmpWebsocketData .= $encodeBuffer; // Check buffer is full. if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) { if ($connection->onBufferFull) { @@ -276,7 +276,7 @@ public static function encode($buffer, ConnectionInterface $connection) return ''; } - return $encode_buffer; + return $encodeBuffer; } /** @@ -288,9 +288,9 @@ public static function encode($buffer, ConnectionInterface $connection) */ public static function decode($buffer, ConnectionInterface $connection) { - $first_byte = \ord($buffer[1]); - $len = $first_byte & 127; - $rsv1 = $first_byte & 64; + $firstByte = \ord($buffer[1]); + $len = $firstByte & 127; + $rsv1 = $firstByte & 64; if ($len === 126) { $masks = \substr($buffer, 4, 4); @@ -331,29 +331,29 @@ public static function dealHandshake($buffer, TcpConnection $connection) // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { // Find \r\n\r\n. - $header_end_pos = \strpos($buffer, "\r\n\r\n"); - if (!$header_end_pos) { + $headerEndPos = \strpos($buffer, "\r\n\r\n"); + if (!$headerEndPos) { return 0; } - $header_length = $header_end_pos + 4; + $headerLength = $headerEndPos + 4; // Get Sec-WebSocket-Key. - $Sec_WebSocket_Key = ''; + $SecWebSocketKey = ''; if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { - $Sec_WebSocket_Key = $match[1]; + $SecWebSocketKey = $match[1]; } else { $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", true); return 0; } // Calculation websocket key. - $new_key = \base64_encode(\sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); + $newKey = \base64_encode(\sha1($SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. - $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n" + $handshakeMessage = "HTTP/1.1 101 Switching Protocols\r\n" . "Upgrade: websocket\r\n" . "Sec-WebSocket-Version: 13\r\n" . "Connection: Upgrade\r\n" - . "Sec-WebSocket-Accept: " . $new_key . "\r\n"; + . "Sec-WebSocket-Accept: " . $newKey . "\r\n"; // Websocket data buffer. $connection->context->websocketDataBuffer = ''; @@ -362,13 +362,13 @@ public static function dealHandshake($buffer, TcpConnection $connection) // Current websocket frame data. $connection->context->websocketCurrentFrameBuffer = ''; // Consume handshake data. - $connection->consumeRecvBuffer($header_length); + $connection->consumeRecvBuffer($headerLength); // Try to emit onWebSocketConnect callback. - $on_websocket_connect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; - if ($on_websocket_connect) { + $onWebsocketConnect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; + if ($onWebsocketConnect) { try { - $on_websocket_connect($connection, new Request($buffer)); + $onWebsocketConnect($connection, new Request($buffer)); } catch (\Throwable $e) { Worker::stopAll(250, $e); } @@ -379,29 +379,29 @@ public static function dealHandshake($buffer, TcpConnection $connection) $connection->websocketType = static::BINARY_TYPE_BLOB; } - $has_server_header = false; + $hasServerHeader = false; if (isset($connection->headers)) { if (\is_array($connection->headers)) { foreach ($connection->headers as $header) { if (\stripos($header, 'Server:') === 0) { - $has_server_header = true; + $hasServerHeader = true; } - $handshake_message .= "$header\r\n"; + $handshakeMessage .= "$header\r\n"; } } else { if (\stripos($connection->headers, 'Server:') !== false) { - $has_server_header = true; + $hasServerHeader = true; } - $handshake_message .= "$connection->headers\r\n"; + $handshakeMessage .= "$connection->headers\r\n"; } } - if (!$has_server_header) { - $handshake_message .= "Server: workerman/" . Worker::VERSION . "\r\n"; + if (!$hasServerHeader) { + $handshakeMessage .= "Server: workerman/" . Worker::VERSION . "\r\n"; } - $handshake_message .= "\r\n"; + $handshakeMessage .= "\r\n"; // Send handshake response. - $connection->send($handshake_message, true); + $connection->send($handshakeMessage, true); // Mark handshake complete.. $connection->context->websocketHandshake = true; @@ -410,8 +410,8 @@ public static function dealHandshake($buffer, TcpConnection $connection) $connection->send($connection->context->tmpWebsocketData, true); $connection->context->tmpWebsocketData = ''; } - if (\strlen($buffer) > $header_length) { - return static::input(\substr($buffer, $header_length), $connection); + if (\strlen($buffer) > $headerLength) { + return static::input(\substr($buffer, $headerLength), $connection); } return 0; } diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index d1be0b884..63bf91a83 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -55,14 +55,14 @@ public static function input($buffer, ConnectionInterface $connection) if ($connection->handshakeStep === 1) { return self::dealHandshake($buffer, $connection); } - $recv_len = \strlen($buffer); - if ($recv_len < 2) { + $recvLen = \strlen($buffer); + if ($recvLen < 2) { return 0; } // Buffer websocket frame data. if ($connection->websocketCurrentFrameLength) { // We need more frame data. - if ($connection->websocketCurrentFrameLength > $recv_len) { + if ($connection->websocketCurrentFrameLength > $recvLen) { // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1. return 0; } @@ -70,8 +70,8 @@ public static function input($buffer, ConnectionInterface $connection) $firstbyte = \ord($buffer[0]); $secondbyte = \ord($buffer[1]); - $data_len = $secondbyte & 127; - $is_fin_frame = $firstbyte >> 7; + $dataLen = $secondbyte & 127; + $isFinFrame = $firstbyte >> 7; $masked = $secondbyte >> 7; if ($masked) { @@ -118,92 +118,92 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } // Calculate packet length. - if ($data_len === 126) { + if ($dataLen === 126) { if (\strlen($buffer) < 4) { return 0; } $pack = \unpack('nn/ntotal_len', $buffer); - $current_frame_length = $pack['total_len'] + 4; - } else if ($data_len === 127) { + $currentFrameLength = $pack['total_len'] + 4; + } else if ($dataLen === 127) { if (\strlen($buffer) < 10) { return 0; } $arr = \unpack('n/N2c', $buffer); - $current_frame_length = $arr['c1'] * 4294967296 + $arr['c2'] + 10; + $currentFrameLength = $arr['c1'] * 4294967296 + $arr['c2'] + 10; } else { - $current_frame_length = $data_len + 2; + $currentFrameLength = $dataLen + 2; } - $total_package_size = \strlen($connection->websocketDataBuffer) + $current_frame_length; - if ($total_package_size > $connection->maxPackageSize) { - Worker::safeEcho("error package. package_length=$total_package_size\n"); + $totalPackageSize = \strlen($connection->websocketDataBuffer) + $currentFrameLength; + if ($totalPackageSize > $connection->maxPackageSize) { + Worker::safeEcho("error package. package_length=$totalPackageSize\n"); $connection->close(); return 0; } - if ($is_fin_frame) { + if ($isFinFrame) { if ($opcode === 0x9) { - if ($recv_len >= $current_frame_length) { - $ping_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); - $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + if ($recvLen >= $currentFrameLength) { + $pingData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $connection->consumeRecvBuffer($currentFrameLength); + $tmpConnectionType = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing)) { try { - ($connection->onWebSocketPing)($connection, $ping_data); + ($connection->onWebSocketPing)($connection, $pingData); } catch (\Throwable $e) { Worker::stopAll(250, $e); } } else { - $connection->send($ping_data); + $connection->send($pingData); } - $connection->websocketType = $tmp_connection_type; - if ($recv_len > $current_frame_length) { - return static::input(\substr($buffer, $current_frame_length), $connection); + $connection->websocketType = $tmpConnectionType; + if ($recvLen > $currentFrameLength) { + return static::input(\substr($buffer, $currentFrameLength), $connection); } } return 0; } else if ($opcode === 0xa) { - if ($recv_len >= $current_frame_length) { - $pong_data = static::decode(\substr($buffer, 0, $current_frame_length), $connection); - $connection->consumeRecvBuffer($current_frame_length); - $tmp_connection_type = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + if ($recvLen >= $currentFrameLength) { + $pongData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $connection->consumeRecvBuffer($currentFrameLength); + $tmpConnectionType = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong)) { try { - ($connection->onWebSocketPong)($connection, $pong_data); + ($connection->onWebSocketPong)($connection, $pongData); } catch (\Throwable $e) { Worker::stopAll(250, $e); } } - $connection->websocketType = $tmp_connection_type; - if ($recv_len > $current_frame_length) { - return static::input(\substr($buffer, $current_frame_length), $connection); + $connection->websocketType = $tmpConnectionType; + if ($recvLen > $currentFrameLength) { + return static::input(\substr($buffer, $currentFrameLength), $connection); } } return 0; } - return $current_frame_length; + return $currentFrameLength; } else { - $connection->websocketCurrentFrameLength = $current_frame_length; + $connection->websocketCurrentFrameLength = $currentFrameLength; } } // Received just a frame length data. - if ($connection->websocketCurrentFrameLength === $recv_len) { + if ($connection->websocketCurrentFrameLength === $recvLen) { self::decode($buffer, $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); $connection->websocketCurrentFrameLength = 0; return 0; } // The length of the received data is greater than the length of a frame. - elseif ($connection->websocketCurrentFrameLength < $recv_len) { + elseif ($connection->websocketCurrentFrameLength < $recvLen) { self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $current_frame_length = $connection->websocketCurrentFrameLength; + $currentFrameLength = $connection->websocketCurrentFrameLength; $connection->websocketCurrentFrameLength = 0; // Continue to read next frame. - return self::input(\substr($buffer, $current_frame_length), $connection); + return self::input(\substr($buffer, $currentFrameLength), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -227,25 +227,25 @@ public static function encode($payload, ConnectionInterface $connection) static::sendHandshake($connection); } $mask = 1; - $mask_key = "\x00\x00\x00\x00"; + $maskKey = "\x00\x00\x00\x00"; $pack = ''; - $length = $length_flag = \strlen($payload); + $length = $lengthFlag = \strlen($payload); if (65535 < $length) { $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); - $length_flag = 127; + $lengthFlag = 127; } else if (125 < $length) { $pack = \pack('n*', $length); - $length_flag = 126; + $lengthFlag = 126; } - $head = ($mask << 7) | $length_flag; + $head = ($mask << 7) | $lengthFlag; $head = $connection->websocketType . \chr($head) . $pack; - $frame = $head . $mask_key; + $frame = $head . $maskKey; // append payload to frame: - $mask_key = \str_repeat($mask_key, \floor($length / 4)) . \substr($mask_key, 0, $length % 4); - $frame .= $payload ^ $mask_key; + $maskKey = \str_repeat($maskKey, \floor($length / 4)) . \substr($maskKey, 0, $length % 4); + $frame .= $payload ^ $maskKey; if ($connection->handshakeStep === 1) { // If buffer has already full then discard the current package. if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { @@ -283,24 +283,24 @@ public static function encode($payload, ConnectionInterface $connection) */ public static function decode($bytes, ConnectionInterface $connection) { - $data_length = \ord($bytes[1]); + $dataLength = \ord($bytes[1]); - if ($data_length === 126) { - $decoded_data = \substr($bytes, 4); - } else if ($data_length === 127) { - $decoded_data = \substr($bytes, 10); + if ($dataLength === 126) { + $decodedData = \substr($bytes, 4); + } else if ($dataLength === 127) { + $decodedData = \substr($bytes, 10); } else { - $decoded_data = \substr($bytes, 2); + $decodedData = \substr($bytes, 2); } if ($connection->websocketCurrentFrameLength) { - $connection->websocketDataBuffer .= $decoded_data; + $connection->websocketDataBuffer .= $decodedData; return $connection->websocketDataBuffer; } else { if ($connection->websocketDataBuffer !== '') { - $decoded_data = $connection->websocketDataBuffer . $decoded_data; + $decodedData = $connection->websocketDataBuffer . $decodedData; $connection->websocketDataBuffer = ''; } - return $decoded_data; + return $decodedData; } } @@ -347,26 +347,26 @@ public static function sendHandshake(TcpConnection $connection) $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->websocketSecKey = \base64_encode(random_bytes(16)); - $user_header = $connection->headers ?? $connection->wsHttpHeader ?? null; - $user_header_str = ''; - if (!empty($user_header)) { - if (\is_array($user_header)) { - foreach ($user_header as $k => $v) { - $user_header_str .= "$k: $v\r\n"; + $userHeader = $connection->headers ?? $connection->wsHttpHeader ?? null; + $userHeaderStr = ''; + if (!empty($userHeader)) { + if (\is_array($userHeader)) { + foreach ($userHeader as $k => $v) { + $userHeaderStr .= "$k: $v\r\n"; } } else { - $user_header_str .= $user_header; + $userHeaderStr .= $userHeader; } - $user_header_str = "\r\n" . \trim($user_header_str); + $userHeaderStr = "\r\n" . \trim($userHeaderStr); } $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" . - (!\preg_match("/\nHost:/i", $user_header_str) ? "Host: $host\r\n" : '') . + (!\preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . (isset($connection->WSClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->WSClientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . - "Sec-WebSocket-Key: " . $connection->websocketSecKey . $user_header_str . "\r\n\r\n"; + "Sec-WebSocket-Key: " . $connection->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); $connection->handshakeStep = 1; $connection->websocketCurrentFrameLength = 0; @@ -406,11 +406,11 @@ public static function dealHandshake($buffer, TcpConnection $connection) } $connection->handshakeStep = 2; - $handshake_response_length = $pos + 4; + $handshakeResponseLength = $pos + 4; // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshake_response_length)); + ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshakeResponseLength)); } catch (\Throwable $e) { Worker::stopAll(250, $e); } @@ -425,13 +425,13 @@ public static function dealHandshake($buffer, TcpConnection $connection) }); } - $connection->consumeRecvBuffer($handshake_response_length); + $connection->consumeRecvBuffer($handshakeResponseLength); if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } - if (\strlen($buffer) > $handshake_response_length) { - return self::input(\substr($buffer, $handshake_response_length), $connection); + if (\strlen($buffer) > $handshakeResponseLength) { + return self::input(\substr($buffer, $handshakeResponseLength), $connection); } } return 0; diff --git a/src/Timer.php b/src/Timer.php index 3f5f0236c..47585738a 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -94,15 +94,15 @@ public static function signalHandle() /** * Add a timer. * - * @param float $time_interval + * @param float $timeInterval * @param callable $func * @param mixed $args * @param bool $persistent * @return int|bool */ - public static function add(float $time_interval, $func, $args = [], $persistent = true) + public static function add(float $timeInterval, $func, $args = [], $persistent = true) { - if ($time_interval < 0) { + if ($timeInterval < 0) { Worker::safeEcho(new Exception("bad time_interval")); return false; } @@ -112,7 +112,7 @@ public static function add(float $time_interval, $func, $args = [], $persistent } if (self::$event) { - return $persistent ? self::$event->repeat($time_interval, $func, $args) : self::$event->delay($time_interval, $func, $args); + return $persistent ? self::$event->repeat($timeInterval, $func, $args) : self::$event->delay($timeInterval, $func, $args); } // If not workerman runtime just return. @@ -129,14 +129,14 @@ public static function add(float $time_interval, $func, $args = [], $persistent \pcntl_alarm(1); } - $run_time = \time() + $time_interval; - if (!isset(self::$tasks[$run_time])) { - self::$tasks[$run_time] = []; + $runTime = \time() + $timeInterval; + if (!isset(self::$tasks[$runTime])) { + self::$tasks[$runTime] = []; } self::$timerId = self::$timerId == \PHP_INT_MAX ? 1 : ++self::$timerId; self::$status[self::$timerId] = true; - self::$tasks[$run_time][self::$timerId] = [$func, (array)$args, $persistent, $time_interval]; + self::$tasks[$runTime][self::$timerId] = [$func, (array)$args, $persistent, $timeInterval]; return self::$timerId; } @@ -164,26 +164,26 @@ public static function tick() \pcntl_alarm(0); return; } - $time_now = \time(); - foreach (self::$tasks as $run_time => $task_data) { - if ($time_now >= $run_time) { - foreach ($task_data as $index => $one_task) { - $task_func = $one_task[0]; - $task_args = $one_task[1]; - $persistent = $one_task[2]; - $time_interval = $one_task[3]; + $timeNow = \time(); + foreach (self::$tasks as $runTime => $taskData) { + if ($timeNow >= $runTime) { + foreach ($taskData as $index => $oneTask) { + $taskFunc = $oneTask[0]; + $taskArgs = $oneTask[1]; + $persistent = $oneTask[2]; + $timeInterval = $oneTask[3]; try { - $task_func(...$task_args); + $taskFunc(...$taskArgs); } catch (\Throwable $e) { Worker::safeEcho($e); } if($persistent && !empty(self::$status[$index])) { - $new_run_time = \time() + $time_interval; - if(!isset(self::$tasks[$new_run_time])) self::$tasks[$new_run_time] = []; - self::$tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval]; + $newRunTime = \time() + $timeInterval; + if(!isset(self::$tasks[$newRunTime])) self::$tasks[$newRunTime] = []; + self::$tasks[$newRunTime][$index] = [$taskFunc, (array)$taskArgs, $persistent, $timeInterval]; } } - unset(self::$tasks[$run_time]); + unset(self::$tasks[$runTime]); } } } @@ -191,21 +191,21 @@ public static function tick() /** * Remove a timer. * - * @param mixed $timer_id + * @param mixed $timerId * @return bool */ - public static function del($timer_id) + public static function del($timerId) { if (self::$event) { - return self::$event->deleteTimer($timer_id); + return self::$event->deleteTimer($timerId); } - foreach(self::$tasks as $run_time => $task_data) + foreach(self::$tasks as $runTime => $taskData) { - if(array_key_exists($timer_id, $task_data)) unset(self::$tasks[$run_time][$timer_id]); + if(array_key_exists($timerId, $taskData)) unset(self::$tasks[$runTime][$timerId]); } - if(array_key_exists($timer_id, self::$status)) unset(self::$status[$timer_id]); + if(array_key_exists($timerId, self::$status)) unset(self::$status[$timerId]); return true; } diff --git a/src/Worker.php b/src/Worker.php index 98c4878e7..982b64d48 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -587,11 +587,11 @@ protected static function init() $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); static::$startFile = end($backtrace)['file']; - $unique_prefix = \str_replace('/', '_', static::$startFile); + $uniquePrefix = \str_replace('/', '_', static::$startFile); // Pid file. if (empty(static::$pidFile)) { - static::$pidFile = __DIR__ . "/../$unique_prefix.pid"; + static::$pidFile = __DIR__ . "/../$uniquePrefix.pid"; } // Log file. @@ -635,16 +635,16 @@ protected static function lock($flag = \LOCK_EX) if (\DIRECTORY_SEPARATOR !== '/') { return; } - $lock_file = static::$pidFile . '.lock'; - $fd = $fd ?: \fopen($lock_file, 'a+'); + $lockFile = static::$pidFile . '.lock'; + $fd = $fd ?: \fopen($lockFile, 'a+'); if ($fd) { flock($fd, $flag); if ($flag === \LOCK_UN) { fclose($fd); $fd = null; clearstatcache(); - if (\is_file($lock_file)) { - unlink($lock_file); + if (\is_file($lockFile)) { + unlink($lockFile); } } } @@ -683,11 +683,11 @@ protected static function initWorkers() $worker->sate = ' [OK] '; // Get column mapping for UI - foreach(static::getUiColumns() as $column_name => $prop){ + foreach(static::getUiColumns() as $columnName => $prop){ !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; - $prop_length = \strlen($worker->{$prop}); - $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - static::$$key = \max(static::$$key, $prop_length); + $propLength = \strlen($worker->{$prop}); + $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; + static::$$key = \max(static::$$key, $propLength); } // Listen. @@ -745,13 +745,13 @@ public function getMainSocket(){ */ protected static function initId() { - foreach (static::$workers as $worker_id => $worker) { - $new_id_map = []; + foreach (static::$workers as $workerId => $worker) { + $newIdMap = []; $worker->count = max($worker->count, 1); for ($key = 0; $key < $worker->count; $key++) { - $new_id_map[$key] = static::$idMap[$worker_id][$key] ?? 0; + $newIdMap[$key] = static::$idMap[$workerId][$key] ?? 0; } - static::$idMap[$worker_id] = $new_id_map; + static::$idMap[$workerId] = $newIdMap; } } @@ -762,8 +762,8 @@ protected static function initId() */ protected static function getCurrentUser() { - $user_info = \posix_getpwuid(\posix_getuid()); - return $user_info['name']; + $userInfo = \posix_getpwuid(\posix_getuid()); + return $userInfo['name']; } /** @@ -773,8 +773,8 @@ protected static function getCurrentUser() */ protected static function displayUI() { - $tmp_argv = static::getArgv(); - if (\in_array('-q', $tmp_argv)) { + $tmpArgv = static::getArgv(); + if (\in_array('-q', $tmpArgv)) { return; } if (\DIRECTORY_SEPARATOR !== '/') { @@ -786,43 +786,43 @@ protected static function displayUI() } //show version - $line_version = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; - !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($line_version)); - $total_length = static::getSingleLineTotalLength(); - $line_one = '' . \str_pad(' WORKERMAN ', $total_length + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; - $line_two = \str_pad(' WORKERS ' , $total_length + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; - static::safeEcho($line_one . $line_version . $line_two); + $lineVersion = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; + !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($lineVersion)); + $totalLength = static::getSingleLineTotalLength(); + $lineOne = '' . \str_pad(' WORKERMAN ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; + $lineTwo = \str_pad(' WORKERS ' , $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; + static::safeEcho($lineOne . $lineVersion . $lineTwo); //Show title $title = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + foreach(static::getUiColumns() as $columnName => $prop){ + $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; //just keep compatible with listen name - $column_name === 'socket' && $column_name = 'listen'; - $title.= "{$column_name}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($column_name)); + $columnName === 'socket' && $columnName = 'listen'; + $title.= "{$columnName}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); } $title && static::safeEcho($title . \PHP_EOL); //Show content foreach (static::$workers as $worker) { $content = ''; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; + foreach(static::getUiColumns() as $columnName => $prop){ + $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); - $place_holder_length = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; - $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $place_holder_length); + $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; + $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); } $content && static::safeEcho($content . \PHP_EOL); } //Show last line - $line_last = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL; - !empty($content) && static::safeEcho($line_last); + $lineLast = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL; + !empty($content) && static::safeEcho($lineLast); if (static::$daemonize) { global $argv; - $start_file = $argv[0]; - static::safeEcho('Input "php '. $start_file . ' stop" to stop. Start success.' . "\n\n"); + $startFile = $argv[0]; + static::safeEcho('Input "php '. $startFile . ' stop" to stop. Start success.' . "\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } @@ -831,7 +831,7 @@ protected static function displayUI() /** * Get UI columns to be shown in terminal * - * 1. $column_map: ['ui_column_name' => 'clas_property_name'] + * 1. $columnMap: ['ui_column_name' => 'clas_property_name'] * 2. Consider move into configuration in future * * @return array @@ -855,18 +855,18 @@ public static function getUiColumns() */ public static function getSingleLineTotalLength() { - $total_length = 0; + $totalLength = 0; - foreach(static::getUiColumns() as $column_name => $prop){ - $key = 'max' . \ucfirst(\strtolower($column_name)) . 'NameLength'; - $total_length += static::$$key + static::UI_SAFE_LENGTH; + foreach(static::getUiColumns() as $columnName => $prop){ + $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; + $totalLength += static::$$key + static::UI_SAFE_LENGTH; } //keep beauty when show less colums !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', 0); - $total_length <= LINE_VERSIOIN_LENGTH && $total_length = LINE_VERSIOIN_LENGTH; + $totalLength <= LINE_VERSIOIN_LENGTH && $totalLength = LINE_VERSIOIN_LENGTH; - return $total_length; + return $totalLength; } /** @@ -881,9 +881,9 @@ protected static function parseCommand() } global $argv; // Check argv; - $start_file = $argv[0]; + $startFile = $argv[0]; $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; - $available_commands = [ + $availableCommands = [ 'start', 'stop', 'restart', @@ -891,15 +891,15 @@ protected static function parseCommand() 'status', 'connections', ]; - $available_mode = [ + $availableMode = [ '-d', '-g' ]; $command = $mode = ''; foreach (static::getArgv() as $value) { - if (\in_array($value, $available_commands)) { + if (\in_array($value, $availableCommands)) { $command = $value; - } elseif (\in_array($value, $available_mode)) { + } elseif (\in_array($value, $availableMode)) { $mode = $value; } } @@ -909,30 +909,30 @@ protected static function parseCommand() } // Start command. - $mode_str = ''; + $modeStr = ''; if ($command === 'start') { if ($mode === '-d' || static::$daemonize) { - $mode_str = 'in DAEMON mode'; + $modeStr = 'in DAEMON mode'; } else { - $mode_str = 'in DEBUG mode'; + $modeStr = 'in DEBUG mode'; } } - static::log("Workerman[$start_file] $command $mode_str"); + static::log("Workerman[$startFile] $command $modeStr"); // Get master process PID. - $master_pid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; + $masterPid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; // Master is still alive? - if (static::checkMasterIsAlive($master_pid)) { + if (static::checkMasterIsAlive($masterPid)) { if ($command === 'start') { - static::log("Workerman[$start_file] already running"); + static::log("Workerman[$startFile] already running"); exit; } } elseif ($command !== 'start' && $command !== 'restart') { - static::log("Workerman[$start_file] not run"); + static::log("Workerman[$startFile] not run"); exit; } - $statistics_file = static::$statusFile ?: __DIR__ . "/../workerman-$master_pid.status"; + $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.status"; // execute command. switch ($command) { @@ -943,11 +943,11 @@ protected static function parseCommand() break; case 'status': while (1) { - if (\is_file($statistics_file)) { - @\unlink($statistics_file); + if (\is_file($statisticsFile)) { + @\unlink($statisticsFile); } // Master process will send SIGIOT signal to all child processes. - \posix_kill($master_pid, SIGIOT); + \posix_kill($masterPid, SIGIOT); // Sleep 1 second. \sleep(1); // Clear terminal. @@ -955,7 +955,7 @@ protected static function parseCommand() static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - static::safeEcho(static::formatStatusData($statistics_file)); + static::safeEcho(static::formatStatusData($statisticsFile)); if ($mode !== '-d') { exit(0); } @@ -963,16 +963,16 @@ protected static function parseCommand() } exit(0); case 'connections': - if (\is_file($statistics_file) && \is_writable($statistics_file)) { - \unlink($statistics_file); + if (\is_file($statisticsFile) && \is_writable($statisticsFile)) { + \unlink($statisticsFile); } // Master process will send SIGIO signal to all child processes. - \posix_kill($master_pid, SIGIO); + \posix_kill($masterPid, SIGIO); // Waiting amoment. \usleep(500000); // Display statisitcs data from a disk file. - if(\is_readable($statistics_file)) { - \readfile($statistics_file); + if(\is_readable($statisticsFile)) { + \readfile($statisticsFile); } exit(0); case 'restart': @@ -980,24 +980,24 @@ protected static function parseCommand() if ($mode === '-g') { static::$gracefulStop = true; $sig = \SIGQUIT; - static::log("Workerman[$start_file] is gracefully stopping ..."); + static::log("Workerman[$startFile] is gracefully stopping ..."); } else { static::$gracefulStop = false; $sig = \SIGINT; - static::log("Workerman[$start_file] is stopping ..."); + static::log("Workerman[$startFile] is stopping ..."); } // Send stop signal to master process. - $master_pid && \posix_kill($master_pid, $sig); + $masterPid && \posix_kill($masterPid, $sig); // Timeout. $timeout = static::$stopTimeout + 3; - $start_time = \time(); + $startTime = \time(); // Check master process is still alive? while (1) { - $master_is_alive = $master_pid && \posix_kill($master_pid, 0); - if ($master_is_alive) { + $masterIsAlive = $masterPid && \posix_kill($masterPid, 0); + if ($masterIsAlive) { // Timeout? - if (!static::$gracefulStop && \time() - $start_time >= $timeout) { - static::log("Workerman[$start_file] stop fail"); + if (!static::$gracefulStop && \time() - $startTime >= $timeout) { + static::log("Workerman[$startFile] stop fail"); exit; } // Waiting amoment. @@ -1005,7 +1005,7 @@ protected static function parseCommand() continue; } // Stop success. - static::log("Workerman[$start_file] stop success"); + static::log("Workerman[$startFile] stop success"); if ($command === 'stop') { exit(0); } @@ -1021,7 +1021,7 @@ protected static function parseCommand() }else{ $sig = \SIGUSR1; } - \posix_kill($master_pid, $sig); + \posix_kill($masterPid, $sig); exit; default : static::safeEcho('Unknown command: ' . $command . "\n"); @@ -1038,84 +1038,84 @@ public static function getArgv() /** * Format status data. * - * @param $statistics_file + * @param $statisticsFile * @return string */ - protected static function formatStatusData($statistics_file) + protected static function formatStatusData($statisticsFile) { - static $total_request_cache = []; - if (!\is_readable($statistics_file)) { + static $totalRequestCache = []; + if (!\is_readable($statisticsFile)) { return ''; } - $info = \file($statistics_file, \FILE_IGNORE_NEW_LINES); + $info = \file($statisticsFile, \FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } - $status_str = ''; - $current_total_request = []; - $worker_info = \unserialize($info[0]); - \ksort($worker_info, SORT_NUMERIC); + $statusStr = ''; + $currentTotalRequest = []; + $workerInfo = \unserialize($info[0]); + \ksort($workerInfo, SORT_NUMERIC); unset($info[0]); - $data_waiting_sort = []; - $read_process_status = false; - $total_requests = 0; - $total_qps = 0; - $total_connections = 0; - $total_fails = 0; - $total_memory = 0; - $total_timers = 0; + $dataWaitingSort = []; + $readProcessStatus = false; + $totalRequests = 0; + $totalQps = 0; + $totalConnections = 0; + $totalFails = 0; + $totalMemory = 0; + $totalTimers = 0; $maxLen1 = static::$maxSocketNameLength; $maxLen2 = static::$maxWorkerNameLength; foreach($info as $value) { - if (!$read_process_status) { - $status_str .= $value . "\n"; + if (!$readProcessStatus) { + $statusStr .= $value . "\n"; if (\preg_match('/^pid.*?memory.*?listening/', $value)) { - $read_process_status = true; + $readProcessStatus = true; } continue; } - if(\preg_match('/^[0-9]+/', $value, $pid_math)) { - $pid = $pid_math[0]; - $data_waiting_sort[$pid] = $value; + if(\preg_match('/^[0-9]+/', $value, $pidMath)) { + $pid = $pidMath[0]; + $dataWaitingSort[$pid] = $value; if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $total_memory += \intval(\str_ireplace('M','',$match[1])); + $totalMemory += \intval(\str_ireplace('M','',$match[1])); $maxLen1 = \max($maxLen1,\strlen($match[2])); $maxLen2 = \max($maxLen2,\strlen($match[3])); - $total_connections += \intval($match[4]); - $total_fails += \intval($match[5]); - $total_timers += \intval($match[6]); - $current_total_request[$pid] = $match[7]; - $total_requests += \intval($match[7]); + $totalConnections += \intval($match[4]); + $totalFails += \intval($match[5]); + $totalTimers += \intval($match[6]); + $currentTotalRequest[$pid] = $match[7]; + $totalRequests += \intval($match[7]); } } } - foreach($worker_info as $pid => $info) { - if (!isset($data_waiting_sort[$pid])) { - $status_str .= "$pid\t" . \str_pad('N/A', 7) . " " + foreach($workerInfo as $pid => $info) { + if (!isset($dataWaitingSort[$pid])) { + $statusStr .= "$pid\t" . \str_pad('N/A', 7) . " " . \str_pad($info['listen'], static::$maxSocketNameLength) . " " . \str_pad($info['name'], static::$maxWorkerNameLength) . " " . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; continue; } - //$qps = isset($total_request_cache[$pid]) ? $current_total_request[$pid] - if (!isset($total_request_cache[$pid]) || !isset($current_total_request[$pid])) { + //$qps = isset($totalRequestCache[$pid]) ? $currentTotalRequest[$pid] + if (!isset($totalRequestCache[$pid]) || !isset($currentTotalRequest[$pid])) { $qps = 0; } else { - $qps = $current_total_request[$pid] - $total_request_cache[$pid]; - $total_qps += $qps; + $qps = $currentTotalRequest[$pid] - $totalRequestCache[$pid]; + $totalQps += $qps; } - $status_str .= $data_waiting_sort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n"; + $statusStr .= $dataWaitingSort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n"; } - $total_request_cache = $current_total_request; - $status_str .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $status_str .= "Summary\t" . \str_pad($total_memory.'M', 7) . " " + $totalRequestCache = $currentTotalRequest; + $statusStr .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; + $statusStr .= "Summary\t" . \str_pad($totalMemory.'M', 7) . " " . \str_pad('-', $maxLen1) . " " . \str_pad('-', $maxLen2) . " " - . \str_pad($total_connections, 11) . " " . \str_pad($total_fails, 9) . " " - . \str_pad($total_timers, 7) . " " . \str_pad($total_requests, 13) . " " - . \str_pad($total_qps,6)." [Summary] \n"; - return $status_str; + . \str_pad($totalConnections, 11) . " " . \str_pad($totalFails, 9) . " " + . \str_pad($totalTimers, 7) . " " . \str_pad($totalRequests, 13) . " " + . \str_pad($totalQps,6)." [Summary] \n"; + return $statusStr; } @@ -1225,11 +1225,11 @@ protected static function daemonize() /** * Redirect standard input and output. * - * @param bool $throw_exception + * @param bool $throwException * @return void * @throws Exception */ - public static function resetStd(bool $throw_exception = true) + public static function resetStd(bool $throwException = true) { if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; @@ -1265,7 +1265,7 @@ public static function resetStd(bool $throw_exception = true) \restore_error_handler(); return; } - if ($throw_exception) { + if ($throwException) { throw new Exception('Can not open stdoutFile ' . static::$stdoutFile); } } @@ -1302,16 +1302,16 @@ protected static function getEventLoopName(): string unset(static::$availableEventLoops['swoole']); } - $loop_name = ''; + $loopName = ''; foreach (static::$availableEventLoops as $name => $class) { if (\extension_loaded($name)) { - $loop_name = $name; + $loopName = $name; break; } } - if ($loop_name) { - static::$eventLoopClass = static::$availableEventLoops[$loop_name]; + if ($loopName) { + static::$eventLoopClass = static::$availableEventLoops[$loopName]; } else { static::$eventLoopClass = Select::class; } @@ -1325,13 +1325,13 @@ protected static function getEventLoopName(): string */ protected static function getAllWorkerPids() { - $pid_array = []; - foreach (static::$pidMap as $worker_pid_array) { - foreach ($worker_pid_array as $worker_pid) { - $pid_array[$worker_pid] = $worker_pid; + $pidArray = []; + foreach (static::$pidMap as $workerPidArray) { + foreach ($workerPidArray as $workerPid) { + $pidArray[$workerPid] = $workerPid; } } - return $pid_array; + return $pidArray; } /** @@ -1361,9 +1361,9 @@ protected static function forkWorkersForLinux() if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } - $worker_name_length = \strlen($worker->name); - if (static::$maxWorkerNameLength < $worker_name_length) { - static::$maxWorkerNameLength = $worker_name_length; + $workerNameLength = \strlen($worker->name); + if (static::$maxWorkerNameLength < $workerNameLength) { + static::$maxWorkerNameLength = $workerNameLength; } } @@ -1407,9 +1407,9 @@ protected static function forkWorkersForWindows() { static::$globalEvent = new Select(); Timer::init(static::$globalEvent); - foreach($files as $start_file) + foreach($files as $startFile) { - static::forkOneWorkerForWindows($start_file); + static::forkOneWorkerForWindows($startFile); } } } @@ -1434,18 +1434,18 @@ public static function getStartFilesForWindows() { /** * Fork one worker process. * - * @param string $start_file + * @param string $startFile */ - public static function forkOneWorkerForWindows($start_file) + public static function forkOneWorkerForWindows($startFile) { - $start_file = \realpath($start_file); + $startFile = \realpath($startFile); $descriptorspec = array( STDIN, STDOUT, STDOUT ); $pipes = array(); - $process = \proc_open("php \"$start_file\" -q", $descriptorspec, $pipes); + $process = \proc_open("php \"$startFile\" -q", $descriptorspec, $pipes); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1453,7 +1453,7 @@ public static function forkOneWorkerForWindows($start_file) } // 保存子进程句柄 - static::$processForWindows[$start_file] = array($process, $start_file); + static::$processForWindows[$startFile] = array($process, $startFile); } /** @@ -1462,18 +1462,18 @@ public static function forkOneWorkerForWindows($start_file) */ public static function checkWorkerStatusForWindows() { - foreach(static::$processForWindows as $process_data) + foreach(static::$processForWindows as $processData) { - $process = $process_data[0]; - $start_file = $process_data[1]; + $process = $processData[0]; + $startFile = $processData[1]; $status = \proc_get_status($process); if(isset($status['running'])) { if(!$status['running']) { - static::safeEcho("process $start_file terminated and try to restart\n"); + static::safeEcho("process $startFile terminated and try to restart\n"); \proc_close($process); - static::forkOneWorkerForWindows($start_file); + static::forkOneWorkerForWindows($startFile); } } else @@ -1512,9 +1512,9 @@ protected static function forkOneWorkerForLinux(self $worker) } static::$pidsToRestart = static::$pidMap = []; // Remove other listener. - foreach(static::$workers as $key => $one_worker) { - if ($one_worker->workerId !== $worker->workerId) { - $one_worker->unlisten(); + foreach(static::$workers as $key => $oneWorker) { + if ($oneWorker->workerId !== $worker->workerId) { + $oneWorker->unlisten(); unset(static::$workers[$key]); } } @@ -1537,14 +1537,14 @@ protected static function forkOneWorkerForLinux(self $worker) /** * Get worker id. * - * @param string $worker_id + * @param string $workerId * @param int $pid * * @return integer */ - protected static function getId($worker_id, $pid) + protected static function getId($workerId, $pid) { - return \array_search($pid, static::$idMap[$worker_id]); + return \array_search($pid, static::$idMap[$workerId]); } /** @@ -1555,27 +1555,27 @@ protected static function getId($worker_id, $pid) public function setUserAndGroup() { // Get uid. - $user_info = \posix_getpwnam($this->user); - if (!$user_info) { + $userInfo = \posix_getpwnam($this->user); + if (!$userInfo) { static::log("Warning: User {$this->user} not exists"); return; } - $uid = $user_info['uid']; + $uid = $userInfo['uid']; // Get gid. if ($this->group) { - $group_info = \posix_getgrnam($this->group); - if (!$group_info) { + $groupInfo = \posix_getgrnam($this->group); + if (!$groupInfo) { static::log("Warning: Group {$this->group} not exists"); return; } - $gid = $group_info['gid']; + $gid = $groupInfo['gid']; } else { - $gid = $user_info['gid']; + $gid = $userInfo['gid']; } // Set uid and gid. if ($uid !== \posix_getuid() || $gid !== \posix_getgid()) { - if (!\posix_setgid($gid) || !\posix_initgroups($user_info['name'], $gid) || !\posix_setuid($uid)) { + if (!\posix_setgid($gid) || !\posix_initgroups($userInfo['name'], $gid) || !\posix_setuid($uid)) { static::log("Warning: change gid or uid fail."); } } @@ -1627,9 +1627,9 @@ protected static function monitorWorkersForLinux() // If a child has already exited. if ($pid > 0) { // Find out which worker process exited. - foreach (static::$pidMap as $worker_id => $worker_pid_array) { - if (isset($worker_pid_array[$pid])) { - $worker = static::$workers[$worker_id]; + foreach (static::$pidMap as $workerId => $workerPidArray) { + if (isset($workerPidArray[$pid])) { + $worker = static::$workers[$workerId]; // Exit status. if ($status !== 0) { static::log("worker[{$worker->name}:$pid] exit with status $status"); @@ -1645,17 +1645,17 @@ protected static function monitorWorkersForLinux() } // For Statistics. - if (!isset(static::$globalStatistics['worker_exit_info'][$worker_id][$status])) { - static::$globalStatistics['worker_exit_info'][$worker_id][$status] = 0; + if (!isset(static::$globalStatistics['worker_exit_info'][$workerId][$status])) { + static::$globalStatistics['worker_exit_info'][$workerId][$status] = 0; } - ++static::$globalStatistics['worker_exit_info'][$worker_id][$status]; + ++static::$globalStatistics['worker_exit_info'][$workerId][$status]; // Clear process data. - unset(static::$pidMap[$worker_id][$pid]); + unset(static::$pidMap[$workerId][$pid]); // Mark id is available. - $id = static::getId($worker_id, $pid); - static::$idMap[$worker_id][$id] = 0; + $id = static::getId($workerId, $pid); + static::$idMap[$workerId][$id] = 0; break; } @@ -1698,9 +1698,9 @@ protected static function monitorWorkersForWindows() protected static function exitAndClearAll() { foreach (static::$workers as $worker) { - $socket_name = $worker->getSocketName(); - if ($worker->transport === 'unix' && $socket_name) { - list(, $address) = \explode(':', $socket_name, 2); + $socketName = $worker->getSocketName(); + if ($worker->transport === 'unix' && $socketName) { + list(, $address) = \explode(':', $socketName, 2); $address = substr($address, strpos($address, '/') + 2); @\unlink($address); } @@ -1742,15 +1742,15 @@ protected static function reload() $sig = static::$gracefulStop ? \SIGUSR2 : \SIGUSR1; // Send reload signal to all child processes. - $reloadable_pid_array = []; - foreach (static::$pidMap as $worker_id => $worker_pid_array) { - $worker = static::$workers[$worker_id]; + $reloadablePidArray = []; + foreach (static::$pidMap as $workerId => $workerPidArray) { + $worker = static::$workers[$workerId]; if ($worker->reloadable) { - foreach ($worker_pid_array as $pid) { - $reloadable_pid_array[$pid] = $pid; + foreach ($workerPidArray as $pid) { + $reloadablePidArray[$pid] = $pid; } } else { - foreach ($worker_pid_array as $pid) { + foreach ($workerPidArray as $pid) { // Send reload signal to a worker process which reloadable is false. \posix_kill($pid, $sig); } @@ -1758,7 +1758,7 @@ protected static function reload() } // Get all pids that are waiting reload. - static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadable_pid_array); + static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadablePidArray); // Reload complete. if (empty(static::$pidsToRestart)) { @@ -1768,12 +1768,12 @@ protected static function reload() return; } // Continue reload. - $one_worker_pid = \current(static::$pidsToRestart); + $oneWorkerPid = \current(static::$pidsToRestart); // Send reload signal to a worker process. - \posix_kill($one_worker_pid, $sig); + \posix_kill($oneWorkerPid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. if(!static::$gracefulStop){ - Timer::add(static::$stopTimeout, '\posix_kill', [$one_worker_pid, \SIGKILL], false); + Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, \SIGKILL], false); } } // For child processes. else { @@ -1812,15 +1812,15 @@ public static function stopAll($code = 0, $log = '') // For master process. if (\DIRECTORY_SEPARATOR === '/' && static::$masterPid === \posix_getpid()) { static::log("Workerman[" . \basename(static::$startFile) . "] stopping ..."); - $worker_pid_array = static::getAllWorkerPids(); + $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. $sig = static::$gracefulStop ? \SIGQUIT : \SIGINT; // Fix exit with status 2 usleep(50000); - foreach ($worker_pid_array as $worker_pid) { - \posix_kill($worker_pid, $sig); + foreach ($workerPidArray as $workerPid) { + \posix_kill($workerPid, $sig); if(!static::$gracefulStop){ - Timer::add(static::$stopTimeout, '\posix_kill', [$worker_pid, \SIGKILL], false); + Timer::add(static::$stopTimeout, '\posix_kill', [$workerPid, \SIGKILL], false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); @@ -1857,10 +1857,10 @@ public static function stopAll($code = 0, $log = '') */ public static function checkIfChildRunning() { - foreach (static::$pidMap as $worker_id => $worker_pid_array) { - foreach ($worker_pid_array as $pid => $worker_pid) { + foreach (static::$pidMap as $workerId => $workerPidArray) { + foreach ($workerPidArray as $pid => $workerPid) { if (!\posix_kill($pid, 0)) { - unset(static::$pidMap[$worker_id][$pid]); + unset(static::$pidMap[$workerId][$pid]); } } } @@ -1895,16 +1895,16 @@ protected static function writeStatisticsToStatusFile() { // For master process. if (static::$masterPid === \posix_getpid()) { - $all_worker_info = []; - foreach(static::$pidMap as $worker_id => $pid_array) { + $allWorkerInfo = []; + foreach(static::$pidMap as $workerId => $pidArray) { /** @var /Workerman/Worker $worker */ - $worker = static::$workers[$worker_id]; - foreach($pid_array as $pid) { - $all_worker_info[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; + $worker = static::$workers[$workerId]; + foreach($pidArray as $pid) { + $allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } - \file_put_contents(static::$statisticsFile, \serialize($all_worker_info)."\n", \FILE_APPEND); + \file_put_contents(static::$statisticsFile, \serialize($allWorkerInfo)."\n", \FILE_APPEND); $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2,2,2]) : ['-', '-', '-']; \file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); @@ -1913,21 +1913,21 @@ protected static function writeStatisticsToStatusFile() \file_put_contents(static::$statisticsFile, 'start time:' . \date('Y-m-d H:i:s', static::$globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); - $load_str = 'load average: ' . \implode(", ", $loadavg); + $loadStr = 'load average: ' . \implode(", ", $loadavg); \file_put_contents(static::$statisticsFile, - \str_pad($load_str, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); + \str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); \file_put_contents(static::$statisticsFile, \count(static::$pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", \FILE_APPEND); \file_put_contents(static::$statisticsFile, \str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); - foreach (static::$pidMap as $worker_id => $worker_pid_array) { - $worker = static::$workers[$worker_id]; - if (isset(static::$globalStatistics['worker_exit_info'][$worker_id])) { - foreach (static::$globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { + foreach (static::$pidMap as $workerId => $workerPidArray) { + $worker = static::$workers[$workerId]; + if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { + foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { \file_put_contents(static::$statisticsFile, - \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad($worker_exit_status, - 16) . " $worker_exit_count\n", \FILE_APPEND); + \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad($workerExitStatus, + 16) . " $workerExitCount\n", \FILE_APPEND); } } else { \file_put_contents(static::$statisticsFile, @@ -1945,8 +1945,8 @@ protected static function writeStatisticsToStatusFile() \chmod(static::$statisticsFile, 0722); - foreach (static::getAllWorkerPids() as $worker_pid) { - \posix_kill($worker_pid, \SIGIOT); + foreach (static::getAllWorkerPids() as $workerPid) { + \posix_kill($workerPid, \SIGIOT); } return; } @@ -1959,15 +1959,15 @@ protected static function writeStatisticsToStatusFile() \reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); - $worker_status_str = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) + $workerStatusStr = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; - $worker_status_str .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) + $workerStatusStr .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; - \file_put_contents(static::$statisticsFile, $worker_status_str, \FILE_APPEND); + \file_put_contents(static::$statisticsFile, $workerStatusStr, \FILE_APPEND); } /** @@ -1982,14 +1982,14 @@ protected static function writeConnectionsStatisticsToStatusFile() \file_put_contents(static::$statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); \chmod(static::$statisticsFile, 0722); - foreach (static::getAllWorkerPids() as $worker_pid) { - \posix_kill($worker_pid, \SIGIO); + foreach (static::getAllWorkerPids() as $workerPid) { + \posix_kill($workerPid, \SIGIO); } return; } // For child processes. - $bytes_format = function($bytes) + $bytesFormat = function($bytes) { if($bytes > 1024*1024*1024*1024) { return round($bytes/(1024*1024*1024*1024), 1)."TB"; @@ -2009,8 +2009,8 @@ protected static function writeConnectionsStatisticsToStatusFile() $pid = \posix_getpid(); $str = ''; \reset(static::$workers); - $current_worker = current(static::$workers); - $default_worker_name = $current_worker->name; + $currentWorker = current(static::$workers); + $defaultWorkerName = $currentWorker->name; /** @var static $worker */ foreach(TcpConnection::$connections as $connection) { @@ -2018,13 +2018,13 @@ protected static function writeConnectionsStatisticsToStatusFile() $transport = $connection->transport; $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; - $recv_q = $bytes_format($connection->getRecvBufferQueueSize()); - $send_q = $bytes_format($connection->getSendBufferQueueSize()); - $local_address = \trim($connection->getLocalAddress()); - $remote_address = \trim($connection->getRemoteAddress()); + $recvQ = $bytesFormat($connection->getRecvBufferQueueSize()); + $sendQ = $bytesFormat($connection->getSendBufferQueueSize()); + $localAddress = \trim($connection->getLocalAddress()); + $remoteAddress = \trim($connection->getRemoteAddress()); $state = $connection->getStatus(false); - $bytes_read = $bytes_format($connection->bytesRead); - $bytes_written = $bytes_format($connection->bytesWritten); + $bytesRead = $bytesFormat($connection->bytesRead); + $bytesWritten = $bytesFormat($connection->bytesWritten); $id = $connection->id; $protocol = $connection->protocol ? $connection->protocol : $connection->transport; $pos = \strrpos($protocol, '\\'); @@ -2034,14 +2034,14 @@ protected static function writeConnectionsStatisticsToStatusFile() if (\strlen($protocol) > 15) { $protocol = \substr($protocol, 0, 13) . '..'; } - $worker_name = isset($connection->worker) ? $connection->worker->name : $default_worker_name; - if (\strlen($worker_name) > 14) { - $worker_name = \substr($worker_name, 0, 12) . '..'; + $workerName = isset($connection->worker) ? $connection->worker->name : $defaultWorkerName; + if (\strlen($workerName) > 14) { + $workerName = \substr($workerName, 0, 12) . '..'; } - $str .= \str_pad($pid, 9) . \str_pad($worker_name, 16) . \str_pad($id, 10) . \str_pad($transport, 8) - . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recv_q, 13) - . \str_pad($send_q, 13) . \str_pad($bytes_read, 13) . \str_pad($bytes_written, 13) . ' ' - . \str_pad($state, 14) . ' ' . \str_pad($local_address, 22) . ' ' . \str_pad($remote_address, 22) ."\n"; + $str .= \str_pad($pid, 9) . \str_pad($workerName, 16) . \str_pad($id, 10) . \str_pad($transport, 8) + . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recvQ, 13) + . \str_pad($sendQ, 13) . \str_pad($bytesRead, 13) . \str_pad($bytesWritten, 13) . ' ' + . \str_pad($state, 14) . ' ' . \str_pad($localAddress, 22) . ' ' . \str_pad($remoteAddress, 22) ."\n"; } if ($str) { \file_put_contents(static::$statisticsFile, $str, \FILE_APPEND); @@ -2056,7 +2056,7 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN !== static::$status) { - $error_msg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; + $errorMsg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; $errors = error_get_last(); if ($errors && ($errors['type'] === \E_ERROR || $errors['type'] === \E_PARSE || @@ -2064,9 +2064,9 @@ public static function checkErrors() $errors['type'] === \E_COMPILE_ERROR || $errors['type'] === \E_RECOVERABLE_ERROR) ) { - $error_msg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; + $errorMsg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } - static::log($error_msg); + static::log($errorMsg); } } @@ -2161,10 +2161,10 @@ private static function outputStream($stream = null) /** * Constructor. * - * @param string $socket_name - * @param array $context_option + * @param string $socketName + * @param array $contextOption */ - public function __construct(string $socket_name = null, array $context_option = []) + public function __construct(string $socketName = null, array $contextOption = []) { // Save all worker instances. $this->workerId = \spl_object_hash($this); @@ -2172,23 +2172,23 @@ public function __construct(string $socket_name = null, array $context_option = static::$pidMap[$this->workerId] = []; // Context for socket. - if ($socket_name) { - $this->socketName = $socket_name; - if (!isset($context_option['socket']['backlog'])) { - $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG; + if ($socketName) { + $this->socketName = $socketName; + if (!isset($contextOption['socket']['backlog'])) { + $contextOption['socket']['backlog'] = static::DEFAULT_BACKLOG; } - $this->context = \stream_context_create($context_option); + $this->context = \stream_context_create($contextOption); } // Try to turn reusePort on. /*if (\DIRECTORY_SEPARATOR === '/' // if linux - && $socket_name + && $socketName && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && strpos($socket_name,'unix') !== 0 // if not unix socket - && strpos($socket_name,'udp') !== 0) { // if not udp socket + && strpos($socketName,'unix') !== 0 // if not unix socket + && strpos($socketName,'udp') !== 0) { // if not udp socket - $address = \parse_url($socket_name); + $address = \parse_url($socketName); if (isset($address['host']) && isset($address['port'])) { try { \set_error_handler(function(){}); @@ -2218,7 +2218,7 @@ public function listen() if (!$this->mainSocket) { - $local_socket = $this->parseSocketAddress(); + $localSocket = $this->parseSocketAddress(); // Flag. $flags = $this->transport === 'udp' ? \STREAM_SERVER_BIND : \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN; @@ -2230,7 +2230,7 @@ public function listen() } // Create an Internet or Unix domain server socket. - $this->mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->context); + $this->mainSocket = \stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->context); if (!$this->mainSocket) { throw new Exception($errmsg); } @@ -2238,12 +2238,12 @@ public function listen() if ($this->transport === 'ssl') { \stream_socket_enable_crypto($this->mainSocket, false); } elseif ($this->transport === 'unix') { - $socket_file = \substr($local_socket, 7); + $socketFile = \substr($localSocket, 7); if ($this->user) { - \chown($socket_file, $this->user); + \chown($socketFile, $this->user); } if ($this->group) { - \chgrp($socket_file, $this->group); + \chgrp($socketFile, $this->group); } } @@ -2368,8 +2368,8 @@ public function run() // Create a global event loop. if (!static::$globalEvent) { - $event_loop_class = static::getEventLoopName(); - static::$globalEvent = new $event_loop_class; + $eventLoopClass = static::getEventLoopName(); + static::$globalEvent = new $eventLoopClass; $this->resumeAccept(); } @@ -2438,16 +2438,16 @@ public function acceptTcpConnection($socket) { // Accept a connection on server socket. \set_error_handler(function(){}); - $new_socket = \stream_socket_accept($socket, 0, $remote_address); + $newSocket = \stream_socket_accept($socket, 0, $remoteAddress); \restore_error_handler(); // Thundering herd. - if (!$new_socket) { + if (!$newSocket) { return; } // TcpConnection. - $connection = new TcpConnection($new_socket, $remote_address); + $connection = new TcpConnection($newSocket, $remoteAddress); $this->connections[$connection->id] = $connection; $connection->worker = $this; $connection->protocol = $this->protocol; @@ -2477,43 +2477,43 @@ public function acceptTcpConnection($socket) public function acceptUdpConnection($socket) { \set_error_handler(function(){}); - $recv_buffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); + $recvBuffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); \restore_error_handler(); - if (false === $recv_buffer || empty($remote_address)) { + if (false === $recvBuffer || empty($remoteAddress)) { return false; } // UdpConnection. - $connection = new UdpConnection($socket, $remote_address); + $connection = new UdpConnection($socket, $remoteAddress); $connection->protocol = $this->protocol; - $message_cb = $this->onMessage; - if ($message_cb) { + $messageCb = $this->onMessage; + if ($messageCb) { try { if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ $parser = $this->protocol; if ($parser && \method_exists($parser, 'input')) { - while ($recv_buffer !== '') { - $len = $parser::input($recv_buffer, $connection); + while ($recvBuffer !== '') { + $len = $parser::input($recvBuffer, $connection); if ($len === 0) return true; - $package = \substr($recv_buffer, 0, $len); - $recv_buffer = \substr($recv_buffer, $len); + $package = \substr($recvBuffer, 0, $len); + $recvBuffer = \substr($recvBuffer, $len); $data = $parser::decode($package, $connection); if ($data === false) { continue; } - $message_cb($connection, $data); + $messageCb($connection, $data); } } else { - $data = $parser::decode($recv_buffer, $connection); + $data = $parser::decode($recvBuffer, $connection); // Discard bad packets. if ($data === false) { return true; } - $message_cb($connection, $data); + $messageCb($connection, $data); } } else { - $message_cb($connection, $recv_buffer); + $messageCb($connection, $recvBuffer); } ++ConnectionInterface::$statistics['total_request']; } catch (Throwable $e) { @@ -2526,21 +2526,21 @@ public function acceptUdpConnection($socket) /** * Check master process is alive * - * @param int $master_pid + * @param int $masterPid * @return bool */ - protected static function checkMasterIsAlive($master_pid) + protected static function checkMasterIsAlive($masterPid) { - if (empty($master_pid)) { + if (empty($masterPid)) { return false; } - $master_is_alive = $master_pid && \posix_kill((int) $master_pid, 0) && \posix_getpid() !== $master_pid; - if (!$master_is_alive) { + $masterIsAlive = $masterPid && \posix_kill((int) $masterPid, 0) && \posix_getpid() !== $masterPid; + if (!$masterIsAlive) { return false; } - $cmdline = "/proc/{$master_pid}/cmdline"; + $cmdline = "/proc/{$masterPid}/cmdline"; if (!is_readable($cmdline) || empty(static::$processTitle)) { return true; } From 10c1882ba6b1f7a979c2b1fb7c9a80459347e631 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 19:42:42 +0800 Subject: [PATCH 0781/1216] Properties --- src/Connection/AsyncTcpConnection.php | 4 +- src/Connection/ConnectionInterface.php | 9 +++- src/Connection/TcpConnection.php | 5 ++- src/Connection/UdpConnection.php | 4 +- src/Protocols/Http/Request.php | 57 +++----------------------- src/Protocols/Http/Response.php | 7 ++++ src/Protocols/Http/Session.php | 6 +++ src/Worker.php | 6 ++- 8 files changed, 39 insertions(+), 59 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 2df5baf54..b7e4bf10b 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -39,14 +39,14 @@ class AsyncTcpConnection extends TcpConnection public $transport = 'tcp'; /** - * Socks5 proxy + * Socks5 proxy. * * @var string */ public $proxySocks5 = ''; /** - * Http proxy + * Http proxy. * * @var string */ diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 865ff586e..de28e2118 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -14,10 +14,11 @@ namespace Workerman\Connection; +use Workerman\Properties; + /** * ConnectionInterface. */ -#[\AllowDynamicProperties] abstract class ConnectionInterface { /** @@ -74,6 +75,11 @@ abstract class ConnectionInterface */ public $protocolContext = []; + /** + * Dynamic Properties。 + */ + use Properties; + /** * Sends data on the connection. * @@ -145,4 +151,5 @@ abstract public function isIPv6(); * @return void */ abstract public function close($data = null); + } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 7fb4c69b0..bd526a2ba 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -16,6 +16,7 @@ use Workerman\Events\EventInterface; use Workerman\Protocols\Http\Request; +use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; /** @@ -104,7 +105,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. * - * @var \Workerman\Protocols\ProtocolInterface + * @var ProtocolInterface */ public $protocol = null; @@ -323,7 +324,7 @@ public function getStatus($rawOutput = true) * * @param mixed $sendBuffer * @param bool $raw - * @return bool|null + * @return bool|void */ public function send($sendBuffer, $raw = false) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 6a1994dc8..d66135cde 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -14,6 +14,8 @@ namespace Workerman\Connection; +use Workerman\Protocols\ProtocolInterface; + /** * UdpConnection. */ @@ -23,7 +25,7 @@ class UdpConnection extends ConnectionInterface implements \JsonSerializable * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. * - * @var \Workerman\Protocols\ProtocolInterface + * @var ProtocolInterface */ public $protocol = null; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 3dc70396d..b4eb9214e 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -15,6 +15,7 @@ namespace Workerman\Protocols\Http; use Workerman\Connection\TcpConnection; +use Workerman\Properties; use Workerman\Protocols\Http\Session; use Workerman\Protocols\Http; use Workerman\Worker; @@ -39,13 +40,6 @@ class Request */ public $session = null; - /** - * Properties. - * - * @var array - */ - public $properties = []; - /** * @var int */ @@ -72,6 +66,10 @@ class Request */ protected static $enableCache = true; + /** + * Dynamic Properties。 + */ + use Properties; /** * Request constructor. @@ -617,51 +615,6 @@ public static function createSessionId() return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8)); } - /** - * Setter. - * - * @param string $name - * @param mixed $value - * @return void - */ - public function __set($name, $value) - { - $this->properties[$name] = $value; - } - - /** - * Getter. - * - * @param string $name - * @return mixed|null - */ - public function __get($name) - { - return $this->properties[$name] ?? null; - } - - /** - * Isset. - * - * @param string $name - * @return bool - */ - public function __isset($name) - { - return isset($this->properties[$name]); - } - - /** - * Unset. - * - * @param string $name - * @return void - */ - public function __unset($name) - { - unset($this->properties[$name]); - } - /** * __toString. */ diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index f780619c7..272bc6d64 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http; +use Workerman\Properties; + /** * Class Response * @package Workerman\Protocols\Http @@ -145,6 +147,11 @@ class Response 511 => 'Network Authentication Required', // RFC 6585 ]; + /** + * Dynamic Properties。 + */ + use Properties; + /** * Init. * diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 13343445e..d2c12edb6 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols\Http; +use Workerman\Properties; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -135,6 +136,11 @@ class Session */ protected $sessionId = null; + /** + * Dynamic Properties。 + */ + use Properties; + /** * Session constructor. * diff --git a/src/Worker.php b/src/Worker.php index 982b64d48..bc7f19439 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -26,7 +26,6 @@ * Worker class * A container for listening ports */ -#[\AllowDynamicProperties] class Worker { /** @@ -537,6 +536,11 @@ class Worker */ protected $workerId = null; + /** + * Dynamic Properties。 + */ + use Properties; + /** * Run all worker instances. * From e2846d5a5888066b9496df64ae114d83f95f2483 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 20:10:55 +0800 Subject: [PATCH 0782/1216] Properties --- src/Properties.php | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/Properties.php diff --git a/src/Properties.php b/src/Properties.php new file mode 100644 index 000000000..d94c42ed2 --- /dev/null +++ b/src/Properties.php @@ -0,0 +1,57 @@ +properties[$name] = $value; + } + + /** + * Getter. + * + * @param string $name + * @return mixed|null + */ + public function __get($name) + { + return $this->properties[$name] ?? null; + } + + /** + * Isset. + * + * @param string $name + * @return bool + */ + public function __isset($name) + { + return isset($this->properties[$name]); + } + + /** + * Unset. + * + * @param string $name + * @return void + */ + public function __unset($name) + { + unset($this->properties[$name]); + } +} \ No newline at end of file From d51038e2b61359b80ca60c103dfd4ee662b1c9b2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 20:56:44 +0800 Subject: [PATCH 0783/1216] optimizations --- src/Connection/AsyncTcpConnection.php | 1 + src/Protocols/Http.php | 8 +- src/Protocols/Websocket.php | 14 ++-- src/Protocols/Ws.php | 106 +++++++++++--------------- src/Worker.php | 28 +++---- 5 files changed, 68 insertions(+), 89 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index b7e4bf10b..0be110c21 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -180,6 +180,7 @@ public function __construct($remoteAddress, array $contextOption = []) $this->maxPackageSize = self::$defaultMaxPackageSize; $this->contextOption = $contextOption; static::$connections[$this->realId] = $this; + $this->context = new \stdClass; } /** diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index d21760749..14b7ad390 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -248,7 +248,7 @@ public static function encode($response, TcpConnection $connection) */ protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) { - $connection->bufferFull = false; + $connection->context->bufferFull = false; $connection->context->streamSending = true; if ($offset !== 0) { \fseek($handler, $offset); @@ -257,7 +257,7 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse // Read file content from disk piece by piece and send to client. $doWrite = function () use ($connection, $handler, $length, $offsetEnd) { // Send buffer not full. - while ($connection->bufferFull === false) { + while ($connection->context->bufferFull === false) { // Read from disk. $size = 1024 * 1024; if ($length !== 0) { @@ -284,11 +284,11 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse }; // Send buffer full. $connection->onBufferFull = function ($connection) { - $connection->bufferFull = true; + $connection->context->bufferFull = true; }; // Send buffer drain. $connection->onBufferDrain = function ($connection) use ($doWrite) { - $connection->bufferFull = false; + $connection->context->bufferFull = false; $doWrite(); }; $doWrite(); diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 8e8320662..a1ade38ef 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -82,12 +82,14 @@ public static function input($buffer, ConnectionInterface $connection) $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: - break; // Blob type. case 0x1: - break; // Arraybuffer type. case 0x2: + // Ping package. + case 0x9: + // Pong package. + case 0xa: break; // Close package. case 0x8: @@ -104,12 +106,6 @@ public static function input($buffer, ConnectionInterface $connection) $connection->close("\x88\x02\x03\xe8", true); } return 0; - // Ping package. - case 0x9: - break; - // Pong package. - case 0xa: - break; // Wrong opcode. default : Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . bin2hex($buffer) . "\n"); @@ -326,7 +322,7 @@ public static function decode($buffer, ConnectionInterface $connection) * @param TcpConnection $connection * @return int */ - public static function dealHandshake($buffer, TcpConnection $connection) + public static function dealHandshake($buffer, ConnectionInterface $connection) { // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 63bf91a83..17d167c63 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -47,12 +47,12 @@ class Ws */ public static function input($buffer, ConnectionInterface $connection) { - if (empty($connection->handshakeStep)) { + if (empty($connection->context->handshakeStep)) { Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n"); return false; } // Recv handshake response - if ($connection->handshakeStep === 1) { + if ($connection->context->handshakeStep === 1) { return self::dealHandshake($buffer, $connection); } $recvLen = \strlen($buffer); @@ -60,9 +60,9 @@ public static function input($buffer, ConnectionInterface $connection) return 0; } // Buffer websocket frame data. - if ($connection->websocketCurrentFrameLength) { + if ($connection->context->websocketCurrentFrameLength) { // We need more frame data. - if ($connection->websocketCurrentFrameLength > $recvLen) { + if ($connection->context->websocketCurrentFrameLength > $recvLen) { // Return 0, because it is not clear the full packet length, waiting for the frame of fin=1. return 0; } @@ -84,12 +84,14 @@ public static function input($buffer, ConnectionInterface $connection) switch ($opcode) { case 0x0: - break; // Blob type. case 0x1: - break; // Arraybuffer type. case 0x2: + // Ping package. + case 0x9: + // Pong package. + case 0xa: break; // Close package. case 0x8: @@ -105,12 +107,6 @@ public static function input($buffer, ConnectionInterface $connection) $connection->close(); } return 0; - // Ping package. - case 0x9: - break; - // Pong package. - case 0xa: - break; // Wrong opcode. default : Worker::safeEcho("error opcode $opcode and close websocket connection. Buffer:" . $buffer . "\n"); @@ -134,7 +130,7 @@ public static function input($buffer, ConnectionInterface $connection) $currentFrameLength = $dataLen + 2; } - $totalPackageSize = \strlen($connection->websocketDataBuffer) + $currentFrameLength; + $totalPackageSize = \strlen($connection->context->websocketDataBuffer) + $currentFrameLength; if ($totalPackageSize > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$totalPackageSize\n"); $connection->close(); @@ -187,21 +183,21 @@ public static function input($buffer, ConnectionInterface $connection) } return $currentFrameLength; } else { - $connection->websocketCurrentFrameLength = $currentFrameLength; + $connection->context->websocketCurrentFrameLength = $currentFrameLength; } } // Received just a frame length data. - if ($connection->websocketCurrentFrameLength === $recvLen) { + if ($connection->context->websocketCurrentFrameLength === $recvLen) { self::decode($buffer, $connection); - $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $connection->websocketCurrentFrameLength = 0; + $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); + $connection->context->websocketCurrentFrameLength = 0; return 0; } // The length of the received data is greater than the length of a frame. - elseif ($connection->websocketCurrentFrameLength < $recvLen) { - self::decode(\substr($buffer, 0, $connection->websocketCurrentFrameLength), $connection); - $connection->consumeRecvBuffer($connection->websocketCurrentFrameLength); - $currentFrameLength = $connection->websocketCurrentFrameLength; - $connection->websocketCurrentFrameLength = 0; + elseif ($connection->context->websocketCurrentFrameLength < $recvLen) { + self::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); + $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); + $currentFrameLength = $connection->context->websocketCurrentFrameLength; + $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. return self::input(\substr($buffer, $currentFrameLength), $connection); } // The length of the received data is less than the length of a frame. @@ -223,7 +219,7 @@ public static function encode($payload, ConnectionInterface $connection) $connection->websocketType = self::BINARY_TYPE_BLOB; } $payload = (string)$payload; - if (empty($connection->handshakeStep)) { + if (empty($connection->context->handshakeStep)) { static::sendHandshake($connection); } $mask = 1; @@ -246,9 +242,9 @@ public static function encode($payload, ConnectionInterface $connection) // append payload to frame: $maskKey = \str_repeat($maskKey, \floor($length / 4)) . \substr($maskKey, 0, $length % 4); $frame .= $payload ^ $maskKey; - if ($connection->handshakeStep === 1) { + if ($connection->context->handshakeStep === 1) { // If buffer has already full then discard the current package. - if (\strlen($connection->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (\strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); @@ -258,9 +254,9 @@ public static function encode($payload, ConnectionInterface $connection) } return ''; } - $connection->tmpWebsocketData = $connection->tmpWebsocketData . $frame; + $connection->context->tmpWebsocketData = $connection->context->tmpWebsocketData . $frame; // Check buffer is full. - if ($connection->maxSendBufferSize <= \strlen($connection->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) { if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); @@ -292,13 +288,13 @@ public static function decode($bytes, ConnectionInterface $connection) } else { $decodedData = \substr($bytes, 2); } - if ($connection->websocketCurrentFrameLength) { - $connection->websocketDataBuffer .= $decodedData; - return $connection->websocketDataBuffer; + if ($connection->context->websocketCurrentFrameLength) { + $connection->context->websocketDataBuffer .= $decodedData; + return $connection->context->websocketDataBuffer; } else { - if ($connection->websocketDataBuffer !== '') { - $decodedData = $connection->websocketDataBuffer . $decodedData; - $connection->websocketDataBuffer = ''; + if ($connection->context->websocketDataBuffer !== '') { + $decodedData = $connection->context->websocketDataBuffer . $decodedData; + $connection->context->websocketDataBuffer = ''; } return $decodedData; } @@ -321,10 +317,10 @@ public static function onConnect($connection) */ public static function onClose($connection) { - $connection->handshakeStep = null; - $connection->websocketCurrentFrameLength = 0; - $connection->tmpWebsocketData = ''; - $connection->websocketDataBuffer = ''; + $connection->context->handshakeStep = null; + $connection->context->websocketCurrentFrameLength = 0; + $connection->context->tmpWebsocketData = ''; + $connection->context->websocketDataBuffer = ''; if (!empty($connection->websocketPingTimer)) { Timer::del($connection->websocketPingTimer); $connection->websocketPingTimer = null; @@ -337,9 +333,9 @@ public static function onClose($connection) * @param TcpConnection $connection * @return void */ - public static function sendHandshake(TcpConnection $connection) + public static function sendHandshake(ConnectionInterface $connection) { - if (!empty($connection->handshakeStep)) { + if (!empty($connection->context->handshakeStep)) { return; } // Get Host. @@ -364,14 +360,14 @@ public static function sendHandshake(TcpConnection $connection) "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . - (isset($connection->WSClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->WSClientProtocol . "\r\n" : '') . + (isset($connection->websocketClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . "Sec-WebSocket-Key: " . $connection->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); - $connection->handshakeStep = 1; - $connection->websocketCurrentFrameLength = 0; - $connection->websocketDataBuffer = ''; - $connection->tmpWebsocketData = ''; + $connection->context->handshakeStep = 1; + $connection->context->websocketCurrentFrameLength = 0; + $connection->context->websocketDataBuffer = ''; + $connection->context->tmpWebsocketData = ''; } /** @@ -381,7 +377,7 @@ public static function sendHandshake(TcpConnection $connection) * @param TcpConnection $connection * @return int */ - public static function dealHandshake($buffer, TcpConnection $connection) + public static function dealHandshake($buffer, ConnectionInterface $connection) { $pos = \strpos($buffer, "\r\n\r\n"); if ($pos) { @@ -402,10 +398,10 @@ public static function dealHandshake($buffer, TcpConnection $connection) // Get WebSocket subprotocol (if specified by server) if (\preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) { - $connection->WSServerProtocol = \trim($match[1]); + $connection->websocketServerProtocol = \trim($match[1]); } - $connection->handshakeStep = 2; + $connection->context->handshakeStep = 2; $handshakeResponseLength = $pos + 4; // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { @@ -426,9 +422,9 @@ public static function dealHandshake($buffer, TcpConnection $connection) } $connection->consumeRecvBuffer($handshakeResponseLength); - if (!empty($connection->tmpWebsocketData)) { - $connection->send($connection->tmpWebsocketData, true); - $connection->tmpWebsocketData = ''; + if (!empty($connection->context->tmpWebsocketData)) { + $connection->send($connection->context->tmpWebsocketData, true); + $connection->context->tmpWebsocketData = ''; } if (\strlen($buffer) > $handshakeResponseLength) { return self::input(\substr($buffer, $handshakeResponseLength), $connection); @@ -437,14 +433,4 @@ public static function dealHandshake($buffer, TcpConnection $connection) return 0; } - public static function WSSetProtocol($connection, $params) - { - $connection->WSClientProtocol = $params[0]; - } - - public static function WSGetServerProtocol($connection) - { - return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null); - } - } diff --git a/src/Worker.php b/src/Worker.php index bc7f19439..b27a96eab 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -342,7 +342,7 @@ class Worker protected $socketName = ''; /** - * parse from _socketName avoid parse again in master or worker + * parse from socketName avoid parse again in master or worker * LocalSocket The format is like tcp://0.0.0.0:8080 * @var string */ @@ -545,6 +545,7 @@ class Worker * Run all worker instances. * * @return void + * @throws Exception */ public static function runAll() { @@ -843,12 +844,12 @@ protected static function displayUI() public static function getUiColumns() { return [ - 'proto' => 'transport', - 'user' => 'user', - 'worker' => 'name', - 'socket' => 'socket', - 'processes' => 'count', - 'state' => 'state', + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', + 'processes' => 'count', + 'state' => 'state', ]; } @@ -866,7 +867,7 @@ public static function getSingleLineTotalLength() $totalLength += static::$$key + static::UI_SAFE_LENGTH; } - //keep beauty when show less colums + //Keep beauty when show less columns !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', 0); $totalLength <= LINE_VERSIOIN_LENGTH && $totalLength = LINE_VERSIOIN_LENGTH; @@ -965,7 +966,6 @@ protected static function parseCommand() } static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } - exit(0); case 'connections': if (\is_file($statisticsFile) && \is_writable($statisticsFile)) { \unlink($statisticsFile); @@ -1302,10 +1302,6 @@ protected static function getEventLoopName(): string return static::$eventLoopClass; } - if (!class_exists(\Swoole\Event::class, false)) { - unset(static::$availableEventLoops['swoole']); - } - $loopName = ''; foreach (static::$availableEventLoops as $name => $class) { if (\extension_loaded($name)) { @@ -1658,7 +1654,7 @@ protected static function monitorWorkersForLinux() unset(static::$pidMap[$workerId][$pid]); // Mark id is available. - $id = static::getId($workerId, $pid); + $id = static::getId($workerId, $pid); static::$idMap[$workerId][$id] = 0; break; @@ -1721,6 +1717,7 @@ protected static function exitAndClearAll() * Execute reload. * * @return void + * @throws Exception */ protected static function reload() { @@ -2082,7 +2079,6 @@ public static function checkErrors() */ protected static function getErrorType($type) { - return self::ERROR_TYPE[$type] ?? ''; } @@ -2289,7 +2285,7 @@ public function unlisten() { */ protected function parseSocketAddress() { if (!$this->socketName) { - return; + return null; } // Get the application layer communication protocol and listening address. list($scheme, $address) = \explode(':', $this->socketName, 2); From 719be4a96e58363efddee646ae2a29df33fb5eab Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 16 Jan 2023 22:16:19 +0800 Subject: [PATCH 0784/1216] Update --- src/Connection/AsyncTcpConnection.php | 5 +++-- src/Events/Revolt.php | 4 +++- src/Worker.php | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 0be110c21..df58bcd44 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -15,6 +15,7 @@ namespace Workerman\Connection; use Workerman\Events\EventInterface; +use Workerman\Events\Select; use Workerman\Timer; use Workerman\Worker; use \Exception; @@ -246,7 +247,7 @@ public function connect() // Add socket to global event loop waiting connection is successfully established or faild. Worker::$globalEvent->onWritable($this->socket, [$this, 'checkConnection']); // For windows. - if (\DIRECTORY_SEPARATOR === '\\') { + if (\DIRECTORY_SEPARATOR === '\\' && Worker::$eventLoopClass === Select::class) { Worker::$globalEvent->onExcept($this->socket, [$this, 'checkConnection']); } } @@ -329,7 +330,7 @@ protected function emitError($code, $msg) public function checkConnection() { // Remove EV_EXPECT for windows. - if (\DIRECTORY_SEPARATOR === '\\') { + if (\DIRECTORY_SEPARATOR === '\\' && Worker::$eventLoopClass === Select::class) { Worker::$globalEvent->offExcept($this->socket); } // Remove write listener. diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 3bf74bfc9..8d4436c90 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -90,7 +90,9 @@ public function stop() $this->driver->cancel($cbId); } $this->driver->stop(); - pcntl_signal(SIGINT, SIG_IGN); + if (\function_exists('pcntl_signal')) { + \pcntl_signal(SIGINT, SIG_IGN); + } } /** diff --git a/src/Worker.php b/src/Worker.php index b27a96eab..56534ac68 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -685,7 +685,7 @@ protected static function initWorkers() $worker->socket = $worker->getSocketName(); // Status name. - $worker->sate = ' [OK] '; + $worker->state = ' [OK] '; // Get column mapping for UI foreach(static::getUiColumns() as $columnName => $prop){ From f38863052e0152ed76a6f619680feb5dac06fac4 Mon Sep 17 00:00:00 2001 From: ZZN <11101627+zzn666@user.noreply.gitee.com> Date: Sat, 21 Jan 2023 12:18:09 +0800 Subject: [PATCH 0785/1216] correct incorrect spelling --- src/Protocols/ProtocolInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/ProtocolInterface.php b/src/Protocols/ProtocolInterface.php index 0d3365311..6a33cad85 100644 --- a/src/Protocols/ProtocolInterface.php +++ b/src/Protocols/ProtocolInterface.php @@ -24,7 +24,7 @@ interface ProtocolInterface /** * Check the integrity of the package. * Please return the length of package. - * If length is unknow please return 0 that mean wating more data. + * If length is unknown please return 0 that means waiting for more data. * If the package has something wrong please return false the connection will be closed. * * @param string $recvBuffer @@ -43,7 +43,7 @@ public static function input($recvBuffer, ConnectionInterface $connection); public static function decode($recvBuffer, ConnectionInterface $connection); /** - * Encode package brefore sending to client. + * Encode package before sending to client. * * @param mixed $data * @param ConnectionInterface $connection From 9e93d41d8d41c17cd94ed883147943959f9b6968 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 22 Jan 2023 20:38:59 +0800 Subject: [PATCH 0786/1216] AllowDynamicProperties --- composer.json | 3 +- src/Connection/ConnectionInterface.php | 15 +--- src/Properties.php | 57 ---------------- src/Protocols/Http/Request.php | 95 +++++++++++++++++++------- src/Protocols/Http/Response.php | 7 -- src/Protocols/Http/Session.php | 6 -- src/Worker.php | 19 +----- 7 files changed, 74 insertions(+), 128 deletions(-) delete mode 100644 src/Properties.php diff --git a/composer.json b/composer.json index 59ac279bf..1893afaf4 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "source": "https://github.com/walkor/workerman" }, "require": { - "php": ">=7.0" + "php": ">=7.0", + "ext-json": "*" }, "suggest": { "ext-event": "For better performance. " diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index de28e2118..ef569d5d1 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -14,11 +14,10 @@ namespace Workerman\Connection; -use Workerman\Properties; - /** * ConnectionInterface. */ +#[\AllowDynamicProperties] abstract class ConnectionInterface { /** @@ -68,18 +67,6 @@ abstract class ConnectionInterface */ public $onError = null; - /** - * Protocol context - * - * @var array - */ - public $protocolContext = []; - - /** - * Dynamic Properties。 - */ - use Properties; - /** * Sends data on the connection. * diff --git a/src/Properties.php b/src/Properties.php deleted file mode 100644 index d94c42ed2..000000000 --- a/src/Properties.php +++ /dev/null @@ -1,57 +0,0 @@ -properties[$name] = $value; - } - - /** - * Getter. - * - * @param string $name - * @return mixed|null - */ - public function __get($name) - { - return $this->properties[$name] ?? null; - } - - /** - * Isset. - * - * @param string $name - * @return bool - */ - public function __isset($name) - { - return isset($this->properties[$name]); - } - - /** - * Unset. - * - * @param string $name - * @return void - */ - public function __unset($name) - { - unset($this->properties[$name]); - } -} \ No newline at end of file diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b4eb9214e..ea5c994ee 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -15,8 +15,6 @@ namespace Workerman\Protocols\Http; use Workerman\Connection\TcpConnection; -use Workerman\Properties; -use Workerman\Protocols\Http\Session; use Workerman\Protocols\Http; use Workerman\Worker; @@ -45,6 +43,13 @@ class Request */ public static $maxFileUploads = 1024; + /** + * Properties. + * + * @var array + */ + public $properties = []; + /** * Http buffer. * @@ -66,11 +71,6 @@ class Request */ protected static $enableCache = true; - /** - * Dynamic Properties。 - */ - use Properties; - /** * Request constructor. * @@ -255,7 +255,7 @@ public function queryString() /** * Get session. * - * @return bool|\Workerman\Protocols\Http\Session + * @return bool|Session */ public function session() { @@ -615,6 +615,23 @@ public static function createSessionId() return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8)); } + /** + * @param string $sessionName + * @param string $sid + * @param array $cookieParams + * @return void + */ + protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) + { + $this->connection->header['Set-Cookie'] = [$sessionName . '=' . $sid + . (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain']) + . (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime']) + . (empty($cookieParams['path']) ? '' : '; Path=' . $cookieParams['path']) + . (empty($cookieParams['samesite']) ? '' : '; SameSite=' . $cookieParams['samesite']) + . (!$cookieParams['secure'] ? '' : '; Secure') + . (!$cookieParams['httponly'] ? '' : '; HttpOnly')]; + } + /** * __toString. */ @@ -623,6 +640,51 @@ public function __toString() return $this->buffer; } + /** + * Setter. + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) + { + $this->properties[$name] = $value; + } + + /** + * Getter. + * + * @param string $name + * @return mixed|null + */ + public function __get($name) + { + return $this->properties[$name] ?? null; + } + + /** + * Isset. + * + * @param string $name + * @return bool + */ + public function __isset($name) + { + return isset($this->properties[$name]); + } + + /** + * Unset. + * + * @param string $name + * @return void + */ + public function __unset($name) + { + unset($this->properties[$name]); + } + /** * __destruct. * @@ -641,21 +703,4 @@ public function __destruct() }); } } - - /** - * @param string $sessionName - * @param string $sid - * @param array $cookieParams - * @return void - */ - protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) - { - $this->connection->header['Set-Cookie'] = [$sessionName . '=' . $sid - . (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain']) - . (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime']) - . (empty($cookieParams['path']) ? '' : '; Path=' . $cookieParams['path']) - . (empty($cookieParams['samesite']) ? '' : '; SameSite=' . $cookieParams['samesite']) - . (!$cookieParams['secure'] ? '' : '; Secure') - . (!$cookieParams['httponly'] ? '' : '; HttpOnly')]; - } } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 272bc6d64..f780619c7 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -14,8 +14,6 @@ namespace Workerman\Protocols\Http; -use Workerman\Properties; - /** * Class Response * @package Workerman\Protocols\Http @@ -147,11 +145,6 @@ class Response 511 => 'Network Authentication Required', // RFC 6585 ]; - /** - * Dynamic Properties。 - */ - use Properties; - /** * Init. * diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index d2c12edb6..13343445e 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -14,7 +14,6 @@ namespace Workerman\Protocols\Http; -use Workerman\Properties; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -136,11 +135,6 @@ class Session */ protected $sessionId = null; - /** - * Dynamic Properties。 - */ - use Properties; - /** * Session constructor. * diff --git a/src/Worker.php b/src/Worker.php index 56534ac68..a55fa78ac 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -26,6 +26,7 @@ * Worker class * A container for listening ports */ +#[\AllowDynamicProperties] class Worker { /** @@ -536,11 +537,6 @@ class Worker */ protected $workerId = null; - /** - * Dynamic Properties。 - */ - use Properties; - /** * Run all worker instances. * @@ -702,19 +698,6 @@ protected static function initWorkers() } } - /** - * Reload all worker instances. - * - * @return void - */ - public static function reloadAllWorkers() - { - static::init(); - static::initWorkers(); - static::displayUI(); - static::$status = static::STATUS_RELOADING; - } - /** * Get all worker instances. * From 301858e5a263999f6af702bb15c3016bdb037736 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 22 Jan 2023 21:24:04 +0800 Subject: [PATCH 0787/1216] optimizations --- src/Connection/TcpConnection.php | 14 ++++++++++++-- src/Protocols/Http.php | 12 ++++++------ src/Protocols/Http/Request.php | 2 +- src/Protocols/Http/Response.php | 22 +++++++++++----------- src/Protocols/Ws.php | 20 ++++++++++---------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index bd526a2ba..82b5ba38f 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -162,9 +162,19 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable /** * Context. * - * @var object|null + * @var object */ - public $context = null; + public $context; + + /** + * @var array + */ + public $headers = []; + + /** + * @var object + */ + public $request; /** * Default send buffer size. diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 14b7ad390..0a358a481 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -185,8 +185,8 @@ public static function encode($response, TcpConnection $connection) } if (!\is_object($response)) { $extHeader = ''; - if (isset($connection->header)) { - foreach ($connection->header as $name => $value) { + if (isset($connection->headers)) { + foreach ($connection->headers as $name => $value) { if (\is_array($value)) { foreach ($value as $item) { $extHeader = "$name: $item\r\n"; @@ -195,15 +195,15 @@ public static function encode($response, TcpConnection $connection) $extHeader = "$name: $value\r\n"; } } - unset($connection->header); + $connection->headers = []; } $bodyLen = \strlen((string)$response); return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; } - if (isset($connection->header)) { - $response->withHeaders($connection->header); - unset($connection->header); + if (isset($connection->headers)) { + $response->withHeaders($connection->headers); + $connection->headers = []; } if (isset($response->file)) { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ea5c994ee..da98e8df5 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -623,7 +623,7 @@ public static function createSessionId() */ protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) { - $this->connection->header['Set-Cookie'] = [$sessionName . '=' . $sid + $this->connection->headers['Set-Cookie'] = [$sessionName . '=' . $sid . (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain']) . (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime']) . (empty($cookieParams['path']) ? '' : '; Path=' . $cookieParams['path']) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index f780619c7..fbe4fe459 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -25,7 +25,7 @@ class Response * * @var array */ - protected $header = null; + protected $headers = null; /** * Http status. @@ -169,7 +169,7 @@ public function __construct( ) { $this->status = $status; - $this->header = $headers; + $this->headers = $headers; $this->body = (string)$body; } @@ -182,7 +182,7 @@ public function __construct( */ public function header($name, $value) { - $this->header[$name] = $value; + $this->headers[$name] = $value; return $this; } @@ -206,7 +206,7 @@ public function withHeader($name, $value) */ public function withHeaders($headers) { - $this->header = \array_merge_recursive($this->header, $headers); + $this->headers = \array_merge_recursive($this->headers, $headers); return $this; } @@ -218,7 +218,7 @@ public function withHeaders($headers) */ public function withoutHeader($name) { - unset($this->header[$name]); + unset($this->headers[$name]); return $this; } @@ -231,7 +231,7 @@ public function withoutHeader($name) public function getHeader($name) { - return $this->header[$name] ?? null; + return $this->headers[$name] ?? null; } /** @@ -241,7 +241,7 @@ public function getHeader($name) */ public function getHeaders() { - return $this->header; + return $this->headers; } /** @@ -344,7 +344,7 @@ public function withFile($file, $offset = 0, $length = 0) */ public function cookie($name, $value = '', $maxAge = null, $path = '', $domain = '', $secure = false, $httpOnly = false, $sameSite = false) { - $this->header['Set-Cookie'][] = $name . '=' . \rawurlencode($value) + $this->headers['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) . ($maxAge === null ? '' : '; Max-Age=' . $maxAge) . (empty($path) ? '' : '; Path=' . $path) @@ -365,7 +365,7 @@ protected function createHeadForFile($fileInfo) $file = $fileInfo['file']; $reason = $this->reason ?: self::PHRASES[$this->status]; $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; - $headers = $this->header; + $headers = $this->headers; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } @@ -420,12 +420,12 @@ public function __toString() $reason = $this->reason ?: self::PHRASES[$this->status] ?? ''; $bodyLen = \strlen($this->body); - if (empty($this->header)) { + if (empty($this->headers)) { return "HTTP/{$this->version} {$this->status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\nConnection: keep-alive\r\n\r\n{$this->body}"; } $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; - $headers = $this->header; + $headers = $this->headers; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 17d167c63..76f1322db 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -321,9 +321,9 @@ public static function onClose($connection) $connection->context->websocketCurrentFrameLength = 0; $connection->context->tmpWebsocketData = ''; $connection->context->websocketDataBuffer = ''; - if (!empty($connection->websocketPingTimer)) { - Timer::del($connection->websocketPingTimer); - $connection->websocketPingTimer = null; + if (!empty($connection->context->websocketPingTimer)) { + Timer::del($connection->context->websocketPingTimer); + $connection->context->websocketPingTimer = null; } } @@ -342,8 +342,8 @@ public static function sendHandshake(ConnectionInterface $connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $connection->websocketSecKey = \base64_encode(random_bytes(16)); - $userHeader = $connection->headers ?? $connection->wsHttpHeader ?? null; + $connection->context->websocketSecKey = \base64_encode(random_bytes(16)); + $userHeader = $connection->headers ?? null; $userHeaderStr = ''; if (!empty($userHeader)) { if (\is_array($userHeader)) { @@ -362,7 +362,7 @@ public static function sendHandshake(ConnectionInterface $connection) (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . (isset($connection->websocketClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . - "Sec-WebSocket-Key: " . $connection->websocketSecKey . $userHeaderStr . "\r\n\r\n"; + "Sec-WebSocket-Key: " . $connection->context->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); $connection->context->handshakeStep = 1; $connection->context->websocketCurrentFrameLength = 0; @@ -383,7 +383,7 @@ public static function dealHandshake($buffer, ConnectionInterface $connection) if ($pos) { //checking Sec-WebSocket-Accept if (\preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { - if ($match[1] !== \base64_encode(\sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { + if ($match[1] !== \base64_encode(\sha1($connection->context->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . \substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; @@ -413,10 +413,10 @@ public static function dealHandshake($buffer, ConnectionInterface $connection) } // Headbeat. if (!empty($connection->websocketPingInterval)) { - $connection->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) { + $connection->context->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) { if (false === $connection->send(\pack('H*', '898000000000'), true)) { - Timer::del($connection->websocketPingTimer); - $connection->websocketPingTimer = null; + Timer::del($connection->context->websocketPingTimer); + $connection->context->websocketPingTimer = null; } }); } From cd959636168a5944855050ca8bb8471824bd5974 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 23 Jan 2023 09:58:50 +0800 Subject: [PATCH 0788/1216] Update --- src/Connection/TcpConnection.php | 1 + src/Timer.php | 23 ++++++++++++++++------- src/Worker.php | 9 ++++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 82b5ba38f..89af657d4 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -21,6 +21,7 @@ /** * TcpConnection. + * @property string websocketType */ class TcpConnection extends ConnectionInterface implements \JsonSerializable { diff --git a/src/Timer.php b/src/Timer.php index 47585738a..9c8d3ea7e 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -13,6 +13,7 @@ */ namespace Workerman; +use Revolt\EventLoop; use Workerman\Events\EventInterface; use Workerman\Events\Select; use Workerman\Worker; @@ -97,10 +98,10 @@ public static function signalHandle() * @param float $timeInterval * @param callable $func * @param mixed $args - * @param bool $persistent + * @param bool $persistent * @return int|bool */ - public static function add(float $timeInterval, $func, $args = [], $persistent = true) + public static function add(float $timeInterval, callable $func, $args = [], bool $persistent = true) { if ($timeInterval < 0) { Worker::safeEcho(new Exception("bad time_interval")); @@ -117,7 +118,7 @@ public static function add(float $timeInterval, $func, $args = [], $persistent = // If not workerman runtime just return. if (!Worker::getAllWorkers()) { - return; + return false; } if (!\is_callable($func)) { @@ -145,14 +146,22 @@ public static function add(float $timeInterval, $func, $args = [], $persistent = * @param float $delay * @param $func * @param array $args - * @return bool|int + * @return bool|int|null */ - public static function delay(float $delay, $func, $args = []) + public static function delay(float $delay, $func = null, array $args = []) { + if (!$func) { + $eventLoop = EventLoop::getDriver(); + $suspension = $eventLoop->getSuspension(); + static::add($delay, function () use ($suspension) { + $suspension->resume(); + }, $args, false); + $suspension->suspend(); + return null; + } return static::add($delay, $func, $args, false); } - /** * Tick. * @@ -170,7 +179,7 @@ public static function tick() foreach ($taskData as $index => $oneTask) { $taskFunc = $oneTask[0]; $taskArgs = $oneTask[1]; - $persistent = $oneTask[2]; + $persistent = $oneTask[2]; $timeInterval = $oneTask[3]; try { $taskFunc(...$taskArgs); diff --git a/src/Worker.php b/src/Worker.php index a55fa78ac..b2436362f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -19,7 +19,9 @@ use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; use Workerman\Events\Event; +use Workerman\Events\Revolt; use Workerman\Events\Select; +use Revolt\EventLoop; /** @@ -473,7 +475,7 @@ class Worker * @var array */ protected static $availableEventLoops = [ - "event" => Event::class, + 'event' => Event::class, ]; /** @@ -1285,6 +1287,11 @@ protected static function getEventLoopName(): string return static::$eventLoopClass; } + if (\class_exists(EventLoop::class)) { + static::$eventLoopClass = Revolt::class; + return static::$eventLoopClass; + } + $loopName = ''; foreach (static::$availableEventLoops as $name => $class) { if (\extension_loaded($name)) { From 26c16a5f22733bc4671a578c4b53fbf5718d3168 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 23 Jan 2023 10:56:53 +0800 Subject: [PATCH 0789/1216] Update --- src/Timer.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Timer.php b/src/Timer.php index 9c8d3ea7e..d7bffacab 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -151,8 +151,7 @@ public static function add(float $timeInterval, callable $func, $args = [], bool public static function delay(float $delay, $func = null, array $args = []) { if (!$func) { - $eventLoop = EventLoop::getDriver(); - $suspension = $eventLoop->getSuspension(); + $suspension = EventLoop::getSuspension(); static::add($delay, function () use ($suspension) { $suspension->resume(); }, $args, false); From 808af1392844be930bb7ceced9c691cfe1b5fa79 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Jan 2023 09:52:00 +0800 Subject: [PATCH 0790/1216] Update --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index da98e8df5..78f980b15 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -400,7 +400,7 @@ protected function parseHeaders() return; } $headBuffer = \substr($rawHead, $endLinePosition + 2); - $cacheable = static::$enableCache && !isset($headBuffer[2048]); + $cacheable = static::$enableCache && !isset($headBuffer[4096]); if ($cacheable && isset($cache[$headBuffer])) { $this->data['headers'] = $cache[$headBuffer]; return; From ff6fedcbd47b8cab18ade5b9a0c108819ec28847 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 25 Jan 2023 21:15:06 +0800 Subject: [PATCH 0791/1216] Update --- src/Connection/TcpConnection.php | 16 ++++++------- src/Events/Swoole.php | 5 ++++ src/Timer.php | 40 ++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 89af657d4..617dde524 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -714,14 +714,14 @@ public function baseRead($socket, $checkEof = true) */ public function baseWrite() { - \set_error_handler(function () { - }); - if ($this->transport === 'ssl') { - $len = @\fwrite($this->socket, $this->sendBuffer, 8192); - } else { - $len = @\fwrite($this->socket, $this->sendBuffer); - } - \restore_error_handler(); + $len = 0; + try { + if ($this->transport === 'ssl') { + $len = @\fwrite($this->socket, $this->sendBuffer, 8192); + } else { + $len = @\fwrite($this->socket, $this->sendBuffer); + } + } catch (\Throwable $e) {} if ($len === \strlen($this->sendBuffer)) { $this->bytesWritten += $len; Worker::$globalEvent->offWritable($this->socket); diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index d4d3a3c44..0edaeae27 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -38,6 +38,11 @@ class Swoole implements EventInterface */ protected $writeEvents = []; + /** + * @var int + */ + protected $mapId = 0; + /** * {@inheritdoc} */ diff --git a/src/Timer.php b/src/Timer.php index d7bffacab..48bbe7898 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -15,9 +15,11 @@ use Revolt\EventLoop; use Workerman\Events\EventInterface; +use Workerman\Events\Revolt; use Workerman\Events\Select; -use Workerman\Worker; -use \Exception; +use Workerman\Events\Swoole; +use Swoole\Coroutine\System; +use Exception; /** * Timer. @@ -143,22 +145,30 @@ public static function add(float $timeInterval, callable $func, $args = [], bool } /** + * Coroutine sleep. + * * @param float $delay - * @param $func - * @param array $args - * @return bool|int|null + * @return null */ - public static function delay(float $delay, $func = null, array $args = []) + public static function sleep(float $delay) { - if (!$func) { - $suspension = EventLoop::getSuspension(); - static::add($delay, function () use ($suspension) { - $suspension->resume(); - }, $args, false); - $suspension->suspend(); - return null; - } - return static::add($delay, $func, $args, false); + switch (Worker::$eventLoopClass) { + // Fiber + case Revolt::class: + $suspension = EventLoop::getSuspension(); + static::add($delay, function () use ($suspension) { + $suspension->resume(); + }, null, false); + $suspension->suspend(); + return null; + // Swoole + case Swoole::class: + System::sleep($delay); + return null; + } + // Swow or non coroutine environment + msleep($delay * 1000); + return null; } /** From 002689ae2fe7a50b99652e48f45c236d75ef1b26 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 15:42:59 +0800 Subject: [PATCH 0792/1216] Fix exit status 2 --- src/Timer.php | 2 +- src/Worker.php | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Timer.php b/src/Timer.php index 48bbe7898..ed9f5a27f 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -167,7 +167,7 @@ public static function sleep(float $delay) return null; } // Swow or non coroutine environment - msleep($delay * 1000); + usleep($delay * 1000 * 1000); return null; } diff --git a/src/Worker.php b/src/Worker.php index b2436362f..e34bfeacf 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1620,6 +1620,10 @@ protected static function monitorWorkersForLinux() foreach (static::$pidMap as $workerId => $workerPidArray) { if (isset($workerPidArray[$pid])) { $worker = static::$workers[$workerId]; + // Fix exit with status 2 for php8.2 + if ($status === \SIGINT && static::$status === static::STATUS_SHUTDOWN) { + $status = 0; + } // Exit status. if ($status !== 0) { static::log("worker[{$worker->name}:$pid] exit with status $status"); @@ -1806,12 +1810,15 @@ public static function stopAll($code = 0, $log = '') $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. $sig = static::$gracefulStop ? \SIGQUIT : \SIGINT; - // Fix exit with status 2 - usleep(50000); foreach ($workerPidArray as $workerPid) { - \posix_kill($workerPid, $sig); + // Fix exit with status 2 for php8.2 + if ($sig === \SIGINT && !Worker::$daemonize) { + Timer::add(1, '\posix_kill', [$workerPid, \SIGINT], false); + } else { + \posix_kill($workerPid, $sig); + } if(!static::$gracefulStop){ - Timer::add(static::$stopTimeout, '\posix_kill', [$workerPid, \SIGKILL], false); + Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, \SIGKILL], false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); From 62b80d65b056bcc7f85e1548b06dba05b98e747e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 16:26:12 +0800 Subject: [PATCH 0793/1216] Fix signal --- src/Events/Swow.php | 47 +++++---------------------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index a5b053100..c877b55f5 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -223,10 +223,11 @@ public function onSignal($signal, $func) return false; } $coroutine = Coroutine::run(static function () use ($signal, $func): void { - try { - Signal::wait($signal); - $func($signal); - } catch (SignalException) { + while (1) { + try { + Signal::wait($signal); + $func($signal); + } catch (SignalException) {} } }); $this->signalListener[$signal] = $coroutine; @@ -270,44 +271,6 @@ public function destroy() $this->stop(); } - public function add($fd, $flag, $func, $args = []) - { - switch ($flag) { - case self::EV_SIGNAL: - return $this->onSignal($fd, $func); - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - $method = self::EV_TIMER === $flag ? 'tick' : 'after'; - if ($method === 'tick') { - return $this->repeat($fd, $func, $args); - } else { - return $this->delay($fd, $func, $args); - } - case self::EV_READ: - return $this->onReadable($fd, $func); - case self::EV_WRITE: - return $this->onWritable($fd, $func); - } - } - - public function del($fd, $flag) - { - switch ($flag) { - case self::EV_SIGNAL: - return $this->offSignal($fd); - case self::EV_TIMER: - case self::EV_TIMER_ONCE: - return $this->deleteTimer($fd); - case self::EV_READ: - case self::EV_WRITE: - if ($flag === self::EV_READ) { - $this->offReadable($fd); - } else { - $this->offWritable($fd); - } - } - } - public function clearAllTimer() { $this->deleteAllTimer(); From 0b02a55864862bf4e93d4d6a46c694bf5bee0e20 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 16:49:39 +0800 Subject: [PATCH 0794/1216] Fix timer --- src/Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 3e89a1824..3d09c153a 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -285,7 +285,7 @@ protected function tick() unset($this->eventTimer[$timerId]); } try { - $taskData[0]($taskData[1]); + $taskData[0](...$taskData[1]); } catch (Throwable $e) { Worker::stopAll(250, $e); } From 1c6b44e799c1c89787d8a98975db93981914d308 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 20:13:34 +0800 Subject: [PATCH 0795/1216] swow --- src/Events/Swow.php | 70 +++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index c877b55f5..b2fe53a83 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -127,23 +127,28 @@ public function deleteAllTimer() */ public function onReadable($stream, $func) { - if (isset($this->readEvents[(int) $stream])) { + $fd = (int) $stream; + if (isset($this->readEvents[$fd])) { $this->offReadable($stream); } - $this->readEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + Coroutine::run(function () use ($stream, $func, $fd): void { try { + $this->readEvents[$fd] = Coroutine::getCurrent(); while (true) { $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP); + if (!isset($this->readEvents[$fd]) || $this->readEvents[$fd] !== Coroutine::getCurrent()) { + break; + } if ($rEvent !== STREAM_POLLNONE) { $func($stream); } if ($rEvent !== STREAM_POLLIN) { - $this->offReadable($stream, bySelf: true); + $this->offReadable($stream); break; } } } catch (RuntimeException) { - $this->offReadable($stream, bySelf: true); + $this->offReadable($stream); } }); return true; @@ -152,20 +157,10 @@ public function onReadable($stream, $func) /** * {@inheritdoc} */ - public function offReadable($stream, bool $bySelf = false) + public function offReadable($stream) { - $fd = (int) $stream; - if (!isset($this->readEvents[$fd])) { - return; - } - if (!$bySelf) { - $coroutine = $this->readEvents[$fd]; - if (!$coroutine->isExecuting()) { - return; - } - $coroutine->kill(); - } - unset($this->readEvents[$fd]); + // 在当前协程执行 $coroutine->kill() 会导致不可预知问题,所以没有使用$coroutine->kill() + unset($this->readEvents[(int) $stream]); } /** @@ -173,23 +168,28 @@ public function offReadable($stream, bool $bySelf = false) */ public function onWritable($stream, $func) { - if (isset($this->writeEvents[(int) $stream])) { + $fd = (int) $stream; + if (isset($this->writeEvents[$fd])) { $this->offWritable($stream); } - $this->writeEvents[(int) $stream] = Coroutine::run(function () use ($stream, $func): void { + Coroutine::run(function () use ($stream, $func, $fd): void { try { + $this->writeEvents[$fd] = Coroutine::getCurrent(); while (true) { $rEvent = stream_poll_one($stream, STREAM_POLLOUT | STREAM_POLLHUP); + if (!isset($this->writeEvents[$fd]) || $this->writeEvents[$fd] !== Coroutine::getCurrent()) { + break; + } if ($rEvent !== STREAM_POLLNONE) { $func($stream); } if ($rEvent !== STREAM_POLLOUT) { - $this->offWritable($stream, bySelf: true); + $this->offWritable($stream); break; } } } catch (RuntimeException) { - $this->offWritable($stream, bySelf: true); + $this->offWritable($stream); } }); return true; @@ -198,20 +198,9 @@ public function onWritable($stream, $func) /** * {@inheritdoc} */ - public function offWritable($stream, bool $bySelf = false) + public function offWritable($stream) { - $fd = (int) $stream; - if (!isset($this->writeEvents[$fd])) { - return; - } - if (!$bySelf) { - $coroutine = $this->writeEvents[$fd]; - if (!$coroutine->isExecuting()) { - return; - } - $coroutine->kill(); - } - unset($this->writeEvents[$fd]); + unset($this->writeEvents[(int) $stream]); } /** @@ -219,18 +208,19 @@ public function offWritable($stream, bool $bySelf = false) */ public function onSignal($signal, $func) { - if (isset($this->signalListener[$signal])) { - return false; - } - $coroutine = Coroutine::run(static function () use ($signal, $func): void { + Coroutine::run(function () use ($signal, $func): void { + $this->signalListener[$signal] = Coroutine::getCurrent(); while (1) { try { Signal::wait($signal); + if (!isset($this->signalListener[$signal]) || + $this->signalListener[$signal] !== Coroutine::getCurrent()) { + break; + } $func($signal); } catch (SignalException) {} } }); - $this->signalListener[$signal] = $coroutine; return true; } @@ -242,7 +232,6 @@ public function offSignal($signal) if (!isset($this->signalListener[$signal])) { return false; } - $this->signalListener[$signal]->kill(); unset($this->signalListener[$signal]); return true; } @@ -263,7 +252,6 @@ public function run() public function stop() { Coroutine::getMain()->kill(); - Signal::kill(getmypid(), Signal::INT); } public function destroy() From ca7a770ee6bce585aa469f1a3711359705631420 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 21:54:40 +0800 Subject: [PATCH 0796/1216] Fix Swoole --- src/Events/Swoole.php | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 0edaeae27..ca1c581db 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -101,8 +101,17 @@ public function repeat(float $interval, $func, $args) */ public function onReadable($stream, $func) { - $this->readEvents[(int)$stream] = $stream; - return Event::add($stream, $func, null, \SWOOLE_EVENT_READ); + $fd = (int)$stream; + if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { + Event::add($stream, $func, null, \SWOOLE_EVENT_READ); + } else { + if (isset($this->writeEvents[$fd])) { + Event::set($stream, $func, null, \SWOOLE_EVENT_READ | \SWOOLE_EVENT_WRITE); + } else { + Event::set($stream, $func, null, \SWOOLE_EVENT_READ); + } + } + $this->readEvents[$fd] = $stream; } /** @@ -116,9 +125,10 @@ public function offReadable($stream) } unset($this->readEvents[$fd]); if (!isset($this->writeEvents[$fd])) { - return Event::del($stream); + Event::del($stream); + return; } - return Event::set($stream, null, null, \SWOOLE_EVENT_READ); + Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); } /** @@ -126,8 +136,17 @@ public function offReadable($stream) */ public function onWritable($stream, $func) { - $this->writeEvents[(int)$stream] = $stream; - return Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE); + $fd = (int)$stream; + if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { + Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE); + } else { + if (isset($this->readEvents[$fd])) { + Event::set($stream, null, $func, \SWOOLE_EVENT_WRITE | \SWOOLE_EVENT_READ); + } else { + Event::set($stream, null, $func, \SWOOLE_EVENT_WRITE); + } + } + $this->writeEvents[$fd] = $stream; } /** @@ -141,9 +160,10 @@ public function offWritable($stream) } unset($this->writeEvents[$fd]); if (!isset($this->readEvents[$fd])) { - return Event::del($stream); + Event::del($stream); + return; } - return Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); + Event::set($stream, null, null, \SWOOLE_EVENT_READ); } /** @@ -159,8 +179,7 @@ public function onSignal($signal, $func) */ public function offSignal($signal) { - return Process::signal($signal, function () { - }); + return Process::signal($signal, function () {}); } /** From c72cda85ce9f396c6d80659c86c8a80a25b2862b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 26 Jan 2023 22:14:25 +0800 Subject: [PATCH 0797/1216] offDealy offRepeat --- src/Events/Ev.php | 10 +++++++++- src/Events/Event.php | 12 ++++++++++-- src/Events/EventInterface.php | 13 ++++++++++--- src/Events/Revolt.php | 10 +++++++++- src/Events/Select.php | 10 +++++++++- src/Events/Swoole.php | 10 +++++++++- src/Events/Swow.php | 21 +++++++++++++++++++-- src/Timer.php | 24 +++++++++++++----------- 8 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 0d0488e82..b33beb06d 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -73,7 +73,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { $this->eventTimer[$timerId]->stop(); @@ -83,6 +83,14 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ diff --git a/src/Events/Event.php b/src/Events/Event.php index 338ebe64a..8d46cb196 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -93,7 +93,7 @@ public function delay(float $delay, $func, $args) $timerId = $this->timerId++; $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args, $timerId) { try { - $this->deleteTimer($timerId); + $this->offDelay($timerId); $func(...$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); @@ -109,7 +109,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { $this->eventTimer[$timerId]->del(); @@ -119,6 +119,14 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 63f27890e..3be91df24 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -34,11 +34,18 @@ public function delay(float $delay, $func, $args); public function repeat(float $interval, $func, $args); /** - * Delete a timer. + * Delete a delay timer. * @param $timerId * @return bool */ - public function deleteTimer($timerId); + public function offDelay($timerId); + + /** + * Delete a repeat timer. + * @param $timerId + * @return bool + */ + public function offRepeat($timerId); /** * Execute a callback when a stream resource becomes readable or is closed for reading. @@ -66,7 +73,7 @@ public function onWritable($stream, $func); /** * Cancel a callback of stream writable. * @param $stream - * @return mixed + * @return void */ public function offWritable($stream); diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 8d4436c90..935d4cad1 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -211,7 +211,7 @@ public function offSignal($signal) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { $this->driver->cancel($this->eventTimer[$timerId]); @@ -221,6 +221,14 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ diff --git a/src/Events/Select.php b/src/Events/Select.php index 3d09c153a..02acccf1f 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -146,7 +146,7 @@ public function repeat(float $delay, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { unset($this->eventTimer[$timerId]); @@ -155,6 +155,14 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ca1c581db..ec74b1c37 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -65,7 +65,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { $res = Timer::clear($timerId); @@ -75,6 +75,14 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ diff --git a/src/Events/Swow.php b/src/Events/Swow.php index b2fe53a83..34bc313ed 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -99,7 +99,7 @@ public function repeat(float $interval, $func, $args) /** * {@inheritdoc} */ - public function deleteTimer($timerId) + public function offDelay($timerId) { if (isset($this->eventTimer[$timerId])) { try { @@ -112,13 +112,21 @@ public function deleteTimer($timerId) return false; } + /** + * {@inheritdoc} + */ + public function offRepeat($timerId) + { + return $this->offDelay($timerId); + } + /** * {@inheritdoc} */ public function deleteAllTimer() { foreach ($this->eventTimer as $timerId) { - $this->deleteTimer($timerId); + $this->offDelay($timerId); } } @@ -254,16 +262,25 @@ public function stop() Coroutine::getMain()->kill(); } + /** + * @return void + */ public function destroy() { $this->stop(); } + /** + * @return void + */ public function clearAllTimer() { $this->deleteAllTimer(); } + /** + * @return void + */ public function loop() { waitAll(); diff --git a/src/Timer.php b/src/Timer.php index ed9f5a27f..97b7e4ad5 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -106,8 +106,7 @@ public static function signalHandle() public static function add(float $timeInterval, callable $func, $args = [], bool $persistent = true) { if ($timeInterval < 0) { - Worker::safeEcho(new Exception("bad time_interval")); - return false; + throw new \RuntimeException('$timeInterval can not less than 0'); } if ($args === null) { @@ -165,10 +164,12 @@ public static function sleep(float $delay) case Swoole::class: System::sleep($delay); return null; + // Swow + case Swow::class: + usleep($delay * 1000 * 1000); + return null; } - // Swow or non coroutine environment - usleep($delay * 1000 * 1000); - return null; + throw new \RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer install revolt/event-loop" and restart workerman'); } /** @@ -215,16 +216,17 @@ public static function tick() public static function del($timerId) { if (self::$event) { - return self::$event->deleteTimer($timerId); + return self::$event->offDelay($timerId); } - foreach(self::$tasks as $runTime => $taskData) { - if(array_key_exists($timerId, $taskData)) unset(self::$tasks[$runTime][$timerId]); + if(array_key_exists($timerId, $taskData)) { + unset(self::$tasks[$runTime][$timerId]); + } + } + if(array_key_exists($timerId, self::$status)) { + unset(self::$status[$timerId]); } - - if(array_key_exists($timerId, self::$status)) unset(self::$status[$timerId]); - return true; } From 58e0cff89e15f69271915f45b46de9a1c72ea351 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Jan 2023 15:26:52 +0800 Subject: [PATCH 0798/1216] Update --- src/Events/Ev.php | 4 ++-- src/Events/Event.php | 4 ++-- src/Events/EventInterface.php | 4 ++-- src/Events/Revolt.php | 4 ++-- src/Events/Select.php | 13 ++++++++++--- src/Events/Swoole.php | 4 ++-- src/Events/Swow.php | 4 ++-- src/Timer.php | 3 +-- 8 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Events/Ev.php b/src/Events/Ev.php index b33beb06d..e3b610044 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -59,7 +59,7 @@ class Ev implements EventInterface /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $timerId = self::$timerId; $event = new \EvTimer($delay, 0, function () use ($func, $args, $timerId) { @@ -94,7 +94,7 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args) + public function repeat(float $interval, $func, $args = []) { $event = new \EvTimer($interval, $interval, function () use ($func, $args) { $func(...(array)$args); diff --git a/src/Events/Event.php b/src/Events/Event.php index 8d46cb196..ecbd6130e 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -87,7 +87,7 @@ public function __construct() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $className = $this->eventClassName; $timerId = $this->timerId++; @@ -130,7 +130,7 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args) + public function repeat(float $interval, $func, $args = []) { $className = $this->eventClassName; $timerId = $this->timerId++; diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 3be91df24..bf15321d5 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -22,7 +22,7 @@ interface EventInterface * @param $args * @return int|bool */ - public function delay(float $delay, $func, $args); + public function delay(float $delay, $func, $args = []); /** * Repeatedly execute a callback. @@ -31,7 +31,7 @@ public function delay(float $delay, $func, $args); * @param $args * @return int|bool */ - public function repeat(float $interval, $func, $args); + public function repeat(float $interval, $func, $args = []); /** * Delete a delay timer. diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 935d4cad1..531dcbc16 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -98,7 +98,7 @@ public function stop() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $args = (array)$args; $timerId = $this->timerId++; @@ -114,7 +114,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args) + public function repeat(float $interval, $func, $args = []) { $args = (array)$args; $timerId = $this->timerId++; diff --git a/src/Events/Select.php b/src/Events/Select.php index 02acccf1f..58fb17156 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -22,6 +22,12 @@ */ class Select implements EventInterface { + /** + * Running. + * @var bool + */ + protected $running = true; + /** * All listeners for read/write event. * @@ -112,7 +118,7 @@ public function __construct() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $timerId = $this->timerId++; $runTime = \microtime(true) + $delay; @@ -129,7 +135,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function repeat(float $delay, $func, $args) + public function repeat(float $delay, $func, $args = []) { $timerId = $this->timerId++; $runTime = \microtime(true) + $delay; @@ -329,7 +335,7 @@ public function deleteAllTimer() */ public function run() { - while (1) { + while ($this->running) { if (\DIRECTORY_SEPARATOR === '/') { // Calls signal handlers for pending signals \pcntl_signal_dispatch(); @@ -382,6 +388,7 @@ public function run() */ public function stop() { + $this->running = false; $this->deleteAllTimer(); foreach ($this->signalEvents as $signal => $item) { $this->offsignal($signal); diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ec74b1c37..f6b15d9cd 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -46,7 +46,7 @@ class Swoole implements EventInterface /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $t = (int)($delay * 1000); $t = $t < 1 ? 1 : $t; @@ -86,7 +86,7 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args) + public function repeat(float $interval, $func, $args = []) { if ($this->mapId > \PHP_INT_MAX) { $this->mapId = 0; diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 34bc313ed..fbf83417b 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -56,7 +56,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args) + public function delay(float $delay, $func, $args = []) { $t = (int) ($delay * 1000); $t = max($t, 1); @@ -77,7 +77,7 @@ public function delay(float $delay, $func, $args) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args) + public function repeat(float $interval, $func, $args = []) { $t = (int) ($interval * 1000); $t = max($t, 1); diff --git a/src/Timer.php b/src/Timer.php index 97b7e4ad5..12c057fed 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -218,8 +218,7 @@ public static function del($timerId) if (self::$event) { return self::$event->offDelay($timerId); } - foreach(self::$tasks as $runTime => $taskData) - { + foreach(self::$tasks as $runTime => $taskData) { if(array_key_exists($timerId, $taskData)) { unset(self::$tasks[$runTime][$timerId]); } From 43d65d7079850f90f7470183c5330747184ac5b8 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Jan 2023 19:46:01 +0800 Subject: [PATCH 0799/1216] Fix offDelay --- src/Events/Event.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index ecbd6130e..a76f49ed1 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -91,9 +91,8 @@ public function delay(float $delay, $func, $args = []) { $className = $this->eventClassName; $timerId = $this->timerId++; - $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args, $timerId) { + $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args) { try { - $this->offDelay($timerId); $func(...$args); } catch (\Throwable $e) { Worker::stopAll(250, $e); @@ -159,7 +158,7 @@ public function onReadable($stream, $func) if (!$event || !$event->add()) { return false; } - $this->writeEvents[$fdKey] = $event; + $this->readEvents[$fdKey] = $event; return true; } From 3b2c4021d6831d4d6b455353660047e2d67b4e32 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 27 Jan 2023 21:14:52 +0800 Subject: [PATCH 0800/1216] support Event->setErrorHandler --- src/Events/Ev.php | 24 +++++++++++++++++-- src/Events/Event.php | 45 ++++++++++++++++++++++++++++++++--- src/Events/EventInterface.php | 29 +++++++++++++++------- src/Events/Revolt.php | 16 +++++++++++++ src/Events/Select.php | 38 +++++++++++++++++++++++++++-- src/Events/Swoole.php | 44 ++++++++++++++++++++++++++++++---- src/Events/Swow.php | 40 ++++++++++++++++++++++++++++--- src/Worker.php | 9 +++++++ 8 files changed, 222 insertions(+), 23 deletions(-) diff --git a/src/Events/Ev.php b/src/Events/Ev.php index e3b610044..884c8131d 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -13,8 +13,8 @@ namespace Workerman\Events; -use Workerman\Worker; -use \EvWatcher; +use Closure; +use EvWatcher; /** * Ev eventloop @@ -49,6 +49,11 @@ class Ev implements EventInterface */ protected $eventTimer = []; + /** + * @var Closure || null + */ + protected $errorHandler; + /** * Timer id. * @@ -208,4 +213,19 @@ public function getTimerCount() return \count($this->eventTimer); } + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->errorHandler; + } } diff --git a/src/Events/Event.php b/src/Events/Event.php index a76f49ed1..2b2a9ceed 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -14,7 +14,7 @@ namespace Workerman\Events; -use Workerman\Worker; +use Throwable; /** * libevent eventloop @@ -64,6 +64,11 @@ class Event implements EventInterface */ protected $eventClassName = ''; + /** + * @var Closure || null + */ + protected $errorHandler; + /** * Construct. * @return void @@ -95,7 +100,7 @@ public function delay(float $delay, $func, $args = []) try { $func(...$args); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } }); if (!$event || !$event->addTimer($delay)) { @@ -137,7 +142,7 @@ public function repeat(float $interval, $func, $args = []) try { $func(...$args); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } }); if (!$event || !$event->addTimer($interval)) { @@ -262,4 +267,38 @@ public function getTimerCount() { return \count($this->eventTimer); } + + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->errorHandler; + } + + /** + * @param Throwable $e + * @return void + * @throws Throwable + */ + public function error(Throwable $e) + { + try { + if (!$this->errorHandler) { + throw new $e; + } + ($this->errorHandler)($e); + } catch (\Throwable $e) { + // Cannot trigger an exception in the Event callback, otherwise it will cause an infinite loop + echo $e; + } + } } diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index bf15321d5..163fe898f 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -24,6 +24,13 @@ interface EventInterface */ public function delay(float $delay, $func, $args = []); + /** + * Delete a delay timer. + * @param $timerId + * @return bool + */ + public function offDelay($timerId); + /** * Repeatedly execute a callback. * @param float $interval @@ -33,13 +40,6 @@ public function delay(float $delay, $func, $args = []); */ public function repeat(float $interval, $func, $args = []); - /** - * Delete a delay timer. - * @param $timerId - * @return bool - */ - public function offDelay($timerId); - /** * Delete a repeat timer. * @param $timerId @@ -111,8 +111,21 @@ public function run(); public function stop(); /** - * + * Get Timer count. * @return int */ public function getTimerCount(); + + /** + * Set error handler + * @param $errorHandler + * @return void + */ + public function setErrorHandler($errorHandler); + + /** + * Get error handler + * @return null|\Closure(\Throwable) + */ + public function getErrorHandler(); } diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 531dcbc16..b7fd24252 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -247,4 +247,20 @@ public function getTimerCount() { return \count($this->eventTimer); } + + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->driver->setErrorHandler($errorHandler); + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->driver->getErrorHandler(); + } } diff --git a/src/Events/Select.php b/src/Events/Select.php index 58fb17156..f05b8a753 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -15,7 +15,6 @@ namespace Workerman\Events; use Throwable; -use Workerman\Worker; /** * select eventloop @@ -105,6 +104,11 @@ class Select implements EventInterface */ protected $selectTimeout = 100000000; + /** + * @var Closure || null + */ + protected $errorHandler; + /** * Construct. */ @@ -301,7 +305,8 @@ protected function tick() try { $taskData[0](...$taskData[1]); } catch (Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); + continue; } } else { break; @@ -405,4 +410,33 @@ public function getTimerCount() return \count($this->eventTimer); } + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->errorHandler; + } + + /** + * @param Throwable $e + * @return void + * @throws Throwable + */ + public function error(Throwable $e) + { + if (!$this->errorHandler) { + throw new $e; + } + ($this->errorHandler)($e); + } + } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index f6b15d9cd..ca1c8ae37 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -13,7 +13,7 @@ namespace Workerman\Events; -use Workerman\Worker; +use Throwable; use Swoole\Event; use Swoole\Timer; use Swoole\Process; @@ -43,6 +43,11 @@ class Swoole implements EventInterface */ protected $mapId = 0; + /** + * @var Closure || null + */ + protected $errorHandler; + /** * {@inheritdoc} */ @@ -54,8 +59,8 @@ public function delay(float $delay, $func, $args = []) unset($this->eventTimer[$timerId]); try { $func(...(array)$args); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); + } catch (Throwable $e) { + $this->error($e); } }); $this->eventTimer[$timerId] = $timerId; @@ -96,8 +101,8 @@ public function repeat(float $interval, $func, $args = []) $timerId = Timer::tick($t, function () use ($func, $args) { try { $func(...(array)$args); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); + } catch (Throwable $e) { + $this->error($e); } }); $this->eventTimer[$timerId] = $timerId; @@ -229,4 +234,33 @@ public function getTimerCount() return \count($this->eventTimer); } + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->errorHandler; + } + + /** + * @param Throwable $e + * @return void + * @throws Throwable + */ + public function error(Throwable $e) + { + if (!$this->errorHandler) { + throw new $e; + } + ($this->errorHandler)($e); + } + } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index fbf83417b..09fd4d97c 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -6,7 +6,7 @@ use Swow\Coroutine; use Swow\Signal; use Swow\SignalException; -use Workerman\Worker; +use Throwable; use function getmypid; use function max; use function msleep; @@ -43,6 +43,11 @@ class Swow implements EventInterface */ protected $signalListener = []; + /** + * @var Closure || null + */ + protected $errorHandler; + /** * Get timer count. * @@ -66,7 +71,7 @@ public function delay(float $delay, $func, $args = []) try { $func(...(array) $args); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } }); $timerId = $coroutine->getId(); @@ -87,7 +92,7 @@ public function repeat(float $interval, $func, $args = []) try { $func(...(array) $args); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } }); @@ -285,4 +290,33 @@ public function loop() { waitAll(); } + + /** + * {@inheritdoc} + */ + public function setErrorHandler($errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * {@inheritdoc} + */ + public function getErrorHandler() + { + return $this->errorHandler; + } + + /** + * @param Throwable $e + * @return void + * @throws Throwable + */ + public function error(Throwable $e) + { + if (!$this->errorHandler) { + throw new $e; + } + ($this->errorHandler)($e); + } } \ No newline at end of file diff --git a/src/Worker.php b/src/Worker.php index e34bfeacf..dee07ad1f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1396,6 +1396,9 @@ protected static function forkWorkersForWindows() else { static::$globalEvent = new Select(); + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); Timer::init(static::$globalEvent); foreach($files as $startFile) { @@ -1439,6 +1442,9 @@ public static function forkOneWorkerForWindows($startFile) if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); Timer::init(static::$globalEvent); } @@ -2367,6 +2373,9 @@ public function run() if (!static::$globalEvent) { $eventLoopClass = static::getEventLoopName(); static::$globalEvent = new $eventLoopClass; + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); $this->resumeAccept(); } From 25586916c2a79056e08607571e2dbb11fbb38723 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Jan 2023 10:09:18 +0800 Subject: [PATCH 0801/1216] Update --- src/Events/Select.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index f05b8a753..fecdca28c 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -257,7 +257,7 @@ public function onSignal($signal, $func) /** * {@inheritdoc} */ - public function offsignal($signal) + public function offSignal($signal) { unset($this->signalEvents[$signal]); \pcntl_signal($signal, SIG_IGN); @@ -341,11 +341,6 @@ public function deleteAllTimer() public function run() { while ($this->running) { - if (\DIRECTORY_SEPARATOR === '/') { - // Calls signal handlers for pending signals - \pcntl_signal_dispatch(); - } - $read = $this->readFds; $write = $this->writeFds; $except = $this->exceptFds; @@ -356,7 +351,6 @@ public function run() @stream_select($read, $write, $except, 0, $this->selectTimeout); } catch (Throwable $e) { } - } else { $this->selectTimeout >= 1 && usleep($this->selectTimeout); } @@ -385,6 +379,11 @@ public function run() $this->exceptEvents[$fdKey]($fd); } } + + if (!empty($this->signalEvents)) { + // Calls signal handlers for pending signals + \pcntl_signal_dispatch(); + } } } From 1a62c4e76049ff3b3b709f116f9475d0acbd1029 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Jan 2023 12:16:59 +0800 Subject: [PATCH 0802/1216] Update --- src/Events/Revolt.php | 2 +- src/Events/Swoole.php | 9 +++++++++ src/Events/Swow.php | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index b7fd24252..6c7154b83 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -118,7 +118,7 @@ public function repeat(float $interval, $func, $args = []) { $args = (array)$args; $timerId = $this->timerId++; - $closure = function () use ($func, $args, $timerId) { + $closure = function () use ($func, $args) { $func(...$args); }; $cbId = $this->driver->repeat($interval, $closure); diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ca1c8ae37..ad95b079b 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -48,6 +48,15 @@ class Swoole implements EventInterface */ protected $errorHandler; + /** + * Construct + */ + public function __construct() + { + // Avoid process exit due to no listening + Timer::tick(100000000, function () {}); + } + /** * {@inheritdoc} */ diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 09fd4d97c..bbedfa8f2 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -148,6 +148,10 @@ public function onReadable($stream, $func) try { $this->readEvents[$fd] = Coroutine::getCurrent(); while (true) { + if (!\is_resource($stream)) { + $this->offReadable($stream); + break; + } $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP); if (!isset($this->readEvents[$fd]) || $this->readEvents[$fd] !== Coroutine::getCurrent()) { break; From 72075d710e4fb70dc8eb503b341420aa0c7e44ce Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Jan 2023 18:30:22 +0800 Subject: [PATCH 0803/1216] add connection->eventLoop --- src/Connection/AsyncTcpConnection.php | 27 +++++++++------- src/Connection/AsyncUdpConnection.php | 23 ++++++++------ src/Connection/ConnectionInterface.php | 38 ++++++++++++++++++++++ src/Connection/TcpConnection.php | 44 ++++++++++++++------------ src/Connection/UdpConnection.php | 1 + src/Events/Select.php | 1 - src/Worker.php | 2 +- 7 files changed, 93 insertions(+), 43 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index df58bcd44..5100cc19f 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -196,6 +196,10 @@ public function connect() return; } + if (!$this->eventLoop) { + $this->eventLoop = Worker::$globalEvent; + } + $this->status = self::STATUS_CONNECTING; $this->connectStartTime = \microtime(true); if ($this->transport !== 'unix') { @@ -245,10 +249,10 @@ public function connect() return; } // Add socket to global event loop waiting connection is successfully established or faild. - Worker::$globalEvent->onWritable($this->socket, [$this, 'checkConnection']); + $this->eventLoop->onWritable($this->socket, [$this, 'checkConnection']); // For windows. - if (\DIRECTORY_SEPARATOR === '\\' && Worker::$eventLoopClass === Select::class) { - Worker::$globalEvent->onExcept($this->socket, [$this, 'checkConnection']); + if (\DIRECTORY_SEPARATOR === '\\' && \method_exists($this->eventLoop, 'onExcept')) { + $this->eventLoop->onExcept($this->socket, [$this, 'checkConnection']); } } @@ -316,7 +320,7 @@ protected function emitError($code, $msg) try { ($this->onError)($this, $code, $msg); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } } @@ -330,11 +334,11 @@ protected function emitError($code, $msg) public function checkConnection() { // Remove EV_EXPECT for windows. - if (\DIRECTORY_SEPARATOR === '\\' && Worker::$eventLoopClass === Select::class) { - Worker::$globalEvent->offExcept($this->socket); + if (\DIRECTORY_SEPARATOR === '\\' && \method_exists($this->eventLoop, 'offExcept')) { + $this->eventLoop->offExcept($this->socket); } // Remove write listener. - Worker::$globalEvent->offWritable($this->socket); + $this->eventLoop->offWritable($this->socket); if ($this->status !== self::STATUS_CONNECTING) { return; @@ -363,11 +367,11 @@ public function checkConnection() } else { // There are some data waiting to send. if ($this->sendBuffer) { - Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); } } // Register a listener waiting read event. - Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); $this->status = self::STATUS_ESTABLISHED; $this->remoteAddress = $address; @@ -377,7 +381,7 @@ public function checkConnection() try { ($this->onConnect)($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } // Try to emit protocol::onConnect @@ -385,10 +389,11 @@ public function checkConnection() try { [$this->protocol, 'onConnect']($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } } else { + // Connection failed. $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(\microtime(true) - $this->connectStartTime, 4) . ' seconds'); if ($this->status === self::STATUS_CLOSING) { diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index be619b817..36162265a 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -14,6 +14,7 @@ namespace Workerman\Connection; +use Throwable; use Workerman\Events\EventInterface; use Workerman\Worker; use \Exception; @@ -97,8 +98,8 @@ public function baseRead($socket) ++ConnectionInterface::$statistics['total_request']; try { ($this->onMessage)($this, $recvBuffer); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); + } catch (Throwable $e) { + $this->error($e); } } return true; @@ -134,24 +135,25 @@ public function send($sendBuffer, $raw = false) * @param bool $raw * * @return bool + * @throws Throwable */ public function close($data = null, $raw = false) { if ($data !== null) { $this->send($data, $raw); } - Worker::$globalEvent->offReadable($this->socket); + $this->eventLoop->offReadable($this->socket); \fclose($this->socket); $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { try { ($this->onClose)($this); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); + } catch (Throwable $e) { + $this->error($e); } } - $this->onConnect = $this->onMessage = $this->onClose = null; + $this->onConnect = $this->onMessage = $this->onClose = $this->eventLoop = $this->errorHandler = null; return true; } @@ -165,6 +167,9 @@ public function connect() if ($this->connected === true) { return; } + if (!$this->eventLoop) { + $this->eventLoop = Worker::$globalEvent; + } if ($this->contextOption) { $context = \stream_context_create($this->contextOption); $this->socket = \stream_socket_client("udp://{$this->remoteAddress}", $errno, $errmsg, @@ -181,15 +186,15 @@ public function connect() \stream_set_blocking($this->socket, false); if ($this->onMessage) { - Worker::$globalEvent->onWritable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onWritable($this->socket, [$this, 'baseRead']); } $this->connected = true; // Try to emit onConnect callback. if ($this->onConnect) { try { ($this->onConnect)($this); - } catch (\Throwable $e) { - Worker::stopAll(250, $e); + } catch (Throwable $e) { + $this->error($e); } } } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index ef569d5d1..929b56075 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -14,6 +14,12 @@ namespace Workerman\Connection; +use Throwable; +use Workerman\Events\Event; +use Workerman\Events\EventInterface; +use Workerman\Events\Revolt; +use Workerman\Worker; + /** * ConnectionInterface. */ @@ -67,6 +73,16 @@ abstract class ConnectionInterface */ public $onError = null; + /** + * @var EventInterface + */ + public $eventLoop; + + /** + * @var \Closure + */ + public $errorHandler; + /** * Sends data on the connection. * @@ -139,4 +155,26 @@ abstract public function isIPv6(); */ abstract public function close($data = null); + /** + * @param Throwable $exception + * @return mixed + * @throws Throwable + */ + public function error(Throwable $exception) + { + if (!$this->errorHandler) { + Worker::stopAll(250, $exception); + return; + } + try { + ($this->errorHandler)($exception); + } catch (Throwable $exception) { + if ($this->eventLoop instanceof Event) { + echo $exception; + return; + } + throw $exception; + } + } + } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 617dde524..8d95c5642 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -294,7 +294,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * @param resource $socket * @param string $remoteAddress */ - public function __construct($socket, $remoteAddress = '') + public function __construct($eventLoop, $socket, $remoteAddress = '') { ++self::$statistics['connection_count']; $this->id = $this->realId = self::$idRecorder++; @@ -307,7 +307,8 @@ public function __construct($socket, $remoteAddress = '') if (\function_exists('stream_set_read_buffer')) { \stream_set_read_buffer($this->socket, 0); } - Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop = $eventLoop; + $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; $this->remoteAddress = $remoteAddress; @@ -366,7 +367,7 @@ public function send($sendBuffer, $raw = false) // Attempt to send data directly. if ($this->sendBuffer === '') { if ($this->transport === 'ssl') { - Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); $this->sendBuffer = $sendBuffer; $this->checkBufferWillFull(); return; @@ -394,7 +395,7 @@ public function send($sendBuffer, $raw = false) try { ($this->onError)($this, static::SEND_FAIL, 'client closed'); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } $this->destroy(); @@ -402,7 +403,7 @@ public function send($sendBuffer, $raw = false) } $this->sendBuffer = $sendBuffer; } - Worker::$globalEvent->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); // Check if the send buffer will be full. $this->checkBufferWillFull(); return; @@ -551,7 +552,7 @@ public function isIpV6() */ public function pauseRecv() { - Worker::$globalEvent->offReadable($this->socket); + $this->eventLoop->offReadable($this->socket); $this->isPaused = true; } @@ -563,7 +564,7 @@ public function pauseRecv() public function resumeRecv() { if ($this->isPaused === true) { - Worker::$globalEvent->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); $this->isPaused = false; $this->baseRead($this->socket, false); } @@ -585,7 +586,7 @@ public function baseRead($socket, $checkEof = true) if ($this->doSslHandshake($socket)) { $this->sslHandshakeCompleted = true; if ($this->sendBuffer) { - Worker::$globalEvent->onWritable($socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($socket, [$this, 'baseWrite']); } } else { return; @@ -620,7 +621,7 @@ public function baseRead($socket, $checkEof = true) try { ($this->onMessage)($this, $request); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } return; } @@ -686,7 +687,7 @@ public function baseRead($socket, $checkEof = true) } ($this->onMessage)($this, $request); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } return; @@ -701,7 +702,7 @@ public function baseRead($socket, $checkEof = true) try { ($this->onMessage)($this, $this->recvBuffer); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } // Clean receive buffer. $this->recvBuffer = ''; @@ -724,14 +725,14 @@ public function baseWrite() } catch (\Throwable $e) {} if ($len === \strlen($this->sendBuffer)) { $this->bytesWritten += $len; - Worker::$globalEvent->offWritable($this->socket); + $this->eventLoop->offWritable($this->socket); $this->sendBuffer = ''; // Try to emit onBufferDrain callback when the send buffer becomes empty. if ($this->onBufferDrain) { try { ($this->onBufferDrain)($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } if ($this->status === self::STATUS_CLOSING) { @@ -801,7 +802,7 @@ public function doSslHandshake($socket) try { ($this->onSslHandshake)($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } return true; @@ -894,7 +895,7 @@ protected function checkBufferWillFull() try { ($this->onBufferFull)($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } } @@ -913,7 +914,7 @@ protected function bufferIsFull() try { ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } return true; @@ -935,6 +936,7 @@ public function bufferIsEmpty() * Destroy connection. * * @return void + * @throws \Throwable */ public function destroy() { @@ -943,8 +945,8 @@ public function destroy() return; } // Remove event listener. - Worker::$globalEvent->offReadable($this->socket); - Worker::$globalEvent->offWritable($this->socket); + $this->eventLoop->offReadable($this->socket); + $this->eventLoop->offWritable($this->socket); // Close socket. try { @@ -958,7 +960,7 @@ public function destroy() try { ($this->onClose)($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } // Try to emit protocol::onClose @@ -966,7 +968,7 @@ public function destroy() try { ([$this->protocol, 'onClose'])($this); } catch (\Throwable $e) { - Worker::stopAll(250, $e); + $this->error($e); } } $this->sendBuffer = $this->recvBuffer = ''; @@ -974,7 +976,7 @@ public function destroy() $this->isPaused = $this->sslHandshakeCompleted = false; if ($this->status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. - $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; + $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = $this->eventLoop = $this->errorHandler = null; // Remove from worker->connections. if ($this->worker) { unset($this->worker->connections[$this->realId]); diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index d66135cde..62da45a54 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -196,6 +196,7 @@ public function close($data = null, $raw = false) if ($data !== null) { $this->send($data, $raw); } + $this->eventLoop = $this->errorHandler = null; return true; } diff --git a/src/Events/Select.php b/src/Events/Select.php index fecdca28c..cfa524cd1 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -344,7 +344,6 @@ public function run() $read = $this->readFds; $write = $this->writeFds; $except = $this->exceptFds; - if ($read || $write || $except) { // Waiting read/write/signal/timeout events. try { diff --git a/src/Worker.php b/src/Worker.php index dee07ad1f..eea2f13cd 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2453,7 +2453,7 @@ public function acceptTcpConnection($socket) } // TcpConnection. - $connection = new TcpConnection($newSocket, $remoteAddress); + $connection = new TcpConnection(Worker::$globalEvent, $newSocket, $remoteAddress); $this->connections[$connection->id] = $connection; $connection->worker = $this; $connection->protocol = $this->protocol; From 4545b906d676c2c7decffc5d8043949c0b5710f1 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Jan 2023 19:59:34 +0800 Subject: [PATCH 0804/1216] Update --- src/Protocols/Ws.php | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 76f1322db..9c9387ebd 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -222,23 +222,19 @@ public static function encode($payload, ConnectionInterface $connection) if (empty($connection->context->handshakeStep)) { static::sendHandshake($connection); } - $mask = 1; + $maskKey = "\x00\x00\x00\x00"; + $length = \strlen($payload); - $pack = ''; - $length = $lengthFlag = \strlen($payload); - if (65535 < $length) { - $pack = \pack('NN', ($length & 0xFFFFFFFF00000000) >> 32, $length & 0x00000000FFFFFFFF); - $lengthFlag = 127; - } else if (125 < $length) { - $pack = \pack('n*', $length); - $lengthFlag = 126; + if (strlen($payload) < 126) { + $head = chr(0x80 | $length); + } elseif ($length < 0xFFFF) { + $head = chr(0x80 | 126) . pack("n", $length); + } else { + $head = chr(0x80 | 127) . pack("N", 0) . pack("N", $length); } - $head = ($mask << 7) | $lengthFlag; - $head = $connection->websocketType . \chr($head) . $pack; - - $frame = $head . $maskKey; + $frame = $connection->websocketType . $head . $maskKey; // append payload to frame: $maskKey = \str_repeat($maskKey, \floor($length / 4)) . \substr($maskKey, 0, $length % 4); $frame .= $payload ^ $maskKey; From f658690a00afb7de18832359681d351039a59029 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 29 Jan 2023 09:56:39 +0800 Subject: [PATCH 0805/1216] onWebSocketConnect --- src/Connection/AsyncTcpConnection.php | 7 +++++++ src/Connection/TcpConnection.php | 14 ++++++++++++++ src/Worker.php | 7 +++++++ 3 files changed, 28 insertions(+) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 5100cc19f..998f57bfb 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -32,6 +32,13 @@ class AsyncTcpConnection extends TcpConnection */ public $onConnect = null; + /** + * Emitted when websocket handshake completed (Only work when protocol is ws). + * + * @var callable|null + */ + public $onWebSocketConnect = null; + /** * Transport layer protocol. * diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 8d95c5642..0726d8d3a 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -67,6 +67,20 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable */ const STATUS_CLOSED = 8; + /** + * Emitted when socket connection is successfully established. + * + * @var callable|null + */ + public $onConnect = null; + + /** + * Emitted when websocket handshake completed (Only work when protocol is ws). + * + * @var callable|null + */ + public $onWebSocketConnect = null; + /** * Emitted when data is received. * diff --git a/src/Worker.php b/src/Worker.php index eea2f13cd..1ed0e08be 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -149,6 +149,13 @@ class Worker */ public $onConnect = null; + /** + * Emitted when websocket handshake completed (Only work when protocol is ws). + * + * @var callable|null + */ + public $onWebSocketConnect = null; + /** * Emitted when data is received. * From 990be3c899968da048b57d1f2a61e5e0d02b57b0 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 29 Jan 2023 16:18:29 +0800 Subject: [PATCH 0806/1216] require php>=8.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1893afaf4..0d5617c69 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "source": "https://github.com/walkor/workerman" }, "require": { - "php": ">=7.0", + "php": ">=8.1", "ext-json": "*" }, "suggest": { From 69fea2bc8d562925d142fa82409d6f0cbf2e1511 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 29 Jan 2023 20:45:23 +0800 Subject: [PATCH 0807/1216] Update --- src/Events/Swow.php | 12 +++++++----- src/Worker.php | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index bbedfa8f2..157d59266 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -65,13 +65,14 @@ public function delay(float $delay, $func, $args = []) { $t = (int) ($delay * 1000); $t = max($t, 1); - $coroutine = Coroutine::run(function () use ($t, $func, $args): void { + $that = $this; + $coroutine = Coroutine::run(function () use ($t, $func, $args, $that): void { msleep($t); unset($this->eventTimer[Coroutine::getCurrent()->getId()]); try { $func(...(array) $args); } catch (\Throwable $e) { - $this->error($e); + $that->error($e); } }); $timerId = $coroutine->getId(); @@ -86,13 +87,14 @@ public function repeat(float $interval, $func, $args = []) { $t = (int) ($interval * 1000); $t = max($t, 1); - $coroutine = Coroutine::run(static function () use ($t, $func, $args): void { + $that = $this; + $coroutine = Coroutine::run(static function () use ($t, $func, $args, $that): void { while (true) { msleep($t); try { $func(...(array) $args); } catch (\Throwable $e) { - $this->error($e); + $that->error($e); } } }); @@ -268,7 +270,7 @@ public function run() */ public function stop() { - Coroutine::getMain()->kill(); + Coroutine::killAll(); } /** diff --git a/src/Worker.php b/src/Worker.php index 1ed0e08be..0d835fe9c 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1526,12 +1526,12 @@ protected static function forkOneWorkerForLinux(self $worker) $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); - if (strpos(static::$eventLoopClass, 'Workerman\Events\Swoole') !== false) { - exit(0); + if (static::$status !== self::STATUS_SHUTDOWN) { + $err = new Exception('event-loop exited'); + static::log($err); + exit(250); } - $err = new Exception('event-loop exited'); - static::log($err); - exit(250); + exit(0); } else { throw new Exception("forkOneWorker fail"); } From 8b85e3392349aa338e6b08be0bd177965b69e05d Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 29 Jan 2023 20:48:34 +0800 Subject: [PATCH 0808/1216] Update --- src/Events/Swow.php | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 157d59266..a0842c1f2 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -272,31 +272,7 @@ public function stop() { Coroutine::killAll(); } - - /** - * @return void - */ - public function destroy() - { - $this->stop(); - } - - /** - * @return void - */ - public function clearAllTimer() - { - $this->deleteAllTimer(); - } - - /** - * @return void - */ - public function loop() - { - waitAll(); - } - + /** * {@inheritdoc} */ From 8defee7cea35fce91887f96dffed5c251063f8a6 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 30 Jan 2023 09:19:29 +0800 Subject: [PATCH 0809/1216] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 093df03cb..5c85026de 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ Workerman is an asynchronous event-driven PHP framework with high performance to Workerman supports HTTP, Websocket, SSL and other custom protocols. Workerman supports event extension. -## Requires -PHP 7.0 or Higher +## Requires A POSIX compatible operating system (Linux, OSX, BSD) POSIX and PCNTL extensions required Event extension recommended for better performance From ec3148bd727a4eea254f08a81b716f8b66531460 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 10:30:33 +0800 Subject: [PATCH 0810/1216] Type restrictions --- src/Connection/AsyncTcpConnection.php | 53 +++-- src/Connection/AsyncUdpConnection.php | 34 ++- src/Connection/ConnectionInterface.php | 75 ++++-- src/Connection/TcpConnection.php | 224 ++++++++---------- src/Connection/UdpConnection.php | 71 ++---- src/Events/Ev.php | 50 ++-- src/Events/Event.php | 64 ++--- src/Events/EventInterface.php | 70 +++--- src/Events/Revolt.php | 52 ++-- src/Events/Select.php | 105 ++++---- src/Events/Swoole.php | 62 +++-- src/Events/Swow.php | 56 +++-- src/Protocols/Frame.php | 15 +- src/Protocols/Http.php | 67 +++--- src/Protocols/Http/Chunk.php | 5 +- src/Protocols/Http/Request.php | 120 +++++----- src/Protocols/Http/Response.php | 69 +++--- src/Protocols/Http/ServerSentEvents.php | 2 +- src/Protocols/Http/Session.php | 88 ++++--- .../Http/Session/FileSessionHandler.php | 29 +-- .../Session/RedisClusterSessionHandler.php | 7 +- .../Http/Session/RedisSessionHandler.php | 31 +-- .../Http/Session/SessionHandlerInterface.php | 18 +- src/Protocols/ProtocolInterface.php | 10 +- src/Protocols/Text.php | 6 +- src/Protocols/Websocket.php | 49 ++-- src/Protocols/Ws.php | 42 ++-- src/Timer.php | 38 +-- src/Worker.php | 198 ++++++++-------- 29 files changed, 858 insertions(+), 852 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 998f57bfb..cd4040513 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -14,11 +14,10 @@ namespace Workerman\Connection; -use Workerman\Events\EventInterface; -use Workerman\Events\Select; +use Throwable; use Workerman\Timer; use Workerman\Worker; -use \Exception; +use Exception; /** * AsyncTcpConnection. @@ -28,14 +27,14 @@ class AsyncTcpConnection extends TcpConnection /** * Emitted when socket connection is successfully established. * - * @var callable|null + * @var ?callable */ public $onConnect = null; /** * Emitted when websocket handshake completed (Only work when protocol is ws). * - * @var callable|null + * @var ?callable */ public $onWebSocketConnect = null; @@ -44,70 +43,70 @@ class AsyncTcpConnection extends TcpConnection * * @var string */ - public $transport = 'tcp'; + public string $transport = 'tcp'; /** * Socks5 proxy. * * @var string */ - public $proxySocks5 = ''; + public string $proxySocks5 = ''; /** * Http proxy. * * @var string */ - public $proxyHttp = ''; + public string $proxyHttp = ''; /** * Status. * * @var int */ - protected $status = self::STATUS_INITIAL; + protected int $status = self::STATUS_INITIAL; /** * Remote host. * * @var string */ - protected $remoteHost = ''; + protected string $remoteHost = ''; /** * Remote port. * * @var int */ - protected $remotePort = 80; + protected int $remotePort = 80; /** * Connect start time. * * @var float */ - protected $connectStartTime = 0; + protected float $connectStartTime = 0; /** * Remote URI. * * @var string */ - protected $remoteURI = ''; + protected string $remoteURI = ''; /** * Context option. * * @var array */ - protected $contextOption = null; + protected array $contextOption = []; /** * Reconnect timer. * * @var int */ - protected $reconnectTimer = null; + protected int $reconnectTimer = 0; /** @@ -132,7 +131,7 @@ class AsyncTcpConnection extends TcpConnection * @param array $contextOption * @throws Exception */ - public function __construct($remoteAddress, array $contextOption = []) + public function __construct(string $remoteAddress, array $contextOption = []) { $addressInfo = \parse_url($remoteAddress); if (!$addressInfo) { @@ -195,6 +194,7 @@ public function __construct($remoteAddress, array $contextOption = []) * Do connect. * * @return void + * @throws Throwable */ public function connect() { @@ -268,8 +268,9 @@ public function connect() * * @param int $after * @return void + * @throws Throwable */ - public function reconnect($after = 0) + public function reconnect(int $after = 0) { $this->status = self::STATUS_INITIAL; static::$connections[$this->realId] = $this; @@ -290,6 +291,7 @@ public function cancelReconnect() { if ($this->reconnectTimer) { Timer::del($this->reconnectTimer); + $this->reconnectTimer = 0; } } @@ -298,7 +300,7 @@ public function cancelReconnect() * * @return string */ - public function getRemoteHost() + public function getRemoteHost(): string { return $this->remoteHost; } @@ -308,7 +310,7 @@ public function getRemoteHost() * * @return string */ - public function getRemoteURI() + public function getRemoteURI(): string { return $this->remoteURI; } @@ -317,16 +319,17 @@ public function getRemoteURI() * Try to emit onError callback. * * @param int $code - * @param string $msg + * @param mixed $msg * @return void + * @throws Throwable */ - protected function emitError($code, $msg) + protected function emitError(int $code, mixed $msg) { $this->status = self::STATUS_CLOSING; if ($this->onError) { try { ($this->onError)($this, $code, $msg); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -335,8 +338,8 @@ protected function emitError($code, $msg) /** * Check connection is successfully established or faild. * - * @param resource $socket * @return void + * @throws Throwable */ public function checkConnection() { @@ -387,7 +390,7 @@ public function checkConnection() if ($this->onConnect) { try { ($this->onConnect)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -395,7 +398,7 @@ public function checkConnection() if ($this->protocol && \method_exists($this->protocol, 'onConnect')) { try { [$this->protocol, 'onConnect']($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 36162265a..83950043d 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -15,9 +15,8 @@ namespace Workerman\Connection; use Throwable; -use Workerman\Events\EventInterface; use Workerman\Worker; -use \Exception; +use Exception; /** * AsyncUdpConnection. @@ -27,14 +26,14 @@ class AsyncUdpConnection extends UdpConnection /** * Emitted when socket connection is successfully established. * - * @var callable + * @var ?callable */ public $onConnect = null; /** * Emitted when socket connection closed. * - * @var callable + * @var ?callable */ public $onClose = null; @@ -43,14 +42,14 @@ class AsyncUdpConnection extends UdpConnection * * @var bool */ - protected $connected = false; + protected bool $connected = false; /** * Context option. * * @var array */ - protected $contextOption = null; + protected array $contextOption = []; /** * Construct. @@ -58,7 +57,7 @@ class AsyncUdpConnection extends UdpConnection * @param string $remoteAddress * @throws Exception */ - public function __construct($remoteAddress, $contextOption = null) + public function __construct($remoteAddress, $contextOption = []) { // Get the application layer communication protocol and listening address. list($scheme, $address) = \explode(':', $remoteAddress, 2); @@ -82,13 +81,14 @@ public function __construct($remoteAddress, $contextOption = null) * For udp package. * * @param resource $socket - * @return bool + * @return void + * @throws Throwable */ public function baseRead($socket) { $recvBuffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); if (false === $recvBuffer || empty($remoteAddress)) { - return false; + return; } if ($this->onMessage) { @@ -102,17 +102,17 @@ public function baseRead($socket) $this->error($e); } } - return true; } /** * Sends data on the connection. * - * @param string $sendBuffer + * @param mixed $sendBuffer * @param bool $raw * @return void|boolean + * @throws Throwable */ - public function send($sendBuffer, $raw = false) + public function send(mixed $sendBuffer, bool $raw = false) { if (false === $raw && $this->protocol) { $parser = $this->protocol; @@ -127,17 +127,15 @@ public function send($sendBuffer, $raw = false) return \strlen($sendBuffer) === \stream_socket_sendto($this->socket, $sendBuffer, 0); } - /** * Close connection. * - * @param mixed $data + * @param mixed|null $data * @param bool $raw - * - * @return bool + * @return void * @throws Throwable */ - public function close($data = null, $raw = false) + public function close(mixed $data = null, bool $raw = false) { if ($data !== null) { $this->send($data, $raw); @@ -154,13 +152,13 @@ public function close($data = null, $raw = false) } } $this->onConnect = $this->onMessage = $this->onClose = $this->eventLoop = $this->errorHandler = null; - return true; } /** * Connect. * * @return void + * @throws Throwable */ public function connect() { diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 929b56075..148512565 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -14,6 +14,8 @@ namespace Workerman\Connection; +use Closure; +use JetBrains\PhpStorm\Pure; use Throwable; use Workerman\Events\Event; use Workerman\Events\EventInterface; @@ -45,119 +47,140 @@ abstract class ConnectionInterface * * @var array */ - public static $statistics = [ + public static array $statistics = [ 'connection_count' => 0, 'total_request' => 0, 'throw_exception' => 0, 'send_fail' => 0, ]; + /** + * Application layer protocol. + * The format is like this Workerman\\Protocols\\Http. + * + * @var ?class-string + */ + public ?string $protocol = null; + /** * Emitted when data is received. * - * @var callable + * @var ?callable */ public $onMessage = null; /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callable + * @var ?callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callable + * @var ?callable */ public $onError = null; /** - * @var EventInterface + * @var ?EventInterface */ - public $eventLoop; + public ?EventInterface $eventLoop; /** - * @var \Closure + * @var ?callable */ - public $errorHandler; + public $errorHandler = null; /** * Sends data on the connection. * * @param mixed $sendBuffer + * @param bool $raw * @return void|boolean */ - abstract public function send($sendBuffer); + abstract public function send(mixed $sendBuffer, bool $raw = false); /** * Get remote IP. * * @return string */ - abstract public function getRemoteIp(); + abstract public function getRemoteIp(): string; /** * Get remote port. * * @return int */ - abstract public function getRemotePort(); + abstract public function getRemotePort(): int; /** * Get remote address. * * @return string */ - abstract public function getRemoteAddress(); + abstract public function getRemoteAddress(): string; /** * Get local IP. * * @return string */ - abstract public function getLocalIp(); + abstract public function getLocalIp(): string; /** * Get local port. * * @return int */ - abstract public function getLocalPort(); + abstract public function getLocalPort(): int; /** * Get local address. * * @return string */ - abstract public function getLocalAddress(); + abstract public function getLocalAddress(): string; /** - * Is ipv4. + * Close connection. * - * @return bool + * @param mixed|null $data + * @return void */ - abstract public function isIPv4(); + abstract public function close(mixed $data = null, bool $raw = false); /** - * Is ipv6. + * Is ipv4. * - * @return bool + * return bool. */ - abstract public function isIPv6(); + public function isIpV4(): bool + { + if ($this->transport === 'unix') { + return false; + } + return !str_contains($this->getRemoteIp(), ':'); + } /** - * Close connection. + * Is ipv6. * - * @param string|null $data - * @return void + * return bool. */ - abstract public function close($data = null); + public function isIpV6(): bool + { + if ($this->transport === 'unix') { + return false; + } + return str_contains($this->getRemoteIp(), ':'); + } /** * @param Throwable $exception - * @return mixed + * @return void * @throws Throwable */ public function error(Throwable $exception) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 0726d8d3a..24c74ae96 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -14,9 +14,10 @@ namespace Workerman\Connection; +use stdClass; +use Throwable; use Workerman\Events\EventInterface; use Workerman\Protocols\Http\Request; -use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; /** @@ -70,161 +71,153 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable /** * Emitted when socket connection is successfully established. * - * @var callable|null + * @var ?callable */ public $onConnect = null; /** * Emitted when websocket handshake completed (Only work when protocol is ws). * - * @var callable|null + * @var ?callable */ public $onWebSocketConnect = null; /** * Emitted when data is received. * - * @var callable + * @var ?callable */ public $onMessage = null; /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callable + * @var ?callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callable + * @var ?callable */ public $onError = null; /** * Emitted when the send buffer becomes full. * - * @var callable + * @var ?callable */ public $onBufferFull = null; /** - * Emitted when the send buffer becomes empty. + * Emitted when send buffer becomes empty. * - * @var callable + * @var ?callable */ public $onBufferDrain = null; - /** - * Application layer protocol. - * The format is like this Workerman\\Protocols\\Http. - * - * @var ProtocolInterface - */ - public $protocol = null; - /** * Transport (tcp/udp/unix/ssl). * * @var string */ - public $transport = 'tcp'; + public string $transport = 'tcp'; /** * Which worker belong to. * - * @var Worker + * @var ?Worker */ - public $worker = null; + public ?Worker $worker = null; /** * Bytes read. * * @var int */ - public $bytesRead = 0; + public int $bytesRead = 0; /** * Bytes written. * * @var int */ - public $bytesWritten = 0; + public int $bytesWritten = 0; /** * Connection->id. * * @var int */ - public $id = 0; + public int $id = 0; /** * A copy of $worker->id which used to clean up the connection in worker->connections * * @var int */ - protected $realId = 0; + protected int $realId = 0; /** * Sets the maximum send buffer size for the current connection. - * OnBufferFull callback will be emited When the send buffer is full. + * OnBufferFull callback will be emited When send buffer is full. * * @var int */ - public $maxSendBufferSize = 1048576; + public int $maxSendBufferSize = 1048576; /** * Context. * - * @var object + * @var ?stdClass */ - public $context; + public ?stdClass $context = null; /** * @var array */ - public $headers = []; + public array $headers = []; /** - * @var object + * @var ?Request */ - public $request; + public ?Request $request = null; /** * Default send buffer size. * * @var int */ - public static $defaultMaxSendBufferSize = 1048576; + public static int $defaultMaxSendBufferSize = 1048576; /** * Sets the maximum acceptable packet size for the current connection. * * @var int */ - public $maxPackageSize = 1048576; + public int $maxPackageSize = 1048576; /** * Default maximum acceptable packet size. * * @var int */ - public static $defaultMaxPackageSize = 10485760; + public static int $defaultMaxPackageSize = 10485760; /** * Id recorder. * * @var int */ - protected static $idRecorder = 1; + protected static int $idRecorder = 1; /** * Cache. * * @var bool. */ - protected static $enableCache = true; + protected static bool $enableCache = true; /** * Socket @@ -238,63 +231,63 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * * @var string */ - protected $sendBuffer = ''; + protected string $sendBuffer = ''; /** * Receive buffer. * * @var string */ - protected $recvBuffer = ''; + protected string $recvBuffer = ''; /** * Current package length. * * @var int */ - protected $currentPackageLength = 0; + protected int $currentPackageLength = 0; /** * Connection status. * * @var int */ - protected $status = self::STATUS_ESTABLISHED; + protected int $status = self::STATUS_ESTABLISHED; /** * Remote address. * * @var string */ - protected $remoteAddress = ''; + protected string $remoteAddress = ''; /** * Is paused. * * @var bool */ - protected $isPaused = false; + protected bool $isPaused = false; /** * SSL handshake completed or not. * * @var bool */ - protected $sslHandshakeCompleted = false; + protected bool $sslHandshakeCompleted = false; /** * All connection instances. * * @var array */ - public static $connections = []; + public static array $connections = []; /** * Status to string. * * @var array */ - public static $statusToString = [ + const STATUS_TO_STRING = [ self::STATUS_INITIAL => 'INITIAL', self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', @@ -305,10 +298,11 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable /** * Construct. * + * @param EventInterface $eventLoop * @param resource $socket * @param string $remoteAddress */ - public function __construct($eventLoop, $socket, $remoteAddress = '') + public function __construct(EventInterface $eventLoop, $socket, string $remoteAddress = '') { ++self::$statistics['connection_count']; $this->id = $this->realId = self::$idRecorder++; @@ -327,7 +321,7 @@ public function __construct($eventLoop, $socket, $remoteAddress = '') $this->maxPackageSize = self::$defaultMaxPackageSize; $this->remoteAddress = $remoteAddress; static::$connections[$this->id] = $this; - $this->context = new \stdClass; + $this->context = new stdClass; } /** @@ -337,12 +331,12 @@ public function __construct($eventLoop, $socket, $remoteAddress = '') * * @return int|string */ - public function getStatus($rawOutput = true) + public function getStatus(bool $rawOutput = true): int|string { if ($rawOutput) { return $this->status; } - return self::$statusToString[$this->status]; + return self::STATUS_TO_STRING[$this->status]; } /** @@ -351,8 +345,9 @@ public function getStatus($rawOutput = true) * @param mixed $sendBuffer * @param bool $raw * @return bool|void + * @throws Throwable */ - public function send($sendBuffer, $raw = false) + public function send(mixed $sendBuffer, bool $raw = false) { if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return false; @@ -389,7 +384,7 @@ public function send($sendBuffer, $raw = false) $len = 0; try { $len = @\fwrite($this->socket, $sendBuffer); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::log($e); } // send successful. @@ -408,7 +403,7 @@ public function send($sendBuffer, $raw = false) if ($this->onError) { try { ($this->onError)($this, static::SEND_FAIL, 'client closed'); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -418,7 +413,7 @@ public function send($sendBuffer, $raw = false) $this->sendBuffer = $sendBuffer; } $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); - // Check if the send buffer will be full. + // Check if send buffer will be full. $this->checkBufferWillFull(); return; } @@ -429,7 +424,7 @@ public function send($sendBuffer, $raw = false) } $this->sendBuffer .= $sendBuffer; - // Check if the send buffer is full. + // Check if send buffer is full. $this->checkBufferWillFull(); } @@ -438,7 +433,7 @@ public function send($sendBuffer, $raw = false) * * @return string */ - public function getRemoteIp() + public function getRemoteIp(): string { $pos = \strrpos($this->remoteAddress, ':'); if ($pos) { @@ -452,7 +447,7 @@ public function getRemoteIp() * * @return int */ - public function getRemotePort() + public function getRemotePort(): int { if ($this->remoteAddress) { return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); @@ -465,7 +460,7 @@ public function getRemotePort() * * @return string */ - public function getRemoteAddress() + public function getRemoteAddress(): string { return $this->remoteAddress; } @@ -475,7 +470,7 @@ public function getRemoteAddress() * * @return string */ - public function getLocalIp() + public function getLocalIp(): string { $address = $this->getLocalAddress(); $pos = \strrpos($address, ':'); @@ -490,7 +485,7 @@ public function getLocalIp() * * @return int */ - public function getLocalPort() + public function getLocalPort(): int { $address = $this->getLocalAddress(); $pos = \strrpos($address, ':'); @@ -505,7 +500,7 @@ public function getLocalPort() * * @return string */ - public function getLocalAddress() + public function getLocalAddress(): string { if (!\is_resource($this->socket)) { return ''; @@ -518,47 +513,21 @@ public function getLocalAddress() * * @return integer */ - public function getSendBufferQueueSize() + public function getSendBufferQueueSize(): int { return \strlen($this->sendBuffer); } /** - * Get recv buffer queue size. + * Get receive buffer queue size. * * @return integer */ - public function getRecvBufferQueueSize() + public function getRecvBufferQueueSize(): int { return \strlen($this->recvBuffer); } - /** - * Is ipv4. - * - * return bool. - */ - public function isIpV4() - { - if ($this->transport === 'unix') { - return false; - } - return \strpos($this->getRemoteIp(), ':') === false; - } - - /** - * Is ipv6. - * - * return bool. - */ - public function isIpV6() - { - if ($this->transport === 'unix') { - return false; - } - return \strpos($this->getRemoteIp(), ':') !== false; - } - /** * Pauses the reading of data. That is onMessage will not be emitted. Useful to throttle back an upload. * @@ -574,6 +543,7 @@ public function pauseRecv() * Resumes reading after a call to pauseRecv. * * @return void + * @throws Throwable */ public function resumeRecv() { @@ -591,8 +561,9 @@ public function resumeRecv() * @param resource $socket * @param bool $checkEof * @return void + * @throws Throwable */ - public function baseRead($socket, $checkEof = true) + public function baseRead($socket, bool $checkEof = true) { static $requests = []; // SSL handshake. @@ -610,7 +581,7 @@ public function baseRead($socket, $checkEof = true) $buffer = ''; try { $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (\Throwable $e) { + } catch (Throwable $e) { } // Check connection closed. @@ -634,7 +605,7 @@ public function baseRead($socket, $checkEof = true) } try { ($this->onMessage)($this, $request); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } return; @@ -658,7 +629,7 @@ public function baseRead($socket, $checkEof = true) // Get current package length. try { $this->currentPackageLength = $this->protocol::input($this->recvBuffer, $this); - } catch (\Throwable $e) { + } catch (Throwable $e) { } // The packet length is unknown. if ($this->currentPackageLength === 0) { @@ -685,7 +656,7 @@ public function baseRead($socket, $checkEof = true) } else { // Get a full package from the buffer. $oneRequestBuffer = \substr($this->recvBuffer, 0, $this->currentPackageLength); - // Remove the current package from the receive buffer. + // Remove the current package from receive buffer. $this->recvBuffer = \substr($this->recvBuffer, $this->currentPackageLength); } // Reset the current packet length to 0. @@ -700,7 +671,7 @@ public function baseRead($socket, $checkEof = true) } } ($this->onMessage)($this, $request); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -715,7 +686,7 @@ public function baseRead($socket, $checkEof = true) ++self::$statistics['total_request']; try { ($this->onMessage)($this, $this->recvBuffer); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } // Clean receive buffer. @@ -725,7 +696,8 @@ public function baseRead($socket, $checkEof = true) /** * Base write handler. * - * @return void|bool + * @return void + * @throws Throwable */ public function baseWrite() { @@ -736,26 +708,26 @@ public function baseWrite() } else { $len = @\fwrite($this->socket, $this->sendBuffer); } - } catch (\Throwable $e) {} + } catch (Throwable $e) {} if ($len === \strlen($this->sendBuffer)) { $this->bytesWritten += $len; $this->eventLoop->offWritable($this->socket); $this->sendBuffer = ''; - // Try to emit onBufferDrain callback when the send buffer becomes empty. + // Try to emit onBufferDrain callback when send buffer becomes empty. if ($this->onBufferDrain) { try { ($this->onBufferDrain)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } if ($this->status === self::STATUS_CLOSING) { if ($this->context->streamSending) { - return true; + return; } $this->destroy(); } - return true; + return; } if ($len > 0) { $this->bytesWritten += $len; @@ -770,9 +742,10 @@ public function baseWrite() * SSL handshake. * * @param resource $socket - * @return bool + * @return bool|int + * @throws Throwable */ - public function doSslHandshake($socket) + public function doSslHandshake($socket): bool|int { if (\feof($socket)) { $this->destroy(); @@ -812,13 +785,6 @@ public function doSslHandshake($socket) // There isn't enough data and should try again. return 0; } - if (isset($this->onSslHandshake)) { - try { - ($this->onSslHandshake)($this); - } catch (\Throwable $e) { - $this->error($e); - } - } return true; } @@ -851,7 +817,7 @@ public function pipe(self $dest) * @param int $length * @return void */ - public function consumeRecvBuffer($length) + public function consumeRecvBuffer(int $length) { $this->recvBuffer = \substr($this->recvBuffer, $length); } @@ -859,11 +825,12 @@ public function consumeRecvBuffer($length) /** * Close connection. * - * @param mixed $data + * @param mixed|null $data * @param bool $raw * @return void + * @throws Throwable */ - public function close($data = null, $raw = false) + public function close(mixed $data = null, bool $raw = false) { if ($this->status === self::STATUS_CONNECTING) { $this->destroy(); @@ -898,9 +865,10 @@ public function getSocket() } /** - * Check whether the send buffer will be full. + * Check whether send buffer will be full. * * @return void + * @throws Throwable */ protected function checkBufferWillFull() { @@ -908,7 +876,7 @@ protected function checkBufferWillFull() if ($this->onBufferFull) { try { ($this->onBufferFull)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -919,15 +887,16 @@ protected function checkBufferWillFull() * Whether send buffer is full. * * @return bool + * @throws Throwable */ - protected function bufferIsFull() + protected function bufferIsFull(): bool { // Buffer has been marked as full but still has data to send then the packet is discarded. if ($this->maxSendBufferSize <= \strlen($this->sendBuffer)) { if ($this->onError) { try { ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -941,7 +910,7 @@ protected function bufferIsFull() * * @return bool */ - public function bufferIsEmpty() + public function bufferIsEmpty(): bool { return empty($this->sendBuffer); } @@ -950,7 +919,7 @@ public function bufferIsEmpty() * Destroy connection. * * @return void - * @throws \Throwable + * @throws Throwable */ public function destroy() { @@ -965,7 +934,7 @@ public function destroy() // Close socket. try { @\fclose($this->socket); - } catch (\Throwable $e) { + } catch (Throwable $e) { } $this->status = self::STATUS_CLOSED; @@ -973,7 +942,7 @@ public function destroy() if ($this->onClose) { try { ($this->onClose)($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -981,7 +950,7 @@ public function destroy() if ($this->protocol && \method_exists($this->protocol, 'onClose')) { try { ([$this->protocol, 'onClose'])($this); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } } @@ -1004,18 +973,17 @@ public function destroy() * * @param mixed $value */ - public static function enableCache($value) + public static function enableCache(bool $value = true) { - static::$enableCache = (bool)$value; + static::$enableCache = $value; } /** * Get the json_encode information. * - * @return mixed + * @return array */ - #[\ReturnTypeWillChange] - public function jsonSerialize() + public function jsonSerialize(): array { return [ 'id' => $this->id, diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 62da45a54..02cec6c57 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -14,41 +14,31 @@ namespace Workerman\Connection; -use Workerman\Protocols\ProtocolInterface; - /** * UdpConnection. */ class UdpConnection extends ConnectionInterface implements \JsonSerializable { - /** - * Application layer protocol. - * The format is like this Workerman\\Protocols\\Http. - * - * @var ProtocolInterface - */ - public $protocol = null; - /** * Transport layer protocol. * * @var string */ - public $transport = 'udp'; + public string $transport = 'udp'; /** * Udp socket. * * @var resource */ - protected $socket = null; + protected $socket; /** * Remote address. * * @var string */ - protected $remoteAddress = ''; + protected string $remoteAddress = ''; /** * Construct. @@ -56,7 +46,7 @@ class UdpConnection extends ConnectionInterface implements \JsonSerializable * @param resource $socket * @param string $remoteAddress */ - public function __construct($socket, $remoteAddress) + public function __construct($socket, string $remoteAddress) { $this->socket = $socket; $this->remoteAddress = $remoteAddress; @@ -65,11 +55,11 @@ public function __construct($socket, $remoteAddress) /** * Sends data on the connection. * - * @param string $sendBuffer + * @param mixed $sendBuffer * @param bool $raw * @return void|boolean */ - public function send($sendBuffer, $raw = false) + public function send(mixed $sendBuffer, bool $raw = false) { if (false === $raw && $this->protocol) { $parser = $this->protocol; @@ -86,7 +76,7 @@ public function send($sendBuffer, $raw = false) * * @return string */ - public function getRemoteIp() + public function getRemoteIp(): string { $pos = \strrpos($this->remoteAddress, ':'); if ($pos) { @@ -100,7 +90,7 @@ public function getRemoteIp() * * @return int */ - public function getRemotePort() + public function getRemotePort(): int { if ($this->remoteAddress) { return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); @@ -113,7 +103,7 @@ public function getRemotePort() * * @return string */ - public function getRemoteAddress() + public function getRemoteAddress(): string { return $this->remoteAddress; } @@ -123,7 +113,7 @@ public function getRemoteAddress() * * @return string */ - public function getLocalIp() + public function getLocalIp(): string { $address = $this->getLocalAddress(); $pos = \strrpos($address, ':'); @@ -138,7 +128,7 @@ public function getLocalIp() * * @return int */ - public function getLocalPort() + public function getLocalPort(): int { $address = $this->getLocalAddress(); $pos = \strrpos($address, ':'); @@ -153,51 +143,24 @@ public function getLocalPort() * * @return string */ - public function getLocalAddress() + public function getLocalAddress(): string { return (string)@\stream_socket_get_name($this->socket, false); } - /** - * Is ipv4. - * - * @return bool. - */ - public function isIpV4() - { - if ($this->transport === 'unix') { - return false; - } - return \strpos($this->getRemoteIp(), ':') === false; - } - - /** - * Is ipv6. - * - * @return bool. - */ - public function isIpV6() - { - if ($this->transport === 'unix') { - return false; - } - return \strpos($this->getRemoteIp(), ':') !== false; - } /** * Close connection. * - * @param mixed $data - * @param bool $raw - * @return bool + * @param mixed|null $data + * @return void */ - public function close($data = null, $raw = false) + public function close(mixed $data = null, bool $raw = false) { if ($data !== null) { $this->send($data, $raw); } $this->eventLoop = $this->errorHandler = null; - return true; } /** @@ -211,11 +174,11 @@ public function getSocket() } /** - * Get the json_encode informattion. + * Get the json_encode information. * * @return array */ - public function jsonSerialize() + public function jsonSerialize(): array { return [ 'transport' => $this->transport, diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 884c8131d..ea1f1b604 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -26,50 +26,50 @@ class Ev implements EventInterface * * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for write event. * * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** * Event listeners of signal. * * @var array */ - protected $eventSignal = []; + protected array $eventSignal = []; /** * All timer event listeners. * * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** - * @var Closure || null + * @var ?callable */ - protected $errorHandler; + protected $errorHandler = null; /** * Timer id. * * @var int */ - protected static $timerId = 1; + protected static int $timerId = 1; /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { $timerId = self::$timerId; $event = new \EvTimer($delay, 0, function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); - $func(...(array)$args); + $func(...$args); }); $this->eventTimer[self::$timerId] = $event; return self::$timerId++; @@ -78,7 +78,7 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { $this->eventTimer[$timerId]->stop(); @@ -91,7 +91,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -99,10 +99,10 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { $event = new \EvTimer($interval, $interval, function () use ($func, $args) { - $func(...(array)$args); + $func(...$args); }); $this->eventTimer[self::$timerId] = $event; return self::$timerId++; @@ -111,7 +111,7 @@ public function repeat(float $interval, $func, $args = []) /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $fdKey = (int)$stream; $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) { @@ -123,19 +123,21 @@ public function onReadable($stream, $func) /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { $this->readEvents[$fdKey]->stop(); unset($this->readEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $fdKey = (int)$stream; $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { @@ -147,19 +149,21 @@ public function onWritable($stream, $func) /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { $fdKey = (int)$stream; if (isset($this->writeEvents[$fdKey])) { $this->writeEvents[$fdKey]->stop(); unset($this->writeEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { $event = new \EvSignal($signal, function () use ($func, $signal) { $func($signal); @@ -170,12 +174,14 @@ public function onSignal($signal, $func) /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { if (isset($this->eventSignal[$signal])) { $this->eventSignal[$signal]->stop(); unset($this->eventSignal[$signal]); + return true; } + return false; } /** @@ -208,7 +214,7 @@ public function stop() /** * {@inheritdoc} */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -216,7 +222,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler) { $this->errorHandler = $errorHandler; } @@ -224,7 +230,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->errorHandler; } diff --git a/src/Events/Event.php b/src/Events/Event.php index 2b2a9ceed..653e5c7ff 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -15,6 +15,7 @@ namespace Workerman\Events; use Throwable; +use EventBase; /** * libevent eventloop @@ -23,51 +24,51 @@ class Event implements EventInterface { /** * Event base. - * @var object + * @var EventBase */ - protected $eventBase = null; + protected $eventBase; /** * All listeners for read event. * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for write event. * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** * Event listeners of signal. * @var array */ - protected $eventSignal = []; + protected array $eventSignal = []; /** * All timer event listeners. * [func, args, event, flag, time_interval] * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** * Timer id. * @var int */ - protected $timerId = 0; + protected int $timerId = 0; /** * Event class name. * @var string */ - protected $eventClassName = ''; + protected string $eventClassName = ''; /** - * @var Closure || null + * @var ?callable */ - protected $errorHandler; + protected $errorHandler = null; /** * Construct. @@ -92,7 +93,7 @@ public function __construct() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; @@ -113,7 +114,7 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { $this->eventTimer[$timerId]->del(); @@ -126,7 +127,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -134,7 +135,7 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; @@ -155,82 +156,85 @@ public function repeat(float $interval, $func, $args = []) /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $className = $this->eventClassName; $fdKey = (int)$stream; $event = new $this->eventClassName($this->eventBase, $stream, $className::READ | $className::PERSIST, $func, $stream); if (!$event || !$event->add()) { - return false; + return; } $this->readEvents[$fdKey] = $event; - return true; } /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { $this->readEvents[$fdKey]->del(); unset($this->readEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $className = $this->eventClassName; $fdKey = (int)$stream; $event = new $this->eventClassName($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func, $stream); if (!$event || !$event->add()) { - return false; + return; } $this->writeEvents[$fdKey] = $event; - return true; } /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { $fdKey = (int)$stream; if (isset($this->writeEvents[$fdKey])) { $this->writeEvents[$fdKey]->del(); unset($this->writeEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { $className = $this->eventClassName; - $fdKey = (int)$signal; + $fdKey = $signal; $event = $className::signal($this->eventBase, $signal, $func); if (!$event || !$event->add()) { - return false; + return; } $this->eventSignal[$fdKey] = $event; - return true; } /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { - $fdKey = (int)$signal; + $fdKey = $signal; if (isset($this->eventSignal[$fdKey])) { $this->eventSignal[$fdKey]->del(); unset($this->eventSignal[$fdKey]); + return true; } + return false; } /** @@ -263,7 +267,7 @@ public function stop() /** * {@inheritdoc} */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -279,7 +283,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->errorHandler; } diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 163fe898f..e546a88f1 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -18,79 +18,79 @@ interface EventInterface /** * Delay the execution of a callback. * @param float $delay - * @param $func - * @param $args - * @return int|bool + * @param callable $func + * @param array $args + * @return int */ - public function delay(float $delay, $func, $args = []); + public function delay(float $delay, callable $func, array $args = []): int; /** * Delete a delay timer. - * @param $timerId + * @param int $timerId * @return bool */ - public function offDelay($timerId); + public function offDelay(int $timerId): bool; /** * Repeatedly execute a callback. * @param float $interval - * @param $func - * @param $args - * @return int|bool + * @param callable $func + * @param array $args + * @return int */ - public function repeat(float $interval, $func, $args = []); + public function repeat(float $interval, callable $func, array $args = []): int; /** * Delete a repeat timer. - * @param $timerId + * @param int $timerId * @return bool */ - public function offRepeat($timerId); + public function offRepeat(int $timerId): bool; /** * Execute a callback when a stream resource becomes readable or is closed for reading. - * @param $stream - * @param $func + * @param resource $stream + * @param callable $func * @return void */ - public function onReadable($stream, $func); + public function onReadable($stream, callable $func); /** * Cancel a callback of stream readable. - * @param $stream - * @return void + * @param resource $stream + * @return bool */ - public function offReadable($stream); + public function offReadable($stream): bool; /** * Execute a callback when a stream resource becomes writable or is closed for writing. - * @param $stream - * @param $func + * @param resource $stream + * @param callable $func * @return void */ - public function onWritable($stream, $func); + public function onWritable($stream, callable $func); /** * Cancel a callback of stream writable. - * @param $stream - * @return void + * @param resource $stream + * @return bool */ - public function offWritable($stream); + public function offWritable($stream): bool; /** * Execute a callback when a signal is received. - * @param $signal - * @param $func + * @param int $signal + * @param callable $func * @return void */ - public function onSignal($signal, $func); + public function onSignal(int $signal, callable $func); /** * Cancel a callback of signal. - * @param $signal - * @return void + * @param int $signal + * @return bool */ - public function offSignal($signal); + public function offSignal(int $signal): bool; /** * Delete all timer. @@ -114,18 +114,18 @@ public function stop(); * Get Timer count. * @return int */ - public function getTimerCount(); + public function getTimerCount(): int; /** * Set error handler - * @param $errorHandler + * @param callable $errorHandler * @return void */ - public function setErrorHandler($errorHandler); + public function setErrorHandler(callable $errorHandler); /** * Get error handler - * @return null|\Closure(\Throwable) + * @return ?callable(Throwable) */ - public function getErrorHandler(); + public function getErrorHandler(): ?callable; } diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 6c7154b83..5c99430f5 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -25,37 +25,37 @@ class Revolt implements EventInterface /** * @var Driver */ - protected $driver = null; + protected Driver $driver; /** * All listeners for read event. * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for write event. * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** * Event listeners of signal. * @var array */ - protected $eventSignal = []; + protected array $eventSignal = []; /** * Event listeners of timer. * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** * Timer id. * @var int */ - protected $timerId = 1; + protected int $timerId = 1; /** * Construct. @@ -68,7 +68,7 @@ public function __construct() /** * {@inheritdoc} */ - public function driver() + public function driver(): Driver { return $this->driver; } @@ -98,9 +98,8 @@ public function stop() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { - $args = (array)$args; $timerId = $this->timerId++; $closure = function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); @@ -114,9 +113,8 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { - $args = (array)$args; $timerId = $this->timerId++; $closure = function () use ($func, $args) { $func(...$args); @@ -129,7 +127,7 @@ public function repeat(float $interval, $func, $args = []) /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { @@ -145,19 +143,21 @@ public function onReadable($stream, $func) /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { $this->driver->cancel($this->readEvents[$fdKey]); unset($this->readEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $fdKey = (int)$stream; if (isset($this->writeEvents[$fdKey])) { @@ -172,21 +172,23 @@ public function onWritable($stream, $func) /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { $fdKey = (int)$stream; if (isset($this->writeEvents[$fdKey])) { $this->driver->cancel($this->writeEvents[$fdKey]); unset($this->writeEvents[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { - $fdKey = (int)$signal; + $fdKey = $signal; if (isset($this->eventSignal[$fdKey])) { $this->driver->cancel($this->eventSignal[$fdKey]); unset($this->eventSignal[$fdKey]); @@ -199,19 +201,21 @@ public function onSignal($signal, $func) /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { - $fdKey = (int)$signal; + $fdKey = $signal; if (isset($this->eventSignal[$fdKey])) { $this->driver->cancel($this->eventSignal[$fdKey]); unset($this->eventSignal[$fdKey]); + return true; } + return false; } /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { $this->driver->cancel($this->eventTimer[$timerId]); @@ -224,7 +228,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -243,7 +247,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -251,7 +255,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler) { $this->driver->setErrorHandler($errorHandler); } @@ -259,7 +263,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->driver->getErrorHandler(); } diff --git a/src/Events/Select.php b/src/Events/Select.php index cfa524cd1..be413b6df 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -14,6 +14,7 @@ namespace Workerman\Events; +use SplPriorityQueue; use Throwable; /** @@ -25,62 +26,62 @@ class Select implements EventInterface * Running. * @var bool */ - protected $running = true; + protected bool $running = true; /** * All listeners for read/write event. * * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for read/write event. * * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** * @var array */ - protected $exceptEvents = []; + protected array $exceptEvents = []; /** * Event listeners of signal. * * @var array */ - protected $signalEvents = []; + protected array $signalEvents = []; /** * Fds waiting for read event. * * @var array */ - protected $readFds = []; + protected array $readFds = []; /** * Fds waiting for write event. * * @var array */ - protected $writeFds = []; + protected array $writeFds = []; /** * Fds waiting for except event. * * @var array */ - protected $exceptFds = []; + protected array $exceptFds = []; /** * Timer scheduler. * {['data':timer_id, 'priority':run_timestamp], ..} * - * @var \SplPriorityQueue + * @var SplPriorityQueue */ - protected $scheduler = null; + protected SplPriorityQueue $scheduler; /** * All timer event listeners. @@ -88,26 +89,26 @@ class Select implements EventInterface * * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** * Timer id. * * @var int */ - protected $timerId = 1; + protected int $timerId = 1; /** * Select timeout. * * @var int */ - protected $selectTimeout = 100000000; + protected int $selectTimeout = 100000000; /** - * @var Closure || null + * @var ?callable */ - protected $errorHandler; + protected $errorHandler = null; /** * Construct. @@ -115,19 +116,19 @@ class Select implements EventInterface public function __construct() { // Init SplPriorityQueue. - $this->scheduler = new \SplPriorityQueue(); - $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new SplPriorityQueue(); + $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); } /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { $timerId = $this->timerId++; $runTime = \microtime(true) + $delay; $this->scheduler->insert($timerId, -$runTime); - $this->eventTimer[$timerId] = [$func, (array)$args]; + $this->eventTimer[$timerId] = [$func, $args]; $selectTimeout = ($runTime - \microtime(true)) * 1000000; $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; if ($this->selectTimeout > $selectTimeout) { @@ -139,12 +140,12 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function repeat(float $delay, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { $timerId = $this->timerId++; - $runTime = \microtime(true) + $delay; + $runTime = \microtime(true) + $interval; $this->scheduler->insert($timerId, -$runTime); - $this->eventTimer[$timerId] = [$func, (array)$args, $delay]; + $this->eventTimer[$timerId] = [$func, $args, $interval]; $selectTimeout = ($runTime - \microtime(true)) * 1000000; $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; if ($this->selectTimeout > $selectTimeout) { @@ -156,7 +157,7 @@ public function repeat(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { unset($this->eventTimer[$timerId]); @@ -168,7 +169,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -176,7 +177,7 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $count = \count($this->readFds); if ($count >= 1024) { @@ -192,16 +193,20 @@ public function onReadable($stream, $func) /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { $fdKey = (int)$stream; - unset($this->readEvents[$fdKey], $this->readFds[$fdKey]); + if (isset($this->readEvents[$fdKey])) { + unset($this->readEvents[$fdKey], $this->readFds[$fdKey]); + return true; + } + return false; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $count = \count($this->writeFds); if ($count >= 1024) { @@ -217,10 +222,14 @@ public function onWritable($stream, $func) /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { $fdKey = (int)$stream; - unset($this->writeEvents[$fdKey], $this->writeFds[$fdKey]); + if (isset($this->writeEvents[$fdKey])) { + unset($this->writeEvents[$fdKey], $this->writeFds[$fdKey]); + return true; + } + return false; } /** @@ -236,19 +245,23 @@ public function onExcept($stream, $func) /** * {@inheritdoc} */ - public function offExcept($stream) + public function offExcept($stream): bool { $fdKey = (int)$stream; - unset($this->exceptEvents[$fdKey], $this->exceptFds[$fdKey]); + if (isset($this->exceptEvents[$fdKey])) { + unset($this->exceptEvents[$fdKey], $this->exceptFds[$fdKey]); + return true; + } + return false; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { if (\DIRECTORY_SEPARATOR !== '/') { - return null; + return; } $this->signalEvents[$signal] = $func; \pcntl_signal($signal, [$this, 'signalHandler']); @@ -257,10 +270,17 @@ public function onSignal($signal, $func) /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { - unset($this->signalEvents[$signal]); + if (\DIRECTORY_SEPARATOR !== '/') { + return false; + } \pcntl_signal($signal, SIG_IGN); + if (isset($this->signalEvents[$signal])) { + unset($this->signalEvents[$signal]); + return true; + } + return false; } /** @@ -268,7 +288,7 @@ public function offSignal($signal) * * @param int $signal */ - public function signalHandler($signal) + public function signalHandler(int $signal) { $this->signalEvents[$signal]($signal); } @@ -277,6 +297,7 @@ public function signalHandler($signal) * Tick for timer. * * @return void + * @throws Throwable */ protected function tick() { @@ -330,8 +351,8 @@ protected function tick() */ public function deleteAllTimer() { - $this->scheduler = new \SplPriorityQueue(); - $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new SplPriorityQueue(); + $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); $this->eventTimer = []; } @@ -403,7 +424,7 @@ public function stop() /** * {@inheritdoc} */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -411,7 +432,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler) { $this->errorHandler = $errorHandler; } @@ -419,7 +440,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->errorHandler; } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ad95b079b..fff765386 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -24,29 +24,24 @@ class Swoole implements EventInterface * All listeners for read timer * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** * All listeners for read event. * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for write event. * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** - * @var int + * @var ?callable */ - protected $mapId = 0; - - /** - * @var Closure || null - */ - protected $errorHandler; + protected $errorHandler = null; /** * Construct @@ -60,14 +55,14 @@ public function __construct() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { $t = (int)($delay * 1000); - $t = $t < 1 ? 1 : $t; + $t = max($t, 1); $timerId = Timer::after($t, function () use ($func, $args, &$timerId) { unset($this->eventTimer[$timerId]); try { - $func(...(array)$args); + $func(...$args); } catch (Throwable $e) { $this->error($e); } @@ -79,7 +74,7 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { $res = Timer::clear($timerId); @@ -92,7 +87,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -100,16 +95,13 @@ public function offRepeat($timerId) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { - if ($this->mapId > \PHP_INT_MAX) { - $this->mapId = 0; - } $t = (int)($interval * 1000); - $t = $t < 1 ? 1 : $t; + $t = max($t, 1); $timerId = Timer::tick($t, function () use ($func, $args) { try { - $func(...(array)$args); + $func(...$args); } catch (Throwable $e) { $this->error($e); } @@ -121,7 +113,7 @@ public function repeat(float $interval, $func, $args = []) /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { @@ -139,24 +131,25 @@ public function onReadable($stream, $func) /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { $fd = (int)$stream; if (!isset($this->readEvents[$fd])) { - return; + return false; } unset($this->readEvents[$fd]); if (!isset($this->writeEvents[$fd])) { Event::del($stream); - return; + return true; } Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); + return true; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { @@ -174,24 +167,25 @@ public function onWritable($stream, $func) /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { $fd = (int)$stream; if (!isset($this->writeEvents[$fd])) { - return; + return false; } unset($this->writeEvents[$fd]); if (!isset($this->readEvents[$fd])) { Event::del($stream); - return; + return true; } Event::set($stream, null, null, \SWOOLE_EVENT_READ); + return true; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { return Process::signal($signal, $func); } @@ -199,7 +193,7 @@ public function onSignal($signal, $func) /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { return Process::signal($signal, function () {}); } @@ -238,7 +232,7 @@ public function stop() * * @return integer */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -246,7 +240,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler) { $this->errorHandler = $errorHandler; } @@ -254,7 +248,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->errorHandler; } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index a0842c1f2..f2682355c 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -7,7 +7,6 @@ use Swow\Signal; use Swow\SignalException; use Throwable; -use function getmypid; use function max; use function msleep; use function stream_poll_one; @@ -23,37 +22,37 @@ class Swow implements EventInterface * All listeners for read timer * @var array */ - protected $eventTimer = []; + protected array $eventTimer = []; /** * All listeners for read event. * @var array */ - protected $readEvents = []; + protected array $readEvents = []; /** * All listeners for write event. * @var array */ - protected $writeEvents = []; + protected array $writeEvents = []; /** * All listeners for signal. * @var array */ - protected $signalListener = []; + protected array $signalListener = []; /** - * @var Closure || null + * @var ?callable */ - protected $errorHandler; + protected $errorHandler = null; /** * Get timer count. * * @return integer */ - public function getTimerCount() + public function getTimerCount(): int { return \count($this->eventTimer); } @@ -61,7 +60,7 @@ public function getTimerCount() /** * {@inheritdoc} */ - public function delay(float $delay, $func, $args = []) + public function delay(float $delay, callable $func, array $args = []): int { $t = (int) ($delay * 1000); $t = max($t, 1); @@ -83,7 +82,7 @@ public function delay(float $delay, $func, $args = []) /** * {@inheritdoc} */ - public function repeat(float $interval, $func, $args = []) + public function repeat(float $interval, callable $func, array $args = []): int { $t = (int) ($interval * 1000); $t = max($t, 1); @@ -106,7 +105,7 @@ public function repeat(float $interval, $func, $args = []) /** * {@inheritdoc} */ - public function offDelay($timerId) + public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { try { @@ -122,7 +121,7 @@ public function offDelay($timerId) /** * {@inheritdoc} */ - public function offRepeat($timerId) + public function offRepeat(int $timerId): bool { return $this->offDelay($timerId); } @@ -140,7 +139,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function onReadable($stream, $func) + public function onReadable($stream, callable $func) { $fd = (int) $stream; if (isset($this->readEvents[$fd])) { @@ -170,22 +169,26 @@ public function onReadable($stream, $func) $this->offReadable($stream); } }); - return true; } /** * {@inheritdoc} */ - public function offReadable($stream) + public function offReadable($stream): bool { // 在当前协程执行 $coroutine->kill() 会导致不可预知问题,所以没有使用$coroutine->kill() - unset($this->readEvents[(int) $stream]); + $fd = (int) $stream; + if (isset($this->readEvents[$fd])) { + unset($this->readEvents[$fd]); + return true; + } + return false; } /** * {@inheritdoc} */ - public function onWritable($stream, $func) + public function onWritable($stream, callable $func) { $fd = (int) $stream; if (isset($this->writeEvents[$fd])) { @@ -211,21 +214,25 @@ public function onWritable($stream, $func) $this->offWritable($stream); } }); - return true; } /** * {@inheritdoc} */ - public function offWritable($stream) + public function offWritable($stream): bool { - unset($this->writeEvents[(int) $stream]); + $fd = (int) $stream; + if (isset($this->writeEvents[$fd])) { + unset($this->writeEvents[$fd]); + return true; + } + return false; } /** * {@inheritdoc} */ - public function onSignal($signal, $func) + public function onSignal(int $signal, callable $func) { Coroutine::run(function () use ($signal, $func): void { $this->signalListener[$signal] = Coroutine::getCurrent(); @@ -240,13 +247,12 @@ public function onSignal($signal, $func) } catch (SignalException) {} } }); - return true; } /** * {@inheritdoc} */ - public function offSignal($signal) + public function offSignal(int $signal): bool { if (!isset($this->signalListener[$signal])) { return false; @@ -276,7 +282,7 @@ public function stop() /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler) { $this->errorHandler = $errorHandler; } @@ -284,7 +290,7 @@ public function setErrorHandler($errorHandler) /** * {@inheritdoc} */ - public function getErrorHandler() + public function getErrorHandler(): ?callable { return $this->errorHandler; } diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index ba77b0956..ff2bb5af4 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -14,8 +14,6 @@ namespace Workerman\Protocols; -use Workerman\Connection\TcpConnection; - /** * Frame Protocol. */ @@ -25,10 +23,9 @@ class Frame * Check the integrity of the package. * * @param string $buffer - * @param TcpConnection $connection * @return int */ - public static function input($buffer, TcpConnection $connection) + public static function input(string $buffer): int { if (\strlen($buffer) < 4) { return 0; @@ -43,7 +40,7 @@ public static function input($buffer, TcpConnection $connection) * @param string $buffer * @return string */ - public static function decode($buffer) + public static function decode(string $buffer): string { return \substr($buffer, 4); } @@ -51,12 +48,12 @@ public static function decode($buffer) /** * Encode. * - * @param string $buffer + * @param string $data * @return string */ - public static function encode($buffer) + public static function encode(string $data): string { - $totalLength = 4 + \strlen($buffer); - return \pack('N', $totalLength) . $buffer; + $totalLength = 4 + \strlen($data); + return \pack('N', $totalLength) . $data; } } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 0a358a481..6017b6a45 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; +use Throwable; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; @@ -29,21 +30,21 @@ class Http * * @var string */ - protected static $requestClass = Request::class; + protected static string $requestClass = Request::class; /** * Upload tmp dir. * * @var string */ - protected static $uploadTmpDir = ''; + protected static string $uploadTmpDir = ''; /** * Cache. * * @var bool. */ - protected static $enableCache = true; + protected static bool $enableCache = true; /** * Get or set the request class name. @@ -51,7 +52,7 @@ class Http * @param string|null $className * @return string */ - public static function requestClass($className = null) + public static function requestClass(string $className = null): string { if ($className) { static::$requestClass = $className; @@ -62,30 +63,31 @@ public static function requestClass($className = null) /** * Enable or disable Cache. * - * @param mixed $value + * @param bool $value */ - public static function enableCache($value) + public static function enableCache(bool $value) { - static::$enableCache = (bool)$value; + static::$enableCache = $value; } /** * Check the integrity of the package. * - * @param string $recvBuffer + * @param string $buffer * @param TcpConnection $connection * @return int + * @throws Throwable */ - public static function input(string $recvBuffer, TcpConnection $connection) + public static function input(string $buffer, TcpConnection $connection): int { static $input = []; - if (!isset($recvBuffer[512]) && isset($input[$recvBuffer])) { - return $input[$recvBuffer]; + if (!isset($buffer[512]) && isset($input[$buffer])) { + return $input[$buffer]; } - $crlfPos = \strpos($recvBuffer, "\r\n\r\n"); + $crlfPos = \strpos($buffer, "\r\n\r\n"); if (false === $crlfPos) { // Judge whether the package length exceeds the limit. - if (\strlen($recvBuffer) >= 16384) { + if (\strlen($buffer) >= 16384) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } @@ -93,14 +95,14 @@ public static function input(string $recvBuffer, TcpConnection $connection) } $length = $crlfPos + 4; - $firstLine = \explode(" ", \strstr($recvBuffer, "\r\n", true), 3); + $firstLine = \explode(" ", \strstr($buffer, "\r\n", true), 3); if (!\in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } - $header = \substr($recvBuffer, 0, $crlfPos); + $header = \substr($buffer, 0, $crlfPos); $hostHeaderPosition = \strpos($header, "\r\nHost: "); if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { @@ -129,8 +131,8 @@ public static function input(string $recvBuffer, TcpConnection $connection) } } - if (!isset($recvBuffer[512])) { - $input[$recvBuffer] = $length; + if (!isset($buffer[512])) { + $input[$buffer] = $length; if (\count($input) > 512) { unset($input[key($input)]); } @@ -142,26 +144,26 @@ public static function input(string $recvBuffer, TcpConnection $connection) /** * Http decode. * - * @param string $recvBuffer + * @param string $buffer * @param TcpConnection $connection - * @return \Workerman\Protocols\Http\Request + * @return Request */ - public static function decode($recvBuffer, TcpConnection $connection) + public static function decode(string $buffer, TcpConnection $connection): Request { static $requests = []; - $cacheable = static::$enableCache && !isset($recvBuffer[512]); - if (true === $cacheable && isset($requests[$recvBuffer])) { - $request = clone $requests[$recvBuffer]; + $cacheable = static::$enableCache && !isset($buffer[512]); + if (true === $cacheable && isset($requests[$buffer])) { + $request = clone $requests[$buffer]; $request->connection = $connection; $connection->request = $request; $request->properties = []; return $request; } - $request = new static::$requestClass($recvBuffer); + $request = new static::$requestClass($buffer); $request->connection = $connection; $connection->request = $request; if (true === $cacheable) { - $requests[$recvBuffer] = $request; + $requests[$buffer] = $request; if (\count($requests) > 512) { unset($requests[\key($requests)]); } @@ -175,13 +177,13 @@ public static function decode($recvBuffer, TcpConnection $connection) * @param string|Response $response * @param TcpConnection $connection * @return string + * @throws Throwable */ - public static function encode($response, TcpConnection $connection) + public static function encode(mixed $response, TcpConnection $connection): string { if (isset($connection->request)) { - $connection->request->session = null; - $connection->request->connection = null; - $connection->request = null; + $request = $connection->request; + $request->session = $request->connection = $connection->request = null; } if (!\is_object($response)) { $extHeader = ''; @@ -246,7 +248,7 @@ public static function encode($response, TcpConnection $connection) * @param int $offset * @param int $length */ - protected static function sendStream(TcpConnection $connection, $handler, $offset = 0, $length = 0) + protected static function sendStream(TcpConnection $connection, $handler, int $offset = 0, int $length = 0) { $connection->context->bufferFull = false; $connection->context->streamSending = true; @@ -297,9 +299,10 @@ protected static function sendStream(TcpConnection $connection, $handler, $offse /** * Set or get uploadTmpDir. * - * @return bool|string + * @param string|null $dir + * @return string */ - public static function uploadTmpDir($dir = null) + public static function uploadTmpDir(string|null $dir = null): string { if (null !== $dir) { static::$uploadTmpDir = $dir; diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 44f73607a..72c87af8f 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -26,13 +26,14 @@ class Chunk * * @var string */ - protected $buffer = null; + protected string $buffer; /** * Chunk constructor. + * * @param string $buffer */ - public function __construct($buffer) + public function __construct(string $buffer) { $this->buffer = $buffer; } diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 78f980b15..c621af21d 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http; +use Exception; +use RuntimeException; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; use Workerman\Worker; @@ -27,68 +29,68 @@ class Request /** * Connection. * - * @var TcpConnection + * @var ?TcpConnection */ - public $connection = null; + public ?TcpConnection $connection = null; /** * Session instance. * - * @var Session + * @var ?Session */ - public $session = null; + public ?Session $session = null; /** * @var int */ - public static $maxFileUploads = 1024; + public static int $maxFileUploads = 1024; /** * Properties. * * @var array */ - public $properties = []; + public array $properties = []; /** * Http buffer. * * @var string */ - protected $buffer = null; + protected string $buffer; /** * Request data. * * @var array */ - protected $data = null; + protected array $data = []; /** * Enable cache. * * @var bool */ - protected static $enableCache = true; + protected static bool $enableCache = true; /** * Request constructor. * * @param string $buffer */ - public function __construct($buffer) + public function __construct(string $buffer) { $this->buffer = $buffer; } /** - * $GET. + * Get query. * * @param string|null $name * @param mixed|null $default - * @return mixed|null + * @return string|null|array */ - public function get($name = null, $default = null) + public function get(string $name = null, mixed $default = null): array|string|null { if (!isset($this->data['get'])) { $this->parseGet(); @@ -100,13 +102,13 @@ public function get($name = null, $default = null) } /** - * $POST. + * Get post. * * @param string|null $name * @param mixed|null $default - * @return mixed|null + * @return string|null|array */ - public function post($name = null, $default = null) + public function post(string $name = null, mixed $default = null): string|null|array { if (!isset($this->data['post'])) { $this->parsePost(); @@ -122,9 +124,9 @@ public function post($name = null, $default = null) * * @param string|null $name * @param mixed|null $default - * @return array|string|null + * @return string|null */ - public function header($name = null, $default = null) + public function header(string $name = null, mixed $default = null): ?string { if (!isset($this->data['headers'])) { $this->parseHeaders(); @@ -141,9 +143,9 @@ public function header($name = null, $default = null) * * @param string|null $name * @param mixed|null $default - * @return array|string|null + * @return string|null|array */ - public function cookie($name = null, $default = null) + public function cookie(string $name = null, mixed $default = null): array|string|null { if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; @@ -161,7 +163,7 @@ public function cookie($name = null, $default = null) * @param string|null $name * @return array|null */ - public function file($name = null) + public function file(string $name = null) { if (!isset($this->data['files'])) { $this->parsePost(); @@ -177,7 +179,7 @@ public function file($name = null) * * @return string */ - public function method() + public function method(): string { if (!isset($this->data['method'])) { $this->parseHeadFirstLine(); @@ -190,7 +192,7 @@ public function method() * * @return string */ - public function protocolVersion() + public function protocolVersion(): string { if (!isset($this->data['protocolVersion'])) { $this->parseProtocolVersion(); @@ -202,9 +204,9 @@ public function protocolVersion() * Get host. * * @param bool $withoutPort - * @return string + * @return string|null */ - public function host($withoutPort = false) + public function host(bool $withoutPort = false): ?string { $host = $this->header('host'); if ($host && $withoutPort && $pos = \strpos($host, ':')) { @@ -216,9 +218,9 @@ public function host($withoutPort = false) /** * Get uri. * - * @return mixed + * @return string */ - public function uri() + public function uri(): string { if (!isset($this->data['uri'])) { $this->parseHeadFirstLine(); @@ -229,9 +231,9 @@ public function uri() /** * Get path. * - * @return mixed + * @return string */ - public function path() + public function path(): string { if (!isset($this->data['path'])) { $this->data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH); @@ -242,9 +244,9 @@ public function path() /** * Get query string. * - * @return mixed + * @return string */ - public function queryString() + public function queryString(): string { if (!isset($this->data['query_string'])) { $this->data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY); @@ -255,16 +257,12 @@ public function queryString() /** * Get session. * - * @return bool|Session + * @return Session */ - public function session() + public function session(): Session { if ($this->session === null) { - $sessionId = $this->sessionId(); - if ($sessionId === false) { - return false; - } - $this->session = new Session($sessionId); + $this->session = new Session($this->sessionId()); } return $this->session; } @@ -272,10 +270,11 @@ public function session() /** * Get/Set session id. * - * @param $sessionId + * @param null $sessionId * @return string + * @throws Exception */ - public function sessionId($sessionId = null) + public function sessionId($sessionId = null): string { if ($sessionId) { unset($this->sid); @@ -284,9 +283,8 @@ public function sessionId($sessionId = null) $sessionName = Session::$name; $sid = $sessionId ? '' : $this->cookie($sessionName); if ($sid === '' || $sid === null) { - if ($this->connection === null) { - Worker::safeEcho('Request->session() fail, header already send'); - return false; + if (!$this->connection) { + throw new RuntimeException('Request->session() fail, header already send'); } $sid = $sessionId ?: static::createSessionId(); $cookieParams = Session::getCookieParams(); @@ -298,11 +296,13 @@ public function sessionId($sessionId = null) } /** - * Session regenerate id + * Session regenerate id. + * * @param bool $deleteOldSession - * @return void + * @return string + * @throws Exception */ - public function sessionRegenerateId($deleteOldSession = false) + public function sessionRegenerateId(bool $deleteOldSession = false): string { $session = $this->session(); $sessionData = $session->all(); @@ -315,6 +315,7 @@ public function sessionRegenerateId($deleteOldSession = false) $cookieParams = Session::getCookieParams(); $sessionName = Session::$name; $this->setSidCookie($sessionName, $newSid, $cookieParams); + return $newSid; } /** @@ -322,7 +323,7 @@ public function sessionRegenerateId($deleteOldSession = false) * * @return string */ - public function rawHead() + public function rawHead(): string { if (!isset($this->data['head'])) { $this->data['head'] = \strstr($this->buffer, "\r\n\r\n", true); @@ -335,7 +336,7 @@ public function rawHead() * * @return string */ - public function rawBody() + public function rawBody(): string { return \substr($this->buffer, \strpos($this->buffer, "\r\n\r\n") + 4); } @@ -345,7 +346,7 @@ public function rawBody() * * @return string */ - public function rawBuffer() + public function rawBuffer(): string { return $this->buffer; } @@ -353,11 +354,11 @@ public function rawBuffer() /** * Enable or disable cache. * - * @param mixed $value + * @param bool $value */ - public static function enableCache($value) + public static function enableCache(bool $value) { - static::$enableCache = (bool)$value; + static::$enableCache = $value; } /** @@ -382,7 +383,7 @@ protected function parseProtocolVersion() { $firstLine = \strstr($this->buffer, "\r\n", true); $protocoVersion = substr(\strstr($firstLine, 'HTTP/'), 5); - $this->data['protocolVersion'] = $protocoVersion ? $protocoVersion : '1.0'; + $this->data['protocolVersion'] = $protocoVersion ?: '1.0'; } /** @@ -407,7 +408,7 @@ protected function parseHeaders() } $headData = \explode("\r\n", $headBuffer); foreach ($headData as $content) { - if (false !== \strpos($content, ':')) { + if (str_contains($content, ':')) { list($key, $value) = \explode(':', $content, 2); $key = \strtolower($key); $value = \ltrim($value); @@ -525,11 +526,16 @@ protected function parseUploadFiles($httpPostBoundary) } /** + * Parse upload file. + * * @param $boundary * @param $sectionStartOffset + * @param $postEncodeString + * @param $filesEncodeStr + * @param $files * @return int */ - protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeString, &$filesEncodeStr, &$files) + protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeString, &$filesEncodeStr, &$files): int { $file = []; $boundary = "\r\n$boundary"; @@ -590,7 +596,6 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } return $sectionEndOffset + \strlen($boundary) + 2; } - break; case "content-type": $file['type'] = \trim($value); break; @@ -609,8 +614,9 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS * Create session id. * * @return string + * @throws Exception */ - public static function createSessionId() + public static function createSessionId(): string { return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8)); } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index fbe4fe459..4738fb734 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -25,48 +25,48 @@ class Response * * @var array */ - protected $headers = null; + protected array $headers = []; /** * Http status. * * @var int */ - protected $status = null; + protected int $status; /** * Http reason. * - * @var string + * @var ?string */ - protected $reason = null; + protected ?string $reason = null; /** * Http version. * * @var string */ - protected $version = '1.1'; + protected string $version = '1.1'; /** * Http body. * * @var string */ - protected $body = null; + protected string $body = ''; /** * Send file info * - * @var array + * @var ?array */ - public $file = null; + public ?array $file = null; /** * Mine type map. * @var array */ - protected static $mimeTypeMap = null; + protected static array $mimeTypeMap = []; /** * Phrases. @@ -163,14 +163,14 @@ public static function init() * @param string $body */ public function __construct( - $status = 200, - $headers = [], - $body = '' + int $status = 200, + array $headers = [], + string $body = '' ) { $this->status = $status; $this->headers = $headers; - $this->body = (string)$body; + $this->body = $body; } /** @@ -180,7 +180,7 @@ public function __construct( * @param string $value * @return $this */ - public function header($name, $value) + public function header(string $name, string $value): static { $this->headers[$name] = $value; return $this; @@ -193,7 +193,7 @@ public function header($name, $value) * @param string $value * @return Response */ - public function withHeader($name, $value) + public function withHeader(string $name, string $value): static { return $this->header($name, $value); } @@ -204,7 +204,7 @@ public function withHeader($name, $value) * @param array $headers * @return $this */ - public function withHeaders($headers) + public function withHeaders(array $headers): static { $this->headers = \array_merge_recursive($this->headers, $headers); return $this; @@ -216,7 +216,7 @@ public function withHeaders($headers) * @param string $name * @return $this */ - public function withoutHeader($name) + public function withoutHeader(string $name): static { unset($this->headers[$name]); return $this; @@ -228,9 +228,8 @@ public function withoutHeader($name) * @param string $name * @return null|array|string */ - public function getHeader($name) + public function getHeader(string $name): array|string|null { - return $this->headers[$name] ?? null; } @@ -239,7 +238,7 @@ public function getHeader($name) * * @return array */ - public function getHeaders() + public function getHeaders(): array { return $this->headers; } @@ -251,7 +250,7 @@ public function getHeaders() * @param string|null $reasonPhrase * @return $this */ - public function withStatus($code, $reasonPhrase = null) + public function withStatus(int $code, string $reasonPhrase = null): static { $this->status = $code; $this->reason = $reasonPhrase; @@ -263,7 +262,7 @@ public function withStatus($code, $reasonPhrase = null) * * @return int */ - public function getStatusCode() + public function getStatusCode(): int { return $this->status; } @@ -271,9 +270,9 @@ public function getStatusCode() /** * Get reason phrase. * - * @return string + * @return ?string */ - public function getReasonPhrase() + public function getReasonPhrase(): ?string { return $this->reason; } @@ -281,10 +280,10 @@ public function getReasonPhrase() /** * Set protocol version. * - * @param int $version + * @param string $version * @return $this */ - public function withProtocolVersion($version) + public function withProtocolVersion(string $version): static { $this->version = $version; return $this; @@ -296,9 +295,9 @@ public function withProtocolVersion($version) * @param string $body * @return $this */ - public function withBody($body) + public function withBody(string $body): static { - $this->body = (string)$body; + $this->body = $body; return $this; } @@ -307,7 +306,7 @@ public function withBody($body) * * @return string */ - public function rawBody() + public function rawBody(): string { return $this->body; } @@ -320,7 +319,7 @@ public function rawBody() * @param int $length * @return $this */ - public function withFile($file, $offset = 0, $length = 0) + public function withFile(string $file, int $offset = 0, int $length = 0): static { if (!\is_file($file)) { return $this->withStatus(404)->withBody('

404 Not Found

'); @@ -332,9 +331,9 @@ public function withFile($file, $offset = 0, $length = 0) /** * Set cookie. * - * @param $name + * @param string $name * @param string $value - * @param int $maxAge + * @param int|null $maxAge * @param string $path * @param string $domain * @param bool $secure @@ -342,7 +341,7 @@ public function withFile($file, $offset = 0, $length = 0) * @param bool $sameSite * @return $this */ - public function cookie($name, $value = '', $maxAge = null, $path = '', $domain = '', $secure = false, $httpOnly = false, $sameSite = false) + public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, bool $sameSite = false): static { $this->headers['Set-Cookie'][] = $name . '=' . \rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) @@ -360,7 +359,7 @@ public function cookie($name, $value = '', $maxAge = null, $path = '', $domain = * @param array $fileInfo * @return string */ - protected function createHeadForFile($fileInfo) + protected function createHeadForFile(array $fileInfo): string { $file = $fileInfo['file']; $reason = $this->reason ?: self::PHRASES[$this->status]; @@ -414,7 +413,7 @@ protected function createHeadForFile($fileInfo) */ public function __toString() { - if (isset($this->file)) { + if ($this->file) { return $this->createHeadForFile($this->file); } diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index 64f02815a..bdd090075 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -24,7 +24,7 @@ class ServerSentEvents * Data. * @var array */ - protected $data = null; + protected array $data; /** * ServerSentEvents constructor. diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 13343445e..5abeb48a6 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http; +use Exception; +use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -28,119 +30,119 @@ class Session * * @var string */ - protected static $handlerClass = FileSessionHandler::class; + protected static string $handlerClass = FileSessionHandler::class; /** * Parameters of __constructor for session handler class. * - * @var null + * @var mixed */ - protected static $handlerConfig = null; + protected static mixed $handlerConfig = null; /** * Session name. * * @var string */ - public static $name = 'PHPSID'; + public static string $name = 'PHPSID'; /** * Auto update timestamp. * * @var bool */ - public static $autoUpdateTimestamp = false; + public static bool $autoUpdateTimestamp = false; /** * Session lifetime. * * @var int */ - public static $lifetime = 1440; + public static int $lifetime = 1440; /** * Cookie lifetime. * * @var int */ - public static $cookieLifetime = 1440; + public static int $cookieLifetime = 1440; /** * Session cookie path. * * @var string */ - public static $cookiePath = '/'; + public static string $cookiePath = '/'; /** * Session cookie domain. * * @var string */ - public static $domain = ''; + public static string $domain = ''; /** * HTTPS only cookies. * * @var bool */ - public static $secure = false; + public static bool $secure = false; /** * HTTP access only. * * @var bool */ - public static $httpOnly = true; + public static bool $httpOnly = true; /** * Same-site cookies. * * @var string */ - public static $sameSite = ''; + public static string $sameSite = ''; /** * Gc probability. * * @var int[] */ - public static $gcProbability = [1, 1000]; + public static array $gcProbability = [1, 20000]; /** * Session handler instance. * - * @var SessionHandlerInterface + * @var ?SessionHandlerInterface */ - protected static $handler = null; + protected static ?SessionHandlerInterface $handler = null; /** * Session data. * * @var array */ - protected $data = []; + protected mixed $data = []; /** * Session changed and need to save. * * @var bool */ - protected $needSave = false; + protected bool $needSave = false; /** * Session id. * - * @var null + * @var string */ - protected $sessionId = null; + protected string $sessionId; /** * Session constructor. * * @param string $sessionId */ - public function __construct($sessionId) + public function __construct(string $sessionId) { static::checkSessionId($sessionId); if (static::$handler === null) { @@ -157,7 +159,7 @@ public function __construct($sessionId) * * @return string */ - public function getId() + public function getId(): string { return $this->sessionId; } @@ -167,9 +169,9 @@ public function getId() * * @param string $name * @param mixed|null $default - * @return mixed|null + * @return mixed */ - public function get($name, $default = null) + public function get(string $name, mixed $default = null): mixed { return $this->data[$name] ?? $default; } @@ -180,7 +182,7 @@ public function get($name, $default = null) * @param string $name * @param mixed $value */ - public function set($name, $value) + public function set(string $name, mixed $value) { $this->data[$name] = $value; $this->needSave = true; @@ -191,7 +193,7 @@ public function set($name, $value) * * @param string $name */ - public function delete($name) + public function delete(string $name) { unset($this->data[$name]); $this->needSave = true; @@ -202,9 +204,9 @@ public function delete($name) * * @param string $name * @param mixed|null $default - * @return mixed|null + * @return mixed */ - public function pull($name, $default = null) + public function pull(string $name, mixed $default = null): mixed { $value = $this->get($name, $default); $this->delete($name); @@ -214,10 +216,10 @@ public function pull($name, $default = null) /** * Store data in the session. * - * @param string|array $key + * @param array|string $key * @param mixed|null $value */ - public function put($key, $value = null) + public function put(array|string $key, mixed $value = null) { if (!\is_array($key)) { $this->set($key, $value); @@ -233,9 +235,9 @@ public function put($key, $value = null) /** * Remove a piece of data from the session. * - * @param string $name + * @param array|string $name */ - public function forget($name) + public function forget(array|string $name) { if (\is_scalar($name)) { $this->delete($name); @@ -254,7 +256,7 @@ public function forget($name) * * @return array */ - public function all() + public function all(): array { return $this->data; } @@ -276,7 +278,7 @@ public function flush() * @param string $name * @return bool */ - public function has($name) + public function has(string $name): bool { return isset($this->data[$name]); } @@ -287,7 +289,7 @@ public function has($name) * @param string $name * @return bool */ - public function exists($name) + public function exists(string $name): bool { return \array_key_exists($name, $this->data); } @@ -316,7 +318,7 @@ public function save() * * @return bool */ - public function refresh() + public function refresh(): bool { return static::$handler->updateTimestamp($this->getId()); } @@ -351,7 +353,7 @@ public static function init() * @param mixed|null $config * @return string */ - public static function handlerClass($className = null, $config = null) + public static function handlerClass(mixed $className = null, mixed $config = null): string { if ($className) { static::$handlerClass = $className; @@ -367,7 +369,7 @@ public static function handlerClass($className = null, $config = null) * * @return array */ - public static function getCookieParams() + public static function getCookieParams(): array { return [ 'lifetime' => static::$cookieLifetime, @@ -407,6 +409,7 @@ public function gc() * __destruct. * * @return void + * @throws Exception */ public function __destruct() { @@ -424,19 +427,10 @@ public function __destruct() protected static function checkSessionId($sessionId) { if (!\preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { - throw new SessionException("session_id $sessionId is invalid"); + throw new RuntimeException("session_id $sessionId is invalid"); } } } -/** - * Class SessionException - * @package Workerman\Protocols\Http - */ -class SessionException extends \RuntimeException -{ - -} - // Init session. Session::init(); diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index e5115f528..e84bf61a5 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -27,14 +27,14 @@ class FileSessionHandler implements SessionHandlerInterface * * @var string */ - protected static $sessionSavePath = null; + protected static string $sessionSavePath; /** * Session file prefix. * * @var string */ - protected static $sessionFilePrefix = 'session_'; + protected static string $sessionFilePrefix = 'session_'; /** * Init. @@ -42,7 +42,7 @@ class FileSessionHandler implements SessionHandlerInterface public static function init() { $savePath = @\session_save_path(); - if (!$savePath || \strpos($savePath, 'tcp://') === 0) { + if (!$savePath || str_starts_with($savePath, 'tcp://')) { $savePath = \sys_get_temp_dir(); } static::sessionSavePath($savePath); @@ -52,7 +52,7 @@ public static function init() * FileSessionHandler constructor. * @param array $config */ - public function __construct($config = []) + public function __construct(array $config = []) { if (isset($config['save_path'])) { static::sessionSavePath($config['save_path']); @@ -62,7 +62,7 @@ public function __construct($config = []) /** * {@inheritdoc} */ - public function open($savePath, $name) + public function open(string $savePath, string $name): bool { return true; } @@ -70,7 +70,7 @@ public function open($savePath, $name) /** * {@inheritdoc} */ - public function read($sessionId) + public function read(string $sessionId): string { $sessionFile = static::sessionFile($sessionId); \clearstatcache(); @@ -88,7 +88,7 @@ public function read($sessionId) /** * {@inheritdoc} */ - public function write($sessionId, $sessionData) + public function write(string $sessionId, string $sessionData): bool { $tempFile = static::$sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); if (!\file_put_contents($tempFile, $sessionData)) { @@ -108,7 +108,7 @@ public function write($sessionId, $sessionData) * * @return bool */ - public function updateTimestamp($id, $data = "") + public function updateTimestamp(string $id, string $data = ""): bool { $sessionFile = static::sessionFile($id); if (!file_exists($sessionFile)) { @@ -124,7 +124,7 @@ public function updateTimestamp($id, $data = "") /** * {@inheritdoc} */ - public function close() + public function close(): bool { return true; } @@ -132,7 +132,7 @@ public function close() /** * {@inheritdoc} */ - public function destroy($sessionId) + public function destroy(string $sessionId): bool { $sessionFile = static::sessionFile($sessionId); if (\is_file($sessionFile)) { @@ -144,14 +144,15 @@ public function destroy($sessionId) /** * {@inheritdoc} */ - public function gc($maxlifetime) + public function gc(int $maxLifetime): bool { $timeNow = \time(); foreach (\glob(static::$sessionSavePath . static::$sessionFilePrefix . '*') as $file) { - if (\is_file($file) && $timeNow - \filemtime($file) > $maxlifetime) { + if (\is_file($file) && $timeNow - \filemtime($file) > $maxLifetime) { \unlink($file); } } + return true; } /** @@ -160,7 +161,7 @@ public function gc($maxlifetime) * @param string $sessionId * @return string */ - protected static function sessionFile($sessionId) + protected static function sessionFile(string $sessionId): string { return static::$sessionSavePath . static::$sessionFilePrefix . $sessionId; } @@ -171,7 +172,7 @@ protected static function sessionFile($sessionId) * @param string $path * @return string */ - public static function sessionSavePath($path) + public static function sessionSavePath(string $path): string { if ($path) { if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) { diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index b938a8237..1e288d102 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -15,9 +15,14 @@ namespace Workerman\Protocols\Http\Session; use Workerman\Protocols\Http\Session; +use RedisClusterException; class RedisClusterSessionHandler extends RedisSessionHandler { + /** + * @param $config + * @throws RedisClusterException + */ public function __construct($config) { $timeout = $config['timeout'] ?? 2; @@ -38,7 +43,7 @@ public function __construct($config) /** * {@inheritdoc} */ - public function read($sessionId) + public function read(string $sessionId): string { return $this->redis->get($sessionId); } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index d7f36bdf9..54140f961 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http\Session; +use Redis; +use Throwable; use Workerman\Protocols\Http\Session; use Workerman\Timer; use RedisException; @@ -26,14 +28,14 @@ class RedisSessionHandler implements SessionHandlerInterface { /** - * @var \Redis + * @var Redis */ - protected $redis; + protected Redis $redis; /** * @var array */ - protected $config; + protected array $config; /** * RedisSessionHandler constructor. @@ -47,7 +49,7 @@ class RedisSessionHandler implements SessionHandlerInterface * 'ping' => 55, * ] */ - public function __construct($config) + public function __construct(array $config) { if (false === extension_loaded('redis')) { throw new \RuntimeException('Please install redis extension.'); @@ -70,7 +72,7 @@ public function connect() { $config = $this->config; - $this->redis = new \Redis(); + $this->redis = new Redis(); if (false === $this->redis->connect($config['host'], $config['port'], $config['timeout'])) { throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); } @@ -83,25 +85,26 @@ public function connect() if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + $this->redis->setOption(Redis::OPT_PREFIX, $config['prefix']); } /** * {@inheritdoc} */ - public function open($savePath, $name) + public function open(string $savePath, string $name): bool { return true; } /** * {@inheritdoc} + * @throws RedisException */ - public function read($sessionId) + public function read(string $sessionId): string { try { return $this->redis->get($sessionId); - } catch (RedisException $e) { + } catch (Throwable $e) { $msg = strtolower($e->getMessage()); if ($msg === 'connection lost' || strpos($msg, 'went away')) { $this->connect(); @@ -114,7 +117,7 @@ public function read($sessionId) /** * {@inheritdoc} */ - public function write($sessionId, $sessionData) + public function write(string $sessionId, string $sessionData): bool { return true === $this->redis->setex($sessionId, Session::$lifetime, $sessionData); } @@ -122,7 +125,7 @@ public function write($sessionId, $sessionData) /** * {@inheritdoc} */ - public function updateTimestamp($id, $data = "") + public function updateTimestamp(string $id, string $data = ""): bool { return true === $this->redis->expire($id, Session::$lifetime); } @@ -130,7 +133,7 @@ public function updateTimestamp($id, $data = "") /** * {@inheritdoc} */ - public function destroy($sessionId) + public function destroy(string $sessionId): bool { $this->redis->del($sessionId); return true; @@ -139,7 +142,7 @@ public function destroy($sessionId) /** * {@inheritdoc} */ - public function close() + public function close(): bool { return true; } @@ -147,7 +150,7 @@ public function close() /** * {@inheritdoc} */ - public function gc($maxlifetime) + public function gc(int $maxLifetime): bool { return true; } diff --git a/src/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php index f1033ec2e..95419cfb3 100644 --- a/src/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -25,7 +25,7 @@ interface SessionHandlerInterface *

* @since 5.4.0 */ - public function close(); + public function close(): bool; /** * Destroy a session @@ -37,12 +37,12 @@ public function close(); *

* @since 5.4.0 */ - public function destroy($sessionId); + public function destroy(string $sessionId): bool; /** * Cleanup old sessions * @link http://php.net/manual/en/sessionhandlerinterface.gc.php - * @param int $maxlifetime

+ * @param int $maxLifetime

* Sessions that have not updated for * the last maxlifetime seconds will be removed. *

@@ -52,7 +52,7 @@ public function destroy($sessionId); *

* @since 5.4.0 */ - public function gc($maxlifetime); + public function gc(int $maxLifetime): bool; /** * Initialize session @@ -65,7 +65,7 @@ public function gc($maxlifetime); *

* @since 5.4.0 */ - public function open($savePath, $name); + public function open(string $savePath, string $name): bool; /** @@ -79,7 +79,7 @@ public function open($savePath, $name); *

* @since 5.4.0 */ - public function read($sessionId); + public function read(string $sessionId): string; /** * Write session data @@ -98,18 +98,18 @@ public function read($sessionId); *

* @since 5.4.0 */ - public function write($sessionId, $sessionData); + public function write(string $sessionId, string $sessionData): bool; /** * Update sesstion modify time. * * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php * - * @param string $id Session id. + * @param string $sessionId * @param string $data Session Data. * * @return bool */ - public function updateTimestamp($id, $data = ""); + public function updateTimestamp(string $sessionId, string $data = ""): bool; } diff --git a/src/Protocols/ProtocolInterface.php b/src/Protocols/ProtocolInterface.php index 6a33cad85..9e71cc22b 100644 --- a/src/Protocols/ProtocolInterface.php +++ b/src/Protocols/ProtocolInterface.php @@ -27,20 +27,20 @@ interface ProtocolInterface * If length is unknown please return 0 that means waiting for more data. * If the package has something wrong please return false the connection will be closed. * - * @param string $recvBuffer + * @param string $buffer * @param ConnectionInterface $connection * @return int|false */ - public static function input($recvBuffer, ConnectionInterface $connection); + public static function input(string $buffer, ConnectionInterface $connection): bool|int; /** * Decode package and emit onMessage($message) callback, $message is the result that decode returned. * - * @param string $recvBuffer + * @param string $buffer * @param ConnectionInterface $connection * @return mixed */ - public static function decode($recvBuffer, ConnectionInterface $connection); + public static function decode(string $buffer, ConnectionInterface $connection): mixed; /** * Encode package before sending to client. @@ -49,5 +49,5 @@ public static function decode($recvBuffer, ConnectionInterface $connection); * @param ConnectionInterface $connection * @return string */ - public static function encode($data, ConnectionInterface $connection); + public static function encode(mixed $data, ConnectionInterface $connection): string; } diff --git a/src/Protocols/Text.php b/src/Protocols/Text.php index 367e8e898..2b65ddf32 100644 --- a/src/Protocols/Text.php +++ b/src/Protocols/Text.php @@ -28,7 +28,7 @@ class Text * @param ConnectionInterface $connection * @return int */ - public static function input($buffer, ConnectionInterface $connection) + public static function input(string $buffer, ConnectionInterface $connection): int { // Judge whether the package length exceeds the limit. if (isset($connection->maxPackageSize) && \strlen($buffer) >= $connection->maxPackageSize) { @@ -51,7 +51,7 @@ public static function input($buffer, ConnectionInterface $connection) * @param string $buffer * @return string */ - public static function encode($buffer) + public static function encode(string $buffer): string { // Add "\n" return $buffer . "\n"; @@ -63,7 +63,7 @@ public static function encode($buffer) * @param string $buffer * @return string */ - public static function decode($buffer) + public static function decode(string $buffer): string { // Remove "\n" return \rtrim($buffer, "\r\n"); diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index a1ade38ef..c581cf28c 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; +use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; @@ -22,7 +23,7 @@ /** * WebSocket protocol. */ -class Websocket implements \Workerman\Protocols\ProtocolInterface +class Websocket { /** * Websocket blob type. @@ -42,10 +43,11 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface * Check the integrity of the package. * * @param string $buffer - * @param ConnectionInterface $connection + * @param TcpConnection $connection * @return int + * @throws Throwable */ - public static function input($buffer, ConnectionInterface $connection) + public static function input(string $buffer, TcpConnection $connection): int { // Receive length. $recvLen = \strlen($buffer); @@ -98,7 +100,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($closeCb) { try { $closeCb($connection); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } // Close connection. @@ -152,7 +154,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($pingCb) { try { $pingCb($connection, $pingData); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } else { @@ -175,7 +177,7 @@ public static function input($buffer, ConnectionInterface $connection) if ($pongCb) { try { $pongCb($connection, $pongData); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -216,14 +218,11 @@ public static function input($buffer, ConnectionInterface $connection) * Websocket encode. * * @param string $buffer - * @param ConnectionInterface $connection + * @param TcpConnection $connection * @return string */ - public static function encode($buffer, ConnectionInterface $connection) + public static function encode(string $buffer, TcpConnection $connection): string { - if (!is_scalar($buffer)) { - throw new \Exception("You can't send(" . \gettype($buffer) . ") to client, you need to convert it to a string. "); - } $len = \strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; @@ -251,7 +250,7 @@ public static function encode($buffer, ConnectionInterface $connection) if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -263,7 +262,7 @@ public static function encode($buffer, ConnectionInterface $connection) if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -279,10 +278,10 @@ public static function encode($buffer, ConnectionInterface $connection) * Websocket decode. * * @param string $buffer - * @param ConnectionInterface $connection + * @param TcpConnection $connection * @return string */ - public static function decode($buffer, ConnectionInterface $connection) + public static function decode(string $buffer, TcpConnection $connection): string { $firstByte = \ord($buffer[1]); $len = $firstByte & 127; @@ -321,8 +320,9 @@ public static function decode($buffer, ConnectionInterface $connection) * @param string $buffer * @param TcpConnection $connection * @return int + * @throws Throwable */ - public static function dealHandshake($buffer, ConnectionInterface $connection) + public static function dealHandshake(string $buffer, TcpConnection $connection): int { // HTTP protocol. if (0 === \strpos($buffer, 'GET')) { @@ -365,7 +365,7 @@ public static function dealHandshake($buffer, ConnectionInterface $connection) if ($onWebsocketConnect) { try { $onWebsocketConnect($connection, new Request($buffer)); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -377,19 +377,12 @@ public static function dealHandshake($buffer, ConnectionInterface $connection) $hasServerHeader = false; - if (isset($connection->headers)) { - if (\is_array($connection->headers)) { - foreach ($connection->headers as $header) { - if (\stripos($header, 'Server:') === 0) { - $hasServerHeader = true; - } - $handshakeMessage .= "$header\r\n"; - } - } else { - if (\stripos($connection->headers, 'Server:') !== false) { + if ($connection->headers) { + foreach ($connection->headers as $header) { + if (\stripos($header, 'Server:') === 0) { $hasServerHeader = true; } - $handshakeMessage .= "$connection->headers\r\n"; + $handshakeMessage .= "$header\r\n"; } } if (!$hasServerHeader) { diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 9c9387ebd..1988b3e93 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; +use Throwable; use Workerman\Worker; use Workerman\Timer; use Workerman\Connection\TcpConnection; @@ -42,10 +43,11 @@ class Ws * Check the integrity of the package. * * @param string $buffer - * @param ConnectionInterface $connection - * @return int + * @param TcpConnection $connection + * @return int|false + * @throws Throwable */ - public static function input($buffer, ConnectionInterface $connection) + public static function input(string $buffer, TcpConnection $connection): bool|int { if (empty($connection->context->handshakeStep)) { Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n"); @@ -99,7 +101,7 @@ public static function input($buffer, ConnectionInterface $connection) if (isset($connection->onWebSocketClose)) { try { ($connection->onWebSocketClose)($connection); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } // Close connection. @@ -147,7 +149,7 @@ public static function input($buffer, ConnectionInterface $connection) if (isset($connection->onWebSocketPing)) { try { ($connection->onWebSocketPing)($connection, $pingData); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } else { @@ -170,7 +172,7 @@ public static function input($buffer, ConnectionInterface $connection) if (isset($connection->onWebSocketPong)) { try { ($connection->onWebSocketPong)($connection, $pongData); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -209,16 +211,16 @@ public static function input($buffer, ConnectionInterface $connection) /** * Websocket encode. * - * @param string $buffer - * @param ConnectionInterface $connection + * @param string $payload + * @param TcpConnection $connection * @return string */ - public static function encode($payload, ConnectionInterface $connection) + public static function encode(string $payload, TcpConnection $connection): string { if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } - $payload = (string)$payload; + $payload = $payload; if (empty($connection->context->handshakeStep)) { static::sendHandshake($connection); } @@ -244,7 +246,7 @@ public static function encode($payload, ConnectionInterface $connection) if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -256,7 +258,7 @@ public static function encode($payload, ConnectionInterface $connection) if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } @@ -269,11 +271,11 @@ public static function encode($payload, ConnectionInterface $connection) /** * Websocket decode. * - * @param string $buffer - * @param ConnectionInterface $connection + * @param string $bytes + * @param TcpConnection $connection * @return string */ - public static function decode($bytes, ConnectionInterface $connection) + public static function decode(string $bytes, TcpConnection $connection): string { $dataLength = \ord($bytes[1]); @@ -311,7 +313,7 @@ public static function onConnect($connection) * * @param TcpConnection $connection */ - public static function onClose($connection) + public static function onClose(TcpConnection $connection) { $connection->context->handshakeStep = null; $connection->context->websocketCurrentFrameLength = 0; @@ -328,8 +330,9 @@ public static function onClose($connection) * * @param TcpConnection $connection * @return void + * @throws Throwable */ - public static function sendHandshake(ConnectionInterface $connection) + public static function sendHandshake(TcpConnection $connection) { if (!empty($connection->context->handshakeStep)) { return; @@ -372,8 +375,9 @@ public static function sendHandshake(ConnectionInterface $connection) * @param string $buffer * @param TcpConnection $connection * @return int + * @throws Throwable */ - public static function dealHandshake($buffer, ConnectionInterface $connection) + public static function dealHandshake(string $buffer, TcpConnection $connection): bool|int { $pos = \strpos($buffer, "\r\n\r\n"); if ($pos) { @@ -403,7 +407,7 @@ public static function dealHandshake($buffer, ConnectionInterface $connection) if (isset($connection->onWebSocketConnect)) { try { ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshakeResponseLength)); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::stopAll(250, $e); } } diff --git a/src/Timer.php b/src/Timer.php index 12c057fed..52aa6412b 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -36,24 +36,24 @@ class Timer * * @var array */ - protected static $tasks = []; + protected static array $tasks = []; /** - * event + * Event * - * @var Select + * @var ?EventInterface */ - protected static $event = null; + protected static ?EventInterface $event = null; /** - * timer id + * Timer id * * @var int */ - protected static $timerId = 0; + protected static int $timerId = 0; /** - * timer status + * Timer status * [ * timer_id1 => bool, * timer_id2 => bool, @@ -62,15 +62,15 @@ class Timer * * @var array */ - protected static $status = []; + protected static array $status = []; /** * Init. * - * @param EventInterface $event + * @param EventInterface|null $event * @return void */ - public static function init($event = null) + public static function init(EventInterface $event = null) { if ($event) { self::$event = $event; @@ -99,11 +99,11 @@ public static function signalHandle() * * @param float $timeInterval * @param callable $func - * @param mixed $args + * @param mixed|array $args * @param bool $persistent - * @return int|bool + * @return int */ - public static function add(float $timeInterval, callable $func, $args = [], bool $persistent = true) + public static function add(float $timeInterval, callable $func, null|array $args = [], bool $persistent = true): int { if ($timeInterval < 0) { throw new \RuntimeException('$timeInterval can not less than 0'); @@ -147,7 +147,7 @@ public static function add(float $timeInterval, callable $func, $args = [], bool * Coroutine sleep. * * @param float $delay - * @return null + * @return void */ public static function sleep(float $delay) { @@ -159,15 +159,15 @@ public static function sleep(float $delay) $suspension->resume(); }, null, false); $suspension->suspend(); - return null; + return; // Swoole case Swoole::class: System::sleep($delay); - return null; + return; // Swow case Swow::class: usleep($delay * 1000 * 1000); - return null; + return; } throw new \RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer install revolt/event-loop" and restart workerman'); } @@ -210,10 +210,10 @@ public static function tick() /** * Remove a timer. * - * @param mixed $timerId + * @param int $timerId * @return bool */ - public static function del($timerId) + public static function del(int $timerId): bool { if (self::$event) { return self::$event->offDelay($timerId); diff --git a/src/Worker.php b/src/Worker.php index 0d835fe9c..2f12eefe5 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -19,6 +19,7 @@ use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; use Workerman\Events\Event; +use Workerman\Events\EventInterface; use Workerman\Events\Revolt; use Workerman\Events\Select; use Revolt\EventLoop; @@ -91,68 +92,68 @@ class Worker * * @var int */ - public $id = 0; + public int $id = 0; /** * Name of the worker processes. * * @var string */ - public $name = 'none'; + public string $name = 'none'; /** * Number of worker processes. * * @var int */ - public $count = 1; + public int $count = 1; /** * Unix user of processes, needs appropriate privileges (usually root). * * @var string */ - public $user = ''; + public string $user = ''; /** * Unix group of processes, needs appropriate privileges (usually root). * * @var string */ - public $group = ''; + public string $group = ''; /** * reloadable. * * @var bool */ - public $reloadable = true; + public bool $reloadable = true; /** * reuse port. * * @var bool */ - public $reusePort = false; + public bool $reusePort = false; /** * Emitted when worker processes start. * - * @var callable + * @var ?callable */ public $onWorkerStart = null; /** * Emitted when a socket connection is successfully established. * - * @var callable + * @var ?callable */ public $onConnect = null; /** * Emitted when websocket handshake completed (Only work when protocol is ws). * - * @var callable|null + * @var ?callable */ public $onWebSocketConnect = null; @@ -166,49 +167,49 @@ class Worker /** * Emitted when the other end of the socket sends a FIN packet. * - * @var callable + * @var ?callable */ public $onClose = null; /** * Emitted when an error occurs with connection. * - * @var callable + * @var ?callable */ public $onError = null; /** * Emitted when the send buffer becomes full. * - * @var callable + * @var ?callable */ public $onBufferFull = null; /** * Emitted when the send buffer becomes empty. * - * @var callable + * @var ?callable */ public $onBufferDrain = null; /** * Emitted when worker processes stopped. * - * @var callable + * @var ?callable */ public $onWorkerStop = null; /** * Emitted when worker processes get reload signal. * - * @var callable + * @var ?callable */ public $onWorkerReload = null; /** * Emitted when worker processes exited. * - * @var callable + * @var ?callable */ public $onWorkerExit = null; @@ -217,104 +218,104 @@ class Worker * * @var string */ - public $transport = 'tcp'; + public string $transport = 'tcp'; /** * Store all connections of clients. * * @var array */ - public $connections = []; + public array $connections = []; /** * Application layer protocol. * - * @var string + * @var ?string */ - public $protocol = null; + public ?string $protocol = null; /** * Pause accept new connections or not. * * @var bool */ - protected $pauseAccept = true; + protected bool $pauseAccept = true; /** * Is worker stopping ? * @var bool */ - public $stopping = false; + public bool $stopping = false; /** * Daemonize. * * @var bool */ - public static $daemonize = false; + public static bool $daemonize = false; /** * Stdout file. * * @var string */ - public static $stdoutFile = '/dev/null'; + public static string $stdoutFile = '/dev/null'; /** * The file to store master process PID. * * @var string */ - public static $pidFile = ''; + public static string $pidFile = ''; /** * The file used to store the master process status file. * * @var string */ - public static $statusFile = ''; + public static string $statusFile = ''; /** * Log file. * - * @var string + * @var mixed */ - public static $logFile = ''; + public static mixed $logFile = ''; /** * Global event loop. * - * @var Select + * @var ?EventInterface */ - public static $globalEvent = null; + public static ?EventInterface $globalEvent = null; /** * Emitted when the master process get reload signal. * - * @var callable + * @var ?callable */ public static $onMasterReload = null; /** * Emitted when the master process terminated. * - * @var callable + * @var ?callable */ public static $onMasterStop = null; /** * EventLoopClass * - * @var string + * @var class-string */ - public static $eventLoopClass = ''; + public static string $eventLoopClass = ''; /** * Process title * * @var string */ - public static $processTitle = 'WorkerMan'; + public static string $processTitle = 'WorkerMan'; /** * After sending the stop command to the child process stopTimeout seconds, @@ -322,20 +323,20 @@ class Worker * * @var int */ - public static $stopTimeout = 2; + public static int $stopTimeout = 2; /** * Command * @var string */ - public static $command = ''; + public static string $command = ''; /** * The PID of master process. * * @var int */ - protected static $masterPid = 0; + protected static int $masterPid = 0; /** * Listening socket. @@ -349,14 +350,14 @@ class Worker * * @var string */ - protected $socketName = ''; + protected string $socketName = ''; /** * parse from socketName avoid parse again in master or worker * LocalSocket The format is like tcp://0.0.0.0:8080 - * @var string + * @var ?string */ - protected $localSocket = null; + protected ?string $localSocket = null; /** * Context of socket. @@ -370,7 +371,7 @@ class Worker * * @var Worker[] */ - protected static $workers = []; + protected static array $workers = []; /** * All worker processes pid. @@ -378,7 +379,7 @@ class Worker * * @var array */ - protected static $pidMap = []; + protected static array $pidMap = []; /** * All worker processes waiting for restart. @@ -386,7 +387,7 @@ class Worker * * @var array */ - protected static $pidsToRestart = []; + protected static array $pidsToRestart = []; /** * Mapping from PID to worker process ID. @@ -394,84 +395,84 @@ class Worker * * @var array */ - protected static $idMap = []; + protected static array $idMap = []; /** * Current status. * * @var int */ - protected static $status = self::STATUS_STARTING; + protected static int $status = self::STATUS_STARTING; /** * Maximum length of the worker names. * * @var int */ - protected static $maxWorkerNameLength = 12; + protected static int $maxWorkerNameLength = 12; /** * Maximum length of the socket names. * * @var int */ - protected static $maxSocketNameLength = 12; + protected static int $maxSocketNameLength = 12; /** * Maximum length of the process user names. * * @var int */ - protected static $maxUserNameLength = 12; + protected static int $maxUserNameLength = 12; /** * Maximum length of the Proto names. * * @var int */ - protected static $maxProtoNameLength = 4; + protected static int $maxProtoNameLength = 4; /** * Maximum length of the Processes names. * * @var int */ - protected static $maxProcessesNameLength = 9; + protected static int $maxProcessesNameLength = 9; /** * Maximum length of the state names. * * @var int */ - protected static $maxStateNameLength = 1; + protected static int $maxStateNameLength = 1; /** * The file to store status info of current worker process. * * @var string */ - protected static $statisticsFile = ''; + protected static string $statisticsFile = ''; /** * Start file. * * @var string */ - protected static $startFile = ''; + protected static string $startFile = ''; /** * Processes for windows. * * @var array */ - protected static $processForWindows = []; + protected static array $processForWindows = []; /** * Status info of current worker process. * * @var array */ - protected static $globalStatistics = [ + protected static array $globalStatistics = [ 'start_timestamp' => 0, 'worker_exit_info' => [] ]; @@ -481,7 +482,7 @@ class Worker * * @var array */ - protected static $availableEventLoops = [ + protected static array $availableEventLoops = [ 'event' => Event::class, ]; @@ -525,7 +526,7 @@ class Worker * * @var bool */ - protected static $gracefulStop = false; + protected static bool $gracefulStop = false; /** * Standard output stream @@ -537,14 +538,14 @@ class Worker * If $outputStream support decorated * @var bool */ - protected static $outputDecorated = null; + protected static ?bool $outputDecorated = null; /** * Worker object's hash id(unique identifier). * - * @var string + * @var ?string */ - protected $workerId = null; + protected ?string $workerId = null; /** * Run all worker instances. @@ -664,6 +665,7 @@ protected static function lock($flag = \LOCK_EX) * Init All worker instances. * * @return void + * @throws Exception */ protected static function initWorkers() { @@ -712,7 +714,7 @@ protected static function initWorkers() * * @return Worker[] */ - public static function getAllWorkers() + public static function getAllWorkers(): array { return static::$workers; } @@ -720,9 +722,9 @@ public static function getAllWorkers() /** * Get global event-loop instance. * - * @return Select + * @return EventInterface */ - public static function getEventLoop() + public static function getEventLoop(): EventInterface { return static::$globalEvent; } @@ -757,7 +759,7 @@ protected static function initId() * * @return string */ - protected static function getCurrentUser() + protected static function getCurrentUser(): string { $userInfo = \posix_getpwuid(\posix_getuid()); return $userInfo['name']; @@ -833,7 +835,7 @@ protected static function displayUI() * * @return array */ - public static function getUiColumns() + public static function getUiColumns(): array { return [ 'proto' => 'transport', @@ -850,7 +852,7 @@ public static function getUiColumns() * * @return int */ - public static function getSingleLineTotalLength() + public static function getSingleLineTotalLength(): int { $totalLength = 0; @@ -1025,7 +1027,12 @@ protected static function parseCommand() } } - public static function getArgv() + /** + * Get argv. + * + * @return mixed + */ + public static function getArgv(): mixed { global $argv; return isset($argv[1]) ? $argv : (static::$command ? \explode(' ', static::$command) : $argv); @@ -1037,7 +1044,7 @@ public static function getArgv() * @param $statisticsFile * @return string */ - protected static function formatStatusData($statisticsFile) + protected static function formatStatusData($statisticsFile): string { static $totalRequestCache = []; if (!\is_readable($statisticsFile)) { @@ -1154,8 +1161,9 @@ protected static function reinstallSignal() * Signal handler. * * @param int $signal + * @throws Exception */ - public static function signalHandler($signal) + public static function signalHandler(int $signal) { switch ($signal) { // Stop. @@ -1320,7 +1328,7 @@ protected static function getEventLoopName(): string * * @return array */ - protected static function getAllWorkerPids() + protected static function getAllWorkerPids(): array { $pidArray = []; foreach (static::$pidMap as $workerPidArray) { @@ -1349,6 +1357,7 @@ protected static function forkWorkers() * Fork some worker processes. * * @return void + * @throws Exception */ protected static function forkWorkersForLinux() { @@ -1374,6 +1383,7 @@ protected static function forkWorkersForLinux() * Fork some worker processes. * * @return void + * @throws Exception */ protected static function forkWorkersForWindows() { @@ -1419,7 +1429,8 @@ protected static function forkWorkersForWindows() * * @return array */ - public static function getStartFilesForWindows() { + public static function getStartFilesForWindows(): array + { $files = []; foreach(static::getArgv() as $file) { @@ -1436,7 +1447,7 @@ public static function getStartFilesForWindows() { * * @param string $startFile */ - public static function forkOneWorkerForWindows($startFile) + public static function forkOneWorkerForWindows(string $startFile) { $startFile = \realpath($startFile); @@ -1486,7 +1497,6 @@ public static function checkWorkerStatusForWindows() } } - /** * Fork one worker process. * @@ -1543,9 +1553,9 @@ protected static function forkOneWorkerForLinux(self $worker) * @param string $workerId * @param int $pid * - * @return integer + * @return false|int|string */ - protected static function getId($workerId, $pid) + protected static function getId(string $workerId, int $pid): bool|int|string { return \array_search($pid, static::$idMap[$workerId]); } @@ -1615,6 +1625,7 @@ protected static function monitorWorkers() * Monitor all child processes. * * @return void + * @throws Exception */ protected static function monitorWorkersForLinux() { @@ -1699,8 +1710,6 @@ protected static function monitorWorkersForWindows() /** * Exit current process. - * - * @return void */ protected static function exitAndClearAll() { @@ -1808,9 +1817,9 @@ protected static function reload() * Stop all. * * @param int $code - * @param string $log + * @param mixed $log */ - public static function stopAll($code = 0, $log = '') + public static function stopAll(int $code = 0, mixed $log = '') { if ($log) { static::log($log); @@ -1880,9 +1889,9 @@ public static function checkIfChildRunning() /** * Get process status. * - * @return number + * @return int */ - public static function getStatus() + public static function getStatus(): int { return static::$status; } @@ -1892,7 +1901,7 @@ public static function getStatus() * * @return bool */ - public static function getGracefulStop() + public static function getGracefulStop(): bool { return static::$gracefulStop; } @@ -2084,10 +2093,10 @@ public static function checkErrors() /** * Get error message by error code. * - * @param integer $type + * @param int $type * @return string */ - protected static function getErrorType($type) + protected static function getErrorType(int $type): string { return self::ERROR_TYPE[$type] ?? ''; } @@ -2095,10 +2104,10 @@ protected static function getErrorType($type) /** * Log. * - * @param string $msg + * @param mixed $msg * @return void */ - public static function log($msg) + public static function log(mixed $msg) { $msg = $msg . "\n"; if (!static::$daemonize) { @@ -2171,7 +2180,7 @@ private static function outputStream($stream = null) /** * Constructor. * - * @param string $socketName + * @param string|null $socketName * @param array $contextOption */ public function __construct(string $socketName = null, array $contextOption = []) @@ -2293,7 +2302,8 @@ public function unlisten() { * * @throws Exception */ - protected function parseSocketAddress() { + protected function parseSocketAddress(): ?string + { if (!$this->socketName) { return null; } @@ -2358,7 +2368,7 @@ public function resumeAccept() * * @return string */ - public function getSocketName() + public function getSocketName(): string { return $this->socketName ? \lcfirst($this->socketName) : 'none'; } @@ -2487,7 +2497,7 @@ public function acceptTcpConnection($socket) * @param resource $socket * @return bool */ - public function acceptUdpConnection($socket) + public function acceptUdpConnection($socket): bool { \set_error_handler(function(){}); $recvBuffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); @@ -2542,13 +2552,13 @@ public function acceptUdpConnection($socket) * @param int $masterPid * @return bool */ - protected static function checkMasterIsAlive($masterPid) + protected static function checkMasterIsAlive(int $masterPid): bool { if (empty($masterPid)) { return false; } - $masterIsAlive = $masterPid && \posix_kill((int) $masterPid, 0) && \posix_getpid() !== $masterPid; + $masterIsAlive = $masterPid && \posix_kill($masterPid, 0) && \posix_getpid() !== $masterPid; if (!$masterIsAlive) { return false; } From 97919e65df3cf417d16849e1c20fb068d86cd3eb Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 11:59:28 +0800 Subject: [PATCH 0811/1216] format --- src/Connection/AsyncTcpConnection.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index cd4040513..c5542c279 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -14,10 +14,10 @@ namespace Workerman\Connection; +use Exception; use Throwable; use Workerman\Timer; use Workerman\Worker; -use Exception; /** * AsyncTcpConnection. @@ -215,22 +215,22 @@ public function connect() $this->remoteAddress = $this->remoteHost . ':' . $this->remotePort; } // Open socket connection asynchronously. - if ($this->proxySocks5){ + if ($this->proxySocks5) { $this->contextOption['ssl']['peer_name'] = $this->remoteHost; $context = \stream_context_create($this->contextOption); $this->socket = \stream_socket_client("tcp://{$this->proxySocks5}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); - fwrite($this->socket,chr(5) . chr(1) . chr(0)); + fwrite($this->socket, chr(5) . chr(1) . chr(0)); fread($this->socket, 512); - fwrite($this->socket,chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); + fwrite($this->socket, chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); fread($this->socket, 512); - }else if($this->proxyHttp){ + } else if ($this->proxyHttp) { $this->contextOption['ssl']['peer_name'] = $this->remoteHost; $context = \stream_context_create($this->contextOption); $this->socket = \stream_socket_client("tcp://{$this->proxyHttp}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); $str = "CONNECT {$this->remoteHost}:{$this->remotePort} HTTP/1.1\n"; $str .= "Host: {$this->remoteHost}:{$this->remotePort}\n"; $str .= "Proxy-Connection: keep-alive\n"; - fwrite($this->socket,$str); + fwrite($this->socket, $str); fread($this->socket, 512); } else if ($this->contextOption) { $context = \stream_context_create($this->contextOption); From 37265a0d182f9439614c80be0dc4045d11637719 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 12:06:16 +0800 Subject: [PATCH 0812/1216] format --- src/Connection/AsyncTcpConnection.php | 200 ++++++++++++++------------ 1 file changed, 105 insertions(+), 95 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index c5542c279..d1b54e63a 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -15,92 +15,118 @@ namespace Workerman\Connection; use Exception; +use stdClass; use Throwable; use Workerman\Timer; use Workerman\Worker; +use function class_exists; +use function explode; +use function function_exists; +use function is_resource; +use function method_exists; +use function microtime; +use function parse_url; +use function socket_import_stream; +use function socket_set_option; +use function stream_context_create; +use function stream_set_blocking; +use function stream_set_read_buffer; +use function stream_socket_client; +use function stream_socket_get_name; +use function ucfirst; +use const DIRECTORY_SEPARATOR; +use const PHP_INT_MAX; +use const SO_KEEPALIVE; +use const SOL_SOCKET; +use const SOL_TCP; +use const STREAM_CLIENT_ASYNC_CONNECT; +use const TCP_NODELAY; /** * AsyncTcpConnection. */ class AsyncTcpConnection extends TcpConnection { + /** + * PHP built-in protocols. + * + * @var array + */ + const BUILD_IN_TRANSPORTS = [ + 'tcp' => 'tcp', + 'udp' => 'udp', + 'unix' => 'unix', + 'ssl' => 'ssl', + 'sslv2' => 'sslv2', + 'sslv3' => 'sslv3', + 'tls' => 'tls' + ]; /** * Emitted when socket connection is successfully established. * * @var ?callable */ public $onConnect = null; - /** * Emitted when websocket handshake completed (Only work when protocol is ws). * * @var ?callable */ public $onWebSocketConnect = null; - /** * Transport layer protocol. * * @var string */ public string $transport = 'tcp'; - /** * Socks5 proxy. * * @var string */ public string $proxySocks5 = ''; - /** * Http proxy. * * @var string */ public string $proxyHttp = ''; - /** * Status. * * @var int */ protected int $status = self::STATUS_INITIAL; - /** * Remote host. * * @var string */ protected string $remoteHost = ''; - /** * Remote port. * * @var int */ protected int $remotePort = 80; - /** * Connect start time. * * @var float */ protected float $connectStartTime = 0; - /** * Remote URI. * * @var string */ protected string $remoteURI = ''; - /** * Context option. * * @var array */ protected array $contextOption = []; - /** * Reconnect timer. * @@ -108,22 +134,6 @@ class AsyncTcpConnection extends TcpConnection */ protected int $reconnectTimer = 0; - - /** - * PHP built-in protocols. - * - * @var array - */ - const BUILD_IN_TRANSPORTS = [ - 'tcp' => 'tcp', - 'udp' => 'udp', - 'unix' => 'unix', - 'ssl' => 'ssl', - 'sslv2' => 'sslv2', - 'sslv3' => 'sslv3', - 'tls' => 'tls' - ]; - /** * Construct. * @@ -133,14 +143,14 @@ class AsyncTcpConnection extends TcpConnection */ public function __construct(string $remoteAddress, array $contextOption = []) { - $addressInfo = \parse_url($remoteAddress); + $addressInfo = parse_url($remoteAddress); if (!$addressInfo) { - list($scheme, $this->remoteAddress) = \explode(':', $remoteAddress, 2); + list($scheme, $this->remoteAddress) = explode(':', $remoteAddress, 2); if ('unix' === strtolower($scheme)) { $this->remoteAddress = substr($remoteAddress, strpos($remoteAddress, '/') + 2); } if (!$this->remoteAddress) { - Worker::safeEcho(new \Exception('bad remote_address')); + Worker::safeEcho(new Exception('bad remote_address')); } } else { if (!isset($addressInfo['port'])) { @@ -164,16 +174,16 @@ public function __construct(string $remoteAddress, array $contextOption = []) } $this->id = $this->realId = self::$idRecorder++; - if (\PHP_INT_MAX === self::$idRecorder) { + if (PHP_INT_MAX === self::$idRecorder) { self::$idRecorder = 0; } // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { - $scheme = \ucfirst($scheme); + $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; - if (!\class_exists($this->protocol)) { + if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!\class_exists($this->protocol)) { + if (!class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } @@ -187,7 +197,28 @@ public function __construct(string $remoteAddress, array $contextOption = []) $this->maxPackageSize = self::$defaultMaxPackageSize; $this->contextOption = $contextOption; static::$connections[$this->realId] = $this; - $this->context = new \stdClass; + $this->context = new stdClass; + } + + /** + * Reconnect. + * + * @param int $after + * @return void + * @throws Throwable + */ + public function reconnect(int $after = 0) + { + $this->status = self::STATUS_INITIAL; + static::$connections[$this->realId] = $this; + if ($this->reconnectTimer) { + Timer::del($this->reconnectTimer); + } + if ($after > 0) { + $this->reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); + return; + } + $this->connect(); } /** @@ -208,7 +239,7 @@ public function connect() } $this->status = self::STATUS_CONNECTING; - $this->connectStartTime = \microtime(true); + $this->connectStartTime = microtime(true); if ($this->transport !== 'unix') { if (!$this->remotePort) { $this->remotePort = $this->transport === 'ssl' ? 443 : 80; @@ -217,36 +248,36 @@ public function connect() // Open socket connection asynchronously. if ($this->proxySocks5) { $this->contextOption['ssl']['peer_name'] = $this->remoteHost; - $context = \stream_context_create($this->contextOption); - $this->socket = \stream_socket_client("tcp://{$this->proxySocks5}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + $context = stream_context_create($this->contextOption); + $this->socket = stream_socket_client("tcp://$this->proxySocks5", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); fwrite($this->socket, chr(5) . chr(1) . chr(0)); fread($this->socket, 512); fwrite($this->socket, chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); fread($this->socket, 512); } else if ($this->proxyHttp) { $this->contextOption['ssl']['peer_name'] = $this->remoteHost; - $context = \stream_context_create($this->contextOption); - $this->socket = \stream_socket_client("tcp://{$this->proxyHttp}", $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); - $str = "CONNECT {$this->remoteHost}:{$this->remotePort} HTTP/1.1\n"; - $str .= "Host: {$this->remoteHost}:{$this->remotePort}\n"; + $context = stream_context_create($this->contextOption); + $this->socket = stream_socket_client("tcp://$this->proxyHttp", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); + $str = "CONNECT $this->remoteHost:$this->remotePort HTTP/1.1\n"; + $str .= "Host: $this->remoteHost:$this->remotePort\n"; $str .= "Proxy-Connection: keep-alive\n"; fwrite($this->socket, $str); fread($this->socket, 512); } else if ($this->contextOption) { - $context = \stream_context_create($this->contextOption); - $this->socket = \stream_socket_client("tcp://{$this->remoteHost}:{$this->remotePort}", - $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context); + $context = stream_context_create($this->contextOption); + $this->socket = stream_socket_client("tcp://$this->remoteHost:$this->remotePort", + $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); } else { - $this->socket = \stream_socket_client("tcp://{$this->remoteHost}:{$this->remotePort}", - $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT); + $this->socket = stream_socket_client("tcp://$this->remoteHost:$this->remotePort", + $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT); } } else { - $this->socket = \stream_socket_client("{$this->transport}://{$this->remoteAddress}", $errno, $errstr, 0, - \STREAM_CLIENT_ASYNC_CONNECT); + $this->socket = stream_socket_client("$this->transport://$this->remoteAddress", $errno, $err_str, 0, + STREAM_CLIENT_ASYNC_CONNECT); } // If failed attempt to emit onError callback. - if (!$this->socket || !\is_resource($this->socket)) { - $this->emitError(static::CONNECT_FAIL, $errstr); + if (!$this->socket || !is_resource($this->socket)) { + $this->emitError(static::CONNECT_FAIL, $err_str); if ($this->status === self::STATUS_CLOSING) { $this->destroy(); } @@ -258,30 +289,29 @@ public function connect() // Add socket to global event loop waiting connection is successfully established or faild. $this->eventLoop->onWritable($this->socket, [$this, 'checkConnection']); // For windows. - if (\DIRECTORY_SEPARATOR === '\\' && \method_exists($this->eventLoop, 'onExcept')) { + if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'onExcept')) { $this->eventLoop->onExcept($this->socket, [$this, 'checkConnection']); } } /** - * Reconnect. + * Try to emit onError callback. * - * @param int $after + * @param int $code + * @param mixed $msg * @return void * @throws Throwable */ - public function reconnect(int $after = 0) + protected function emitError(int $code, mixed $msg) { - $this->status = self::STATUS_INITIAL; - static::$connections[$this->realId] = $this; - if ($this->reconnectTimer) { - Timer::del($this->reconnectTimer); - } - if ($after > 0) { - $this->reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); - return; + $this->status = self::STATUS_CLOSING; + if ($this->onError) { + try { + ($this->onError)($this, $code, $msg); + } catch (Throwable $e) { + $this->error($e); + } } - $this->connect(); } /** @@ -315,26 +345,6 @@ public function getRemoteURI(): string return $this->remoteURI; } - /** - * Try to emit onError callback. - * - * @param int $code - * @param mixed $msg - * @return void - * @throws Throwable - */ - protected function emitError(int $code, mixed $msg) - { - $this->status = self::STATUS_CLOSING; - if ($this->onError) { - try { - ($this->onError)($this, $code, $msg); - } catch (Throwable $e) { - $this->error($e); - } - } - } - /** * Check connection is successfully established or faild. * @@ -344,7 +354,7 @@ protected function emitError(int $code, mixed $msg) public function checkConnection() { // Remove EV_EXPECT for windows. - if (\DIRECTORY_SEPARATOR === '\\' && \method_exists($this->eventLoop, 'offExcept')) { + if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { $this->eventLoop->offExcept($this->socket); } // Remove write listener. @@ -355,18 +365,18 @@ public function checkConnection() } // Check socket state. - if ($address = \stream_socket_get_name($this->socket, true)) { + if ($address = stream_socket_get_name($this->socket, true)) { // Nonblocking. - \stream_set_blocking($this->socket, false); + stream_set_blocking($this->socket, false); // Compatible with hhvm - if (\function_exists('stream_set_read_buffer')) { - \stream_set_read_buffer($this->socket, 0); + if (function_exists('stream_set_read_buffer')) { + stream_set_read_buffer($this->socket, 0); } // Try to open keepalive for tcp and disable Nagle algorithm. - if (\function_exists('socket_import_stream') && $this->transport === 'tcp') { - $rawSocket = \socket_import_stream($this->socket); - \socket_set_option($rawSocket, \SOL_SOCKET, \SO_KEEPALIVE, 1); - \socket_set_option($rawSocket, \SOL_TCP, \TCP_NODELAY, 1); + if (function_exists('socket_import_stream') && $this->transport === 'tcp') { + $rawSocket = socket_import_stream($this->socket); + socket_set_option($rawSocket, SOL_SOCKET, SO_KEEPALIVE, 1); + socket_set_option($rawSocket, SOL_TCP, TCP_NODELAY, 1); } // SSL handshake. if ($this->transport === 'ssl') { @@ -395,7 +405,7 @@ public function checkConnection() } } // Try to emit protocol::onConnect - if ($this->protocol && \method_exists($this->protocol, 'onConnect')) { + if ($this->protocol && method_exists($this->protocol, 'onConnect')) { try { [$this->protocol, 'onConnect']($this); } catch (Throwable $e) { @@ -405,7 +415,7 @@ public function checkConnection() } else { // Connection failed. - $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(\microtime(true) - $this->connectStartTime, 4) . ' seconds'); + $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(microtime(true) - $this->connectStartTime, 4) . ' seconds'); if ($this->status === self::STATUS_CLOSING) { $this->destroy(); } From 767c4c211bbcc6c8eea6d571d4db73574d8c17ec Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 12:17:29 +0800 Subject: [PATCH 0813/1216] format --- src/Connection/AsyncUdpConnection.php | 92 +++++++++++++++----------- src/Connection/ConnectionInterface.php | 5 +- src/Connection/TcpConnection.php | 13 +++- src/Connection/UdpConnection.php | 3 + 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 83950043d..4cd8bda11 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -14,9 +14,22 @@ namespace Workerman\Connection; +use Exception; use Throwable; +use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; -use Exception; +use function class_exists; +use function explode; +use function fclose; +use function stream_context_create; +use function stream_set_blocking; +use function stream_socket_client; +use function stream_socket_recvfrom; +use function stream_socket_sendto; +use function strlen; +use function substr; +use function ucfirst; +use const STREAM_CLIENT_CONNECT; /** * AsyncUdpConnection. @@ -60,20 +73,20 @@ class AsyncUdpConnection extends UdpConnection public function __construct($remoteAddress, $contextOption = []) { // Get the application layer communication protocol and listening address. - list($scheme, $address) = \explode(':', $remoteAddress, 2); + list($scheme, $address) = explode(':', $remoteAddress, 2); // Check application layer protocol class. if ($scheme !== 'udp') { - $scheme = \ucfirst($scheme); + $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; - if (!\class_exists($this->protocol)) { + if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; - if (!\class_exists($this->protocol)) { + if (!class_exists($this->protocol)) { throw new Exception("class \\Protocols\\$scheme not exist"); } } } - $this->remoteAddress = \substr($address, 2); + $this->remoteAddress = substr($address, 2); $this->contextOption = $contextOption; } @@ -86,14 +99,16 @@ public function __construct($remoteAddress, $contextOption = []) */ public function baseRead($socket) { - $recvBuffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); + $recvBuffer = stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); if (false === $recvBuffer || empty($remoteAddress)) { return; } if ($this->onMessage) { if ($this->protocol) { - $recvBuffer = $this->protocol::decode($recvBuffer, $this); + /** @var ProtocolInterface $parser */ + $parser = $this->protocol; + $recvBuffer = $parser::decode($recvBuffer, $this); } ++ConnectionInterface::$statistics['total_request']; try { @@ -104,29 +119,6 @@ public function baseRead($socket) } } - /** - * Sends data on the connection. - * - * @param mixed $sendBuffer - * @param bool $raw - * @return void|boolean - * @throws Throwable - */ - public function send(mixed $sendBuffer, bool $raw = false) - { - if (false === $raw && $this->protocol) { - $parser = $this->protocol; - $sendBuffer = $parser::encode($sendBuffer, $this); - if ($sendBuffer === '') { - return; - } - } - if ($this->connected === false) { - $this->connect(); - } - return \strlen($sendBuffer) === \stream_socket_sendto($this->socket, $sendBuffer, 0); - } - /** * Close connection. * @@ -141,7 +133,7 @@ public function close(mixed $data = null, bool $raw = false) $this->send($data, $raw); } $this->eventLoop->offReadable($this->socket); - \fclose($this->socket); + fclose($this->socket); $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { @@ -154,6 +146,30 @@ public function close(mixed $data = null, bool $raw = false) $this->onConnect = $this->onMessage = $this->onClose = $this->eventLoop = $this->errorHandler = null; } + /** + * Sends data on the connection. + * + * @param mixed $sendBuffer + * @param bool $raw + * @return void|boolean + * @throws Throwable + */ + public function send(mixed $sendBuffer, bool $raw = false) + { + if (false === $raw && $this->protocol) { + /** @var ProtocolInterface $parser */ + $parser = $this->protocol; + $sendBuffer = $parser::encode($sendBuffer, $this); + if ($sendBuffer === '') { + return; + } + } + if ($this->connected === false) { + $this->connect(); + } + return strlen($sendBuffer) === stream_socket_sendto($this->socket, $sendBuffer, 0); + } + /** * Connect. * @@ -169,19 +185,19 @@ public function connect() $this->eventLoop = Worker::$globalEvent; } if ($this->contextOption) { - $context = \stream_context_create($this->contextOption); - $this->socket = \stream_socket_client("udp://{$this->remoteAddress}", $errno, $errmsg, - 30, \STREAM_CLIENT_CONNECT, $context); + $context = stream_context_create($this->contextOption); + $this->socket = stream_socket_client("udp://$this->remoteAddress", $errno, $errmsg, + 30, STREAM_CLIENT_CONNECT, $context); } else { - $this->socket = \stream_socket_client("udp://{$this->remoteAddress}", $errno, $errmsg); + $this->socket = stream_socket_client("udp://$this->remoteAddress", $errno, $errmsg); } if (!$this->socket) { - Worker::safeEcho(new \Exception($errmsg)); + Worker::safeEcho(new Exception($errmsg)); return; } - \stream_set_blocking($this->socket, false); + stream_set_blocking($this->socket, false); if ($this->onMessage) { $this->eventLoop->onWritable($this->socket, [$this, 'baseRead']); diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 148512565..c85cb5bfe 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -14,12 +14,9 @@ namespace Workerman\Connection; -use Closure; -use JetBrains\PhpStorm\Pure; use Throwable; use Workerman\Events\Event; use Workerman\Events\EventInterface; -use Workerman\Events\Revolt; use Workerman\Worker; /** @@ -58,7 +55,7 @@ abstract class ConnectionInterface * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. * - * @var ?class-string + * @var ?string */ public ?string $protocol = null; diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 24c74ae96..04544d149 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -18,6 +18,7 @@ use Throwable; use Workerman\Events\EventInterface; use Workerman\Protocols\Http\Request; +use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; /** @@ -355,7 +356,9 @@ public function send(mixed $sendBuffer, bool $raw = false) // Try to call protocol::encode($sendBuffer) before sending. if (false === $raw && $this->protocol !== null) { - $sendBuffer = $this->protocol::encode($sendBuffer, $this); + /** @var ProtocolInterface $parser */ + $parser = $this->protocol; + $sendBuffer = $parser::encode($sendBuffer, $this); if ($sendBuffer === '') { return; } @@ -628,7 +631,9 @@ public function baseRead($socket, bool $checkEof = true) } else { // Get current package length. try { - $this->currentPackageLength = $this->protocol::input($this->recvBuffer, $this); + /** @var ProtocolInterface $parser */ + $parser = $this->protocol; + $this->currentPackageLength = $parser::input($this->recvBuffer, $this); } catch (Throwable $e) { } // The packet length is unknown. @@ -663,7 +668,9 @@ public function baseRead($socket, bool $checkEof = true) $this->currentPackageLength = 0; try { // Decode request buffer before Emitting onMessage callback. - $request = $this->protocol::decode($oneRequestBuffer, $this); + /** @var ProtocolInterface $parser */ + $parser = $this->protocol; + $request = $parser::decode($oneRequestBuffer, $this); if (static::$enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) { $requests[$oneRequestBuffer] = $request; if (\count($requests) > 512) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 02cec6c57..ec2546298 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -14,6 +14,8 @@ namespace Workerman\Connection; +use Workerman\Protocols\ProtocolInterface; + /** * UdpConnection. */ @@ -62,6 +64,7 @@ public function __construct($socket, string $remoteAddress) public function send(mixed $sendBuffer, bool $raw = false) { if (false === $raw && $this->protocol) { + /** @var ProtocolInterface $parser */ $parser = $this->protocol; $sendBuffer = $parser::encode($sendBuffer, $this); if ($sendBuffer === '') { From ed7910473d3ef2c95e17edb5621ff64100c0516d Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 12:44:51 +0800 Subject: [PATCH 0814/1216] format --- src/Connection/TcpConnection.php | 151 +++++++++++++++++++------------ src/Connection/UdpConnection.php | 33 ++++--- src/Events/Ev.php | 18 ++-- 3 files changed, 122 insertions(+), 80 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 04544d149..979eb7197 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -14,18 +14,47 @@ namespace Workerman\Connection; +use JsonSerializable; use stdClass; use Throwable; use Workerman\Events\EventInterface; use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; +use function ceil; +use function count; +use function fclose; +use function feof; +use function fread; +use function function_exists; +use function fwrite; +use function is_object; +use function is_resource; +use function key; +use function method_exists; +use function posix_getpid; +use function restore_error_handler; +use function set_error_handler; +use function stream_set_blocking; +use function stream_set_read_buffer; +use function stream_socket_enable_crypto; +use function stream_socket_get_name; +use function strlen; +use function strrchr; +use function strrpos; +use function substr; +use function var_export; +use const PHP_INT_MAX; +use const STREAM_CRYPTO_METHOD_SSLv23_CLIENT; +use const STREAM_CRYPTO_METHOD_SSLv23_SERVER; +use const STREAM_CRYPTO_METHOD_SSLv2_CLIENT; +use const STREAM_CRYPTO_METHOD_SSLv2_SERVER; /** * TcpConnection. * @property string websocketType */ -class TcpConnection extends ConnectionInterface implements \JsonSerializable +class TcpConnection extends ConnectionInterface implements JsonSerializable { /** * Read buffer size. @@ -167,7 +196,7 @@ class TcpConnection extends ConnectionInterface implements \JsonSerializable * @var int */ public int $maxSendBufferSize = 1048576; - + /** * Context. * @@ -307,14 +336,14 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd { ++self::$statistics['connection_count']; $this->id = $this->realId = self::$idRecorder++; - if (self::$idRecorder === \PHP_INT_MAX) { + if (self::$idRecorder === PHP_INT_MAX) { self::$idRecorder = 0; } $this->socket = $socket; - \stream_set_blocking($this->socket, 0); + stream_set_blocking($this->socket, 0); // Compatible with hhvm - if (\function_exists('stream_set_read_buffer')) { - \stream_set_read_buffer($this->socket, 0); + if (function_exists('stream_set_read_buffer')) { + stream_set_read_buffer($this->socket, 0); } $this->eventLoop = $eventLoop; $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); @@ -386,22 +415,22 @@ public function send(mixed $sendBuffer, bool $raw = false) } $len = 0; try { - $len = @\fwrite($this->socket, $sendBuffer); + $len = @fwrite($this->socket, $sendBuffer); } catch (Throwable $e) { Worker::log($e); } // send successful. - if ($len === \strlen($sendBuffer)) { + if ($len === strlen($sendBuffer)) { $this->bytesWritten += $len; return true; } // Send only part of the data. if ($len > 0) { - $this->sendBuffer = \substr($sendBuffer, $len); + $this->sendBuffer = substr($sendBuffer, $len); $this->bytesWritten += $len; } else { // Connection closed? - if (!\is_resource($this->socket) || \feof($this->socket)) { + if (!is_resource($this->socket) || feof($this->socket)) { ++self::$statistics['send_fail']; if ($this->onError) { try { @@ -438,9 +467,9 @@ public function send(mixed $sendBuffer, bool $raw = false) */ public function getRemoteIp(): string { - $pos = \strrpos($this->remoteAddress, ':'); + $pos = strrpos($this->remoteAddress, ':'); if ($pos) { - return (string)\substr($this->remoteAddress, 0, $pos); + return substr($this->remoteAddress, 0, $pos); } return ''; } @@ -453,7 +482,7 @@ public function getRemoteIp(): string public function getRemotePort(): int { if ($this->remoteAddress) { - return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); + return (int)substr(strrchr($this->remoteAddress, ':'), 1); } return 0; } @@ -476,11 +505,11 @@ public function getRemoteAddress(): string public function getLocalIp(): string { $address = $this->getLocalAddress(); - $pos = \strrpos($address, ':'); + $pos = strrpos($address, ':'); if (!$pos) { return ''; } - return \substr($address, 0, $pos); + return substr($address, 0, $pos); } /** @@ -491,11 +520,11 @@ public function getLocalIp(): string public function getLocalPort(): int { $address = $this->getLocalAddress(); - $pos = \strrpos($address, ':'); + $pos = strrpos($address, ':'); if (!$pos) { return 0; } - return (int)\substr(\strrchr($address, ':'), 1); + return (int)substr(strrchr($address, ':'), 1); } /** @@ -505,10 +534,10 @@ public function getLocalPort(): int */ public function getLocalAddress(): string { - if (!\is_resource($this->socket)) { + if (!is_resource($this->socket)) { return ''; } - return (string)@\stream_socket_get_name($this->socket, false); + return (string)@stream_socket_get_name($this->socket, false); } /** @@ -518,7 +547,7 @@ public function getLocalAddress(): string */ public function getSendBufferQueueSize(): int { - return \strlen($this->sendBuffer); + return strlen($this->sendBuffer); } /** @@ -528,7 +557,7 @@ public function getSendBufferQueueSize(): int */ public function getRecvBufferQueueSize(): int { - return \strlen($this->recvBuffer); + return strlen($this->recvBuffer); } /** @@ -583,18 +612,18 @@ public function baseRead($socket, bool $checkEof = true) $buffer = ''; try { - $buffer = @\fread($socket, self::READ_BUFFER_SIZE); - } catch (Throwable $e) { + $buffer = @fread($socket, self::READ_BUFFER_SIZE); + } catch (Throwable) { } // Check connection closed. if ($buffer === '' || $buffer === false) { - if ($checkEof && (\feof($socket) || !\is_resource($socket) || $buffer === false)) { + if ($checkEof && (feof($socket) || !is_resource($socket) || $buffer === false)) { $this->destroy(); return; } } else { - $this->bytesRead += \strlen($buffer); + $this->bytesRead += strlen($buffer); if ($this->recvBuffer === '') { if (static::$enableCache && !isset($buffer[512]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; @@ -625,7 +654,7 @@ public function baseRead($socket, bool $checkEof = true) // The current packet length is known. if ($this->currentPackageLength) { // Data is not enough for a package. - if ($this->currentPackageLength > \strlen($this->recvBuffer)) { + if ($this->currentPackageLength > strlen($this->recvBuffer)) { break; } } else { @@ -634,19 +663,19 @@ public function baseRead($socket, bool $checkEof = true) /** @var ProtocolInterface $parser */ $parser = $this->protocol; $this->currentPackageLength = $parser::input($this->recvBuffer, $this); - } catch (Throwable $e) { + } catch (Throwable) { } // The packet length is unknown. if ($this->currentPackageLength === 0) { break; } elseif ($this->currentPackageLength > 0 && $this->currentPackageLength <= $this->maxPackageSize) { // Data is not enough for a package. - if ($this->currentPackageLength > \strlen($this->recvBuffer)) { + if ($this->currentPackageLength > strlen($this->recvBuffer)) { break; } } // Wrong package. else { - Worker::safeEcho('Error package. package_length=' . \var_export($this->currentPackageLength, true)); + Worker::safeEcho('Error package. package_length=' . var_export($this->currentPackageLength, true)); $this->destroy(); return; } @@ -655,14 +684,14 @@ public function baseRead($socket, bool $checkEof = true) // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if ($one = \strlen($this->recvBuffer) === $this->currentPackageLength) { + if ($one = strlen($this->recvBuffer) === $this->currentPackageLength) { $oneRequestBuffer = $this->recvBuffer; $this->recvBuffer = ''; } else { // Get a full package from the buffer. - $oneRequestBuffer = \substr($this->recvBuffer, 0, $this->currentPackageLength); + $oneRequestBuffer = substr($this->recvBuffer, 0, $this->currentPackageLength); // Remove the current package from receive buffer. - $this->recvBuffer = \substr($this->recvBuffer, $this->currentPackageLength); + $this->recvBuffer = substr($this->recvBuffer, $this->currentPackageLength); } // Reset the current packet length to 0. $this->currentPackageLength = 0; @@ -671,10 +700,10 @@ public function baseRead($socket, bool $checkEof = true) /** @var ProtocolInterface $parser */ $parser = $this->protocol; $request = $parser::decode($oneRequestBuffer, $this); - if (static::$enableCache && (!\is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) { + if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) { $requests[$oneRequestBuffer] = $request; - if (\count($requests) > 512) { - unset($requests[\key($requests)]); + if (count($requests) > 512) { + unset($requests[key($requests)]); } } ($this->onMessage)($this, $request); @@ -711,12 +740,13 @@ public function baseWrite() $len = 0; try { if ($this->transport === 'ssl') { - $len = @\fwrite($this->socket, $this->sendBuffer, 8192); + $len = @fwrite($this->socket, $this->sendBuffer, 8192); } else { - $len = @\fwrite($this->socket, $this->sendBuffer); + $len = @fwrite($this->socket, $this->sendBuffer); } - } catch (Throwable $e) {} - if ($len === \strlen($this->sendBuffer)) { + } catch (Throwable) { + } + if ($len === strlen($this->sendBuffer)) { $this->bytesWritten += $len; $this->eventLoop->offWritable($this->socket); $this->sendBuffer = ''; @@ -738,7 +768,7 @@ public function baseWrite() } if ($len > 0) { $this->bytesWritten += $len; - $this->sendBuffer = \substr($this->sendBuffer, $len); + $this->sendBuffer = substr($this->sendBuffer, $len); } else { ++self::$statistics['send_fail']; $this->destroy(); @@ -754,7 +784,7 @@ public function baseWrite() */ public function doSslHandshake($socket): bool|int { - if (\feof($socket)) { + if (feof($socket)) { $this->destroy(); return false; } @@ -771,19 +801,19 @@ public function doSslHandshake($socket): bool|int }*/ if ($async) { - $type = \STREAM_CRYPTO_METHOD_SSLv2_CLIENT | \STREAM_CRYPTO_METHOD_SSLv23_CLIENT; + $type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT | STREAM_CRYPTO_METHOD_SSLv23_CLIENT; } else { - $type = \STREAM_CRYPTO_METHOD_SSLv2_SERVER | \STREAM_CRYPTO_METHOD_SSLv23_SERVER; + $type = STREAM_CRYPTO_METHOD_SSLv2_SERVER | STREAM_CRYPTO_METHOD_SSLv23_SERVER; } // Hidden error. - \set_error_handler(function ($errno, $errstr, $file) { + set_error_handler(function ($errno, $err_str) { if (!Worker::$daemonize) { - Worker::safeEcho("SSL handshake error: $errstr \n"); + Worker::safeEcho("SSL handshake error: $err_str \n"); } }); - $ret = \stream_socket_enable_crypto($socket, true, $type); - \restore_error_handler(); + $ret = stream_socket_enable_crypto($socket, true, $type); + restore_error_handler(); // Negotiation has failed. if (false === $ret) { $this->destroy(); @@ -807,13 +837,13 @@ public function pipe(self $dest) $this->onMessage = function ($source, $data) use ($dest) { $dest->send($data); }; - $this->onClose = function ($source) use ($dest) { + $this->onClose = function () use ($dest) { $dest->close(); }; - $dest->onBufferFull = function ($dest) use ($source) { + $dest->onBufferFull = function () use ($source) { $source->pauseRecv(); }; - $dest->onBufferDrain = function ($dest) use ($source) { + $dest->onBufferDrain = function () use ($source) { $source->resumeRecv(); }; } @@ -826,7 +856,7 @@ public function pipe(self $dest) */ public function consumeRecvBuffer(int $length) { - $this->recvBuffer = \substr($this->recvBuffer, $length); + $this->recvBuffer = substr($this->recvBuffer, $length); } /** @@ -879,7 +909,7 @@ public function getSocket() */ protected function checkBufferWillFull() { - if ($this->maxSendBufferSize <= \strlen($this->sendBuffer)) { + if ($this->maxSendBufferSize <= strlen($this->sendBuffer)) { if ($this->onBufferFull) { try { ($this->onBufferFull)($this); @@ -899,7 +929,7 @@ protected function checkBufferWillFull() protected function bufferIsFull(): bool { // Buffer has been marked as full but still has data to send then the packet is discarded. - if ($this->maxSendBufferSize <= \strlen($this->sendBuffer)) { + if ($this->maxSendBufferSize <= strlen($this->sendBuffer)) { if ($this->onError) { try { ($this->onError)($this, static::SEND_FAIL, 'send buffer full and drop package'); @@ -940,8 +970,8 @@ public function destroy() // Close socket. try { - @\fclose($this->socket); - } catch (Throwable $e) { + @fclose($this->socket); + } catch (Throwable) { } $this->status = self::STATUS_CLOSED; @@ -954,7 +984,7 @@ public function destroy() } } // Try to emit protocol::onClose - if ($this->protocol && \method_exists($this->protocol, 'onClose')) { + if ($this->protocol && method_exists($this->protocol, 'onClose')) { try { ([$this->protocol, 'onClose'])($this); } catch (Throwable $e) { @@ -984,14 +1014,14 @@ public static function enableCache(bool $value = true) { static::$enableCache = $value; } - + /** * Get the json_encode information. * * @return array */ public function jsonSerialize(): array - { + { return [ 'id' => $this->id, 'status' => $this->getStatus(), @@ -1018,11 +1048,12 @@ public function __destruct() self::$statistics['connection_count']--; if (Worker::getGracefulStop()) { if (!isset($mod)) { - $mod = \ceil((self::$statistics['connection_count'] + 1) / 3); + $mod = ceil((self::$statistics['connection_count'] + 1) / 3); } if (0 === self::$statistics['connection_count'] % $mod) { - Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); + $pid = function_exists('posix_getpid') ? posix_getpid() : 0; + Worker::log('worker[' . $pid . '] remains ' . self::$statistics['connection_count'] . ' connection(s)'); } if (0 === self::$statistics['connection_count']) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index ec2546298..1bfeee809 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -14,12 +14,21 @@ namespace Workerman\Connection; +use JetBrains\PhpStorm\ArrayShape; +use JsonSerializable; use Workerman\Protocols\ProtocolInterface; +use function stream_socket_get_name; +use function stream_socket_sendto; +use function strlen; +use function strrchr; +use function strrpos; +use function substr; +use function trim; /** * UdpConnection. */ -class UdpConnection extends ConnectionInterface implements \JsonSerializable +class UdpConnection extends ConnectionInterface implements JsonSerializable { /** * Transport layer protocol. @@ -71,7 +80,7 @@ public function send(mixed $sendBuffer, bool $raw = false) return; } } - return \strlen($sendBuffer) === \stream_socket_sendto($this->socket, $sendBuffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); + return strlen($sendBuffer) === stream_socket_sendto($this->socket, $sendBuffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); } /** @@ -81,9 +90,9 @@ public function send(mixed $sendBuffer, bool $raw = false) */ public function getRemoteIp(): string { - $pos = \strrpos($this->remoteAddress, ':'); + $pos = strrpos($this->remoteAddress, ':'); if ($pos) { - return \trim(\substr($this->remoteAddress, 0, $pos), '[]'); + return trim(substr($this->remoteAddress, 0, $pos), '[]'); } return ''; } @@ -96,7 +105,7 @@ public function getRemoteIp(): string public function getRemotePort(): int { if ($this->remoteAddress) { - return (int)\substr(\strrchr($this->remoteAddress, ':'), 1); + return (int)substr(strrchr($this->remoteAddress, ':'), 1); } return 0; } @@ -119,11 +128,11 @@ public function getRemoteAddress(): string public function getLocalIp(): string { $address = $this->getLocalAddress(); - $pos = \strrpos($address, ':'); + $pos = strrpos($address, ':'); if (!$pos) { return ''; } - return \substr($address, 0, $pos); + return substr($address, 0, $pos); } /** @@ -134,11 +143,11 @@ public function getLocalIp(): string public function getLocalPort(): int { $address = $this->getLocalAddress(); - $pos = \strrpos($address, ':'); + $pos = strrpos($address, ':'); if (!$pos) { return 0; } - return (int)\substr(\strrchr($address, ':'), 1); + return (int)substr(strrchr($address, ':'), 1); } /** @@ -148,7 +157,7 @@ public function getLocalPort(): int */ public function getLocalAddress(): string { - return (string)@\stream_socket_get_name($this->socket, false); + return (string)@stream_socket_get_name($this->socket, false); } @@ -175,13 +184,13 @@ public function getSocket() { return $this->socket; } - + /** * Get the json_encode information. * * @return array */ - public function jsonSerialize(): array + #[ArrayShape(['transport' => "string", 'getRemoteIp' => "string", 'remotePort' => "int", 'getRemoteAddress' => "string", 'getLocalIp' => "string", 'getLocalPort' => "int", 'getLocalAddress' => "string", 'isIpV4' => "bool", 'isIpV6' => "bool"])] public function jsonSerialize(): array { return [ 'transport' => $this->transport, diff --git a/src/Events/Ev.php b/src/Events/Ev.php index ea1f1b604..d7f9e33eb 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -13,8 +13,10 @@ namespace Workerman\Events; -use Closure; -use EvWatcher; +use EvIo; +use EvSignal; +use EvTimer; +use function count; /** * Ev eventloop @@ -67,7 +69,7 @@ class Ev implements EventInterface public function delay(float $delay, callable $func, array $args = []): int { $timerId = self::$timerId; - $event = new \EvTimer($delay, 0, function () use ($func, $args, $timerId) { + $event = new EvTimer($delay, 0, function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); $func(...$args); }); @@ -101,7 +103,7 @@ public function offRepeat(int $timerId): bool */ public function repeat(float $interval, callable $func, array $args = []): int { - $event = new \EvTimer($interval, $interval, function () use ($func, $args) { + $event = new EvTimer($interval, $interval, function () use ($func, $args) { $func(...$args); }); $this->eventTimer[self::$timerId] = $event; @@ -114,7 +116,7 @@ public function repeat(float $interval, callable $func, array $args = []): int public function onReadable($stream, callable $func) { $fdKey = (int)$stream; - $event = new \EvIo($stream, \Ev::READ, function () use ($func, $stream) { + $event = new EvIo($stream, \Ev::READ, function () use ($func, $stream) { $func($stream); }); $this->readEvents[$fdKey] = $event; @@ -140,7 +142,7 @@ public function offReadable($stream): bool public function onWritable($stream, callable $func) { $fdKey = (int)$stream; - $event = new \EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { + $event = new EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { $func($stream); }); $this->readEvents[$fdKey] = $event; @@ -165,7 +167,7 @@ public function offWritable($stream): bool */ public function onSignal(int $signal, callable $func) { - $event = new \EvSignal($signal, function () use ($func, $signal) { + $event = new EvSignal($signal, function () use ($func, $signal) { $func($signal); }); $this->eventSignal[$signal] = $event; @@ -216,7 +218,7 @@ public function stop() */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** From 553e307ed3828ef36aa44c657ac34372cacd6924 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 12:56:35 +0800 Subject: [PATCH 0815/1216] format --- src/Events/Event.php | 16 ++++++------ src/Events/EventInterface.php | 4 +++ src/Events/Revolt.php | 15 ++++++++---- src/Events/Select.php | 46 ++++++++++++++++++++--------------- src/Events/Swoole.php | 34 +++++++++++++++----------- src/Events/Swow.php | 31 ++++++++++++----------- 6 files changed, 86 insertions(+), 60 deletions(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index 653e5c7ff..8ec4217d1 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -14,8 +14,10 @@ namespace Workerman\Events; -use Throwable; use EventBase; +use Throwable; +use function class_exists; +use function count; /** * libevent eventloop @@ -76,13 +78,13 @@ class Event implements EventInterface */ public function __construct() { - if (\class_exists('\\\\Event', false)) { + if (class_exists('\\\\Event', false)) { $className = '\\\\Event'; } else { $className = '\Event'; } $this->eventClassName = $className; - if (\class_exists('\\\\EventBase', false)) { + if (class_exists('\\\\EventBase', false)) { $className = '\\\\EventBase'; } else { $className = '\EventBase'; @@ -100,7 +102,7 @@ public function delay(float $delay, callable $func, array $args = []): int $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args) { try { $func(...$args); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } }); @@ -142,7 +144,7 @@ public function repeat(float $interval, callable $func, array $args = []): int $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, function () use ($func, $args) { try { $func(...$args); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->error($e); } }); @@ -269,7 +271,7 @@ public function stop() */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** @@ -300,7 +302,7 @@ public function error(Throwable $e) throw new $e; } ($this->errorHandler)($e); - } catch (\Throwable $e) { + } catch (Throwable $e) { // Cannot trigger an exception in the Event callback, otherwise it will cause an infinite loop echo $e; } diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index e546a88f1..abc6dfc2b 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -13,6 +13,8 @@ */ namespace Workerman\Events; +use Throwable; + interface EventInterface { /** @@ -82,6 +84,7 @@ public function offWritable($stream): bool; * @param int $signal * @param callable $func * @return void + * @throws Throwable */ public function onSignal(int $signal, callable $func); @@ -101,6 +104,7 @@ public function deleteAllTimer(); /** * Run the event loop. * @return void + * @throws Throwable */ public function run(); diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 5c99430f5..634a6a99c 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -14,8 +14,11 @@ namespace Workerman\Events; -use Revolt\EventLoop\Driver; use Revolt\EventLoop; +use Revolt\EventLoop\Driver; +use function count; +use function function_exists; +use function pcntl_signal; /** * Revolt eventloop @@ -66,7 +69,9 @@ public function __construct() } /** - * {@inheritdoc} + * Get driver + * + * @return Driver */ public function driver(): Driver { @@ -90,8 +95,8 @@ public function stop() $this->driver->cancel($cbId); } $this->driver->stop(); - if (\function_exists('pcntl_signal')) { - \pcntl_signal(SIGINT, SIG_IGN); + if (function_exists('pcntl_signal')) { + pcntl_signal(SIGINT, SIG_IGN); } } @@ -249,7 +254,7 @@ public function deleteAllTimer() */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** diff --git a/src/Events/Select.php b/src/Events/Select.php index be413b6df..3636e1bef 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -16,6 +16,12 @@ use SplPriorityQueue; use Throwable; +use function count; +use function max; +use function microtime; +use function pcntl_signal; +use function pcntl_signal_dispatch; +use const DIRECTORY_SEPARATOR; /** * select eventloop @@ -126,10 +132,10 @@ public function __construct() public function delay(float $delay, callable $func, array $args = []): int { $timerId = $this->timerId++; - $runTime = \microtime(true) + $delay; + $runTime = microtime(true) + $delay; $this->scheduler->insert($timerId, -$runTime); $this->eventTimer[$timerId] = [$func, $args]; - $selectTimeout = ($runTime - \microtime(true)) * 1000000; + $selectTimeout = ($runTime - microtime(true)) * 1000000; $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; if ($this->selectTimeout > $selectTimeout) { $this->selectTimeout = $selectTimeout; @@ -143,10 +149,10 @@ public function delay(float $delay, callable $func, array $args = []): int public function repeat(float $interval, callable $func, array $args = []): int { $timerId = $this->timerId++; - $runTime = \microtime(true) + $interval; + $runTime = microtime(true) + $interval; $this->scheduler->insert($timerId, -$runTime); $this->eventTimer[$timerId] = [$func, $args, $interval]; - $selectTimeout = ($runTime - \microtime(true)) * 1000000; + $selectTimeout = ($runTime - microtime(true)) * 1000000; $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; if ($this->selectTimeout > $selectTimeout) { $this->selectTimeout = $selectTimeout; @@ -179,10 +185,10 @@ public function offRepeat(int $timerId): bool */ public function onReadable($stream, callable $func) { - $count = \count($this->readFds); + $count = count($this->readFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; - } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } $fdKey = (int)$stream; @@ -208,10 +214,10 @@ public function offReadable($stream): bool */ public function onWritable($stream, callable $func) { - $count = \count($this->writeFds); + $count = count($this->writeFds); if ($count >= 1024) { echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; - } else if (\DIRECTORY_SEPARATOR !== '/' && $count >= 256) { + } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { echo "Warning: system call select exceeded the maximum number of connections 256.\n"; } $fdKey = (int)$stream; @@ -233,7 +239,7 @@ public function offWritable($stream): bool } /** - * {@inheritdoc} + * On except. */ public function onExcept($stream, $func) { @@ -243,7 +249,7 @@ public function onExcept($stream, $func) } /** - * {@inheritdoc} + * Off except. */ public function offExcept($stream): bool { @@ -260,11 +266,11 @@ public function offExcept($stream): bool */ public function onSignal(int $signal, callable $func) { - if (\DIRECTORY_SEPARATOR !== '/') { + if (!function_exists('pcntl_signal')) { return; } $this->signalEvents[$signal] = $func; - \pcntl_signal($signal, [$this, 'signalHandler']); + pcntl_signal($signal, [$this, 'signalHandler']); } /** @@ -272,10 +278,10 @@ public function onSignal(int $signal, callable $func) */ public function offSignal(int $signal): bool { - if (\DIRECTORY_SEPARATOR !== '/') { + if (!function_exists('pcntl_signal')) { return false; } - \pcntl_signal($signal, SIG_IGN); + pcntl_signal($signal, SIG_IGN); if (isset($this->signalEvents[$signal])) { unset($this->signalEvents[$signal]); return true; @@ -306,7 +312,7 @@ protected function tick() $schedulerData = $this->scheduler->top(); $timerId = $schedulerData['data']; $nextRunTime = -$schedulerData['priority']; - $timeNow = \microtime(true); + $timeNow = microtime(true); $this->selectTimeout = (int)(($nextRunTime - $timeNow) * 1000000); if ($this->selectTimeout <= 0) { $this->scheduler->extract(); @@ -339,8 +345,8 @@ protected function tick() if (!$this->scheduler->isEmpty()) { $schedulerData = $this->scheduler->top(); $nextRunTime = -$schedulerData['priority']; - $timeNow = \microtime(true); - $this->selectTimeout = \max((int)(($nextRunTime - $timeNow) * 1000000), 0); + $timeNow = microtime(true); + $this->selectTimeout = max((int)(($nextRunTime - $timeNow) * 1000000), 0); return; } $this->selectTimeout = 100000000; @@ -369,7 +375,7 @@ public function run() // Waiting read/write/signal/timeout events. try { @stream_select($read, $write, $except, 0, $this->selectTimeout); - } catch (Throwable $e) { + } catch (Throwable) { } } else { $this->selectTimeout >= 1 && usleep($this->selectTimeout); @@ -402,7 +408,7 @@ public function run() if (!empty($this->signalEvents)) { // Calls signal handlers for pending signals - \pcntl_signal_dispatch(); + pcntl_signal_dispatch(); } } } @@ -426,7 +432,7 @@ public function stop() */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index fff765386..5782567be 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -13,10 +13,14 @@ namespace Workerman\Events; -use Throwable; use Swoole\Event; -use Swoole\Timer; use Swoole\Process; +use Swoole\Timer; +use Throwable; +use function count; +use function posix_kill; +use const SWOOLE_EVENT_READ; +use const SWOOLE_EVENT_WRITE; class Swoole implements EventInterface { @@ -49,7 +53,8 @@ class Swoole implements EventInterface public function __construct() { // Avoid process exit due to no listening - Timer::tick(100000000, function () {}); + Timer::tick(100000000, function () { + }); } /** @@ -117,12 +122,12 @@ public function onReadable($stream, callable $func) { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, $func, null, \SWOOLE_EVENT_READ); + Event::add($stream, $func, null, SWOOLE_EVENT_READ); } else { if (isset($this->writeEvents[$fd])) { - Event::set($stream, $func, null, \SWOOLE_EVENT_READ | \SWOOLE_EVENT_WRITE); + Event::set($stream, $func, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); } else { - Event::set($stream, $func, null, \SWOOLE_EVENT_READ); + Event::set($stream, $func, null, SWOOLE_EVENT_READ); } } $this->readEvents[$fd] = $stream; @@ -142,7 +147,7 @@ public function offReadable($stream): bool Event::del($stream); return true; } - Event::set($stream, null, null, \SWOOLE_EVENT_WRITE); + Event::set($stream, null, null, SWOOLE_EVENT_WRITE); return true; } @@ -153,12 +158,12 @@ public function onWritable($stream, callable $func) { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, null, $func, \SWOOLE_EVENT_WRITE); + Event::add($stream, null, $func, SWOOLE_EVENT_WRITE); } else { if (isset($this->readEvents[$fd])) { - Event::set($stream, null, $func, \SWOOLE_EVENT_WRITE | \SWOOLE_EVENT_READ); + Event::set($stream, null, $func, SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); } else { - Event::set($stream, null, $func, \SWOOLE_EVENT_WRITE); + Event::set($stream, null, $func, SWOOLE_EVENT_WRITE); } } $this->writeEvents[$fd] = $stream; @@ -178,7 +183,7 @@ public function offWritable($stream): bool Event::del($stream); return true; } - Event::set($stream, null, null, \SWOOLE_EVENT_READ); + Event::set($stream, null, null, SWOOLE_EVENT_READ); return true; } @@ -195,7 +200,8 @@ public function onSignal(int $signal, callable $func) */ public function offSignal(int $signal): bool { - return Process::signal($signal, function () {}); + return Process::signal($signal, function () { + }); } /** @@ -224,7 +230,7 @@ public function run() public function stop() { Event::exit(); - \posix_kill(posix_getpid(), SIGINT); + posix_kill(posix_getpid(), SIGINT); } /** @@ -234,7 +240,7 @@ public function stop() */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** diff --git a/src/Events/Swow.php b/src/Events/Swow.php index f2682355c..1964d60ff 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -7,6 +7,8 @@ use Swow\Signal; use Swow\SignalException; use Throwable; +use function count; +use function is_resource; use function max; use function msleep; use function stream_poll_one; @@ -54,7 +56,7 @@ class Swow implements EventInterface */ public function getTimerCount(): int { - return \count($this->eventTimer); + return count($this->eventTimer); } /** @@ -62,15 +64,15 @@ public function getTimerCount(): int */ public function delay(float $delay, callable $func, array $args = []): int { - $t = (int) ($delay * 1000); + $t = (int)($delay * 1000); $t = max($t, 1); $that = $this; $coroutine = Coroutine::run(function () use ($t, $func, $args, $that): void { msleep($t); unset($this->eventTimer[Coroutine::getCurrent()->getId()]); try { - $func(...(array) $args); - } catch (\Throwable $e) { + $func(...$args); + } catch (Throwable $e) { $that->error($e); } }); @@ -84,15 +86,15 @@ public function delay(float $delay, callable $func, array $args = []): int */ public function repeat(float $interval, callable $func, array $args = []): int { - $t = (int) ($interval * 1000); + $t = (int)($interval * 1000); $t = max($t, 1); $that = $this; $coroutine = Coroutine::run(static function () use ($t, $func, $args, $that): void { while (true) { msleep($t); try { - $func(...(array) $args); - } catch (\Throwable $e) { + $func(...$args); + } catch (Throwable $e) { $that->error($e); } } @@ -141,7 +143,7 @@ public function deleteAllTimer() */ public function onReadable($stream, callable $func) { - $fd = (int) $stream; + $fd = (int)$stream; if (isset($this->readEvents[$fd])) { $this->offReadable($stream); } @@ -149,7 +151,7 @@ public function onReadable($stream, callable $func) try { $this->readEvents[$fd] = Coroutine::getCurrent(); while (true) { - if (!\is_resource($stream)) { + if (!is_resource($stream)) { $this->offReadable($stream); break; } @@ -177,7 +179,7 @@ public function onReadable($stream, callable $func) public function offReadable($stream): bool { // 在当前协程执行 $coroutine->kill() 会导致不可预知问题,所以没有使用$coroutine->kill() - $fd = (int) $stream; + $fd = (int)$stream; if (isset($this->readEvents[$fd])) { unset($this->readEvents[$fd]); return true; @@ -190,7 +192,7 @@ public function offReadable($stream): bool */ public function onWritable($stream, callable $func) { - $fd = (int) $stream; + $fd = (int)$stream; if (isset($this->writeEvents[$fd])) { $this->offWritable($stream); } @@ -221,7 +223,7 @@ public function onWritable($stream, callable $func) */ public function offWritable($stream): bool { - $fd = (int) $stream; + $fd = (int)$stream; if (isset($this->writeEvents[$fd])) { unset($this->writeEvents[$fd]); return true; @@ -244,7 +246,8 @@ public function onSignal(int $signal, callable $func) break; } $func($signal); - } catch (SignalException) {} + } catch (SignalException) { + } } }); } @@ -278,7 +281,7 @@ public function stop() { Coroutine::killAll(); } - + /** * {@inheritdoc} */ From 300640b229b29e3e72d3f5af6a1fd505325b7afc Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 13:01:05 +0800 Subject: [PATCH 0816/1216] format session --- src/Protocols/Http/Chunk.php | 5 +- .../Http/Session/FileSessionHandler.php | 61 ++++++++++++------- .../Session/RedisClusterSessionHandler.php | 7 ++- .../Http/Session/RedisSessionHandler.php | 11 ++-- 4 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 72c87af8f..87b46cb19 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -15,6 +15,9 @@ namespace Workerman\Protocols\Http; +use function dechex; +use function strlen; + /** * Class Chunk * @package Workerman\Protocols\Http @@ -45,6 +48,6 @@ public function __construct(string $buffer) */ public function __toString() { - return \dechex(\strlen($this->buffer)) . "\r\n$this->buffer\r\n"; + return dechex(strlen($this->buffer)) . "\r\n$this->buffer\r\n"; } } \ No newline at end of file diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index e84bf61a5..49b1842d6 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -15,6 +15,21 @@ namespace Workerman\Protocols\Http\Session; use Workerman\Protocols\Http\Session; +use function clearstatcache; +use function file_get_contents; +use function file_put_contents; +use function filemtime; +use function glob; +use function is_dir; +use function is_file; +use function mkdir; +use function rename; +use function session_save_path; +use function strlen; +use function sys_get_temp_dir; +use function time; +use function touch; +use function unlink; /** * Class FileSessionHandler @@ -41,9 +56,9 @@ class FileSessionHandler implements SessionHandlerInterface */ public static function init() { - $savePath = @\session_save_path(); + $savePath = @session_save_path(); if (!$savePath || str_starts_with($savePath, 'tcp://')) { - $savePath = \sys_get_temp_dir(); + $savePath = sys_get_temp_dir(); } static::sessionSavePath($savePath); } @@ -73,13 +88,13 @@ public function open(string $savePath, string $name): bool public function read(string $sessionId): string { $sessionFile = static::sessionFile($sessionId); - \clearstatcache(); - if (\is_file($sessionFile)) { - if (\time() - \filemtime($sessionFile) > Session::$lifetime) { - \unlink($sessionFile); + clearstatcache(); + if (is_file($sessionFile)) { + if (time() - filemtime($sessionFile) > Session::$lifetime) { + unlink($sessionFile); return ''; } - $data = \file_get_contents($sessionFile); + $data = file_get_contents($sessionFile); return $data ?: ''; } return ''; @@ -91,10 +106,10 @@ public function read(string $sessionId): string public function write(string $sessionId, string $sessionData): bool { $tempFile = static::$sessionSavePath . uniqid(bin2hex(random_bytes(8)), true); - if (!\file_put_contents($tempFile, $sessionData)) { + if (!file_put_contents($tempFile, $sessionData)) { return false; } - return \rename($tempFile, static::sessionFile($sessionId)); + return rename($tempFile, static::sessionFile($sessionId)); } /** @@ -103,21 +118,21 @@ public function write(string $sessionId, string $sessionData): bool * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php * @see https://www.php.net/manual/zh/function.touch.php * - * @param string $id Session id. + * @param string $sessionId Session id. * @param string $data Session Data. * * @return bool */ - public function updateTimestamp(string $id, string $data = ""): bool + public function updateTimestamp(string $sessionId, string $data = ""): bool { - $sessionFile = static::sessionFile($id); + $sessionFile = static::sessionFile($sessionId); if (!file_exists($sessionFile)) { return false; } // set file modify time to current time - $setModifyTime = \touch($sessionFile); + $setModifyTime = touch($sessionFile); // clear file stat cache - \clearstatcache(); + clearstatcache(); return $setModifyTime; } @@ -135,8 +150,8 @@ public function close(): bool public function destroy(string $sessionId): bool { $sessionFile = static::sessionFile($sessionId); - if (\is_file($sessionFile)) { - \unlink($sessionFile); + if (is_file($sessionFile)) { + unlink($sessionFile); } return true; } @@ -146,10 +161,10 @@ public function destroy(string $sessionId): bool */ public function gc(int $maxLifetime): bool { - $timeNow = \time(); - foreach (\glob(static::$sessionSavePath . static::$sessionFilePrefix . '*') as $file) { - if (\is_file($file) && $timeNow - \filemtime($file) > $maxLifetime) { - \unlink($file); + $timeNow = time(); + foreach (glob(static::$sessionSavePath . static::$sessionFilePrefix . '*') as $file) { + if (is_file($file) && $timeNow - filemtime($file) > $maxLifetime) { + unlink($file); } } return true; @@ -175,12 +190,12 @@ protected static function sessionFile(string $sessionId): string public static function sessionSavePath(string $path): string { if ($path) { - if ($path[\strlen($path) - 1] !== DIRECTORY_SEPARATOR) { + if ($path[strlen($path) - 1] !== DIRECTORY_SEPARATOR) { $path .= DIRECTORY_SEPARATOR; } static::$sessionSavePath = $path; - if (!\is_dir($path)) { - \mkdir($path, 0777, true); + if (!is_dir($path)) { + mkdir($path, 0777, true); } } return $path; diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 1e288d102..5e0846062 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -14,7 +14,8 @@ namespace Workerman\Protocols\Http\Session; -use Workerman\Protocols\Http\Session; +use Redis; +use RedisCluster; use RedisClusterException; class RedisClusterSessionHandler extends RedisSessionHandler @@ -33,11 +34,11 @@ public function __construct($config) if ($auth) { $args[] = $auth; } - $this->redis = new \RedisCluster(...$args); + $this->redis = new RedisCluster(...$args); if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->redis->setOption(\Redis::OPT_PREFIX, $config['prefix']); + $this->redis->setOption(Redis::OPT_PREFIX, $config['prefix']); } /** diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 54140f961..a68f4025d 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -15,10 +15,11 @@ namespace Workerman\Protocols\Http\Session; use Redis; +use RedisException; +use RuntimeException; use Throwable; use Workerman\Protocols\Http\Session; use Workerman\Timer; -use RedisException; /** * Class RedisSessionHandler @@ -52,7 +53,7 @@ class RedisSessionHandler implements SessionHandlerInterface public function __construct(array $config) { if (false === extension_loaded('redis')) { - throw new \RuntimeException('Please install redis extension.'); + throw new RuntimeException('Please install redis extension.'); } if (!isset($config['timeout'])) { @@ -74,7 +75,7 @@ public function connect() $this->redis = new Redis(); if (false === $this->redis->connect($config['host'], $config['port'], $config['timeout'])) { - throw new \RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); + throw new RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); } if (!empty($config['auth'])) { $this->redis->auth($config['auth']); @@ -125,9 +126,9 @@ public function write(string $sessionId, string $sessionData): bool /** * {@inheritdoc} */ - public function updateTimestamp(string $id, string $data = ""): bool + public function updateTimestamp(string $sessionId, string $data = ""): bool { - return true === $this->redis->expire($id, Session::$lifetime); + return true === $this->redis->expire($sessionId, Session::$lifetime); } /** From 74acb3c08e774719a7706fb19fa3e538b431ec6a Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 13:06:16 +0800 Subject: [PATCH 0817/1216] format http --- src/Protocols/Http/Request.php | 140 ++++++++++++++---------- src/Protocols/Http/Response.php | 59 ++++++---- src/Protocols/Http/ServerSentEvents.php | 4 +- src/Protocols/Http/Session.php | 35 ++++-- 4 files changed, 145 insertions(+), 93 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index c621af21d..43b5df52b 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -18,7 +18,30 @@ use RuntimeException; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; -use Workerman\Worker; +use function array_walk_recursive; +use function bin2hex; +use function clearstatcache; +use function count; +use function explode; +use function file_put_contents; +use function is_file; +use function json_decode; +use function ltrim; +use function microtime; +use function pack; +use function parse_str; +use function parse_url; +use function preg_match; +use function preg_replace; +use function strlen; +use function strpos; +use function strstr; +use function strtolower; +use function substr; +use function tempnam; +use function trim; +use function unlink; +use function urlencode; /** * Class Request @@ -134,7 +157,7 @@ public function header(string $name = null, mixed $default = null): ?string if (null === $name) { return $this->data['headers']; } - $name = \strtolower($name); + $name = strtolower($name); return $this->data['headers'][$name] ?? $default; } @@ -149,7 +172,7 @@ public function cookie(string $name = null, mixed $default = null): array|string { if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; - \parse_str(\preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); + parse_str(preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); } if ($name === null) { return $this->data['cookie']; @@ -209,8 +232,8 @@ public function protocolVersion(): string public function host(bool $withoutPort = false): ?string { $host = $this->header('host'); - if ($host && $withoutPort && $pos = \strpos($host, ':')) { - return \substr($host, 0, $pos); + if ($host && $withoutPort && $pos = strpos($host, ':')) { + return substr($host, 0, $pos); } return $host; } @@ -236,7 +259,7 @@ public function uri(): string public function path(): string { if (!isset($this->data['path'])) { - $this->data['path'] = (string)\parse_url($this->uri(), PHP_URL_PATH); + $this->data['path'] = (string)parse_url($this->uri(), PHP_URL_PATH); } return $this->data['path']; } @@ -249,7 +272,7 @@ public function path(): string public function queryString(): string { if (!isset($this->data['query_string'])) { - $this->data['query_string'] = (string)\parse_url($this->uri(), PHP_URL_QUERY); + $this->data['query_string'] = (string)parse_url($this->uri(), PHP_URL_QUERY); } return $this->data['query_string']; } @@ -258,6 +281,7 @@ public function queryString(): string * Get session. * * @return Session + * @throws Exception */ public function session(): Session { @@ -326,7 +350,7 @@ public function sessionRegenerateId(bool $deleteOldSession = false): string public function rawHead(): string { if (!isset($this->data['head'])) { - $this->data['head'] = \strstr($this->buffer, "\r\n\r\n", true); + $this->data['head'] = strstr($this->buffer, "\r\n\r\n", true); } return $this->data['head']; } @@ -338,7 +362,7 @@ public function rawHead(): string */ public function rawBody(): string { - return \substr($this->buffer, \strpos($this->buffer, "\r\n\r\n") + 4); + return substr($this->buffer, strpos($this->buffer, "\r\n\r\n") + 4); } /** @@ -368,8 +392,8 @@ public static function enableCache(bool $value) */ protected function parseHeadFirstLine() { - $firstLine = \strstr($this->buffer, "\r\n", true); - $tmp = \explode(' ', $firstLine, 3); + $firstLine = strstr($this->buffer, "\r\n", true); + $tmp = explode(' ', $firstLine, 3); $this->data['method'] = $tmp[0]; $this->data['uri'] = $tmp[1] ?? '/'; } @@ -381,8 +405,8 @@ protected function parseHeadFirstLine() */ protected function parseProtocolVersion() { - $firstLine = \strstr($this->buffer, "\r\n", true); - $protocoVersion = substr(\strstr($firstLine, 'HTTP/'), 5); + $firstLine = strstr($this->buffer, "\r\n", true); + $protocoVersion = substr(strstr($firstLine, 'HTTP/'), 5); $this->data['protocolVersion'] = $protocoVersion ?: '1.0'; } @@ -396,24 +420,24 @@ protected function parseHeaders() static $cache = []; $this->data['headers'] = []; $rawHead = $this->rawHead(); - $endLinePosition = \strpos($rawHead, "\r\n"); + $endLinePosition = strpos($rawHead, "\r\n"); if ($endLinePosition === false) { return; } - $headBuffer = \substr($rawHead, $endLinePosition + 2); + $headBuffer = substr($rawHead, $endLinePosition + 2); $cacheable = static::$enableCache && !isset($headBuffer[4096]); if ($cacheable && isset($cache[$headBuffer])) { $this->data['headers'] = $cache[$headBuffer]; return; } - $headData = \explode("\r\n", $headBuffer); + $headData = explode("\r\n", $headBuffer); foreach ($headData as $content) { if (str_contains($content, ':')) { - list($key, $value) = \explode(':', $content, 2); - $key = \strtolower($key); - $value = \ltrim($value); + list($key, $value) = explode(':', $content, 2); + $key = strtolower($key); + $value = ltrim($value); } else { - $key = \strtolower($content); + $key = strtolower($content); $value = ''; } if (isset($this->data['headers'][$key])) { @@ -424,7 +448,7 @@ protected function parseHeaders() } if ($cacheable) { $cache[$headBuffer] = $this->data['headers']; - if (\count($cache) > 128) { + if (count($cache) > 128) { unset($cache[key($cache)]); } } @@ -448,10 +472,10 @@ protected function parseGet() $this->data['get'] = $cache[$queryString]; return; } - \parse_str($queryString, $this->data['get']); + parse_str($queryString, $this->data['get']); if ($cacheable) { $cache[$queryString] = $this->data['get']; - if (\count($cache) > 256) { + if (count($cache) > 256) { unset($cache[key($cache)]); } } @@ -467,7 +491,7 @@ protected function parsePost() static $cache = []; $this->data['post'] = $this->data['files'] = []; $contentType = $this->header('content-type', ''); - if (\preg_match('/boundary="?(\S+)"?/', $contentType, $match)) { + if (preg_match('/boundary="?(\S+)"?/', $contentType, $match)) { $httpPostBoundary = '--' . $match[1]; $this->parseUploadFiles($httpPostBoundary); return; @@ -481,14 +505,14 @@ protected function parsePost() $this->data['post'] = $cache[$bodyBuffer]; return; } - if (\preg_match('/\bjson\b/i', $contentType)) { - $this->data['post'] = (array)\json_decode($bodyBuffer, true); + if (preg_match('/\bjson\b/i', $contentType)) { + $this->data['post'] = (array)json_decode($bodyBuffer, true); } else { - \parse_str($bodyBuffer, $this->data['post']); + parse_str($bodyBuffer, $this->data['post']); } if ($cacheable) { $cache[$bodyBuffer] = $this->data['post']; - if (\count($cache) > 256) { + if (count($cache) > 256) { unset($cache[key($cache)]); } } @@ -500,9 +524,9 @@ protected function parsePost() * @param string $httpPostBoundary * @return void */ - protected function parseUploadFiles($httpPostBoundary) + protected function parseUploadFiles(string $httpPostBoundary) { - $httpPostBoundary = \trim($httpPostBoundary, '"'); + $httpPostBoundary = trim($httpPostBoundary, '"'); $buffer = $this->buffer; $postEncodeString = ''; $filesEncodeString = ''; @@ -519,7 +543,7 @@ protected function parseUploadFiles($httpPostBoundary) if ($filesEncodeString) { parse_str($filesEncodeString, $this->data['files']); - \array_walk_recursive($this->data['files'], function (&$value) use ($files) { + array_walk_recursive($this->data['files'], function (&$value) use ($files) { $value = $files[$value]; }); } @@ -539,41 +563,41 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS { $file = []; $boundary = "\r\n$boundary"; - if (\strlen($this->buffer) < $sectionStartOffset) { + if (strlen($this->buffer) < $sectionStartOffset) { return 0; } - $sectionEndOffset = \strpos($this->buffer, $boundary, $sectionStartOffset); + $sectionEndOffset = strpos($this->buffer, $boundary, $sectionStartOffset); if (!$sectionEndOffset) { return 0; } - $contentLinesEndOffset = \strpos($this->buffer, "\r\n\r\n", $sectionStartOffset); + $contentLinesEndOffset = strpos($this->buffer, "\r\n\r\n", $sectionStartOffset); if (!$contentLinesEndOffset || $contentLinesEndOffset + 4 > $sectionEndOffset) { return 0; } - $contentLinesStr = \substr($this->buffer, $sectionStartOffset, $contentLinesEndOffset - $sectionStartOffset); - $contentLines = \explode("\r\n", trim($contentLinesStr . "\r\n")); - $boundaryValue = \substr($this->buffer, $contentLinesEndOffset + 4, $sectionEndOffset - $contentLinesEndOffset - 4); + $contentLinesStr = substr($this->buffer, $sectionStartOffset, $contentLinesEndOffset - $sectionStartOffset); + $contentLines = explode("\r\n", trim($contentLinesStr . "\r\n")); + $boundaryValue = substr($this->buffer, $contentLinesEndOffset + 4, $sectionEndOffset - $contentLinesEndOffset - 4); $uploadKey = false; foreach ($contentLines as $contentLine) { - if (!\strpos($contentLine, ': ')) { + if (!strpos($contentLine, ': ')) { return 0; } - list($key, $value) = \explode(': ', $contentLine); + list($key, $value) = explode(': ', $contentLine); switch (strtolower($key)) { case "content-disposition": // Is file data. - if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { + if (preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { $error = 0; $tmpFile = ''; - $size = \strlen($boundaryValue); + $size = strlen($boundaryValue); $tmpUploadDir = HTTP::uploadTmpDir(); if (!$tmpUploadDir) { $error = UPLOAD_ERR_NO_TMP_DIR; } else if ($boundaryValue === '') { $error = UPLOAD_ERR_NO_FILE; } else { - $tmpFile = \tempnam($tmpUploadDir, 'workerman.upload.'); - if ($tmpFile === false || false == \file_put_contents($tmpFile, $boundaryValue)) { + $tmpFile = tempnam($tmpUploadDir, 'workerman.upload.'); + if ($tmpFile === false || false == file_put_contents($tmpFile, $boundaryValue)) { $error = UPLOAD_ERR_CANT_WRITE; } } @@ -590,24 +614,24 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } // Is post field. else { // Parse $POST. - if (\preg_match('/name="(.*?)"$/', $value, $match)) { + if (preg_match('/name="(.*?)"$/', $value, $match)) { $k = $match[1]; - $postEncodeString .= \urlencode($k) . "=" . \urlencode($boundaryValue) . '&'; + $postEncodeString .= urlencode($k) . "=" . urlencode($boundaryValue) . '&'; } - return $sectionEndOffset + \strlen($boundary) + 2; + return $sectionEndOffset + strlen($boundary) + 2; } case "content-type": - $file['type'] = \trim($value); + $file['type'] = trim($value); break; } } if ($uploadKey === false) { return 0; } - $filesEncodeStr .= \urlencode($uploadKey) . '=' . \count($files) . '&'; + $filesEncodeStr .= urlencode($uploadKey) . '=' . count($files) . '&'; $files[] = $file; - return $sectionEndOffset + \strlen($boundary) + 2; + return $sectionEndOffset + strlen($boundary) + 2; } /** @@ -618,7 +642,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS */ public static function createSessionId(): string { - return \bin2hex(\pack('d', \microtime(true)) . random_bytes(8)); + return bin2hex(pack('d', microtime(true)) . random_bytes(8)); } /** @@ -653,7 +677,7 @@ public function __toString() * @param mixed $value * @return void */ - public function __set($name, $value) + public function __set(string $name, mixed $value) { $this->properties[$name] = $value; } @@ -664,7 +688,7 @@ public function __set($name, $value) * @param string $name * @return mixed|null */ - public function __get($name) + public function __get(string $name) { return $this->properties[$name] ?? null; } @@ -675,7 +699,7 @@ public function __get($name) * @param string $name * @return bool */ - public function __isset($name) + public function __isset(string $name) { return isset($this->properties[$name]); } @@ -686,7 +710,7 @@ public function __isset($name) * @param string $name * @return void */ - public function __unset($name) + public function __unset(string $name) { unset($this->properties[$name]); } @@ -699,11 +723,11 @@ public function __unset($name) public function __destruct() { if (isset($this->data['files'])) { - \clearstatcache(); - \array_walk_recursive($this->data['files'], function ($value, $key) { + clearstatcache(); + array_walk_recursive($this->data['files'], function ($value, $key) { if ($key === 'tmp_name') { - if (\is_file($value)) { - \unlink($value); + if (is_file($value)) { + unlink($value); } } }); diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 4738fb734..205deb4a8 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -14,6 +14,21 @@ namespace Workerman\Protocols\Http; +use function array_merge_recursive; +use function explode; +use function file; +use function filemtime; +use function gmdate; +use function is_array; +use function is_file; +use function pathinfo; +use function preg_match; +use function rawurlencode; +use function strlen; +use function substr; +use const FILE_IGNORE_NEW_LINES; +use const FILE_SKIP_EMPTY_LINES; + /** * Class Response * @package Workerman\Protocols\Http @@ -72,7 +87,7 @@ class Response * Phrases. * * @var array - * + * * @link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ const PHRASES = [ @@ -131,7 +146,7 @@ class Response 429 => 'Too Many Requests', // RFC 6585 431 => 'Request Header Fields Too Large', // RFC 6585 451 => 'Unavailable For Legal Reasons', // RFC 7725 - + 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', @@ -163,8 +178,8 @@ public static function init() * @param string $body */ public function __construct( - int $status = 200, - array $headers = [], + int $status = 200, + array $headers = [], string $body = '' ) { @@ -206,7 +221,7 @@ public function withHeader(string $name, string $value): static */ public function withHeaders(array $headers): static { - $this->headers = \array_merge_recursive($this->headers, $headers); + $this->headers = array_merge_recursive($this->headers, $headers); return $this; } @@ -321,7 +336,7 @@ public function rawBody(): string */ public function withFile(string $file, int $offset = 0, int $length = 0): static { - if (!\is_file($file)) { + if (!is_file($file)) { return $this->withStatus(404)->withBody('

404 Not Found

'); } $this->file = ['file' => $file, 'offset' => $offset, 'length' => $length]; @@ -341,9 +356,9 @@ public function withFile(string $file, int $offset = 0, int $length = 0): static * @param bool $sameSite * @return $this */ - public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, bool $sameSite = false): static + public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, bool $sameSite = false): static { - $this->headers['Set-Cookie'][] = $name . '=' . \rawurlencode($value) + $this->headers['Set-Cookie'][] = $name . '=' . rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) . ($maxAge === null ? '' : '; Max-Age=' . $maxAge) . (empty($path) ? '' : '; Path=' . $path) @@ -363,13 +378,13 @@ protected function createHeadForFile(array $fileInfo): string { $file = $fileInfo['file']; $reason = $this->reason ?: self::PHRASES[$this->status]; - $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; + $head = "HTTP/$this->version $this->status $reason\r\n"; $headers = $this->headers; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } foreach ($headers as $name => $value) { - if (\is_array($value)) { + if (is_array($value)) { foreach ($value as $item) { $head .= "$name: $item\r\n"; } @@ -382,7 +397,7 @@ protected function createHeadForFile(array $fileInfo): string $head .= "Connection: keep-alive\r\n"; } - $fileInfo = \pathinfo($file); + $fileInfo = pathinfo($file); $extension = $fileInfo['extension'] ?? ''; $baseName = $fileInfo['basename'] ?? 'unknown'; if (!isset($headers['Content-Type'])) { @@ -398,12 +413,12 @@ protected function createHeadForFile(array $fileInfo): string } if (!isset($headers['Last-Modified'])) { - if ($mtime = \filemtime($file)) { - $head .= 'Last-Modified: ' . \gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; + if ($mtime = filemtime($file)) { + $head .= 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; } } - return "{$head}\r\n"; + return "$head\r\n"; } /** @@ -418,18 +433,18 @@ public function __toString() } $reason = $this->reason ?: self::PHRASES[$this->status] ?? ''; - $bodyLen = \strlen($this->body); + $bodyLen = strlen($this->body); if (empty($this->headers)) { - return "HTTP/{$this->version} {$this->status} $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\nConnection: keep-alive\r\n\r\n{$this->body}"; + return "HTTP/$this->version $this->status $reason\r\nServer: workerman\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\nConnection: keep-alive\r\n\r\n$this->body"; } - $head = "HTTP/{$this->version} {$this->status} $reason\r\n"; + $head = "HTTP/$this->version $this->status $reason\r\n"; $headers = $this->headers; if (!isset($headers['Server'])) { $head .= "Server: workerman\r\n"; } foreach ($headers as $name => $value) { - if (\is_array($value)) { + if (is_array($value)) { foreach ($value as $item) { $head .= "$name: $item\r\n"; } @@ -451,7 +466,7 @@ public function __toString() if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $bodyLen\r\n\r\n"; } else { - return "$head\r\n" . dechex($bodyLen) . "\r\n{$this->body}\r\n"; + return "$head\r\n" . dechex($bodyLen) . "\r\n$this->body\r\n"; } // The whole http package @@ -466,12 +481,12 @@ public function __toString() public static function initMimeTypeMap() { $mimeFile = __DIR__ . '/mime.types'; - $items = \file($mimeFile, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); + $items = file($mimeFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($items as $content) { - if (\preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { + if (preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { $mimeType = $match[1]; $extensionVar = $match[2]; - $extensionArray = \explode(' ', \substr($extensionVar, 0, -1)); + $extensionArray = explode(' ', substr($extensionVar, 0, -1)); foreach ($extensionArray as $fileExtension) { static::$mimeTypeMap[$fileExtension] = $mimeType; } diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index bdd090075..b52adb21d 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -14,6 +14,8 @@ namespace Workerman\Protocols\Http; +use function str_replace; + /** * Class ServerSentEvents * @package Workerman\Protocols\Http @@ -52,7 +54,7 @@ public function __toString() $buffer .= "event: {$data['event']}\n"; } if (isset($data['data'])) { - $buffer .= 'data: ' . \str_replace("\n", "\ndata: ", $data['data']) . "\n\n"; + $buffer .= 'data: ' . str_replace("\n", "\ndata: ", $data['data']) . "\n\n"; } if (isset($data['id'])) { $buffer .= "id: {$data['id']}\n"; diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 5abeb48a6..73f5d55bf 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -15,9 +15,19 @@ namespace Workerman\Protocols\Http; use Exception; +use JetBrains\PhpStorm\ArrayShape; use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; +use function array_key_exists; +use function ini_get; +use function is_array; +use function is_scalar; +use function preg_match; +use function random_int; +use function serialize; +use function session_get_cookie_params; +use function unserialize; /** * Class Session @@ -150,7 +160,7 @@ public function __construct(string $sessionId) } $this->sessionId = $sessionId; if ($data = static::$handler->read($sessionId)) { - $this->data = \unserialize($data); + $this->data = unserialize($data); } } @@ -221,7 +231,7 @@ public function pull(string $name, mixed $default = null): mixed */ public function put(array|string $key, mixed $value = null) { - if (!\is_array($key)) { + if (!is_array($key)) { $this->set($key, $value); return; } @@ -239,11 +249,11 @@ public function put(array|string $key, mixed $value = null) */ public function forget(array|string $name) { - if (\is_scalar($name)) { + if (is_scalar($name)) { $this->delete($name); return; } - if (\is_array($name)) { + if (is_array($name)) { foreach ($name as $key) { unset($this->data[$key]); } @@ -291,7 +301,7 @@ public function has(string $name): bool */ public function exists(string $name): bool { - return \array_key_exists($name, $this->data); + return array_key_exists($name, $this->data); } /** @@ -305,7 +315,7 @@ public function save() if (empty($this->data)) { static::$handler->destroy($this->sessionId); } else { - static::$handler->write($this->sessionId, \serialize($this->data)); + static::$handler->write($this->sessionId, serialize($this->data)); } } elseif (static::$autoUpdateTimestamp) { static::refresh(); @@ -330,15 +340,15 @@ public function refresh(): bool */ public static function init() { - if (($gcProbability = (int)\ini_get('session.gc_probability')) && ($gcDivisor = (int)\ini_get('session.gc_divisor'))) { + if (($gcProbability = (int)ini_get('session.gc_probability')) && ($gcDivisor = (int)ini_get('session.gc_divisor'))) { static::$gcProbability = [$gcProbability, $gcDivisor]; } - if ($gcMaxLifeTime = \ini_get('session.gc_maxlifetime')) { + if ($gcMaxLifeTime = ini_get('session.gc_maxlifetime')) { self::$lifetime = (int)$gcMaxLifeTime; } - $sessionCookieParams = \session_get_cookie_params(); + $sessionCookieParams = session_get_cookie_params(); static::$cookieLifetime = $sessionCookieParams['lifetime']; static::$cookiePath = $sessionCookieParams['path']; static::$domain = $sessionCookieParams['domain']; @@ -369,6 +379,7 @@ public static function handlerClass(mixed $className = null, mixed $config = nul * * @return array */ + #[ArrayShape(['lifetime' => "int", 'path' => "string", 'domain' => "string", 'secure' => "bool", 'httponly' => "bool", 'samesite' => "string"])] public static function getCookieParams(): array { return [ @@ -414,7 +425,7 @@ public function gc() public function __destruct() { $this->save(); - if (\random_int(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { + if (random_int(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { $this->gc(); } } @@ -424,9 +435,9 @@ public function __destruct() * * @param string $sessionId */ - protected static function checkSessionId($sessionId) + protected static function checkSessionId(string $sessionId) { - if (!\preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { + if (!preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { throw new RuntimeException("session_id $sessionId is invalid"); } } From de8e9b2b1c6429770130c6928a1d55344e7997f6 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 14:12:53 +0800 Subject: [PATCH 0818/1216] format --- src/Protocols/Frame.php | 15 ++-- src/Protocols/Http.php | 68 +++++++++++------- src/Protocols/Text.php | 9 ++- src/Protocols/Websocket.php | 91 +++++++++++++----------- src/Protocols/Ws.php | 138 +++++++++++++++++++----------------- 5 files changed, 185 insertions(+), 136 deletions(-) diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index ff2bb5af4..bccf7782b 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -14,6 +14,11 @@ namespace Workerman\Protocols; +use function pack; +use function strlen; +use function substr; +use function unpack; + /** * Frame Protocol. */ @@ -27,10 +32,10 @@ class Frame */ public static function input(string $buffer): int { - if (\strlen($buffer) < 4) { + if (strlen($buffer) < 4) { return 0; } - $unpackData = \unpack('Ntotal_length', $buffer); + $unpackData = unpack('Ntotal_length', $buffer); return $unpackData['total_length']; } @@ -42,7 +47,7 @@ public static function input(string $buffer): int */ public static function decode(string $buffer): string { - return \substr($buffer, 4); + return substr($buffer, 4); } /** @@ -53,7 +58,7 @@ public static function decode(string $buffer): string */ public static function encode(string $data): string { - $totalLength = 4 + \strlen($data); - return \pack('N', $totalLength) . $data; + $totalLength = 4 + strlen($data); + return pack('N', $totalLength) . $data; } } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 6017b6a45..3ad522671 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -18,6 +18,25 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; +use function clearstatcache; +use function count; +use function explode; +use function filesize; +use function fopen; +use function fread; +use function fseek; +use function ftell; +use function in_array; +use function ini_get; +use function is_array; +use function is_object; +use function key; +use function preg_match; +use function strlen; +use function strpos; +use function strstr; +use function substr; +use function sys_get_temp_dir; /** * Class Http. @@ -84,10 +103,10 @@ public static function input(string $buffer, TcpConnection $connection): int if (!isset($buffer[512]) && isset($input[$buffer])) { return $input[$buffer]; } - $crlfPos = \strpos($buffer, "\r\n\r\n"); + $crlfPos = strpos($buffer, "\r\n\r\n"); if (false === $crlfPos) { // Judge whether the package length exceeds the limit. - if (\strlen($buffer) >= 16384) { + if (strlen($buffer) >= 16384) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } @@ -95,25 +114,25 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $firstLine = \explode(" ", \strstr($buffer, "\r\n", true), 3); + $firstLine = explode(" ", strstr($buffer, "\r\n", true), 3); - if (!\in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { + if (!in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } - $header = \substr($buffer, 0, $crlfPos); - $hostHeaderPosition = \strpos($header, "\r\nHost: "); + $header = substr($buffer, 0, $crlfPos); + $hostHeaderPosition = strpos($header, "\r\nHost: "); if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } - if ($pos = \strpos($header, "\r\nContent-Length: ")) { - $length = $length + (int)\substr($header, $pos + 18, 10); + if ($pos = strpos($header, "\r\nContent-Length: ")) { + $length = $length + (int)substr($header, $pos + 18, 10); $hasContentLength = true; - } else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { + } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { $length = $length + $match[1]; $hasContentLength = true; } else { @@ -133,7 +152,7 @@ public static function input(string $buffer, TcpConnection $connection): int if (!isset($buffer[512])) { $input[$buffer] = $length; - if (\count($input) > 512) { + if (count($input) > 512) { unset($input[key($input)]); } } @@ -164,8 +183,8 @@ public static function decode(string $buffer, TcpConnection $connection): Reques $connection->request = $request; if (true === $cacheable) { $requests[$buffer] = $request; - if (\count($requests) > 512) { - unset($requests[\key($requests)]); + if (count($requests) > 512) { + unset($requests[key($requests)]); } } return $request; @@ -185,11 +204,11 @@ public static function encode(mixed $response, TcpConnection $connection): strin $request = $connection->request; $request->session = $request->connection = $connection->request = null; } - if (!\is_object($response)) { + if (!is_object($response)) { $extHeader = ''; if (isset($connection->headers)) { foreach ($connection->headers as $name => $value) { - if (\is_array($value)) { + if (is_array($value)) { foreach ($value as $item) { $extHeader = "$name: $item\r\n"; } @@ -199,7 +218,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin } $connection->headers = []; } - $bodyLen = \strlen((string)$response); + $bodyLen = strlen((string)$response); return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; } @@ -212,8 +231,8 @@ public static function encode(mixed $response, TcpConnection $connection): strin $file = $response->file['file']; $offset = $response->file['offset']; $length = $response->file['length']; - \clearstatcache(); - $fileSize = (int)\filesize($file); + clearstatcache(); + $fileSize = (int)filesize($file); $bodyLen = $length > 0 ? $length : $fileSize - $offset; $response->withHeaders([ 'Content-Length' => $bodyLen, @@ -224,10 +243,10 @@ public static function encode(mixed $response, TcpConnection $connection): strin $response->header('Content-Range', "bytes $offset-$offsetEnd/$fileSize"); } if ($bodyLen < 2 * 1024 * 1024) { - $connection->send((string)$response . file_get_contents($file, false, null, $offset, $bodyLen), true); + $connection->send($response . file_get_contents($file, false, null, $offset, $bodyLen), true); return ''; } - $handler = \fopen($file, 'r'); + $handler = fopen($file, 'r'); if (false === $handler) { $connection->close(new Response(403, null, '403 Forbidden')); return ''; @@ -247,13 +266,14 @@ public static function encode(mixed $response, TcpConnection $connection): strin * @param resource $handler * @param int $offset * @param int $length + * @throws Throwable */ protected static function sendStream(TcpConnection $connection, $handler, int $offset = 0, int $length = 0) { $connection->context->bufferFull = false; $connection->context->streamSending = true; if ($offset !== 0) { - \fseek($handler, $offset); + fseek($handler, $offset); } $offsetEnd = $offset + $length; // Read file content from disk piece by piece and send to client. @@ -263,7 +283,7 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o // Read from disk. $size = 1024 * 1024; if ($length !== 0) { - $tell = \ftell($handler); + $tell = ftell($handler); $remainSize = $offsetEnd - $tell; if ($remainSize <= 0) { fclose($handler); @@ -273,7 +293,7 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o $size = $remainSize > $size ? $size : $remainSize; } - $buffer = \fread($handler, $size); + $buffer = fread($handler, $size); // Read eof. if ($buffer === '' || $buffer === false) { fclose($handler); @@ -308,9 +328,9 @@ public static function uploadTmpDir(string|null $dir = null): string static::$uploadTmpDir = $dir; } if (static::$uploadTmpDir === '') { - if ($uploadTmpDir = \ini_get('upload_tmp_dir')) { + if ($uploadTmpDir = ini_get('upload_tmp_dir')) { static::$uploadTmpDir = $uploadTmpDir; - } else if ($uploadTmpDir = \sys_get_temp_dir()) { + } else if ($uploadTmpDir = sys_get_temp_dir()) { static::$uploadTmpDir = $uploadTmpDir; } } diff --git a/src/Protocols/Text.php b/src/Protocols/Text.php index 2b65ddf32..4fe4f8937 100644 --- a/src/Protocols/Text.php +++ b/src/Protocols/Text.php @@ -15,6 +15,9 @@ namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; +use function rtrim; +use function strlen; +use function strpos; /** * Text Protocol. @@ -31,12 +34,12 @@ class Text public static function input(string $buffer, ConnectionInterface $connection): int { // Judge whether the package length exceeds the limit. - if (isset($connection->maxPackageSize) && \strlen($buffer) >= $connection->maxPackageSize) { + if (isset($connection->maxPackageSize) && strlen($buffer) >= $connection->maxPackageSize) { $connection->close(); return 0; } // Find the position of "\n". - $pos = \strpos($buffer, "\n"); + $pos = strpos($buffer, "\n"); // No "\n", packet length is unknown, continue to wait for the data so return 0. if ($pos === false) { return 0; @@ -66,6 +69,6 @@ public static function encode(string $buffer): string public static function decode(string $buffer): string { // Remove "\n" - return \rtrim($buffer, "\r\n"); + return rtrim($buffer, "\r\n"); } } \ No newline at end of file diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index c581cf28c..5fc53fc15 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -19,6 +19,19 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Worker; +use function base64_encode; +use function chr; +use function floor; +use function ord; +use function pack; +use function preg_match; +use function sha1; +use function str_repeat; +use function stripos; +use function strlen; +use function strpos; +use function substr; +use function unpack; /** * WebSocket protocol. @@ -50,7 +63,7 @@ class Websocket public static function input(string $buffer, TcpConnection $connection): int { // Receive length. - $recvLen = \strlen($buffer); + $recvLen = strlen($buffer); // We need more data. if ($recvLen < 6) { return 0; @@ -69,8 +82,8 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } } else { - $firstbyte = \ord($buffer[0]); - $secondbyte = \ord($buffer[1]); + $firstbyte = ord($buffer[0]); + $secondbyte = ord($buffer[1]); $dataLen = $secondbyte & 127; $isFinFrame = $firstbyte >> 7; $masked = $secondbyte >> 7; @@ -84,13 +97,13 @@ public static function input(string $buffer, TcpConnection $connection): int $opcode = $firstbyte & 0xf; switch ($opcode) { case 0x0: - // Blob type. + // Blob type. case 0x1: - // Arraybuffer type. + // Arraybuffer type. case 0x2: - // Ping package. + // Ping package. case 0x9: - // Pong package. + // Pong package. case 0xa: break; // Close package. @@ -122,7 +135,7 @@ public static function input(string $buffer, TcpConnection $connection): int if ($headLen > $recvLen) { return 0; } - $pack = \unpack('nn/ntotal_len', $buffer); + $pack = unpack('nn/ntotal_len', $buffer); $dataLen = $pack['total_len']; } else { if ($dataLen === 127) { @@ -130,13 +143,13 @@ public static function input(string $buffer, TcpConnection $connection): int if ($headLen > $recvLen) { return 0; } - $arr = \unpack('n/N2c', $buffer); + $arr = unpack('n/N2c', $buffer); $dataLen = $arr['c1'] * 4294967296 + $arr['c2']; } } $currentFrameLength = $headLen + $dataLen; - $totalPackageSize = \strlen($connection->context->websocketDataBuffer) + $currentFrameLength; + $totalPackageSize = strlen($connection->context->websocketDataBuffer) + $currentFrameLength; if ($totalPackageSize > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$totalPackageSize\n"); $connection->close(); @@ -146,7 +159,7 @@ public static function input(string $buffer, TcpConnection $connection): int if ($isFinFrame) { if ($opcode === 0x9) { if ($recvLen >= $currentFrameLength) { - $pingData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $pingData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; @@ -162,13 +175,13 @@ public static function input(string $buffer, TcpConnection $connection): int } $connection->websocketType = $tmpConnectionType; if ($recvLen > $currentFrameLength) { - return static::input(\substr($buffer, $currentFrameLength), $connection); + return static::input(substr($buffer, $currentFrameLength), $connection); } } return 0; } else if ($opcode === 0xa) { if ($recvLen >= $currentFrameLength) { - $pongData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $pongData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; @@ -183,7 +196,7 @@ public static function input(string $buffer, TcpConnection $connection): int } $connection->websocketType = $tmpConnectionType; if ($recvLen > $currentFrameLength) { - return static::input(\substr($buffer, $currentFrameLength), $connection); + return static::input(substr($buffer, $currentFrameLength), $connection); } } return 0; @@ -202,12 +215,12 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } // The length of the received data is greater than the length of a frame. elseif ($connection->context->websocketCurrentFrameLength < $recvLen) { - static::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); + static::decode(substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); $currentFrameLength = $connection->context->websocketCurrentFrameLength; $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. - return static::input(\substr($buffer, $currentFrameLength), $connection); + return static::input(substr($buffer, $currentFrameLength), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -223,7 +236,7 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function encode(string $buffer, TcpConnection $connection): string { - $len = \strlen($buffer); + $len = strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; } @@ -231,12 +244,12 @@ public static function encode(string $buffer, TcpConnection $connection): string $firstByte = $connection->websocketType; if ($len <= 125) { - $encodeBuffer = $firstByte . \chr($len) . $buffer; + $encodeBuffer = $firstByte . chr($len) . $buffer; } else { if ($len <= 65535) { - $encodeBuffer = $firstByte . \chr(126) . \pack("n", $len) . $buffer; + $encodeBuffer = $firstByte . chr(126) . pack("n", $len) . $buffer; } else { - $encodeBuffer = $firstByte . \chr(127) . \pack("xxxxN", $len) . $buffer; + $encodeBuffer = $firstByte . chr(127) . pack("xxxxN", $len) . $buffer; } } @@ -246,7 +259,7 @@ public static function encode(string $buffer, TcpConnection $connection): string $connection->context->tmpWebsocketData = ''; } // If buffer has already full then discard the current package. - if (\strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); @@ -258,7 +271,7 @@ public static function encode(string $buffer, TcpConnection $connection): string } $connection->context->tmpWebsocketData .= $encodeBuffer; // Check buffer is full. - if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); @@ -283,24 +296,23 @@ public static function encode(string $buffer, TcpConnection $connection): string */ public static function decode(string $buffer, TcpConnection $connection): string { - $firstByte = \ord($buffer[1]); + $firstByte = ord($buffer[1]); $len = $firstByte & 127; - $rsv1 = $firstByte & 64; if ($len === 126) { - $masks = \substr($buffer, 4, 4); - $data = \substr($buffer, 8); + $masks = substr($buffer, 4, 4); + $data = substr($buffer, 8); } else { if ($len === 127) { - $masks = \substr($buffer, 10, 4); - $data = \substr($buffer, 14); + $masks = substr($buffer, 10, 4); + $data = substr($buffer, 14); } else { - $masks = \substr($buffer, 2, 4); - $data = \substr($buffer, 6); + $masks = substr($buffer, 2, 4); + $data = substr($buffer, 6); } } - $dataLength = \strlen($data); - $masks = \str_repeat($masks, \floor($dataLength / 4)) . \substr($masks, 0, $dataLength % 4); + $dataLength = strlen($data); + $masks = str_repeat($masks, floor($dataLength / 4)) . substr($masks, 0, $dataLength % 4); $decoded = $data ^ $masks; if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decoded; @@ -325,17 +337,16 @@ public static function decode(string $buffer, TcpConnection $connection): string public static function dealHandshake(string $buffer, TcpConnection $connection): int { // HTTP protocol. - if (0 === \strpos($buffer, 'GET')) { + if (str_starts_with($buffer, 'GET')) { // Find \r\n\r\n. - $headerEndPos = \strpos($buffer, "\r\n\r\n"); + $headerEndPos = strpos($buffer, "\r\n\r\n"); if (!$headerEndPos) { return 0; } $headerLength = $headerEndPos + 4; // Get Sec-WebSocket-Key. - $SecWebSocketKey = ''; - if (\preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { + if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $SecWebSocketKey = $match[1]; } else { $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", @@ -343,7 +354,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): return 0; } // Calculation websocket key. - $newKey = \base64_encode(\sha1($SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); + $newKey = base64_encode(sha1($SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshakeMessage = "HTTP/1.1 101 Switching Protocols\r\n" . "Upgrade: websocket\r\n" @@ -379,7 +390,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): if ($connection->headers) { foreach ($connection->headers as $header) { - if (\stripos($header, 'Server:') === 0) { + if (stripos($header, 'Server:') === 0) { $hasServerHeader = true; } $handshakeMessage .= "$header\r\n"; @@ -399,8 +410,8 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $connection->send($connection->context->tmpWebsocketData, true); $connection->context->tmpWebsocketData = ''; } - if (\strlen($buffer) > $headerLength) { - return static::input(\substr($buffer, $headerLength), $connection); + if (strlen($buffer) > $headerLength) { + return static::input(substr($buffer, $headerLength), $connection); } return 0; } diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 1988b3e93..783385046 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -15,10 +15,24 @@ namespace Workerman\Protocols; use Throwable; -use Workerman\Worker; -use Workerman\Timer; -use Workerman\Connection\TcpConnection; +use Workerman\Connection\AsyncTcpConnection; use Workerman\Connection\ConnectionInterface; +use Workerman\Timer; +use Workerman\Worker; +use function base64_encode; +use function bin2hex; +use function floor; +use function is_array; +use function ord; +use function pack; +use function preg_match; +use function sha1; +use function str_repeat; +use function strlen; +use function strpos; +use function substr; +use function trim; +use function unpack; /** * Websocket protocol for client. @@ -43,21 +57,21 @@ class Ws * Check the integrity of the package. * * @param string $buffer - * @param TcpConnection $connection + * @param AsyncTcpConnection $connection * @return int|false * @throws Throwable */ - public static function input(string $buffer, TcpConnection $connection): bool|int + public static function input(string $buffer, AsyncTcpConnection $connection): bool|int { if (empty($connection->context->handshakeStep)) { - Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n"); + Worker::safeEcho("recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"); return false; } // Recv handshake response if ($connection->context->handshakeStep === 1) { return self::dealHandshake($buffer, $connection); } - $recvLen = \strlen($buffer); + $recvLen = strlen($buffer); if ($recvLen < 2) { return 0; } @@ -70,8 +84,8 @@ public static function input(string $buffer, TcpConnection $connection): bool|in } } else { - $firstbyte = \ord($buffer[0]); - $secondbyte = \ord($buffer[1]); + $firstbyte = ord($buffer[0]); + $secondbyte = ord($buffer[1]); $dataLen = $secondbyte & 127; $isFinFrame = $firstbyte >> 7; $masked = $secondbyte >> 7; @@ -86,11 +100,11 @@ public static function input(string $buffer, TcpConnection $connection): bool|in switch ($opcode) { case 0x0: - // Blob type. + // Blob type. case 0x1: - // Arraybuffer type. + // Arraybuffer type. case 0x2: - // Ping package. + // Ping package. case 0x9: // Pong package. case 0xa: @@ -117,22 +131,22 @@ public static function input(string $buffer, TcpConnection $connection): bool|in } // Calculate packet length. if ($dataLen === 126) { - if (\strlen($buffer) < 4) { + if (strlen($buffer) < 4) { return 0; } - $pack = \unpack('nn/ntotal_len', $buffer); + $pack = unpack('nn/ntotal_len', $buffer); $currentFrameLength = $pack['total_len'] + 4; } else if ($dataLen === 127) { - if (\strlen($buffer) < 10) { + if (strlen($buffer) < 10) { return 0; } - $arr = \unpack('n/N2c', $buffer); + $arr = unpack('n/N2c', $buffer); $currentFrameLength = $arr['c1'] * 4294967296 + $arr['c2'] + 10; } else { $currentFrameLength = $dataLen + 2; } - $totalPackageSize = \strlen($connection->context->websocketDataBuffer) + $currentFrameLength; + $totalPackageSize = strlen($connection->context->websocketDataBuffer) + $currentFrameLength; if ($totalPackageSize > $connection->maxPackageSize) { Worker::safeEcho("error package. package_length=$totalPackageSize\n"); $connection->close(); @@ -142,9 +156,9 @@ public static function input(string $buffer, TcpConnection $connection): bool|in if ($isFinFrame) { if ($opcode === 0x9) { if ($recvLen >= $currentFrameLength) { - $pingData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $pingData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); - $tmpConnectionType = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; if (isset($connection->onWebSocketPing)) { try { @@ -157,16 +171,16 @@ public static function input(string $buffer, TcpConnection $connection): bool|in } $connection->websocketType = $tmpConnectionType; if ($recvLen > $currentFrameLength) { - return static::input(\substr($buffer, $currentFrameLength), $connection); + return static::input(substr($buffer, $currentFrameLength), $connection); } } return 0; } else if ($opcode === 0xa) { if ($recvLen >= $currentFrameLength) { - $pongData = static::decode(\substr($buffer, 0, $currentFrameLength), $connection); + $pongData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); - $tmpConnectionType = isset($connection->websocketType) ? $connection->websocketType : static::BINARY_TYPE_BLOB; + $tmpConnectionType = $connection->websocketType ?? static::BINARY_TYPE_BLOB; $connection->websocketType = "\x8a"; // Try to emit onWebSocketPong callback. if (isset($connection->onWebSocketPong)) { @@ -178,7 +192,7 @@ public static function input(string $buffer, TcpConnection $connection): bool|in } $connection->websocketType = $tmpConnectionType; if ($recvLen > $currentFrameLength) { - return static::input(\substr($buffer, $currentFrameLength), $connection); + return static::input(substr($buffer, $currentFrameLength), $connection); } } return 0; @@ -196,12 +210,12 @@ public static function input(string $buffer, TcpConnection $connection): bool|in return 0; } // The length of the received data is greater than the length of a frame. elseif ($connection->context->websocketCurrentFrameLength < $recvLen) { - self::decode(\substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); + self::decode(substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); $currentFrameLength = $connection->context->websocketCurrentFrameLength; $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. - return self::input(\substr($buffer, $currentFrameLength), $connection); + return self::input(substr($buffer, $currentFrameLength), $connection); } // The length of the received data is less than the length of a frame. else { return 0; @@ -212,21 +226,21 @@ public static function input(string $buffer, TcpConnection $connection): bool|in * Websocket encode. * * @param string $payload - * @param TcpConnection $connection + * @param AsyncTcpConnection $connection * @return string + * @throws Throwable */ - public static function encode(string $payload, TcpConnection $connection): string + public static function encode(string $payload, AsyncTcpConnection $connection): string { if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } - $payload = $payload; if (empty($connection->context->handshakeStep)) { static::sendHandshake($connection); } $maskKey = "\x00\x00\x00\x00"; - $length = \strlen($payload); + $length = strlen($payload); if (strlen($payload) < 126) { $head = chr(0x80 | $length); @@ -238,11 +252,11 @@ public static function encode(string $payload, TcpConnection $connection): strin $frame = $connection->websocketType . $head . $maskKey; // append payload to frame: - $maskKey = \str_repeat($maskKey, \floor($length / 4)) . \substr($maskKey, 0, $length % 4); + $maskKey = str_repeat($maskKey, floor($length / 4)) . substr($maskKey, 0, $length % 4); $frame .= $payload ^ $maskKey; if ($connection->context->handshakeStep === 1) { // If buffer has already full then discard the current package. - if (\strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { + if (strlen($connection->context->tmpWebsocketData) > $connection->maxSendBufferSize) { if ($connection->onError) { try { ($connection->onError)($connection, ConnectionInterface::SEND_FAIL, 'send buffer full and drop package'); @@ -254,7 +268,7 @@ public static function encode(string $payload, TcpConnection $connection): strin } $connection->context->tmpWebsocketData = $connection->context->tmpWebsocketData . $frame; // Check buffer is full. - if ($connection->maxSendBufferSize <= \strlen($connection->context->tmpWebsocketData)) { + if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { if ($connection->onBufferFull) { try { ($connection->onBufferFull)($connection); @@ -272,19 +286,19 @@ public static function encode(string $payload, TcpConnection $connection): strin * Websocket decode. * * @param string $bytes - * @param TcpConnection $connection + * @param AsyncTcpConnection $connection * @return string */ - public static function decode(string $bytes, TcpConnection $connection): string + public static function decode(string $bytes, AsyncTcpConnection $connection): string { - $dataLength = \ord($bytes[1]); + $dataLength = ord($bytes[1]); if ($dataLength === 126) { - $decodedData = \substr($bytes, 4); + $decodedData = substr($bytes, 4); } else if ($dataLength === 127) { - $decodedData = \substr($bytes, 10); + $decodedData = substr($bytes, 10); } else { - $decodedData = \substr($bytes, 2); + $decodedData = substr($bytes, 2); } if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decodedData; @@ -301,7 +315,9 @@ public static function decode(string $bytes, TcpConnection $connection): string /** * Send websocket handshake data. * + * @param $connection * @return void + * @throws Throwable */ public static function onConnect($connection) { @@ -311,9 +327,9 @@ public static function onConnect($connection) /** * Clean * - * @param TcpConnection $connection + * @param AsyncTcpConnection $connection */ - public static function onClose(TcpConnection $connection) + public static function onClose(AsyncTcpConnection $connection) { $connection->context->handshakeStep = null; $connection->context->websocketCurrentFrameLength = 0; @@ -328,11 +344,11 @@ public static function onClose(TcpConnection $connection) /** * Send websocket handshake. * - * @param TcpConnection $connection + * @param AsyncTcpConnection $connection * @return void * @throws Throwable */ - public static function sendHandshake(TcpConnection $connection) + public static function sendHandshake(AsyncTcpConnection $connection) { if (!empty($connection->context->handshakeStep)) { return; @@ -341,21 +357,21 @@ public static function sendHandshake(TcpConnection $connection) $port = $connection->getRemotePort(); $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. - $connection->context->websocketSecKey = \base64_encode(random_bytes(16)); + $connection->context->websocketSecKey = base64_encode(random_bytes(16)); $userHeader = $connection->headers ?? null; $userHeaderStr = ''; if (!empty($userHeader)) { - if (\is_array($userHeader)) { + if (is_array($userHeader)) { foreach ($userHeader as $k => $v) { $userHeaderStr .= "$k: $v\r\n"; } } else { $userHeaderStr .= $userHeader; } - $userHeaderStr = "\r\n" . \trim($userHeaderStr); + $userHeaderStr = "\r\n" . trim($userHeaderStr); } $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" . - (!\preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . + (!preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . @@ -373,40 +389,34 @@ public static function sendHandshake(TcpConnection $connection) * Websocket handshake. * * @param string $buffer - * @param TcpConnection $connection - * @return int + * @param AsyncTcpConnection $connection + * @return bool|int * @throws Throwable */ - public static function dealHandshake(string $buffer, TcpConnection $connection): bool|int + public static function dealHandshake(string $buffer, AsyncTcpConnection $connection): bool|int { - $pos = \strpos($buffer, "\r\n\r\n"); + $pos = strpos($buffer, "\r\n\r\n"); if ($pos) { //checking Sec-WebSocket-Accept - if (\preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { - if ($match[1] !== \base64_encode(\sha1($connection->context->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { - Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . \substr($buffer, 0, $pos) . "\n"); + if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) { + if ($match[1] !== base64_encode(sha1($connection->context->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) { + Worker::safeEcho("Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } } else { - Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . \substr($buffer, 0, $pos) . "\n"); + Worker::safeEcho("Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n"); $connection->close(); return 0; } // handshake complete - - // Get WebSocket subprotocol (if specified by server) - if (\preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) { - $connection->websocketServerProtocol = \trim($match[1]); - } - $connection->context->handshakeStep = 2; $handshakeResponseLength = $pos + 4; // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - ($connection->onWebSocketConnect)($connection, \substr($buffer, 0, $handshakeResponseLength)); + ($connection->onWebSocketConnect)($connection, substr($buffer, 0, $handshakeResponseLength)); } catch (Throwable $e) { Worker::stopAll(250, $e); } @@ -414,7 +424,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): // Headbeat. if (!empty($connection->websocketPingInterval)) { $connection->context->websocketPingTimer = Timer::add($connection->websocketPingInterval, function () use ($connection) { - if (false === $connection->send(\pack('H*', '898000000000'), true)) { + if (false === $connection->send(pack('H*', '898000000000'), true)) { Timer::del($connection->context->websocketPingTimer); $connection->context->websocketPingTimer = null; } @@ -426,8 +436,8 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $connection->send($connection->context->tmpWebsocketData, true); $connection->context->tmpWebsocketData = ''; } - if (\strlen($buffer) > $handshakeResponseLength) { - return self::input(\substr($buffer, $handshakeResponseLength), $connection); + if (strlen($buffer) > $handshakeResponseLength) { + return self::input(substr($buffer, $handshakeResponseLength), $connection); } } return 0; From 27e22e72f0e2ede6b3bea5e02b77cccccadc59e9 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 14:25:21 +0800 Subject: [PATCH 0819/1216] format --- src/Timer.php | 65 +++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/Timer.php b/src/Timer.php index 52aa6412b..e47226841 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -11,15 +11,24 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman; +use Exception; use Revolt\EventLoop; +use RuntimeException; +use Swoole\Coroutine\System; +use Throwable; use Workerman\Events\EventInterface; use Workerman\Events\Revolt; -use Workerman\Events\Select; use Workerman\Events\Swoole; -use Swoole\Coroutine\System; -use Exception; +use function function_exists; +use function is_callable; +use function pcntl_alarm; +use function pcntl_signal; +use function time; +use const PHP_INT_MAX; +use const SIGALRM; /** * Timer. @@ -76,8 +85,8 @@ public static function init(EventInterface $event = null) self::$event = $event; return; } - if (\function_exists('pcntl_signal')) { - \pcntl_signal(\SIGALRM, ['\Workerman\Timer', 'signalHandle'], false); + if (function_exists('pcntl_signal')) { + pcntl_signal(SIGALRM, ['\Workerman\Timer', 'signalHandle'], false); } } @@ -89,7 +98,7 @@ public static function init(EventInterface $event = null) public static function signalHandle() { if (!self::$event) { - \pcntl_alarm(1); + pcntl_alarm(1); self::tick(); } } @@ -97,7 +106,7 @@ public static function signalHandle() /** * Add a timer. * - * @param float $timeInterval + * @param float $timeInterval * @param callable $func * @param mixed|array $args * @param bool $persistent @@ -106,7 +115,7 @@ public static function signalHandle() public static function add(float $timeInterval, callable $func, null|array $args = [], bool $persistent = true): int { if ($timeInterval < 0) { - throw new \RuntimeException('$timeInterval can not less than 0'); + throw new RuntimeException('$timeInterval can not less than 0'); } if ($args === null) { @@ -116,27 +125,27 @@ public static function add(float $timeInterval, callable $func, null|array $args if (self::$event) { return $persistent ? self::$event->repeat($timeInterval, $func, $args) : self::$event->delay($timeInterval, $func, $args); } - + // If not workerman runtime just return. if (!Worker::getAllWorkers()) { return false; } - if (!\is_callable($func)) { + if (!is_callable($func)) { Worker::safeEcho(new Exception("not callable")); return false; } if (empty(self::$tasks)) { - \pcntl_alarm(1); + pcntl_alarm(1); } - $runTime = \time() + $timeInterval; + $runTime = time() + $timeInterval; if (!isset(self::$tasks[$runTime])) { self::$tasks[$runTime] = []; } - self::$timerId = self::$timerId == \PHP_INT_MAX ? 1 : ++self::$timerId; + self::$timerId = self::$timerId == PHP_INT_MAX ? 1 : ++self::$timerId; self::$status[self::$timerId] = true; self::$tasks[$runTime][self::$timerId] = [$func, (array)$args, $persistent, $timeInterval]; @@ -169,7 +178,7 @@ public static function sleep(float $delay) usleep($delay * 1000 * 1000); return; } - throw new \RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer install revolt/event-loop" and restart workerman'); + throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer install revolt/event-loop" and restart workerman'); } /** @@ -180,25 +189,25 @@ public static function sleep(float $delay) public static function tick() { if (empty(self::$tasks)) { - \pcntl_alarm(0); + pcntl_alarm(0); return; } - $timeNow = \time(); + $timeNow = time(); foreach (self::$tasks as $runTime => $taskData) { if ($timeNow >= $runTime) { foreach ($taskData as $index => $oneTask) { - $taskFunc = $oneTask[0]; - $taskArgs = $oneTask[1]; - $persistent = $oneTask[2]; + $taskFunc = $oneTask[0]; + $taskArgs = $oneTask[1]; + $persistent = $oneTask[2]; $timeInterval = $oneTask[3]; try { $taskFunc(...$taskArgs); - } catch (\Throwable $e) { + } catch (Throwable $e) { Worker::safeEcho($e); } - if($persistent && !empty(self::$status[$index])) { - $newRunTime = \time() + $timeInterval; - if(!isset(self::$tasks[$newRunTime])) self::$tasks[$newRunTime] = []; + if ($persistent && !empty(self::$status[$index])) { + $newRunTime = time() + $timeInterval; + if (!isset(self::$tasks[$newRunTime])) self::$tasks[$newRunTime] = []; self::$tasks[$newRunTime][$index] = [$taskFunc, (array)$taskArgs, $persistent, $timeInterval]; } } @@ -218,12 +227,12 @@ public static function del(int $timerId): bool if (self::$event) { return self::$event->offDelay($timerId); } - foreach(self::$tasks as $runTime => $taskData) { - if(array_key_exists($timerId, $taskData)) { + foreach (self::$tasks as $runTime => $taskData) { + if (array_key_exists($timerId, $taskData)) { unset(self::$tasks[$runTime][$timerId]); } } - if(array_key_exists($timerId, self::$status)) { + if (array_key_exists($timerId, self::$status)) { unset(self::$status[$timerId]); } return true; @@ -237,8 +246,8 @@ public static function del(int $timerId): bool public static function delAll() { self::$tasks = self::$status = []; - if (\function_exists('pcntl_alarm')) { - \pcntl_alarm(0); + if (function_exists('pcntl_alarm')) { + pcntl_alarm(0); } if (self::$event) { self::$event->deleteAllTimer(); From 91f1f4f40fbcd91b83635cb804fe31637d60259b Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 14:28:29 +0800 Subject: [PATCH 0820/1216] format --- src/Worker.php | 281 ++++++++++++++++++++++++------------------------- 1 file changed, 138 insertions(+), 143 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 2f12eefe5..3e71c5cad 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ + namespace Workerman; use Exception; @@ -473,7 +474,7 @@ class Worker * @var array */ protected static array $globalStatistics = [ - 'start_timestamp' => 0, + 'start_timestamp' => 0, 'worker_exit_info' => [] ]; @@ -492,10 +493,10 @@ class Worker * @var array */ const BUILD_IN_TRANSPORTS = [ - 'tcp' => 'tcp', - 'udp' => 'udp', - 'unix' => 'unix', - 'ssl' => 'tcp' + 'tcp' => 'tcp', + 'udp' => 'udp', + 'unix' => 'unix', + 'ssl' => 'tcp' ]; /** @@ -504,21 +505,21 @@ class Worker * @var array */ const ERROR_TYPE = [ - \E_ERROR => 'E_ERROR', // 1 - \E_WARNING => 'E_WARNING', // 2 - \E_PARSE => 'E_PARSE', // 4 - \E_NOTICE => 'E_NOTICE', // 8 - \E_CORE_ERROR => 'E_CORE_ERROR', // 16 - \E_CORE_WARNING => 'E_CORE_WARNING', // 32 - \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 - \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 - \E_USER_ERROR => 'E_USER_ERROR', // 256 - \E_USER_WARNING => 'E_USER_WARNING', // 512 - \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 - \E_STRICT => 'E_STRICT', // 2048 + \E_ERROR => 'E_ERROR', // 1 + \E_WARNING => 'E_WARNING', // 2 + \E_PARSE => 'E_PARSE', // 4 + \E_NOTICE => 'E_NOTICE', // 8 + \E_CORE_ERROR => 'E_CORE_ERROR', // 16 + \E_CORE_WARNING => 'E_CORE_WARNING', // 32 + \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 + \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 + \E_USER_ERROR => 'E_USER_ERROR', // 256 + \E_USER_WARNING => 'E_USER_WARNING', // 512 + \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 + \E_STRICT => 'E_STRICT', // 2048 \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 - \E_DEPRECATED => 'E_DEPRECATED', // 8192 - \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + \E_DEPRECATED => 'E_DEPRECATED', // 8192 + \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 ]; /** @@ -612,8 +613,8 @@ protected static function init() if (!\is_file(static::$logFile)) { // if /runtime/logs default folder not exists - if(!is_dir(dirname(static::$logFile))){ - @mkdir(dirname(static::$logFile),0777,true); + if (!is_dir(dirname(static::$logFile))) { + @mkdir(dirname(static::$logFile), 0777, true); } \touch(static::$logFile); \chmod(static::$logFile, 0622); @@ -672,7 +673,7 @@ protected static function initWorkers() if (\DIRECTORY_SEPARATOR !== '/') { return; } - static::$statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' .posix_getpid().'.status'; + static::$statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' . posix_getpid() . '.status'; foreach (static::$workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -695,7 +696,7 @@ protected static function initWorkers() $worker->state = ' [OK] '; // Get column mapping for UI - foreach(static::getUiColumns() as $columnName => $prop){ + foreach (static::getUiColumns() as $columnName => $prop) { !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; $propLength = \strlen($worker->{$prop}); $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; @@ -733,7 +734,8 @@ public static function getEventLoop(): EventInterface * Get main socket resource * @return resource */ - public function getMainSocket(){ + public function getMainSocket() + { return $this->mainSocket; } @@ -778,7 +780,7 @@ protected static function displayUI() } if (\DIRECTORY_SEPARATOR !== '/') { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); + static::safeEcho('Workerman version:' . static::VERSION . ' PHP version:' . \PHP_VERSION . "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; @@ -788,24 +790,24 @@ protected static function displayUI() $lineVersion = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); - $lineOne = '' . \str_pad(' WORKERMAN ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . ''. \PHP_EOL; - $lineTwo = \str_pad(' WORKERS ' , $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; + $lineOne = '' . \str_pad(' WORKERMAN ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . '' . \PHP_EOL; + $lineTwo = \str_pad(' WORKERS ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; static::safeEcho($lineOne . $lineVersion . $lineTwo); //Show title $title = ''; - foreach(static::getUiColumns() as $columnName => $prop){ + foreach (static::getUiColumns() as $columnName => $prop) { $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; //just keep compatible with listen name $columnName === 'socket' && $columnName = 'listen'; - $title.= "{$columnName}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); + $title .= "{$columnName}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); } $title && static::safeEcho($title . \PHP_EOL); //Show content foreach (static::$workers as $worker) { $content = ''; - foreach(static::getUiColumns() as $columnName => $prop){ + foreach (static::getUiColumns() as $columnName => $prop) { $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; @@ -821,7 +823,7 @@ protected static function displayUI() if (static::$daemonize) { global $argv; $startFile = $argv[0]; - static::safeEcho('Input "php '. $startFile . ' stop" to stop. Start success.' . "\n\n"); + static::safeEcho('Input "php ' . $startFile . ' stop" to stop. Start success.' . "\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } @@ -838,12 +840,12 @@ protected static function displayUI() public static function getUiColumns(): array { return [ - 'proto' => 'transport', - 'user' => 'user', - 'worker' => 'name', - 'socket' => 'socket', + 'proto' => 'transport', + 'user' => 'user', + 'worker' => 'name', + 'socket' => 'socket', 'processes' => 'count', - 'state' => 'state', + 'state' => 'state', ]; } @@ -856,7 +858,7 @@ public static function getSingleLineTotalLength(): int { $totalLength = 0; - foreach(static::getUiColumns() as $columnName => $prop){ + foreach (static::getUiColumns() as $columnName => $prop) { $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; $totalLength += static::$$key + static::UI_SAFE_LENGTH; } @@ -919,7 +921,7 @@ protected static function parseCommand() static::log("Workerman[$startFile] $command $modeStr"); // Get master process PID. - $masterPid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; + $masterPid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; // Master is still alive? if (static::checkMasterIsAlive($masterPid)) { if ($command === 'start') { @@ -931,7 +933,7 @@ protected static function parseCommand() exit; } - $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.status"; + $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.status"; // execute command. switch ($command) { @@ -969,7 +971,7 @@ protected static function parseCommand() // Waiting amoment. \usleep(500000); // Display statisitcs data from a disk file. - if(\is_readable($statisticsFile)) { + if (\is_readable($statisticsFile)) { \readfile($statisticsFile); } exit(0); @@ -987,7 +989,7 @@ protected static function parseCommand() // Send stop signal to master process. $masterPid && \posix_kill($masterPid, $sig); // Timeout. - $timeout = static::$stopTimeout + 3; + $timeout = static::$stopTimeout + 3; $startTime = \time(); // Check master process is still alive? while (1) { @@ -1014,9 +1016,9 @@ protected static function parseCommand() } break; case 'reload': - if($mode === '-g'){ + if ($mode === '-g') { $sig = \SIGUSR2; - }else{ + } else { $sig = \SIGUSR1; } \posix_kill($masterPid, $sig); @@ -1069,7 +1071,7 @@ protected static function formatStatusData($statisticsFile): string $totalTimers = 0; $maxLen1 = static::$maxSocketNameLength; $maxLen2 = static::$maxWorkerNameLength; - foreach($info as $value) { + foreach ($info as $value) { if (!$readProcessStatus) { $statusStr .= $value . "\n"; if (\preg_match('/^pid.*?memory.*?listening/', $value)) { @@ -1077,13 +1079,13 @@ protected static function formatStatusData($statisticsFile): string } continue; } - if(\preg_match('/^[0-9]+/', $value, $pidMath)) { + if (\preg_match('/^[0-9]+/', $value, $pidMath)) { $pid = $pidMath[0]; $dataWaitingSort[$pid] = $value; - if(\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $totalMemory += \intval(\str_ireplace('M','',$match[1])); - $maxLen1 = \max($maxLen1,\strlen($match[2])); - $maxLen2 = \max($maxLen2,\strlen($match[3])); + if (\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { + $totalMemory += \intval(\str_ireplace('M', '', $match[1])); + $maxLen1 = \max($maxLen1, \strlen($match[2])); + $maxLen2 = \max($maxLen2, \strlen($match[3])); $totalConnections += \intval($match[4]); $totalFails += \intval($match[5]); $totalTimers += \intval($match[6]); @@ -1092,7 +1094,7 @@ protected static function formatStatusData($statisticsFile): string } } } - foreach($workerInfo as $pid => $info) { + foreach ($workerInfo as $pid => $info) { if (!isset($dataWaitingSort[$pid])) { $statusStr .= "$pid\t" . \str_pad('N/A', 7) . " " . \str_pad($info['listen'], static::$maxSocketNameLength) . " " @@ -1108,16 +1110,16 @@ protected static function formatStatusData($statisticsFile): string $qps = $currentTotalRequest[$pid] - $totalRequestCache[$pid]; $totalQps += $qps; } - $statusStr .= $dataWaitingSort[$pid]. " " . \str_pad($qps, 6) ." [idle]\n"; + $statusStr .= $dataWaitingSort[$pid] . " " . \str_pad($qps, 6) . " [idle]\n"; } $totalRequestCache = $currentTotalRequest; $statusStr .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $statusStr .= "Summary\t" . \str_pad($totalMemory.'M', 7) . " " + $statusStr .= "Summary\t" . \str_pad($totalMemory . 'M', 7) . " " . \str_pad('-', $maxLen1) . " " . \str_pad('-', $maxLen2) . " " . \str_pad($totalConnections, 11) . " " . \str_pad($totalFails, 9) . " " . \str_pad($totalTimers, 7) . " " . \str_pad($totalRequests, 13) . " " - . \str_pad($totalQps,6)." [Summary] \n"; + . \str_pad($totalQps, 6) . " [Summary] \n"; return $statusStr; } @@ -1242,7 +1244,8 @@ public static function resetStd(bool $throwException = true) $handle = \fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - \set_error_handler(function(){}); + \set_error_handler(function () { + }); if ($STDOUT) { \fclose($STDOUT); } @@ -1388,15 +1391,11 @@ protected static function forkWorkersForLinux() protected static function forkWorkersForWindows() { $files = static::getStartFilesForWindows(); - if(\in_array('-q', static::getArgv()) || \count($files) === 1) - { - if(\count(static::$workers) > 1) - { + if (\in_array('-q', static::getArgv()) || \count($files) === 1) { + if (\count(static::$workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); static::safeEcho("@@@ See https://www.workerman.net/doc/workerman/faq/multi-woker-for-windows.html @@@\r\n"); - } - elseif(\count(static::$workers) <= 0) - { + } elseif (\count(static::$workers) <= 0) { exit("@@@no worker inited@@@\r\n\r\n"); } @@ -1409,16 +1408,13 @@ protected static function forkWorkersForWindows() $worker->listen(); $worker->run(); exit("@@@child exit@@@\r\n"); - } - else - { + } else { static::$globalEvent = new Select(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); }); Timer::init(static::$globalEvent); - foreach($files as $startFile) - { + foreach ($files as $startFile) { static::forkOneWorkerForWindows($startFile); } } @@ -1432,10 +1428,8 @@ protected static function forkWorkersForWindows() public static function getStartFilesForWindows(): array { $files = []; - foreach(static::getArgv() as $file) - { - if(\is_file($file)) - { + foreach (static::getArgv() as $file) { + if (\is_file($file)) { $files[$file] = $file; } } @@ -1455,8 +1449,8 @@ public static function forkOneWorkerForWindows(string $startFile) STDIN, STDOUT, STDOUT ); - $pipes = array(); - $process = \proc_open("php \"$startFile\" -q", $descriptorspec, $pipes); + $pipes = array(); + $process = \proc_open("php \"$startFile\" -q", $descriptorspec, $pipes); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1476,22 +1470,17 @@ public static function forkOneWorkerForWindows(string $startFile) */ public static function checkWorkerStatusForWindows() { - foreach(static::$processForWindows as $processData) - { + foreach (static::$processForWindows as $processData) { $process = $processData[0]; $startFile = $processData[1]; $status = \proc_get_status($process); - if(isset($status['running'])) - { - if(!$status['running']) - { + if (isset($status['running'])) { + if (!$status['running']) { static::safeEcho("process $startFile terminated and try to restart\n"); \proc_close($process); static::forkOneWorkerForWindows($startFile); } - } - else - { + } else { static::safeEcho("proc_get_status fail\n"); } } @@ -1511,7 +1500,7 @@ protected static function forkOneWorkerForLinux(self $worker) // For master process. if ($pid > 0) { static::$pidMap[$worker->workerId][$pid] = $pid; - static::$idMap[$worker->workerId][$id] = $pid; + static::$idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { \srand(); @@ -1523,9 +1512,9 @@ protected static function forkOneWorkerForLinux(self $worker) if (static::$status === static::STATUS_STARTING) { static::resetStd(); } - static::$pidsToRestart = static::$pidMap = []; + static::$pidsToRestart = static::$pidMap = []; // Remove other listener. - foreach(static::$workers as $key => $oneWorker) { + foreach (static::$workers as $key => $oneWorker) { if ($oneWorker->workerId !== $worker->workerId) { $oneWorker->unlisten(); unset(static::$workers[$key]); @@ -1602,7 +1591,8 @@ public function setUserAndGroup() */ protected static function setProcessTitle(string $title) { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); \cli_set_process_title($title); \restore_error_handler(); } @@ -1635,7 +1625,7 @@ protected static function monitorWorkersForLinux() \pcntl_signal_dispatch(); // Suspends execution of the current process until a child has exited, or until a signal is delivered $status = 0; - $pid = \pcntl_wait($status, \WUNTRACED); + $pid = \pcntl_wait($status, \WUNTRACED); // Calls signal handlers for pending signals again. \pcntl_signal_dispatch(); // If a child has already exited. @@ -1789,7 +1779,7 @@ protected static function reload() // Send reload signal to a worker process. \posix_kill($oneWorkerPid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. - if(!static::$gracefulStop){ + if (!static::$gracefulStop) { Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, \SIGKILL], false); } } // For child processes. @@ -1839,7 +1829,7 @@ public static function stopAll(int $code = 0, mixed $log = '') } else { \posix_kill($workerPid, $sig); } - if(!static::$gracefulStop){ + if (!static::$gracefulStop) { Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, \SIGKILL], false); } } @@ -1852,7 +1842,7 @@ public static function stopAll(int $code = 0, mixed $log = '') else { // Execute exit. foreach (static::$workers as $worker) { - if(!$worker->stopping){ + if (!$worker->stopping) { $worker->stop(); $worker->stopping = true; } @@ -1916,16 +1906,16 @@ protected static function writeStatisticsToStatusFile() // For master process. if (static::$masterPid === \posix_getpid()) { $allWorkerInfo = []; - foreach(static::$pidMap as $workerId => $pidArray) { + foreach (static::$pidMap as $workerId => $pidArray) { /** @var /Workerman/Worker $worker */ $worker = static::$workers[$workerId]; - foreach($pidArray as $pid) { + foreach ($pidArray as $pid) { $allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } - \file_put_contents(static::$statisticsFile, \serialize($allWorkerInfo)."\n", \FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2,2,2]) : ['-', '-', '-']; + \file_put_contents(static::$statisticsFile, \serialize($allWorkerInfo) . "\n", \FILE_APPEND); + $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; \file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); \file_put_contents(static::$statisticsFile, @@ -1961,7 +1951,7 @@ protected static function writeStatisticsToStatusFile() \file_put_contents(static::$statisticsFile, "pid\tmemory " . \str_pad('listening', static::$maxSocketNameLength) . " " . \str_pad('worker_name', static::$maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " - . \str_pad('timers', 8) . \str_pad('total_request', 13) ." qps status\n", \FILE_APPEND); + . \str_pad('timers', 8) . \str_pad('total_request', 13) . " qps status\n", \FILE_APPEND); \chmod(static::$statisticsFile, 0722); @@ -1978,13 +1968,13 @@ protected static function writeStatisticsToStatusFile() } \reset(static::$workers); /** @var static $worker */ - $worker = current(static::$workers); + $worker = current(static::$workers); $workerStatusStr = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; $workerStatusStr .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) - . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) + . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; \file_put_contents(static::$statisticsFile, $workerStatusStr, \FILE_APPEND); @@ -2009,21 +1999,20 @@ protected static function writeConnectionsStatisticsToStatusFile() } // For child processes. - $bytesFormat = function($bytes) - { - if($bytes > 1024*1024*1024*1024) { - return round($bytes/(1024*1024*1024*1024), 1)."TB"; + $bytesFormat = function ($bytes) { + if ($bytes > 1024 * 1024 * 1024 * 1024) { + return round($bytes / (1024 * 1024 * 1024 * 1024), 1) . "TB"; } - if($bytes > 1024*1024*1024) { - return round($bytes/(1024*1024*1024), 1)."GB"; + if ($bytes > 1024 * 1024 * 1024) { + return round($bytes / (1024 * 1024 * 1024), 1) . "GB"; } - if($bytes > 1024*1024) { - return round($bytes/(1024*1024), 1)."MB"; + if ($bytes > 1024 * 1024) { + return round($bytes / (1024 * 1024), 1) . "MB"; } - if($bytes > 1024) { - return round($bytes/(1024), 1)."KB"; + if ($bytes > 1024) { + return round($bytes / (1024), 1) . "KB"; } - return $bytes."B"; + return $bytes . "B"; }; $pid = \posix_getpid(); @@ -2033,23 +2022,23 @@ protected static function writeConnectionsStatisticsToStatusFile() $defaultWorkerName = $currentWorker->name; /** @var static $worker */ - foreach(TcpConnection::$connections as $connection) { + foreach (TcpConnection::$connections as $connection) { /** @var \Workerman\Connection\TcpConnection $connection */ - $transport = $connection->transport; - $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; - $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; - $recvQ = $bytesFormat($connection->getRecvBufferQueueSize()); - $sendQ = $bytesFormat($connection->getSendBufferQueueSize()); - $localAddress = \trim($connection->getLocalAddress()); + $transport = $connection->transport; + $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; + $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; + $recvQ = $bytesFormat($connection->getRecvBufferQueueSize()); + $sendQ = $bytesFormat($connection->getSendBufferQueueSize()); + $localAddress = \trim($connection->getLocalAddress()); $remoteAddress = \trim($connection->getRemoteAddress()); - $state = $connection->getStatus(false); - $bytesRead = $bytesFormat($connection->bytesRead); - $bytesWritten = $bytesFormat($connection->bytesWritten); - $id = $connection->id; - $protocol = $connection->protocol ? $connection->protocol : $connection->transport; - $pos = \strrpos($protocol, '\\'); + $state = $connection->getStatus(false); + $bytesRead = $bytesFormat($connection->bytesRead); + $bytesWritten = $bytesFormat($connection->bytesWritten); + $id = $connection->id; + $protocol = $connection->protocol ? $connection->protocol : $connection->transport; + $pos = \strrpos($protocol, '\\'); if ($pos) { - $protocol = \substr($protocol, $pos+1); + $protocol = \substr($protocol, $pos + 1); } if (\strlen($protocol) > 15) { $protocol = \substr($protocol, 0, 13) . '..'; @@ -2058,10 +2047,10 @@ protected static function writeConnectionsStatisticsToStatusFile() if (\strlen($workerName) > 14) { $workerName = \substr($workerName, 0, 12) . '..'; } - $str .= \str_pad($pid, 9) . \str_pad($workerName, 16) . \str_pad($id, 10) . \str_pad($transport, 8) + $str .= \str_pad($pid, 9) . \str_pad($workerName, 16) . \str_pad($id, 10) . \str_pad($transport, 8) . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recvQ, 13) . \str_pad($sendQ, 13) . \str_pad($bytesRead, 13) . \str_pad($bytesWritten, 13) . ' ' - . \str_pad($state, 14) . ' ' . \str_pad($localAddress, 22) . ' ' . \str_pad($remoteAddress, 22) ."\n"; + . \str_pad($state, 14) . ' ' . \str_pad($localAddress, 22) . ' ' . \str_pad($remoteAddress, 22) . "\n"; } if ($str) { \file_put_contents(static::$statisticsFile, $str, \FILE_APPEND); @@ -2076,8 +2065,8 @@ protected static function writeConnectionsStatisticsToStatusFile() public static function checkErrors() { if (static::STATUS_SHUTDOWN !== static::$status) { - $errorMsg = \DIRECTORY_SEPARATOR === '/' ? 'Worker['. \posix_getpid() .'] process terminated' : 'Worker process terminated'; - $errors = error_get_last(); + $errorMsg = \DIRECTORY_SEPARATOR === '/' ? 'Worker[' . \posix_getpid() . '] process terminated' : 'Worker process terminated'; + $errors = error_get_last(); if ($errors && ($errors['type'] === \E_ERROR || $errors['type'] === \E_PARSE || $errors['type'] === \E_CORE_ERROR || @@ -2268,7 +2257,8 @@ public function listen() // Try to open keepalive for tcp and disable Nagle algorithm. if (\function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); $socket = \socket_import_stream($this->mainSocket); \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1); @@ -2287,10 +2277,12 @@ public function listen() * * @return void */ - public function unlisten() { + public function unlisten() + { $this->pauseAccept(); if ($this->mainSocket) { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); \fclose($this->mainSocket); \restore_error_handler(); $this->mainSocket = null; @@ -2311,8 +2303,8 @@ protected function parseSocketAddress(): ?string list($scheme, $address) = \explode(':', $this->socketName, 2); // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { - $scheme = \ucfirst($scheme); - $this->protocol = \substr($scheme,0,1)==='\\' ? $scheme : 'Protocols\\' . $scheme; + $scheme = \ucfirst($scheme); + $this->protocol = \substr($scheme, 0, 1) === '\\' ? $scheme : 'Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { $this->protocol = "Workerman\\Protocols\\$scheme"; if (!\class_exists($this->protocol)) { @@ -2404,7 +2396,8 @@ public function run() // Set an empty onMessage callback. if (empty($this->onMessage)) { - $this->onMessage = function () {}; + $this->onMessage = function () { + }; } \restore_error_handler(); @@ -2460,7 +2453,8 @@ public function stop() public function acceptTcpConnection($socket) { // Accept a connection on server socket. - \set_error_handler(function(){}); + \set_error_handler(function () { + }); $newSocket = \stream_socket_accept($socket, 0, $remoteAddress); \restore_error_handler(); @@ -2470,16 +2464,16 @@ public function acceptTcpConnection($socket) } // TcpConnection. - $connection = new TcpConnection(Worker::$globalEvent, $newSocket, $remoteAddress); + $connection = new TcpConnection(Worker::$globalEvent, $newSocket, $remoteAddress); $this->connections[$connection->id] = $connection; - $connection->worker = $this; - $connection->protocol = $this->protocol; - $connection->transport = $this->transport; - $connection->onMessage = $this->onMessage; - $connection->onClose = $this->onClose; - $connection->onError = $this->onError; - $connection->onBufferDrain = $this->onBufferDrain; - $connection->onBufferFull = $this->onBufferFull; + $connection->worker = $this; + $connection->protocol = $this->protocol; + $connection->transport = $this->transport; + $connection->onMessage = $this->onMessage; + $connection->onClose = $this->onClose; + $connection->onError = $this->onError; + $connection->onBufferDrain = $this->onBufferDrain; + $connection->onBufferFull = $this->onBufferFull; // Try to emit onConnect callback. if ($this->onConnect) { @@ -2499,14 +2493,15 @@ public function acceptTcpConnection($socket) */ public function acceptUdpConnection($socket): bool { - \set_error_handler(function(){}); + \set_error_handler(function () { + }); $recvBuffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); \restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { return false; } // UdpConnection. - $connection = new UdpConnection($socket, $remoteAddress); + $connection = new UdpConnection($socket, $remoteAddress); $connection->protocol = $this->protocol; $messageCb = $this->onMessage; if ($messageCb) { From 41a46d75300f1f03fbfd26593891ef8355e4d427 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 16:02:49 +0800 Subject: [PATCH 0821/1216] Update --- src/Connection/ConnectionInterface.php | 18 +++------------- src/Connection/TcpConnection.php | 29 ++++++++++++++++++++++++++ src/Connection/UdpConnection.php | 29 ++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index c85cb5bfe..43b96406b 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -83,7 +83,7 @@ abstract class ConnectionInterface /** * @var ?EventInterface */ - public ?EventInterface $eventLoop; + public ?EventInterface $eventLoop = null; /** * @var ?callable @@ -154,26 +154,14 @@ abstract public function close(mixed $data = null, bool $raw = false); * * return bool. */ - public function isIpV4(): bool - { - if ($this->transport === 'unix') { - return false; - } - return !str_contains($this->getRemoteIp(), ':'); - } + abstract public function isIpV4(): bool; /** * Is ipv6. * * return bool. */ - public function isIpV6(): bool - { - if ($this->transport === 'unix') { - return false; - } - return str_contains($this->getRemoteIp(), ':'); - } + abstract public function isIpV6(): bool; /** * @param Throwable $exception diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 979eb7197..818b1541d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -14,6 +14,7 @@ namespace Workerman\Connection; +use JetBrains\PhpStorm\Pure; use JsonSerializable; use stdClass; use Throwable; @@ -891,6 +892,34 @@ public function close(mixed $data = null, bool $raw = false) } } + /** + * Is ipv4. + * + * return bool. + */ + #[Pure] + public function isIpV4(): bool + { + if ($this->transport === 'unix') { + return false; + } + return !str_contains($this->getRemoteIp(), ':'); + } + + /** + * Is ipv6. + * + * return bool. + */ + #[Pure] + public function isIpV6(): bool + { + if ($this->transport === 'unix') { + return false; + } + return str_contains($this->getRemoteIp(), ':'); + } + /** * Get the real socket. * diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 1bfeee809..0346a8c2c 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -15,6 +15,7 @@ namespace Workerman\Connection; use JetBrains\PhpStorm\ArrayShape; +use JetBrains\PhpStorm\Pure; use JsonSerializable; use Workerman\Protocols\ProtocolInterface; use function stream_socket_get_name; @@ -175,6 +176,34 @@ public function close(mixed $data = null, bool $raw = false) $this->eventLoop = $this->errorHandler = null; } + /** + * Is ipv4. + * + * return bool. + */ + #[Pure] + public function isIpV4(): bool + { + if ($this->transport === 'unix') { + return false; + } + return !str_contains($this->getRemoteIp(), ':'); + } + + /** + * Is ipv6. + * + * return bool. + */ + #[Pure] + public function isIpV6(): bool + { + if ($this->transport === 'unix') { + return false; + } + return str_contains($this->getRemoteIp(), ':'); + } + /** * Get the real socket. * From c5fdf9a2439cd5f6e3ac5702ebac804e0755e39f Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 17:33:16 +0800 Subject: [PATCH 0822/1216] update --- src/Connection/AsyncUdpConnection.php | 6 +++--- src/Connection/UdpConnection.php | 7 +++++++ src/Protocols/Http/Request.php | 3 +++ src/Worker.php | 8 +------- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 4cd8bda11..fa3aff5e2 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -99,7 +99,7 @@ public function __construct($remoteAddress, $contextOption = []) */ public function baseRead($socket) { - $recvBuffer = stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); + $recvBuffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); if (false === $recvBuffer || empty($remoteAddress)) { return; } @@ -194,13 +194,13 @@ public function connect() if (!$this->socket) { Worker::safeEcho(new Exception($errmsg)); + $this->eventLoop = null; return; } stream_set_blocking($this->socket, false); - if ($this->onMessage) { - $this->eventLoop->onWritable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); } $this->connected = true; // Try to emit onConnect callback. diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 0346a8c2c..07937e7ce 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -31,6 +31,13 @@ */ class UdpConnection extends ConnectionInterface implements JsonSerializable { + /** + * Max udp package size. + * + * @var int + */ + const MAX_UDP_PACKAGE_SIZE = 65535; + /** * Transport layer protocol. * diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 43b5df52b..55b69f559 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -653,6 +653,9 @@ public static function createSessionId(): string */ protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) { + if (!$this->connection) { + throw new RuntimeException('Request->setSidCookie() fail, header already send'); + } $this->connection->headers['Set-Cookie'] = [$sessionName . '=' . $sid . (empty($cookieParams['domain']) ? '' : '; Domain=' . $cookieParams['domain']) . (empty($cookieParams['lifetime']) ? '' : '; Max-Age=' . $cookieParams['lifetime']) diff --git a/src/Worker.php b/src/Worker.php index 3e71c5cad..8f5e65f62 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -74,12 +74,6 @@ class Worker * @var int */ const DEFAULT_BACKLOG = 102400; - /** - * Max udp package size. - * - * @var int - */ - const MAX_UDP_PACKAGE_SIZE = 65535; /** * The safe distance for columns adjacent @@ -2495,7 +2489,7 @@ public function acceptUdpConnection($socket): bool { \set_error_handler(function () { }); - $recvBuffer = \stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); + $recvBuffer = \stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); \restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { return false; From 0cd85cfc6a3002489006d800b37c1f82096916ab Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 20:24:08 +0800 Subject: [PATCH 0823/1216] Fix reload --- src/Worker.php | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 8f5e65f62..555f698af 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -586,7 +586,7 @@ protected static function checkSapiEnv() protected static function init() { \set_error_handler(function ($code, $msg, $file, $line) { - Worker::safeEcho("$msg in file $file on line $line\n"); + static::safeEcho("$msg in file $file on line $line\n"); }); // Start file. @@ -1178,6 +1178,9 @@ public static function signalHandler(int $signal) // Reload. case \SIGUSR2: case \SIGUSR1: + if (static::$status === static::STATUS_RELOADING || static::$status === static::STATUS_SHUTDOWN) { + return; + } static::$gracefulStop = $signal === \SIGUSR2; static::$pidsToRestart = static::getAllWorkerPids(); static::reload(); @@ -1723,6 +1726,7 @@ protected static function reload() { // For master process. if (static::$masterPid === \posix_getpid()) { + $sig = static::$gracefulStop ? \SIGUSR2 : \SIGUSR1; // Set reloading state. if (static::$status !== static::STATUS_RELOADING && static::$status !== static::STATUS_SHUTDOWN) { static::log("Workerman[" . \basename(static::$startFile) . "] reloading"); @@ -1738,29 +1742,26 @@ protected static function reload() } static::initId(); } - } - $sig = static::$gracefulStop ? \SIGUSR2 : \SIGUSR1; - - // Send reload signal to all child processes. - $reloadablePidArray = []; - foreach (static::$pidMap as $workerId => $workerPidArray) { - $worker = static::$workers[$workerId]; - if ($worker->reloadable) { - foreach ($workerPidArray as $pid) { - $reloadablePidArray[$pid] = $pid; - } - } else { - foreach ($workerPidArray as $pid) { - // Send reload signal to a worker process which reloadable is false. - \posix_kill($pid, $sig); + // Send reload signal to all child processes. + $reloadablePidArray = []; + foreach (static::$pidMap as $workerId => $workerPidArray) { + $worker = static::$workers[$workerId]; + if ($worker->reloadable) { + foreach ($workerPidArray as $pid) { + $reloadablePidArray[$pid] = $pid; + } + } else { + foreach ($workerPidArray as $pid) { + // Send reload signal to a worker process which reloadable is false. + \posix_kill($pid, $sig); + } } } + // Get all pids that are waiting reload. + static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadablePidArray); } - // Get all pids that are waiting reload. - static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadablePidArray); - // Reload complete. if (empty(static::$pidsToRestart)) { if (static::$status !== static::STATUS_SHUTDOWN) { @@ -1818,7 +1819,7 @@ public static function stopAll(int $code = 0, mixed $log = '') $sig = static::$gracefulStop ? \SIGQUIT : \SIGINT; foreach ($workerPidArray as $workerPid) { // Fix exit with status 2 for php8.2 - if ($sig === \SIGINT && !Worker::$daemonize) { + if ($sig === \SIGINT && !static::$daemonize) { Timer::add(1, '\posix_kill', [$workerPid, \SIGINT], false); } else { \posix_kill($workerPid, $sig); @@ -2423,7 +2424,7 @@ public function stop() try { ($this->onWorkerStop)($this); } catch (Throwable $e) { - Worker::log($e); + static::log($e); } } // Remove listener for server socket. @@ -2458,7 +2459,7 @@ public function acceptTcpConnection($socket) } // TcpConnection. - $connection = new TcpConnection(Worker::$globalEvent, $newSocket, $remoteAddress); + $connection = new TcpConnection(static::$globalEvent, $newSocket, $remoteAddress); $this->connections[$connection->id] = $connection; $connection->worker = $this; $connection->protocol = $this->protocol; From 13191067186077f8c759d103e322923153a349eb Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 31 Jan 2023 20:53:27 +0800 Subject: [PATCH 0824/1216] unlink statistics file --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index 555f698af..7cbdedd73 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -952,6 +952,7 @@ protected static function parseCommand() // Echo status data. static::safeEcho(static::formatStatusData($statisticsFile)); if ($mode !== '-d') { + @\unlink($statisticsFile); exit(0); } static::safeEcho("\nPress Ctrl+C to quit.\n\n"); From 943325ea0090e9c9036e96c9e8b1bedb2439cf20 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Feb 2023 15:18:33 +0800 Subject: [PATCH 0825/1216] Fix tips --- src/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index e47226841..1829160b0 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -178,7 +178,7 @@ public static function sleep(float $delay) usleep($delay * 1000 * 1000); return; } - throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer install revolt/event-loop" and restart workerman'); + throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer require revolt/event-loop" and restart workerman'); } /** From d46a0c1621383ad07d59286ee82661291ddf37c8 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Feb 2023 16:45:21 +0800 Subject: [PATCH 0826/1216] fix header return type --- src/Protocols/Http/Request.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 55b69f559..ece0cf860 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -129,9 +129,9 @@ public function get(string $name = null, mixed $default = null): array|string|nu * * @param string|null $name * @param mixed|null $default - * @return string|null|array + * @return array|string|null */ - public function post(string $name = null, mixed $default = null): string|null|array + public function post(string $name = null, mixed $default = null): array|string|null { if (!isset($this->data['post'])) { $this->parsePost(); @@ -147,9 +147,9 @@ public function post(string $name = null, mixed $default = null): string|null|ar * * @param string|null $name * @param mixed|null $default - * @return string|null + * @return array|string|null */ - public function header(string $name = null, mixed $default = null): ?string + public function header(string $name = null, mixed $default = null): array|string|null { if (!isset($this->data['headers'])) { $this->parseHeaders(); From 51804005ecc6350dc1a9b5c04d01cede33fbe174 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 1 Feb 2023 16:50:57 +0800 Subject: [PATCH 0827/1216] fix typo --- src/Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ece0cf860..2eb7b27f4 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -406,8 +406,8 @@ protected function parseHeadFirstLine() protected function parseProtocolVersion() { $firstLine = strstr($this->buffer, "\r\n", true); - $protocoVersion = substr(strstr($firstLine, 'HTTP/'), 5); - $this->data['protocolVersion'] = $protocoVersion ?: '1.0'; + $protocolVersion = substr(strstr($firstLine, 'HTTP/'), 5); + $this->data['protocolVersion'] = $protocolVersion ?: '1.0'; } /** From cdd671f6fe8322f0e17c49037c4e4192d3b71782 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Feb 2023 10:38:23 +0800 Subject: [PATCH 0828/1216] Update --- src/Connection/AsyncTcpConnection.php | 20 ++++----- src/Worker.php | 58 +++++++++++++++------------ 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index d1b54e63a..02f8f54fa 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -126,7 +126,7 @@ class AsyncTcpConnection extends TcpConnection * * @var array */ - protected array $contextOption = []; + protected array $socketContext = []; /** * Reconnect timer. * @@ -138,10 +138,10 @@ class AsyncTcpConnection extends TcpConnection * Construct. * * @param string $remoteAddress - * @param array $contextOption + * @param array $socketContext * @throws Exception */ - public function __construct(string $remoteAddress, array $contextOption = []) + public function __construct(string $remoteAddress, array $socketContext = []) { $addressInfo = parse_url($remoteAddress); if (!$addressInfo) { @@ -195,7 +195,7 @@ public function __construct(string $remoteAddress, array $contextOption = []) ++self::$statistics['connection_count']; $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; - $this->contextOption = $contextOption; + $this->socketContext = $socketContext; static::$connections[$this->realId] = $this; $this->context = new stdClass; } @@ -247,24 +247,24 @@ public function connect() } // Open socket connection asynchronously. if ($this->proxySocks5) { - $this->contextOption['ssl']['peer_name'] = $this->remoteHost; - $context = stream_context_create($this->contextOption); + $this->socketContext['ssl']['peer_name'] = $this->remoteHost; + $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->proxySocks5", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); fwrite($this->socket, chr(5) . chr(1) . chr(0)); fread($this->socket, 512); fwrite($this->socket, chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); fread($this->socket, 512); } else if ($this->proxyHttp) { - $this->contextOption['ssl']['peer_name'] = $this->remoteHost; - $context = stream_context_create($this->contextOption); + $this->socketContext['ssl']['peer_name'] = $this->remoteHost; + $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->proxyHttp", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); $str = "CONNECT $this->remoteHost:$this->remotePort HTTP/1.1\n"; $str .= "Host: $this->remoteHost:$this->remotePort\n"; $str .= "Proxy-Connection: keep-alive\n"; fwrite($this->socket, $str); fread($this->socket, 512); - } else if ($this->contextOption) { - $context = stream_context_create($this->contextOption); + } else if ($this->socketContext) { + $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->remoteHost:$this->remotePort", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); } else { diff --git a/src/Worker.php b/src/Worker.php index 7cbdedd73..cde857639 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -15,6 +15,7 @@ namespace Workerman; use Exception; +use stdClass; use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; @@ -201,13 +202,6 @@ class Worker */ public $onWorkerReload = null; - /** - * Emitted when worker processes exited. - * - * @var ?callable - */ - public $onWorkerExit = null; - /** * Transport layer protocol. * @@ -298,6 +292,13 @@ class Worker */ public static $onMasterStop = null; + /** + * Emitted when worker processes exited. + * + * @var ?callable + */ + public static $onWorkerExit = null; + /** * EventLoopClass * @@ -359,7 +360,12 @@ class Worker * * @var resource */ - protected $context = null; + protected $socketContext = null; + + /** + * @var stdClass + */ + protected stdClass $context; /** * All worker instances. @@ -684,15 +690,15 @@ protected static function initWorkers() } // Socket name. - $worker->socket = $worker->getSocketName(); + $worker->context->statusSocket = $worker->getSocketName(); // Status name. - $worker->state = ' [OK] '; + $worker->context->statusState = ' [OK] '; // Get column mapping for UI foreach (static::getUiColumns() as $columnName => $prop) { - !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN'; - $propLength = \strlen($worker->{$prop}); + !isset($worker->$prop) && !isset($worker->context->$prop) && $worker->context->$prop = 'NNNN'; + $propLength = \strlen($worker->$prop ?? $worker->context->$prop); $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; static::$$key = \max(static::$$key, $propLength); } @@ -802,10 +808,11 @@ protected static function displayUI() foreach (static::$workers as $worker) { $content = ''; foreach (static::getUiColumns() as $columnName => $prop) { + $propValue = $worker->$prop ?? $worker->context->$prop; $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; - \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $worker->{$prop}, $matches); + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $propValue, $matches); $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; - $content .= \str_pad($worker->{$prop}, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); + $content .= \str_pad($propValue, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); } $content && static::safeEcho($content . \PHP_EOL); } @@ -837,9 +844,9 @@ public static function getUiColumns(): array 'proto' => 'transport', 'user' => 'user', 'worker' => 'name', - 'socket' => 'socket', + 'socket' => 'statusSocket', 'processes' => 'count', - 'state' => 'state', + 'state' => 'statusState', ]; } @@ -1642,9 +1649,9 @@ protected static function monitorWorkersForLinux() } // onWorkerExit - if ($worker->onWorkerExit) { + if (static::$onWorkerExit) { try { - ($worker->onWorkerExit)($worker, $status, $pid); + (static::$onWorkerExit)($worker, $status, $pid); } catch (Throwable $exception) { static::log("worker[{$worker->name}] onWorkerExit $exception"); } @@ -2166,22 +2173,23 @@ private static function outputStream($stream = null) * Constructor. * * @param string|null $socketName - * @param array $contextOption + * @param array $socketContext */ - public function __construct(string $socketName = null, array $contextOption = []) + public function __construct(string $socketName = null, array $socketContext = []) { // Save all worker instances. $this->workerId = \spl_object_hash($this); + $this->context = new stdClass(); static::$workers[$this->workerId] = $this; static::$pidMap[$this->workerId] = []; // Context for socket. if ($socketName) { $this->socketName = $socketName; - if (!isset($contextOption['socket']['backlog'])) { - $contextOption['socket']['backlog'] = static::DEFAULT_BACKLOG; + if (!isset($socketContext['socket']['backlog'])) { + $socketContext['socket']['backlog'] = static::DEFAULT_BACKLOG; } - $this->context = \stream_context_create($contextOption); + $this->socketContext = \stream_context_create($socketContext); } // Try to turn reusePort on. @@ -2230,11 +2238,11 @@ public function listen() $errmsg = ''; // SO_REUSEPORT. if ($this->reusePort) { - \stream_context_set_option($this->context, 'socket', 'so_reuseport', 1); + \stream_context_set_option($this->socketContext, 'socket', 'so_reuseport', 1); } // Create an Internet or Unix domain server socket. - $this->mainSocket = \stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->context); + $this->mainSocket = \stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->socketContext); if (!$this->mainSocket) { throw new Exception($errmsg); } From bdc535ac18318a93d2f066c204e56d2f5a422c3c Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Feb 2023 11:46:57 +0800 Subject: [PATCH 0829/1216] Support innerworker onWorkerStart --- src/Worker.php | 73 ++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index cde857639..539b10fed 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1526,10 +1526,36 @@ protected static function forkOneWorkerForLinux(self $worker) } } Timer::delAll(); + + //Update process state. + static::$status = static::STATUS_RUNNING; + + // Register shutdown function for checking errors. + \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); + + // Create a global event loop. + if (!static::$globalEvent) { + $eventLoopClass = static::getEventLoopName(); + static::$globalEvent = new $eventLoopClass; + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); + } + + // Reinstall signal. + static::reinstallSignal(); + + // Init Timer. + Timer::init(static::$globalEvent); + + \restore_error_handler(); + static::setProcessTitle(self::$processTitle . ': worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); + // Main loop. + static::$globalEvent->run(); if (static::$status !== self::STATUS_SHUTDOWN) { $err = new Exception('event-loop exited'); static::log($err); @@ -1844,7 +1870,8 @@ public static function stopAll(int $code = 0, mixed $log = '') } // For child processes. else { // Execute exit. - foreach (static::$workers as $worker) { + $workers = array_reverse(static::$workers); + foreach ($workers as $worker) { if (!$worker->stopping) { $worker->stop(); $worker->stopping = true; @@ -2373,38 +2400,11 @@ public function getSocketName(): string * Run worker instance. * * @return void + * @throws Throwable */ public function run() { - //Update process state. - static::$status = static::STATUS_RUNNING; - - // Register shutdown function for checking errors. - \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); - - // Create a global event loop. - if (!static::$globalEvent) { - $eventLoopClass = static::getEventLoopName(); - static::$globalEvent = new $eventLoopClass; - static::$globalEvent->setErrorHandler(function ($exception) { - static::stopAll(250, $exception); - }); - $this->resumeAccept(); - } - - // Reinstall signal. - static::reinstallSignal(); - - // Init Timer. - Timer::init(static::$globalEvent); - - // Set an empty onMessage callback. - if (empty($this->onMessage)) { - $this->onMessage = function () { - }; - } - - \restore_error_handler(); + $this->listen(); // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { @@ -2416,9 +2416,6 @@ public function run() static::stopAll(250, $e); } } - - // Main loop. - static::$globalEvent->run(); } /** @@ -2507,8 +2504,8 @@ public function acceptUdpConnection($socket): bool // UdpConnection. $connection = new UdpConnection($socket, $remoteAddress); $connection->protocol = $this->protocol; - $messageCb = $this->onMessage; - if ($messageCb) { + $messageCallback = $this->onMessage; + if ($messageCallback) { try { if ($this->protocol !== null) { /** @var \Workerman\Protocols\ProtocolInterface $parser */ @@ -2524,7 +2521,7 @@ public function acceptUdpConnection($socket): bool if ($data === false) { continue; } - $messageCb($connection, $data); + $messageCallback($connection, $data); } } else { $data = $parser::decode($recvBuffer, $connection); @@ -2532,10 +2529,10 @@ public function acceptUdpConnection($socket): bool if ($data === false) { return true; } - $messageCb($connection, $data); + $messageCallback($connection, $data); } } else { - $messageCb($connection, $recvBuffer); + $messageCallback($connection, $recvBuffer); } ++ConnectionInterface::$statistics['total_request']; } catch (Throwable $e) { From 3033d668ca6355ed3a7e79d4fa5ff4524c837ebe Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Feb 2023 12:08:20 +0800 Subject: [PATCH 0830/1216] Delete worker when stop --- src/Worker.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 539b10fed..25042485b 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1511,9 +1511,6 @@ protected static function forkOneWorkerForLinux(self $worker) \srand(); \mt_srand(); static::$gracefulStop = false; - if ($worker->reusePort) { - $worker->listen(); - } if (static::$status === static::STATUS_STARTING) { static::resetStd(); } @@ -2441,6 +2438,12 @@ public function stop() $connection->close(); } } + // Remove worker. + foreach(static::$workers as $key => $one_worker) { + if ($one_worker->workerId === $this->workerId) { + unset(static::$workers[$key]); + } + } // Clear callback. $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; } From dcd849d27a04f25015bea26973dc6cabe396844e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 2 Feb 2023 15:19:26 +0800 Subject: [PATCH 0831/1216] Use PHP_BINARY for windows --- src/Worker.php | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 25042485b..452ddfa3e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1408,11 +1408,42 @@ protected static function forkWorkersForWindows() /** @var Worker $worker */ $worker = current(static::$workers); + Timer::delAll(); + + //Update process state. + static::$status = static::STATUS_RUNNING; + + // Register shutdown function for checking errors. + \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); + + // Create a global event loop. + if (!static::$globalEvent) { + $eventLoopClass = static::getEventLoopName(); + static::$globalEvent = new $eventLoopClass; + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); + } + + // Reinstall signal. + static::reinstallSignal(); + + // Init Timer. + Timer::init(static::$globalEvent); + + \restore_error_handler(); + // Display UI. static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); - exit("@@@child exit@@@\r\n"); + static::$globalEvent->run(); + if (static::$status !== self::STATUS_SHUTDOWN) { + $err = new Exception('event-loop exited'); + static::log($err); + exit(250); + } + exit(0); } else { static::$globalEvent = new Select(); static::$globalEvent->setErrorHandler(function ($exception) { @@ -1455,7 +1486,7 @@ public static function forkOneWorkerForWindows(string $startFile) ); $pipes = array(); - $process = \proc_open("php \"$startFile\" -q", $descriptorspec, $pipes); + $process = \proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptorspec, $pipes, null, null, ['bypass_shell' => true]); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); From e36a75e914918180a3a7ff7873751877c07300ea Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 3 Feb 2023 10:42:07 +0800 Subject: [PATCH 0832/1216] is_scalar --- src/Protocols/Websocket.php | 12 ++++++++++-- src/Protocols/Ws.php | 11 +++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 5fc53fc15..be679b01a 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; +use Exception; use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; @@ -22,6 +23,8 @@ use function base64_encode; use function chr; use function floor; +use function gettype; +use function is_scalar; use function ord; use function pack; use function preg_match; @@ -230,12 +233,17 @@ public static function input(string $buffer, TcpConnection $connection): int /** * Websocket encode. * - * @param string $buffer + * @param mixed $buffer * @param TcpConnection $connection * @return string + * @throws Exception */ - public static function encode(string $buffer, TcpConnection $connection): string + public static function encode(mixed $buffer, TcpConnection $connection): string { + if (!is_scalar($buffer)) { + throw new Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to string. "); + } + $len = strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 783385046..b8c075132 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -14,6 +14,7 @@ namespace Workerman\Protocols; +use Exception; use Throwable; use Workerman\Connection\AsyncTcpConnection; use Workerman\Connection\ConnectionInterface; @@ -22,7 +23,9 @@ use function base64_encode; use function bin2hex; use function floor; +use function gettype; use function is_array; +use function is_scalar; use function ord; use function pack; use function preg_match; @@ -225,13 +228,17 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo /** * Websocket encode. * - * @param string $payload + * @param mixed $payload * @param AsyncTcpConnection $connection * @return string * @throws Throwable */ - public static function encode(string $payload, AsyncTcpConnection $connection): string + public static function encode(mixed $payload, AsyncTcpConnection $connection): string { + if (!is_scalar($payload)) { + throw new Exception("You can't send(" . gettype($payload) . ") to client, you need to convert it to string. "); + } + if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } From 50288fc79bee183abafc84a803cd19c4176d9dde Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 4 Feb 2023 12:04:56 +0800 Subject: [PATCH 0833/1216] Fix sleep --- src/Timer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Timer.php b/src/Timer.php index 1829160b0..da9019c63 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -22,6 +22,7 @@ use Workerman\Events\EventInterface; use Workerman\Events\Revolt; use Workerman\Events\Swoole; +use Workerman\Events\Swow; use function function_exists; use function is_callable; use function pcntl_alarm; From fa3305943274eeef6244a27318ac1258f18eac74 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 6 Feb 2023 19:47:43 +0800 Subject: [PATCH 0834/1216] 5.0.0-beta.2 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 452ddfa3e..03102bc8d 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -39,7 +39,7 @@ class Worker * * @var string */ - const VERSION = '5.0.0'; + const VERSION = '5.0.0-beta.2'; /** * Status starting. From 7ca1782358e40f81a723250ee85ccfd05b78a50e Mon Sep 17 00:00:00 2001 From: royee Date: Mon, 6 Feb 2023 21:01:19 +0800 Subject: [PATCH 0835/1216] enhance some code --- composer.json | 4 +- src/Worker.php | 137 +++++++++++++++++++++++++------------------------ 2 files changed, 72 insertions(+), 69 deletions(-) diff --git a/composer.json b/composer.json index 7637e319d..e4f8ac31b 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,9 @@ }, "require": { "php": ">=8.1", - "ext-json": "*" + "ext-json": "*", + "ext-pcntl": "*", + "ext-posix": "*" }, "suggest": { "ext-event": "For better performance. " diff --git a/src/Worker.php b/src/Worker.php index 03102bc8d..eceb29461 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -39,49 +39,49 @@ class Worker * * @var string */ - const VERSION = '5.0.0-beta.2'; + public const VERSION = '5.0.0-beta.2'; /** * Status starting. * * @var int */ - const STATUS_STARTING = 1; + public const STATUS_STARTING = 1; /** * Status running. * * @var int */ - const STATUS_RUNNING = 2; + public const STATUS_RUNNING = 2; /** * Status shutdown. * * @var int */ - const STATUS_SHUTDOWN = 4; + public const STATUS_SHUTDOWN = 4; /** * Status reloading. * * @var int */ - const STATUS_RELOADING = 8; + public const STATUS_RELOADING = 8; /** * Default backlog. Backlog is the maximum length of the queue of pending connections. * * @var int */ - const DEFAULT_BACKLOG = 102400; + public const DEFAULT_BACKLOG = 102400; /** * The safe distance for columns adjacent * * @var int */ - const UI_SAFE_LENGTH = 4; + public const UI_SAFE_LENGTH = 4; /** * Worker id. @@ -492,7 +492,7 @@ class Worker * * @var array */ - const BUILD_IN_TRANSPORTS = [ + public const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', @@ -504,7 +504,7 @@ class Worker * * @var array */ - const ERROR_TYPE = [ + public const ERROR_TYPE = [ \E_ERROR => 'E_ERROR', // 1 \E_WARNING => 'E_WARNING', // 2 \E_PARSE => 'E_PARSE', // 4 @@ -554,7 +554,7 @@ class Worker * @return void * @throws Exception */ - public static function runAll() + public static function runAll(): void { static::checkSapiEnv(); static::init(); @@ -576,7 +576,7 @@ public static function runAll() * * @return void */ - protected static function checkSapiEnv() + protected static function checkSapiEnv(): void { // Only for cli. if (\PHP_SAPI !== 'cli') { @@ -589,7 +589,7 @@ protected static function checkSapiEnv() * * @return void */ - protected static function init() + protected static function init(): void { \set_error_handler(function ($code, $msg, $file, $line) { static::safeEcho("$msg in file $file on line $line\n"); @@ -639,9 +639,10 @@ protected static function init() /** * Lock. * + * @param int $flag * @return void */ - protected static function lock($flag = \LOCK_EX) + protected static function lock($flag = \LOCK_EX): void { static $fd; if (\DIRECTORY_SEPARATOR !== '/') { @@ -668,7 +669,7 @@ protected static function lock($flag = \LOCK_EX) * @return void * @throws Exception */ - protected static function initWorkers() + protected static function initWorkers(): void { if (\DIRECTORY_SEPARATOR !== '/') { return; @@ -744,7 +745,7 @@ public function getMainSocket() * * @return void */ - protected static function initId() + protected static function initId(): void { foreach (static::$workers as $workerId => $worker) { $newIdMap = []; @@ -772,7 +773,7 @@ protected static function getCurrentUser(): string * * @return void */ - protected static function displayUI() + protected static function displayUI(): void { $tmpArgv = static::getArgv(); if (\in_array('-q', $tmpArgv)) { @@ -876,7 +877,7 @@ public static function getSingleLineTotalLength(): int * * @return void */ - protected static function parseCommand() + protected static function parseCommand(): void { if (\DIRECTORY_SEPARATOR !== '/') { return; @@ -1085,14 +1086,14 @@ protected static function formatStatusData($statisticsFile): string $pid = $pidMath[0]; $dataWaitingSort[$pid] = $value; if (\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $totalMemory += \intval(\str_ireplace('M', '', $match[1])); + $totalMemory += (int)\str_ireplace('M', '', $match[1]); $maxLen1 = \max($maxLen1, \strlen($match[2])); $maxLen2 = \max($maxLen2, \strlen($match[3])); - $totalConnections += \intval($match[4]); - $totalFails += \intval($match[5]); - $totalTimers += \intval($match[6]); + $totalConnections += (int)$match[4]; + $totalFails += (int)$match[5]; + $totalTimers += (int)$match[6]; $currentTotalRequest[$pid] = $match[7]; - $totalRequests += \intval($match[7]); + $totalRequests += (int)$match[7]; } } } @@ -1131,7 +1132,7 @@ protected static function formatStatusData($statisticsFile): string * * @return void */ - protected static function installSignal() + protected static function installSignal(): void { if (\DIRECTORY_SEPARATOR !== '/') { return; @@ -1149,7 +1150,7 @@ protected static function installSignal() * * @return void */ - protected static function reinstallSignal() + protected static function reinstallSignal(): void { if (\DIRECTORY_SEPARATOR !== '/') { return; @@ -1167,7 +1168,7 @@ protected static function reinstallSignal() * @param int $signal * @throws Exception */ - public static function signalHandler(int $signal) + public static function signalHandler(int $signal): void { switch ($signal) { // Stop. @@ -1209,7 +1210,7 @@ public static function signalHandler(int $signal) * * @throws Exception */ - protected static function daemonize() + protected static function daemonize(): void { if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; @@ -1217,17 +1218,17 @@ protected static function daemonize() \umask(0); $pid = \pcntl_fork(); if (-1 === $pid) { - throw new Exception('Fork fail'); + throw new \RuntimeException('Fork fail'); } elseif ($pid > 0) { exit(0); } if (-1 === \posix_setsid()) { - throw new Exception("Setsid fail"); + throw new \RuntimeException("Setsid fail"); } // Fork again avoid SVR4 system regain the control of terminal. $pid = \pcntl_fork(); if (-1 === $pid) { - throw new Exception("Fork fail"); + throw new \RuntimeException("Fork fail"); } elseif (0 !== $pid) { exit(0); } @@ -1240,7 +1241,7 @@ protected static function daemonize() * @return void * @throws Exception */ - public static function resetStd(bool $throwException = true) + public static function resetStd(bool $throwException = true): void { if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { return; @@ -1278,7 +1279,7 @@ public static function resetStd(bool $throwException = true) return; } if ($throwException) { - throw new Exception('Can not open stdoutFile ' . static::$stdoutFile); + throw new \RuntimeException('Can not open stdoutFile ' . static::$stdoutFile); } } @@ -1287,7 +1288,7 @@ public static function resetStd(bool $throwException = true) * * @throws Exception */ - protected static function saveMasterPid() + protected static function saveMasterPid(): void { if (\DIRECTORY_SEPARATOR !== '/') { return; @@ -1295,7 +1296,7 @@ protected static function saveMasterPid() static::$masterPid = \posix_getpid(); if (false === \file_put_contents(static::$pidFile, static::$masterPid)) { - throw new Exception('can not save pid to ' . static::$pidFile); + throw new \RuntimeException('can not save pid to ' . static::$pidFile); } } @@ -1351,8 +1352,9 @@ protected static function getAllWorkerPids(): array * Fork some worker processes. * * @return void + * @throws Exception */ - protected static function forkWorkers() + protected static function forkWorkers(): void { if (\DIRECTORY_SEPARATOR === '/') { static::forkWorkersForLinux(); @@ -1367,7 +1369,7 @@ protected static function forkWorkers() * @return void * @throws Exception */ - protected static function forkWorkersForLinux() + protected static function forkWorkersForLinux(): void { foreach (static::$workers as $worker) { @@ -1393,7 +1395,7 @@ protected static function forkWorkersForLinux() * @return void * @throws Exception */ - protected static function forkWorkersForWindows() + protected static function forkWorkersForWindows(): void { $files = static::getStartFilesForWindows(); if (\in_array('-q', static::getArgv()) || \count($files) === 1) { @@ -1414,7 +1416,7 @@ protected static function forkWorkersForWindows() static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); + \register_shutdown_function([__CLASS__, 'checkErrors']); // Create a global event loop. if (!static::$globalEvent) { @@ -1477,7 +1479,7 @@ public static function getStartFilesForWindows(): array * * @param string $startFile */ - public static function forkOneWorkerForWindows(string $startFile) + public static function forkOneWorkerForWindows(string $startFile): void { $startFile = \realpath($startFile); @@ -1504,7 +1506,7 @@ public static function forkOneWorkerForWindows(string $startFile) * check worker status for windows. * @return void */ - public static function checkWorkerStatusForWindows() + public static function checkWorkerStatusForWindows(): void { foreach (static::$processForWindows as $processData) { $process = $processData[0]; @@ -1526,9 +1528,9 @@ public static function checkWorkerStatusForWindows() * Fork one worker process. * * @param self $worker - * @throws Exception + * @throws Exception|Throwable */ - protected static function forkOneWorkerForLinux(self $worker) + protected static function forkOneWorkerForLinux(self $worker): void { // Get available worker id. $id = static::getId($worker->workerId, 0); @@ -1591,7 +1593,7 @@ protected static function forkOneWorkerForLinux(self $worker) } exit(0); } else { - throw new Exception("forkOneWorker fail"); + throw new \RuntimeException("forkOneWorker fail"); } } @@ -1613,7 +1615,7 @@ protected static function getId(string $workerId, int $pid): bool|int|string * * @return void */ - public function setUserAndGroup() + public function setUserAndGroup(): void { // Get uid. $userInfo = \posix_getpwnam($this->user); @@ -1648,7 +1650,7 @@ public function setUserAndGroup() * @param string $title * @return void */ - protected static function setProcessTitle(string $title) + protected static function setProcessTitle(string $title): void { \set_error_handler(function () { }); @@ -1660,8 +1662,9 @@ protected static function setProcessTitle(string $title) * Monitor all child processes. * * @return void + * @throws Exception */ - protected static function monitorWorkers() + protected static function monitorWorkers(): void { if (\DIRECTORY_SEPARATOR === '/') { static::monitorWorkersForLinux(); @@ -1676,7 +1679,7 @@ protected static function monitorWorkers() * @return void * @throws Exception */ - protected static function monitorWorkersForLinux() + protected static function monitorWorkersForLinux(): void { static::$status = static::STATUS_RUNNING; while (1) { @@ -1750,7 +1753,7 @@ protected static function monitorWorkersForLinux() * * @return void */ - protected static function monitorWorkersForWindows() + protected static function monitorWorkersForWindows(): void { Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows"); @@ -1784,7 +1787,7 @@ protected static function exitAndClearAll() * @return void * @throws Exception */ - protected static function reload() + protected static function reload(): void { // For master process. if (static::$masterPid === \posix_getpid()) { @@ -1866,7 +1869,7 @@ protected static function reload() * @param int $code * @param mixed $log */ - public static function stopAll(int $code = 0, mixed $log = '') + public static function stopAll(int $code = 0, mixed $log = ''): void { if ($log) { static::log($log); @@ -1923,7 +1926,7 @@ public static function stopAll(int $code = 0, mixed $log = '') /** * check if child processes is really running */ - public static function checkIfChildRunning() + public static function checkIfChildRunning(): void { foreach (static::$pidMap as $workerId => $workerPidArray) { foreach ($workerPidArray as $pid => $workerPid) { @@ -1959,7 +1962,7 @@ public static function getGracefulStop(): bool * * @return void */ - protected static function writeStatisticsToStatusFile() + protected static function writeStatisticsToStatusFile(): void { // For master process. if (static::$masterPid === \posix_getpid()) { @@ -2043,7 +2046,7 @@ protected static function writeStatisticsToStatusFile() * * @return void */ - protected static function writeConnectionsStatisticsToStatusFile() + protected static function writeConnectionsStatisticsToStatusFile(): void { // For master process. if (static::$masterPid === \posix_getpid()) { @@ -2120,7 +2123,7 @@ protected static function writeConnectionsStatisticsToStatusFile() * * @return void */ - public static function checkErrors() + public static function checkErrors(): void { if (static::STATUS_SHUTDOWN !== static::$status) { $errorMsg = \DIRECTORY_SEPARATOR === '/' ? 'Worker[' . \posix_getpid() . '] process terminated' : 'Worker process terminated'; @@ -2154,7 +2157,7 @@ protected static function getErrorType(int $type): string * @param mixed $msg * @return void */ - public static function log(mixed $msg) + public static function log(mixed $msg): void { $msg = $msg . "\n"; if (!static::$daemonize) { @@ -2277,7 +2280,7 @@ public function __construct(string $socketName = null, array $socketContext = [] * * @throws Exception */ - public function listen() + public function listen(): void { if (!$this->socketName) { return; @@ -2336,7 +2339,7 @@ public function listen() * * @return void */ - public function unlisten() + public function unlisten(): void { $this->pauseAccept(); if ($this->mainSocket) { @@ -2363,21 +2366,19 @@ protected function parseSocketAddress(): ?string // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { $scheme = \ucfirst($scheme); - $this->protocol = \substr($scheme, 0, 1) === '\\' ? $scheme : 'Protocols\\' . $scheme; + $this->protocol = $scheme[0] === '\\' ? $scheme : 'Protocols\\' . $scheme; if (!\class_exists($this->protocol)) { $this->protocol = "Workerman\\Protocols\\$scheme"; if (!\class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); + throw new \RuntimeException("class \\Protocols\\$scheme not exist"); } } if (!isset(self::BUILD_IN_TRANSPORTS[$this->transport])) { - throw new Exception('Bad worker->transport ' . \var_export($this->transport, true)); - } - } else { - if ($this->transport === 'tcp') { - $this->transport = $scheme; + throw new \RuntimeException('Bad worker->transport ' . \var_export($this->transport, true)); } + } else if ($this->transport === 'tcp') { + $this->transport = $scheme; } //local socket return self::BUILD_IN_TRANSPORTS[$this->transport] . ":" . $address; @@ -2388,7 +2389,7 @@ protected function parseSocketAddress(): ?string * * @return void */ - public function pauseAccept() + public function pauseAccept(): void { if (static::$globalEvent && false === $this->pauseAccept && $this->mainSocket) { static::$globalEvent->offReadable($this->mainSocket); @@ -2401,7 +2402,7 @@ public function pauseAccept() * * @return void */ - public function resumeAccept() + public function resumeAccept(): void { // Register a listener to be notified when server socket is ready to read. if (static::$globalEvent && true === $this->pauseAccept && $this->mainSocket) { @@ -2430,7 +2431,7 @@ public function getSocketName(): string * @return void * @throws Throwable */ - public function run() + public function run(): void { $this->listen(); @@ -2451,7 +2452,7 @@ public function run() * * @return void */ - public function stop() + public function stop(): void { // Try to emit onWorkerStop callback. if ($this->onWorkerStop) { @@ -2485,7 +2486,7 @@ public function stop() * @param resource $socket * @return void */ - public function acceptTcpConnection($socket) + public function acceptTcpConnection($socket): void { // Accept a connection on server socket. \set_error_handler(function () { From 46ce7bfb3631833315121b6bbdd0dcf368c12842 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 6 Feb 2023 21:30:51 +0800 Subject: [PATCH 0836/1216] Windows not support posix and pcntl --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index e4f8ac31b..7637e319d 100644 --- a/composer.json +++ b/composer.json @@ -25,9 +25,7 @@ }, "require": { "php": ">=8.1", - "ext-json": "*", - "ext-pcntl": "*", - "ext-posix": "*" + "ext-json": "*" }, "suggest": { "ext-event": "For better performance. " From 3dd89b35e74fe3dcd3a37435c651191caf224035 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 21:47:29 +0800 Subject: [PATCH 0837/1216] Fix #879 --- src/Connection/TcpConnection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 818b1541d..6f1028dba 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -11,6 +11,7 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); namespace Workerman\Connection; @@ -304,7 +305,7 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable * * @var bool */ - protected bool $sslHandshakeCompleted = false; + protected bool|int $sslHandshakeCompleted = false; /** * All connection instances. @@ -341,7 +342,7 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd self::$idRecorder = 0; } $this->socket = $socket; - stream_set_blocking($this->socket, 0); + stream_set_blocking($this->socket, false); // Compatible with hhvm if (function_exists('stream_set_read_buffer')) { stream_set_read_buffer($this->socket, 0); From 9d7c4ed30874b44fe5089c6f64dfe7e68f032bf3 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 21:49:18 +0800 Subject: [PATCH 0838/1216] declare(strict_types=1) --- src/Connection/AsyncTcpConnection.php | 2 ++ src/Connection/AsyncUdpConnection.php | 4 +++- src/Connection/ConnectionInterface.php | 2 ++ src/Connection/UdpConnection.php | 2 ++ src/Events/Ev.php | 2 ++ src/Events/Event.php | 10 ++++++---- src/Events/Revolt.php | 2 ++ src/Events/Select.php | 2 ++ src/Events/Swoole.php | 2 ++ src/Events/Swow.php | 2 ++ src/Protocols/Frame.php | 2 ++ src/Protocols/Http.php | 2 ++ src/Protocols/Http/Chunk.php | 3 ++- src/Protocols/Http/Request.php | 2 ++ src/Protocols/Http/Response.php | 2 ++ src/Protocols/Http/ServerSentEvents.php | 2 ++ src/Protocols/Http/Session.php | 2 ++ .../Http/Session/FileSessionHandler.php | 2 ++ .../Session/RedisClusterSessionHandler.php | 2 ++ .../Http/Session/RedisSessionHandler.php | 2 ++ .../Http/Session/SessionHandlerInterface.php | 2 ++ src/Protocols/ProtocolInterface.php | 2 ++ src/Protocols/Text.php | 2 ++ src/Protocols/Websocket.php | 2 ++ src/Protocols/Ws.php | 2 ++ src/Timer.php | 11 ++++------- src/Worker.php | 18 ++++++++++-------- 27 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 02f8f54fa..131f882f5 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Connection; use Exception; diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index fa3aff5e2..aa66c35ed 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Connection; use Exception; @@ -193,7 +195,7 @@ public function connect() } if (!$this->socket) { - Worker::safeEcho(new Exception($errmsg)); + Worker::safeEcho((string)(new Exception($errmsg))); $this->eventLoop = null; return; } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 43b96406b..5f9ebee79 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Connection; use Throwable; diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 07937e7ce..a7ec6a0e0 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Connection; use JetBrains\PhpStorm\ArrayShape; diff --git a/src/Events/Ev.php b/src/Events/Ev.php index d7f9e33eb..6909515c0 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -11,6 +11,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Events; use EvIo; diff --git a/src/Events/Event.php b/src/Events/Event.php index 8ec4217d1..f498ad40d 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Events; use EventBase; @@ -106,8 +108,8 @@ public function delay(float $delay, callable $func, array $args = []): int $this->error($e); } }); - if (!$event || !$event->addTimer($delay)) { - return false; + if (!$event->addTimer($delay)) { + throw new \RuntimeException("Event::addTimer($delay) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; @@ -148,8 +150,8 @@ public function repeat(float $interval, callable $func, array $args = []): int $this->error($e); } }); - if (!$event || !$event->addTimer($interval)) { - return false; + if (!$event->addTimer($interval)) { + throw new \RuntimeException("Event::addTimer($interval) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 634a6a99c..0e3eb03b0 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Events; use Revolt\EventLoop; diff --git a/src/Events/Select.php b/src/Events/Select.php index 3636e1bef..d4e15b567 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -12,6 +12,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Events; use SplPriorityQueue; diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 5782567be..3ed840c6f 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -11,6 +11,8 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ +declare(strict_types=1); + namespace Workerman\Events; use Swoole\Event; diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 1964d60ff..2bc85e6eb 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -1,5 +1,7 @@ $prop) { !isset($worker->$prop) && !isset($worker->context->$prop) && $worker->context->$prop = 'NNNN'; - $propLength = \strlen($worker->$prop ?? $worker->context->$prop); + $propLength = \strlen((string)($worker->$prop ?? $worker->context->$prop)); $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; static::$$key = \max(static::$$key, $propLength); } @@ -809,7 +811,7 @@ protected static function displayUI(): void foreach (static::$workers as $worker) { $content = ''; foreach (static::getUiColumns() as $columnName => $prop) { - $propValue = $worker->$prop ?? $worker->context->$prop; + $propValue = (string)($worker->$prop ?? $worker->context->$prop); $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $propValue, $matches); $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; @@ -1120,8 +1122,8 @@ protected static function formatStatusData($statisticsFile): string $statusStr .= "Summary\t" . \str_pad($totalMemory . 'M', 7) . " " . \str_pad('-', $maxLen1) . " " . \str_pad('-', $maxLen2) . " " - . \str_pad($totalConnections, 11) . " " . \str_pad($totalFails, 9) . " " - . \str_pad($totalTimers, 7) . " " . \str_pad($totalRequests, 13) . " " + . \str_pad((string)$totalConnections, 11) . " " . \str_pad((string)$totalFails, 9) . " " + . \str_pad((string)$totalTimers, 7) . " " . \str_pad((string)$totalRequests, 13) . " " . \str_pad($totalQps, 6) . " [Summary] \n"; return $statusStr; } @@ -1436,7 +1438,7 @@ protected static function forkWorkersForWindows(): void \restore_error_handler(); // Display UI. - static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad($worker->count, 10) . "[ok]\n"); + static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad((string)$worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); static::$globalEvent->run(); @@ -2002,7 +2004,7 @@ protected static function writeStatisticsToStatusFile(): void } } else { \file_put_contents(static::$statisticsFile, - \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad(0, 16) . " 0\n", + \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad('0', 16) . " 0\n", \FILE_APPEND); } } @@ -2036,7 +2038,7 @@ protected static function writeStatisticsToStatusFile(): void . " "; $workerStatusStr .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) - . " " . \str_pad(static::$globalEvent->getTimerCount(), 7) + . " " . \str_pad((string)static::$globalEvent->getTimerCount(), 7) . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; \file_put_contents(static::$statisticsFile, $workerStatusStr, \FILE_APPEND); } @@ -2108,7 +2110,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void if (\strlen($workerName) > 14) { $workerName = \substr($workerName, 0, 12) . '..'; } - $str .= \str_pad($pid, 9) . \str_pad($workerName, 16) . \str_pad($id, 10) . \str_pad($transport, 8) + $str .= \str_pad((string)$pid, 9) . \str_pad($workerName, 16) . \str_pad((string)$id, 10) . \str_pad($transport, 8) . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recvQ, 13) . \str_pad($sendQ, 13) . \str_pad($bytesRead, 13) . \str_pad($bytesWritten, 13) . ' ' . \str_pad($state, 14) . ' ' . \str_pad($localAddress, 22) . ' ' . \str_pad($remoteAddress, 22) . "\n"; From 8ce5bef2663954b1912537b86ef89d9448c08853 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 22:08:54 +0800 Subject: [PATCH 0839/1216] Update --- src/Connection/AsyncTcpConnection.php | 3 ++- src/Protocols/Websocket.php | 2 +- src/Protocols/Ws.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 131f882f5..351269bb2 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -17,6 +17,7 @@ namespace Workerman\Connection; use Exception; +use RuntimeException; use stdClass; use Throwable; use Workerman\Timer; @@ -152,7 +153,7 @@ public function __construct(string $remoteAddress, array $socketContext = []) $this->remoteAddress = substr($remoteAddress, strpos($remoteAddress, '/') + 2); } if (!$this->remoteAddress) { - Worker::safeEcho(new Exception('bad remote_address')); + throw new RuntimeException('Bad remoteAddress'); } } else { if (!isset($addressInfo['port'])) { diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 72d0b4a04..d914407de 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -322,7 +322,7 @@ public static function decode(string $buffer, TcpConnection $connection): string } } $dataLength = strlen($data); - $masks = str_repeat($masks, floor($dataLength / 4)) . substr($masks, 0, $dataLength % 4); + $masks = str_repeat($masks, (int)floor($dataLength / 4)) . substr($masks, 0, $dataLength % 4); $decoded = $data ^ $masks; if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decoded; diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 41771bd8f..8daa08e36 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -261,7 +261,7 @@ public static function encode(mixed $payload, AsyncTcpConnection $connection): s $frame = $connection->websocketType . $head . $maskKey; // append payload to frame: - $maskKey = str_repeat($maskKey, floor($length / 4)) . substr($maskKey, 0, $length % 4); + $maskKey = str_repeat($maskKey, (int)floor($length / 4)) . substr($maskKey, 0, $length % 4); $frame .= $payload ^ $maskKey; if ($connection->context->handshakeStep === 1) { // If buffer has already full then discard the current package. From 4905549b910af6a09ef22e4e0d90c72399e8e672 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 22:21:03 +0800 Subject: [PATCH 0840/1216] Fix str_pad --- src/Worker.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 4e10b451d..98dbae426 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1103,7 +1103,7 @@ protected static function formatStatusData($statisticsFile): string if (!isset($dataWaitingSort[$pid])) { $statusStr .= "$pid\t" . \str_pad('N/A', 7) . " " . \str_pad($info['listen'], static::$maxSocketNameLength) . " " - . \str_pad($info['name'], static::$maxWorkerNameLength) . " " + . \str_pad((string)$info['name'], static::$maxWorkerNameLength) . " " . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; continue; @@ -1115,7 +1115,7 @@ protected static function formatStatusData($statisticsFile): string $qps = $currentTotalRequest[$pid] - $totalRequestCache[$pid]; $totalQps += $qps; } - $statusStr .= $dataWaitingSort[$pid] . " " . \str_pad($qps, 6) . " [idle]\n"; + $statusStr .= $dataWaitingSort[$pid] . " " . \str_pad((string)$qps, 6) . " [idle]\n"; } $totalRequestCache = $currentTotalRequest; $statusStr .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; @@ -1124,7 +1124,7 @@ protected static function formatStatusData($statisticsFile): string . \str_pad('-', $maxLen2) . " " . \str_pad((string)$totalConnections, 11) . " " . \str_pad((string)$totalFails, 9) . " " . \str_pad((string)$totalTimers, 7) . " " . \str_pad((string)$totalRequests, 13) . " " - . \str_pad($totalQps, 6) . " [Summary] \n"; + . \str_pad((string)$totalQps, 6) . " [Summary] \n"; return $statusStr; } @@ -1999,7 +1999,7 @@ protected static function writeStatisticsToStatusFile(): void if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { \file_put_contents(static::$statisticsFile, - \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad($workerExitStatus, + \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad((string)$workerExitStatus, 16) . " $workerExitCount\n", \FILE_APPEND); } } else { @@ -2032,14 +2032,14 @@ protected static function writeStatisticsToStatusFile(): void \reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); - $workerStatusStr = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) + $workerStatusStr = \posix_getpid() . "\t" . \str_pad((string)round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; - $workerStatusStr .= \str_pad(ConnectionInterface::$statistics['connection_count'], 11) - . " " . \str_pad(ConnectionInterface::$statistics['send_fail'], 9) + $workerStatusStr .= \str_pad((string)ConnectionInterface::$statistics['connection_count'], 11) + . " " . \str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) . " " . \str_pad((string)static::$globalEvent->getTimerCount(), 7) - . " " . \str_pad(ConnectionInterface::$statistics['total_request'], 13) . "\n"; + . " " . \str_pad((string)ConnectionInterface::$statistics['total_request'], 13) . "\n"; \file_put_contents(static::$statisticsFile, $workerStatusStr, \FILE_APPEND); } From 2a2c85ab8a281cbd552bcc3eca08b4ee0398c25f Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 22:23:58 +0800 Subject: [PATCH 0841/1216] Update --- src/Protocols/Http.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 7595109bc..b690fe918 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -220,7 +220,8 @@ public static function encode(mixed $response, TcpConnection $connection): strin } $connection->headers = []; } - $bodyLen = strlen((string)$response); + $response = (string)$response; + $bodyLen = strlen($response); return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; } From 36f409ad7d8d68521af1c299e4b1c86156177bed Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 22:37:04 +0800 Subject: [PATCH 0842/1216] Fix Timer::sleep --- src/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index 87b67ce5f..32b21d494 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -173,7 +173,7 @@ public static function sleep(float $delay) return; // Swow case Swow::class: - usleep($delay * 1000 * 1000); + usleep((int)$delay * 1000 * 1000); return; } throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer require revolt/event-loop" and restart workerman'); From d1beba09281f7fcaeedd00c6699a17c71024c87c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 15 Feb 2023 22:53:16 +0800 Subject: [PATCH 0843/1216] Fix Timer::sleep --- src/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index 32b21d494..efb3fcd44 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -173,7 +173,7 @@ public static function sleep(float $delay) return; // Swow case Swow::class: - usleep((int)$delay * 1000 * 1000); + usleep((int)($delay * 1000 * 1000)); return; } throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer require revolt/event-loop" and restart workerman'); From b4c30bb41b3b2786914722c4d4477e9b123acae5 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Feb 2023 19:41:33 +0800 Subject: [PATCH 0844/1216] Return type mixed --- src/Protocols/Http/Request.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ca69e8ac1..7a5a29153 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -113,9 +113,9 @@ public function __construct(string $buffer) * * @param string|null $name * @param mixed|null $default - * @return string|null|array + * @return mixed */ - public function get(string $name = null, mixed $default = null): array|string|null + public function get(string $name = null, mixed $default = null): mixed { if (!isset($this->data['get'])) { $this->parseGet(); @@ -131,9 +131,9 @@ public function get(string $name = null, mixed $default = null): array|string|nu * * @param string|null $name * @param mixed|null $default - * @return array|string|null + * @return mixed */ - public function post(string $name = null, mixed $default = null): array|string|null + public function post(string $name = null, mixed $default = null): mixed { if (!isset($this->data['post'])) { $this->parsePost(); @@ -149,9 +149,9 @@ public function post(string $name = null, mixed $default = null): array|string|n * * @param string|null $name * @param mixed|null $default - * @return array|string|null + * @return mixed */ - public function header(string $name = null, mixed $default = null): array|string|null + public function header(string $name = null, mixed $default = null): mixed { if (!isset($this->data['headers'])) { $this->parseHeaders(); @@ -168,9 +168,9 @@ public function header(string $name = null, mixed $default = null): array|string * * @param string|null $name * @param mixed|null $default - * @return string|null|array + * @return mixed */ - public function cookie(string $name = null, mixed $default = null): array|string|null + public function cookie(string $name = null, mixed $default = null): mixed { if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; From d681e9c2cb2dc858ac6a88c523115ca67f0408cb Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 23 Feb 2023 20:57:30 +0800 Subject: [PATCH 0845/1216] optimizations --- src/Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index b690fe918..1acfe7a94 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -208,7 +208,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin } if (!is_object($response)) { $extHeader = ''; - if (isset($connection->headers)) { + if ($connection->headers) { foreach ($connection->headers as $name => $value) { if (is_array($value)) { foreach ($value as $item) { @@ -225,7 +225,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; } - if (isset($connection->headers)) { + if ($connection->headers) { $response->withHeaders($connection->headers); $connection->headers = []; } From 69c28b0da8e519ddf2dbc972a22385275540c661 Mon Sep 17 00:00:00 2001 From: liutao Date: Fri, 24 Feb 2023 21:09:50 +0800 Subject: [PATCH 0846/1216] ignore vendor and lock file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f3f9e18c5..fbc9bcb68 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ logs .settings .idea .DS_Store +vendor/ +composer.lock From 1def60dfc178486fa15d5fcd0fc4b00e48034b27 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Mar 2023 21:23:58 +0800 Subject: [PATCH 0847/1216] Support upload empty file --- src/Protocols/Http/Request.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 7a5a29153..ffa8e0c43 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -591,19 +591,20 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS if (preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { $error = 0; $tmpFile = ''; + $fileName = $match[1]; $size = strlen($boundaryValue); $tmpUploadDir = HTTP::uploadTmpDir(); if (!$tmpUploadDir) { $error = UPLOAD_ERR_NO_TMP_DIR; - } else if ($boundaryValue === '') { + } else if ($boundaryValue === '' && $fileName === '') { $error = UPLOAD_ERR_NO_FILE; } else { $tmpFile = tempnam($tmpUploadDir, 'workerman.upload.'); - if ($tmpFile === false || false == file_put_contents($tmpFile, $boundaryValue)) { + if ($tmpFile === false || false === file_put_contents($tmpFile, $boundaryValue)) { $error = UPLOAD_ERR_CANT_WRITE; } } - $uploadKey = $match[1]; + $uploadKey = $fileName; // Parse upload files. $file = [ 'name' => $match[2], From 41f9548bdb85456649dc89412b93cecd08285bc0 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Mar 2023 21:48:20 +0800 Subject: [PATCH 0848/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 98dbae426..e005fb094 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -767,7 +767,7 @@ protected static function initId(): void protected static function getCurrentUser(): string { $userInfo = \posix_getpwuid(\posix_getuid()); - return $userInfo['name']; + return $userInfo['name'] ?? 'unknown'; } /** From 8dfe72bb2655ae2be4a5a6784c471973f2939bac Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 10 Mar 2023 21:51:36 +0800 Subject: [PATCH 0849/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index e005fb094..c279c1486 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -937,7 +937,7 @@ protected static function parseCommand(): void exit; } - $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.status"; + $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.$command"; // execute command. switch ($command) { From c783e1e98cdda031c4c946774f4b7c45efb0d051 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 10 Mar 2023 22:05:00 +0800 Subject: [PATCH 0850/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index c279c1486..4d64dd3fc 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -41,7 +41,7 @@ class Worker * * @var string */ - public const VERSION = '5.0.0-beta.2'; + public const VERSION = '5.0.0-beta.3'; /** * Status starting. From 0ebb7496604aab8731da9f57c8861594ac6687c2 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Sat, 11 Mar 2023 02:25:13 +0200 Subject: [PATCH 0851/1216] Added missing types and corrected grammar errors. --- src/Protocols/Http.php | 2 +- src/Protocols/Http/Request.php | 18 +++--- src/Protocols/Http/Response.php | 14 ++--- .../Http/Session/FileSessionHandler.php | 4 +- .../Session/RedisClusterSessionHandler.php | 2 + .../Http/Session/RedisSessionHandler.php | 16 +++++- .../Http/Session/SessionHandlerInterface.php | 2 +- src/Protocols/Ws.php | 8 +-- src/Timer.php | 14 ++--- src/Worker.php | 56 +++++++++---------- 10 files changed, 74 insertions(+), 62 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 1acfe7a94..a96f59a05 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -135,7 +135,7 @@ public static function input(string $buffer, TcpConnection $connection): int $length = $length + (int)substr($header, $pos + 18, 10); $hasContentLength = true; } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { - $length = $length + $match[1]; + $length = $length + (int)$match[1]; $hasContentLength = true; } else { $hasContentLength = false; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ffa8e0c43..8d04a386e 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -188,7 +188,7 @@ public function cookie(string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(string $name = null) + public function file(string $name = null): ?array { if (!isset($this->data['files'])) { $this->parsePost(); @@ -382,7 +382,7 @@ public function rawBuffer(): string * * @param bool $value */ - public static function enableCache(bool $value) + public static function enableCache(bool $value): void { static::$enableCache = $value; } @@ -392,7 +392,7 @@ public static function enableCache(bool $value) * * @return void */ - protected function parseHeadFirstLine() + protected function parseHeadFirstLine(): void { $firstLine = strstr($this->buffer, "\r\n", true); $tmp = explode(' ', $firstLine, 3); @@ -405,7 +405,7 @@ protected function parseHeadFirstLine() * * @return void */ - protected function parseProtocolVersion() + protected function parseProtocolVersion(): void { $firstLine = strstr($this->buffer, "\r\n", true); $protocolVersion = substr(strstr($firstLine, 'HTTP/'), 5); @@ -417,7 +417,7 @@ protected function parseProtocolVersion() * * @return void */ - protected function parseHeaders() + protected function parseHeaders(): void { static $cache = []; $this->data['headers'] = []; @@ -461,7 +461,7 @@ protected function parseHeaders() * * @return void */ - protected function parseGet() + protected function parseGet(): void { static $cache = []; $queryString = $this->queryString(); @@ -488,7 +488,7 @@ protected function parseGet() * * @return void */ - protected function parsePost() + protected function parsePost(): void { static $cache = []; $this->data['post'] = $this->data['files'] = []; @@ -526,7 +526,7 @@ protected function parsePost() * @param string $httpPostBoundary * @return void */ - protected function parseUploadFiles(string $httpPostBoundary) + protected function parseUploadFiles(string $httpPostBoundary): void { $httpPostBoundary = trim($httpPostBoundary, '"'); $buffer = $this->buffer; @@ -654,7 +654,7 @@ public static function createSessionId(): string * @param array $cookieParams * @return void */ - protected function setSidCookie(string $sessionName, string $sid, array $cookieParams) + protected function setSidCookie(string $sessionName, string $sid, array $cookieParams): void { if (!$this->connection) { throw new RuntimeException('Request->setSidCookie() fail, header already send'); diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 2c15b6138..907c5e914 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -167,7 +167,7 @@ class Response * * @return void */ - public static function init() + public static function init(): void { static::initMimeTypeMap(); } @@ -176,13 +176,13 @@ public static function init() * Response constructor. * * @param int $status - * @param array $headers + * @param array|null $headers * @param string $body */ public function __construct( - int $status = 200, - array $headers = [], - string $body = '' + int $status = 200, + ?array $headers = [], + string $body = '' ) { $this->status = $status; @@ -208,7 +208,7 @@ public function header(string $name, string $value): static * * @param string $name * @param string $value - * @return Response + * @return $this */ public function withHeader(string $name, string $value): static { @@ -480,7 +480,7 @@ public function __toString() * * @return void */ - public static function initMimeTypeMap() + public static function initMimeTypeMap(): void { $mimeFile = __DIR__ . '/mime.types'; $items = file($mimeFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index c4a1581e9..aea6d06e7 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -16,6 +16,7 @@ namespace Workerman\Protocols\Http\Session; +use Exception; use Workerman\Protocols\Http\Session; use function clearstatcache; use function file_get_contents; @@ -104,6 +105,7 @@ public function read(string $sessionId): string /** * {@inheritdoc} + * @throws Exception */ public function write(string $sessionId, string $sessionData): bool { @@ -115,7 +117,7 @@ public function write(string $sessionId, string $sessionData): bool } /** - * Update sesstion modify time. + * Update session modify time. * * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php * @see https://www.php.net/manual/zh/function.touch.php diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 68150b6fe..68d371638 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -19,12 +19,14 @@ use Redis; use RedisCluster; use RedisClusterException; +use RedisException; class RedisClusterSessionHandler extends RedisSessionHandler { /** * @param $config * @throws RedisClusterException + * @throws RedisException */ public function __construct($config) { diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index ca738b72e..e1999ea55 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -17,6 +17,7 @@ namespace Workerman\Protocols\Http\Session; use Redis; +use RedisCluster; use RedisException; use RuntimeException; use Throwable; @@ -29,11 +30,10 @@ */ class RedisSessionHandler implements SessionHandlerInterface { - /** - * @var Redis + * @var Redis|RedisCluster */ - protected Redis $redis; + protected Redis|RedisCluster $redis; /** * @var array @@ -51,6 +51,7 @@ class RedisSessionHandler implements SessionHandlerInterface * 'prefix' => 'redis_session_', * 'ping' => 55, * ] + * @throws RedisException */ public function __construct(array $config) { @@ -71,6 +72,9 @@ public function __construct(array $config) }); } + /** + * @throws RedisException + */ public function connect() { $config = $this->config; @@ -101,7 +105,10 @@ public function open(string $savePath, string $name): bool /** * {@inheritdoc} + * @param string $sessionId + * @return string * @throws RedisException + * @throws Throwable */ public function read(string $sessionId): string { @@ -119,6 +126,7 @@ public function read(string $sessionId): string /** * {@inheritdoc} + * @throws RedisException */ public function write(string $sessionId, string $sessionData): bool { @@ -127,6 +135,7 @@ public function write(string $sessionId, string $sessionData): bool /** * {@inheritdoc} + * @throws RedisException */ public function updateTimestamp(string $sessionId, string $data = ""): bool { @@ -135,6 +144,7 @@ public function updateTimestamp(string $sessionId, string $data = ""): bool /** * {@inheritdoc} + * @throws RedisException */ public function destroy(string $sessionId): bool { diff --git a/src/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php index 485981fba..5e4a56eb5 100644 --- a/src/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -103,7 +103,7 @@ public function read(string $sessionId): string; public function write(string $sessionId, string $sessionData): bool; /** - * Update sesstion modify time. + * Update session modify time. * * @see https://www.php.net/manual/en/class.sessionupdatetimestamphandlerinterface.php * diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 8daa08e36..38c2b250d 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -324,11 +324,11 @@ public static function decode(string $bytes, AsyncTcpConnection $connection): st /** * Send websocket handshake data. * - * @param $connection + * @param AsyncTcpConnection $connection * @return void * @throws Throwable */ - public static function onConnect($connection) + public static function onConnect(AsyncTcpConnection $connection): void { static::sendHandshake($connection); } @@ -338,7 +338,7 @@ public static function onConnect($connection) * * @param AsyncTcpConnection $connection */ - public static function onClose(AsyncTcpConnection $connection) + public static function onClose(AsyncTcpConnection $connection): void { $connection->context->handshakeStep = null; $connection->context->websocketCurrentFrameLength = 0; @@ -357,7 +357,7 @@ public static function onClose(AsyncTcpConnection $connection) * @return void * @throws Throwable */ - public static function sendHandshake(AsyncTcpConnection $connection) + public static function sendHandshake(AsyncTcpConnection $connection): void { if (!empty($connection->context->handshakeStep)) { return; diff --git a/src/Timer.php b/src/Timer.php index efb3fcd44..973ae5ddf 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -82,7 +82,7 @@ class Timer * @param EventInterface|null $event * @return void */ - public static function init(EventInterface $event = null) + public static function init(EventInterface $event = null): void { if ($event) { self::$event = $event; @@ -98,7 +98,7 @@ public static function init(EventInterface $event = null) * * @return void */ - public static function signalHandle() + public static function signalHandle(): void { if (!self::$event) { pcntl_alarm(1); @@ -156,7 +156,7 @@ public static function add(float $timeInterval, callable $func, null|array $args * @param float $delay * @return void */ - public static function sleep(float $delay) + public static function sleep(float $delay): void { switch (Worker::$eventLoopClass) { // Fiber @@ -184,7 +184,7 @@ public static function sleep(float $delay) * * @return void */ - public static function tick() + public static function tick(): void { if (empty(self::$tasks)) { pcntl_alarm(0); @@ -241,14 +241,12 @@ public static function del(int $timerId): bool * * @return void */ - public static function delAll() + public static function delAll(): void { self::$tasks = self::$status = []; if (function_exists('pcntl_alarm')) { pcntl_alarm(0); } - if (self::$event) { - self::$event->deleteAllTimer(); - } + self::$event?->deleteAllTimer(); } } diff --git a/src/Worker.php b/src/Worker.php index 4d64dd3fc..40df08083 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -422,7 +422,7 @@ class Worker protected static int $maxSocketNameLength = 12; /** - * Maximum length of the process user names. + * Maximum length of the process usernames. * * @var int */ @@ -554,7 +554,7 @@ class Worker * Run all worker instances. * * @return void - * @throws Exception + * @throws Throwable */ public static function runAll(): void { @@ -644,7 +644,7 @@ protected static function init(): void * @param int $flag * @return void */ - protected static function lock($flag = \LOCK_EX): void + protected static function lock(int $flag = \LOCK_EX): void { static $fd; if (\DIRECTORY_SEPARATOR !== '/') { @@ -803,7 +803,7 @@ protected static function displayUI(): void $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; //just keep compatible with listen name $columnName === 'socket' && $columnName = 'listen'; - $title .= "{$columnName}" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); + $title .= "$columnName" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); } $title && static::safeEcho($title . \PHP_EOL); @@ -813,7 +813,7 @@ protected static function displayUI(): void foreach (static::getUiColumns() as $columnName => $prop) { $propValue = (string)($worker->$prop ?? $worker->context->$prop); $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; - \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/is", $propValue, $matches); + \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/i", $propValue, $matches); $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; $content .= \str_pad($propValue, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); } @@ -1037,9 +1037,9 @@ protected static function parseCommand(): void /** * Get argv. * - * @return mixed + * @return array */ - public static function getArgv(): mixed + public static function getArgv(): array { global $argv; return isset($argv[1]) ? $argv : (static::$command ? \explode(' ', static::$command) : $argv); @@ -1151,6 +1151,7 @@ protected static function installSignal(): void * Reinstall signal handler. * * @return void + * @throws Throwable */ protected static function reinstallSignal(): void { @@ -1161,7 +1162,7 @@ protected static function reinstallSignal(): void foreach ($signals as $signal) { \pcntl_signal($signal, \SIG_IGN, false); static::$globalEvent->onSignal($signal, [static::class, 'signalHandler']); - }; + } } /** @@ -1354,7 +1355,7 @@ protected static function getAllWorkerPids(): array * Fork some worker processes. * * @return void - * @throws Exception + * @throws Throwable */ protected static function forkWorkers(): void { @@ -1369,7 +1370,7 @@ protected static function forkWorkers(): void * Fork some worker processes. * * @return void - * @throws Exception + * @throws Throwable */ protected static function forkWorkersForLinux(): void { @@ -1395,7 +1396,7 @@ protected static function forkWorkersForLinux(): void * Fork some worker processes. * * @return void - * @throws Exception + * @throws Throwable */ protected static function forkWorkersForWindows(): void { @@ -1485,12 +1486,12 @@ public static function forkOneWorkerForWindows(string $startFile): void { $startFile = \realpath($startFile); - $descriptorspec = array( + $descriptor_spec = array( STDIN, STDOUT, STDOUT ); $pipes = array(); - $process = \proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptorspec, $pipes, null, null, ['bypass_shell' => true]); + $process = \proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1622,7 +1623,7 @@ public function setUserAndGroup(): void // Get uid. $userInfo = \posix_getpwnam($this->user); if (!$userInfo) { - static::log("Warning: User {$this->user} not exists"); + static::log("Warning: User $this->user not exists"); return; } $uid = $userInfo['uid']; @@ -1630,7 +1631,7 @@ public function setUserAndGroup(): void if ($this->group) { $groupInfo = \posix_getgrnam($this->group); if (!$groupInfo) { - static::log("Warning: Group {$this->group} not exists"); + static::log("Warning: Group $this->group not exists"); return; } $gid = $groupInfo['gid']; @@ -1664,7 +1665,7 @@ protected static function setProcessTitle(string $title): void * Monitor all child processes. * * @return void - * @throws Exception + * @throws Throwable */ protected static function monitorWorkers(): void { @@ -1679,7 +1680,7 @@ protected static function monitorWorkers(): void * Monitor all child processes. * * @return void - * @throws Exception + * @throws Throwable */ protected static function monitorWorkersForLinux(): void { @@ -1704,7 +1705,7 @@ protected static function monitorWorkersForLinux(): void } // Exit status. if ($status !== 0) { - static::log("worker[{$worker->name}:$pid] exit with status $status"); + static::log("worker[$worker->name:$pid] exit with status $status"); } // onWorkerExit @@ -1712,7 +1713,7 @@ protected static function monitorWorkersForLinux(): void try { (static::$onWorkerExit)($worker, $status, $pid); } catch (Throwable $exception) { - static::log("worker[{$worker->name}] onWorkerExit $exception"); + static::log("worker[$worker->name] onWorkerExit $exception"); } } @@ -1754,6 +1755,7 @@ protected static function monitorWorkersForLinux(): void * Monitor all child processes. * * @return void + * @throws Throwable */ protected static function monitorWorkersForWindows(): void { @@ -1765,7 +1767,7 @@ protected static function monitorWorkersForWindows(): void /** * Exit current process. */ - protected static function exitAndClearAll() + protected static function exitAndClearAll(): void { foreach (static::$workers as $worker) { $socketName = $worker->getSocketName(); @@ -1912,9 +1914,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void } if (!static::$gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { static::$workers = []; - if (static::$globalEvent) { - static::$globalEvent->stop(); - } + static::$globalEvent?->stop(); try { exit($code); @@ -2032,7 +2032,7 @@ protected static function writeStatisticsToStatusFile(): void \reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); - $workerStatusStr = \posix_getpid() . "\t" . \str_pad((string)round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) + $workerStatusStr = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; @@ -2086,7 +2086,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void /** @var static $worker */ foreach (TcpConnection::$connections as $connection) { - /** @var \Workerman\Connection\TcpConnection $connection */ + /** @var TcpConnection $connection */ $transport = $connection->transport; $ipv4 = $connection->isIpV4() ? ' 1' : ' 0'; $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; @@ -2098,7 +2098,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void $bytesRead = $bytesFormat($connection->bytesRead); $bytesWritten = $bytesFormat($connection->bytesWritten); $id = $connection->id; - $protocol = $connection->protocol ? $connection->protocol : $connection->transport; + $protocol = $connection->protocol ?: $connection->transport; $pos = \strrpos($protocol, '\\'); if ($pos) { $protocol = \substr($protocol, $pos + 1); @@ -2591,12 +2591,12 @@ protected static function checkMasterIsAlive(int $masterPid): bool return false; } - $masterIsAlive = $masterPid && \posix_kill($masterPid, 0) && \posix_getpid() !== $masterPid; + $masterIsAlive = \posix_kill($masterPid, 0) && \posix_getpid() !== $masterPid; if (!$masterIsAlive) { return false; } - $cmdline = "/proc/{$masterPid}/cmdline"; + $cmdline = "/proc/$masterPid/cmdline"; if (!is_readable($cmdline) || empty(static::$processTitle)) { return true; } From f5dd7cc6008b8afbd2003ae1ce7515e6df639177 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Sat, 11 Mar 2023 03:30:14 +0200 Subject: [PATCH 0852/1216] Added missing types and @throws, removed global function imports (pollutes code). --- src/Connection/AsyncTcpConnection.php | 34 +- src/Connection/AsyncUdpConnection.php | 20 +- src/Connection/ConnectionInterface.php | 5 +- src/Connection/TcpConnection.php | 48 +- src/Connection/UdpConnection.php | 16 +- src/Events/Ev.php | 15 +- src/Events/Event.php | 25 +- src/Events/EventInterface.php | 14 +- src/Events/Revolt.php | 17 +- src/Events/Select.php | 26 +- src/Events/Swoole.php | 24 +- src/Events/Swow.php | 28 +- src/Protocols/Frame.php | 5 - src/Protocols/Http.php | 23 +- src/Protocols/Http/Chunk.php | 3 - src/Protocols/Http/Request.php | 24 - src/Protocols/Http/Response.php | 15 - src/Protocols/Http/ServerSentEvents.php | 2 - src/Protocols/Http/Session.php | 29 +- .../Http/Session/FileSessionHandler.php | 15 - src/Protocols/Text.php | 3 - src/Protocols/Websocket.php | 15 - src/Protocols/Ws.php | 16 - src/Timer.php | 14 +- src/Worker.php | 662 +++++++++--------- 25 files changed, 443 insertions(+), 655 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 351269bb2..5cdfdf4d1 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -22,28 +22,6 @@ use Throwable; use Workerman\Timer; use Workerman\Worker; -use function class_exists; -use function explode; -use function function_exists; -use function is_resource; -use function method_exists; -use function microtime; -use function parse_url; -use function socket_import_stream; -use function socket_set_option; -use function stream_context_create; -use function stream_set_blocking; -use function stream_set_read_buffer; -use function stream_socket_client; -use function stream_socket_get_name; -use function ucfirst; -use const DIRECTORY_SEPARATOR; -use const PHP_INT_MAX; -use const SO_KEEPALIVE; -use const SOL_SOCKET; -use const SOL_TCP; -use const STREAM_CLIENT_ASYNC_CONNECT; -use const TCP_NODELAY; /** * AsyncTcpConnection. @@ -210,7 +188,7 @@ public function __construct(string $remoteAddress, array $socketContext = []) * @return void * @throws Throwable */ - public function reconnect(int $after = 0) + public function reconnect(int $after = 0): void { $this->status = self::STATUS_INITIAL; static::$connections[$this->realId] = $this; @@ -230,7 +208,7 @@ public function reconnect(int $after = 0) * @return void * @throws Throwable */ - public function connect() + public function connect(): void { if ($this->status !== self::STATUS_INITIAL && $this->status !== self::STATUS_CLOSING && $this->status !== self::STATUS_CLOSED) { @@ -305,7 +283,7 @@ public function connect() * @return void * @throws Throwable */ - protected function emitError(int $code, mixed $msg) + protected function emitError(int $code, mixed $msg): void { $this->status = self::STATUS_CLOSING; if ($this->onError) { @@ -320,7 +298,7 @@ protected function emitError(int $code, mixed $msg) /** * CancelReconnect. */ - public function cancelReconnect() + public function cancelReconnect(): void { if ($this->reconnectTimer) { Timer::del($this->reconnectTimer); @@ -349,12 +327,12 @@ public function getRemoteURI(): string } /** - * Check connection is successfully established or faild. + * Check connection is successfully established or failed. * * @return void * @throws Throwable */ - public function checkConnection() + public function checkConnection(): void { // Remove EV_EXPECT for windows. if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index aa66c35ed..3cd684dae 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -20,18 +20,6 @@ use Throwable; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; -use function class_exists; -use function explode; -use function fclose; -use function stream_context_create; -use function stream_set_blocking; -use function stream_socket_client; -use function stream_socket_recvfrom; -use function stream_socket_sendto; -use function strlen; -use function substr; -use function ucfirst; -use const STREAM_CLIENT_CONNECT; /** * AsyncUdpConnection. @@ -99,7 +87,7 @@ public function __construct($remoteAddress, $contextOption = []) * @return void * @throws Throwable */ - public function baseRead($socket) + public function baseRead($socket): void { $recvBuffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); if (false === $recvBuffer || empty($remoteAddress)) { @@ -129,7 +117,7 @@ public function baseRead($socket) * @return void * @throws Throwable */ - public function close(mixed $data = null, bool $raw = false) + public function close(mixed $data = null, bool $raw = false): void { if ($data !== null) { $this->send($data, $raw); @@ -169,7 +157,7 @@ public function send(mixed $sendBuffer, bool $raw = false) if ($this->connected === false) { $this->connect(); } - return strlen($sendBuffer) === stream_socket_sendto($this->socket, $sendBuffer, 0); + return strlen($sendBuffer) === stream_socket_sendto($this->socket, $sendBuffer); } /** @@ -178,7 +166,7 @@ public function send(mixed $sendBuffer, bool $raw = false) * @return void * @throws Throwable */ - public function connect() + public function connect(): void { if ($this->connected === true) { return; diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 5f9ebee79..6b44b53ea 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -147,9 +147,10 @@ abstract public function getLocalAddress(): string; * Close connection. * * @param mixed|null $data + * @param bool $raw * @return void */ - abstract public function close(mixed $data = null, bool $raw = false); + abstract public function close(mixed $data = null, bool $raw = false): void; /** * Is ipv4. @@ -170,7 +171,7 @@ abstract public function isIpV6(): bool; * @return void * @throws Throwable */ - public function error(Throwable $exception) + public function error(Throwable $exception): void { if (!$this->errorHandler) { Worker::stopAll(250, $exception); diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 6f1028dba..9b756f086 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -23,34 +23,6 @@ use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; -use function ceil; -use function count; -use function fclose; -use function feof; -use function fread; -use function function_exists; -use function fwrite; -use function is_object; -use function is_resource; -use function key; -use function method_exists; -use function posix_getpid; -use function restore_error_handler; -use function set_error_handler; -use function stream_set_blocking; -use function stream_set_read_buffer; -use function stream_socket_enable_crypto; -use function stream_socket_get_name; -use function strlen; -use function strrchr; -use function strrpos; -use function substr; -use function var_export; -use const PHP_INT_MAX; -use const STREAM_CRYPTO_METHOD_SSLv23_CLIENT; -use const STREAM_CRYPTO_METHOD_SSLv23_SERVER; -use const STREAM_CRYPTO_METHOD_SSLv2_CLIENT; -use const STREAM_CRYPTO_METHOD_SSLv2_SERVER; /** * TcpConnection. @@ -193,7 +165,7 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable /** * Sets the maximum send buffer size for the current connection. - * OnBufferFull callback will be emited When send buffer is full. + * OnBufferFull callback will be emitted When send buffer is full. * * @var int */ @@ -567,7 +539,7 @@ public function getRecvBufferQueueSize(): int * * @return void */ - public function pauseRecv() + public function pauseRecv(): void { $this->eventLoop->offReadable($this->socket); $this->isPaused = true; @@ -579,7 +551,7 @@ public function pauseRecv() * @return void * @throws Throwable */ - public function resumeRecv() + public function resumeRecv(): void { if ($this->isPaused === true) { $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); @@ -597,7 +569,7 @@ public function resumeRecv() * @return void * @throws Throwable */ - public function baseRead($socket, bool $checkEof = true) + public function baseRead($socket, bool $checkEof = true): void { static $requests = []; // SSL handshake. @@ -737,7 +709,7 @@ public function baseRead($socket, bool $checkEof = true) * @return void * @throws Throwable */ - public function baseWrite() + public function baseWrite(): void { $len = 0; try { @@ -833,7 +805,7 @@ public function doSslHandshake($socket): bool|int * @param self $dest * @return void */ - public function pipe(self $dest) + public function pipe(self $dest): void { $source = $this; $this->onMessage = function ($source, $data) use ($dest) { @@ -856,7 +828,7 @@ public function pipe(self $dest) * @param int $length * @return void */ - public function consumeRecvBuffer(int $length) + public function consumeRecvBuffer(int $length): void { $this->recvBuffer = substr($this->recvBuffer, $length); } @@ -869,7 +841,7 @@ public function consumeRecvBuffer(int $length) * @return void * @throws Throwable */ - public function close(mixed $data = null, bool $raw = false) + public function close(mixed $data = null, bool $raw = false): void { if ($this->status === self::STATUS_CONNECTING) { $this->destroy(); @@ -937,7 +909,7 @@ public function getSocket() * @return void * @throws Throwable */ - protected function checkBufferWillFull() + protected function checkBufferWillFull(): void { if ($this->maxSendBufferSize <= strlen($this->sendBuffer)) { if ($this->onBufferFull) { @@ -988,7 +960,7 @@ public function bufferIsEmpty(): bool * @return void * @throws Throwable */ - public function destroy() + public function destroy(): void { // Avoid repeated calls. if ($this->status === self::STATUS_CLOSED) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index a7ec6a0e0..e43d6838d 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -20,13 +20,6 @@ use JetBrains\PhpStorm\Pure; use JsonSerializable; use Workerman\Protocols\ProtocolInterface; -use function stream_socket_get_name; -use function stream_socket_sendto; -use function strlen; -use function strrchr; -use function strrpos; -use function substr; -use function trim; /** * UdpConnection. @@ -175,9 +168,10 @@ public function getLocalAddress(): string * Close connection. * * @param mixed|null $data + * @param bool $raw * @return void */ - public function close(mixed $data = null, bool $raw = false) + public function close(mixed $data = null, bool $raw = false): void { if ($data !== null) { $this->send($data, $raw); @@ -228,7 +222,11 @@ public function getSocket() * * @return array */ - #[ArrayShape(['transport' => "string", 'getRemoteIp' => "string", 'remotePort' => "int", 'getRemoteAddress' => "string", 'getLocalIp' => "string", 'getLocalPort' => "int", 'getLocalAddress' => "string", 'isIpV4' => "bool", 'isIpV6' => "bool"])] public function jsonSerialize(): array + #[ArrayShape([ + 'transport' => "string", 'getRemoteIp' => "string", 'remotePort' => "int", 'getRemoteAddress' => "string", + 'getLocalIp' => "string", 'getLocalPort' => "int", 'getLocalAddress' => "string", 'isIpV4' => "bool", 'isIpV6' => "bool"] + )] + public function jsonSerialize(): array { return [ 'transport' => $this->transport, diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 6909515c0..a9d89c669 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -18,7 +18,6 @@ use EvIo; use EvSignal; use EvTimer; -use function count; /** * Ev eventloop @@ -115,7 +114,7 @@ public function repeat(float $interval, callable $func, array $args = []): int /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $fdKey = (int)$stream; $event = new EvIo($stream, \Ev::READ, function () use ($func, $stream) { @@ -141,7 +140,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $fdKey = (int)$stream; $event = new EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { @@ -167,7 +166,7 @@ public function offWritable($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { $event = new EvSignal($signal, function () use ($func, $signal) { $func($signal); @@ -191,7 +190,7 @@ public function offSignal(int $signal): bool /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { foreach ($this->eventTimer as $event) { $event->stop(); @@ -202,7 +201,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function run() + public function run(): void { \Ev::run(); } @@ -210,7 +209,7 @@ public function run() /** * {@inheritdoc} */ - public function stop() + public function stop(): void { \Ev::stop(); } @@ -226,7 +225,7 @@ public function getTimerCount(): int /** * {@inheritdoc} */ - public function setErrorHandler(callable $errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->errorHandler = $errorHandler; } diff --git a/src/Events/Event.php b/src/Events/Event.php index f498ad40d..b39f2d41e 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -17,9 +17,8 @@ namespace Workerman\Events; use EventBase; +use RuntimeException; use Throwable; -use function class_exists; -use function count; /** * libevent eventloop @@ -30,7 +29,7 @@ class Event implements EventInterface * Event base. * @var EventBase */ - protected $eventBase; + protected EventBase $eventBase; /** * All listeners for read event. @@ -109,7 +108,7 @@ public function delay(float $delay, callable $func, array $args = []): int } }); if (!$event->addTimer($delay)) { - throw new \RuntimeException("Event::addTimer($delay) failed"); + throw new RuntimeException("Event::addTimer($delay) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; @@ -151,7 +150,7 @@ public function repeat(float $interval, callable $func, array $args = []): int } }); if (!$event->addTimer($interval)) { - throw new \RuntimeException("Event::addTimer($interval) failed"); + throw new RuntimeException("Event::addTimer($interval) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; @@ -160,7 +159,7 @@ public function repeat(float $interval, callable $func, array $args = []): int /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; @@ -188,7 +187,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; @@ -216,7 +215,7 @@ public function offWritable($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { $className = $this->eventClassName; $fdKey = $signal; @@ -244,7 +243,7 @@ public function offSignal(int $signal): bool /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { foreach ($this->eventTimer as $event) { $event->del(); @@ -255,7 +254,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function run() + public function run(): void { $this->eventBase->loop(); } @@ -263,7 +262,7 @@ public function run() /** * {@inheritdoc} */ - public function stop() + public function stop(): void { $this->eventBase->exit(); } @@ -279,7 +278,7 @@ public function getTimerCount(): int /** * {@inheritdoc} */ - public function setErrorHandler($errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->errorHandler = $errorHandler; } @@ -297,7 +296,7 @@ public function getErrorHandler(): ?callable * @return void * @throws Throwable */ - public function error(Throwable $e) + public function error(Throwable $e): void { try { if (!$this->errorHandler) { diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index abc6dfc2b..0897a8231 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -55,7 +55,7 @@ public function offRepeat(int $timerId): bool; * @param callable $func * @return void */ - public function onReadable($stream, callable $func); + public function onReadable($stream, callable $func): void; /** * Cancel a callback of stream readable. @@ -70,7 +70,7 @@ public function offReadable($stream): bool; * @param callable $func * @return void */ - public function onWritable($stream, callable $func); + public function onWritable($stream, callable $func): void; /** * Cancel a callback of stream writable. @@ -86,7 +86,7 @@ public function offWritable($stream): bool; * @return void * @throws Throwable */ - public function onSignal(int $signal, callable $func); + public function onSignal(int $signal, callable $func): void; /** * Cancel a callback of signal. @@ -99,20 +99,20 @@ public function offSignal(int $signal): bool; * Delete all timer. * @return void */ - public function deleteAllTimer(); + public function deleteAllTimer(): void; /** * Run the event loop. * @return void * @throws Throwable */ - public function run(); + public function run(): void; /** * Stop event loop. * @return void */ - public function stop(); + public function stop(): void; /** * Get Timer count. @@ -125,7 +125,7 @@ public function getTimerCount(): int; * @param callable $errorHandler * @return void */ - public function setErrorHandler(callable $errorHandler); + public function setErrorHandler(callable $errorHandler): void; /** * Get error handler diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 0e3eb03b0..64661aa89 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -18,9 +18,6 @@ use Revolt\EventLoop; use Revolt\EventLoop\Driver; -use function count; -use function function_exists; -use function pcntl_signal; /** * Revolt eventloop @@ -83,7 +80,7 @@ public function driver(): Driver /** * {@inheritdoc} */ - public function run() + public function run(): void { $this->driver->run(); } @@ -91,7 +88,7 @@ public function run() /** * {@inheritdoc} */ - public function stop() + public function stop(): void { foreach ($this->eventSignal as $cbId) { $this->driver->cancel($cbId); @@ -134,7 +131,7 @@ public function repeat(float $interval, callable $func, array $args = []): int /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { @@ -164,7 +161,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $fdKey = (int)$stream; if (isset($this->writeEvents[$fdKey])) { @@ -193,7 +190,7 @@ public function offWritable($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { $fdKey = $signal; if (isset($this->eventSignal[$fdKey])) { @@ -243,7 +240,7 @@ public function offRepeat(int $timerId): bool /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { foreach ($this->eventTimer as $cbId) { $this->driver->cancel($cbId); @@ -262,7 +259,7 @@ public function getTimerCount(): int /** * {@inheritdoc} */ - public function setErrorHandler(callable $errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->driver->setErrorHandler($errorHandler); } diff --git a/src/Events/Select.php b/src/Events/Select.php index d4e15b567..a919809d2 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -185,7 +185,7 @@ public function offRepeat(int $timerId): bool /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $count = count($this->readFds); if ($count >= 1024) { @@ -214,7 +214,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $count = count($this->writeFds); if ($count >= 1024) { @@ -242,8 +242,10 @@ public function offWritable($stream): bool /** * On except. + * @param resource $stream + * @param $func */ - public function onExcept($stream, $func) + public function onExcept($stream, $func): void { $fdKey = (int)$stream; $this->exceptEvents[$fdKey] = $func; @@ -252,6 +254,8 @@ public function onExcept($stream, $func) /** * Off except. + * @param resource $stream + * @return bool */ public function offExcept($stream): bool { @@ -266,7 +270,7 @@ public function offExcept($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { if (!function_exists('pcntl_signal')) { return; @@ -296,7 +300,7 @@ public function offSignal(int $signal): bool * * @param int $signal */ - public function signalHandler(int $signal) + public function signalHandler(int $signal): void { $this->signalEvents[$signal]($signal); } @@ -307,7 +311,7 @@ public function signalHandler(int $signal) * @return void * @throws Throwable */ - protected function tick() + protected function tick(): void { $tasksToInsert = []; while (!$this->scheduler->isEmpty()) { @@ -357,7 +361,7 @@ protected function tick() /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { $this->scheduler = new SplPriorityQueue(); $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); @@ -367,7 +371,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function run() + public function run(): void { while ($this->running) { $read = $this->readFds; @@ -418,7 +422,7 @@ public function run() /** * {@inheritdoc} */ - public function stop() + public function stop(): void { $this->running = false; $this->deleteAllTimer(); @@ -440,7 +444,7 @@ public function getTimerCount(): int /** * {@inheritdoc} */ - public function setErrorHandler(callable $errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->errorHandler = $errorHandler; } @@ -458,7 +462,7 @@ public function getErrorHandler(): ?callable * @return void * @throws Throwable */ - public function error(Throwable $e) + public function error(Throwable $e): void { if (!$this->errorHandler) { throw new $e; diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 3ed840c6f..a951efc7b 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -19,10 +19,6 @@ use Swoole\Process; use Swoole\Timer; use Throwable; -use function count; -use function posix_kill; -use const SWOOLE_EVENT_READ; -use const SWOOLE_EVENT_WRITE; class Swoole implements EventInterface { @@ -61,6 +57,7 @@ public function __construct() /** * {@inheritdoc} + * @throws Throwable */ public function delay(float $delay, callable $func, array $args = []): int { @@ -101,6 +98,7 @@ public function offRepeat(int $timerId): bool /** * {@inheritdoc} + * @throws Throwable */ public function repeat(float $interval, callable $func, array $args = []): int { @@ -120,7 +118,7 @@ public function repeat(float $interval, callable $func, array $args = []): int /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { @@ -156,7 +154,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { @@ -192,9 +190,9 @@ public function offWritable($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { - return Process::signal($signal, $func); + Process::signal($signal, $func); } /** @@ -209,7 +207,7 @@ public function offSignal(int $signal): bool /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { foreach ($this->eventTimer as $timerId) { Timer::clear($timerId); @@ -219,7 +217,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function run() + public function run(): void { Event::wait(); } @@ -229,7 +227,7 @@ public function run() * * @return void */ - public function stop() + public function stop(): void { Event::exit(); posix_kill(posix_getpid(), SIGINT); @@ -248,7 +246,7 @@ public function getTimerCount(): int /** * {@inheritdoc} */ - public function setErrorHandler(callable $errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->errorHandler = $errorHandler; } @@ -266,7 +264,7 @@ public function getErrorHandler(): ?callable * @return void * @throws Throwable */ - public function error(Throwable $e) + public function error(Throwable $e): void { if (!$this->errorHandler) { throw new $e; diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 2bc85e6eb..b7c0655ba 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -9,16 +9,6 @@ use Swow\Signal; use Swow\SignalException; use Throwable; -use function count; -use function is_resource; -use function max; -use function msleep; -use function stream_poll_one; -use function Swow\Sync\waitAll; -use const STREAM_POLLHUP; -use const STREAM_POLLIN; -use const STREAM_POLLNONE; -use const STREAM_POLLOUT; class Swow implements EventInterface { @@ -63,6 +53,7 @@ public function getTimerCount(): int /** * {@inheritdoc} + * @throws Throwable */ public function delay(float $delay, callable $func, array $args = []): int { @@ -85,6 +76,7 @@ public function delay(float $delay, callable $func, array $args = []): int /** * {@inheritdoc} + * @throws Throwable */ public function repeat(float $interval, callable $func, array $args = []): int { @@ -133,7 +125,7 @@ public function offRepeat(int $timerId): bool /** * {@inheritdoc} */ - public function deleteAllTimer() + public function deleteAllTimer(): void { foreach ($this->eventTimer as $timerId) { $this->offDelay($timerId); @@ -143,7 +135,7 @@ public function deleteAllTimer() /** * {@inheritdoc} */ - public function onReadable($stream, callable $func) + public function onReadable($stream, callable $func): void { $fd = (int)$stream; if (isset($this->readEvents[$fd])) { @@ -192,7 +184,7 @@ public function offReadable($stream): bool /** * {@inheritdoc} */ - public function onWritable($stream, callable $func) + public function onWritable($stream, callable $func): void { $fd = (int)$stream; if (isset($this->writeEvents[$fd])) { @@ -236,7 +228,7 @@ public function offWritable($stream): bool /** * {@inheritdoc} */ - public function onSignal(int $signal, callable $func) + public function onSignal(int $signal, callable $func): void { Coroutine::run(function () use ($signal, $func): void { $this->signalListener[$signal] = Coroutine::getCurrent(); @@ -269,7 +261,7 @@ public function offSignal(int $signal): bool /** * {@inheritdoc} */ - public function run() + public function run(): void { waitAll(); } @@ -279,7 +271,7 @@ public function run() * * @return void */ - public function stop() + public function stop(): void { Coroutine::killAll(); } @@ -287,7 +279,7 @@ public function stop() /** * {@inheritdoc} */ - public function setErrorHandler(callable $errorHandler) + public function setErrorHandler(callable $errorHandler): void { $this->errorHandler = $errorHandler; } @@ -305,7 +297,7 @@ public function getErrorHandler(): ?callable * @return void * @throws Throwable */ - public function error(Throwable $e) + public function error(Throwable $e): void { if (!$this->errorHandler) { throw new $e; diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index c8ce71c52..82cedc820 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -16,11 +16,6 @@ namespace Workerman\Protocols; -use function pack; -use function strlen; -use function substr; -use function unpack; - /** * Frame Protocol. */ diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index a96f59a05..4a36459c5 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -20,25 +20,6 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; -use function clearstatcache; -use function count; -use function explode; -use function filesize; -use function fopen; -use function fread; -use function fseek; -use function ftell; -use function in_array; -use function ini_get; -use function is_array; -use function is_object; -use function key; -use function preg_match; -use function strlen; -use function strpos; -use function strstr; -use function substr; -use function sys_get_temp_dir; /** * Class Http. @@ -271,7 +252,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin * @param int $length * @throws Throwable */ - protected static function sendStream(TcpConnection $connection, $handler, int $offset = 0, int $length = 0) + protected static function sendStream(TcpConnection $connection, $handler, int $offset = 0, int $length = 0): void { $connection->context->bufferFull = false; $connection->context->streamSending = true; @@ -293,7 +274,7 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o $connection->onBufferDrain = null; return; } - $size = $remainSize > $size ? $size : $remainSize; + $size = min($remainSize, $size); } $buffer = fread($handler, $size); diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 619d622c9..8c900ac02 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -16,9 +16,6 @@ namespace Workerman\Protocols\Http; -use function dechex; -use function strlen; - /** * Class Chunk * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 8d04a386e..b73c67702 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -20,30 +20,6 @@ use RuntimeException; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; -use function array_walk_recursive; -use function bin2hex; -use function clearstatcache; -use function count; -use function explode; -use function file_put_contents; -use function is_file; -use function json_decode; -use function ltrim; -use function microtime; -use function pack; -use function parse_str; -use function parse_url; -use function preg_match; -use function preg_replace; -use function strlen; -use function strpos; -use function strstr; -use function strtolower; -use function substr; -use function tempnam; -use function trim; -use function unlink; -use function urlencode; /** * Class Request diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 907c5e914..2772fdd2c 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -16,21 +16,6 @@ namespace Workerman\Protocols\Http; -use function array_merge_recursive; -use function explode; -use function file; -use function filemtime; -use function gmdate; -use function is_array; -use function is_file; -use function pathinfo; -use function preg_match; -use function rawurlencode; -use function strlen; -use function substr; -use const FILE_IGNORE_NEW_LINES; -use const FILE_SKIP_EMPTY_LINES; - /** * Class Response * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index 28eaf6ca7..fd73379ea 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -16,8 +16,6 @@ namespace Workerman\Protocols\Http; -use function str_replace; - /** * Class ServerSentEvents * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 261d9a842..634b7ebef 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -21,15 +21,6 @@ use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; -use function array_key_exists; -use function ini_get; -use function is_array; -use function is_scalar; -use function preg_match; -use function random_int; -use function serialize; -use function session_get_cookie_params; -use function unserialize; /** * Class Session @@ -194,7 +185,7 @@ public function get(string $name, mixed $default = null): mixed * @param string $name * @param mixed $value */ - public function set(string $name, mixed $value) + public function set(string $name, mixed $value): void { $this->data[$name] = $value; $this->needSave = true; @@ -205,7 +196,7 @@ public function set(string $name, mixed $value) * * @param string $name */ - public function delete(string $name) + public function delete(string $name): void { unset($this->data[$name]); $this->needSave = true; @@ -231,7 +222,7 @@ public function pull(string $name, mixed $default = null): mixed * @param array|string $key * @param mixed|null $value */ - public function put(array|string $key, mixed $value = null) + public function put(array|string $key, mixed $value = null): void { if (!is_array($key)) { $this->set($key, $value); @@ -249,7 +240,7 @@ public function put(array|string $key, mixed $value = null) * * @param array|string $name */ - public function forget(array|string $name) + public function forget(array|string $name): void { if (is_scalar($name)) { $this->delete($name); @@ -278,7 +269,7 @@ public function all(): array * * @return void */ - public function flush() + public function flush(): void { $this->needSave = true; $this->data = []; @@ -311,7 +302,7 @@ public function exists(string $name): bool * * @return void */ - public function save() + public function save(): void { if ($this->needSave) { if (empty($this->data)) { @@ -340,7 +331,7 @@ public function refresh(): bool * * @return void */ - public static function init() + public static function init(): void { if (($gcProbability = (int)ini_get('session.gc_probability')) && ($gcDivisor = (int)ini_get('session.gc_divisor'))) { static::$gcProbability = [$gcProbability, $gcDivisor]; @@ -399,7 +390,7 @@ public static function getCookieParams(): array * * @return void */ - protected static function initHandler() + protected static function initHandler(): void { if (static::$handlerConfig === null) { static::$handler = new static::$handlerClass(); @@ -413,7 +404,7 @@ protected static function initHandler() * * @return void */ - public function gc() + public function gc(): void { static::$handler->gc(static::$lifetime); } @@ -437,7 +428,7 @@ public function __destruct() * * @param string $sessionId */ - protected static function checkSessionId(string $sessionId) + protected static function checkSessionId(string $sessionId): void { if (!preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { throw new RuntimeException("session_id $sessionId is invalid"); diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index aea6d06e7..d9d36a0dc 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -18,21 +18,6 @@ use Exception; use Workerman\Protocols\Http\Session; -use function clearstatcache; -use function file_get_contents; -use function file_put_contents; -use function filemtime; -use function glob; -use function is_dir; -use function is_file; -use function mkdir; -use function rename; -use function session_save_path; -use function strlen; -use function sys_get_temp_dir; -use function time; -use function touch; -use function unlink; /** * Class FileSessionHandler diff --git a/src/Protocols/Text.php b/src/Protocols/Text.php index df32ebe41..64e1ad7ea 100644 --- a/src/Protocols/Text.php +++ b/src/Protocols/Text.php @@ -17,9 +17,6 @@ namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; -use function rtrim; -use function strlen; -use function strpos; /** * Text Protocol. diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index d914407de..ed25c3b7e 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -22,21 +22,6 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Worker; -use function base64_encode; -use function chr; -use function floor; -use function gettype; -use function is_scalar; -use function ord; -use function pack; -use function preg_match; -use function sha1; -use function str_repeat; -use function stripos; -use function strlen; -use function strpos; -use function substr; -use function unpack; /** * WebSocket protocol. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 38c2b250d..b1d17927c 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -22,22 +22,6 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Timer; use Workerman\Worker; -use function base64_encode; -use function bin2hex; -use function floor; -use function gettype; -use function is_array; -use function is_scalar; -use function ord; -use function pack; -use function preg_match; -use function sha1; -use function str_repeat; -use function strlen; -use function strpos; -use function substr; -use function trim; -use function unpack; /** * Websocket protocol for client. diff --git a/src/Timer.php b/src/Timer.php index 973ae5ddf..b9aafad4e 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -16,22 +16,12 @@ namespace Workerman; -use Exception; -use Revolt\EventLoop; use RuntimeException; -use Swoole\Coroutine\System; use Throwable; use Workerman\Events\EventInterface; use Workerman\Events\Revolt; use Workerman\Events\Swoole; use Workerman\Events\Swow; -use function function_exists; -use function is_callable; -use function pcntl_alarm; -use function pcntl_signal; -use function time; -use const PHP_INT_MAX; -use const SIGALRM; /** * Timer. @@ -161,7 +151,7 @@ public static function sleep(float $delay): void switch (Worker::$eventLoopClass) { // Fiber case Revolt::class: - $suspension = EventLoop::getSuspension(); + $suspension = \Revolt\EventLoop::getSuspension(); static::add($delay, function () use ($suspension) { $suspension->resume(); }, null, false); @@ -169,7 +159,7 @@ public static function sleep(float $delay): void return; // Swoole case Swoole::class: - System::sleep($delay); + \Swoole\Coroutine\System::sleep($delay); return; // Swow case Swow::class: diff --git a/src/Worker.php b/src/Worker.php index 40df08083..51ccbb0c5 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -16,7 +16,9 @@ namespace Workerman; +use AllowDynamicProperties; use Exception; +use RuntimeException; use stdClass; use Throwable; use Workerman\Connection\ConnectionInterface; @@ -26,14 +28,12 @@ use Workerman\Events\EventInterface; use Workerman\Events\Revolt; use Workerman\Events\Select; -use Revolt\EventLoop; - /** * Worker class * A container for listening ports */ -#[\AllowDynamicProperties] +#[AllowDynamicProperties] class Worker { /** @@ -507,21 +507,21 @@ class Worker * @var array */ public const ERROR_TYPE = [ - \E_ERROR => 'E_ERROR', // 1 - \E_WARNING => 'E_WARNING', // 2 - \E_PARSE => 'E_PARSE', // 4 - \E_NOTICE => 'E_NOTICE', // 8 - \E_CORE_ERROR => 'E_CORE_ERROR', // 16 - \E_CORE_WARNING => 'E_CORE_WARNING', // 32 - \E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 - \E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 - \E_USER_ERROR => 'E_USER_ERROR', // 256 - \E_USER_WARNING => 'E_USER_WARNING', // 512 - \E_USER_NOTICE => 'E_USER_NOTICE', // 1024 - \E_STRICT => 'E_STRICT', // 2048 - \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 - \E_DEPRECATED => 'E_DEPRECATED', // 8192 - \E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + E_ERROR => 'E_ERROR', // 1 + E_WARNING => 'E_WARNING', // 2 + E_PARSE => 'E_PARSE', // 4 + E_NOTICE => 'E_NOTICE', // 8 + E_CORE_ERROR => 'E_CORE_ERROR', // 16 + E_CORE_WARNING => 'E_CORE_WARNING', // 32 + E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 + E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 + E_USER_ERROR => 'E_USER_ERROR', // 256 + E_USER_WARNING => 'E_USER_WARNING', // 512 + E_USER_NOTICE => 'E_USER_NOTICE', // 1024 + E_STRICT => 'E_STRICT', // 2048 + E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 + E_DEPRECATED => 'E_DEPRECATED', // 8192 + E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 ]; /** @@ -566,7 +566,7 @@ public static function runAll(): void static::initWorkers(); static::installSignal(); static::saveMasterPid(); - static::lock(\LOCK_UN); + static::lock(LOCK_UN); static::displayUI(); static::forkWorkers(); static::resetStd(); @@ -581,7 +581,7 @@ public static function runAll(): void protected static function checkSapiEnv(): void { // Only for cli. - if (\PHP_SAPI !== 'cli') { + if (PHP_SAPI !== 'cli') { exit("Only run in command line mode \n"); } } @@ -593,15 +593,15 @@ protected static function checkSapiEnv(): void */ protected static function init(): void { - \set_error_handler(function ($code, $msg, $file, $line) { + set_error_handler(function ($code, $msg, $file, $line) { static::safeEcho("$msg in file $file on line $line\n"); }); // Start file. - $backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); static::$startFile = end($backtrace)['file']; - $uniquePrefix = \str_replace('/', '_', static::$startFile); + $uniquePrefix = str_replace('/', '_', static::$startFile); // Pid file. if (empty(static::$pidFile)) { @@ -613,20 +613,20 @@ protected static function init(): void static::$logFile = __DIR__ . '/../../workerman.log'; } - if (!\is_file(static::$logFile)) { + if (!is_file(static::$logFile)) { // if /runtime/logs default folder not exists if (!is_dir(dirname(static::$logFile))) { @mkdir(dirname(static::$logFile), 0777, true); } - \touch(static::$logFile); - \chmod(static::$logFile, 0622); + touch(static::$logFile); + chmod(static::$logFile, 0622); } // State. static::$status = static::STATUS_STARTING; // For statistics. - static::$globalStatistics['start_timestamp'] = \time(); + static::$globalStatistics['start_timestamp'] = time(); // Process title. static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$startFile); @@ -644,21 +644,21 @@ protected static function init(): void * @param int $flag * @return void */ - protected static function lock(int $flag = \LOCK_EX): void + protected static function lock(int $flag = LOCK_EX): void { static $fd; - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } $lockFile = static::$pidFile . '.lock'; - $fd = $fd ?: \fopen($lockFile, 'a+'); + $fd = $fd ?: fopen($lockFile, 'a+'); if ($fd) { flock($fd, $flag); - if ($flag === \LOCK_UN) { + if ($flag === LOCK_UN) { fclose($fd); $fd = null; clearstatcache(); - if (\is_file($lockFile)) { + if (is_file($lockFile)) { unlink($lockFile); } } @@ -673,7 +673,7 @@ protected static function lock(int $flag = \LOCK_EX): void */ protected static function initWorkers(): void { - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } static::$statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' . posix_getpid() . '.status'; @@ -687,7 +687,7 @@ protected static function initWorkers(): void if (empty($worker->user)) { $worker->user = static::getCurrentUser(); } else { - if (\posix_getuid() !== 0 && $worker->user !== static::getCurrentUser()) { + if (posix_getuid() !== 0 && $worker->user !== static::getCurrentUser()) { static::log('Warning: You must have the root privileges to change uid and gid.'); } } @@ -701,9 +701,9 @@ protected static function initWorkers(): void // Get column mapping for UI foreach (static::getUiColumns() as $columnName => $prop) { !isset($worker->$prop) && !isset($worker->context->$prop) && $worker->context->$prop = 'NNNN'; - $propLength = \strlen((string)($worker->$prop ?? $worker->context->$prop)); - $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; - static::$$key = \max(static::$$key, $propLength); + $propLength = strlen((string)($worker->$prop ?? $worker->context->$prop)); + $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; + static::$$key = max(static::$$key, $propLength); } // Listen. @@ -766,7 +766,7 @@ protected static function initId(): void */ protected static function getCurrentUser(): string { - $userInfo = \posix_getpwuid(\posix_getuid()); + $userInfo = posix_getpwuid(posix_getuid()); return $userInfo['name'] ?? 'unknown'; } @@ -778,50 +778,50 @@ protected static function getCurrentUser(): string protected static function displayUI(): void { $tmpArgv = static::getArgv(); - if (\in_array('-q', $tmpArgv)) { + if (in_array('-q', $tmpArgv)) { return; } - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:' . static::VERSION . ' PHP version:' . \PHP_VERSION . "\r\n"); + static::safeEcho('Workerman version:' . static::VERSION . ' PHP version:' . PHP_VERSION . "\r\n"); static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; } //show version - $lineVersion = 'Workerman version:' . static::VERSION . \str_pad('PHP version:', 16, ' ', \STR_PAD_LEFT) . \PHP_VERSION . \str_pad('Event-loop:', 16, ' ', \STR_PAD_LEFT) . static::getEventLoopName() . \PHP_EOL; - !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', \strlen($lineVersion)); + $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . str_pad('Event-loop:', 16, ' ', STR_PAD_LEFT) . static::getEventLoopName() . PHP_EOL; + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); - $lineOne = '' . \str_pad(' WORKERMAN ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . '' . \PHP_EOL; - $lineTwo = \str_pad(' WORKERS ', $totalLength + \strlen(''), '-', \STR_PAD_BOTH) . \PHP_EOL; + $lineOne = '' . str_pad(' WORKERMAN ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . '' . PHP_EOL; + $lineTwo = str_pad(' WORKERS ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; static::safeEcho($lineOne . $lineVersion . $lineTwo); //Show title $title = ''; foreach (static::getUiColumns() as $columnName => $prop) { - $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; + $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; //just keep compatible with listen name $columnName === 'socket' && $columnName = 'listen'; - $title .= "$columnName" . \str_pad('', static::$$key + static::UI_SAFE_LENGTH - \strlen($columnName)); + $title .= "$columnName" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($columnName)); } - $title && static::safeEcho($title . \PHP_EOL); + $title && static::safeEcho($title . PHP_EOL); //Show content foreach (static::$workers as $worker) { $content = ''; foreach (static::getUiColumns() as $columnName => $prop) { $propValue = (string)($worker->$prop ?? $worker->context->$prop); - $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; - \preg_match_all("/(|<\/n>||<\/w>||<\/g>)/i", $propValue, $matches); - $placeHolderLength = !empty($matches) ? \strlen(\implode('', $matches[0])) : 0; - $content .= \str_pad($propValue, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); + $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; + preg_match_all("/(|<\/n>||<\/w>||<\/g>)/i", $propValue, $matches); + $placeHolderLength = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $content .= str_pad($propValue, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); } - $content && static::safeEcho($content . \PHP_EOL); + $content && static::safeEcho($content . PHP_EOL); } //Show last line - $lineLast = \str_pad('', static::getSingleLineTotalLength(), '-') . \PHP_EOL; + $lineLast = str_pad('', static::getSingleLineTotalLength(), '-') . PHP_EOL; !empty($content) && static::safeEcho($lineLast); if (static::$daemonize) { @@ -863,12 +863,12 @@ public static function getSingleLineTotalLength(): int $totalLength = 0; foreach (static::getUiColumns() as $columnName => $prop) { - $key = 'max' . \ucfirst(\strtolower($columnName)) . 'NameLength'; + $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; $totalLength += static::$$key + static::UI_SAFE_LENGTH; } //Keep beauty when show less columns - !\defined('LINE_VERSIOIN_LENGTH') && \define('LINE_VERSIOIN_LENGTH', 0); + !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); $totalLength <= LINE_VERSIOIN_LENGTH && $totalLength = LINE_VERSIOIN_LENGTH; return $totalLength; @@ -881,7 +881,7 @@ public static function getSingleLineTotalLength(): int */ protected static function parseCommand(): void { - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } global $argv; @@ -902,9 +902,9 @@ protected static function parseCommand(): void ]; $command = $mode = ''; foreach (static::getArgv() as $value) { - if (\in_array($value, $availableCommands)) { + if (in_array($value, $availableCommands)) { $command = $value; - } elseif (\in_array($value, $availableMode)) { + } elseif (in_array($value, $availableMode)) { $mode = $value; } } @@ -925,7 +925,7 @@ protected static function parseCommand(): void static::log("Workerman[$startFile] $command $modeStr"); // Get master process PID. - $masterPid = \is_file(static::$pidFile) ? (int)\file_get_contents(static::$pidFile) : 0; + $masterPid = is_file(static::$pidFile) ? (int)file_get_contents(static::$pidFile) : 0; // Master is still alive? if (static::checkMasterIsAlive($masterPid)) { if ($command === 'start') { @@ -948,13 +948,13 @@ protected static function parseCommand(): void break; case 'status': while (1) { - if (\is_file($statisticsFile)) { - @\unlink($statisticsFile); + if (is_file($statisticsFile)) { + @unlink($statisticsFile); } // Master process will send SIGIOT signal to all child processes. - \posix_kill($masterPid, SIGIOT); + posix_kill($masterPid, SIGIOT); // Sleep 1 second. - \sleep(1); + sleep(1); // Clear terminal. if ($mode === '-d') { static::safeEcho("\33[H\33[2J\33(B\33[m", true); @@ -962,51 +962,51 @@ protected static function parseCommand(): void // Echo status data. static::safeEcho(static::formatStatusData($statisticsFile)); if ($mode !== '-d') { - @\unlink($statisticsFile); + @unlink($statisticsFile); exit(0); } static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } case 'connections': - if (\is_file($statisticsFile) && \is_writable($statisticsFile)) { - \unlink($statisticsFile); + if (is_file($statisticsFile) && is_writable($statisticsFile)) { + unlink($statisticsFile); } // Master process will send SIGIO signal to all child processes. - \posix_kill($masterPid, SIGIO); + posix_kill($masterPid, SIGIO); // Waiting amoment. - \usleep(500000); + usleep(500000); // Display statisitcs data from a disk file. - if (\is_readable($statisticsFile)) { - \readfile($statisticsFile); + if (is_readable($statisticsFile)) { + readfile($statisticsFile); } exit(0); case 'restart': case 'stop': if ($mode === '-g') { static::$gracefulStop = true; - $sig = \SIGQUIT; + $sig = SIGQUIT; static::log("Workerman[$startFile] is gracefully stopping ..."); } else { static::$gracefulStop = false; - $sig = \SIGINT; + $sig = SIGINT; static::log("Workerman[$startFile] is stopping ..."); } // Send stop signal to master process. - $masterPid && \posix_kill($masterPid, $sig); + $masterPid && posix_kill($masterPid, $sig); // Timeout. $timeout = static::$stopTimeout + 3; - $startTime = \time(); + $startTime = time(); // Check master process is still alive? while (1) { - $masterIsAlive = $masterPid && \posix_kill($masterPid, 0); + $masterIsAlive = $masterPid && posix_kill($masterPid, 0); if ($masterIsAlive) { // Timeout? - if (!static::$gracefulStop && \time() - $startTime >= $timeout) { + if (!static::$gracefulStop && time() - $startTime >= $timeout) { static::log("Workerman[$startFile] stop fail"); exit; } // Waiting amoment. - \usleep(10000); + usleep(10000); continue; } // Stop success. @@ -1022,11 +1022,11 @@ protected static function parseCommand(): void break; case 'reload': if ($mode === '-g') { - $sig = \SIGUSR2; + $sig = SIGUSR2; } else { - $sig = \SIGUSR1; + $sig = SIGUSR1; } - \posix_kill($masterPid, $sig); + posix_kill($masterPid, $sig); exit; default : static::safeEcho('Unknown command: ' . $command . "\n"); @@ -1042,7 +1042,7 @@ protected static function parseCommand(): void public static function getArgv(): array { global $argv; - return isset($argv[1]) ? $argv : (static::$command ? \explode(' ', static::$command) : $argv); + return isset($argv[1]) ? $argv : (static::$command ? explode(' ', static::$command) : $argv); } /** @@ -1054,17 +1054,17 @@ public static function getArgv(): array protected static function formatStatusData($statisticsFile): string { static $totalRequestCache = []; - if (!\is_readable($statisticsFile)) { + if (!is_readable($statisticsFile)) { return ''; } - $info = \file($statisticsFile, \FILE_IGNORE_NEW_LINES); + $info = file($statisticsFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } $statusStr = ''; $currentTotalRequest = []; - $workerInfo = \unserialize($info[0]); - \ksort($workerInfo, SORT_NUMERIC); + $workerInfo = unserialize($info[0]); + ksort($workerInfo, SORT_NUMERIC); unset($info[0]); $dataWaitingSort = []; $readProcessStatus = false; @@ -1079,18 +1079,18 @@ protected static function formatStatusData($statisticsFile): string foreach ($info as $value) { if (!$readProcessStatus) { $statusStr .= $value . "\n"; - if (\preg_match('/^pid.*?memory.*?listening/', $value)) { + if (preg_match('/^pid.*?memory.*?listening/', $value)) { $readProcessStatus = true; } continue; } - if (\preg_match('/^[0-9]+/', $value, $pidMath)) { + if (preg_match('/^[0-9]+/', $value, $pidMath)) { $pid = $pidMath[0]; $dataWaitingSort[$pid] = $value; - if (\preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $totalMemory += (int)\str_ireplace('M', '', $match[1]); - $maxLen1 = \max($maxLen1, \strlen($match[2])); - $maxLen2 = \max($maxLen2, \strlen($match[3])); + if (preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { + $totalMemory += (int)str_ireplace('M', '', $match[1]); + $maxLen1 = max($maxLen1, strlen($match[2])); + $maxLen2 = max($maxLen2, strlen($match[3])); $totalConnections += (int)$match[4]; $totalFails += (int)$match[5]; $totalTimers += (int)$match[6]; @@ -1101,11 +1101,11 @@ protected static function formatStatusData($statisticsFile): string } foreach ($workerInfo as $pid => $info) { if (!isset($dataWaitingSort[$pid])) { - $statusStr .= "$pid\t" . \str_pad('N/A', 7) . " " - . \str_pad($info['listen'], static::$maxSocketNameLength) . " " - . \str_pad((string)$info['name'], static::$maxWorkerNameLength) . " " - . \str_pad('N/A', 11) . " " . \str_pad('N/A', 9) . " " - . \str_pad('N/A', 7) . " " . \str_pad('N/A', 13) . " N/A [busy] \n"; + $statusStr .= "$pid\t" . str_pad('N/A', 7) . " " + . str_pad($info['listen'], static::$maxSocketNameLength) . " " + . str_pad((string)$info['name'], static::$maxWorkerNameLength) . " " + . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " + . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; continue; } //$qps = isset($totalRequestCache[$pid]) ? $currentTotalRequest[$pid] @@ -1115,16 +1115,16 @@ protected static function formatStatusData($statisticsFile): string $qps = $currentTotalRequest[$pid] - $totalRequestCache[$pid]; $totalQps += $qps; } - $statusStr .= $dataWaitingSort[$pid] . " " . \str_pad((string)$qps, 6) . " [idle]\n"; + $statusStr .= $dataWaitingSort[$pid] . " " . str_pad((string)$qps, 6) . " [idle]\n"; } $totalRequestCache = $currentTotalRequest; $statusStr .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; - $statusStr .= "Summary\t" . \str_pad($totalMemory . 'M', 7) . " " - . \str_pad('-', $maxLen1) . " " - . \str_pad('-', $maxLen2) . " " - . \str_pad((string)$totalConnections, 11) . " " . \str_pad((string)$totalFails, 9) . " " - . \str_pad((string)$totalTimers, 7) . " " . \str_pad((string)$totalRequests, 13) . " " - . \str_pad((string)$totalQps, 6) . " [Summary] \n"; + $statusStr .= "Summary\t" . str_pad($totalMemory . 'M', 7) . " " + . str_pad('-', $maxLen1) . " " + . str_pad('-', $maxLen2) . " " + . str_pad((string)$totalConnections, 11) . " " . str_pad((string)$totalFails, 9) . " " + . str_pad((string)$totalTimers, 7) . " " . str_pad((string)$totalRequests, 13) . " " + . str_pad((string)$totalQps, 6) . " [Summary] \n"; return $statusStr; } @@ -1136,15 +1136,15 @@ protected static function formatStatusData($statisticsFile): string */ protected static function installSignal(): void { - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } - $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; + $signals = [SIGINT, SIGTERM, SIGHUP, SIGTSTP, SIGQUIT, SIGUSR1, SIGUSR2, SIGIOT, SIGIO]; foreach ($signals as $signal) { - \pcntl_signal($signal, [static::class, 'signalHandler'], false); + pcntl_signal($signal, [static::class, 'signalHandler'], false); } // ignore - \pcntl_signal(\SIGPIPE, \SIG_IGN, false); + pcntl_signal(SIGPIPE, SIG_IGN, false); } /** @@ -1155,12 +1155,12 @@ protected static function installSignal(): void */ protected static function reinstallSignal(): void { - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } - $signals = [\SIGINT, \SIGTERM, \SIGHUP, \SIGTSTP, \SIGQUIT, \SIGUSR1, \SIGUSR2, \SIGIOT, \SIGIO]; + $signals = [SIGINT, SIGTERM, SIGHUP, SIGTSTP, SIGQUIT, SIGUSR1, SIGUSR2, SIGIOT, SIGIO]; foreach ($signals as $signal) { - \pcntl_signal($signal, \SIG_IGN, false); + pcntl_signal($signal, SIG_IGN, false); static::$globalEvent->onSignal($signal, [static::class, 'signalHandler']); } } @@ -1175,34 +1175,34 @@ public static function signalHandler(int $signal): void { switch ($signal) { // Stop. - case \SIGINT: - case \SIGTERM: - case \SIGHUP: - case \SIGTSTP: + case SIGINT: + case SIGTERM: + case SIGHUP: + case SIGTSTP: static::$gracefulStop = false; static::stopAll(); break; // Graceful stop. - case \SIGQUIT: + case SIGQUIT: static::$gracefulStop = true; static::stopAll(); break; // Reload. - case \SIGUSR2: - case \SIGUSR1: + case SIGUSR2: + case SIGUSR1: if (static::$status === static::STATUS_RELOADING || static::$status === static::STATUS_SHUTDOWN) { return; } - static::$gracefulStop = $signal === \SIGUSR2; + static::$gracefulStop = $signal === SIGUSR2; static::$pidsToRestart = static::getAllWorkerPids(); static::reload(); break; // Show status. - case \SIGIOT: + case SIGIOT: static::writeStatisticsToStatusFile(); break; // Show connection status. - case \SIGIO: + case SIGIO: static::writeConnectionsStatisticsToStatusFile(); break; } @@ -1215,23 +1215,23 @@ public static function signalHandler(int $signal): void */ protected static function daemonize(): void { - if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { + if (!static::$daemonize || DIRECTORY_SEPARATOR !== '/') { return; } - \umask(0); - $pid = \pcntl_fork(); + umask(0); + $pid = pcntl_fork(); if (-1 === $pid) { - throw new \RuntimeException('Fork fail'); + throw new RuntimeException('Fork fail'); } elseif ($pid > 0) { exit(0); } - if (-1 === \posix_setsid()) { - throw new \RuntimeException("Setsid fail"); + if (-1 === posix_setsid()) { + throw new RuntimeException("Setsid fail"); } // Fork again avoid SVR4 system regain the control of terminal. - $pid = \pcntl_fork(); + $pid = pcntl_fork(); if (-1 === $pid) { - throw new \RuntimeException("Fork fail"); + throw new RuntimeException("Fork fail"); } elseif (0 !== $pid) { exit(0); } @@ -1246,43 +1246,43 @@ protected static function daemonize(): void */ public static function resetStd(bool $throwException = true): void { - if (!static::$daemonize || \DIRECTORY_SEPARATOR !== '/') { + if (!static::$daemonize || DIRECTORY_SEPARATOR !== '/') { return; } global $STDOUT, $STDERR; - $handle = \fopen(static::$stdoutFile, "a"); + $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - \set_error_handler(function () { + set_error_handler(function () { }); if ($STDOUT) { - \fclose($STDOUT); + fclose($STDOUT); } if ($STDERR) { - \fclose($STDERR); + fclose($STDERR); } - if (\is_resource(\STDOUT)) { - \fclose(\STDOUT); + if (is_resource(STDOUT)) { + fclose(STDOUT); } - if (\is_resource(\STDERR)) { - \fclose(\STDERR); + if (is_resource(STDERR)) { + fclose(STDERR); } - $STDOUT = \fopen(static::$stdoutFile, "a"); - $STDERR = \fopen(static::$stdoutFile, "a"); + $STDOUT = fopen(static::$stdoutFile, "a"); + $STDERR = fopen(static::$stdoutFile, "a"); // Fix standard output cannot redirect of PHP 8.1.8's bug - if (\function_exists('posix_isatty') && \posix_isatty(2)) { - \ob_start(function ($string) { - \file_put_contents(static::$stdoutFile, $string, FILE_APPEND); + if (function_exists('posix_isatty') && posix_isatty(2)) { + ob_start(function ($string) { + file_put_contents(static::$stdoutFile, $string, FILE_APPEND); }, 1); } // change output stream static::$outputStream = null; static::outputStream($STDOUT); - \restore_error_handler(); + restore_error_handler(); return; } if ($throwException) { - throw new \RuntimeException('Can not open stdoutFile ' . static::$stdoutFile); + throw new RuntimeException('Can not open stdoutFile ' . static::$stdoutFile); } } @@ -1293,13 +1293,13 @@ public static function resetStd(bool $throwException = true): void */ protected static function saveMasterPid(): void { - if (\DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/') { return; } - static::$masterPid = \posix_getpid(); - if (false === \file_put_contents(static::$pidFile, static::$masterPid)) { - throw new \RuntimeException('can not save pid to ' . static::$pidFile); + static::$masterPid = posix_getpid(); + if (false === file_put_contents(static::$pidFile, static::$masterPid)) { + throw new RuntimeException('can not save pid to ' . static::$pidFile); } } @@ -1314,14 +1314,14 @@ protected static function getEventLoopName(): string return static::$eventLoopClass; } - if (\class_exists(EventLoop::class)) { + if (class_exists(\Revolt\EventLoop::class)) { static::$eventLoopClass = Revolt::class; return static::$eventLoopClass; } $loopName = ''; foreach (static::$availableEventLoops as $name => $class) { - if (\extension_loaded($name)) { + if (extension_loaded($name)) { $loopName = $name; break; } @@ -1359,7 +1359,7 @@ protected static function getAllWorkerPids(): array */ protected static function forkWorkers(): void { - if (\DIRECTORY_SEPARATOR === '/') { + if (DIRECTORY_SEPARATOR === '/') { static::forkWorkersForLinux(); } else { static::forkWorkersForWindows(); @@ -1374,19 +1374,18 @@ protected static function forkWorkers(): void */ protected static function forkWorkersForLinux(): void { - foreach (static::$workers as $worker) { if (static::$status === static::STATUS_STARTING) { if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } - $workerNameLength = \strlen($worker->name); + $workerNameLength = strlen($worker->name); if (static::$maxWorkerNameLength < $workerNameLength) { static::$maxWorkerNameLength = $workerNameLength; } } - while (\count(static::$pidMap[$worker->workerId]) < $worker->count) { + while (count(static::$pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorkerForLinux($worker); } } @@ -1401,15 +1400,15 @@ protected static function forkWorkersForLinux(): void protected static function forkWorkersForWindows(): void { $files = static::getStartFilesForWindows(); - if (\in_array('-q', static::getArgv()) || \count($files) === 1) { - if (\count(static::$workers) > 1) { + if (in_array('-q', static::getArgv()) || count($files) === 1) { + if (count(static::$workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); static::safeEcho("@@@ See https://www.workerman.net/doc/workerman/faq/multi-woker-for-windows.html @@@\r\n"); - } elseif (\count(static::$workers) <= 0) { + } elseif (count(static::$workers) <= 0) { exit("@@@no worker inited@@@\r\n\r\n"); } - \reset(static::$workers); + reset(static::$workers); /** @var Worker $worker */ $worker = current(static::$workers); @@ -1419,7 +1418,7 @@ protected static function forkWorkersForWindows(): void static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - \register_shutdown_function([__CLASS__, 'checkErrors']); + register_shutdown_function([__CLASS__, 'checkErrors']); // Create a global event loop. if (!static::$globalEvent) { @@ -1436,10 +1435,10 @@ protected static function forkWorkersForWindows(): void // Init Timer. Timer::init(static::$globalEvent); - \restore_error_handler(); + restore_error_handler(); // Display UI. - static::safeEcho(\str_pad($worker->name, 21) . \str_pad($worker->getSocketName(), 36) . \str_pad((string)$worker->count, 10) . "[ok]\n"); + static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad((string)$worker->count, 10) . "[ok]\n"); $worker->listen(); $worker->run(); static::$globalEvent->run(); @@ -1470,7 +1469,7 @@ public static function getStartFilesForWindows(): array { $files = []; foreach (static::getArgv() as $file) { - if (\is_file($file)) { + if (is_file($file)) { $files[$file] = $file; } } @@ -1484,14 +1483,14 @@ public static function getStartFilesForWindows(): array */ public static function forkOneWorkerForWindows(string $startFile): void { - $startFile = \realpath($startFile); + $startFile = realpath($startFile); $descriptor_spec = array( STDIN, STDOUT, STDOUT ); $pipes = array(); - $process = \proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); + $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1514,11 +1513,11 @@ public static function checkWorkerStatusForWindows(): void foreach (static::$processForWindows as $processData) { $process = $processData[0]; $startFile = $processData[1]; - $status = \proc_get_status($process); + $status = proc_get_status($process); if (isset($status['running'])) { if (!$status['running']) { static::safeEcho("process $startFile terminated and try to restart\n"); - \proc_close($process); + proc_close($process); static::forkOneWorkerForWindows($startFile); } } else { @@ -1537,15 +1536,15 @@ protected static function forkOneWorkerForLinux(self $worker): void { // Get available worker id. $id = static::getId($worker->workerId, 0); - $pid = \pcntl_fork(); + $pid = pcntl_fork(); // For master process. if ($pid > 0) { static::$pidMap[$worker->workerId][$pid] = $pid; static::$idMap[$worker->workerId][$id] = $pid; } // For child processes. elseif (0 === $pid) { - \srand(); - \mt_srand(); + srand(); + mt_srand(); static::$gracefulStop = false; if (static::$status === static::STATUS_STARTING) { static::resetStd(); @@ -1564,7 +1563,7 @@ protected static function forkOneWorkerForLinux(self $worker): void static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - \register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); + register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); // Create a global event loop. if (!static::$globalEvent) { @@ -1581,7 +1580,7 @@ protected static function forkOneWorkerForLinux(self $worker): void // Init Timer. Timer::init(static::$globalEvent); - \restore_error_handler(); + restore_error_handler(); static::setProcessTitle(self::$processTitle . ': worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); @@ -1596,7 +1595,7 @@ protected static function forkOneWorkerForLinux(self $worker): void } exit(0); } else { - throw new \RuntimeException("forkOneWorker fail"); + throw new RuntimeException("forkOneWorker fail"); } } @@ -1610,7 +1609,7 @@ protected static function forkOneWorkerForLinux(self $worker): void */ protected static function getId(string $workerId, int $pid): bool|int|string { - return \array_search($pid, static::$idMap[$workerId]); + return array_search($pid, static::$idMap[$workerId]); } /** @@ -1621,7 +1620,7 @@ protected static function getId(string $workerId, int $pid): bool|int|string public function setUserAndGroup(): void { // Get uid. - $userInfo = \posix_getpwnam($this->user); + $userInfo = posix_getpwnam($this->user); if (!$userInfo) { static::log("Warning: User $this->user not exists"); return; @@ -1629,7 +1628,7 @@ public function setUserAndGroup(): void $uid = $userInfo['uid']; // Get gid. if ($this->group) { - $groupInfo = \posix_getgrnam($this->group); + $groupInfo = posix_getgrnam($this->group); if (!$groupInfo) { static::log("Warning: Group $this->group not exists"); return; @@ -1640,8 +1639,8 @@ public function setUserAndGroup(): void } // Set uid and gid. - if ($uid !== \posix_getuid() || $gid !== \posix_getgid()) { - if (!\posix_setgid($gid) || !\posix_initgroups($userInfo['name'], $gid) || !\posix_setuid($uid)) { + if ($uid !== posix_getuid() || $gid !== posix_getgid()) { + if (!posix_setgid($gid) || !posix_initgroups($userInfo['name'], $gid) || !posix_setuid($uid)) { static::log("Warning: change gid or uid fail."); } } @@ -1655,10 +1654,10 @@ public function setUserAndGroup(): void */ protected static function setProcessTitle(string $title): void { - \set_error_handler(function () { + set_error_handler(function () { }); - \cli_set_process_title($title); - \restore_error_handler(); + cli_set_process_title($title); + restore_error_handler(); } /** @@ -1669,7 +1668,7 @@ protected static function setProcessTitle(string $title): void */ protected static function monitorWorkers(): void { - if (\DIRECTORY_SEPARATOR === '/') { + if (DIRECTORY_SEPARATOR === '/') { static::monitorWorkersForLinux(); } else { static::monitorWorkersForWindows(); @@ -1687,12 +1686,12 @@ protected static function monitorWorkersForLinux(): void static::$status = static::STATUS_RUNNING; while (1) { // Calls signal handlers for pending signals. - \pcntl_signal_dispatch(); + pcntl_signal_dispatch(); // Suspends execution of the current process until a child has exited, or until a signal is delivered $status = 0; - $pid = \pcntl_wait($status, \WUNTRACED); + $pid = pcntl_wait($status, WUNTRACED); // Calls signal handlers for pending signals again. - \pcntl_signal_dispatch(); + pcntl_signal_dispatch(); // If a child has already exited. if ($pid > 0) { // Find out which worker process exited. @@ -1700,7 +1699,7 @@ protected static function monitorWorkersForLinux(): void if (isset($workerPidArray[$pid])) { $worker = static::$workers[$workerId]; // Fix exit with status 2 for php8.2 - if ($status === \SIGINT && static::$status === static::STATUS_SHUTDOWN) { + if ($status === SIGINT && static::$status === static::STATUS_SHUTDOWN) { $status = 0; } // Exit status. @@ -1772,15 +1771,15 @@ protected static function exitAndClearAll(): void foreach (static::$workers as $worker) { $socketName = $worker->getSocketName(); if ($worker->transport === 'unix' && $socketName) { - list(, $address) = \explode(':', $socketName, 2); + list(, $address) = explode(':', $socketName, 2); $address = substr($address, strpos($address, '/') + 2); - @\unlink($address); + @unlink($address); } } - @\unlink(static::$pidFile); - static::log("Workerman[" . \basename(static::$startFile) . "] has been stopped"); + @unlink(static::$pidFile); + static::log("Workerman[" . basename(static::$startFile) . "] has been stopped"); if (static::$onMasterStop) { - \call_user_func(static::$onMasterStop); + call_user_func(static::$onMasterStop); } exit(0); } @@ -1794,18 +1793,18 @@ protected static function exitAndClearAll(): void protected static function reload(): void { // For master process. - if (static::$masterPid === \posix_getpid()) { - $sig = static::$gracefulStop ? \SIGUSR2 : \SIGUSR1; + if (static::$masterPid === posix_getpid()) { + $sig = static::$gracefulStop ? SIGUSR2 : SIGUSR1; // Set reloading state. if (static::$status !== static::STATUS_RELOADING && static::$status !== static::STATUS_SHUTDOWN) { - static::log("Workerman[" . \basename(static::$startFile) . "] reloading"); + static::log("Workerman[" . basename(static::$startFile) . "] reloading"); static::$status = static::STATUS_RELOADING; static::resetStd(false); // Try to emit onMasterReload callback. if (static::$onMasterReload) { try { - \call_user_func(static::$onMasterReload); + call_user_func(static::$onMasterReload); } catch (Throwable $e) { static::stopAll(250, $e); } @@ -1823,12 +1822,12 @@ protected static function reload(): void } else { foreach ($workerPidArray as $pid) { // Send reload signal to a worker process which reloadable is false. - \posix_kill($pid, $sig); + posix_kill($pid, $sig); } } } // Get all pids that are waiting reload. - static::$pidsToRestart = \array_intersect(static::$pidsToRestart, $reloadablePidArray); + static::$pidsToRestart = array_intersect(static::$pidsToRestart, $reloadablePidArray); } // Reload complete. @@ -1839,21 +1838,21 @@ protected static function reload(): void return; } // Continue reload. - $oneWorkerPid = \current(static::$pidsToRestart); + $oneWorkerPid = current(static::$pidsToRestart); // Send reload signal to a worker process. - \posix_kill($oneWorkerPid, $sig); + posix_kill($oneWorkerPid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. if (!static::$gracefulStop) { - Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, \SIGKILL], false); + Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, SIGKILL], false); } } // For child processes. else { - \reset(static::$workers); - $worker = \current(static::$workers); + reset(static::$workers); + $worker = current(static::$workers); // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { try { - \call_user_func($worker->onWorkerReload, $worker); + call_user_func($worker->onWorkerReload, $worker); } catch (Throwable $e) { static::stopAll(250, $e); } @@ -1881,26 +1880,26 @@ public static function stopAll(int $code = 0, mixed $log = ''): void static::$status = static::STATUS_SHUTDOWN; // For master process. - if (\DIRECTORY_SEPARATOR === '/' && static::$masterPid === \posix_getpid()) { - static::log("Workerman[" . \basename(static::$startFile) . "] stopping ..."); + if (DIRECTORY_SEPARATOR === '/' && static::$masterPid === posix_getpid()) { + static::log("Workerman[" . basename(static::$startFile) . "] stopping ..."); $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. - $sig = static::$gracefulStop ? \SIGQUIT : \SIGINT; + $sig = static::$gracefulStop ? SIGQUIT : SIGINT; foreach ($workerPidArray as $workerPid) { // Fix exit with status 2 for php8.2 - if ($sig === \SIGINT && !static::$daemonize) { - Timer::add(1, '\posix_kill', [$workerPid, \SIGINT], false); + if ($sig === SIGINT && !static::$daemonize) { + Timer::add(1, '\posix_kill', [$workerPid, SIGINT], false); } else { - \posix_kill($workerPid, $sig); + posix_kill($workerPid, $sig); } if (!static::$gracefulStop) { - Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, \SIGKILL], false); + Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, SIGKILL], false); } } Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); // Remove statistics file. - if (\is_file(static::$statisticsFile)) { - @\unlink(static::$statisticsFile); + if (is_file(static::$statisticsFile)) { + @unlink(static::$statisticsFile); } } // For child processes. else { @@ -1932,7 +1931,7 @@ public static function checkIfChildRunning(): void { foreach (static::$pidMap as $workerId => $workerPidArray) { foreach ($workerPidArray as $pid => $workerPid) { - if (!\posix_kill($pid, 0)) { + if (!posix_kill($pid, 0)) { unset(static::$pidMap[$workerId][$pid]); } } @@ -1967,7 +1966,7 @@ public static function getGracefulStop(): bool protected static function writeStatisticsToStatusFile(): void { // For master process. - if (static::$masterPid === \posix_getpid()) { + if (static::$masterPid === posix_getpid()) { $allWorkerInfo = []; foreach (static::$pidMap as $workerId => $pidArray) { /** @var /Workerman/Worker $worker */ @@ -1977,70 +1976,70 @@ protected static function writeStatisticsToStatusFile(): void } } - \file_put_contents(static::$statisticsFile, \serialize($allWorkerInfo) . "\n", \FILE_APPEND); - $loadavg = \function_exists('sys_getloadavg') ? \array_map('round', \sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; - \file_put_contents(static::$statisticsFile, - "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", \FILE_APPEND); - \file_put_contents(static::$statisticsFile, - 'Workerman version:' . static::VERSION . " PHP version:" . \PHP_VERSION . "\n", \FILE_APPEND); - \file_put_contents(static::$statisticsFile, 'start time:' . \date('Y-m-d H:i:s', - static::$globalStatistics['start_timestamp']) . ' run ' . \floor((\time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . \floor(((\time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", + file_put_contents(static::$statisticsFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); + $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; + file_put_contents(static::$statisticsFile, + "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, + 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, 'start time:' . date('Y-m-d H:i:s', + static::$globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); - $loadStr = 'load average: ' . \implode(", ", $loadavg); - \file_put_contents(static::$statisticsFile, - \str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", \FILE_APPEND); - \file_put_contents(static::$statisticsFile, - \count(static::$pidMap) . ' workers ' . \count(static::getAllWorkerPids()) . " processes\n", - \FILE_APPEND); - \file_put_contents(static::$statisticsFile, - \str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", \FILE_APPEND); + $loadStr = 'load average: ' . implode(", ", $loadavg); + file_put_contents(static::$statisticsFile, + str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, + count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", + FILE_APPEND); + file_put_contents(static::$statisticsFile, + str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { - \file_put_contents(static::$statisticsFile, - \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad((string)$workerExitStatus, - 16) . " $workerExitCount\n", \FILE_APPEND); + file_put_contents(static::$statisticsFile, + str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad((string)$workerExitStatus, + 16) . " $workerExitCount\n", FILE_APPEND); } } else { - \file_put_contents(static::$statisticsFile, - \str_pad($worker->name, static::$maxWorkerNameLength) . " " . \str_pad('0', 16) . " 0\n", - \FILE_APPEND); + file_put_contents(static::$statisticsFile, + str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad('0', 16) . " 0\n", + FILE_APPEND); } } - \file_put_contents(static::$statisticsFile, + file_put_contents(static::$statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", - \FILE_APPEND); - \file_put_contents(static::$statisticsFile, - "pid\tmemory " . \str_pad('listening', static::$maxSocketNameLength) . " " . \str_pad('worker_name', - static::$maxWorkerNameLength) . " connections " . \str_pad('send_fail', 9) . " " - . \str_pad('timers', 8) . \str_pad('total_request', 13) . " qps status\n", \FILE_APPEND); + FILE_APPEND); + file_put_contents(static::$statisticsFile, + "pid\tmemory " . str_pad('listening', static::$maxSocketNameLength) . " " . str_pad('worker_name', + static::$maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " + . str_pad('timers', 8) . str_pad('total_request', 13) . " qps status\n", FILE_APPEND); - \chmod(static::$statisticsFile, 0722); + chmod(static::$statisticsFile, 0722); foreach (static::getAllWorkerPids() as $workerPid) { - \posix_kill($workerPid, \SIGIOT); + posix_kill($workerPid, SIGIOT); } return; } // For child processes. - \gc_collect_cycles(); - if (\function_exists('gc_mem_caches')) { - \gc_mem_caches(); + gc_collect_cycles(); + if (function_exists('gc_mem_caches')) { + gc_mem_caches(); } - \reset(static::$workers); + reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); - $workerStatusStr = \posix_getpid() . "\t" . \str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) - . " " . \str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " - . \str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) + $workerStatusStr = posix_getpid() . "\t" . str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) + . " " . str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " + . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) . " "; - $workerStatusStr .= \str_pad((string)ConnectionInterface::$statistics['connection_count'], 11) - . " " . \str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) - . " " . \str_pad((string)static::$globalEvent->getTimerCount(), 7) - . " " . \str_pad((string)ConnectionInterface::$statistics['total_request'], 13) . "\n"; - \file_put_contents(static::$statisticsFile, $workerStatusStr, \FILE_APPEND); + $workerStatusStr .= str_pad((string)ConnectionInterface::$statistics['connection_count'], 11) + . " " . str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) + . " " . str_pad((string)static::$globalEvent->getTimerCount(), 7) + . " " . str_pad((string)ConnectionInterface::$statistics['total_request'], 13) . "\n"; + file_put_contents(static::$statisticsFile, $workerStatusStr, FILE_APPEND); } /** @@ -2051,12 +2050,12 @@ protected static function writeStatisticsToStatusFile(): void protected static function writeConnectionsStatisticsToStatusFile(): void { // For master process. - if (static::$masterPid === \posix_getpid()) { - \file_put_contents(static::$statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", \FILE_APPEND); - \file_put_contents(static::$statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", \FILE_APPEND); - \chmod(static::$statisticsFile, 0722); + if (static::$masterPid === posix_getpid()) { + file_put_contents(static::$statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + chmod(static::$statisticsFile, 0722); foreach (static::getAllWorkerPids() as $workerPid) { - \posix_kill($workerPid, \SIGIO); + posix_kill($workerPid, SIGIO); } return; } @@ -2078,9 +2077,9 @@ protected static function writeConnectionsStatisticsToStatusFile(): void return $bytes . "B"; }; - $pid = \posix_getpid(); + $pid = posix_getpid(); $str = ''; - \reset(static::$workers); + reset(static::$workers); $currentWorker = current(static::$workers); $defaultWorkerName = $currentWorker->name; @@ -2092,31 +2091,31 @@ protected static function writeConnectionsStatisticsToStatusFile(): void $ipv6 = $connection->isIpV6() ? ' 1' : ' 0'; $recvQ = $bytesFormat($connection->getRecvBufferQueueSize()); $sendQ = $bytesFormat($connection->getSendBufferQueueSize()); - $localAddress = \trim($connection->getLocalAddress()); - $remoteAddress = \trim($connection->getRemoteAddress()); + $localAddress = trim($connection->getLocalAddress()); + $remoteAddress = trim($connection->getRemoteAddress()); $state = $connection->getStatus(false); $bytesRead = $bytesFormat($connection->bytesRead); $bytesWritten = $bytesFormat($connection->bytesWritten); $id = $connection->id; $protocol = $connection->protocol ?: $connection->transport; - $pos = \strrpos($protocol, '\\'); + $pos = strrpos($protocol, '\\'); if ($pos) { - $protocol = \substr($protocol, $pos + 1); + $protocol = substr($protocol, $pos + 1); } - if (\strlen($protocol) > 15) { - $protocol = \substr($protocol, 0, 13) . '..'; + if (strlen($protocol) > 15) { + $protocol = substr($protocol, 0, 13) . '..'; } $workerName = isset($connection->worker) ? $connection->worker->name : $defaultWorkerName; - if (\strlen($workerName) > 14) { - $workerName = \substr($workerName, 0, 12) . '..'; + if (strlen($workerName) > 14) { + $workerName = substr($workerName, 0, 12) . '..'; } - $str .= \str_pad((string)$pid, 9) . \str_pad($workerName, 16) . \str_pad((string)$id, 10) . \str_pad($transport, 8) - . \str_pad($protocol, 16) . \str_pad($ipv4, 7) . \str_pad($ipv6, 7) . \str_pad($recvQ, 13) - . \str_pad($sendQ, 13) . \str_pad($bytesRead, 13) . \str_pad($bytesWritten, 13) . ' ' - . \str_pad($state, 14) . ' ' . \str_pad($localAddress, 22) . ' ' . \str_pad($remoteAddress, 22) . "\n"; + $str .= str_pad((string)$pid, 9) . str_pad($workerName, 16) . str_pad((string)$id, 10) . str_pad($transport, 8) + . str_pad($protocol, 16) . str_pad($ipv4, 7) . str_pad($ipv6, 7) . str_pad($recvQ, 13) + . str_pad($sendQ, 13) . str_pad($bytesRead, 13) . str_pad($bytesWritten, 13) . ' ' + . str_pad($state, 14) . ' ' . str_pad($localAddress, 22) . ' ' . str_pad($remoteAddress, 22) . "\n"; } if ($str) { - \file_put_contents(static::$statisticsFile, $str, \FILE_APPEND); + file_put_contents(static::$statisticsFile, $str, FILE_APPEND); } } @@ -2128,13 +2127,13 @@ protected static function writeConnectionsStatisticsToStatusFile(): void public static function checkErrors(): void { if (static::STATUS_SHUTDOWN !== static::$status) { - $errorMsg = \DIRECTORY_SEPARATOR === '/' ? 'Worker[' . \posix_getpid() . '] process terminated' : 'Worker process terminated'; + $errorMsg = DIRECTORY_SEPARATOR === '/' ? 'Worker[' . posix_getpid() . '] process terminated' : 'Worker process terminated'; $errors = error_get_last(); - if ($errors && ($errors['type'] === \E_ERROR || - $errors['type'] === \E_PARSE || - $errors['type'] === \E_CORE_ERROR || - $errors['type'] === \E_COMPILE_ERROR || - $errors['type'] === \E_RECOVERABLE_ERROR) + if ($errors && ($errors['type'] === E_ERROR || + $errors['type'] === E_PARSE || + $errors['type'] === E_CORE_ERROR || + $errors['type'] === E_COMPILE_ERROR || + $errors['type'] === E_RECOVERABLE_ERROR) ) { $errorMsg .= ' with ERROR: ' . static::getErrorType($errors['type']) . " \"{$errors['message']} in {$errors['file']} on line {$errors['line']}\""; } @@ -2165,8 +2164,8 @@ public static function log(mixed $msg): void if (!static::$daemonize) { static::safeEcho($msg); } - \file_put_contents(static::$logFile, \date('Y-m-d H:i:s') . ' ' . 'pid:' - . (\DIRECTORY_SEPARATOR === '/' ? \posix_getpid() : 1) . ' ' . $msg, \FILE_APPEND | \LOCK_EX); + file_put_contents(static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' + . (DIRECTORY_SEPARATOR === '/' ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** @@ -2189,13 +2188,13 @@ public static function safeEcho(string $msg, bool $decorated = false): bool $green = "\033[32;40m"; $end = "\033[0m"; } - $msg = \str_replace(['', '', ''], [$line, $white, $green], $msg); - $msg = \str_replace(['', '', ''], $end, $msg); + $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); + $msg = str_replace(['', '', ''], $end, $msg); } elseif (!static::$outputDecorated) { return false; } - \fwrite($stream, $msg); - \fflush($stream); + fwrite($stream, $msg); + fflush($stream); return true; } @@ -2208,12 +2207,12 @@ public static function safeEcho(string $msg, bool $decorated = false): bool private static function outputStream($stream = null) { if (!$stream) { - $stream = static::$outputStream ?: \STDOUT; + $stream = static::$outputStream ?: STDOUT; } - if (!$stream || !\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { + if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) { return false; } - $stat = \fstat($stream); + $stat = fstat($stream); if (!$stat) { return false; } @@ -2222,9 +2221,9 @@ private static function outputStream($stream = null) static::$outputDecorated = false; } else { static::$outputDecorated = - \DIRECTORY_SEPARATOR === '/' && // linux or unix - \function_exists('posix_isatty') && - \posix_isatty($stream); // whether is interactive terminal + DIRECTORY_SEPARATOR === '/' && // linux or unix + function_exists('posix_isatty') && + posix_isatty($stream); // whether is interactive terminal } return static::$outputStream = $stream; } @@ -2238,7 +2237,7 @@ private static function outputStream($stream = null) public function __construct(string $socketName = null, array $socketContext = []) { // Save all worker instances. - $this->workerId = \spl_object_hash($this); + $this->workerId = spl_object_hash($this); $this->context = new stdClass(); static::$workers[$this->workerId] = $this; static::$pidMap[$this->workerId] = []; @@ -2249,7 +2248,7 @@ public function __construct(string $socketName = null, array $socketContext = [] if (!isset($socketContext['socket']['backlog'])) { $socketContext['socket']['backlog'] = static::DEFAULT_BACKLOG; } - $this->socketContext = \stream_context_create($socketContext); + $this->socketContext = stream_context_create($socketContext); } // Try to turn reusePort on. @@ -2276,7 +2275,6 @@ public function __construct(string $socketName = null, array $socketContext = [] }*/ } - /** * Listen. * @@ -2293,44 +2291,44 @@ public function listen(): void $localSocket = $this->parseSocketAddress(); // Flag. - $flags = $this->transport === 'udp' ? \STREAM_SERVER_BIND : \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN; + $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $errno = 0; $errmsg = ''; // SO_REUSEPORT. if ($this->reusePort) { - \stream_context_set_option($this->socketContext, 'socket', 'so_reuseport', 1); + stream_context_set_option($this->socketContext, 'socket', 'so_reuseport', 1); } // Create an Internet or Unix domain server socket. - $this->mainSocket = \stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->socketContext); + $this->mainSocket = stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->socketContext); if (!$this->mainSocket) { throw new Exception($errmsg); } if ($this->transport === 'ssl') { - \stream_socket_enable_crypto($this->mainSocket, false); + stream_socket_enable_crypto($this->mainSocket, false); } elseif ($this->transport === 'unix') { - $socketFile = \substr($localSocket, 7); + $socketFile = substr($localSocket, 7); if ($this->user) { - \chown($socketFile, $this->user); + chown($socketFile, $this->user); } if ($this->group) { - \chgrp($socketFile, $this->group); + chgrp($socketFile, $this->group); } } // Try to open keepalive for tcp and disable Nagle algorithm. - if (\function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { - \set_error_handler(function () { + if (function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { + set_error_handler(function () { }); - $socket = \socket_import_stream($this->mainSocket); - \socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1); - \socket_set_option($socket, \SOL_TCP, \TCP_NODELAY, 1); - \restore_error_handler(); + $socket = socket_import_stream($this->mainSocket); + socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); + socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + restore_error_handler(); } // Non blocking. - \stream_set_blocking($this->mainSocket, false); + stream_set_blocking($this->mainSocket, false); } $this->resumeAccept(); @@ -2345,10 +2343,10 @@ public function unlisten(): void { $this->pauseAccept(); if ($this->mainSocket) { - \set_error_handler(function () { + set_error_handler(function () { }); - \fclose($this->mainSocket); - \restore_error_handler(); + fclose($this->mainSocket); + restore_error_handler(); $this->mainSocket = null; } } @@ -2364,20 +2362,20 @@ protected function parseSocketAddress(): ?string return null; } // Get the application layer communication protocol and listening address. - list($scheme, $address) = \explode(':', $this->socketName, 2); + list($scheme, $address) = explode(':', $this->socketName, 2); // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { - $scheme = \ucfirst($scheme); + $scheme = ucfirst($scheme); $this->protocol = $scheme[0] === '\\' ? $scheme : 'Protocols\\' . $scheme; - if (!\class_exists($this->protocol)) { + if (!class_exists($this->protocol)) { $this->protocol = "Workerman\\Protocols\\$scheme"; - if (!\class_exists($this->protocol)) { - throw new \RuntimeException("class \\Protocols\\$scheme not exist"); + if (!class_exists($this->protocol)) { + throw new RuntimeException("class \\Protocols\\$scheme not exist"); } } if (!isset(self::BUILD_IN_TRANSPORTS[$this->transport])) { - throw new \RuntimeException('Bad worker->transport ' . \var_export($this->transport, true)); + throw new RuntimeException('Bad worker->transport ' . var_export($this->transport, true)); } } else if ($this->transport === 'tcp') { $this->transport = $scheme; @@ -2424,7 +2422,7 @@ public function resumeAccept(): void */ public function getSocketName(): string { - return $this->socketName ? \lcfirst($this->socketName) : 'none'; + return $this->socketName ? lcfirst($this->socketName) : 'none'; } /** @@ -2491,10 +2489,10 @@ public function stop(): void public function acceptTcpConnection($socket): void { // Accept a connection on server socket. - \set_error_handler(function () { + set_error_handler(function () { }); - $newSocket = \stream_socket_accept($socket, 0, $remoteAddress); - \restore_error_handler(); + $newSocket = stream_socket_accept($socket, 0, $remoteAddress); + restore_error_handler(); // Thundering herd. if (!$newSocket) { @@ -2531,10 +2529,10 @@ public function acceptTcpConnection($socket): void */ public function acceptUdpConnection($socket): bool { - \set_error_handler(function () { + set_error_handler(function () { }); - $recvBuffer = \stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); - \restore_error_handler(); + $recvBuffer = stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); + restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { return false; } @@ -2545,15 +2543,15 @@ public function acceptUdpConnection($socket): bool if ($messageCallback) { try { if ($this->protocol !== null) { - /** @var \Workerman\Protocols\ProtocolInterface $parser */ + /** @var ProtocolInterface $parser */ $parser = $this->protocol; - if ($parser && \method_exists($parser, 'input')) { + if ($parser && method_exists($parser, 'input')) { while ($recvBuffer !== '') { $len = $parser::input($recvBuffer, $connection); if ($len === 0) return true; - $package = \substr($recvBuffer, 0, $len); - $recvBuffer = \substr($recvBuffer, $len); + $package = substr($recvBuffer, 0, $len); + $recvBuffer = substr($recvBuffer, $len); $data = $parser::decode($package, $connection); if ($data === false) { continue; @@ -2591,7 +2589,7 @@ protected static function checkMasterIsAlive(int $masterPid): bool return false; } - $masterIsAlive = \posix_kill($masterPid, 0) && \posix_getpid() !== $masterPid; + $masterIsAlive = posix_kill($masterPid, 0) && posix_getpid() !== $masterPid; if (!$masterIsAlive) { return false; } From 9d587dae018fe357e5022d97dee60147fc760919 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Sat, 11 Mar 2023 03:56:30 +0200 Subject: [PATCH 0853/1216] Renamed WebSocket variables to camelCase. --- src/Protocols/Websocket.php | 14 +++++++------- src/Protocols/Ws.php | 12 ++++++------ src/Worker.php | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index ed25c3b7e..b457122d5 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -72,11 +72,11 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } } else { - $firstbyte = ord($buffer[0]); - $secondbyte = ord($buffer[1]); - $dataLen = $secondbyte & 127; - $isFinFrame = $firstbyte >> 7; - $masked = $secondbyte >> 7; + $firstByte = ord($buffer[0]); + $secondByte = ord($buffer[1]); + $dataLen = $secondByte & 127; + $isFinFrame = $firstByte >> 7; + $masked = $secondByte >> 7; if (!$masked) { Worker::safeEcho("frame not masked so close the connection\n"); @@ -84,7 +84,7 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } - $opcode = $firstbyte & 0xf; + $opcode = $firstByte & 0xf; switch ($opcode) { case 0x0: // Blob type. @@ -392,7 +392,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } } if (!$hasServerHeader) { - $handshakeMessage .= "Server: workerman/" . Worker::VERSION . "\r\n"; + $handshakeMessage .= 'Server: ' . Worker::$processTitle . ' ('. Worker::VERSION . ')' . "\r\n"; } $handshakeMessage .= "\r\n"; // Send handshake response. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index b1d17927c..bd701abd5 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -73,11 +73,11 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo } } else { - $firstbyte = ord($buffer[0]); - $secondbyte = ord($buffer[1]); - $dataLen = $secondbyte & 127; - $isFinFrame = $firstbyte >> 7; - $masked = $secondbyte >> 7; + $firstByte = ord($buffer[0]); + $secondByte = ord($buffer[1]); + $dataLen = $secondByte & 127; + $isFinFrame = $firstByte >> 7; + $masked = $secondByte >> 7; if ($masked) { Worker::safeEcho("frame masked so close the connection\n"); @@ -85,7 +85,7 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo return 0; } - $opcode = $firstbyte & 0xf; + $opcode = $firstByte & 0xf; switch ($opcode) { case 0x0: diff --git a/src/Worker.php b/src/Worker.php index 51ccbb0c5..04fadd0a8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -28,6 +28,7 @@ use Workerman\Events\EventInterface; use Workerman\Events\Revolt; use Workerman\Events\Select; +use Workerman\Protocols\ProtocolInterface; /** * Worker class From 8d807ce59463fc22dccdcd3b020e600f532d896f Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 16 Mar 2023 07:04:17 +0200 Subject: [PATCH 0854/1216] Fixed grammar issues and added default $decorator parameter for Worker::log function. --- src/Protocols/Http/Request.php | 4 ++-- src/Protocols/Websocket.php | 12 ++++++---- src/Worker.php | 43 +++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b73c67702..45f70eee8 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -509,8 +509,8 @@ protected function parseUploadFiles(string $httpPostBoundary): void $postEncodeString = ''; $filesEncodeString = ''; $files = []; - $bodayPosition = strpos($buffer, "\r\n\r\n") + 4; - $offset = $bodayPosition + strlen($httpPostBoundary) + 2; + $bodyPosition = strpos($buffer, "\r\n\r\n") + 4; + $offset = $bodyPosition + strlen($httpPostBoundary) + 2; $maxCount = static::$maxFileUploads; while ($maxCount-- > 0 && $offset) { $offset = $this->parseUploadFile($httpPostBoundary, $offset, $postEncodeString, $filesEncodeString, $files); diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index b457122d5..5546e84d9 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -344,14 +344,15 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $SecWebSocketKey = $match[1]; } else { - $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", - true); + $connection->close( + 'HTTP/1.1 200 OK\r\nServer: '. Worker::$processTitle . ' ('. Worker::VERSION . ')' + . '\r\n\r\n

WebSocket


'. Worker::$processTitle . '/' . Worker::VERSION . '
', true); return 0; } // Calculation websocket key. $newKey = base64_encode(sha1($SecWebSocketKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. - $handshakeMessage = "HTTP/1.1 101 Switching Protocols\r\n" + $handshakeMessage = "HTTP/1.1 101 Switching Protocol\r\n" . "Upgrade: websocket\r\n" . "Sec-WebSocket-Version: 13\r\n" . "Connection: Upgrade\r\n" @@ -411,8 +412,9 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): return 0; } // Bad websocket handshake request. - $connection->close("HTTP/1.1 200 WebSocket\r\nServer: workerman/" . Worker::VERSION . "\r\n\r\n

WebSocket


workerman/" . Worker::VERSION . "
", - true); + $connection->close( + 'HTTP/1.1 200 OK\r\nServer: ' . Worker::$processTitle . ' ('. Worker::VERSION . ')' + . '\r\n\r\n

WebSocket


'. Worker::$processTitle . '/' . Worker::VERSION . '
', true); return 0; } diff --git a/src/Worker.php b/src/Worker.php index 04fadd0a8..94c710496 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -136,7 +136,7 @@ class Worker public bool $reusePort = false; /** - * Emitted when worker processes start. + * Emitted when worker processes is starting. * * @var ?callable */ @@ -150,7 +150,7 @@ class Worker public $onConnect = null; /** - * Emitted when websocket handshake completed (Only work when protocol is ws). + * Emitted when websocket handshake did complete (Only called when protocol is ws). * * @var ?callable */ @@ -192,14 +192,14 @@ class Worker public $onBufferDrain = null; /** - * Emitted when worker processes stopped. + * Emitted when worker processes has stopped. * * @var ?callable */ public $onWorkerStop = null; /** - * Emitted when worker processes get reload signal. + * Emitted when worker processes receives reload signal. * * @var ?callable */ @@ -215,7 +215,7 @@ class Worker /** * Store all connections of clients. * - * @var array + * @var TcpConnection[] */ public array $connections = []; @@ -542,7 +542,7 @@ class Worker * If $outputStream support decorated * @var bool */ - protected static ?bool $outputDecorated = null; + protected static bool $outputDecorated = false; /** * Worker object's hash id(unique identifier). @@ -647,8 +647,9 @@ protected static function init(): void */ protected static function lock(int $flag = LOCK_EX): void { + global $argv; static $fd; - if (DIRECTORY_SEPARATOR !== '/') { + if (DIRECTORY_SEPARATOR !== '/' | empty($argv)) { return; } $lockFile = static::$pidFile . '.lock'; @@ -882,10 +883,12 @@ public static function getSingleLineTotalLength(): int */ protected static function parseCommand(): void { - if (DIRECTORY_SEPARATOR !== '/') { + global $argv; + + if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; } - global $argv; + // Check argv; $startFile = $argv[0]; $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; @@ -1294,7 +1297,8 @@ public static function resetStd(bool $throwException = true): void */ protected static function saveMasterPid(): void { - if (DIRECTORY_SEPARATOR !== '/') { + global $argv; + if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; } @@ -2153,17 +2157,18 @@ protected static function getErrorType(int $type): string return self::ERROR_TYPE[$type] ?? ''; } - /** - * Log. - * - * @param mixed $msg - * @return void - */ - public static function log(mixed $msg): void + /** + * Log. + * + * @param mixed $msg + * @param bool $decorated + * @return void + */ + public static function log(mixed $msg,bool $decorated = false): void { $msg = $msg . "\n"; if (!static::$daemonize) { - static::safeEcho($msg); + static::safeEcho($msg, $decorated); } file_put_contents(static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' . (DIRECTORY_SEPARATOR === '/' ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); @@ -2181,7 +2186,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool if (!$stream) { return false; } - if (!$decorated) { + if ($decorated) { $line = $white = $green = $end = ''; if (static::$outputDecorated) { $line = "\033[1A\n\033[K"; From 68c632b418c12ca4117fdba0929ca6e7ae3c61ca Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Mar 2023 11:08:02 +0800 Subject: [PATCH 0855/1216] fix typos --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 94c710496..0e72c31f8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -649,7 +649,7 @@ protected static function lock(int $flag = LOCK_EX): void { global $argv; static $fd; - if (DIRECTORY_SEPARATOR !== '/' | empty($argv)) { + if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; } $lockFile = static::$pidFile . '.lock'; From cd2392f65bf65f98e118b47c6b2e7e09e2fd0593 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Mar 2023 11:45:09 +0800 Subject: [PATCH 0856/1216] Improve performance with explicit namespaces --- src/Connection/AsyncTcpConnection.php | 22 ++++++++++++ src/Connection/AsyncUdpConnection.php | 12 +++++++ src/Connection/TcpConnection.php | 28 +++++++++++++++ src/Connection/UdpConnection.php | 7 ++++ src/Events/Event.php | 2 ++ src/Events/Revolt.php | 3 ++ src/Protocols/Frame.php | 5 +++ src/Protocols/Http.php | 19 ++++++++++ src/Protocols/Http/Chunk.php | 3 ++ src/Protocols/Http/Request.php | 24 +++++++++++++ src/Protocols/Http/Response.php | 15 ++++++++ src/Protocols/Http/ServerSentEvents.php | 2 ++ src/Protocols/Http/Session.php | 9 +++++ .../Http/Session/FileSessionHandler.php | 15 ++++++++ src/Protocols/Text.php | 3 ++ src/Protocols/Websocket.php | 15 ++++++++ src/Protocols/Ws.php | 16 +++++++++ src/Timer.php | 7 ++++ src/Worker.php | 35 +++++++++++-------- 19 files changed, 228 insertions(+), 14 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 5cdfdf4d1..cbfea6c01 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -22,6 +22,28 @@ use Throwable; use Workerman\Timer; use Workerman\Worker; +use function class_exists; +use function explode; +use function function_exists; +use function is_resource; +use function method_exists; +use function microtime; +use function parse_url; +use function socket_import_stream; +use function socket_set_option; +use function stream_context_create; +use function stream_set_blocking; +use function stream_set_read_buffer; +use function stream_socket_client; +use function stream_socket_get_name; +use function ucfirst; +use const DIRECTORY_SEPARATOR; +use const PHP_INT_MAX; +use const SO_KEEPALIVE; +use const SOL_SOCKET; +use const SOL_TCP; +use const STREAM_CLIENT_ASYNC_CONNECT; +use const TCP_NODELAY; /** * AsyncTcpConnection. diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 3cd684dae..294eb1280 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -20,6 +20,18 @@ use Throwable; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; +use function class_exists; +use function explode; +use function fclose; +use function stream_context_create; +use function stream_set_blocking; +use function stream_socket_client; +use function stream_socket_recvfrom; +use function stream_socket_sendto; +use function strlen; +use function substr; +use function ucfirst; +use const STREAM_CLIENT_CONNECT; /** * AsyncUdpConnection. diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 9b756f086..c18482e6a 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -23,6 +23,34 @@ use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; +use function ceil; +use function count; +use function fclose; +use function feof; +use function fread; +use function function_exists; +use function fwrite; +use function is_object; +use function is_resource; +use function key; +use function method_exists; +use function posix_getpid; +use function restore_error_handler; +use function set_error_handler; +use function stream_set_blocking; +use function stream_set_read_buffer; +use function stream_socket_enable_crypto; +use function stream_socket_get_name; +use function strlen; +use function strrchr; +use function strrpos; +use function substr; +use function var_export; +use const PHP_INT_MAX; +use const STREAM_CRYPTO_METHOD_SSLv23_CLIENT; +use const STREAM_CRYPTO_METHOD_SSLv23_SERVER; +use const STREAM_CRYPTO_METHOD_SSLv2_CLIENT; +use const STREAM_CRYPTO_METHOD_SSLv2_SERVER; /** * TcpConnection. diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index e43d6838d..8dd36819f 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -20,6 +20,13 @@ use JetBrains\PhpStorm\Pure; use JsonSerializable; use Workerman\Protocols\ProtocolInterface; +use function stream_socket_get_name; +use function stream_socket_sendto; +use function strlen; +use function strrchr; +use function strrpos; +use function substr; +use function trim; /** * UdpConnection. diff --git a/src/Events/Event.php b/src/Events/Event.php index b39f2d41e..fa272ce25 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -19,6 +19,8 @@ use EventBase; use RuntimeException; use Throwable; +use function class_exists; +use function count; /** * libevent eventloop diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 64661aa89..fdd75bf47 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -18,6 +18,9 @@ use Revolt\EventLoop; use Revolt\EventLoop\Driver; +use function count; +use function function_exists; +use function pcntl_signal; /** * Revolt eventloop diff --git a/src/Protocols/Frame.php b/src/Protocols/Frame.php index 82cedc820..c8ce71c52 100644 --- a/src/Protocols/Frame.php +++ b/src/Protocols/Frame.php @@ -16,6 +16,11 @@ namespace Workerman\Protocols; +use function pack; +use function strlen; +use function substr; +use function unpack; + /** * Frame Protocol. */ diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 4a36459c5..46cb01dfa 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -20,6 +20,25 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; +use function clearstatcache; +use function count; +use function explode; +use function filesize; +use function fopen; +use function fread; +use function fseek; +use function ftell; +use function in_array; +use function ini_get; +use function is_array; +use function is_object; +use function key; +use function preg_match; +use function strlen; +use function strpos; +use function strstr; +use function substr; +use function sys_get_temp_dir; /** * Class Http. diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 8c900ac02..619d622c9 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -16,6 +16,9 @@ namespace Workerman\Protocols\Http; +use function dechex; +use function strlen; + /** * Class Chunk * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 45f70eee8..8324226d0 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -20,6 +20,30 @@ use RuntimeException; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; +use function array_walk_recursive; +use function bin2hex; +use function clearstatcache; +use function count; +use function explode; +use function file_put_contents; +use function is_file; +use function json_decode; +use function ltrim; +use function microtime; +use function pack; +use function parse_str; +use function parse_url; +use function preg_match; +use function preg_replace; +use function strlen; +use function strpos; +use function strstr; +use function strtolower; +use function substr; +use function tempnam; +use function trim; +use function unlink; +use function urlencode; /** * Class Request diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 2772fdd2c..907c5e914 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -16,6 +16,21 @@ namespace Workerman\Protocols\Http; +use function array_merge_recursive; +use function explode; +use function file; +use function filemtime; +use function gmdate; +use function is_array; +use function is_file; +use function pathinfo; +use function preg_match; +use function rawurlencode; +use function strlen; +use function substr; +use const FILE_IGNORE_NEW_LINES; +use const FILE_SKIP_EMPTY_LINES; + /** * Class Response * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index fd73379ea..28eaf6ca7 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -16,6 +16,8 @@ namespace Workerman\Protocols\Http; +use function str_replace; + /** * Class ServerSentEvents * @package Workerman\Protocols\Http diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 634b7ebef..8c0071d9f 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -21,6 +21,15 @@ use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; +use function array_key_exists; +use function ini_get; +use function is_array; +use function is_scalar; +use function preg_match; +use function random_int; +use function serialize; +use function session_get_cookie_params; +use function unserialize; /** * Class Session diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index d9d36a0dc..aea6d06e7 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -18,6 +18,21 @@ use Exception; use Workerman\Protocols\Http\Session; +use function clearstatcache; +use function file_get_contents; +use function file_put_contents; +use function filemtime; +use function glob; +use function is_dir; +use function is_file; +use function mkdir; +use function rename; +use function session_save_path; +use function strlen; +use function sys_get_temp_dir; +use function time; +use function touch; +use function unlink; /** * Class FileSessionHandler diff --git a/src/Protocols/Text.php b/src/Protocols/Text.php index 64e1ad7ea..df32ebe41 100644 --- a/src/Protocols/Text.php +++ b/src/Protocols/Text.php @@ -17,6 +17,9 @@ namespace Workerman\Protocols; use Workerman\Connection\ConnectionInterface; +use function rtrim; +use function strlen; +use function strpos; /** * Text Protocol. diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 5546e84d9..2d09ab07c 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -22,6 +22,21 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Worker; +use function base64_encode; +use function chr; +use function floor; +use function gettype; +use function is_scalar; +use function ord; +use function pack; +use function preg_match; +use function sha1; +use function str_repeat; +use function stripos; +use function strlen; +use function strpos; +use function substr; +use function unpack; /** * WebSocket protocol. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index bd701abd5..7f8ca03f2 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -22,6 +22,22 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Timer; use Workerman\Worker; +use function base64_encode; +use function bin2hex; +use function floor; +use function gettype; +use function is_array; +use function is_scalar; +use function ord; +use function pack; +use function preg_match; +use function sha1; +use function str_repeat; +use function strlen; +use function strpos; +use function substr; +use function trim; +use function unpack; /** * Websocket protocol for client. diff --git a/src/Timer.php b/src/Timer.php index b9aafad4e..9a8738bbd 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -22,6 +22,13 @@ use Workerman\Events\Revolt; use Workerman\Events\Swoole; use Workerman\Events\Swow; +use function function_exists; +use function is_callable; +use function pcntl_alarm; +use function pcntl_signal; +use function time; +use const PHP_INT_MAX; +use const SIGALRM; /** * Timer. diff --git a/src/Worker.php b/src/Worker.php index 0e72c31f8..552ad1c0f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -18,6 +18,7 @@ use AllowDynamicProperties; use Exception; +use Revolt\EventLoop; use RuntimeException; use stdClass; use Throwable; @@ -29,6 +30,12 @@ use Workerman\Events\Revolt; use Workerman\Events\Select; use Workerman\Protocols\ProtocolInterface; +use function method_exists; +use function restore_error_handler; +use function set_error_handler; +use function stream_socket_accept; +use function stream_socket_recvfrom; +use function substr; /** * Worker class @@ -647,7 +654,7 @@ protected static function init(): void */ protected static function lock(int $flag = LOCK_EX): void { - global $argv; + global $argv; static $fd; if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; @@ -883,7 +890,7 @@ public static function getSingleLineTotalLength(): int */ protected static function parseCommand(): void { - global $argv; + global $argv; if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; @@ -1297,7 +1304,7 @@ public static function resetStd(bool $throwException = true): void */ protected static function saveMasterPid(): void { - global $argv; + global $argv; if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { return; } @@ -1319,7 +1326,7 @@ protected static function getEventLoopName(): string return static::$eventLoopClass; } - if (class_exists(\Revolt\EventLoop::class)) { + if (class_exists(EventLoop::class)) { static::$eventLoopClass = Revolt::class; return static::$eventLoopClass; } @@ -1495,7 +1502,7 @@ public static function forkOneWorkerForWindows(string $startFile): void ); $pipes = array(); - $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); + $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -2157,14 +2164,14 @@ protected static function getErrorType(int $type): string return self::ERROR_TYPE[$type] ?? ''; } - /** - * Log. - * - * @param mixed $msg - * @param bool $decorated - * @return void - */ - public static function log(mixed $msg,bool $decorated = false): void + /** + * Log. + * + * @param mixed $msg + * @param bool $decorated + * @return void + */ + public static function log(mixed $msg, bool $decorated = false): void { $msg = $msg . "\n"; if (!static::$daemonize) { @@ -2477,7 +2484,7 @@ public function stop(): void } } // Remove worker. - foreach(static::$workers as $key => $one_worker) { + foreach (static::$workers as $key => $one_worker) { if ($one_worker->workerId === $this->workerId) { unset(static::$workers[$key]); } From fc66e2048a782c889aa445e72a8ae21a884330fc Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Mar 2023 11:54:25 +0800 Subject: [PATCH 0857/1216] format --- src/Connection/AsyncTcpConnection.php | 12 ++++++++++++ src/Connection/ConnectionInterface.php | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index cbfea6c01..6897e92cb 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -64,72 +64,84 @@ class AsyncTcpConnection extends TcpConnection 'sslv3' => 'sslv3', 'tls' => 'tls' ]; + /** * Emitted when socket connection is successfully established. * * @var ?callable */ public $onConnect = null; + /** * Emitted when websocket handshake completed (Only work when protocol is ws). * * @var ?callable */ public $onWebSocketConnect = null; + /** * Transport layer protocol. * * @var string */ public string $transport = 'tcp'; + /** * Socks5 proxy. * * @var string */ public string $proxySocks5 = ''; + /** * Http proxy. * * @var string */ public string $proxyHttp = ''; + /** * Status. * * @var int */ protected int $status = self::STATUS_INITIAL; + /** * Remote host. * * @var string */ protected string $remoteHost = ''; + /** * Remote port. * * @var int */ protected int $remotePort = 80; + /** * Connect start time. * * @var float */ protected float $connectStartTime = 0; + /** * Remote URI. * * @var string */ protected string $remoteURI = ''; + /** * Context option. * * @var array */ protected array $socketContext = []; + /** * Reconnect timer. * diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 6b44b53ea..7131c7904 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -20,11 +20,12 @@ use Workerman\Events\Event; use Workerman\Events\EventInterface; use Workerman\Worker; +use AllowDynamicProperties; /** * ConnectionInterface. */ -#[\AllowDynamicProperties] +#[AllowDynamicProperties] abstract class ConnectionInterface { /** From 658c8073980949ef44f8a5e69f875bdcc9188b57 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Mar 2023 12:04:43 +0800 Subject: [PATCH 0858/1216] Fix decorated --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 552ad1c0f..00bce3098 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2193,7 +2193,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool if (!$stream) { return false; } - if ($decorated) { + if (!$decorated) { $line = $white = $green = $end = ''; if (static::$outputDecorated) { $line = "\033[1A\n\033[K"; From 12fa2d4d8cc8be7c58154e90e5b70263cf5e02bc Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 17 Mar 2023 12:40:40 +0800 Subject: [PATCH 0859/1216] Process dispaly 1 on windows --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 00bce3098..f553b8b10 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1450,7 +1450,7 @@ protected static function forkWorkersForWindows(): void restore_error_handler(); // Display UI. - static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad((string)$worker->count, 10) . "[ok]\n"); + static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . "[ok]\n"); $worker->listen(); $worker->run(); static::$globalEvent->run(); From c5e3d918497ff9bfb679f640b5026dee9554d663 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 28 Mar 2023 13:00:15 +0800 Subject: [PATCH 0860/1216] Update Request.php --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 8324226d0..7b189a823 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -188,7 +188,7 @@ public function cookie(string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(string $name = null): ?array + public function file(string $name = null) { if (!isset($this->data['files'])) { $this->parsePost(); From e46753ede4f487b710670a4e323698f7aede3e10 Mon Sep 17 00:00:00 2001 From: logdd Date: Fri, 31 Mar 2023 11:34:49 +0800 Subject: [PATCH 0861/1216] =?UTF-8?q?git=E5=BF=BD=E7=95=A5.vscode=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fbc9bcb68..f5c56bdd2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ logs .idea .DS_Store vendor/ +/.vscode composer.lock From 944e31c1295d1dfb370be14c433fdaaa2041657e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 6 Apr 2023 10:46:43 +0800 Subject: [PATCH 0862/1216] fix Undefined property: stdClass::$streamSending --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index c18482e6a..49f37ffb9 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -761,7 +761,7 @@ public function baseWrite(): void } } if ($this->status === self::STATUS_CLOSING) { - if ($this->context->streamSending) { + if (!empty($this->context->streamSending)) { return; } $this->destroy(); From 1801549e1cf6bf61807b7ffcce49aa85216369d5 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 6 Apr 2023 10:56:48 +0800 Subject: [PATCH 0863/1216] fix #897 --- src/Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 46cb01dfa..9265edf8c 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -124,14 +124,14 @@ public static function input(string $buffer, TcpConnection $connection): int } $header = substr($buffer, 0, $crlfPos); - $hostHeaderPosition = strpos($header, "\r\nHost: "); + $hostHeaderPosition = stripos($header, "\r\nHost: "); if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); return 0; } - if ($pos = strpos($header, "\r\nContent-Length: ")) { + if ($pos = stripos($header, "\r\nContent-Length: ")) { $length = $length + (int)substr($header, $pos + 18, 10); $hasContentLength = true; } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { From a2d7b5bc1ba2e01abcbf24fe78212798956b94b6 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 10 Apr 2023 14:43:31 +0800 Subject: [PATCH 0864/1216] fix total memory --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index f553b8b10..e2b2dab37 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1099,7 +1099,7 @@ protected static function formatStatusData($statisticsFile): string $pid = $pidMath[0]; $dataWaitingSort[$pid] = $value; if (preg_match('/^\S+?\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?(\S+?)\s+?/', $value, $match)) { - $totalMemory += (int)str_ireplace('M', '', $match[1]); + $totalMemory += (float)str_ireplace('M', '', $match[1]); $maxLen1 = max($maxLen1, strlen($match[2])); $maxLen2 = max($maxLen2, strlen($match[3])); $totalConnections += (int)$match[4]; From d6f3225b88c89a4e93d1818c1020e5e7a43c1c39 Mon Sep 17 00:00:00 2001 From: wanglei <317448423@qq.com> Date: Fri, 14 Apr 2023 17:39:24 +0800 Subject: [PATCH 0865/1216] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtype=E8=A2=AB?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Protocols/Http/Request.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 7b189a823..71ea47dd6 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -606,13 +606,13 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } $uploadKey = $fileName; // Parse upload files. - $file = [ + $file = array_merge($file, [ 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, - 'error' => $error, - 'type' => '', - ]; + 'error' => $error + ]); + if (!isset($file['type'])) $file['type'] = ''; break; } // Is post field. else { From 35be62d13eb37fe6f55a729fa1bf33bca30f2f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=9D=A6=E7=B1=B3?= Date: Sat, 15 Apr 2023 04:30:03 +0800 Subject: [PATCH 0866/1216] Fix extheaders. Now multiple extension headers can be added correctly for non-object response. --- src/Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 9265edf8c..293893665 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -212,10 +212,10 @@ public static function encode(mixed $response, TcpConnection $connection): strin foreach ($connection->headers as $name => $value) { if (is_array($value)) { foreach ($value as $item) { - $extHeader = "$name: $item\r\n"; + $extHeader .= "$name: $item\r\n"; } } else { - $extHeader = "$name: $value\r\n"; + $extHeader .= "$name: $value\r\n"; } } $connection->headers = []; From 3f7731a9748b00656c568e53958e431448ada80c Mon Sep 17 00:00:00 2001 From: jhdxr Date: Sat, 15 Apr 2023 03:17:45 +0800 Subject: [PATCH 0867/1216] introduce ptest and mockery for testing --- composer.json | 9 +++++++ phpunit.xml | 18 ++++++++++++++ tests/Feature/ExampleTest.php | 6 +++++ tests/Pest.php | 45 +++++++++++++++++++++++++++++++++++ tests/TestCase.php | 10 ++++++++ 5 files changed, 88 insertions(+) create mode 100644 phpunit.xml create mode 100644 tests/Feature/ExampleTest.php create mode 100644 tests/Pest.php create mode 100644 tests/TestCase.php diff --git a/composer.json b/composer.json index 7637e319d..267aba478 100644 --- a/composer.json +++ b/composer.json @@ -38,5 +38,14 @@ "minimum-stability": "dev", "conflict": { "ext-swow": " + + + + ./tests + + + + + + ./src + + + diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 000000000..782d85721 --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,6 @@ +toBeTrue(); +// expect('3')->toBe(3); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 000000000..5949c6173 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,45 @@ +in('Feature'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function something() +{ + // .. +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 000000000..cfb05b6dd --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ + Date: Sat, 15 Apr 2023 03:18:10 +0800 Subject: [PATCH 0868/1216] test case for Text and Http(WIP) --- tests/Unit/Protocols/HttpTest.php | 27 +++++++++++++++++++++++++++ tests/Unit/Protocols/TextTest.php | 24 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/Unit/Protocols/HttpTest.php create mode 100644 tests/Unit/Protocols/TextTest.php diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php new file mode 100644 index 000000000..e8e008d50 --- /dev/null +++ b/tests/Unit/Protocols/HttpTest.php @@ -0,0 +1,27 @@ +toBe($class::class); + + //restore old request class + Http::requestClass($oldRequestClass); +}); + +it('tests ::encode', function () { + $tcpConnection = Mockery::mock(TcpConnection::class); + +}); + +it('tests ::decode', function () { + +}); \ No newline at end of file diff --git a/tests/Unit/Protocols/TextTest.php b/tests/Unit/Protocols/TextTest.php new file mode 100644 index 000000000..2b1a9f07f --- /dev/null +++ b/tests/Unit/Protocols/TextTest.php @@ -0,0 +1,24 @@ +toBe(0); + //input with "\n" + expect(Text::input("jhdxr\n", $connection)) + ->toBe(6); + + //::encode + expect(Text::encode('jhdxr')) + ->toBe("jhdxr\n"); + + //::decode + expect(Text::decode("jhdxr\n")) + ->toBe('jhdxr'); +}); \ No newline at end of file From 681e373e22a0e11f228899e7b0f70ea891c435c5 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Sat, 15 Apr 2023 03:28:32 +0800 Subject: [PATCH 0869/1216] github action tests --- .github/workflows/test.yml | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..b66e48663 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,47 @@ +name: tests + +on: + push: + branches: + - master + - feature/tests + pull_request: + schedule: + - cron: '0 0 * * *' + +jobs: + linux_tests: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: true + matrix: + php: [8.1, 8.2] + stability: [prefer-lowest, prefer-stable] + + name: PHP ${{ matrix.php }} - ${{ matrix.stability }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: json + ini-values: error_reporting=E_ALL + tools: composer:v2 + coverage: xdebug + + - name: Install dependencies + uses: nick-fields/retry@v2 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress +# command: composer install --prefer-dist --no-interaction --no-progress + + - name: Execute tests + run: vendor/bin/pest --coverage + From 6d36552711fc41f876b6d844d06a08fd11517d4e Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 00:59:28 +0800 Subject: [PATCH 0870/1216] test for Protocols\Http --- tests/Unit/Protocols/HttpTest.php | 102 +++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index e8e008d50..e38adaf68 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -2,13 +2,15 @@ use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; +use Workerman\Protocols\Http\Request; +use Workerman\Protocols\Http\Response; it('customizes request class', function () { //backup old request class $oldRequestClass = Http::requestClass(); //actual test - $class = new class{ + $class = new class { }; Http::requestClass($class::class); expect(Http::requestClass())->toBe($class::class); @@ -17,11 +19,107 @@ Http::requestClass($oldRequestClass); }); -it('tests ::encode', function () { +it('tests ::input', function () { + $testWithConnectionClose = function (Closure $closure, string $dataContains = null) { + $tcpConnection = Mockery::spy(TcpConnection::class); + $closure($tcpConnection); + if ($dataContains) { + $tcpConnection->shouldHaveReceived('close', function ($actual) use ($dataContains) { + return str_contains($actual, $dataContains); + }); + } else { + $tcpConnection->shouldHaveReceived('close'); + } + }; + + //test 413 payload too large + $testWithConnectionClose(function (TcpConnection $tcpConnection) { + expect(Http::input(str_repeat('jhdxr', 3333), $tcpConnection)) + ->toBe(0); + }, '413 Payload Too Large'); + + //example request from ChatGPT :) + $buffer = "POST /path/to/resource HTTP/1.1\r\n" . + "Host: example.com\r\n" . + "Content-Type: application/json\r\n" . + "Content-Length: 27\r\n" . + "\r\n" . + '{"key": "value", "foo": "bar"}'; + + //unrecognized method + $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + expect(Http::input(str_replace('POST', 'MIAOWU', $buffer), $tcpConnection)) + ->toBe(0); + }, '400 Bad Request'); + + //HTTP 1.1 without Host header + $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + expect(Http::input(str_replace("Host: ", 'NotHost: ', $buffer), $tcpConnection)) + ->toBe(0); + }, '400 Bad Request'); + + //content-length exceeds connection max package size + $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + $tcpConnection->maxPackageSize = 10; + expect(Http::input($buffer, $tcpConnection)) + ->toBe(0); + }, '413 Payload Too Large'); +}); + +it('tests ::encode for non-object response', function () { $tcpConnection = Mockery::mock(TcpConnection::class); + $tcpConnection->headers = [ + 'foo' => 'bar', + 'jhdxr' => ['a', 'b'], + ]; + $extHeader = "foo: bar\r\n" . + "jhdxr: a\r\n" . + "jhdxr: b\r\n"; + expect(Http::encode('xiami', $tcpConnection)) + ->toBe("HTTP/1.1 200 OK\r\n" . + "Server: workerman\r\n" . + "{$extHeader}Connection: keep-alive\r\n" . + "Content-Type: text/html;charset=utf-8\r\n" . + "Content-Length: 5\r\n\r\nxiami"); +}); + +it('tests ::encode for ' . Response::class, function () { + $tcpConnection = Mockery::mock(TcpConnection::class); + $tcpConnection->headers = [ + 'foo' => 'bar', + 'jhdxr' => ['a', 'b'], + ]; + $extHeader = "foo: bar\r\n" . + "jhdxr: a\r\n" . + "jhdxr: b\r\n"; + + $response = new Response(body: 'xiami'); + + expect(Http::encode($response, $tcpConnection)) + ->toBe("HTTP/1.1 200 OK\r\n" . + "Server: workerman\r\n" . + "{$extHeader}Connection: keep-alive\r\n" . + "Content-Type: text/html;charset=utf-8\r\n" . + "Content-Length: 5\r\n\r\nxiami"); }); it('tests ::decode', function () { + $tcpConnection = Mockery::mock(TcpConnection::class); + + //example request from ChatGPT :) + $buffer = "POST /path/to/resource HTTP/1.1\r\n" . + "Host: example.com\r\n" . + "Content-Type: application/json\r\n" . + "Content-Length: 27\r\n" . + "\r\n" . + '{"key": "value", "foo": "bar"}'; + + $value = expect(Http::decode($buffer, $tcpConnection)) + ->toBeInstanceOf(Request::class) + ->value; + //test cache + expect($value == Http::decode($buffer, $tcpConnection)) + ->toBeTrue(); }); \ No newline at end of file From 79f59578f82793381599ab13737aa35428f29b21 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 01:10:06 +0800 Subject: [PATCH 0871/1216] complete TextTest: add test for ::input with buffer exeeeds max package length --- tests/Pest.php | 15 +++++++++++++++ tests/Unit/Protocols/HttpTest.php | 20 ++++---------------- tests/Unit/Protocols/TextTest.php | 6 ++++++ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/tests/Pest.php b/tests/Pest.php index 5949c6173..76e00132b 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -24,6 +24,8 @@ | */ +use Workerman\Connection\TcpConnection; + expect()->extend('toBeOne', function () { return $this->toBe(1); }); @@ -43,3 +45,16 @@ function something() { // .. } + +function testWithConnectionClose(Closure $closure, string $dataContains = null, $connectionClass = TcpConnection::class): void +{ + $tcpConnection = Mockery::spy($connectionClass); + $closure($tcpConnection); + if ($dataContains) { + $tcpConnection->shouldHaveReceived('close', function ($actual) use ($dataContains) { + return str_contains($actual, $dataContains); + }); + } else { + $tcpConnection->shouldHaveReceived('close'); + } +} \ No newline at end of file diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index e38adaf68..e34d833cf 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -20,20 +20,8 @@ }); it('tests ::input', function () { - $testWithConnectionClose = function (Closure $closure, string $dataContains = null) { - $tcpConnection = Mockery::spy(TcpConnection::class); - $closure($tcpConnection); - if ($dataContains) { - $tcpConnection->shouldHaveReceived('close', function ($actual) use ($dataContains) { - return str_contains($actual, $dataContains); - }); - } else { - $tcpConnection->shouldHaveReceived('close'); - } - }; - //test 413 payload too large - $testWithConnectionClose(function (TcpConnection $tcpConnection) { + testWithConnectionClose(function (TcpConnection $tcpConnection) { expect(Http::input(str_repeat('jhdxr', 3333), $tcpConnection)) ->toBe(0); }, '413 Payload Too Large'); @@ -47,19 +35,19 @@ '{"key": "value", "foo": "bar"}'; //unrecognized method - $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input(str_replace('POST', 'MIAOWU', $buffer), $tcpConnection)) ->toBe(0); }, '400 Bad Request'); //HTTP 1.1 without Host header - $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input(str_replace("Host: ", 'NotHost: ', $buffer), $tcpConnection)) ->toBe(0); }, '400 Bad Request'); //content-length exceeds connection max package size - $testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { $tcpConnection->maxPackageSize = 10; expect(Http::input($buffer, $tcpConnection)) ->toBe(0); diff --git a/tests/Unit/Protocols/TextTest.php b/tests/Unit/Protocols/TextTest.php index 2b1a9f07f..c3b4157d1 100644 --- a/tests/Unit/Protocols/TextTest.php +++ b/tests/Unit/Protocols/TextTest.php @@ -7,6 +7,12 @@ $connection = Mockery::mock(ConnectionInterface::class); //::input + //input too long + testWithConnectionClose(function ($connection) { + $connection->maxPackageSize = 5; + expect(Text::input('abcdefgh', $connection)) + ->toBe(0); + }); //input without "\n" expect(Text::input('jhdxr', $connection)) ->toBe(0); From cdab4736909f4b666fe3a672432900a037082a39 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 01:18:44 +0800 Subject: [PATCH 0872/1216] test for Protocols\Frame --- tests/Unit/Protocols/FrameTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/Unit/Protocols/FrameTest.php diff --git a/tests/Unit/Protocols/FrameTest.php b/tests/Unit/Protocols/FrameTest.php new file mode 100644 index 000000000..7978729ca --- /dev/null +++ b/tests/Unit/Protocols/FrameTest.php @@ -0,0 +1,20 @@ +toBe(0); + expect(Frame::input("\0\0\0*foobar")) + ->toBe(42); +}); + +it('tests ::decode', function () { + $buffer = pack('N', 5) . 'jhdxr'; + expect(Frame::decode($buffer)) + ->toBe('jhdxr'); +}); + +it('tests ::encode', function () { + expect(Frame::encode('jhdxr')) + ->toBe(pack('N', 9) . 'jhdxr'); +}); \ No newline at end of file From 8f97226fedcc5d6e7a6993c063ff387721460d37 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 01:22:56 +0800 Subject: [PATCH 0873/1216] test for Protocols\Http\ServerSentEvents --- .../Unit/Protocols/Http/ServerSentEventsTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/Unit/Protocols/Http/ServerSentEventsTest.php diff --git a/tests/Unit/Protocols/Http/ServerSentEventsTest.php b/tests/Unit/Protocols/Http/ServerSentEventsTest.php new file mode 100644 index 000000000..9c692d827 --- /dev/null +++ b/tests/Unit/Protocols/Http/ServerSentEventsTest.php @@ -0,0 +1,15 @@ + 'ping', + 'data' => 'some thing', + 'id' => 1000, + 'retry' => 5000, + ]; + $sse = new ServerSentEvents($data); + $expected = "event: {$data['event']}\ndata: {$data['data']}\n\nid: {$data['id']}\nretry: {$data['retry']}\n"; + expect((string)$sse)->toBe($expected); +}); \ No newline at end of file From 90509b162f137044ad302f126d923a3444da5aca Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 02:01:09 +0800 Subject: [PATCH 0874/1216] test for Http/Response --- tests/Unit/Protocols/Http/ResponseTest.php | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/Unit/Protocols/Http/ResponseTest.php diff --git a/tests/Unit/Protocols/Http/ResponseTest.php b/tests/Unit/Protocols/Http/ResponseTest.php new file mode 100644 index 000000000..32bba425d --- /dev/null +++ b/tests/Unit/Protocols/Http/ResponseTest.php @@ -0,0 +1,57 @@ + 'bar'], 'hello, xiami'); + + expect($response->getStatusCode())->toBe(201); + expect($response->getHeaders())->toBe(['X-foo' => 'bar']); + expect($response->rawBody())->toBe('hello, xiami'); + + //headers + $response->header('abc', '123'); + $response->withHeader('X-foo', 'baz'); + $response->withHeaders(['def' => '456']); + expect((string)$response) + ->toContain('X-foo: baz') + ->toContain('abc: 123') + ->toContain('def: 456'); + $response->withoutHeader('def'); + expect((string)$response)->not->toContain('def: 456'); + expect($response->getHeader('abc')) + ->toBe('123'); + + $response->withStatus(202, 'some reason'); + expect($response->getReasonPhrase())->toBe('some reason'); + + $response->withProtocolVersion('1.0'); + $response->withBody('hello, world'); + expect((string)$response) + ->toContain('HTTP/1.0') + ->toContain('hello, world') + ->toContain('Content-Type: ') + ->toContain('Content-Length: 12') + ->not()->toContain('Transfer-Encoding: '); + + + //cookie + $response->cookie('foo', 'bar', httpOnly: true, domain: 'xia.moe'); + expect((string)$response) + ->toContain('Set-Cookie: foo=bar; Domain=xia.moe; HttpOnly'); +}); + +it('tests file', function (){ + //todo may have to redo the simple test, + // as the implementation of headers is a different function for files. + // or actually maybe the Response is the one should be rewritten to reuse? + $response = new Response(); + $tmpFile = tempnam(sys_get_temp_dir(), 'test'); + rename($tmpFile, $tmpFile .'.jpg'); + $tmpFile .= '.jpg'; + file_put_contents($tmpFile, 'hello, xiami'); + $response->withFile($tmpFile, 0, 12); + expect((string)$response) + ->toContain('Content-Type: image/jpeg') + ->toContain('Last-Modified: '); +}); \ No newline at end of file From e3b87615d196b28128abc1a32fbbe18c66e604d8 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 02:29:14 +0800 Subject: [PATCH 0875/1216] feature test: udp connection --- tests/Feature/UdpConnectionTest.php | 32 +++++++++++++++++++++ tests/Pest.php | 5 ++++ tests/Unit/Connection/UdpConnectionTest.php | 5 ++++ 3 files changed, 42 insertions(+) create mode 100644 tests/Feature/UdpConnectionTest.php create mode 100644 tests/Unit/Connection/UdpConnectionTest.php diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php new file mode 100644 index 000000000..1e977b77d --- /dev/null +++ b/tests/Feature/UdpConnectionTest.php @@ -0,0 +1,32 @@ +onMessage = function ($connection, $data) { + expect($data)->toBe('hello'); + $connection->send('xiami'); + }; + $server->onWorkerStart = function () { + //client + Timer::add(1, function () { + $client = new AsyncUdpConnection('udp://127.0.0.1:1234'); + $client->onConnect = function ($client) { + $client->send('hello'); + }; + $client->onMessage = function ($client, $data) { + expect($data)->toBe('xiami'); + //terminal this test + terminate_current_test(); + }; + $client->connect(); + }, null, false); + }; + Worker::runAll(); +}) + //require posix, multiple workers + ->skip(PHP_OS_FAMILY === 'Windows', 'necessary features are not supported on Windows'); diff --git a/tests/Pest.php b/tests/Pest.php index 76e00132b..29b3182a7 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -57,4 +57,9 @@ function testWithConnectionClose(Closure $closure, string $dataContains = null, } else { $tcpConnection->shouldHaveReceived('close'); } +} + +function terminate_current_test() +{ + posix_kill(posix_getppid(), SIGINT); } \ No newline at end of file diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php new file mode 100644 index 000000000..f5cab3d6c --- /dev/null +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -0,0 +1,5 @@ + Date: Mon, 17 Apr 2023 02:58:13 +0800 Subject: [PATCH 0876/1216] skip test until pest can run in isolated process --- tests/Feature/UdpConnectionTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 1e977b77d..b858c0f95 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -27,6 +27,5 @@ }, null, false); }; Worker::runAll(); -}) - //require posix, multiple workers - ->skip(PHP_OS_FAMILY === 'Windows', 'necessary features are not supported on Windows'); +})->skipOnWindows() //require posix, multiple workers +->skip(message: 'this test needs to run isolated process while pest not support doing so yet'); \ No newline at end of file From 098c8b6951660c76835b1907400b31e0f9c1696b Mon Sep 17 00:00:00 2001 From: jhdxr Date: Mon, 17 Apr 2023 04:50:22 +0800 Subject: [PATCH 0877/1216] UdpConnection test --- tests/Unit/Connection/UdpConnectionTest.php | 41 ++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index f5cab3d6c..ea05ea1c4 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -1,5 +1,44 @@ start(); + +it('tests ' . UdpConnection::class, function () use ($remoteAddress) { + + $socketClient = stream_socket_client("udp://$remoteAddress"); + $udpConnection = new UdpConnection($socketClient, $remoteAddress); + $udpConnection->protocol = \Workerman\Protocols\Text::class; + expect($udpConnection->send('foo'))->toBeTrue(); + + expect($udpConnection->getRemoteIp())->toBe('::1'); + expect($udpConnection->getRemotePort())->toBe(12345); + expect($udpConnection->getRemoteAddress())->toBe($remoteAddress); + expect($udpConnection->getLocalIp())->toBeIn(['::1', '[::1]', '127.0.0.1']); + expect($udpConnection->getLocalPort())->toBeInt(); + + expect(json_encode($udpConnection))->toBeJson() + ->toContain('transport') + ->toContain('getRemoteIp') + ->toContain('remotePort') + ->toContain('getRemoteAddress') + ->toContain('getLocalIp') + ->toContain('getLocalPort') + ->toContain('isIpV4') + ->toContain('isIpV6'); + + $udpConnection->close('bye'); + if (is_resource($socketClient)) { + fclose($socketClient); + } }); \ No newline at end of file From f0994fb9841907ea7f7c8d597f72f914a75339c0 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 17 Apr 2023 11:46:34 +0800 Subject: [PATCH 0878/1216] remove server version --- src/Protocols/Websocket.php | 8 +++----- src/Worker.php | 15 ++++----------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 2d09ab07c..b3009d5f1 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -360,8 +360,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $SecWebSocketKey = $match[1]; } else { $connection->close( - 'HTTP/1.1 200 OK\r\nServer: '. Worker::$processTitle . ' ('. Worker::VERSION . ')' - . '\r\n\r\n

WebSocket


'. Worker::$processTitle . '/' . Worker::VERSION . '
', true); + "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); return 0; } // Calculation websocket key. @@ -408,7 +407,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } } if (!$hasServerHeader) { - $handshakeMessage .= 'Server: ' . Worker::$processTitle . ' ('. Worker::VERSION . ')' . "\r\n"; + $handshakeMessage .= "Server: workerman\r\n"; } $handshakeMessage .= "\r\n"; // Send handshake response. @@ -428,8 +427,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } // Bad websocket handshake request. $connection->close( - 'HTTP/1.1 200 OK\r\nServer: ' . Worker::$processTitle . ' ('. Worker::VERSION . ')' - . '\r\n\r\n

WebSocket


'. Worker::$processTitle . '/' . Worker::VERSION . '
', true); + "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); return 0; } diff --git a/src/Worker.php b/src/Worker.php index e2b2dab37..0b8095338 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -316,13 +316,6 @@ class Worker */ public static string $eventLoopClass = ''; - /** - * Process title - * - * @var string - */ - public static string $processTitle = 'WorkerMan'; - /** * After sending the stop command to the child process stopTimeout seconds, * if the process is still living then forced to kill. @@ -637,7 +630,7 @@ protected static function init(): void static::$globalStatistics['start_timestamp'] = time(); // Process title. - static::setProcessTitle(static::$processTitle . ': master process start_file=' . static::$startFile); + static::setProcessTitle('WorkerMan: master process start_file=' . static::$startFile); // Init data for worker id. static::initId(); @@ -1594,7 +1587,7 @@ protected static function forkOneWorkerForLinux(self $worker): void restore_error_handler(); - static::setProcessTitle(self::$processTitle . ': worker process ' . $worker->name . ' ' . $worker->getSocketName()); + static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); @@ -2608,7 +2601,7 @@ protected static function checkMasterIsAlive(int $masterPid): bool } $cmdline = "/proc/$masterPid/cmdline"; - if (!is_readable($cmdline) || empty(static::$processTitle)) { + if (!is_readable($cmdline)) { return true; } @@ -2617,7 +2610,7 @@ protected static function checkMasterIsAlive(int $masterPid): bool return true; } - return stripos($content, static::$processTitle) !== false || stripos($content, 'php') !== false; + return stripos($content, 'WorkerMan') !== false || stripos($content, 'php') !== false; } } From 5935ff5a940a2f8765c9c5ff67d0d90349c01092 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Thu, 20 Apr 2023 18:38:57 +0800 Subject: [PATCH 0879/1216] install posix & pcntl --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b66e48663..b6b8355ff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,7 @@ on: branches: - master - feature/tests + - feature/feature-tests pull_request: schedule: - cron: '0 0 * * *' @@ -29,7 +30,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: json + extensions: json, posix, pcntl ini-values: error_reporting=E_ALL tools: composer:v2 coverage: xdebug From f087ebb205cd7da32911ddba1d1ea17862f48ac0 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Thu, 20 Apr 2023 18:00:48 +0800 Subject: [PATCH 0880/1216] udp connection test --- tests/Feature/UdpConnectionTest.php | 71 +++++++++++++++++------------ tests/Pest.php | 2 +- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index b858c0f95..89f349012 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -1,31 +1,46 @@ onMessage = function ($connection, $data) { - expect($data)->toBe('hello'); - $connection->send('xiami'); - }; - $server->onWorkerStart = function () { - //client - Timer::add(1, function () { - $client = new AsyncUdpConnection('udp://127.0.0.1:1234'); - $client->onConnect = function ($client) { - $client->send('hello'); - }; - $client->onMessage = function ($client, $data) { - expect($data)->toBe('xiami'); - //terminal this test - terminate_current_test(); - }; - $client->connect(); - }, null, false); - }; - Worker::runAll(); -})->skipOnWindows() //require posix, multiple workers -->skip(message: 'this test needs to run isolated process while pest not support doing so yet'); \ No newline at end of file +$serverAddress = 'udp://127.0.0.1:6789'; +beforeAll(function () use ($serverAddress) { + $process = new PhpProcess(<<onMessage = function (\$connection, \$data) { + if(str_starts_with(\$data, 'bye')) { + terminate_current_process(); + } + \$connection->send('received: '.\$data); + }; + global \$argv; + \$argv = ['', 'start']; + Worker::runAll(); + PHP + ); + $process->start(); + sleep(5); +}); + +afterAll(function () use ($serverAddress) { + $socket = stream_socket_client(self::$serverAddress, timeout: 1); + fwrite($socket, 'bye'); + fclose($socket); +}); + +it('tests udp connection', function () use ($serverAddress) { + $socket = stream_socket_client($serverAddress, $errno, $errstr, 1); + expect($errno)->toBeInt(0); + fwrite($socket, 'xiami'); + $data = fread($socket, 1024); + expect($data)->toBeString('received: xiami'); + fclose($socket); +}) + ->skipOnWindows(); //require posix diff --git a/tests/Pest.php b/tests/Pest.php index 29b3182a7..ff027c86c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -59,7 +59,7 @@ function testWithConnectionClose(Closure $closure, string $dataContains = null, } } -function terminate_current_test() +function terminate_current_process() { posix_kill(posix_getppid(), SIGINT); } \ No newline at end of file From 36bda0fa84c760c1ed6076a2d473d66222fea697 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Apr 2023 16:30:48 +0800 Subject: [PATCH 0881/1216] Remove unnecessary $argv --- src/Worker.php | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 0b8095338..6e381fbd8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -49,7 +49,7 @@ class Worker * * @var string */ - public const VERSION = '5.0.0-beta.3'; + public const VERSION = '5.0.0-beta.5'; /** * Status starting. @@ -647,9 +647,8 @@ protected static function init(): void */ protected static function lock(int $flag = LOCK_EX): void { - global $argv; static $fd; - if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { + if (DIRECTORY_SEPARATOR !== '/') { return; } $lockFile = static::$pidFile . '.lock'; @@ -827,9 +826,7 @@ protected static function displayUI(): void !empty($content) && static::safeEcho($lineLast); if (static::$daemonize) { - global $argv; - $startFile = $argv[0]; - static::safeEcho('Input "php ' . $startFile . ' stop" to stop. Start success.' . "\n\n"); + static::safeEcho('Input "php ' . basename(static::$startFile) . ' stop" to stop. Start success.' . "\n\n"); } else { static::safeEcho("Press Ctrl+C to stop. Start success.\n"); } @@ -883,14 +880,12 @@ public static function getSingleLineTotalLength(): int */ protected static function parseCommand(): void { - global $argv; - - if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { + if (DIRECTORY_SEPARATOR !== '/') { return; } // Check argv; - $startFile = $argv[0]; + $startFile = basename(static::$startFile); $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; $availableCommands = [ 'start', @@ -906,9 +901,10 @@ protected static function parseCommand(): void ]; $command = $mode = ''; foreach (static::getArgv() as $value) { - if (in_array($value, $availableCommands)) { + if (!$command && in_array($value, $availableCommands)) { $command = $value; - } elseif (in_array($value, $availableMode)) { + } + if (!$mode && in_array($value, $availableMode)) { $mode = $value; } } @@ -1046,7 +1042,7 @@ protected static function parseCommand(): void public static function getArgv(): array { global $argv; - return isset($argv[1]) ? $argv : (static::$command ? explode(' ', static::$command) : $argv); + return static::$command ? array_merge($argv, explode(' ', static::$command)) : $argv; } /** @@ -1297,8 +1293,7 @@ public static function resetStd(bool $throwException = true): void */ protected static function saveMasterPid(): void { - global $argv; - if (DIRECTORY_SEPARATOR !== '/' || empty($argv)) { + if (DIRECTORY_SEPARATOR !== '/') { return; } From ca4bcaf0bda4ee997c100f619326f6df6d487558 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Apr 2023 16:39:53 +0800 Subject: [PATCH 0882/1216] Use Worker::$command instead of $argv Refer https://github.com/walkor/workerman/pull/907 --- tests/Feature/UdpConnectionTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 89f349012..a6e362108 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -20,8 +20,7 @@ } \$connection->send('received: '.\$data); }; - global \$argv; - \$argv = ['', 'start']; + Worker::$command = 'start'; Worker::runAll(); PHP ); From 44622912790d69596440ebc56d388df8173e4459 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 21 Apr 2023 18:50:21 +0800 Subject: [PATCH 0883/1216] Update UdpConnectionTest.php --- tests/Feature/UdpConnectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index a6e362108..232803407 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -20,7 +20,7 @@ } \$connection->send('received: '.\$data); }; - Worker::$command = 'start'; + Worker::\$command = 'start'; Worker::runAll(); PHP ); From f3eec6fd7d1d9c6fcd81f59fb6114c1de29b70ed Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 28 Apr 2023 13:10:42 +0800 Subject: [PATCH 0884/1216] Fix the SSE response data format --- src/Protocols/Http/ServerSentEvents.php | 10 +++++----- tests/Unit/Protocols/Http/ServerSentEventsTest.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index 28eaf6ca7..e740be9a2 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -55,15 +55,15 @@ public function __toString() if (isset($data['event'])) { $buffer .= "event: {$data['event']}\n"; } - if (isset($data['data'])) { - $buffer .= 'data: ' . str_replace("\n", "\ndata: ", $data['data']) . "\n\n"; - } if (isset($data['id'])) { $buffer .= "id: {$data['id']}\n"; } if (isset($data['retry'])) { $buffer .= "retry: {$data['retry']}\n"; } - return $buffer; + if (isset($data['data'])) { + $buffer .= 'data: ' . str_replace("\n", "\ndata: ", $data['data']) . "\n"; + } + return $buffer . "\n"; } -} \ No newline at end of file +} diff --git a/tests/Unit/Protocols/Http/ServerSentEventsTest.php b/tests/Unit/Protocols/Http/ServerSentEventsTest.php index 9c692d827..494328530 100644 --- a/tests/Unit/Protocols/Http/ServerSentEventsTest.php +++ b/tests/Unit/Protocols/Http/ServerSentEventsTest.php @@ -10,6 +10,6 @@ 'retry' => 5000, ]; $sse = new ServerSentEvents($data); - $expected = "event: {$data['event']}\ndata: {$data['data']}\n\nid: {$data['id']}\nretry: {$data['retry']}\n"; + $expected = "event: {$data['event']}\nid: {$data['id']}\nretry: {$data['retry']}\ndata: {$data['data']}\n\n"; expect((string)$sse)->toBe($expected); -}); \ No newline at end of file +}); From 5c7c71cea5ca58edbe882565817149f32cffc2b9 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 1 May 2023 10:26:15 +0800 Subject: [PATCH 0885/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 6e381fbd8..e31261624 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -49,7 +49,7 @@ class Worker * * @var string */ - public const VERSION = '5.0.0-beta.5'; + public const VERSION = '5.0.0-beta.6'; /** * Status starting. From 7a4aa1ebee3224127a75256ad5b149097695b4ac Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 9 May 2023 11:03:06 +0800 Subject: [PATCH 0886/1216] Optimization chunked --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 907c5e914..9ac250a05 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -468,7 +468,7 @@ public function __toString() if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $bodyLen\r\n\r\n"; } else { - return "$head\r\n" . dechex($bodyLen) . "\r\n$this->body\r\n"; + return $bodyLen ? "$head\r\n" . dechex($bodyLen) . "\r\n{$this->body}\r\n" : "$head\r\n"; } // The whole http package From bc40b225b383313323296a0a855fa7260612e466 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 9 May 2023 16:41:17 +0800 Subject: [PATCH 0887/1216] Style optimizations --- src/Worker.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index e31261624..d0e15beec 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -783,10 +783,10 @@ protected static function displayUI(): void return; } if (DIRECTORY_SEPARATOR !== '/') { - static::safeEcho("----------------------- WORKERMAN -----------------------------\r\n"); - static::safeEcho('Workerman version:' . static::VERSION . ' PHP version:' . PHP_VERSION . "\r\n"); - static::safeEcho("------------------------ WORKERS -------------------------------\r\n"); - static::safeEcho("worker listen processes status\r\n"); + static::safeEcho("---------------------------------------------- WORKERMAN -----------------------------------------------\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); + static::safeEcho("----------------------------------------------- WORKERS ------------------------------------------------\r\n"); + static::safeEcho("worker listen processes status\r\n"); return; } @@ -1438,7 +1438,7 @@ protected static function forkWorkersForWindows(): void restore_error_handler(); // Display UI. - static::safeEcho(str_pad($worker->name, 21) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . "[ok]\n"); + static::safeEcho(str_pad($worker->name, 48) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . " [ok]\n"); $worker->listen(); $worker->run(); static::$globalEvent->run(); From a2a787757feb2cf52a563e3a02a5b95b8819de97 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 May 2023 11:53:49 +0800 Subject: [PATCH 0888/1216] Cookie optimizations --- src/Protocols/Http/Request.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 71ea47dd6..2f7eeb0c5 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -175,6 +175,13 @@ public function cookie(string $name = null, mixed $default = null): mixed if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; parse_str(preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); + foreach ($this->data['cookie'] as $key => $value) { + if ($key[0] ?? '' === '$') { + unset($this->data['cookie'][$key]); + continue; + } + $this->data['cookie'][$key] = trim($value, '"'); + } } if ($name === null) { return $this->data['cookie']; From b299157d739de789e3ef3a46df7d5a3ee1fc1620 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 May 2023 12:04:21 +0800 Subject: [PATCH 0889/1216] Cookie optimizations --- src/Protocols/Http/Request.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 2f7eeb0c5..4ce7f6177 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -176,10 +176,6 @@ public function cookie(string $name = null, mixed $default = null): mixed $this->data['cookie'] = []; parse_str(preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); foreach ($this->data['cookie'] as $key => $value) { - if ($key[0] ?? '' === '$') { - unset($this->data['cookie'][$key]); - continue; - } $this->data['cookie'][$key] = trim($value, '"'); } } From 8dc8414fb284fe66e5893443b829485ce6cecbe2 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 May 2023 14:56:21 +0800 Subject: [PATCH 0890/1216] Cookie optimizations --- src/Protocols/Http/Request.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 4ce7f6177..71ea47dd6 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -175,9 +175,6 @@ public function cookie(string $name = null, mixed $default = null): mixed if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; parse_str(preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); - foreach ($this->data['cookie'] as $key => $value) { - $this->data['cookie'][$key] = trim($value, '"'); - } } if ($name === null) { return $this->data['cookie']; From 75c4a5aad9c27dbcc1f87a750099fac67f162a7e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 May 2023 15:03:07 +0800 Subject: [PATCH 0891/1216] checkSessionId --- src/Protocols/Http/Session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 8c0071d9f..4b2828743 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -439,7 +439,7 @@ public function __destruct() */ protected static function checkSessionId(string $sessionId): void { - if (!preg_match('/^[a-zA-Z0-9]+$/', $sessionId)) { + if (!preg_match('/^[a-zA-Z0-9"]+$/', $sessionId)) { throw new RuntimeException("session_id $sessionId is invalid"); } } From df024f91afb07f041d69cd98977f58994cc4be61 Mon Sep 17 00:00:00 2001 From: Oladoyinbo Vincent <73993087+oladoyinbov@users.noreply.github.com> Date: Mon, 15 May 2023 10:20:20 +0100 Subject: [PATCH 0892/1216] Update composer.json Added some additional info to composer.json --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 267aba478..ad6da6487 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,9 @@ "type": "library", "keywords": [ "event-loop", - "asynchronous" + "asynchronous", + "http", + "framework" ], "homepage": "https://www.workerman.net", "license": "MIT", From be9f39cd47e86e44ff0421463319120008180660 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:23:17 +0200 Subject: [PATCH 0893/1216] merged nested ifs together --- src/Connection/TcpConnection.php | 12 +++++------- src/Protocols/Http.php | 8 +++----- src/Protocols/Http/Request.php | 6 ++---- src/Protocols/Http/Response.php | 6 ++---- src/Protocols/Websocket.php | 12 +++++------- src/Protocols/Ws.php | 12 +++++------- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 49f37ffb9..391ad75c1 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -939,13 +939,11 @@ public function getSocket() */ protected function checkBufferWillFull(): void { - if ($this->maxSendBufferSize <= strlen($this->sendBuffer)) { - if ($this->onBufferFull) { - try { - ($this->onBufferFull)($this); - } catch (Throwable $e) { - $this->error($e); - } + if ($this->maxSendBufferSize <= strlen($this->sendBuffer) && $this->onBufferFull) { + try { + ($this->onBufferFull)($this); + } catch (Throwable $e) { + $this->error($e); } } } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 293893665..d136f77a9 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -145,11 +145,9 @@ public static function input(string $buffer, TcpConnection $connection): int } } - if ($hasContentLength) { - if ($length > $connection->maxPackageSize) { - $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); - return 0; - } + if ($hasContentLength && $length > $connection->maxPackageSize) { + $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); + return 0; } if (!isset($buffer[512])) { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 71ea47dd6..e9f7b5a7c 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -731,10 +731,8 @@ public function __destruct() if (isset($this->data['files'])) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { - if ($key === 'tmp_name') { - if (is_file($value)) { - unlink($value); - } + if ($key === 'tmp_name' && is_file($value)) { + unlink($value); } }); } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 9ac250a05..1e14e0f78 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -414,10 +414,8 @@ protected function createHeadForFile(array $fileInfo): string $head .= "Content-Disposition: attachment; filename=\"$baseName\"\r\n"; } - if (!isset($headers['Last-Modified'])) { - if ($mtime = filemtime($file)) { - $head .= 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; - } + if (!isset($headers['Last-Modified']) && $mtime = filemtime($file)) { + $head .= 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT' . "\r\n"; } return "$head\r\n"; diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index b3009d5f1..51e94700e 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -281,13 +281,11 @@ public static function encode(mixed $buffer, TcpConnection $connection): string } $connection->context->tmpWebsocketData .= $encodeBuffer; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { - if ($connection->onBufferFull) { - try { - ($connection->onBufferFull)($connection); - } catch (Throwable $e) { - Worker::stopAll(250, $e); - } + if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData) && $connection->onBufferFull) { + try { + ($connection->onBufferFull)($connection); + } catch (Throwable $e) { + Worker::stopAll(250, $e); } } // Return empty string. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 7f8ca03f2..cab62f4d2 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -277,13 +277,11 @@ public static function encode(mixed $payload, AsyncTcpConnection $connection): s } $connection->context->tmpWebsocketData = $connection->context->tmpWebsocketData . $frame; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { - if ($connection->onBufferFull) { - try { - ($connection->onBufferFull)($connection); - } catch (Throwable $e) { - Worker::stopAll(250, $e); - } + if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData) && $connection->onBufferFull) { + try { + ($connection->onBufferFull)($connection); + } catch (Throwable $e) { + Worker::stopAll(250, $e); } } return ''; From 627658c5b0a991c6c429a9471c5585796c1e33fb Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:23:28 +0200 Subject: [PATCH 0894/1216] removed redundant return --- src/Protocols/Http.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index d136f77a9..41825db39 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -110,7 +110,6 @@ public static function input(string $buffer, TcpConnection $connection): int // Judge whether the package length exceeds the limit. if (strlen($buffer) >= 16384) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); - return 0; } return 0; } From a1fb67b2e170bd2132d3e80c95129eb2a66833a9 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:25:13 +0200 Subject: [PATCH 0895/1216] array_merge replaced with spread syntax --- src/Protocols/Http/Request.php | 7 +------ src/Worker.php | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index e9f7b5a7c..596203af1 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -606,12 +606,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } $uploadKey = $fileName; // Parse upload files. - $file = array_merge($file, [ - 'name' => $match[2], - 'tmp_name' => $tmpFile, - 'size' => $size, - 'error' => $error - ]); + $file = [...$file, 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error]; if (!isset($file['type'])) $file['type'] = ''; break; } // Is post field. diff --git a/src/Worker.php b/src/Worker.php index d0e15beec..19d91ba18 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1042,7 +1042,7 @@ protected static function parseCommand(): void public static function getArgv(): array { global $argv; - return static::$command ? array_merge($argv, explode(' ', static::$command)) : $argv; + return static::$command ? [...$argv, ...explode(' ', static::$command)] : $argv; } /** @@ -2259,7 +2259,7 @@ public function __construct(string $socketName = null, array $socketContext = [] && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS && strpos($socketName,'unix') !== 0 // if not unix socket && strpos($socketName,'udp') !== 0) { // if not udp socket - + $address = \parse_url($socketName); if (isset($address['host']) && isset($address['port'])) { try { @@ -2608,4 +2608,3 @@ protected static function checkMasterIsAlive(int $masterPid): bool return stripos($content, 'WorkerMan') !== false || stripos($content, 'php') !== false; } } - From 941823b5c55326467989ce47029c96be638a57b8 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:32:25 +0200 Subject: [PATCH 0896/1216] removed unused use statement --- src/Timer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index 9a8738bbd..eac39b33f 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -23,7 +23,6 @@ use Workerman\Events\Swoole; use Workerman\Events\Swow; use function function_exists; -use function is_callable; use function pcntl_alarm; use function pcntl_signal; use function time; From 2e0afcf62102f47505cc4b7cd72f23274c1dba21 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:37:28 +0200 Subject: [PATCH 0897/1216] fixed improper if condition --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 391ad75c1..f8d8ad0b3 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -686,7 +686,7 @@ public function baseRead($socket, bool $checkEof = true): void // The data is enough for a packet. ++self::$statistics['total_request']; // The current packet length is equal to the length of the buffer. - if ($one = strlen($this->recvBuffer) === $this->currentPackageLength) { + if ($one = (strlen($this->recvBuffer) === $this->currentPackageLength)) { $oneRequestBuffer = $this->recvBuffer; $this->recvBuffer = ''; } else { From d8f994b65d1801a271a7f83a7b19cb4f2aef8a92 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:43:45 +0200 Subject: [PATCH 0898/1216] using short list syntax instead of list() --- src/Connection/AsyncTcpConnection.php | 2 +- src/Connection/AsyncUdpConnection.php | 2 +- src/Protocols/Http/Request.php | 4 ++-- src/Worker.php | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 6897e92cb..fcf56bd92 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -160,7 +160,7 @@ public function __construct(string $remoteAddress, array $socketContext = []) { $addressInfo = parse_url($remoteAddress); if (!$addressInfo) { - list($scheme, $this->remoteAddress) = explode(':', $remoteAddress, 2); + [$scheme, $this->remoteAddress] = explode(':', $remoteAddress, 2); if ('unix' === strtolower($scheme)) { $this->remoteAddress = substr($remoteAddress, strpos($remoteAddress, '/') + 2); } diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 294eb1280..a5e5972df 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -75,7 +75,7 @@ class AsyncUdpConnection extends UdpConnection public function __construct($remoteAddress, $contextOption = []) { // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $remoteAddress, 2); + [$scheme, $address] = explode(':', $remoteAddress, 2); // Check application layer protocol class. if ($scheme !== 'udp') { $scheme = ucfirst($scheme); diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 596203af1..4f267a3f1 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -435,7 +435,7 @@ protected function parseHeaders(): void $headData = explode("\r\n", $headBuffer); foreach ($headData as $content) { if (str_contains($content, ':')) { - list($key, $value) = explode(':', $content, 2); + [$key, $value] = explode(':', $content, 2); $key = strtolower($key); $value = ltrim($value); } else { @@ -584,7 +584,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS if (!strpos($contentLine, ': ')) { return 0; } - list($key, $value) = explode(': ', $contentLine); + [$key, $value] = explode(': ', $contentLine); switch (strtolower($key)) { case "content-disposition": // Is file data. diff --git a/src/Worker.php b/src/Worker.php index 19d91ba18..7807cb09a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1771,7 +1771,7 @@ protected static function exitAndClearAll(): void foreach (static::$workers as $worker) { $socketName = $worker->getSocketName(); if ($worker->transport === 'unix' && $socketName) { - list(, $address) = explode(':', $socketName, 2); + [, $address] = explode(':', $socketName, 2); $address = substr($address, strpos($address, '/') + 2); @unlink($address); } @@ -2363,7 +2363,7 @@ protected function parseSocketAddress(): ?string return null; } // Get the application layer communication protocol and listening address. - list($scheme, $address) = explode(':', $this->socketName, 2); + [$scheme, $address] = explode(':', $this->socketName, 2); // Check application layer protocol class. if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) { $scheme = ucfirst($scheme); From 99f507cda4ccfcb2d3081bdc18575187f6763ccb Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:46:33 +0200 Subject: [PATCH 0899/1216] wrapping if body in braces to comply with PSR12 --- src/Protocols/Http/Request.php | 4 +++- src/Timer.php | 4 +++- src/Worker.php | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 4f267a3f1..63364b177 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -607,7 +607,9 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS $uploadKey = $fileName; // Parse upload files. $file = [...$file, 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error]; - if (!isset($file['type'])) $file['type'] = ''; + if (!isset($file['type'])) { + $file['type'] = ''; + } break; } // Is post field. else { diff --git a/src/Timer.php b/src/Timer.php index eac39b33f..cbed87919 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -201,7 +201,9 @@ public static function tick(): void } if ($persistent && !empty(self::$status[$index])) { $newRunTime = time() + $timeInterval; - if (!isset(self::$tasks[$newRunTime])) self::$tasks[$newRunTime] = []; + if (!isset(self::$tasks[$newRunTime])) { + self::$tasks[$newRunTime] = []; + } self::$tasks[$newRunTime][$index] = [$taskFunc, (array)$taskArgs, $persistent, $timeInterval]; } } diff --git a/src/Worker.php b/src/Worker.php index 7807cb09a..14ca716da 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2549,8 +2549,9 @@ public function acceptUdpConnection($socket): bool if ($parser && method_exists($parser, 'input')) { while ($recvBuffer !== '') { $len = $parser::input($recvBuffer, $connection); - if ($len === 0) + if ($len === 0) { return true; + } $package = substr($recvBuffer, 0, $len); $recvBuffer = substr($recvBuffer, $len); $data = $parser::decode($package, $connection); From 9209697d1293439cd9bdb49c4a3b01589030f18f Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:52:41 +0200 Subject: [PATCH 0900/1216] simplified if-else branches --- src/Protocols/Http/Request.php | 15 +++++++-------- src/Protocols/Websocket.php | 32 ++++++++++++++++++-------------- src/Protocols/Ws.php | 20 +++++++++++--------- src/Worker.php | 18 +++++++++--------- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 63364b177..499996408 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -611,15 +611,14 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS $file['type'] = ''; } break; - } // Is post field. - else { - // Parse $POST. - if (preg_match('/name="(.*?)"$/', $value, $match)) { - $k = $match[1]; - $postEncodeString .= urlencode($k) . "=" . urlencode($boundaryValue) . '&'; - } - return $sectionEndOffset + strlen($boundary) + 2; } + // Is post field. + // Parse $POST. + if (preg_match('/name="(.*?)"$/', $value, $match)) { + $k = $match[1]; + $postEncodeString .= urlencode($k) . "=" . urlencode($boundaryValue) . '&'; + } + return $sectionEndOffset + strlen($boundary) + 2; case "content-type": $file['type'] = trim($value); break; diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 51e94700e..f2fddb587 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -184,7 +184,9 @@ public static function input(string $buffer, TcpConnection $connection): int } } return 0; - } else if ($opcode === 0xa) { + } + + if ($opcode === 0xa) { if ($recvLen >= $currentFrameLength) { $pongData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); @@ -207,9 +209,9 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } return $currentFrameLength; - } else { - $connection->context->websocketCurrentFrameLength = $currentFrameLength; } + + $connection->context->websocketCurrentFrameLength = $currentFrameLength; } // Received just a frame length data. @@ -218,18 +220,20 @@ public static function input(string $buffer, TcpConnection $connection): int $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); $connection->context->websocketCurrentFrameLength = 0; return 0; - } // The length of the received data is greater than the length of a frame. - elseif ($connection->context->websocketCurrentFrameLength < $recvLen) { + } + + // The length of the received data is greater than the length of a frame. + if ($connection->context->websocketCurrentFrameLength < $recvLen) { static::decode(substr($buffer, 0, $connection->context->websocketCurrentFrameLength), $connection); $connection->consumeRecvBuffer($connection->context->websocketCurrentFrameLength); $currentFrameLength = $connection->context->websocketCurrentFrameLength; $connection->context->websocketCurrentFrameLength = 0; // Continue to read next frame. return static::input(substr($buffer, $currentFrameLength), $connection); - } // The length of the received data is less than the length of a frame. - else { - return 0; } + + // The length of the received data is less than the length of a frame. + return 0; } /** @@ -325,13 +329,13 @@ public static function decode(string $buffer, TcpConnection $connection): string if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decoded; return $connection->context->websocketDataBuffer; - } else { - if ($connection->context->websocketDataBuffer !== '') { - $decoded = $connection->context->websocketDataBuffer . $decoded; - $connection->context->websocketDataBuffer = ''; - } - return $decoded; } + + if ($connection->context->websocketDataBuffer !== '') { + $decoded = $connection->context->websocketDataBuffer . $decoded; + $connection->context->websocketDataBuffer = ''; + } + return $decoded; } /** diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index cab62f4d2..ca4a276bc 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -181,7 +181,9 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo } return 0; - } else if ($opcode === 0xa) { + } + + if ($opcode === 0xa) { if ($recvLen >= $currentFrameLength) { $pongData = static::decode(substr($buffer, 0, $currentFrameLength), $connection); $connection->consumeRecvBuffer($currentFrameLength); @@ -203,9 +205,9 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo return 0; } return $currentFrameLength; - } else { - $connection->context->websocketCurrentFrameLength = $currentFrameLength; } + + $connection->context->websocketCurrentFrameLength = $currentFrameLength; } // Received just a frame length data. if ($connection->context->websocketCurrentFrameLength === $recvLen) { @@ -310,13 +312,13 @@ public static function decode(string $bytes, AsyncTcpConnection $connection): st if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decodedData; return $connection->context->websocketDataBuffer; - } else { - if ($connection->context->websocketDataBuffer !== '') { - $decodedData = $connection->context->websocketDataBuffer . $decodedData; - $connection->context->websocketDataBuffer = ''; - } - return $decodedData; } + + if ($connection->context->websocketDataBuffer !== '') { + $decodedData = $connection->context->websocketDataBuffer . $decodedData; + $connection->context->websocketDataBuffer = ''; + } + return $decodedData; } /** diff --git a/src/Worker.php b/src/Worker.php index 14ca716da..bd5b59cd3 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1448,15 +1448,15 @@ protected static function forkWorkersForWindows(): void exit(250); } exit(0); - } else { - static::$globalEvent = new Select(); - static::$globalEvent->setErrorHandler(function ($exception) { - static::stopAll(250, $exception); - }); - Timer::init(static::$globalEvent); - foreach ($files as $startFile) { - static::forkOneWorkerForWindows($startFile); - } + } + + static::$globalEvent = new Select(); + static::$globalEvent->setErrorHandler(function ($exception) { + static::stopAll(250, $exception); + }); + Timer::init(static::$globalEvent); + foreach ($files as $startFile) { + static::forkOneWorkerForWindows($startFile); } } From e921a04b9173110fcddb7c601b224e3055efc72f Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 01:56:54 +0200 Subject: [PATCH 0901/1216] flipped conditions to gain performance --- src/Connection/TcpConnection.php | 2 +- src/Protocols/Websocket.php | 2 +- src/Protocols/Ws.php | 2 +- src/Worker.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f8d8ad0b3..172c42312 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -939,7 +939,7 @@ public function getSocket() */ protected function checkBufferWillFull(): void { - if ($this->maxSendBufferSize <= strlen($this->sendBuffer) && $this->onBufferFull) { + if ($this->onBufferFull && $this->maxSendBufferSize <= strlen($this->sendBuffer)) { try { ($this->onBufferFull)($this); } catch (Throwable $e) { diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index f2fddb587..1cb2f3960 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -285,7 +285,7 @@ public static function encode(mixed $buffer, TcpConnection $connection): string } $connection->context->tmpWebsocketData .= $encodeBuffer; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData) && $connection->onBufferFull) { + if ($connection->onBufferFull && $connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { try { ($connection->onBufferFull)($connection); } catch (Throwable $e) { diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index ca4a276bc..b6b67d868 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -279,7 +279,7 @@ public static function encode(mixed $payload, AsyncTcpConnection $connection): s } $connection->context->tmpWebsocketData = $connection->context->tmpWebsocketData . $frame; // Check buffer is full. - if ($connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData) && $connection->onBufferFull) { + if ($connection->onBufferFull && $connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { try { ($connection->onBufferFull)($connection); } catch (Throwable $e) { diff --git a/src/Worker.php b/src/Worker.php index bd5b59cd3..c29c729f2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1400,7 +1400,7 @@ protected static function forkWorkersForLinux(): void protected static function forkWorkersForWindows(): void { $files = static::getStartFilesForWindows(); - if (in_array('-q', static::getArgv()) || count($files) === 1) { + if (count($files) === 1 || in_array('-q', static::getArgv())) { if (count(static::$workers) > 1) { static::safeEcho("@@@ Error: multi workers init in one php file are not support @@@\r\n"); static::safeEcho("@@@ See https://www.workerman.net/doc/workerman/faq/multi-woker-for-windows.html @@@\r\n"); From 0e1d70f1febf6c01f3e8512cbe0c21afc9a2d88f Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 02:01:01 +0200 Subject: [PATCH 0902/1216] merged multiple isset()s --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index c29c729f2..c3bc5597d 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1109,7 +1109,7 @@ protected static function formatStatusData($statisticsFile): string continue; } //$qps = isset($totalRequestCache[$pid]) ? $currentTotalRequest[$pid] - if (!isset($totalRequestCache[$pid]) || !isset($currentTotalRequest[$pid])) { + if (!isset($totalRequestCache[$pid], $currentTotalRequest[$pid])) { $qps = 0; } else { $qps = $currentTotalRequest[$pid] - $totalRequestCache[$pid]; From f7095db38c1a9679b1b26c2b310a29a3652abf8b Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 02:03:27 +0200 Subject: [PATCH 0903/1216] added missing access modifiers --- src/Connection/AsyncTcpConnection.php | 2 +- src/Connection/ConnectionInterface.php | 4 ++-- src/Connection/TcpConnection.php | 14 +++++++------- src/Connection/UdpConnection.php | 2 +- src/Protocols/Http/Response.php | 2 +- src/Protocols/Websocket.php | 4 ++-- src/Protocols/Ws.php | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index fcf56bd92..f2fd3c935 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -55,7 +55,7 @@ class AsyncTcpConnection extends TcpConnection * * @var array */ - const BUILD_IN_TRANSPORTS = [ + public const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', 'udp' => 'udp', 'unix' => 'unix', diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 7131c7904..ca1fc44cb 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -33,14 +33,14 @@ abstract class ConnectionInterface * * @var int */ - const CONNECT_FAIL = 1; + public const CONNECT_FAIL = 1; /** * Send failed. * * @var int */ - const SEND_FAIL = 2; + public const SEND_FAIL = 2; /** * Statistics for status command. diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 172c42312..1cc84e7ca 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -63,42 +63,42 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable * * @var int */ - const READ_BUFFER_SIZE = 87380; + public const READ_BUFFER_SIZE = 87380; /** * Status initial. * * @var int */ - const STATUS_INITIAL = 0; + public const STATUS_INITIAL = 0; /** * Status connecting. * * @var int */ - const STATUS_CONNECTING = 1; + public const STATUS_CONNECTING = 1; /** * Status connection established. * * @var int */ - const STATUS_ESTABLISHED = 2; + public const STATUS_ESTABLISHED = 2; /** * Status closing. * * @var int */ - const STATUS_CLOSING = 4; + public const STATUS_CLOSING = 4; /** * Status closed. * * @var int */ - const STATUS_CLOSED = 8; + public const STATUS_CLOSED = 8; /** * Emitted when socket connection is successfully established. @@ -319,7 +319,7 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable * * @var array */ - const STATUS_TO_STRING = [ + public const STATUS_TO_STRING = [ self::STATUS_INITIAL => 'INITIAL', self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 8dd36819f..d2af4a42e 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -38,7 +38,7 @@ class UdpConnection extends ConnectionInterface implements JsonSerializable * * @var int */ - const MAX_UDP_PACKAGE_SIZE = 65535; + public const MAX_UDP_PACKAGE_SIZE = 65535; /** * Transport layer protocol. diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 1e14e0f78..df16e8ec4 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -92,7 +92,7 @@ class Response * * @link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ - const PHRASES = [ + public const PHRASES = [ 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', // WebDAV; RFC 2518 diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 1cb2f3960..8e5678c6f 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -48,14 +48,14 @@ class Websocket * * @var string */ - const BINARY_TYPE_BLOB = "\x81"; + public const BINARY_TYPE_BLOB = "\x81"; /** * Websocket arraybuffer type. * * @var string */ - const BINARY_TYPE_ARRAYBUFFER = "\x82"; + public const BINARY_TYPE_ARRAYBUFFER = "\x82"; /** * Check the integrity of the package. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index b6b67d868..4cf6b2b43 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -49,14 +49,14 @@ class Ws * * @var string */ - const BINARY_TYPE_BLOB = "\x81"; + public const BINARY_TYPE_BLOB = "\x81"; /** * Websocket arraybuffer type. * * @var string */ - const BINARY_TYPE_ARRAYBUFFER = "\x82"; + public const BINARY_TYPE_ARRAYBUFFER = "\x82"; /** * Check the integrity of the package. From df39972cfdc83fc04c9aa66b26ef42324f8dd4d7 Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 02:05:57 +0200 Subject: [PATCH 0904/1216] replaced long notation with combined assignment --- src/Protocols/Http.php | 4 ++-- src/Protocols/Ws.php | 2 +- src/Worker.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 41825db39..8455b534e 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -131,10 +131,10 @@ public static function input(string $buffer, TcpConnection $connection): int } if ($pos = stripos($header, "\r\nContent-Length: ")) { - $length = $length + (int)substr($header, $pos + 18, 10); + $length += (int)substr($header, $pos + 18, 10); $hasContentLength = true; } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { - $length = $length + (int)$match[1]; + $length += (int)$match[1]; $hasContentLength = true; } else { $hasContentLength = false; diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 4cf6b2b43..479f14de7 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -277,7 +277,7 @@ public static function encode(mixed $payload, AsyncTcpConnection $connection): s } return ''; } - $connection->context->tmpWebsocketData = $connection->context->tmpWebsocketData . $frame; + $connection->context->tmpWebsocketData .= $frame; // Check buffer is full. if ($connection->onBufferFull && $connection->maxSendBufferSize <= strlen($connection->context->tmpWebsocketData)) { try { diff --git a/src/Worker.php b/src/Worker.php index c3bc5597d..5c43b44b6 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2161,7 +2161,7 @@ protected static function getErrorType(int $type): string */ public static function log(mixed $msg, bool $decorated = false): void { - $msg = $msg . "\n"; + $msg .= "\n"; if (!static::$daemonize) { static::safeEcho($msg, $decorated); } From db3c9fb942e4fd8f432b2db8a679474dac0a9d8c Mon Sep 17 00:00:00 2001 From: Mark Magyar <14284867+xHeaven@users.noreply.github.com> Date: Thu, 18 May 2023 02:08:19 +0200 Subject: [PATCH 0905/1216] using dynamic invocation instead of static --- src/Protocols/Http/Session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 4b2828743..aa3a65a78 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -320,7 +320,7 @@ public function save(): void static::$handler->write($this->sessionId, serialize($this->data)); } } elseif (static::$autoUpdateTimestamp) { - static::refresh(); + $this->refresh(); } $this->needSave = false; } From 5125dbbb6a36ec0a8257784c75b9856c960a19c5 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 29 May 2023 22:37:35 +0800 Subject: [PATCH 0906/1216] Fix #916 --- src/Protocols/Http/Request.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 499996408..ed5e3ff68 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -234,8 +234,8 @@ public function protocolVersion(): string public function host(bool $withoutPort = false): ?string { $host = $this->header('host'); - if ($host && $withoutPort && $pos = strpos($host, ':')) { - return substr($host, 0, $pos); + if ($host && $without_port) { + return preg_replace('/:\d{1,5}$/', '', $host); } return $host; } From 541777531e7f935887c12d0d3a47cbb2c7c2f8d0 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 29 May 2023 22:47:51 +0800 Subject: [PATCH 0907/1216] Update Request.php --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ed5e3ff68..1cf9148b3 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -234,7 +234,7 @@ public function protocolVersion(): string public function host(bool $withoutPort = false): ?string { $host = $this->header('host'); - if ($host && $without_port) { + if ($host && $withoutPort) { return preg_replace('/:\d{1,5}$/', '', $host); } return $host; From 247d87ca29c31ec0e1d5163e83c8af0d90832cb8 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 1 Jun 2023 05:42:57 +0300 Subject: [PATCH 0908/1216] Removed PHPStrom attributes, fixed minor typos and changed DEBUG to USER mode. --- src/Connection/AsyncTcpConnection.php | 2 +- src/Connection/TcpConnection.php | 18 ++--- src/Connection/UdpConnection.php | 8 -- src/Events/Select.php | 2 +- src/Protocols/Websocket.php | 16 ++-- src/Worker.php | 108 ++++++++++++++------------ 6 files changed, 75 insertions(+), 79 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index f2fd3c935..29a7e602d 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -301,7 +301,7 @@ public function connect(): void } return; } - // Add socket to global event loop waiting connection is successfully established or faild. + // Add socket to global event loop waiting connection is successfully established or failed. $this->eventLoop->onWritable($this->socket, [$this, 'checkConnection']); // For windows. if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'onExcept')) { diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 1cc84e7ca..a5286aba2 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -15,7 +15,6 @@ namespace Workerman\Connection; -use JetBrains\PhpStorm\Pure; use JsonSerializable; use stdClass; use Throwable; @@ -898,7 +897,6 @@ public function close(mixed $data = null, bool $raw = false): void * * return bool. */ - #[Pure] public function isIpV4(): bool { if ($this->transport === 'unix') { @@ -912,7 +910,6 @@ public function isIpV4(): bool * * return bool. */ - #[Pure] public function isIpV6(): bool { if ($this->transport === 'unix') { @@ -1038,8 +1035,8 @@ public function destroy(): void * * @param mixed $value */ - public static function enableCache(bool $value = true) - { + public static function enableCache(bool $value = true): void + { static::$enableCache = $value; } @@ -1065,11 +1062,12 @@ public function jsonSerialize(): array ]; } - /** - * Destruct. - * - * @return void - */ + /** + * Destruct. + * + * @return void + * @throws Throwable + */ public function __destruct() { static $mod; diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index d2af4a42e..05bdbc44a 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -16,8 +16,6 @@ namespace Workerman\Connection; -use JetBrains\PhpStorm\ArrayShape; -use JetBrains\PhpStorm\Pure; use JsonSerializable; use Workerman\Protocols\ProtocolInterface; use function stream_socket_get_name; @@ -191,7 +189,6 @@ public function close(mixed $data = null, bool $raw = false): void * * return bool. */ - #[Pure] public function isIpV4(): bool { if ($this->transport === 'unix') { @@ -205,7 +202,6 @@ public function isIpV4(): bool * * return bool. */ - #[Pure] public function isIpV6(): bool { if ($this->transport === 'unix') { @@ -229,10 +225,6 @@ public function getSocket() * * @return array */ - #[ArrayShape([ - 'transport' => "string", 'getRemoteIp' => "string", 'remotePort' => "int", 'getRemoteAddress' => "string", - 'getLocalIp' => "string", 'getLocalPort' => "int", 'getLocalAddress' => "string", 'isIpV4' => "bool", 'isIpV6' => "bool"] - )] public function jsonSerialize(): array { return [ diff --git a/src/Events/Select.php b/src/Events/Select.php index a919809d2..d06fbba41 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -380,7 +380,7 @@ public function run(): void if ($read || $write || $except) { // Waiting read/write/signal/timeout events. try { - @stream_select($read, $write, $except, 0, $this->selectTimeout); + stream_select($read, $write, $except, 0, $this->selectTimeout); } catch (Throwable) { } } else { diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 8e5678c6f..095deb17a 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -236,14 +236,14 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } - /** - * Websocket encode. - * - * @param mixed $buffer - * @param TcpConnection $connection - * @return string - * @throws Exception - */ + /** + * Websocket encode. + * + * @param mixed $buffer + * @param TcpConnection $connection + * @return string + * @throws Throwable + */ public static function encode(mixed $buffer, TcpConnection $connection): string { if (!is_scalar($buffer)) { diff --git a/src/Worker.php b/src/Worker.php index 5c43b44b6..852c0edd4 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -620,7 +620,7 @@ protected static function init(): void @mkdir(dirname(static::$logFile), 0777, true); } touch(static::$logFile); - chmod(static::$logFile, 0622); + chmod(static::$logFile, 0644); } // State. @@ -761,7 +761,7 @@ protected static function initId(): void } /** - * Get unix user of current porcess. + * Get unix user of current process. * * @return string */ @@ -792,7 +792,7 @@ protected static function displayUI(): void //show version $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . str_pad('Event-loop:', 16, ' ', STR_PAD_LEFT) . static::getEventLoopName() . PHP_EOL; - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', strlen($lineVersion)); + !defined('LINE_VERSION_LENGTH') && define('LINE_VERSION_LENGTH', strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); $lineOne = '' . str_pad(' WORKERMAN ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . '' . PHP_EOL; $lineTwo = str_pad(' WORKERS ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . PHP_EOL; @@ -827,9 +827,11 @@ protected static function displayUI(): void if (static::$daemonize) { static::safeEcho('Input "php ' . basename(static::$startFile) . ' stop" to stop. Start success.' . "\n\n"); + } else if (!empty(static::$command)) { + static::safeEcho("Start success.\n"); // Workerman used as library } else { - static::safeEcho("Press Ctrl+C to stop. Start success.\n"); - } + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); + } } /** @@ -867,8 +869,8 @@ public static function getSingleLineTotalLength(): int } //Keep beauty when show less columns - !defined('LINE_VERSIOIN_LENGTH') && define('LINE_VERSIOIN_LENGTH', 0); - $totalLength <= LINE_VERSIOIN_LENGTH && $totalLength = LINE_VERSIOIN_LENGTH; + !defined('LINE_VERSION_LENGTH') && define('LINE_VERSION_LENGTH', 0); + $totalLength <= LINE_VERSION_LENGTH && $totalLength = LINE_VERSION_LENGTH; return $totalLength; } @@ -886,7 +888,7 @@ protected static function parseCommand(): void // Check argv; $startFile = basename(static::$startFile); - $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; + $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in USER mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; $availableCommands = [ 'start', 'stop', @@ -919,7 +921,7 @@ protected static function parseCommand(): void if ($mode === '-d' || static::$daemonize) { $modeStr = 'in DAEMON mode'; } else { - $modeStr = 'in DEBUG mode'; + $modeStr = 'in USER mode'; } } static::log("Workerman[$startFile] $command $modeStr"); @@ -973,9 +975,9 @@ protected static function parseCommand(): void } // Master process will send SIGIO signal to all child processes. posix_kill($masterPid, SIGIO); - // Waiting amoment. + // Waiting a moment. usleep(500000); - // Display statisitcs data from a disk file. + // Display statistics data from a disk file. if (is_readable($statisticsFile)) { readfile($statisticsFile); } @@ -1005,7 +1007,7 @@ protected static function parseCommand(): void static::log("Workerman[$startFile] stop fail"); exit; } - // Waiting amoment. + // Waiting a moment. usleep(10000); continue; } @@ -1165,12 +1167,12 @@ protected static function reinstallSignal(): void } } - /** - * Signal handler. - * - * @param int $signal - * @throws Exception - */ + /** + * Signal handler. + * + * @param int $signal + * @throws Throwable + */ public static function signalHandler(int $signal): void { switch ($signal) { @@ -1298,9 +1300,9 @@ protected static function saveMasterPid(): void } static::$masterPid = posix_getpid(); - if (false === file_put_contents(static::$pidFile, static::$masterPid)) { - throw new RuntimeException('can not save pid to ' . static::$pidFile); - } + if (false === file_put_contents(static::$pidFile, static::$masterPid)) { + throw new RuntimeException('can not save pid to ' . static::$pidFile); + } } /** @@ -1784,12 +1786,12 @@ protected static function exitAndClearAll(): void exit(0); } - /** - * Execute reload. - * - * @return void - * @throws Exception - */ + /** + * Execute reload. + * + * @return void + * @throws Throwable + */ protected static function reload(): void { // For master process. @@ -1866,12 +1868,13 @@ protected static function reload(): void } } - /** - * Stop all. - * - * @param int $code - * @param mixed $log - */ + /** + * Stop all. + * + * @param int $code + * @param mixed $log + * @throws Throwable + */ public static function stopAll(int $code = 0, mixed $log = ''): void { if ($log) { @@ -2448,11 +2451,12 @@ public function run(): void } } - /** - * Stop current worker instance. - * - * @return void - */ + /** + * Stop current worker instance. + * + * @return void + * @throws Throwable + */ public function stop(): void { // Try to emit onWorkerStop callback. @@ -2466,7 +2470,7 @@ public function stop(): void // Remove listener for server socket. $this->unlisten(); // Close all connections for the worker. - if (!static::$gracefulStop) { + if (static::$gracefulStop) { foreach ($this->connections as $connection) { $connection->close(); } @@ -2481,12 +2485,13 @@ public function stop(): void $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; } - /** - * Accept a connection. - * - * @param resource $socket - * @return void - */ + /** + * Accept a connection. + * + * @param resource $socket + * @return void + * @throws Throwable + */ public function acceptTcpConnection($socket): void { // Accept a connection on server socket. @@ -2522,12 +2527,13 @@ public function acceptTcpConnection($socket): void } } - /** - * For udp package. - * - * @param resource $socket - * @return bool - */ + /** + * For udp package. + * + * @param resource $socket + * @return bool + * @throws Throwable + */ public function acceptUdpConnection($socket): bool { set_error_handler(function () { From 8d9a9c1bd73952c5b06dc32fe14fd18c96c9fdf7 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 1 Jun 2023 05:53:13 +0300 Subject: [PATCH 0909/1216] Replaced tabs with spaces project wide. --- src/Connection/TcpConnection.php | 14 ++--- src/Protocols/Websocket.php | 18 +++---- src/Worker.php | 90 ++++++++++++++++---------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index a5286aba2..f1d021c78 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1036,7 +1036,7 @@ public function destroy(): void * @param mixed $value */ public static function enableCache(bool $value = true): void - { + { static::$enableCache = $value; } @@ -1062,12 +1062,12 @@ public function jsonSerialize(): array ]; } - /** - * Destruct. - * - * @return void - * @throws Throwable - */ + /** + * Destruct. + * + * @return void + * @throws Throwable + */ public function __destruct() { static $mod; diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 095deb17a..5b63b6d02 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -236,14 +236,14 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } - /** - * Websocket encode. - * - * @param mixed $buffer - * @param TcpConnection $connection - * @return string - * @throws Throwable - */ + /** + * Websocket encode. + * + * @param mixed $buffer + * @param TcpConnection $connection + * @return string + * @throws Throwable + */ public static function encode(mixed $buffer, TcpConnection $connection): string { if (!is_scalar($buffer)) { @@ -362,7 +362,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $SecWebSocketKey = $match[1]; } else { $connection->close( - "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); + "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); return 0; } // Calculation websocket key. diff --git a/src/Worker.php b/src/Worker.php index 852c0edd4..85541161f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -828,10 +828,10 @@ protected static function displayUI(): void if (static::$daemonize) { static::safeEcho('Input "php ' . basename(static::$startFile) . ' stop" to stop. Start success.' . "\n\n"); } else if (!empty(static::$command)) { - static::safeEcho("Start success.\n"); // Workerman used as library + static::safeEcho("Start success.\n"); // Workerman used as library } else { - static::safeEcho("Press Ctrl+C to stop. Start success.\n"); - } + static::safeEcho("Press Ctrl+C to stop. Start success.\n"); + } } /** @@ -1167,12 +1167,12 @@ protected static function reinstallSignal(): void } } - /** - * Signal handler. - * - * @param int $signal - * @throws Throwable - */ + /** + * Signal handler. + * + * @param int $signal + * @throws Throwable + */ public static function signalHandler(int $signal): void { switch ($signal) { @@ -1300,9 +1300,9 @@ protected static function saveMasterPid(): void } static::$masterPid = posix_getpid(); - if (false === file_put_contents(static::$pidFile, static::$masterPid)) { - throw new RuntimeException('can not save pid to ' . static::$pidFile); - } + if (false === file_put_contents(static::$pidFile, static::$masterPid)) { + throw new RuntimeException('can not save pid to ' . static::$pidFile); + } } /** @@ -1786,12 +1786,12 @@ protected static function exitAndClearAll(): void exit(0); } - /** - * Execute reload. - * - * @return void - * @throws Throwable - */ + /** + * Execute reload. + * + * @return void + * @throws Throwable + */ protected static function reload(): void { // For master process. @@ -1868,13 +1868,13 @@ protected static function reload(): void } } - /** - * Stop all. - * - * @param int $code - * @param mixed $log - * @throws Throwable - */ + /** + * Stop all. + * + * @param int $code + * @param mixed $log + * @throws Throwable + */ public static function stopAll(int $code = 0, mixed $log = ''): void { if ($log) { @@ -2451,12 +2451,12 @@ public function run(): void } } - /** - * Stop current worker instance. - * - * @return void - * @throws Throwable - */ + /** + * Stop current worker instance. + * + * @return void + * @throws Throwable + */ public function stop(): void { // Try to emit onWorkerStop callback. @@ -2485,13 +2485,13 @@ public function stop(): void $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; } - /** - * Accept a connection. - * - * @param resource $socket - * @return void - * @throws Throwable - */ + /** + * Accept a connection. + * + * @param resource $socket + * @return void + * @throws Throwable + */ public function acceptTcpConnection($socket): void { // Accept a connection on server socket. @@ -2527,13 +2527,13 @@ public function acceptTcpConnection($socket): void } } - /** - * For udp package. - * - * @param resource $socket - * @return bool - * @throws Throwable - */ + /** + * For udp package. + * + * @param resource $socket + * @return bool + * @throws Throwable + */ public function acceptUdpConnection($socket): bool { set_error_handler(function () { From b9d540d751ded63ee9db2adf3098d144dbb63edc Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 2 Jun 2023 15:44:15 +0800 Subject: [PATCH 0910/1216] Suppress notice interrupted by signal --- src/Events/Select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index d06fbba41..a919809d2 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -380,7 +380,7 @@ public function run(): void if ($read || $write || $except) { // Waiting read/write/signal/timeout events. try { - stream_select($read, $write, $except, 0, $this->selectTimeout); + @stream_select($read, $write, $except, 0, $this->selectTimeout); } catch (Throwable) { } } else { From 01f43d8adb1ef754e7230d99616ba374b7528e82 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 11 Jun 2023 23:12:08 +0800 Subject: [PATCH 0911/1216] ws response --- src/Protocols/Ws.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 479f14de7..c19e61e2a 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -20,6 +20,7 @@ use Throwable; use Workerman\Connection\AsyncTcpConnection; use Workerman\Connection\ConnectionInterface; +use Workerman\Protocols\Http\Response; use Workerman\Timer; use Workerman\Worker; use function base64_encode; @@ -422,10 +423,12 @@ public static function dealHandshake(string $buffer, AsyncTcpConnection $connect // handshake complete $connection->context->handshakeStep = 2; $handshakeResponseLength = $pos + 4; + $buffer = substr($buffer, 0, $handshakeResponseLength); + $response = static::parseResponse($buffer); // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { try { - ($connection->onWebSocketConnect)($connection, substr($buffer, 0, $handshakeResponseLength)); + ($connection->onWebSocketConnect)($connection, $response); } catch (Throwable $e) { Worker::stopAll(250, $e); } @@ -452,4 +455,29 @@ public static function dealHandshake(string $buffer, AsyncTcpConnection $connect return 0; } + /** + * Parse response. + * + * @param string $buffer + * @return Response + */ + protected static function parseResponse(string $buffer): Response + { + [$http_header, ] = \explode("\r\n\r\n", $buffer, 2); + $header_data = \explode("\r\n", $http_header); + [$protocol, $status, $phrase] = \explode(' ', $header_data[0], 3); + $protocolVersion = substr($protocol, 5); + unset($header_data[0]); + $headers = []; + foreach ($header_data as $content) { + // \r\n\r\n + if (empty($content)) { + continue; + } + list($key, $value) = \explode(':', $content, 2); + $value = \trim($value); + $headers[$key] = $value; + } + return (new Response())->withStatus((int)$status, $phrase)->withHeaders($headers)->withProtocolVersion($protocolVersion); + } } From ed9df9b4686cb99bebfc459ee1d4d3d2d7589ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=A3=E8=A8=80=E5=B0=B1=E6=98=AFSiam?= <59419979@qq.com> Date: Mon, 12 Jun 2023 14:27:09 +0800 Subject: [PATCH 0912/1216] =?UTF-8?q?=F0=9F=90=9B=20import=20function=20`w?= =?UTF-8?q?atiAll`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Events/Swow.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index b7c0655ba..9a6a2ec3e 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -9,6 +9,7 @@ use Swow\Signal; use Swow\SignalException; use Throwable; +use function Swow\Sync\waitAll; class Swow implements EventInterface { From 2fbb26b41dc626d9a1f88d0395f94bb429c4b93f Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 20 Jun 2023 10:33:21 +0800 Subject: [PATCH 0913/1216] Start the socket server in beforeAll --- tests/Feature/UdpConnectionTest.php | 2 +- tests/Unit/Connection/UdpConnectionTest.php | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 232803407..43e69bc98 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -29,7 +29,7 @@ }); afterAll(function () use ($serverAddress) { - $socket = stream_socket_client(self::$serverAddress, timeout: 1); + $socket = stream_socket_client($serverAddress, timeout: 1); fwrite($socket, 'bye'); fclose($socket); }); diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index ea05ea1c4..851996d4b 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -4,15 +4,17 @@ use Symfony\Component\Process\PhpProcess; $remoteAddress = '[::1]:12345'; -$process = new PhpProcess(<<start(); +beforeAll(function () use ($remoteAddress) { + $process = new PhpProcess(<<start(); +}); it('tests ' . UdpConnection::class, function () use ($remoteAddress) { From 0f57772057c9857c66504a784847e8118633620a Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 20 Jun 2023 10:40:25 +0800 Subject: [PATCH 0914/1216] Multiple expect conversions to chained calls --- tests/Feature/ExampleTest.php | 1 - tests/Unit/Connection/UdpConnectionTest.php | 19 +++++++++---------- tests/Unit/Protocols/FrameTest.php | 4 ++-- tests/Unit/Protocols/Http/ResponseTest.php | 12 ++++++------ tests/Unit/Protocols/TextTest.php | 20 +++++++++----------- 5 files changed, 26 insertions(+), 30 deletions(-) diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 782d85721..61cd84c32 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -2,5 +2,4 @@ test('example', function () { expect(true)->toBeTrue(); -// expect('3')->toBe(3); }); diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index 851996d4b..f87733cf9 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -2,6 +2,7 @@ use Workerman\Connection\UdpConnection; use Symfony\Component\Process\PhpProcess; +use Workerman\Protocols\Text; $remoteAddress = '[::1]:12345'; beforeAll(function () use ($remoteAddress) { @@ -20,16 +21,14 @@ $socketClient = stream_socket_client("udp://$remoteAddress"); $udpConnection = new UdpConnection($socketClient, $remoteAddress); - $udpConnection->protocol = \Workerman\Protocols\Text::class; - expect($udpConnection->send('foo'))->toBeTrue(); - - expect($udpConnection->getRemoteIp())->toBe('::1'); - expect($udpConnection->getRemotePort())->toBe(12345); - expect($udpConnection->getRemoteAddress())->toBe($remoteAddress); - expect($udpConnection->getLocalIp())->toBeIn(['::1', '[::1]', '127.0.0.1']); - expect($udpConnection->getLocalPort())->toBeInt(); - - expect(json_encode($udpConnection))->toBeJson() + $udpConnection->protocol = Text::class; + expect($udpConnection->send('foo'))->toBeTrue() + ->and($udpConnection->getRemoteIp())->toBe('::1') + ->and($udpConnection->getRemotePort())->toBe(12345) + ->and($udpConnection->getRemoteAddress())->toBe($remoteAddress) + ->and($udpConnection->getLocalIp())->toBeIn(['::1', '[::1]', '127.0.0.1']) + ->and($udpConnection->getLocalPort())->toBeInt() + ->and(json_encode($udpConnection))->toBeJson() ->toContain('transport') ->toContain('getRemoteIp') ->toContain('remotePort') diff --git a/tests/Unit/Protocols/FrameTest.php b/tests/Unit/Protocols/FrameTest.php index 7978729ca..2e09078ce 100644 --- a/tests/Unit/Protocols/FrameTest.php +++ b/tests/Unit/Protocols/FrameTest.php @@ -3,8 +3,8 @@ use Workerman\Protocols\Frame; it('tests ::input', function () { - expect(Frame::input('foo'))->toBe(0); - expect(Frame::input("\0\0\0*foobar")) + expect(Frame::input('foo'))->toBe(0) + ->and(Frame::input("\0\0\0*foobar")) ->toBe(42); }); diff --git a/tests/Unit/Protocols/Http/ResponseTest.php b/tests/Unit/Protocols/Http/ResponseTest.php index 32bba425d..1bd61fd6a 100644 --- a/tests/Unit/Protocols/Http/ResponseTest.php +++ b/tests/Unit/Protocols/Http/ResponseTest.php @@ -5,9 +5,9 @@ it('test some simple case', function () { $response = new Response(201, ['X-foo' => 'bar'], 'hello, xiami'); - expect($response->getStatusCode())->toBe(201); - expect($response->getHeaders())->toBe(['X-foo' => 'bar']); - expect($response->rawBody())->toBe('hello, xiami'); + expect($response->getStatusCode())->toBe(201) + ->and($response->getHeaders())->toBe(['X-foo' => 'bar']) + ->and($response->rawBody())->toBe('hello, xiami'); //headers $response->header('abc', '123'); @@ -18,8 +18,8 @@ ->toContain('abc: 123') ->toContain('def: 456'); $response->withoutHeader('def'); - expect((string)$response)->not->toContain('def: 456'); - expect($response->getHeader('abc')) + expect((string)$response)->not->toContain('def: 456') + ->and($response->getHeader('abc')) ->toBe('123'); $response->withStatus(202, 'some reason'); @@ -36,7 +36,7 @@ //cookie - $response->cookie('foo', 'bar', httpOnly: true, domain: 'xia.moe'); + $response->cookie('foo', 'bar', domain: 'xia.moe', httpOnly: true); expect((string)$response) ->toContain('Set-Cookie: foo=bar; Domain=xia.moe; HttpOnly'); }); diff --git a/tests/Unit/Protocols/TextTest.php b/tests/Unit/Protocols/TextTest.php index c3b4157d1..769d933d1 100644 --- a/tests/Unit/Protocols/TextTest.php +++ b/tests/Unit/Protocols/TextTest.php @@ -15,16 +15,14 @@ }); //input without "\n" expect(Text::input('jhdxr', $connection)) - ->toBe(0); - //input with "\n" - expect(Text::input("jhdxr\n", $connection)) - ->toBe(6); - - //::encode - expect(Text::encode('jhdxr')) - ->toBe("jhdxr\n"); - - //::decode - expect(Text::decode("jhdxr\n")) + ->toBe(0) + //input with "\n" + ->and(Text::input("jhdxr\n", $connection)) + ->toBe(6) + //::encode + ->and(Text::encode('jhdxr')) + ->toBe("jhdxr\n") + //::decode + ->and(Text::decode("jhdxr\n")) ->toBe('jhdxr'); }); \ No newline at end of file From 10569a751abcc5c694e5e9aa1f1b6ac414b2b031 Mon Sep 17 00:00:00 2001 From: Chance Date: Wed, 21 Jun 2023 14:25:54 +0800 Subject: [PATCH 0915/1216] Stop the process in `afterAll` --- tests/Feature/UdpConnectionTest.php | 14 +++++--------- tests/Pest.php | 5 ----- tests/Unit/Connection/UdpConnectionTest.php | 10 ++++++++-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 43e69bc98..6044feffc 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -4,7 +4,8 @@ use Workerman\Worker; $serverAddress = 'udp://127.0.0.1:6789'; -beforeAll(function () use ($serverAddress) { +$process = null; +beforeAll(function () use ($serverAddress, &$process) { $process = new PhpProcess(<<onMessage = function (\$connection, \$data) { - if(str_starts_with(\$data, 'bye')) { - terminate_current_process(); - } \$connection->send('received: '.\$data); }; Worker::\$command = 'start'; @@ -25,13 +23,11 @@ PHP ); $process->start(); - sleep(5); + sleep(1); }); -afterAll(function () use ($serverAddress) { - $socket = stream_socket_client($serverAddress, timeout: 1); - fwrite($socket, 'bye'); - fclose($socket); +afterAll(function () use (&$process) { + $process->stop(); }); it('tests udp connection', function () use ($serverAddress) { diff --git a/tests/Pest.php b/tests/Pest.php index ff027c86c..ccf40d3bf 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -58,8 +58,3 @@ function testWithConnectionClose(Closure $closure, string $dataContains = null, $tcpConnection->shouldHaveReceived('close'); } } - -function terminate_current_process() -{ - posix_kill(posix_getppid(), SIGINT); -} \ No newline at end of file diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index f87733cf9..d45f2d429 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -5,16 +5,22 @@ use Workerman\Protocols\Text; $remoteAddress = '[::1]:12345'; -beforeAll(function () use ($remoteAddress) { +$process = null; +beforeAll(function () use ($remoteAddress, &$process) { $process = new PhpProcess(<<start(); + sleep(1); +}); + +afterAll(function () use (&$process) { + $process->stop(); }); it('tests ' . UdpConnection::class, function () use ($remoteAddress) { From 3b4044a0185ff9759ef29eb99832ce50d891eeae Mon Sep 17 00:00:00 2001 From: Chance Date: Wed, 21 Jun 2023 15:01:28 +0800 Subject: [PATCH 0916/1216] Feature test of http server --- composer.json | 3 +- tests/Feature/HttpConnectionTest.php | 117 +++++++++++++++++++++++++++ tests/Feature/Stub/HttpServer.php | 52 ++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/HttpConnectionTest.php create mode 100644 tests/Feature/Stub/HttpServer.php diff --git a/composer.json b/composer.json index ad6da6487..084d0390d 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,8 @@ }, "require-dev": { "pestphp/pest": "2.x-dev", - "mockery/mockery": "2.0.x-dev" + "mockery/mockery": "2.0.x-dev", + "guzzlehttp/guzzle": "^7.0" }, "config": { "allow-plugins": { diff --git a/tests/Feature/HttpConnectionTest.php b/tests/Feature/HttpConnectionTest.php new file mode 100644 index 000000000..384ec3e8f --- /dev/null +++ b/tests/Feature/HttpConnectionTest.php @@ -0,0 +1,117 @@ +start(); + sleep(1); +}); + +afterAll(function () use (&$process) { + $process->stop(); +}); + +it('tests http connection', function () { + $client = new Client([ + 'base_uri' => 'http://127.0.0.1:8080', + 'cookies' => true, + 'http_errors' => false, + ]); + + $response = $client->get('/'); + expect($response->getStatusCode()) + ->toBe(200) + ->and($response->getHeaderLine('Server')) + ->tobe('workerman') + ->and($response->getHeaderLine('Content-Length')) + ->tobe('12') + ->and($response->getBody()->getContents()) + ->toBe('Hello Chance'); + + $data = [ + 'foo' => 'bar', + 'key' => ['hello', 'chance'] + ]; + $response = $client->get('/get', [ + 'query' => $data + ]); + expect($response->getBody()->getContents()) + ->toBeJson() + ->json() + ->toBe($data); + + $response = $client->post('/post', [ + 'json' => $data + ]); + expect($response->getBody()->getContents()) + ->toBeJson() + ->json() + ->toBe($data); + + $response = $client->post('/header', [ + 'headers' => [ + 'foo' => 'bar' + ] + ]); + expect($response->getBody()->getContents()) + ->toBe('bar'); + + $cookie = new CookieJar(); + $client->get('/setSession', [ + 'cookies' => $cookie + ]); + $response = $client->get('/session', [ + 'cookies' => $cookie + ]); + expect($response->getBody()->getContents()) + ->toBe('bar'); + $response = $client->get('/session', [ + 'cookies' => $cookie + ]); + expect($response->getBody()->getContents()) + ->toBe(''); + + $response = $client->get('/sse', [ + 'stream' => true, + ]); + $stream = $response->getBody(); + $i = 0; + while (!$stream->eof()) { + if ($i >= 5) { + expect($stream->read(1024))->toBeEmpty(); + continue; + } + $i++; + expect($stream->read(1024))->toBe("data: hello$i\n\n"); + } + + $file = Utils::tryFopen(__DIR__ . '/Stub/HttpServer.php', 'r'); + $response = $client->post('/file', [ + 'multipart' => [ + [ + 'name' => 'file', + 'contents' => $file + ] + ] + ]); + expect($response->getBody()->getContents()) + ->toBeJson() + ->json() + ->toMatchArray([ + 'name' => 'HttpServer.php', + 'error' => 0, + 'type' => 'application/x-httpd-php', + ]); + + $response = $client->get('/404'); + expect($response->getStatusCode()) + ->toBe(404) + ->and($response->getBody()->getContents()) + ->toBe('404 not found'); +}); \ No newline at end of file diff --git a/tests/Feature/Stub/HttpServer.php b/tests/Feature/Stub/HttpServer.php new file mode 100644 index 000000000..a1b1a0078 --- /dev/null +++ b/tests/Feature/Stub/HttpServer.php @@ -0,0 +1,52 @@ +onMessage = function (TcpConnection $connection, Request $request) { + match ($request->path()) { + '/' => $connection->send('Hello Chance'), + '/get' => $connection->send(json_encode($request->get())), + '/post' => $connection->send(json_encode($request->post())), + '/header' => $connection->send($request->header('foo')), + '/setSession' => (function () use ($connection, $request) { + $request->session()->set('foo', 'bar'); + $connection->send(''); + })(), + '/session' => $connection->send($request->session()->pull('foo')), + '/sse' => (function () use ($connection) { + $connection->send(new Response(200, ['Content-Type' => 'text/event-stream'], "\r\n")); + $i = 0; + $timer_id = Timer::add(0.001, function () use ($connection, &$timer_id, &$i) { + if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) { + Timer::del($timer_id); + return; + } + if ($i >= 5) { + Timer::del($timer_id); + $connection->close(); + return; + } + $i++; + $connection->send(new ServerSentEvents(['data' => "hello$i"])); + }); + })(), + '/file' => $connection->send(json_encode($request->file('file'))), + default => $connection->send(new Response(404, [], '404 not found')) + }; +}; + +Worker::$command = 'start'; +Worker::runAll(); \ No newline at end of file From e62c08b533903f7c23085b457b37e9ae66d6ce1d Mon Sep 17 00:00:00 2001 From: Chance Date: Sun, 25 Jun 2023 13:05:07 +0800 Subject: [PATCH 0917/1216] Fix test --- tests/Feature/HttpConnectionTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Feature/HttpConnectionTest.php b/tests/Feature/HttpConnectionTest.php index 384ec3e8f..fa71e0ef2 100644 --- a/tests/Feature/HttpConnectionTest.php +++ b/tests/Feature/HttpConnectionTest.php @@ -106,7 +106,6 @@ ->toMatchArray([ 'name' => 'HttpServer.php', 'error' => 0, - 'type' => 'application/x-httpd-php', ]); $response = $client->get('/404'); From 59b6eb0e6608cb733b5a7dbc2d5fe0d13284a7db Mon Sep 17 00:00:00 2001 From: Joanhey Date: Wed, 28 Jun 2023 13:55:09 +0200 Subject: [PATCH 0918/1216] Fix 400 Bad Request --- src/Protocols/Http.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 8455b534e..bd76a9393 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -118,7 +118,7 @@ public static function input(string $buffer, TcpConnection $connection): int $firstLine = explode(" ", strstr($buffer, "\r\n", true), 3); if (!in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { - $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } @@ -126,7 +126,7 @@ public static function input(string $buffer, TcpConnection $connection): int $hostHeaderPosition = stripos($header, "\r\nHost: "); if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { - $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } @@ -139,7 +139,7 @@ public static function input(string $buffer, TcpConnection $connection): int } else { $hasContentLength = false; if (false !== stripos($header, "\r\nTransfer-Encoding:")) { - $connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true); + $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } } From adcada7656e51429d6b1f10f200aea042c746d5e Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 2 Jul 2023 13:17:01 +0200 Subject: [PATCH 0919/1216] Rename phpunit.xml to .dist --- phpunit.xml => phpunit.xml.dist | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename phpunit.xml => phpunit.xml.dist (100%) diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 100% rename from phpunit.xml rename to phpunit.xml.dist From a2f82b502103dd38d45e8dbe4afc4098cc50eb25 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 2 Jul 2023 13:17:21 +0200 Subject: [PATCH 0920/1216] Add phpunit.xml to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f5c56bdd2..1e1ad2809 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ logs vendor/ /.vscode composer.lock +phpunit.xml From 5cf1d02d86428bd0a0aadc64b53229a6266197d8 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sun, 2 Jul 2023 13:18:22 +0200 Subject: [PATCH 0921/1216] Add tests to .gitattributes --- .gitattributes | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index f948e41e0..ab8b65906 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ -/.gitattributes export-ignore -/.github export-ignore -/.gitignore export-ignore +/.gitattributes export-ignore +/.github/ export-ignore +/.gitignore export-ignore +/phpunit.xml.dist export-ignore +/tests/ export-ignore From b62eaafd753dfccde0c13644cf4a59803e0fb2e1 Mon Sep 17 00:00:00 2001 From: Chance Date: Mon, 3 Jul 2023 17:11:35 +0800 Subject: [PATCH 0922/1216] phpstan analyse level 0 --- composer.json | 6 +++++- phpstan.neon | 25 +++++++++++++++++++++++++ src/Protocols/Http/Session.php | 2 -- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 phpstan.neon diff --git a/composer.json b/composer.json index 084d0390d..67e0c6694 100644 --- a/composer.json +++ b/composer.json @@ -44,11 +44,15 @@ "require-dev": { "pestphp/pest": "2.x-dev", "mockery/mockery": "2.0.x-dev", - "guzzlehttp/guzzle": "^7.0" + "guzzlehttp/guzzle": "^7.0", + "phpstan/phpstan": "1.11.x-dev" }, "config": { "allow-plugins": { "pestphp/pest-plugin": true } + }, + "scripts": { + "analyse": "phpstan analyse -c phpstan.neon --memory-limit=-1" } } diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..d917a8eee --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,25 @@ +parameters: + level: 0 + paths: + - src + - tests + ignoreErrors: + - + path: src/Events/Revolt.php + messages: + - '#Property Workerman\\Events\\Revolt::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' + - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' + - '#Method Workerman\\Events\\Revolt::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' + - + path: src/Events/Swow.php + messages: + - '#Used function Swow\\Sync\\waitAll not found.#' + - '#Call to static method .* on an unknown class Swow\\.*.#' + - '#Function msleep not found.#' + - '#Function stream_poll_one not found.#' + - '#Caught class Swow\\SignalException not found.#' + - '#Function Swow\\Sync\\waitAll not found.#' + - path: src/Timer.php + message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' + - path: tests/Pest.php + message: '#Undefined variable: \$this#' \ No newline at end of file diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index aa3a65a78..62dc04baa 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -17,7 +17,6 @@ namespace Workerman\Protocols\Http; use Exception; -use JetBrains\PhpStorm\ArrayShape; use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -381,7 +380,6 @@ public static function handlerClass(mixed $className = null, mixed $config = nul * * @return array */ - #[ArrayShape(['lifetime' => "int", 'path' => "string", 'domain' => "string", 'secure' => "bool", 'httponly' => "bool", 'samesite' => "string"])] public static function getCookieParams(): array { return [ From 4106df5a3c312eea83df0d400d81e75183086897 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:38:48 +0800 Subject: [PATCH 0923/1216] phpstan analyse level 1 --- phpstan.neon | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index d917a8eee..029cc4a74 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 0 + level: 1 paths: - src - tests @@ -19,7 +19,13 @@ parameters: - '#Function stream_poll_one not found.#' - '#Caught class Swow\\SignalException not found.#' - '#Function Swow\\Sync\\waitAll not found.#' + - '#Constant STREAM_POLLHUP not found.#' + - '#Constant STREAM_POLLIN not found.#' + - '#Constant STREAM_POLLNONE not found.#' + - '#Constant STREAM_POLLOUT not found.#' - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: tests/Pest.php - message: '#Undefined variable: \$this#' \ No newline at end of file + message: '#Undefined variable: \$this#' + - path: src/Worker.php + message: '#Constant LINE_VERSION_LENGTH not found.#' \ No newline at end of file From a51b271d7b5e5481853edc8f61063d26f0e3276c Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:41:02 +0800 Subject: [PATCH 0924/1216] analyse fix: Access to an undefined property --- src/Protocols/Http/Request.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 1cf9148b3..28d2ca0a1 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -98,6 +98,13 @@ class Request */ protected static bool $enableCache = true; + /** + * Session id. + * + * @var mixed|string + */ + protected mixed $sid; + /** * Request constructor. * From de778cd2bae75b7eab181450f43cf185cb586bfd Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:47:24 +0800 Subject: [PATCH 0925/1216] phpstan analyse level 2 --- phpstan.neon | 4 +++- src/Connection/TcpConnection.php | 4 ++-- src/Timer.php | 2 +- src/Worker.php | 2 -- tests/Unit/Protocols/HttpTest.php | 2 ++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 029cc4a74..70a1bc3e9 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 1 + level: 2 paths: - src - tests @@ -10,6 +10,7 @@ parameters: - '#Property Workerman\\Events\\Revolt::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - '#Method Workerman\\Events\\Revolt::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' + - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - path: src/Events/Swow.php messages: @@ -23,6 +24,7 @@ parameters: - '#Constant STREAM_POLLIN not found.#' - '#Constant STREAM_POLLNONE not found.#' - '#Constant STREAM_POLLOUT not found.#' + - '#Property Workerman\\Events\\Swow::.* has unknown class Swow\\Coroutine as its type.#' - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: tests/Pest.php diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f1d021c78..57860f64c 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -53,7 +53,7 @@ /** * TcpConnection. - * @property string websocketType + * @property string $websocketType */ class TcpConnection extends ConnectionInterface implements JsonSerializable { @@ -1033,7 +1033,7 @@ public function destroy(): void /** * Enable or disable Cache. * - * @param mixed $value + * @param bool $value */ public static function enableCache(bool $value = true): void { diff --git a/src/Timer.php b/src/Timer.php index cbed87919..c4053ed7d 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -107,7 +107,7 @@ public static function signalHandle(): void * * @param float $timeInterval * @param callable $func - * @param mixed|array $args + * @param null|array $args * @param bool $persistent * @return int */ diff --git a/src/Worker.php b/src/Worker.php index 85541161f..ae70b9564 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1972,7 +1972,6 @@ protected static function writeStatisticsToStatusFile(): void if (static::$masterPid === posix_getpid()) { $allWorkerInfo = []; foreach (static::$pidMap as $workerId => $pidArray) { - /** @var /Workerman/Worker $worker */ $worker = static::$workers[$workerId]; foreach ($pidArray as $pid) { $allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; @@ -2086,7 +2085,6 @@ protected static function writeConnectionsStatisticsToStatusFile(): void $currentWorker = current(static::$workers); $defaultWorkerName = $currentWorker->name; - /** @var static $worker */ foreach (TcpConnection::$connections as $connection) { /** @var TcpConnection $connection */ $transport = $connection->transport; diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index e34d833cf..de3cb976a 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -55,6 +55,7 @@ }); it('tests ::encode for non-object response', function () { + /** @var TcpConnection $tcpConnection */ $tcpConnection = Mockery::mock(TcpConnection::class); $tcpConnection->headers = [ 'foo' => 'bar', @@ -73,6 +74,7 @@ }); it('tests ::encode for ' . Response::class, function () { + /** @var TcpConnection $tcpConnection */ $tcpConnection = Mockery::mock(TcpConnection::class); $tcpConnection->headers = [ 'foo' => 'bar', From 0f6ed92fc3e0425684b5e8b34a3a688d37811ee1 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:49:16 +0800 Subject: [PATCH 0926/1216] analyse fix: Unsafe call to private method through static:: --- src/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index ae70b9564..9255e7a4a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1279,7 +1279,7 @@ public static function resetStd(bool $throwException = true): void } // change output stream static::$outputStream = null; - static::outputStream($STDOUT); + self::outputStream($STDOUT); restore_error_handler(); return; } @@ -2178,7 +2178,7 @@ public static function log(mixed $msg, bool $decorated = false): void */ public static function safeEcho(string $msg, bool $decorated = false): bool { - $stream = static::outputStream(); + $stream = self::outputStream(); if (!$stream) { return false; } From 683ef384ac02ef83e9c5e98fa55e2688116bb4d8 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:51:00 +0800 Subject: [PATCH 0927/1216] analyse fix: Binary operation "^" between bool|float|int|string and string results in an error --- src/Protocols/Ws.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index c19e61e2a..116d1c01d 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -233,17 +233,13 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo /** * Websocket encode. * - * @param mixed $payload + * @param string $payload * @param AsyncTcpConnection $connection * @return string * @throws Throwable */ - public static function encode(mixed $payload, AsyncTcpConnection $connection): string + public static function encode(string $payload, AsyncTcpConnection $connection): string { - if (!is_scalar($payload)) { - throw new Exception("You can't send(" . gettype($payload) . ") to client, you need to convert it to string. "); - } - if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } From 123ac8aae8ba87c66b9f0660d7615ec66b4cfe60 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 13:53:04 +0800 Subject: [PATCH 0928/1216] phpstan analyse level 3 --- phpstan.neon | 2 +- src/Worker.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 70a1bc3e9..365bab1c8 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 2 + level: 3 paths: - src - tests diff --git a/src/Worker.php b/src/Worker.php index 9255e7a4a..9bd22a900 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -166,7 +166,7 @@ class Worker /** * Emitted when data is received. * - * @var callable + * @var ?callable */ public $onMessage = null; @@ -312,7 +312,7 @@ class Worker /** * EventLoopClass * - * @var class-string + * @var string|class-string */ public static string $eventLoopClass = ''; @@ -340,7 +340,7 @@ class Worker /** * Listening socket. * - * @var resource + * @var ?resource */ protected $mainSocket = null; @@ -534,7 +534,7 @@ class Worker /** * Standard output stream - * @var resource + * @var ?resource */ protected static $outputStream = null; From d6d3df31150ab3ff6451589bb5f38dc015ded4e1 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 14:23:35 +0800 Subject: [PATCH 0929/1216] phpstan analyse level 4 --- phpstan.neon | 2 +- src/Events/Event.php | 2 ++ src/Events/Swow.php | 1 + src/Protocols/Http/Request.php | 4 ++-- src/Worker.php | 3 +++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 365bab1c8..454e059b6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 3 + level: 4 paths: - src - tests diff --git a/src/Events/Event.php b/src/Events/Event.php index fa272ce25..3f1d81b1d 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -166,6 +166,7 @@ public function onReadable($stream, callable $func): void $className = $this->eventClassName; $fdKey = (int)$stream; $event = new $this->eventClassName($this->eventBase, $stream, $className::READ | $className::PERSIST, $func, $stream); + // @phpstan-ignore-next-line Negated boolean expression is always false. if (!$event || !$event->add()) { return; } @@ -194,6 +195,7 @@ public function onWritable($stream, callable $func): void $className = $this->eventClassName; $fdKey = (int)$stream; $event = new $this->eventClassName($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func, $stream); + // @phpstan-ignore-next-line Negated boolean expression is always false. if (!$event || !$event->add()) { return; } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 9a6a2ec3e..5ac0b37b3 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -85,6 +85,7 @@ public function repeat(float $interval, callable $func, array $args = []): int $t = max($t, 1); $that = $this; $coroutine = Coroutine::run(static function () use ($t, $func, $args, $that): void { + // @phpstan-ignore-next-line While loop condition is always true. while (true) { msleep($t); try { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 28d2ca0a1..ae0ad6460 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -303,11 +303,11 @@ public function session(): Session /** * Get/Set session id. * - * @param null $sessionId + * @param string|null $sessionId * @return string * @throws Exception */ - public function sessionId($sessionId = null): string + public function sessionId(string $sessionId = null): string { if ($sessionId) { unset($this->sid); diff --git a/src/Worker.php b/src/Worker.php index 9bd22a900..c4436b392 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1686,6 +1686,7 @@ protected static function monitorWorkers(): void protected static function monitorWorkersForLinux(): void { static::$status = static::STATUS_RUNNING; + // @phpstan-ignore-next-line While loop condition is always true. while (1) { // Calls signal handlers for pending signals. pcntl_signal_dispatch(); @@ -2211,6 +2212,7 @@ private static function outputStream($stream = null) if (!$stream) { $stream = static::$outputStream ?: STDOUT; } + // @phpstan-ignore-next-line Negated boolean expression is always false. if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) { return false; } @@ -2550,6 +2552,7 @@ public function acceptUdpConnection($socket): bool if ($this->protocol !== null) { /** @var ProtocolInterface $parser */ $parser = $this->protocol; + // @phpstan-ignore-next-line Left side of && is always true. if ($parser && method_exists($parser, 'input')) { while ($recvBuffer !== '') { $len = $parser::input($recvBuffer, $connection); From c106f4c0eefa9a4369e777dcb430c4a93e18817d Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 14:32:05 +0800 Subject: [PATCH 0930/1216] analyse fix: The key 'basename' is always present in the return value of `pathinfo` --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index df16e8ec4..f54f27b04 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -401,7 +401,7 @@ protected function createHeadForFile(array $fileInfo): string $fileInfo = pathinfo($file); $extension = $fileInfo['extension'] ?? ''; - $baseName = $fileInfo['basename'] ?? 'unknown'; + $baseName = $fileInfo['basename'] ?: 'unknown'; if (!isset($headers['Content-Type'])) { if (isset(self::$mimeTypeMap[$extension])) { $head .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; From 953d40d3719f61c2a85722642c9994da5cbf4bc4 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 14:36:40 +0800 Subject: [PATCH 0931/1216] analyse fix: headers type is an array, else branch is unreachable because previous condition is always true --- src/Protocols/Ws.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 116d1c01d..7ae2e4c43 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -367,12 +367,8 @@ public static function sendHandshake(AsyncTcpConnection $connection): void $userHeader = $connection->headers ?? null; $userHeaderStr = ''; if (!empty($userHeader)) { - if (is_array($userHeader)) { - foreach ($userHeader as $k => $v) { - $userHeaderStr .= "$k: $v\r\n"; - } - } else { - $userHeaderStr .= $userHeader; + foreach ($userHeader as $k => $v) { + $userHeaderStr .= "$k: $v\r\n"; } $userHeaderStr = "\r\n" . trim($userHeaderStr); } From 21d244b6b1bc65636be62e37befab4754d1e583a Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 14:44:30 +0800 Subject: [PATCH 0932/1216] analyse fix: Offset 'running' on array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int} in isset() always exists and is not nullable --- src/Worker.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index c4436b392..9c9ffd30a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1516,14 +1516,10 @@ public static function checkWorkerStatusForWindows(): void $process = $processData[0]; $startFile = $processData[1]; $status = proc_get_status($process); - if (isset($status['running'])) { - if (!$status['running']) { - static::safeEcho("process $startFile terminated and try to restart\n"); - proc_close($process); - static::forkOneWorkerForWindows($startFile); - } - } else { - static::safeEcho("proc_get_status fail\n"); + if (!$status['running']) { + static::safeEcho("process $startFile terminated and try to restart\n"); + proc_close($process); + static::forkOneWorkerForWindows($startFile); } } } From 50f20ebd1c70bc8d67dab5de735c04515b632362 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 14:45:39 +0800 Subject: [PATCH 0933/1216] analyse fix: Dead catch - Exception is never thrown in the try block --- src/Worker.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 9c9ffd30a..0c5c9bbf8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1915,11 +1915,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void static::$workers = []; static::$globalEvent?->stop(); - try { - exit($code); - } catch (Exception $e) { - - } + exit($code); } } } From 50473063b1c41b907a6607bd6a0f6973bae326c8 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 15:07:52 +0800 Subject: [PATCH 0934/1216] phpstan analyse level 5 --- phpstan.neon | 5 +++-- tests/Feature/UdpConnectionTest.php | 2 +- tests/Unit/Protocols/HttpTest.php | 1 + tests/Unit/Protocols/TextTest.php | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 454e059b6..fad677a19 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 4 + level: 5 paths: - src - tests @@ -30,4 +30,5 @@ parameters: - path: tests/Pest.php message: '#Undefined variable: \$this#' - path: src/Worker.php - message: '#Constant LINE_VERSION_LENGTH not found.#' \ No newline at end of file + message: '#Constant LINE_VERSION_LENGTH not found.#' + - message: '#Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\): bool\)\|null,.*#' \ No newline at end of file diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 6044feffc..441528f85 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -32,7 +32,7 @@ it('tests udp connection', function () use ($serverAddress) { $socket = stream_socket_client($serverAddress, $errno, $errstr, 1); - expect($errno)->toBeInt(0); + expect($errno)->toBeInt()->toBe(0); fwrite($socket, 'xiami'); $data = fread($socket, 1024); expect($data)->toBeString('received: xiami'); diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index de3cb976a..0cd3db677 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -95,6 +95,7 @@ }); it('tests ::decode', function () { + /** @var TcpConnection $tcpConnection */ $tcpConnection = Mockery::mock(TcpConnection::class); //example request from ChatGPT :) diff --git a/tests/Unit/Protocols/TextTest.php b/tests/Unit/Protocols/TextTest.php index 769d933d1..c59d126fc 100644 --- a/tests/Unit/Protocols/TextTest.php +++ b/tests/Unit/Protocols/TextTest.php @@ -4,6 +4,7 @@ use Workerman\Protocols\Text; test(Text::class, function () { + /** @var ConnectionInterface $connection */ $connection = Mockery::mock(ConnectionInterface::class); //::input From 0a8d8c0f0444e022a39fb45561d47afb7a3ff4d4 Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 4 Jul 2023 16:20:31 +0800 Subject: [PATCH 0935/1216] ci static analysis --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b6b8355ff..7dac46bdf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,9 @@ jobs: timeout_minutes: 5 max_attempts: 5 command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress -# command: composer install --prefer-dist --no-interaction --no-progress + + - name: Static analysis + run: composer analyse - name: Execute tests run: vendor/bin/pest --coverage From 765e6971b25a5e1cb411598b8b47dd5f48a814ec Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 4 Jul 2023 13:29:22 +0200 Subject: [PATCH 0936/1216] Add PHP 8.3 nightly to tests --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b6b8355ff..510c9620a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: true matrix: - php: [8.1, 8.2] + php: ["8.1", "8.2", "8.3"] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} From 1c257f6ba57881aedc9e0b1331fbed8c7336bd83 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 4 Jul 2023 13:39:06 +0200 Subject: [PATCH 0937/1216] Add color to pest tests --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 510c9620a..63d9eca19 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,5 +44,5 @@ jobs: # command: composer install --prefer-dist --no-interaction --no-progress - name: Execute tests - run: vendor/bin/pest --coverage + run: vendor/bin/pest --coverage --colors=always From bdc3677232f975897bae66e6c65030eaed50a488 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 4 Jul 2023 14:37:17 +0200 Subject: [PATCH 0938/1216] Rename phpstan.neon to .dist --- .gitattributes | 1 + .gitignore | 1 + composer.json | 2 +- phpstan.neon => phpstan.neon.dist | 0 4 files changed, 3 insertions(+), 1 deletion(-) rename phpstan.neon => phpstan.neon.dist (100%) diff --git a/.gitattributes b/.gitattributes index ab8b65906..0859900ba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,4 @@ /.gitignore export-ignore /phpunit.xml.dist export-ignore /tests/ export-ignore +/phpstan.neon.dist export-ignore diff --git a/.gitignore b/.gitignore index 1e1ad2809..e64b947ec 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ vendor/ /.vscode composer.lock phpunit.xml +/phpstan.neon diff --git a/composer.json b/composer.json index 67e0c6694..05c171466 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,6 @@ } }, "scripts": { - "analyse": "phpstan analyse -c phpstan.neon --memory-limit=-1" + "analyse": "phpstan" } } diff --git a/phpstan.neon b/phpstan.neon.dist similarity index 100% rename from phpstan.neon rename to phpstan.neon.dist From bbd0336eef8e79cccdb61025f10a550a8bcd62e9 Mon Sep 17 00:00:00 2001 From: Chance Date: Wed, 5 Jul 2023 16:26:56 +0800 Subject: [PATCH 0939/1216] Functional test of websocket services --- tests/Feature/WebsocketServiceTest.php | 155 +++++++++++++++++++++++++ tests/Pest.php | 10 ++ 2 files changed, 165 insertions(+) create mode 100644 tests/Feature/WebsocketServiceTest.php diff --git a/tests/Feature/WebsocketServiceTest.php b/tests/Feature/WebsocketServiceTest.php new file mode 100644 index 000000000..e3d6a24f7 --- /dev/null +++ b/tests/Feature/WebsocketServiceTest.php @@ -0,0 +1,155 @@ +onWorkerStart = function(\$worker){ + \$con = new AsyncTcpConnection('ws://127.0.0.1:2000'); + %s + \$con->connect(); +}; +Worker::\$pidFile = __DIR__ . '/WebsocketClient.pid'; +Worker::\$command = 'start'; +Worker::runAll(); +PHP; + +it('tests websocket connection', function () use ($serverCode, $clientCode) { + $serverProcess = new PhpProcess(sprintf($serverCode, <<onWebSocketConnect = function () { + echo "connected"; + }; + \$worker->onMessage = function () {}; + PHP + )); + $serverProcess->start(); + sleep(1); + + $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { + \$con->send('connect'); + }; + PHP + )); + $clientProcess->start(); + sleep(1); + + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('connected') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe(''); + + $serverProcess->stop(); + $clientProcess->stop(); +}); + +it('tests server and client sending and receiving messages', function () use ($serverCode, $clientCode) { + $serverProcess = new PhpProcess(sprintf($serverCode, <<onMessage = function (TcpConnection \$connection, \$data) { + echo \$data; + \$connection->send('Hi'); + }; + PHP + )); + $serverProcess->start(); + sleep(1); + + $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { + \$con->send('Hello Chance'); + }; + \$con->onMessage = function(\$con, \$data) { + echo \$data; + }; + PHP + )); + $clientProcess->start(); + sleep(1); + + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('Hello Chance') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('Hi'); + + $serverProcess->stop(); + $clientProcess->stop(); +}); + +it('tests server close connection', function () use ($serverCode, $clientCode) { + $serverProcess = new PhpProcess(sprintf($serverCode, <<onWebSocketConnect = function (TcpConnection \$connection) { + echo 'close connection'; + \$connection->close(); + }; + \$worker->onMessage = function () {}; + PHP + )); + $serverProcess->start(); + sleep(1); + + $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { + \$con->send('connect'); + }; + \$con->onClose = function () { + echo 'closed'; + }; + PHP + )); + $clientProcess->start(); + sleep(1); + + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('close connection') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('closed'); + + $serverProcess->stop(); + $clientProcess->stop(); +}); + +it('tests client close connection', function () use ($serverCode, $clientCode) { + $serverProcess = new PhpProcess(sprintf($serverCode, <<onMessage = function () {}; + \$worker->onClose = function () { + echo 'closed'; + }; + PHP + )); + $serverProcess->start(); + sleep(1); + + $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { + \$con->send('connect'); + echo 'close connection'; + \$con->close(); + }; + PHP + )); + $clientProcess->start(); + sleep(1); + + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('closed') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('close connection'); + + $serverProcess->stop(); + $clientProcess->stop(); +}); diff --git a/tests/Pest.php b/tests/Pest.php index ccf40d3bf..19f6fad10 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -58,3 +58,13 @@ function testWithConnectionClose(Closure $closure, string $dataContains = null, $tcpConnection->shouldHaveReceived('close'); } } + +function getNonFrameOutput(string $output): string +{ + $end = "Start success.\n"; + $pos = strpos($output, $end); + if ($pos !== false) { + return substr($output, $pos + strlen($end)); + } + return $output; +} From 975d94a9091e0d33c33356af00b8b48bcbb43170 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Thu, 6 Jul 2023 17:40:39 +0200 Subject: [PATCH 0940/1216] Small changes --- src/Connection/TcpConnection.php | 3 ++- src/Events/Select.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 57860f64c..edc93cc56 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -819,7 +819,8 @@ public function doSslHandshake($socket): bool|int if (false === $ret) { $this->destroy(); return false; - } elseif (0 === $ret) { + } + if (0 === $ret) { // There isn't enough data and should try again. return 0; } diff --git a/src/Events/Select.php b/src/Events/Select.php index a919809d2..5e33b5067 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -116,7 +116,7 @@ class Select implements EventInterface /** * @var ?callable */ - protected $errorHandler = null; + protected $errorHandler; /** * Construct. @@ -276,7 +276,7 @@ public function onSignal(int $signal, callable $func): void return; } $this->signalEvents[$signal] = $func; - pcntl_signal($signal, [$this, 'signalHandler']); + pcntl_signal($signal, $this->signalHandler(...)); } /** From db69c8afbe531b6f2e50b0b8b64081011cfeffa5 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Thu, 6 Jul 2023 17:42:06 +0200 Subject: [PATCH 0941/1216] Fix typo --- .github/workflows/test.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12fbac7da..2abb2de16 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,7 +43,7 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress - name: Static analysis - run: composer analyse + run: composer analyze - name: Execute tests run: vendor/bin/pest --coverage --colors=always diff --git a/composer.json b/composer.json index 05c171466..fab158922 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,6 @@ } }, "scripts": { - "analyse": "phpstan" + "analyze": "phpstan" } } From 2bd8e3bb281ea904258a01292617a16139005ff2 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 8 Jul 2023 14:55:50 +0200 Subject: [PATCH 0942/1216] Disable fail-fast in GH actions --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2abb2de16..4a0ca49b0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-22.04 strategy: - fail-fast: true + fail-fast: false matrix: php: ["8.1", "8.2", "8.3"] stability: [prefer-lowest, prefer-stable] From 8b52773e94d95411724326f42ab4504a52fd79f8 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 10 Jul 2023 13:38:54 +0200 Subject: [PATCH 0943/1216] Add $_FILES['full_path'] --- src/Protocols/Http/Request.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ae0ad6460..f4ca9566c 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -593,6 +593,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } [$key, $value] = explode(': ', $contentLine); switch (strtolower($key)) { + case "content-disposition": // Is file data. if (preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) { @@ -613,7 +614,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS } $uploadKey = $fileName; // Parse upload files. - $file = [...$file, 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error]; + $file = [...$file, 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error, 'full_path' => $match[2]]; if (!isset($file['type'])) { $file['type'] = ''; } @@ -626,9 +627,14 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS $postEncodeString .= urlencode($k) . "=" . urlencode($boundaryValue) . '&'; } return $sectionEndOffset + strlen($boundary) + 2; + case "content-type": $file['type'] = trim($value); break; + + case "webkitRelativePath": + $file['full_path'] = \trim($value); + break; } } if ($uploadKey === false) { From 4fb74f9949f7f69b498fc8f3d5d5ab1497ffd7f7 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 10 Jul 2023 13:42:49 +0200 Subject: [PATCH 0944/1216] Use lower case $key --- src/Events/EventInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 0897a8231..0dc83f656 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -21,7 +21,7 @@ interface EventInterface * Delay the execution of a callback. * @param float $delay * @param callable $func - * @param array $args + * @param mixed[] $args * @return int */ public function delay(float $delay, callable $func, array $args = []): int; @@ -37,7 +37,7 @@ public function offDelay(int $timerId): bool; * Repeatedly execute a callback. * @param float $interval * @param callable $func - * @param array $args + * @param mixed[] $args * @return int */ public function repeat(float $interval, callable $func, array $args = []): int; From b7164358c5af95844cd86779c4e5f6a25877183b Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 10 Jul 2023 13:44:02 +0200 Subject: [PATCH 0945/1216] Use lowercase $key --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index f4ca9566c..4e3502b2a 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -632,7 +632,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS $file['type'] = trim($value); break; - case "webkitRelativePath": + case "webkitrelativepath": $file['full_path'] = \trim($value); break; } From a6a084098640876ea8d4bee96a1bba23f531e6a3 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Fri, 14 Jul 2023 02:16:24 +0200 Subject: [PATCH 0946/1216] Use Stringable --- src/Protocols/Http/Chunk.php | 6 ++++-- src/Protocols/Http/Request.php | 5 +++-- src/Protocols/Http/Response.php | 6 ++++-- src/Protocols/Http/ServerSentEvents.php | 6 ++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 619d622c9..f9a7394d7 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -16,6 +16,8 @@ namespace Workerman\Protocols\Http; +use Stringable; + use function dechex; use function strlen; @@ -23,7 +25,7 @@ * Class Chunk * @package Workerman\Protocols\Http */ -class Chunk +class Chunk implements Stringable { /** * Chunk buffer. @@ -47,7 +49,7 @@ public function __construct(string $buffer) * * @return string */ - public function __toString() + public function __toString(): string { return dechex(strlen($this->buffer)) . "\r\n$this->buffer\r\n"; } diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 4e3502b2a..1f40b691c 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -18,6 +18,7 @@ use Exception; use RuntimeException; +use Stringable; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http; use function array_walk_recursive; @@ -49,7 +50,7 @@ * Class Request * @package Workerman\Protocols\Http */ -class Request +class Request implements Stringable { /** * Connection. @@ -680,7 +681,7 @@ protected function setSidCookie(string $sessionName, string $sid, array $cookieP /** * __toString. */ - public function __toString() + public function __toString(): string { return $this->buffer; } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index f54f27b04..9ec9ec75c 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -16,6 +16,8 @@ namespace Workerman\Protocols\Http; +use Stringable; + use function array_merge_recursive; use function explode; use function file; @@ -35,7 +37,7 @@ * Class Response * @package Workerman\Protocols\Http */ -class Response +class Response implements Stringable { /** * Header data. @@ -426,7 +428,7 @@ protected function createHeadForFile(array $fileInfo): string * * @return string */ - public function __toString() + public function __toString(): string { if ($this->file) { return $this->createHeadForFile($this->file); diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index e740be9a2..ad4a4ffa4 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -16,13 +16,15 @@ namespace Workerman\Protocols\Http; +use Stringable; + use function str_replace; /** * Class ServerSentEvents * @package Workerman\Protocols\Http */ -class ServerSentEvents +class ServerSentEvents implements Stringable { /** * Data. @@ -45,7 +47,7 @@ public function __construct(array $data) * * @return string */ - public function __toString() + public function __toString(): string { $buffer = ''; $data = $this->data; From 1fa2c3308d4b1897e9debc393e66f76b51b43eb1 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 19 Jul 2023 20:06:58 +0800 Subject: [PATCH 0947/1216] check isSafe when __destruct --- src/Protocols/Http/Request.php | 20 +++++++++++++++++++- src/Protocols/Http/Session.php | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 1f40b691c..6970f6e0e 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -92,6 +92,13 @@ class Request implements Stringable */ protected array $data = []; + /** + * Is safe. + * + * @var bool + */ + protected $isSafe = true; + /** * Enable cache. * @@ -731,6 +738,17 @@ public function __unset(string $name) unset($this->properties[$name]); } + + /** + * __wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->isSafe = false; + } + /** * __destruct. * @@ -738,7 +756,7 @@ public function __unset(string $name) */ public function __destruct() { - if (isset($this->data['files'])) { + if (isset($this->data['files']) && $this->isSafe) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { if ($key === 'tmp_name' && is_file($value)) { diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 62dc04baa..e7dec8233 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -148,6 +148,13 @@ class Session */ protected string $sessionId; + /** + * Is safe. + * + * @var bool + */ + protected $isSafe = true; + /** * Session constructor. * @@ -416,6 +423,16 @@ public function gc(): void static::$handler->gc(static::$lifetime); } + /** + * __wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->isSafe = false; + } + /** * __destruct. * @@ -424,6 +441,9 @@ public function gc(): void */ public function __destruct() { + if (!$this->isSafe) { + return; + } $this->save(); if (random_int(1, static::$gcProbability[1]) <= static::$gcProbability[0]) { $this->gc(); From 2f2675104fb978c771266e7c0cd39f870376ea14 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 19 Jul 2023 20:13:58 +0800 Subject: [PATCH 0948/1216] allowed_classes options for unserialize --- src/Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 0c5c9bbf8..35d7d488e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1065,7 +1065,9 @@ protected static function formatStatusData($statisticsFile): string } $statusStr = ''; $currentTotalRequest = []; - $workerInfo = unserialize($info[0]); + try { + $workerInfo = unserialize($info[0], ['allowed_classes' => false]); + } catch (Throwable $exception) {} ksort($workerInfo, SORT_NUMERIC); unset($info[0]); $dataWaitingSort = []; From 20681c27f42b4f41c491c69e1e49acb9c6808143 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 27 Jul 2023 15:31:46 +0800 Subject: [PATCH 0949/1216] Update Worker.php --- src/Worker.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 35d7d488e..bf89da2ee 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -49,7 +49,7 @@ class Worker * * @var string */ - public const VERSION = '5.0.0-beta.6'; + public const VERSION = '5.0.0-beta.7'; /** * Status starting. @@ -1441,6 +1441,9 @@ protected static function forkWorkersForWindows(): void restore_error_handler(); + // Add an empty timer to prevent the event-loop from exiting. + Timer::add(1000000, function (){}); + // Display UI. static::safeEcho(str_pad($worker->name, 48) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . " [ok]\n"); $worker->listen(); From b1f8c5a58640f17fe6acb59081e488a9b4f5e896 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 27 Jul 2023 15:34:23 +0800 Subject: [PATCH 0950/1216] Update Worker.php --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index bf89da2ee..f242b1462 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1065,6 +1065,7 @@ protected static function formatStatusData($statisticsFile): string } $statusStr = ''; $currentTotalRequest = []; + $workerInfo = []; try { $workerInfo = unserialize($info[0], ['allowed_classes' => false]); } catch (Throwable $exception) {} From 5d9e576a9fe5bfc1060f1ac6a46bb5fbe03b9f97 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Aug 2023 11:36:46 +0800 Subject: [PATCH 0951/1216] Support sapi micro --- src/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index f242b1462..aac6d7797 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -581,8 +581,8 @@ public static function runAll(): void */ protected static function checkSapiEnv(): void { - // Only for cli. - if (PHP_SAPI !== 'cli') { + // Only for cli and micro. + if (!in_array(\PHP_SAPI, ['cli', 'micro'])) { exit("Only run in command line mode \n"); } } From 0d011e3b1a7eed9b52ba24764c9ff8e8bd120a24 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 17:08:07 +0200 Subject: [PATCH 0952/1216] Show Workerman info in tests --- tests/Feature/HttpConnectionTest.php | 1 + tests/Feature/UdpConnectionTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Feature/HttpConnectionTest.php b/tests/Feature/HttpConnectionTest.php index fa71e0ef2..de2063833 100644 --- a/tests/Feature/HttpConnectionTest.php +++ b/tests/Feature/HttpConnectionTest.php @@ -14,6 +14,7 @@ }); afterAll(function () use (&$process) { + echo $process->getOutput(); $process->stop(); }); diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 441528f85..3bbd37681 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -27,6 +27,7 @@ }); afterAll(function () use (&$process) { + echo "\nUDP Test:\n", $process->getOutput(); $process->stop(); }); From 33ea3fe930aaa64178bbd289d027e39e2293ccfc Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 17:14:56 +0200 Subject: [PATCH 0953/1216] Add Windows and Mac Os to tests --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a0ca49b0..62ad2cf42 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,10 +17,11 @@ jobs: strategy: fail-fast: false matrix: + os: [ubuntu-latest, macos-latest, windows-latest] php: ["8.1", "8.2", "8.3"] stability: [prefer-lowest, prefer-stable] - name: PHP ${{ matrix.php }} - ${{ matrix.stability }} + name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code From 27096b3e54d9a3dfcc6e82d3070e19eeae5b009b Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 17:22:12 +0200 Subject: [PATCH 0954/1216] Small change to rerun tests --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 62ad2cf42..91a108b8d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -48,4 +48,3 @@ jobs: - name: Execute tests run: vendor/bin/pest --coverage --colors=always - From fb0df80dbb64514b2f0db5fa620c663f62f8d762 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 17:35:18 +0200 Subject: [PATCH 0955/1216] Change runner OS --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 91a108b8d..de3c0f2fb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ on: jobs: linux_tests: - runs-on: ubuntu-22.04 + runs-on: ${{ matrix.os }} strategy: fail-fast: false From a97f5cabf98cb489a1dc81e841f64628e823d85c Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 20:23:53 +0200 Subject: [PATCH 0956/1216] Inform why we skip test in windows --- tests/Feature/UdpConnectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index 441528f85..d78d8257b 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -38,4 +38,4 @@ expect($data)->toBeString('received: xiami'); fclose($socket); }) - ->skipOnWindows(); //require posix + ->skipOnWindows('require posix'); //require posix From 5bcf904e79b49684ca2dd5c1ad1d1364a7031bb7 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Sat, 19 Aug 2023 20:27:23 +0200 Subject: [PATCH 0957/1216] Revert last commit --- tests/Feature/UdpConnectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index d78d8257b..441528f85 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -38,4 +38,4 @@ expect($data)->toBeString('received: xiami'); fclose($socket); }) - ->skipOnWindows('require posix'); //require posix + ->skipOnWindows(); //require posix From db8ca2469632bd35fb717b0d9ba9bb3deaaed20e Mon Sep 17 00:00:00 2001 From: twomiao <995200452@qq.com> Date: Sun, 10 Sep 2023 17:06:45 +0800 Subject: [PATCH 0958/1216] Fixed: Graceful stop and Standardized code format --- src/Worker.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index aac6d7797..02e32bb72 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1003,7 +1003,7 @@ protected static function parseCommand(): void $masterIsAlive = $masterPid && posix_kill($masterPid, 0); if ($masterIsAlive) { // Timeout? - if (!static::$gracefulStop && time() - $startTime >= $timeout) { + if (!static::getGracefulStop() && time() - $startTime >= $timeout) { static::log("Workerman[$startFile] stop fail"); exit; } @@ -1799,7 +1799,7 @@ protected static function reload(): void { // For master process. if (static::$masterPid === posix_getpid()) { - $sig = static::$gracefulStop ? SIGUSR2 : SIGUSR1; + $sig = static::getGracefulStop() ? SIGUSR2 : SIGUSR1; // Set reloading state. if (static::$status !== static::STATUS_RELOADING && static::$status !== static::STATUS_SHUTDOWN) { static::log("Workerman[" . basename(static::$startFile) . "] reloading"); @@ -1847,7 +1847,7 @@ protected static function reload(): void // Send reload signal to a worker process. posix_kill($oneWorkerPid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. - if (!static::$gracefulStop) { + if (!static::getGracefulStop()) { Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, SIGKILL], false); } } // For child processes. @@ -1890,7 +1890,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void static::log("Workerman[" . basename(static::$startFile) . "] stopping ..."); $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. - $sig = static::$gracefulStop ? SIGQUIT : SIGINT; + $sig = static::getGracefulStop() ? SIGQUIT : SIGINT; foreach ($workerPidArray as $workerPid) { // Fix exit with status 2 for php8.2 if ($sig === SIGINT && !static::$daemonize) { @@ -1898,7 +1898,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void } else { posix_kill($workerPid, $sig); } - if (!static::$gracefulStop) { + if (!static::getGracefulStop()) { Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, SIGKILL], false); } } @@ -1917,7 +1917,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void $worker->stopping = true; } } - if (!static::$gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) { + if (!static::getGracefulStop() || ConnectionInterface::$statistics['connection_count'] <= 0) { static::$workers = []; static::$globalEvent?->stop(); @@ -2468,7 +2468,7 @@ public function stop(): void // Remove listener for server socket. $this->unlisten(); // Close all connections for the worker. - if (static::$gracefulStop) { + if (!static::getGracefulStop()) { foreach ($this->connections as $connection) { $connection->close(); } From 9fcf04bb19df83bee4d222389edf700ebb40cb5b Mon Sep 17 00:00:00 2001 From: twomiao <995200452@qq.com> Date: Thu, 5 Oct 2023 00:23:11 +0800 Subject: [PATCH 0959/1216] Fixed bug: onWorkerStop cannot be triggered. --- src/Worker.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 02e32bb72..6fa5a8b8b 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -36,6 +36,7 @@ use function stream_socket_accept; use function stream_socket_recvfrom; use function substr; +use function array_walk; /** * Worker class @@ -1165,7 +1166,7 @@ protected static function reinstallSignal(): void } $signals = [SIGINT, SIGTERM, SIGHUP, SIGTSTP, SIGQUIT, SIGUSR1, SIGUSR2, SIGIOT, SIGIO]; foreach ($signals as $signal) { - pcntl_signal($signal, SIG_IGN, false); + // Rewrite master process signal. static::$globalEvent->onSignal($signal, [static::class, 'signalHandler']); } } @@ -1801,7 +1802,7 @@ protected static function reload(): void if (static::$masterPid === posix_getpid()) { $sig = static::getGracefulStop() ? SIGUSR2 : SIGUSR1; // Set reloading state. - if (static::$status !== static::STATUS_RELOADING && static::$status !== static::STATUS_SHUTDOWN) { + if (static::$status === static::STATUS_RUNNING) { static::log("Workerman[" . basename(static::$startFile) . "] reloading"); static::$status = static::STATUS_RELOADING; @@ -1911,17 +1912,18 @@ public static function stopAll(int $code = 0, mixed $log = ''): void else { // Execute exit. $workers = array_reverse(static::$workers); - foreach ($workers as $worker) { - if (!$worker->stopping) { - $worker->stop(); - $worker->stopping = true; - } - } + array_walk($workers, static fn (Worker $worker) => $worker->stop()); + if (!static::getGracefulStop() || ConnectionInterface::$statistics['connection_count'] <= 0) { static::$workers = []; static::$globalEvent?->stop(); - exit($code); + try { + // Ignore Swoole ExitException: Swoole exit. + exit($code); + } catch(\Exception $e) { + + } } } } @@ -2457,6 +2459,9 @@ public function run(): void */ public function stop(): void { + if ($this->stopping === true) { + return; + } // Try to emit onWorkerStop callback. if ($this->onWorkerStop) { try { @@ -2481,6 +2486,7 @@ public function stop(): void } // Clear callback. $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; + $this->stopping = true; } /** From 825e6dd5fa6fa7307a78700eb936216ea6d0c163 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Oct 2023 09:31:54 +0800 Subject: [PATCH 0960/1216] Update test.yml --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de3c0f2fb..91a108b8d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ on: jobs: linux_tests: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-22.04 strategy: fail-fast: false From 06d3a6d75970e0cb05aaa38c5ecd7ed51340c82e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 5 Oct 2023 09:34:36 +0800 Subject: [PATCH 0961/1216] Update Worker.php --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index 6fa5a8b8b..39262277e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1921,6 +1921,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void try { // Ignore Swoole ExitException: Swoole exit. exit($code); + /** @phpstan-ignore-next-line */ } catch(\Exception $e) { } From d9e2be02ac0030d80b1cea52761111841ecde88f Mon Sep 17 00:00:00 2001 From: twomiao <995200452@qq.com> Date: Sat, 7 Oct 2023 20:21:45 +0800 Subject: [PATCH 0962/1216] Updated Swoole TcpConnection --- src/Connection/TcpConnection.php | 10 ++++++++-- src/Events/Swoole.php | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index edc93cc56..019f3d231 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -22,6 +22,7 @@ use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; + use function ceil; use function count; use function fclose; @@ -45,6 +46,7 @@ use function strrpos; use function substr; use function var_export; + use const PHP_INT_MAX; use const STREAM_CRYPTO_METHOD_SSLv23_CLIENT; use const STREAM_CRYPTO_METHOD_SSLv23_SERVER; @@ -352,7 +354,7 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd $this->maxPackageSize = self::$defaultMaxPackageSize; $this->remoteAddress = $remoteAddress; static::$connections[$this->id] = $this; - $this->context = new stdClass; + $this->context = new stdClass(); } /** @@ -388,7 +390,11 @@ public function send(mixed $sendBuffer, bool $raw = false) if (false === $raw && $this->protocol !== null) { /** @var ProtocolInterface $parser */ $parser = $this->protocol; - $sendBuffer = $parser::encode($sendBuffer, $this); + try { + $sendBuffer = $parser::encode($sendBuffer, $this); + } catch(\Throwable $e) { + $this->error($e); + } if ($sendBuffer === '') { return; } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index a951efc7b..ff2cf24bf 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -196,12 +196,12 @@ public function onSignal(int $signal, callable $func): void } /** + * Please see https://wiki.swoole.com/#/process/process?id=signal * {@inheritdoc} */ public function offSignal(int $signal): bool { - return Process::signal($signal, function () { - }); + return Process::signal($signal, null); } /** From db19df0ff95e71564415dad3210e689a613668fd Mon Sep 17 00:00:00 2001 From: Linfly <45063822+imlinfly@users.noreply.github.com> Date: Thu, 12 Oct 2023 00:23:45 +0800 Subject: [PATCH 0963/1216] Update Event.php --- src/Events/Event.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index 3f1d81b1d..9534b8a78 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -102,7 +102,8 @@ public function delay(float $delay, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; - $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args) { + $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args, $timerId) { + unset($this->eventTimer[$timerId]); try { $func(...$args); } catch (Throwable $e) { From e1c95e047c9a448e64a521125514d0c421f6a25b Mon Sep 17 00:00:00 2001 From: twomiao <995200452@qq.com> Date: Sun, 15 Oct 2023 00:06:10 +0800 Subject: [PATCH 0964/1216] Update worker --- src/Events/Swoole.php | 12 ++---------- src/Worker.php | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ff2cf24bf..1e2c9eea0 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -45,16 +45,6 @@ class Swoole implements EventInterface */ protected $errorHandler = null; - /** - * Construct - */ - public function __construct() - { - // Avoid process exit due to no listening - Timer::tick(100000000, function () { - }); - } - /** * {@inheritdoc} * @throws Throwable @@ -219,6 +209,8 @@ public function deleteAllTimer(): void */ public function run(): void { + // Avoid process exit due to no listening + Timer::tick(100000000, static fn() => null); Event::wait(); } diff --git a/src/Worker.php b/src/Worker.php index 39262277e..087e47584 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -37,6 +37,7 @@ use function stream_socket_recvfrom; use function substr; use function array_walk; +use function get_class; /** * Worker class @@ -627,6 +628,9 @@ protected static function init(): void // State. static::$status = static::STATUS_STARTING; + // Avoiding incorrect user calls. + // static::resetGlobalEvent(); + // For statistics. static::$globalStatistics['start_timestamp'] = time(); @@ -640,6 +644,20 @@ protected static function init(): void Timer::init(); } + /** + * reset globalEvent Instance. + * + * @return void + */ + protected static function resetGlobalEvent(): void + { + if (static::$status === static::STATUS_STARTING && + static::$globalEvent instanceof EventInterface) { + static::$eventLoopClass = get_class(static::$globalEvent); + static::$globalEvent = null; + } + } + /** * Lock. * @@ -1822,15 +1840,11 @@ protected static function reload(): void foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if ($worker->reloadable) { - foreach ($workerPidArray as $pid) { - $reloadablePidArray[$pid] = $pid; - } - } else { - foreach ($workerPidArray as $pid) { - // Send reload signal to a worker process which reloadable is false. - posix_kill($pid, $sig); - } + $reloadablePidArray += $workerPidArray; + continue; } + // Send reload signal to a worker process which reloadable is false. + array_walk($workerPidArray, static fn ($pid) => posix_kill($pid, $sig)); } // Get all pids that are waiting reload. static::$pidsToRestart = array_intersect(static::$pidsToRestart, $reloadablePidArray); From 74e8dfb764507bfb0216243219be7a243d22c75c Mon Sep 17 00:00:00 2001 From: twomiao <995200452@qq.com> Date: Sun, 15 Oct 2023 00:15:14 +0800 Subject: [PATCH 0965/1216] Update worker --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 087e47584..120ffe86e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -629,7 +629,7 @@ protected static function init(): void static::$status = static::STATUS_STARTING; // Avoiding incorrect user calls. - // static::resetGlobalEvent(); + static::resetGlobalEvent(); // For statistics. static::$globalStatistics['start_timestamp'] = time(); From c445ca7a691db2997dbe1fac5ffd2640639fd4ed Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 30 Oct 2023 18:00:26 +0800 Subject: [PATCH 0966/1216] Replaced all old style callables to new first class callable syntax --- src/Connection/AsyncTcpConnection.php | 16 ++- src/Connection/AsyncUdpConnection.php | 3 +- src/Connection/ConnectionInterface.php | 1 - src/Connection/TcpConnection.php | 13 ++- src/Events/Select.php | 1 - src/Events/Swoole.php | 1 - src/Protocols/Http.php | 5 +- src/Protocols/Http/Response.php | 2 +- .../Session/RedisClusterSessionHandler.php | 1 - src/Protocols/Websocket.php | 1 - src/Timer.php | 2 +- src/Worker.php | 106 ++++++++---------- 12 files changed, 68 insertions(+), 84 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 29a7e602d..79be70dbc 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -53,7 +53,7 @@ class AsyncTcpConnection extends TcpConnection /** * PHP built-in protocols. * - * @var array + * @var array */ public const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', @@ -230,7 +230,7 @@ public function reconnect(int $after = 0): void Timer::del($this->reconnectTimer); } if ($after > 0) { - $this->reconnectTimer = Timer::add($after, [$this, 'connect'], null, false); + $this->reconnectTimer = Timer::add($after, $this->connect(...), null, false); return; } $this->connect(); @@ -302,10 +302,10 @@ public function connect(): void return; } // Add socket to global event loop waiting connection is successfully established or failed. - $this->eventLoop->onWritable($this->socket, [$this, 'checkConnection']); + $this->eventLoop->onWritable($this->socket, $this->checkConnection(...)); // For windows. if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'onExcept')) { - $this->eventLoop->onExcept($this->socket, [$this, 'checkConnection']); + $this->eventLoop->onExcept($this->socket, $this->checkConnection(...)); } } @@ -402,11 +402,11 @@ public function checkConnection(): void } else { // There are some data waiting to send. if ($this->sendBuffer) { - $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, $this->baseWrite(...)); } } // Register a listener waiting read event. - $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); $this->status = self::STATUS_ESTABLISHED; $this->remoteAddress = $address; @@ -422,13 +422,12 @@ public function checkConnection(): void // Try to emit protocol::onConnect if ($this->protocol && method_exists($this->protocol, 'onConnect')) { try { - [$this->protocol, 'onConnect']($this); + $this->protocol->onConnect($this); } catch (Throwable $e) { $this->error($e); } } } else { - // Connection failed. $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(microtime(true) - $this->connectStartTime, 4) . ' seconds'); if ($this->status === self::STATUS_CLOSING) { @@ -438,6 +437,5 @@ public function checkConnection(): void $this->onConnect = null; } } - } } diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index a5e5972df..dfed54fd3 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -202,7 +202,7 @@ public function connect(): void stream_set_blocking($this->socket, false); if ($this->onMessage) { - $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); } $this->connected = true; // Try to emit onConnect callback. @@ -214,5 +214,4 @@ public function connect(): void } } } - } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index ca1fc44cb..cee7d1044 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -188,5 +188,4 @@ public function error(Throwable $exception): void throw $exception; } } - } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 019f3d231..f03598c0b 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -349,7 +349,7 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd stream_set_read_buffer($this->socket, 0); } $this->eventLoop = $eventLoop; - $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; $this->remoteAddress = $remoteAddress; @@ -415,7 +415,7 @@ public function send(mixed $sendBuffer, bool $raw = false) // Attempt to send data directly. if ($this->sendBuffer === '') { if ($this->transport === 'ssl') { - $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, $this->baseWrite(...)); $this->sendBuffer = $sendBuffer; $this->checkBufferWillFull(); return; @@ -451,7 +451,7 @@ public function send(mixed $sendBuffer, bool $raw = false) } $this->sendBuffer = $sendBuffer; } - $this->eventLoop->onWritable($this->socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($this->socket, $this->baseWrite(...)); // Check if send buffer will be full. $this->checkBufferWillFull(); return; @@ -587,7 +587,7 @@ public function pauseRecv(): void public function resumeRecv(): void { if ($this->isPaused === true) { - $this->eventLoop->onReadable($this->socket, [$this, 'baseRead']); + $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); $this->isPaused = false; $this->baseRead($this->socket, false); } @@ -610,7 +610,7 @@ public function baseRead($socket, bool $checkEof = true): void if ($this->doSslHandshake($socket)) { $this->sslHandshakeCompleted = true; if ($this->sendBuffer) { - $this->eventLoop->onWritable($socket, [$this, 'baseWrite']); + $this->eventLoop->onWritable($socket, $this->baseWrite(...)); } } else { return; @@ -621,6 +621,7 @@ public function baseRead($socket, bool $checkEof = true): void try { $buffer = @fread($socket, self::READ_BUFFER_SIZE); } catch (Throwable) { + // do nothing } // Check connection closed. @@ -1018,7 +1019,7 @@ public function destroy(): void // Try to emit protocol::onClose if ($this->protocol && method_exists($this->protocol, 'onClose')) { try { - ([$this->protocol, 'onClose'])($this); + $this->protocol->onClose($this); } catch (Throwable $e) { $this->error($e); } diff --git a/src/Events/Select.php b/src/Events/Select.php index 5e33b5067..4998f32ba 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -469,5 +469,4 @@ public function error(Throwable $e): void } ($this->errorHandler)($e); } - } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 1e2c9eea0..64e6d1e3e 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -263,5 +263,4 @@ public function error(Throwable $e): void } ($this->errorHandler)($e); } - } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index bd76a9393..62a42482c 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -123,9 +123,8 @@ public static function input(string $buffer, TcpConnection $connection): int } $header = substr($buffer, 0, $crlfPos); - $hostHeaderPosition = stripos($header, "\r\nHost: "); - if (false === $hostHeaderPosition && $firstLine[2] === "HTTP/1.1") { + if (!str_contains($header, "\r\nHost: ") && $firstLine[2] === "HTTP/1.1") { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } @@ -138,7 +137,7 @@ public static function input(string $buffer, TcpConnection $connection): int $hasContentLength = true; } else { $hasContentLength = false; - if (false !== stripos($header, "\r\nTransfer-Encoding:")) { + if (str_contains($header, "\r\nTransfer-Encoding:")) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 9ec9ec75c..7a4c9e2f4 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -90,7 +90,7 @@ class Response implements Stringable /** * Phrases. * - * @var array + * @var array * * @link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 68d371638..685dc0334 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -52,5 +52,4 @@ public function read(string $sessionId): string { return $this->redis->get($sessionId); } - } diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 5b63b6d02..00f5a3776 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -432,5 +432,4 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); return 0; } - } diff --git a/src/Timer.php b/src/Timer.php index c4053ed7d..3398b40e2 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -85,7 +85,7 @@ public static function init(EventInterface $event = null): void return; } if (function_exists('pcntl_signal')) { - pcntl_signal(SIGALRM, ['\Workerman\Timer', 'signalHandle'], false); + pcntl_signal(SIGALRM, self::signalHandle(...), false); } } diff --git a/src/Worker.php b/src/Worker.php index 120ffe86e..d8d9be51a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -328,6 +328,7 @@ class Worker /** * Command + * * @var string */ public static string $command = ''; @@ -356,6 +357,7 @@ class Worker /** * parse from socketName avoid parse again in master or worker * LocalSocket The format is like tcp://0.0.0.0:8080 + * * @var ?string */ protected ?string $localSocket = null; @@ -495,7 +497,7 @@ class Worker /** * PHP built-in protocols. * - * @var array + * @var array */ public const BUILD_IN_TRANSPORTS = [ 'tcp' => 'tcp', @@ -507,7 +509,7 @@ class Worker /** * PHP built-in error types. * - * @var array + * @var array */ public const ERROR_TYPE = [ E_ERROR => 'E_ERROR', // 1 @@ -585,7 +587,7 @@ protected static function checkSapiEnv(): void { // Only for cli and micro. if (!in_array(\PHP_SAPI, ['cli', 'micro'])) { - exit("Only run in command line mode \n"); + exit("Only run in command line mode\n"); } } @@ -651,8 +653,7 @@ protected static function init(): void */ protected static function resetGlobalEvent(): void { - if (static::$status === static::STATUS_STARTING && - static::$globalEvent instanceof EventInterface) { + if (static::$status === static::STATUS_STARTING && static::$globalEvent instanceof EventInterface) { static::$eventLoopClass = get_class(static::$globalEvent); static::$globalEvent = null; } @@ -755,9 +756,10 @@ public static function getEventLoop(): EventInterface /** * Get main socket resource + * * @return resource */ - public function getMainSocket() + public function getMainSocket(): mixed { return $this->mainSocket; } @@ -1069,10 +1071,10 @@ public static function getArgv(): array /** * Format status data. * - * @param $statisticsFile + * @param string $statisticsFile * @return string */ - protected static function formatStatusData($statisticsFile): string + protected static function formatStatusData(string $statisticsFile): string { static $totalRequestCache = []; if (!is_readable($statisticsFile)) { @@ -1087,7 +1089,9 @@ protected static function formatStatusData($statisticsFile): string $workerInfo = []; try { $workerInfo = unserialize($info[0], ['allowed_classes' => false]); - } catch (Throwable $exception) {} + } catch (Throwable) { + // do nothing + } ksort($workerInfo, SORT_NUMERIC); unset($info[0]); $dataWaitingSort = []; @@ -1152,7 +1156,6 @@ protected static function formatStatusData($statisticsFile): string return $statusStr; } - /** * Install signal handler. * @@ -1165,7 +1168,7 @@ protected static function installSignal(): void } $signals = [SIGINT, SIGTERM, SIGHUP, SIGTSTP, SIGQUIT, SIGUSR1, SIGUSR2, SIGIOT, SIGIO]; foreach ($signals as $signal) { - pcntl_signal($signal, [static::class, 'signalHandler'], false); + pcntl_signal($signal, static::signalHandler(...), false); } // ignore pcntl_signal(SIGPIPE, SIG_IGN, false); @@ -1185,7 +1188,7 @@ protected static function reinstallSignal(): void $signals = [SIGINT, SIGTERM, SIGHUP, SIGTSTP, SIGQUIT, SIGUSR1, SIGUSR2, SIGIOT, SIGIO]; foreach ($signals as $signal) { // Rewrite master process signal. - static::$globalEvent->onSignal($signal, [static::class, 'signalHandler']); + static::$globalEvent->onSignal($signal, static::signalHandler(...)); } } @@ -1195,7 +1198,7 @@ protected static function reinstallSignal(): void * @param int $signal * @throws Throwable */ - public static function signalHandler(int $signal): void + protected static function signalHandler(int $signal): void { switch ($signal) { // Stop. @@ -1277,8 +1280,7 @@ public static function resetStd(bool $throwException = true): void $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - set_error_handler(function () { - }); + set_error_handler(function () {}); if ($STDOUT) { fclose($STDOUT); } @@ -1442,7 +1444,7 @@ protected static function forkWorkersForWindows(): void static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - register_shutdown_function([__CLASS__, 'checkErrors']); + register_shutdown_function(static::checkErrors(...)); // Create a global event loop. if (!static::$globalEvent) { @@ -1463,7 +1465,7 @@ protected static function forkWorkersForWindows(): void // Add an empty timer to prevent the event-loop from exiting. Timer::add(1000000, function (){}); - + // Display UI. static::safeEcho(str_pad($worker->name, 48) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . " [ok]\n"); $worker->listen(); @@ -1511,13 +1513,9 @@ public static function getStartFilesForWindows(): array public static function forkOneWorkerForWindows(string $startFile): void { $startFile = realpath($startFile); - - $descriptor_spec = array( - STDIN, STDOUT, STDOUT - ); - - $pipes = array(); - $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptor_spec, $pipes, null, null, ['bypass_shell' => true]); + $descriptorSpec = [STDIN, STDOUT, STDOUT]; + $pipes = []; + $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptorSpec, $pipes, null, null, ['bypass_shell' => true]); if (empty(static::$globalEvent)) { static::$globalEvent = new Select(); @@ -1528,14 +1526,15 @@ public static function forkOneWorkerForWindows(string $startFile): void } // 保存子进程句柄 - static::$processForWindows[$startFile] = array($process, $startFile); + static::$processForWindows[$startFile] = [$process, $startFile]; } /** * check worker status for windows. + * * @return void */ - public static function checkWorkerStatusForWindows(): void + protected static function checkWorkerStatusForWindows(): void { foreach (static::$processForWindows as $processData) { $process = $processData[0]; @@ -1586,7 +1585,7 @@ protected static function forkOneWorkerForLinux(self $worker): void static::$status = static::STATUS_RUNNING; // Register shutdown function for checking errors. - register_shutdown_function(["\\Workerman\\Worker", 'checkErrors']); + register_shutdown_function(static::checkErrors(...)); // Create a global event loop. if (!static::$globalEvent) { @@ -1627,10 +1626,9 @@ protected static function forkOneWorkerForLinux(self $worker): void * * @param string $workerId * @param int $pid - * * @return false|int|string */ - protected static function getId(string $workerId, int $pid): bool|int|string + protected static function getId(string $workerId, int $pid): false|int|string { return array_search($pid, static::$idMap[$workerId]); } @@ -1677,8 +1675,7 @@ public function setUserAndGroup(): void */ protected static function setProcessTitle(string $title): void { - set_error_handler(function () { - }); + set_error_handler(function (){}); cli_set_process_title($title); restore_error_handler(); } @@ -1782,7 +1779,7 @@ protected static function monitorWorkersForLinux(): void */ protected static function monitorWorkersForWindows(): void { - Timer::add(1, "\\Workerman\\Worker::checkWorkerStatusForWindows"); + Timer::add(1, static::checkWorkerStatusForWindows(...)); static::$globalEvent->run(); } @@ -1863,7 +1860,7 @@ protected static function reload(): void posix_kill($oneWorkerPid, $sig); // If the process does not exit after stopTimeout seconds try to kill it. if (!static::getGracefulStop()) { - Timer::add(static::$stopTimeout, '\posix_kill', [$oneWorkerPid, SIGKILL], false); + Timer::add(static::$stopTimeout, posix_kill(...), [$oneWorkerPid, SIGKILL], false); } } // For child processes. else { @@ -1909,15 +1906,15 @@ public static function stopAll(int $code = 0, mixed $log = ''): void foreach ($workerPidArray as $workerPid) { // Fix exit with status 2 for php8.2 if ($sig === SIGINT && !static::$daemonize) { - Timer::add(1, '\posix_kill', [$workerPid, SIGINT], false); + Timer::add(1, posix_kill(...), [$workerPid, SIGINT], false); } else { posix_kill($workerPid, $sig); } if (!static::getGracefulStop()) { - Timer::add(ceil(static::$stopTimeout), '\posix_kill', [$workerPid, SIGKILL], false); + Timer::add(ceil(static::$stopTimeout), posix_kill(...), [$workerPid, SIGKILL], false); } } - Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning"); + Timer::add(1, static::checkIfChildRunning(...)); // Remove statistics file. if (is_file(static::$statisticsFile)) { @unlink(static::$statisticsFile); @@ -1936,8 +1933,8 @@ public static function stopAll(int $code = 0, mixed $log = ''): void // Ignore Swoole ExitException: Swoole exit. exit($code); /** @phpstan-ignore-next-line */ - } catch(\Exception $e) { - + } catch (\Exception) { + // do nothing } } } @@ -1946,7 +1943,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void /** * check if child processes is really running */ - public static function checkIfChildRunning(): void + protected static function checkIfChildRunning(): void { foreach (static::$pidMap as $workerId => $workerPidArray) { foreach ($workerPidArray as $pid => $workerPid) { @@ -2043,9 +2040,7 @@ protected static function writeStatisticsToStatusFile(): void // For child processes. gc_collect_cycles(); - if (function_exists('gc_mem_caches')) { - gc_mem_caches(); - } + gc_mem_caches(); reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); @@ -2141,7 +2136,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void * * @return void */ - public static function checkErrors(): void + protected static function checkErrors(): void { if (static::STATUS_SHUTDOWN !== static::$status) { $errorMsg = DIRECTORY_SEPARATOR === '/' ? 'Worker[' . posix_getpid() . '] process terminated' : 'Worker process terminated'; @@ -2188,6 +2183,7 @@ public static function log(mixed $msg, bool $decorated = false): void /** * Safe Echo. + * * @param string $msg * @param bool $decorated * @return bool @@ -2222,7 +2218,7 @@ public static function safeEcho(string $msg, bool $decorated = false): bool * @param resource|null $stream * @return false|resource */ - private static function outputStream($stream = null) + private static function outputStream($stream = null): mixed { if (!$stream) { $stream = static::$outputStream ?: STDOUT; @@ -2338,8 +2334,7 @@ public function listen(): void // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { - set_error_handler(function () { - }); + set_error_handler(function () {}); $socket = socket_import_stream($this->mainSocket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); @@ -2362,8 +2357,7 @@ public function unlisten(): void { $this->pauseAccept(); if ($this->mainSocket) { - set_error_handler(function () { - }); + set_error_handler(function () {}); fclose($this->mainSocket); restore_error_handler(); $this->mainSocket = null; @@ -2426,9 +2420,9 @@ public function resumeAccept(): void // Register a listener to be notified when server socket is ready to read. if (static::$globalEvent && true === $this->pauseAccept && $this->mainSocket) { if ($this->transport !== 'udp') { - static::$globalEvent->onReadable($this->mainSocket, [$this, 'acceptTcpConnection']); + static::$globalEvent->onReadable($this->mainSocket, $this->acceptTcpConnection(...)); } else { - static::$globalEvent->onReadable($this->mainSocket, [$this, 'acceptUdpConnection']); + static::$globalEvent->onReadable($this->mainSocket, $this->acceptUdpConnection(...)); } $this->pauseAccept = false; } @@ -2511,11 +2505,10 @@ public function stop(): void * @return void * @throws Throwable */ - public function acceptTcpConnection($socket): void + protected function acceptTcpConnection(mixed $socket): void { // Accept a connection on server socket. - set_error_handler(function () { - }); + set_error_handler(function () {}); $newSocket = stream_socket_accept($socket, 0, $remoteAddress); restore_error_handler(); @@ -2553,10 +2546,9 @@ public function acceptTcpConnection($socket): void * @return bool * @throws Throwable */ - public function acceptUdpConnection($socket): bool + protected function acceptUdpConnection(mixed $socket): bool { - set_error_handler(function () { - }); + set_error_handler(function () {}); $recvBuffer = stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { @@ -2632,6 +2624,6 @@ protected static function checkMasterIsAlive(int $masterPid): bool return true; } - return stripos($content, 'WorkerMan') !== false || stripos($content, 'php') !== false; + return str_contains($content, 'WorkerMan') || str_contains($content, 'php'); } } From 50fe3b8a1f279780d9c58320d540c87abcf7e653 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 30 Oct 2023 18:29:10 +0800 Subject: [PATCH 0967/1216] Change ports in tests because port 2000 and ipv6 not available in some systems --- tests/Feature/Stub/HttpServer.php | 2 +- tests/Feature/WebsocketServiceTest.php | 4 ++-- tests/Unit/Connection/UdpConnectionTest.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Feature/Stub/HttpServer.php b/tests/Feature/Stub/HttpServer.php index a1b1a0078..fb047cb3f 100644 --- a/tests/Feature/Stub/HttpServer.php +++ b/tests/Feature/Stub/HttpServer.php @@ -13,7 +13,7 @@ if (!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'w')); if (!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w')); -$worker = new Worker('http://0.0.0.0:8080'); +$worker = new Worker('http://127.0.0.1:8080'); $worker->onMessage = function (TcpConnection $connection, Request $request) { match ($request->path()) { diff --git a/tests/Feature/WebsocketServiceTest.php b/tests/Feature/WebsocketServiceTest.php index e3d6a24f7..cf1e342a2 100644 --- a/tests/Feature/WebsocketServiceTest.php +++ b/tests/Feature/WebsocketServiceTest.php @@ -11,7 +11,7 @@ if (!defined('STDIN')) define('STDIN', fopen('php://stdin', 'r')); if (!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'w')); if (!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w')); -\$worker = new Worker("websocket://0.0.0.0:2000"); +\$worker = new Worker("websocket://127.0.0.1:8081"); %s Worker::\$pidFile = __DIR__ . '/WebsocketServer.pid'; Worker::\$command = 'start'; @@ -28,7 +28,7 @@ if (!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w')); \$worker = new Worker(); \$worker->onWorkerStart = function(\$worker){ - \$con = new AsyncTcpConnection('ws://127.0.0.1:2000'); + \$con = new AsyncTcpConnection('ws://127.0.0.1:8081'); %s \$con->connect(); }; diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index d45f2d429..706581915 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -4,7 +4,7 @@ use Symfony\Component\Process\PhpProcess; use Workerman\Protocols\Text; -$remoteAddress = '[::1]:12345'; +$remoteAddress = '127.0.0.1:8082'; $process = null; beforeAll(function () use ($remoteAddress, &$process) { $process = new PhpProcess(<<protocol = Text::class; expect($udpConnection->send('foo'))->toBeTrue() - ->and($udpConnection->getRemoteIp())->toBe('::1') - ->and($udpConnection->getRemotePort())->toBe(12345) + ->and($udpConnection->getRemoteIp())->toBe('127.0.0.1') + ->and($udpConnection->getRemotePort())->toBe(8082) ->and($udpConnection->getRemoteAddress())->toBe($remoteAddress) ->and($udpConnection->getLocalIp())->toBeIn(['::1', '[::1]', '127.0.0.1']) ->and($udpConnection->getLocalPort())->toBeInt() From 7d3aa2ef53b67db28b7f2589f2b041fcbeb2d7fd Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 31 Oct 2023 00:47:21 +0800 Subject: [PATCH 0968/1216] Fix call static methods --- src/Connection/AsyncTcpConnection.php | 2 +- src/Connection/ConnectionInterface.php | 2 +- src/Connection/TcpConnection.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 79be70dbc..041f94d48 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -422,7 +422,7 @@ public function checkConnection(): void // Try to emit protocol::onConnect if ($this->protocol && method_exists($this->protocol, 'onConnect')) { try { - $this->protocol->onConnect($this); + $this->protocol::onConnect($this); } catch (Throwable $e) { $this->error($e); } diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index cee7d1044..0983cc245 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -58,7 +58,7 @@ abstract class ConnectionInterface * Application layer protocol. * The format is like this Workerman\\Protocols\\Http. * - * @var ?string + * @var ?class-string */ public ?string $protocol = null; diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f03598c0b..fe594f7ee 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1019,7 +1019,7 @@ public function destroy(): void // Try to emit protocol::onClose if ($this->protocol && method_exists($this->protocol, 'onClose')) { try { - $this->protocol->onClose($this); + $this->protocol::onClose($this); } catch (Throwable $e) { $this->error($e); } From 72d857c62b66c58328153a3d128cdb21eafed21f Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 31 Oct 2023 01:15:03 +0800 Subject: [PATCH 0969/1216] Added test script to composer file --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fab158922..3846cbc6f 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,7 @@ } }, "scripts": { - "analyze": "phpstan" + "analyze": "phpstan", + "test": "pest" } } From afdb4e1bbd782f330929cbd9bd0b6339b1979e38 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 1 Nov 2023 12:04:38 +0800 Subject: [PATCH 0970/1216] Type definitions improvements --- src/Connection/AsyncUdpConnection.php | 8 +++--- src/Connection/ConnectionInterface.php | 6 ++-- src/Connection/TcpConnection.php | 15 +++++----- src/Connection/UdpConnection.php | 8 +++--- src/Protocols/Http.php | 5 ++-- src/Protocols/Http/Request.php | 39 +++++++++++++------------- src/Protocols/Http/Session.php | 10 +++---- src/Worker.php | 2 +- 8 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index dfed54fd3..512ab187b 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -124,7 +124,7 @@ public function baseRead($socket): void /** * Close connection. * - * @param mixed|null $data + * @param mixed $data * @param bool $raw * @return void * @throws Throwable @@ -153,17 +153,17 @@ public function close(mixed $data = null, bool $raw = false): void * * @param mixed $sendBuffer * @param bool $raw - * @return void|boolean + * @return bool|null * @throws Throwable */ - public function send(mixed $sendBuffer, bool $raw = false) + public function send(mixed $sendBuffer, bool $raw = false): bool|null { if (false === $raw && $this->protocol) { /** @var ProtocolInterface $parser */ $parser = $this->protocol; $sendBuffer = $parser::encode($sendBuffer, $this); if ($sendBuffer === '') { - return; + return null; } } if ($this->connected === false) { diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index 0983cc245..f496adafa 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -98,9 +98,9 @@ abstract class ConnectionInterface * * @param mixed $sendBuffer * @param bool $raw - * @return void|boolean + * @return bool|null */ - abstract public function send(mixed $sendBuffer, bool $raw = false); + abstract public function send(mixed $sendBuffer, bool $raw = false): bool|null; /** * Get remote IP. @@ -147,7 +147,7 @@ abstract public function getLocalAddress(): string; /** * Close connection. * - * @param mixed|null $data + * @param mixed $data * @param bool $raw * @return void */ diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index fe594f7ee..6f9bbe8e4 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -377,10 +377,10 @@ public function getStatus(bool $rawOutput = true): int|string * * @param mixed $sendBuffer * @param bool $raw - * @return bool|void + * @return bool|null * @throws Throwable */ - public function send(mixed $sendBuffer, bool $raw = false) + public function send(mixed $sendBuffer, bool $raw = false): bool|null { if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return false; @@ -396,7 +396,7 @@ public function send(mixed $sendBuffer, bool $raw = false) $this->error($e); } if ($sendBuffer === '') { - return; + return null; } } @@ -409,7 +409,7 @@ public function send(mixed $sendBuffer, bool $raw = false) } $this->sendBuffer .= $sendBuffer; $this->checkBufferWillFull(); - return; + return null; } // Attempt to send data directly. @@ -418,7 +418,7 @@ public function send(mixed $sendBuffer, bool $raw = false) $this->eventLoop->onWritable($this->socket, $this->baseWrite(...)); $this->sendBuffer = $sendBuffer; $this->checkBufferWillFull(); - return; + return null; } $len = 0; try { @@ -454,7 +454,7 @@ public function send(mixed $sendBuffer, bool $raw = false) $this->eventLoop->onWritable($this->socket, $this->baseWrite(...)); // Check if send buffer will be full. $this->checkBufferWillFull(); - return; + return null; } if ($this->bufferIsFull()) { @@ -465,6 +465,7 @@ public function send(mixed $sendBuffer, bool $raw = false) $this->sendBuffer .= $sendBuffer; // Check if send buffer is full. $this->checkBufferWillFull(); + return null; } /** @@ -871,7 +872,7 @@ public function consumeRecvBuffer(int $length): void /** * Close connection. * - * @param mixed|null $data + * @param mixed $data * @param bool $raw * @return void * @throws Throwable diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 05bdbc44a..1a25af0af 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -76,16 +76,16 @@ public function __construct($socket, string $remoteAddress) * * @param mixed $sendBuffer * @param bool $raw - * @return void|boolean + * @return bool|null */ - public function send(mixed $sendBuffer, bool $raw = false) + public function send(mixed $sendBuffer, bool $raw = false): bool|null { if (false === $raw && $this->protocol) { /** @var ProtocolInterface $parser */ $parser = $this->protocol; $sendBuffer = $parser::encode($sendBuffer, $this); if ($sendBuffer === '') { - return; + return null; } } return strlen($sendBuffer) === stream_socket_sendto($this->socket, $sendBuffer, 0, $this->isIpV6() ? '[' . $this->getRemoteIp() . ']:' . $this->getRemotePort() : $this->remoteAddress); @@ -172,7 +172,7 @@ public function getLocalAddress(): string /** * Close connection. * - * @param mixed|null $data + * @param mixed $data * @param bool $raw * @return void */ diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 62a42482c..53d27778c 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -70,12 +70,12 @@ class Http /** * Get or set the request class name. * - * @param string|null $className + * @param class-string|null $className * @return string */ public static function requestClass(string $className = null): string { - if ($className) { + if ($className !== null) { static::$requestClass = $className; } return static::$requestClass; @@ -202,6 +202,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin $request = $connection->request; $request->session = $request->connection = $connection->request = null; } + if (!is_object($response)) { $extHeader = ''; if ($connection->headers) { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 6970f6e0e..b674e5e45 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -97,7 +97,7 @@ class Request implements Stringable * * @var bool */ - protected $isSafe = true; + protected bool $isSafe = true; /** * Enable cache. @@ -109,7 +109,7 @@ class Request implements Stringable /** * Session id. * - * @var mixed|string + * @var mixed */ protected mixed $sid; @@ -127,7 +127,7 @@ public function __construct(string $buffer) * Get query. * * @param string|null $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function get(string $name = null, mixed $default = null): mixed @@ -145,7 +145,7 @@ public function get(string $name = null, mixed $default = null): mixed * Get post. * * @param string|null $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function post(string $name = null, mixed $default = null): mixed @@ -163,7 +163,7 @@ public function post(string $name = null, mixed $default = null): mixed * Get header item by name. * * @param string|null $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function header(string $name = null, mixed $default = null): mixed @@ -182,7 +182,7 @@ public function header(string $name = null, mixed $default = null): mixed * Get cookie item by name. * * @param string|null $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function cookie(string $name = null, mixed $default = null): mixed @@ -203,7 +203,7 @@ public function cookie(string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(string $name = null) + public function file(string $name = null): array|null { if (!isset($this->data['files'])) { $this->parsePost(); @@ -569,14 +569,14 @@ protected function parseUploadFiles(string $httpPostBoundary): void /** * Parse upload file. * - * @param $boundary - * @param $sectionStartOffset - * @param $postEncodeString - * @param $filesEncodeStr - * @param $files + * @param string $boundary + * @param int $sectionStartOffset + * @param string $postEncodeString + * @param string $filesEncodeStr + * @param array $files * @return int */ - protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeString, &$filesEncodeStr, &$files): int + protected function parseUploadFile(string $boundary, int $sectionStartOffset, string &$postEncodeString, string &$filesEncodeStr, array &$files): int { $file = []; $boundary = "\r\n$boundary"; @@ -700,7 +700,7 @@ public function __toString(): string * @param mixed $value * @return void */ - public function __set(string $name, mixed $value) + public function __set(string $name, mixed $value): void { $this->properties[$name] = $value; } @@ -709,9 +709,9 @@ public function __set(string $name, mixed $value) * Getter. * * @param string $name - * @return mixed|null + * @return mixed */ - public function __get(string $name) + public function __get(string $name): mixed { return $this->properties[$name] ?? null; } @@ -722,7 +722,7 @@ public function __get(string $name) * @param string $name * @return bool */ - public function __isset(string $name) + public function __isset(string $name): bool { return isset($this->properties[$name]); } @@ -733,18 +733,17 @@ public function __isset(string $name) * @param string $name * @return void */ - public function __unset(string $name) + public function __unset(string $name): void { unset($this->properties[$name]); } - /** * __wakeup. * * @return void */ - public function __wakeup() + public function __wakeup(): void { $this->isSafe = false; } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index e7dec8233..c463630e8 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -186,7 +186,7 @@ public function getId(): string * Get session. * * @param string $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function get(string $name, mixed $default = null): mixed @@ -221,7 +221,7 @@ public function delete(string $name): void * Retrieve and delete an item from the session. * * @param string $name - * @param mixed|null $default + * @param mixed $default * @return mixed */ public function pull(string $name, mixed $default = null): mixed @@ -235,7 +235,7 @@ public function pull(string $name, mixed $default = null): mixed * Store data in the session. * * @param array|string $key - * @param mixed|null $value + * @param mixed $value */ public function put(array|string $key, mixed $value = null): void { @@ -367,8 +367,8 @@ public static function init(): void /** * Set session handler class. * - * @param mixed|null $className - * @param mixed|null $config + * @param mixed $className + * @param mixed $config * @return string */ public static function handlerClass(mixed $className = null, mixed $config = null): string diff --git a/src/Worker.php b/src/Worker.php index d8d9be51a..ec8fb380c 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1992,7 +1992,7 @@ protected static function writeStatisticsToStatusFile(): void } file_put_contents(static::$statisticsFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); - $loadavg = function_exists('sys_getloadavg') ? array_map('round', sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; + $loadavg = function_exists('sys_getloadavg') ? array_map(round(...), sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); file_put_contents(static::$statisticsFile, From 0391b58fb374bd6c0329278218b857a0b15e1f89 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 1 Nov 2023 18:57:11 +0800 Subject: [PATCH 0971/1216] Change command in github workflow file --- .github/workflows/test.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 91a108b8d..6a310546b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,4 +47,4 @@ jobs: run: composer analyze - name: Execute tests - run: vendor/bin/pest --coverage --colors=always + run: composer test diff --git a/composer.json b/composer.json index 3846cbc6f..4afb589e0 100644 --- a/composer.json +++ b/composer.json @@ -54,6 +54,6 @@ }, "scripts": { "analyze": "phpstan", - "test": "pest" + "test": "pest --colors=always" } } From 96cc3ad4058fa77a087468f123bbd67632882e98 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 1 Nov 2023 20:10:48 +0800 Subject: [PATCH 0972/1216] isset conditions replaced by null coalescing assignments --- src/Connection/AsyncTcpConnection.php | 8 ++----- src/Connection/TcpConnection.php | 4 +--- src/Protocols/Http/Request.php | 24 ++++--------------- .../Http/Session/RedisSessionHandler.php | 6 +---- src/Worker.php | 12 ++++------ 5 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 041f94d48..e88b2c098 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -168,12 +168,8 @@ public function __construct(string $remoteAddress, array $socketContext = []) throw new RuntimeException('Bad remoteAddress'); } } else { - if (!isset($addressInfo['port'])) { - $addressInfo['port'] = 0; - } - if (!isset($addressInfo['path'])) { - $addressInfo['path'] = '/'; - } + $addressInfo['port'] ??= 0; + $addressInfo['path'] ??= '/'; if (!isset($addressInfo['query'])) { $addressInfo['query'] = ''; } else { diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index fe594f7ee..edc7d01ce 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1081,9 +1081,7 @@ public function __destruct() static $mod; self::$statistics['connection_count']--; if (Worker::getGracefulStop()) { - if (!isset($mod)) { - $mod = ceil((self::$statistics['connection_count'] + 1) / 3); - } + $mod ??= ceil((self::$statistics['connection_count'] + 1) / 3); if (0 === self::$statistics['connection_count'] % $mod) { $pid = function_exists('posix_getpid') ? posix_getpid() : 0; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 6970f6e0e..e6dcb34b7 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -275,10 +275,7 @@ public function uri(): string */ public function path(): string { - if (!isset($this->data['path'])) { - $this->data['path'] = (string)parse_url($this->uri(), PHP_URL_PATH); - } - return $this->data['path']; + return $this->data['path'] ??= (string)parse_url($this->uri(), PHP_URL_PATH); } /** @@ -288,10 +285,7 @@ public function path(): string */ public function queryString(): string { - if (!isset($this->data['query_string'])) { - $this->data['query_string'] = (string)parse_url($this->uri(), PHP_URL_QUERY); - } - return $this->data['query_string']; + return $this->data['query_string'] ??= (string)parse_url($this->uri(), PHP_URL_QUERY); } /** @@ -302,10 +296,7 @@ public function queryString(): string */ public function session(): Session { - if ($this->session === null) { - $this->session = new Session($this->sessionId()); - } - return $this->session; + return $this->session ??= new Session($this->sessionId()); } /** @@ -366,10 +357,7 @@ public function sessionRegenerateId(bool $deleteOldSession = false): string */ public function rawHead(): string { - if (!isset($this->data['head'])) { - $this->data['head'] = strstr($this->buffer, "\r\n\r\n", true); - } - return $this->data['head']; + return $this->data['head'] ??= strstr($this->buffer, "\r\n\r\n", true); } /** @@ -623,9 +611,7 @@ protected function parseUploadFile($boundary, $sectionStartOffset, &$postEncodeS $uploadKey = $fileName; // Parse upload files. $file = [...$file, 'name' => $match[2], 'tmp_name' => $tmpFile, 'size' => $size, 'error' => $error, 'full_path' => $match[2]]; - if (!isset($file['type'])) { - $file['type'] = ''; - } + $file['type'] ??= ''; break; } // Is post field. diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index e1999ea55..f1fed758e 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -59,12 +59,8 @@ public function __construct(array $config) throw new RuntimeException('Please install redis extension.'); } - if (!isset($config['timeout'])) { - $config['timeout'] = 2; - } - + $config['timeout'] ??= 2; $this->config = $config; - $this->connect(); Timer::add($config['ping'] ?? 55, function () { diff --git a/src/Worker.php b/src/Worker.php index d8d9be51a..c51957eca 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1738,10 +1738,8 @@ protected static function monitorWorkersForLinux(): void } // For Statistics. - if (!isset(static::$globalStatistics['worker_exit_info'][$workerId][$status])) { - static::$globalStatistics['worker_exit_info'][$workerId][$status] = 0; - } - ++static::$globalStatistics['worker_exit_info'][$workerId][$status]; + static::$globalStatistics['worker_exit_info'][$workerId][$status] ??= 0; + static::$globalStatistics['worker_exit_info'][$workerId][$status]++; // Clear process data. unset(static::$pidMap[$workerId][$pid]); @@ -2260,9 +2258,7 @@ public function __construct(string $socketName = null, array $socketContext = [] // Context for socket. if ($socketName) { $this->socketName = $socketName; - if (!isset($socketContext['socket']['backlog'])) { - $socketContext['socket']['backlog'] = static::DEFAULT_BACKLOG; - } + $socketContext['socket']['backlog'] ??= static::DEFAULT_BACKLOG; $this->socketContext = stream_context_create($socketContext); } @@ -2589,7 +2585,7 @@ protected function acceptUdpConnection(mixed $socket): bool } else { $messageCallback($connection, $recvBuffer); } - ++ConnectionInterface::$statistics['total_request']; + ConnectionInterface::$statistics['total_request']++; } catch (Throwable $e) { static::stopAll(250, $e); } From b4a253a98606f389abb235e3cffaa7a19e1fb4cc Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 13:55:45 +0800 Subject: [PATCH 0973/1216] Implemented error handling properly in all Event classes --- phpstan.neon.dist | 5 ++ src/Events/Ev.php | 52 ++++++++++--------- src/Events/Event.php | 92 ++++++++++++++------------------- src/Events/EventInterface.php | 43 +++++++++++----- src/Events/Revolt.php | 34 ++++++------ src/Events/Select.php | 97 +++++++++++++++++------------------ src/Events/Swoole.php | 69 ++++++++++++------------- src/Events/Swow.php | 64 +++++++++++------------ src/Worker.php | 11 ++-- 9 files changed, 229 insertions(+), 238 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fad677a19..d3d3beabf 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,6 +25,11 @@ parameters: - '#Constant STREAM_POLLNONE not found.#' - '#Constant STREAM_POLLOUT not found.#' - '#Property Workerman\\Events\\Swow::.* has unknown class Swow\\Coroutine as its type.#' + - + path: src/Events/Event.php + reportUnmatched: false + messages: + - '#Call to an undefined method EventBase::+.#' - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: tests/Pest.php diff --git a/src/Events/Ev.php b/src/Events/Ev.php index a9d89c669..2a669e944 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -15,10 +15,6 @@ namespace Workerman\Events; -use EvIo; -use EvSignal; -use EvTimer; - /** * Ev eventloop */ @@ -27,28 +23,28 @@ class Ev implements EventInterface /** * All listeners for read event. * - * @var array + * @var array */ protected array $readEvents = []; /** * All listeners for write event. * - * @var array + * @var array */ protected array $writeEvents = []; /** * Event listeners of signal. * - * @var array + * @var array */ protected array $eventSignal = []; /** * All timer event listeners. * - * @var array + * @var array */ protected array $eventTimer = []; @@ -70,9 +66,9 @@ class Ev implements EventInterface public function delay(float $delay, callable $func, array $args = []): int { $timerId = self::$timerId; - $event = new EvTimer($delay, 0, function () use ($func, $args, $timerId) { + $event = new \EvTimer($delay, 0, function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); - $func(...$args); + $this->safeCall($func, $args); }); $this->eventTimer[self::$timerId] = $event; return self::$timerId++; @@ -104,9 +100,7 @@ public function offRepeat(int $timerId): bool */ public function repeat(float $interval, callable $func, array $args = []): int { - $event = new EvTimer($interval, $interval, function () use ($func, $args) { - $func(...$args); - }); + $event = new \EvTimer($interval, $interval, fn () => $this->safeCall($func, $args)); $this->eventTimer[self::$timerId] = $event; return self::$timerId++; } @@ -117,9 +111,7 @@ public function repeat(float $interval, callable $func, array $args = []): int public function onReadable($stream, callable $func): void { $fdKey = (int)$stream; - $event = new EvIo($stream, \Ev::READ, function () use ($func, $stream) { - $func($stream); - }); + $event = new \EvIo($stream, \Ev::READ, fn () => $this->safeCall($func, [$stream])); $this->readEvents[$fdKey] = $event; } @@ -143,10 +135,8 @@ public function offReadable($stream): bool public function onWritable($stream, callable $func): void { $fdKey = (int)$stream; - $event = new EvIo($stream, \Ev::WRITE, function () use ($func, $stream) { - $func($stream); - }); - $this->readEvents[$fdKey] = $event; + $event = new \EvIo($stream, \Ev::WRITE, fn () => $this->safeCall($func, [$stream])); + $this->writeEvents[$fdKey] = $event; } /** @@ -168,9 +158,7 @@ public function offWritable($stream): bool */ public function onSignal(int $signal, callable $func): void { - $event = new EvSignal($signal, function () use ($func, $signal) { - $func($signal); - }); + $event = new \EvSignal($signal, fn () => $this->safeCall($func, [$signal])); $this->eventSignal[$signal] = $event; } @@ -237,4 +225,22 @@ public function getErrorHandler(): ?callable { return $this->errorHandler; } + + /** + * @param callable $func + * @param array $args + * @return void + */ + private function safeCall(callable $func, array $args = []): void + { + try { + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } + } + } } diff --git a/src/Events/Event.php b/src/Events/Event.php index 9534b8a78..10be122ea 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -16,12 +16,6 @@ namespace Workerman\Events; -use EventBase; -use RuntimeException; -use Throwable; -use function class_exists; -use function count; - /** * libevent eventloop */ @@ -29,43 +23,49 @@ class Event implements EventInterface { /** * Event base. - * @var EventBase + * + * @var \EventBase */ - protected EventBase $eventBase; + protected \EventBase $eventBase; /** * All listeners for read event. - * @var array + * + * @var array */ protected array $readEvents = []; /** * All listeners for write event. - * @var array + * + * @var array */ protected array $writeEvents = []; /** * Event listeners of signal. - * @var array + * + * @var array */ protected array $eventSignal = []; /** * All timer event listeners. - * [func, args, event, flag, time_interval] - * @var array + * + * @var array */ protected array $eventTimer = []; /** * Timer id. + * * @var int */ protected int $timerId = 0; /** * Event class name. + * * @var string */ protected string $eventClassName = ''; @@ -77,17 +77,16 @@ class Event implements EventInterface /** * Construct. - * @return void */ public function __construct() { - if (class_exists('\\\\Event', false)) { + if (\class_exists('\\\\Event', false)) { $className = '\\\\Event'; } else { $className = '\Event'; } $this->eventClassName = $className; - if (class_exists('\\\\EventBase', false)) { + if (\class_exists('\\\\EventBase', false)) { $className = '\\\\EventBase'; } else { $className = '\EventBase'; @@ -104,14 +103,10 @@ public function delay(float $delay, callable $func, array $args = []): int $timerId = $this->timerId++; $event = new $className($this->eventBase, -1, $className::TIMEOUT, function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); - try { - $func(...$args); - } catch (Throwable $e) { - $this->error($e); - } + $this->safeCall($func, $args); }); if (!$event->addTimer($delay)) { - throw new RuntimeException("Event::addTimer($delay) failed"); + throw new \RuntimeException("Event::addTimer($delay) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; @@ -145,15 +140,9 @@ public function repeat(float $interval, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; - $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, function () use ($func, $args) { - try { - $func(...$args); - } catch (Throwable $e) { - $this->error($e); - } - }); + $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, fn () => $this->safeCall($func, $args)); if (!$event->addTimer($interval)) { - throw new RuntimeException("Event::addTimer($interval) failed"); + throw new \RuntimeException("Event::addTimer($interval) failed"); } $this->eventTimer[$timerId] = $event; return $timerId; @@ -166,12 +155,10 @@ public function onReadable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; - $event = new $this->eventClassName($this->eventBase, $stream, $className::READ | $className::PERSIST, $func, $stream); - // @phpstan-ignore-next-line Negated boolean expression is always false. - if (!$event || !$event->add()) { - return; + $event = new $className($this->eventBase, $stream, $className::READ | $className::PERSIST, fn () => $this->safeCall($func, [$stream])); + if ($event->add()) { + $this->readEvents[$fdKey] = $event; } - $this->readEvents[$fdKey] = $event; } /** @@ -195,12 +182,10 @@ public function onWritable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; - $event = new $this->eventClassName($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func, $stream); - // @phpstan-ignore-next-line Negated boolean expression is always false. - if (!$event || !$event->add()) { - return; + $event = new $className($this->eventBase, $stream, $className::WRITE | $className::PERSIST, fn () => $this->safeCall($func, [$stream])); + if ($event->add()) { + $this->writeEvents[$fdKey] = $event; } - $this->writeEvents[$fdKey] = $event; } /** @@ -224,11 +209,10 @@ public function onSignal(int $signal, callable $func): void { $className = $this->eventClassName; $fdKey = $signal; - $event = $className::signal($this->eventBase, $signal, $func); - if (!$event || !$event->add()) { - return; + $event = $className::signal($this->eventBase, $signal, fn () => $this->safeCall($func, [$signal])); + if ($event->add()) { + $this->eventSignal[$fdKey] = $event; } - $this->eventSignal[$fdKey] = $event; } /** @@ -277,7 +261,7 @@ public function stop(): void */ public function getTimerCount(): int { - return count($this->eventTimer); + return \count($this->eventTimer); } /** @@ -297,20 +281,20 @@ public function getErrorHandler(): ?callable } /** - * @param Throwable $e + * @param callable $func + * @param array $args * @return void - * @throws Throwable */ - public function error(Throwable $e): void + private function safeCall(callable $func, array $args = []): void { try { - if (!$this->errorHandler) { - throw new $e; + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); } - ($this->errorHandler)($e); - } catch (Throwable $e) { - // Cannot trigger an exception in the Event callback, otherwise it will cause an infinite loop - echo $e; } } } diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index 0dc83f656..edc09373a 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -11,23 +11,26 @@ * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ -namespace Workerman\Events; -use Throwable; +declare(strict_types=1); + +namespace Workerman\Events; interface EventInterface { /** * Delay the execution of a callback. + * * @param float $delay - * @param callable $func - * @param mixed[] $args + * @param callable(mixed...): void $func + * @param array $args * @return int */ public function delay(float $delay, callable $func, array $args = []): int; /** * Delete a delay timer. + * * @param int $timerId * @return bool */ @@ -35,15 +38,17 @@ public function offDelay(int $timerId): bool; /** * Repeatedly execute a callback. + * * @param float $interval - * @param callable $func - * @param mixed[] $args + * @param callable(mixed...): void $func + * @param array $args * @return int */ public function repeat(float $interval, callable $func, array $args = []): int; /** * Delete a repeat timer. + * * @param int $timerId * @return bool */ @@ -51,14 +56,16 @@ public function offRepeat(int $timerId): bool; /** * Execute a callback when a stream resource becomes readable or is closed for reading. + * * @param resource $stream - * @param callable $func + * @param callable(resource): void $func * @return void */ public function onReadable($stream, callable $func): void; /** * Cancel a callback of stream readable. + * * @param resource $stream * @return bool */ @@ -66,14 +73,16 @@ public function offReadable($stream): bool; /** * Execute a callback when a stream resource becomes writable or is closed for writing. + * * @param resource $stream - * @param callable $func + * @param callable(resource): void $func * @return void */ public function onWritable($stream, callable $func): void; /** * Cancel a callback of stream writable. + * * @param resource $stream * @return bool */ @@ -81,15 +90,16 @@ public function offWritable($stream): bool; /** * Execute a callback when a signal is received. + * * @param int $signal - * @param callable $func + * @param callable(int): void $func * @return void - * @throws Throwable */ public function onSignal(int $signal, callable $func): void; /** * Cancel a callback of signal. + * * @param int $signal * @return bool */ @@ -97,39 +107,44 @@ public function offSignal(int $signal): bool; /** * Delete all timer. + * * @return void */ public function deleteAllTimer(): void; /** * Run the event loop. + * * @return void - * @throws Throwable */ public function run(): void; /** * Stop event loop. + * * @return void */ public function stop(): void; /** * Get Timer count. + * * @return int */ public function getTimerCount(): int; /** - * Set error handler - * @param callable $errorHandler + * Set error handler. + * + * @param callable(\Throwable): void $errorHandler * @return void */ public function setErrorHandler(callable $errorHandler): void; /** * Get error handler - * @return ?callable(Throwable) + * + * @return null|callable (\Throwable): void */ public function getErrorHandler(): ?callable; } diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index fdd75bf47..9e5aec857 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -34,30 +34,35 @@ class Revolt implements EventInterface /** * All listeners for read event. - * @var array + * + * @var array */ protected array $readEvents = []; /** * All listeners for write event. - * @var array + * + * @var array */ protected array $writeEvents = []; /** * Event listeners of signal. - * @var array + * + * @var array */ protected array $eventSignal = []; /** * Event listeners of timer. - * @var array + * + * @var array */ protected array $eventTimer = []; /** * Timer id. + * * @var int */ protected int $timerId = 1; @@ -71,7 +76,7 @@ public function __construct() } /** - * Get driver + * Get driver. * * @return Driver */ @@ -108,7 +113,7 @@ public function stop(): void public function delay(float $delay, callable $func, array $args = []): int { $timerId = $this->timerId++; - $closure = function () use ($func, $args, $timerId) { + $closure = static function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); $func(...$args); }; @@ -123,10 +128,7 @@ public function delay(float $delay, callable $func, array $args = []): int public function repeat(float $interval, callable $func, array $args = []): int { $timerId = $this->timerId++; - $closure = function () use ($func, $args) { - $func(...$args); - }; - $cbId = $this->driver->repeat($interval, $closure); + $cbId = $this->driver->repeat($interval, static fn () => $func(...$args)); $this->eventTimer[$timerId] = $cbId; return $timerId; } @@ -142,9 +144,7 @@ public function onReadable($stream, callable $func): void unset($this->readEvents[$fdKey]); } - $this->readEvents[$fdKey] = $this->driver->onReadable($stream, function () use ($stream, $func) { - $func($stream); - }); + $this->readEvents[$fdKey] = $this->driver->onReadable($stream, static fn () => $func($stream)); } /** @@ -171,9 +171,7 @@ public function onWritable($stream, callable $func): void $this->driver->cancel($this->writeEvents[$fdKey]); unset($this->writeEvents[$fdKey]); } - $this->writeEvents[$fdKey] = $this->driver->onWritable($stream, function () use ($stream, $func) { - $func($stream); - }); + $this->writeEvents[$fdKey] = $this->driver->onWritable($stream, static fn () => $func($stream)); } /** @@ -200,9 +198,7 @@ public function onSignal(int $signal, callable $func): void $this->driver->cancel($this->eventSignal[$fdKey]); unset($this->eventSignal[$fdKey]); } - $this->eventSignal[$fdKey] = $this->driver->onSignal($signal, function () use ($signal, $func) { - $func($signal); - }); + $this->eventSignal[$fdKey] = $this->driver->onSignal($signal, static fn () => $func($signal)); } /** diff --git a/src/Events/Select.php b/src/Events/Select.php index 4998f32ba..1ad06cbc4 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -16,8 +16,6 @@ namespace Workerman\Events; -use SplPriorityQueue; -use Throwable; use function count; use function max; use function microtime; @@ -32,6 +30,7 @@ class Select implements EventInterface { /** * Running. + * * @var bool */ protected bool $running = true; @@ -39,47 +38,47 @@ class Select implements EventInterface /** * All listeners for read/write event. * - * @var array + * @var array */ protected array $readEvents = []; /** * All listeners for read/write event. * - * @var array + * @var array */ protected array $writeEvents = []; /** - * @var array + * @var array */ protected array $exceptEvents = []; /** * Event listeners of signal. * - * @var array + * @var array */ protected array $signalEvents = []; /** * Fds waiting for read event. * - * @var array + * @var array */ protected array $readFds = []; /** * Fds waiting for write event. * - * @var array + * @var array */ protected array $writeFds = []; /** * Fds waiting for except event. * - * @var array + * @var array */ protected array $exceptFds = []; @@ -87,9 +86,9 @@ class Select implements EventInterface * Timer scheduler. * {['data':timer_id, 'priority':run_timestamp], ..} * - * @var SplPriorityQueue + * @var \SplPriorityQueue */ - protected SplPriorityQueue $scheduler; + protected \SplPriorityQueue $scheduler; /** * All timer event listeners. @@ -116,16 +115,15 @@ class Select implements EventInterface /** * @var ?callable */ - protected $errorHandler; + protected $errorHandler = null; /** * Construct. */ public function __construct() { - // Init SplPriorityQueue. - $this->scheduler = new SplPriorityQueue(); - $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new \SplPriorityQueue(); + $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); } /** @@ -242,10 +240,11 @@ public function offWritable($stream): bool /** * On except. + * * @param resource $stream - * @param $func + * @param callable $func */ - public function onExcept($stream, $func): void + public function onExcept($stream, callable $func): void { $fdKey = (int)$stream; $this->exceptEvents[$fdKey] = $func; @@ -254,6 +253,7 @@ public function onExcept($stream, $func): void /** * Off except. + * * @param resource $stream * @return bool */ @@ -276,7 +276,7 @@ public function onSignal(int $signal, callable $func): void return; } $this->signalEvents[$signal] = $func; - pcntl_signal($signal, $this->signalHandler(...)); + pcntl_signal($signal, fn () => $this->safeCall($this->signalEvents[$signal], [$signal])); } /** @@ -295,21 +295,11 @@ public function offSignal(int $signal): bool return false; } - /** - * Signal handler. - * - * @param int $signal - */ - public function signalHandler(int $signal): void - { - $this->signalEvents[$signal]($signal); - } - /** * Tick for timer. * * @return void - * @throws Throwable + * @throws \Throwable */ protected function tick(): void { @@ -320,6 +310,7 @@ protected function tick(): void $nextRunTime = -$schedulerData['priority']; $timeNow = microtime(true); $this->selectTimeout = (int)(($nextRunTime - $timeNow) * 1000000); + if ($this->selectTimeout <= 0) { $this->scheduler->extract(); @@ -335,12 +326,7 @@ protected function tick(): void } else { unset($this->eventTimer[$timerId]); } - try { - $taskData[0](...$taskData[1]); - } catch (Throwable $e) { - $this->error($e); - continue; - } + $this->safeCall($taskData[0], $taskData[1]); } else { break; } @@ -363,8 +349,8 @@ protected function tick(): void */ public function deleteAllTimer(): void { - $this->scheduler = new SplPriorityQueue(); - $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new \SplPriorityQueue(); + $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); $this->eventTimer = []; } @@ -377,11 +363,12 @@ public function run(): void $read = $this->readFds; $write = $this->writeFds; $except = $this->exceptFds; - if ($read || $write || $except) { + if (!empty($read) || !empty($write) || !empty($except)) { // Waiting read/write/signal/timeout events. try { @stream_select($read, $write, $except, 0, $this->selectTimeout); - } catch (Throwable) { + } catch (\Throwable) { + // do nothing } } else { $this->selectTimeout >= 1 && usleep($this->selectTimeout); @@ -394,21 +381,21 @@ public function run(): void foreach ($read as $fd) { $fdKey = (int)$fd; if (isset($this->readEvents[$fdKey])) { - $this->readEvents[$fdKey]($fd); + $this->safeCall($this->readEvents[$fdKey], [$fd]); } } foreach ($write as $fd) { $fdKey = (int)$fd; if (isset($this->writeEvents[$fdKey])) { - $this->writeEvents[$fdKey]($fd); + $this->safeCall($this->writeEvents[$fdKey], [$fd]); } } foreach ($except as $fd) { $fdKey = (int)$fd; if (isset($this->exceptEvents[$fdKey])) { - $this->exceptEvents[$fdKey]($fd); + $this->safeCall($this->exceptEvents[$fdKey], [$fd]); } } @@ -429,8 +416,13 @@ public function stop(): void foreach ($this->signalEvents as $signal => $item) { $this->offsignal($signal); } - $this->readFds = $this->writeFds = $this->exceptFds = $this->readEvents - = $this->writeEvents = $this->exceptEvents = $this->signalEvents = []; + $this->readFds = []; + $this->writeFds = []; + $this->exceptFds = []; + $this->readEvents = []; + $this->writeEvents = []; + $this->exceptEvents = []; + $this->signalEvents = []; } /** @@ -458,15 +450,20 @@ public function getErrorHandler(): ?callable } /** - * @param Throwable $e + * @param callable $func + * @param array $args * @return void - * @throws Throwable */ - public function error(Throwable $e): void + private function safeCall(callable $func, array $args = []): void { - if (!$this->errorHandler) { - throw new $e; + try { + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } } - ($this->errorHandler)($e); } } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 64e6d1e3e..9f5485383 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -18,25 +18,27 @@ use Swoole\Event; use Swoole\Process; use Swoole\Timer; -use Throwable; class Swoole implements EventInterface { /** * All listeners for read timer - * @var array + * + * @var array */ protected array $eventTimer = []; /** * All listeners for read event. - * @var array + * + * @var array */ protected array $readEvents = []; /** * All listeners for write event. - * @var array + * + * @var array */ protected array $writeEvents = []; @@ -47,7 +49,6 @@ class Swoole implements EventInterface /** * {@inheritdoc} - * @throws Throwable */ public function delay(float $delay, callable $func, array $args = []): int { @@ -55,11 +56,7 @@ public function delay(float $delay, callable $func, array $args = []): int $t = max($t, 1); $timerId = Timer::after($t, function () use ($func, $args, &$timerId) { unset($this->eventTimer[$timerId]); - try { - $func(...$args); - } catch (Throwable $e) { - $this->error($e); - } + $this->safeCall($func, $args); }); $this->eventTimer[$timerId] = $timerId; return $timerId; @@ -71,9 +68,9 @@ public function delay(float $delay, callable $func, array $args = []): int public function offDelay(int $timerId): bool { if (isset($this->eventTimer[$timerId])) { - $res = Timer::clear($timerId); + Timer::clear($timerId); unset($this->eventTimer[$timerId]); - return $res; + return true; } return false; } @@ -88,18 +85,13 @@ public function offRepeat(int $timerId): bool /** * {@inheritdoc} - * @throws Throwable */ public function repeat(float $interval, callable $func, array $args = []): int { $t = (int)($interval * 1000); $t = max($t, 1); $timerId = Timer::tick($t, function () use ($func, $args) { - try { - $func(...$args); - } catch (Throwable $e) { - $this->error($e); - } + $this->safeCall($func, $args); }); $this->eventTimer[$timerId] = $timerId; return $timerId; @@ -112,14 +104,13 @@ public function onReadable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, $func, null, SWOOLE_EVENT_READ); + Event::add($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ); + } elseif (isset($this->writeEvents[$fd])) { + Event::set($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); } else { - if (isset($this->writeEvents[$fd])) { - Event::set($stream, $func, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); - } else { - Event::set($stream, $func, null, SWOOLE_EVENT_READ); - } + Event::set($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ); } + $this->readEvents[$fd] = $stream; } @@ -148,14 +139,13 @@ public function onWritable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, null, $func, SWOOLE_EVENT_WRITE); + Event::add($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE); + } elseif (isset($this->readEvents[$fd])) { + Event::set($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); } else { - if (isset($this->readEvents[$fd])) { - Event::set($stream, null, $func, SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); - } else { - Event::set($stream, null, $func, SWOOLE_EVENT_WRITE); - } + Event::set($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE); } + $this->writeEvents[$fd] = $stream; } @@ -182,7 +172,7 @@ public function offWritable($stream): bool */ public function onSignal(int $signal, callable $func): void { - Process::signal($signal, $func); + Process::signal($signal, fn () => $this->safeCall($func, [$signal])); } /** @@ -252,15 +242,20 @@ public function getErrorHandler(): ?callable } /** - * @param Throwable $e + * @param callable $func + * @param array $args * @return void - * @throws Throwable */ - public function error(Throwable $e): void + private function safeCall(callable $func, array $args = []): void { - if (!$this->errorHandler) { - throw new $e; + try { + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } } - ($this->errorHandler)($e); } } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 5ac0b37b3..38bf4ca11 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -4,36 +4,36 @@ namespace Workerman\Events; -use RuntimeException; use Swow\Coroutine; use Swow\Signal; use Swow\SignalException; -use Throwable; use function Swow\Sync\waitAll; class Swow implements EventInterface { /** - * All listeners for read timer - * @var array + * All listeners for read timer. + * + * @var array */ protected array $eventTimer = []; /** * All listeners for read event. - * @var array + * + * @var array */ protected array $readEvents = []; /** * All listeners for write event. - * @var array + * @var array */ protected array $writeEvents = []; /** * All listeners for signal. - * @var array + * @var array */ protected array $signalListener = []; @@ -54,21 +54,15 @@ public function getTimerCount(): int /** * {@inheritdoc} - * @throws Throwable */ public function delay(float $delay, callable $func, array $args = []): int { $t = (int)($delay * 1000); $t = max($t, 1); - $that = $this; - $coroutine = Coroutine::run(function () use ($t, $func, $args, $that): void { + $coroutine = Coroutine::run(function () use ($t, $func, $args): void { msleep($t); unset($this->eventTimer[Coroutine::getCurrent()->getId()]); - try { - $func(...$args); - } catch (Throwable $e) { - $that->error($e); - } + $this->safeCall($func, $args); }); $timerId = $coroutine->getId(); $this->eventTimer[$timerId] = $timerId; @@ -77,22 +71,16 @@ public function delay(float $delay, callable $func, array $args = []): int /** * {@inheritdoc} - * @throws Throwable */ public function repeat(float $interval, callable $func, array $args = []): int { $t = (int)($interval * 1000); $t = max($t, 1); - $that = $this; - $coroutine = Coroutine::run(static function () use ($t, $func, $args, $that): void { + $coroutine = Coroutine::run(function () use ($t, $func, $args): void { // @phpstan-ignore-next-line While loop condition is always true. while (true) { msleep($t); - try { - $func(...$args); - } catch (Throwable $e) { - $that->error($e); - } + $this->safeCall($func, $args); } }); $timerId = $coroutine->getId(); @@ -156,14 +144,14 @@ public function onReadable($stream, callable $func): void break; } if ($rEvent !== STREAM_POLLNONE) { - $func($stream); + $this->safeCall($func, [$stream]); } if ($rEvent !== STREAM_POLLIN) { $this->offReadable($stream); break; } } - } catch (RuntimeException) { + } catch (\RuntimeException) { $this->offReadable($stream); } }); @@ -201,14 +189,14 @@ public function onWritable($stream, callable $func): void break; } if ($rEvent !== STREAM_POLLNONE) { - $func($stream); + $this->safeCall($func, [$stream]); } if ($rEvent !== STREAM_POLLOUT) { $this->offWritable($stream); break; } } - } catch (RuntimeException) { + } catch (\RuntimeException) { $this->offWritable($stream); } }); @@ -241,8 +229,9 @@ public function onSignal(int $signal, callable $func): void $this->signalListener[$signal] !== Coroutine::getCurrent()) { break; } - $func($signal); + $this->safeCall($func, [$signal]); } catch (SignalException) { + // do nothing } } }); @@ -295,15 +284,20 @@ public function getErrorHandler(): ?callable } /** - * @param Throwable $e + * @param callable $func + * @param array $args * @return void - * @throws Throwable */ - public function error(Throwable $e): void + private function safeCall(callable $func, array $args = []): void { - if (!$this->errorHandler) { - throw new $e; + try { + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } } - ($this->errorHandler)($e); } -} \ No newline at end of file +} diff --git a/src/Worker.php b/src/Worker.php index b9e22fa5c..a5dea3cb5 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2539,16 +2539,16 @@ protected function acceptTcpConnection(mixed $socket): void * For udp package. * * @param resource $socket - * @return bool + * @return void * @throws Throwable */ - protected function acceptUdpConnection(mixed $socket): bool + protected function acceptUdpConnection(mixed $socket): void { set_error_handler(function () {}); $recvBuffer = stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { - return false; + return; } // UdpConnection. $connection = new UdpConnection($socket, $remoteAddress); @@ -2564,7 +2564,7 @@ protected function acceptUdpConnection(mixed $socket): bool while ($recvBuffer !== '') { $len = $parser::input($recvBuffer, $connection); if ($len === 0) { - return true; + return; } $package = substr($recvBuffer, 0, $len); $recvBuffer = substr($recvBuffer, $len); @@ -2578,7 +2578,7 @@ protected function acceptUdpConnection(mixed $socket): bool $data = $parser::decode($recvBuffer, $connection); // Discard bad packets. if ($data === false) { - return true; + return; } $messageCallback($connection, $data); } @@ -2590,7 +2590,6 @@ protected function acceptUdpConnection(mixed $socket): bool static::stopAll(250, $e); } } - return true; } /** From d9fade889994981823f7c42253ebee66b9ac5a26 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 14:22:10 +0800 Subject: [PATCH 0974/1216] Finalize Event classes --- src/Events/Ev.php | 14 +++++++------- src/Events/Event.php | 18 +++++++++--------- src/Events/Revolt.php | 14 +++++++------- src/Events/Select.php | 28 ++++++++++++++-------------- src/Events/Swoole.php | 10 +++++----- src/Events/Swow.php | 12 ++++++------ 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 2a669e944..3de774041 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -18,47 +18,47 @@ /** * Ev eventloop */ -class Ev implements EventInterface +final class Ev implements EventInterface { /** * All listeners for read event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for write event. * * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * Event listeners of signal. * * @var array */ - protected array $eventSignal = []; + private array $eventSignal = []; /** * All timer event listeners. * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * @var ?callable */ - protected $errorHandler = null; + private $errorHandler = null; /** * Timer id. * * @var int */ - protected static int $timerId = 1; + private static int $timerId = 1; /** * {@inheritdoc} diff --git a/src/Events/Event.php b/src/Events/Event.php index 10be122ea..0f856405b 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -19,61 +19,61 @@ /** * libevent eventloop */ -class Event implements EventInterface +final class Event implements EventInterface { /** * Event base. * * @var \EventBase */ - protected \EventBase $eventBase; + private \EventBase $eventBase; /** * All listeners for read event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for write event. * * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * Event listeners of signal. * * @var array */ - protected array $eventSignal = []; + private array $eventSignal = []; /** * All timer event listeners. * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * Timer id. * * @var int */ - protected int $timerId = 0; + private int $timerId = 0; /** * Event class name. * * @var string */ - protected string $eventClassName = ''; + private string $eventClassName = ''; /** * @var ?callable */ - protected $errorHandler = null; + private $errorHandler = null; /** * Construct. diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 9e5aec857..7413c71ec 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -25,47 +25,47 @@ /** * Revolt eventloop */ -class Revolt implements EventInterface +final class Revolt implements EventInterface { /** * @var Driver */ - protected Driver $driver; + private Driver $driver; /** * All listeners for read event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for write event. * * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * Event listeners of signal. * * @var array */ - protected array $eventSignal = []; + private array $eventSignal = []; /** * Event listeners of timer. * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * Timer id. * * @var int */ - protected int $timerId = 1; + private int $timerId = 1; /** * Construct. diff --git a/src/Events/Select.php b/src/Events/Select.php index 1ad06cbc4..26bc0db06 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -26,61 +26,61 @@ /** * select eventloop */ -class Select implements EventInterface +final class Select implements EventInterface { /** * Running. * * @var bool */ - protected bool $running = true; + private bool $running = true; /** * All listeners for read/write event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for read/write event. * * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * @var array */ - protected array $exceptEvents = []; + private array $exceptEvents = []; /** * Event listeners of signal. * * @var array */ - protected array $signalEvents = []; + private array $signalEvents = []; /** * Fds waiting for read event. * * @var array */ - protected array $readFds = []; + private array $readFds = []; /** * Fds waiting for write event. * * @var array */ - protected array $writeFds = []; + private array $writeFds = []; /** * Fds waiting for except event. * * @var array */ - protected array $exceptFds = []; + private array $exceptFds = []; /** * Timer scheduler. @@ -88,7 +88,7 @@ class Select implements EventInterface * * @var \SplPriorityQueue */ - protected \SplPriorityQueue $scheduler; + private \SplPriorityQueue $scheduler; /** * All timer event listeners. @@ -96,26 +96,26 @@ class Select implements EventInterface * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * Timer id. * * @var int */ - protected int $timerId = 1; + private int $timerId = 1; /** * Select timeout. * * @var int */ - protected int $selectTimeout = 100000000; + private int $selectTimeout = 100000000; /** * @var ?callable */ - protected $errorHandler = null; + private $errorHandler = null; /** * Construct. diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 9f5485383..24ce6732b 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -19,33 +19,33 @@ use Swoole\Process; use Swoole\Timer; -class Swoole implements EventInterface +final class Swoole implements EventInterface { /** * All listeners for read timer * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * All listeners for read event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for write event. * * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * @var ?callable */ - protected $errorHandler = null; + private $errorHandler = null; /** * {@inheritdoc} diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 38bf4ca11..4dab6d8d6 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -9,38 +9,38 @@ use Swow\SignalException; use function Swow\Sync\waitAll; -class Swow implements EventInterface +final class Swow implements EventInterface { /** * All listeners for read timer. * * @var array */ - protected array $eventTimer = []; + private array $eventTimer = []; /** * All listeners for read event. * * @var array */ - protected array $readEvents = []; + private array $readEvents = []; /** * All listeners for write event. * @var array */ - protected array $writeEvents = []; + private array $writeEvents = []; /** * All listeners for signal. * @var array */ - protected array $signalListener = []; + private array $signalListener = []; /** * @var ?callable */ - protected $errorHandler = null; + private $errorHandler = null; /** * Get timer count. From 4f4e6562062c852fad37119bd9e56e86ba421ca8 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 14:40:42 +0800 Subject: [PATCH 0975/1216] Fix closure definition and codestyle fix --- src/Events/Revolt.php | 2 +- src/Events/Swow.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 9e5aec857..0924c41b7 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -113,7 +113,7 @@ public function stop(): void public function delay(float $delay, callable $func, array $args = []): int { $timerId = $this->timerId++; - $closure = static function () use ($func, $args, $timerId) { + $closure = function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); $func(...$args); }; diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 38bf4ca11..05a761779 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -27,12 +27,14 @@ class Swow implements EventInterface /** * All listeners for write event. + * * @var array */ protected array $writeEvents = []; /** * All listeners for signal. + * * @var array */ protected array $signalListener = []; From b2b82439225436c234a37b27fe1d482f4d5329da Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 15:58:40 +0800 Subject: [PATCH 0976/1216] Removed some ignoreErrors from phpstan and resolve those errors --- phpstan.neon.dist | 3 --- src/Connection/TcpConnection.php | 5 +++-- src/Worker.php | 19 ++++++++++--------- tests/Pest.php | 4 ---- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fad677a19..72557b042 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -27,8 +27,5 @@ parameters: - '#Property Workerman\\Events\\Swow::.* has unknown class Swow\\Coroutine as its type.#' - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - - path: tests/Pest.php - message: '#Undefined variable: \$this#' - path: src/Worker.php message: '#Constant LINE_VERSION_LENGTH not found.#' - - message: '#Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\): bool\)\|null,.*#' \ No newline at end of file diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 6556a1fe3..c5a0b81e7 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -816,10 +816,11 @@ public function doSslHandshake($socket): bool|int } // Hidden error. - set_error_handler(function ($errno, $err_str) { + set_error_handler(static function (int $code, string $msg): bool { if (!Worker::$daemonize) { - Worker::safeEcho("SSL handshake error: $err_str \n"); + Worker::safeEcho(sprintf("SSL handshake error: %s\n", $msg)); } + return true; }); $ret = stream_socket_enable_crypto($socket, true, $type); restore_error_handler(); diff --git a/src/Worker.php b/src/Worker.php index b9e22fa5c..de24cb9aa 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -598,8 +598,9 @@ protected static function checkSapiEnv(): void */ protected static function init(): void { - set_error_handler(function ($code, $msg, $file, $line) { - static::safeEcho("$msg in file $file on line $line\n"); + set_error_handler(static function (int $code, string $msg, string $file, int $line): bool { + static::safeEcho(sprintf("%s \"%s\" in file %s on line %d\n", static::getErrorType($code), $msg, $file, $line)); + return true; }); // Start file. @@ -1280,7 +1281,7 @@ public static function resetStd(bool $throwException = true): void $handle = fopen(static::$stdoutFile, "a"); if ($handle) { unset($handle); - set_error_handler(function () {}); + set_error_handler(static fn (): bool => true); if ($STDOUT) { fclose($STDOUT); } @@ -1675,7 +1676,7 @@ public function setUserAndGroup(): void */ protected static function setProcessTitle(string $title): void { - set_error_handler(function (){}); + set_error_handler(static fn (): bool => true); cli_set_process_title($title); restore_error_handler(); } @@ -2273,7 +2274,7 @@ public function __construct(string $socketName = null, array $socketContext = [] $address = \parse_url($socketName); if (isset($address['host']) && isset($address['port'])) { try { - \set_error_handler(function(){}); + \set_error_handler(static fn (): bool => true); // If address not in use, turn reusePort on automatically. $server = stream_socket_server("tcp://{$address['host']}:{$address['port']}"); if ($server) { @@ -2330,7 +2331,7 @@ public function listen(): void // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && self::BUILD_IN_TRANSPORTS[$this->transport] === 'tcp') { - set_error_handler(function () {}); + set_error_handler(static fn (): bool => true); $socket = socket_import_stream($this->mainSocket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); @@ -2353,7 +2354,7 @@ public function unlisten(): void { $this->pauseAccept(); if ($this->mainSocket) { - set_error_handler(function () {}); + set_error_handler(static fn (): bool => true); fclose($this->mainSocket); restore_error_handler(); $this->mainSocket = null; @@ -2504,7 +2505,7 @@ public function stop(): void protected function acceptTcpConnection(mixed $socket): void { // Accept a connection on server socket. - set_error_handler(function () {}); + set_error_handler(static fn (): bool => true); $newSocket = stream_socket_accept($socket, 0, $remoteAddress); restore_error_handler(); @@ -2544,7 +2545,7 @@ protected function acceptTcpConnection(mixed $socket): void */ protected function acceptUdpConnection(mixed $socket): bool { - set_error_handler(function () {}); + set_error_handler(static fn (): bool => true); $recvBuffer = stream_socket_recvfrom($socket, UdpConnection::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress); restore_error_handler(); if (false === $recvBuffer || empty($remoteAddress)) { diff --git a/tests/Pest.php b/tests/Pest.php index 19f6fad10..7db6ab1bc 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -26,10 +26,6 @@ use Workerman\Connection\TcpConnection; -expect()->extend('toBeOne', function () { - return $this->toBe(1); -}); - /* |-------------------------------------------------------------------------- | Functions From b3b8c99774e2002a66e89f41c7ec77fa2099715a Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 17:49:00 +0800 Subject: [PATCH 0977/1216] Rewrited $eventLoopClass initialization process. Print all throwed exceptions through Worker::log method. --- src/Worker.php | 133 +++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 71 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index b9e22fa5c..9b6787131 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -279,9 +279,9 @@ class Worker /** * Log file. * - * @var mixed + * @var string */ - public static mixed $logFile = ''; + public static string $logFile; /** * Global event loop. @@ -314,9 +314,9 @@ class Worker /** * EventLoopClass * - * @var string|class-string + * @var class-string */ - public static string $eventLoopClass = ''; + public static string $eventLoopClass; /** * After sending the stop command to the child process stopTimeout seconds, @@ -485,15 +485,6 @@ class Worker 'worker_exit_info' => [] ]; - /** - * Available event loops. - * - * @var array - */ - protected static array $availableEventLoops = [ - 'event' => Event::class, - ]; - /** * PHP built-in protocols. * @@ -563,19 +554,23 @@ class Worker */ public static function runAll(): void { - static::checkSapiEnv(); - static::init(); - static::parseCommand(); - static::lock(); - static::daemonize(); - static::initWorkers(); - static::installSignal(); - static::saveMasterPid(); - static::lock(LOCK_UN); - static::displayUI(); - static::forkWorkers(); - static::resetStd(); - static::monitorWorkers(); + try { + static::checkSapiEnv(); + static::init(); + static::parseCommand(); + static::lock(); + static::daemonize(); + static::initWorkers(); + static::installSignal(); + static::saveMasterPid(); + static::lock(LOCK_UN); + static::displayUI(); + static::forkWorkers(); + static::resetStd(); + static::monitorWorkers(); + } catch (\Throwable $e) { + static::log($e); + } } /** @@ -587,7 +582,7 @@ protected static function checkSapiEnv(): void { // Only for cli and micro. if (!in_array(\PHP_SAPI, ['cli', 'micro'])) { - exit("Only run in command line mode\n"); + throw new \RuntimeException("Only run in command line mode"); } } @@ -630,8 +625,8 @@ protected static function init(): void // State. static::$status = static::STATUS_STARTING; - // Avoiding incorrect user calls. - static::resetGlobalEvent(); + // Init global event. + static::initGlobalEvent(); // For statistics. static::$globalStatistics['start_timestamp'] = time(); @@ -647,16 +642,30 @@ protected static function init(): void } /** - * reset globalEvent Instance. + * Init global event. * * @return void */ - protected static function resetGlobalEvent(): void + protected static function initGlobalEvent(): void { - if (static::$status === static::STATUS_STARTING && static::$globalEvent instanceof EventInterface) { + if (static::$globalEvent !== null) { static::$eventLoopClass = get_class(static::$globalEvent); static::$globalEvent = null; + return; } + + if (isset(static::$eventLoopClass)) { + if (!is_subclass_of(static::$eventLoopClass, EventInterface::class)) { + throw new RuntimeException(sprintf('%s::$eventLoopClass must implement %s', static::class, EventInterface::class)); + } + return; + } + + static::$eventLoopClass = match (true) { + class_exists(EventLoop::class) => Revolt::class, + extension_loaded('event') => Event::class, + default => Select::class, + }; } /** @@ -1332,32 +1341,10 @@ protected static function saveMasterPid(): void /** * Get event loop name. * - * @return string + * @return class-string */ protected static function getEventLoopName(): string { - if (static::$eventLoopClass) { - return static::$eventLoopClass; - } - - if (class_exists(EventLoop::class)) { - static::$eventLoopClass = Revolt::class; - return static::$eventLoopClass; - } - - $loopName = ''; - foreach (static::$availableEventLoops as $name => $class) { - if (extension_loaded($name)) { - $loopName = $name; - break; - } - } - - if ($loopName) { - static::$eventLoopClass = static::$availableEventLoops[$loopName]; - } else { - static::$eventLoopClass = Select::class; - } return static::$eventLoopClass; } @@ -1447,9 +1434,9 @@ protected static function forkWorkersForWindows(): void register_shutdown_function(static::checkErrors(...)); // Create a global event loop. - if (!static::$globalEvent) { + if (static::$globalEvent === null) { $eventLoopClass = static::getEventLoopName(); - static::$globalEvent = new $eventLoopClass; + static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); }); @@ -1517,7 +1504,7 @@ public static function forkOneWorkerForWindows(string $startFile): void $pipes = []; $process = proc_open('"' . PHP_BINARY . '" ' . " \"$startFile\" -q", $descriptorSpec, $pipes, null, null, ['bypass_shell' => true]); - if (empty(static::$globalEvent)) { + if (static::$globalEvent === null) { static::$globalEvent = new Select(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); @@ -1588,9 +1575,9 @@ protected static function forkOneWorkerForLinux(self $worker): void register_shutdown_function(static::checkErrors(...)); // Create a global event loop. - if (!static::$globalEvent) { + if (static::$globalEvent === null) { $eventLoopClass = static::getEventLoopName(); - static::$globalEvent = new $eventLoopClass; + static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); }); @@ -1798,7 +1785,7 @@ protected static function exitAndClearAll(): void @unlink(static::$pidFile); static::log("Workerman[" . basename(static::$startFile) . "] has been stopped"); if (static::$onMasterStop) { - call_user_func(static::$onMasterStop); + (static::$onMasterStop)(); } exit(0); } @@ -1823,7 +1810,7 @@ protected static function reload(): void // Try to emit onMasterReload callback. if (static::$onMasterReload) { try { - call_user_func(static::$onMasterReload); + (static::$onMasterReload)(); } catch (Throwable $e) { static::stopAll(250, $e); } @@ -1867,7 +1854,7 @@ protected static function reload(): void // Try to emit onWorkerReload callback. if ($worker->onWorkerReload) { try { - call_user_func($worker->onWorkerReload, $worker); + ($worker->onWorkerReload)($worker); } catch (Throwable $e) { static::stopAll(250, $e); } @@ -2165,18 +2152,22 @@ protected static function getErrorType(int $type): string /** * Log. * - * @param mixed $msg + * @param \Stringable|string $msg * @param bool $decorated * @return void */ - public static function log(mixed $msg, bool $decorated = false): void + public static function log(\Stringable|string $msg, bool $decorated = false): void { - $msg .= "\n"; + $msg = trim((string)$msg); + if (!static::$daemonize) { - static::safeEcho($msg, $decorated); + static::safeEcho("$msg\n", $decorated); + } + + if (isset(static::$logFile)) { + $pid = DIRECTORY_SEPARATOR === '/' ? posix_getpid() : 1; + file_put_contents(static::$logFile, sprintf("%s pid:%d %s\n", date('Y-m-d H:i:s'), $pid, $msg), FILE_APPEND | LOCK_EX); } - file_put_contents(static::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:' - . (DIRECTORY_SEPARATOR === '/' ? posix_getpid() : 1) . ' ' . $msg, FILE_APPEND | LOCK_EX); } /** @@ -2400,7 +2391,7 @@ protected function parseSocketAddress(): ?string */ public function pauseAccept(): void { - if (static::$globalEvent && false === $this->pauseAccept && $this->mainSocket) { + if (static::$globalEvent !== null && $this->pauseAccept === false && $this->mainSocket !== null) { static::$globalEvent->offReadable($this->mainSocket); $this->pauseAccept = true; } @@ -2414,7 +2405,7 @@ public function pauseAccept(): void public function resumeAccept(): void { // Register a listener to be notified when server socket is ready to read. - if (static::$globalEvent && true === $this->pauseAccept && $this->mainSocket) { + if (static::$globalEvent !== null && $this->pauseAccept === true && $this->mainSocket !== null) { if ($this->transport !== 'udp') { static::$globalEvent->onReadable($this->mainSocket, $this->acceptTcpConnection(...)); } else { From f34e31fb2085c58ea6a37964f5e0bbd659401a51 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 4 Nov 2023 20:48:50 +0800 Subject: [PATCH 0978/1216] Remove getErrorHandler --- src/Events/Ev.php | 8 -------- src/Events/Event.php | 8 -------- src/Events/EventInterface.php | 7 ------- src/Events/Revolt.php | 8 -------- src/Events/Select.php | 8 -------- src/Events/Swoole.php | 8 -------- src/Events/Swow.php | 8 -------- 7 files changed, 55 deletions(-) diff --git a/src/Events/Ev.php b/src/Events/Ev.php index 3de774041..67c165295 100644 --- a/src/Events/Ev.php +++ b/src/Events/Ev.php @@ -218,14 +218,6 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->errorHandler; - } - /** * @param callable $func * @param array $args diff --git a/src/Events/Event.php b/src/Events/Event.php index 0f856405b..51fcead36 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -272,14 +272,6 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->errorHandler; - } - /** * @param callable $func * @param array $args diff --git a/src/Events/EventInterface.php b/src/Events/EventInterface.php index edc09373a..4d538c694 100644 --- a/src/Events/EventInterface.php +++ b/src/Events/EventInterface.php @@ -140,11 +140,4 @@ public function getTimerCount(): int; * @return void */ public function setErrorHandler(callable $errorHandler): void; - - /** - * Get error handler - * - * @return null|callable (\Throwable): void - */ - public function getErrorHandler(): ?callable; } diff --git a/src/Events/Revolt.php b/src/Events/Revolt.php index 7413c71ec..bb985de68 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Revolt.php @@ -262,12 +262,4 @@ public function setErrorHandler(callable $errorHandler): void { $this->driver->setErrorHandler($errorHandler); } - - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->driver->getErrorHandler(); - } } diff --git a/src/Events/Select.php b/src/Events/Select.php index 26bc0db06..f8ec7ec71 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -441,14 +441,6 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->errorHandler; - } - /** * @param callable $func * @param array $args diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 24ce6732b..e703d14b5 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -233,14 +233,6 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->errorHandler; - } - /** * @param callable $func * @param array $args diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 4dab6d8d6..d3d3a3568 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -275,14 +275,6 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } - /** - * {@inheritdoc} - */ - public function getErrorHandler(): ?callable - { - return $this->errorHandler; - } - /** * @param callable $func * @param array $args From 4d2f1f1f71550fac32ba81affa4f441493f1898f Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 5 Nov 2023 20:16:13 +0800 Subject: [PATCH 0979/1216] Temp files processing refactoring --- src/Worker.php | 120 +++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 63 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 52a3847e6..67970f050 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -267,14 +267,21 @@ class Worker * * @var string */ - public static string $pidFile = ''; + public static string $pidFile; /** - * The file used to store the master process status file. + * The file used to store the master process status. * * @var string */ - public static string $statusFile = ''; + public static string $processStatusFile; + + /** + * The file used to store connections status. + * + * @var string + */ + public static string $connectionStatusFile; /** * Log file. @@ -454,19 +461,12 @@ class Worker */ protected static int $maxStateNameLength = 1; - /** - * The file to store status info of current worker process. - * - * @var string - */ - protected static string $statisticsFile = ''; - /** * Start file. * * @var string */ - protected static string $startFile = ''; + protected static string $startFile; /** * Processes for windows. @@ -600,19 +600,20 @@ protected static function init(): void // Start file. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - static::$startFile = end($backtrace)['file']; - - $uniquePrefix = str_replace('/', '_', static::$startFile); + static::$startFile ??= end($backtrace)['file']; + $startFilePrefix = hash('xxh64', static::$startFile); // Pid file. - if (empty(static::$pidFile)) { - static::$pidFile = __DIR__ . "/../$uniquePrefix.pid"; - } + static::$pidFile ??= sprintf('%s/workerman.%s.pid', sys_get_temp_dir(), $startFilePrefix); + + // Process status file. + static::$processStatusFile ??= sprintf('%s/workerman.%s.process.status', sys_get_temp_dir(), $startFilePrefix); + + // Connections status file. + static::$connectionStatusFile ??= sprintf('%s/workerman.%s.connection.status', sys_get_temp_dir(), $startFilePrefix); // Log file. - if (empty(static::$logFile)) { - static::$logFile = __DIR__ . '/../../workerman.log'; - } + static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); if (!is_file(static::$logFile)) { // if /runtime/logs default folder not exists @@ -707,7 +708,7 @@ protected static function initWorkers(): void if (DIRECTORY_SEPARATOR !== '/') { return; } - static::$statisticsFile = static::$statusFile ?: __DIR__ . '/../workerman-' . posix_getpid() . '.status'; + foreach (static::$workers as $worker) { // Worker name. if (empty($worker->name)) { @@ -970,8 +971,6 @@ protected static function parseCommand(): void exit; } - $statisticsFile = static::$statusFile ?: __DIR__ . "/../workerman-$masterPid.$command"; - // execute command. switch ($command) { case 'start': @@ -980,38 +979,33 @@ protected static function parseCommand(): void } break; case 'status': + // Delete status file on shutdown + register_shutdown_function(unlink(...), static::$processStatusFile); while (1) { - if (is_file($statisticsFile)) { - @unlink($statisticsFile); - } // Master process will send SIGIOT signal to all child processes. posix_kill($masterPid, SIGIOT); - // Sleep 1 second. - sleep(1); + // Waiting a moment. + usleep(500000); // Clear terminal. if ($mode === '-d') { static::safeEcho("\33[H\33[2J\33(B\33[m", true); } // Echo status data. - static::safeEcho(static::formatStatusData($statisticsFile)); + static::safeEcho(static::formatProcessStatusData()); if ($mode !== '-d') { - @unlink($statisticsFile); exit(0); } static::safeEcho("\nPress Ctrl+C to quit.\n\n"); } case 'connections': - if (is_file($statisticsFile) && is_writable($statisticsFile)) { - unlink($statisticsFile); - } + // Delete status file on shutdown + register_shutdown_function(unlink(...), static::$connectionStatusFile); // Master process will send SIGIO signal to all child processes. posix_kill($masterPid, SIGIO); // Waiting a moment. usleep(500000); // Display statistics data from a disk file. - if (is_readable($statisticsFile)) { - readfile($statisticsFile); - } + static::safeEcho(static::formatConnectionStatusData()); exit(0); case 'restart': case 'stop': @@ -1081,16 +1075,15 @@ public static function getArgv(): array /** * Format status data. * - * @param string $statisticsFile * @return string */ - protected static function formatStatusData(string $statisticsFile): string + protected static function formatProcessStatusData(): string { static $totalRequestCache = []; - if (!is_readable($statisticsFile)) { + if (!is_readable(static::$processStatusFile)) { return ''; } - $info = file($statisticsFile, FILE_IGNORE_NEW_LINES); + $info = file(static::$processStatusFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } @@ -1166,6 +1159,11 @@ protected static function formatStatusData(string $statisticsFile): string return $statusStr; } + protected static function formatConnectionStatusData(): string + { + return file_get_contents(static::$connectionStatusFile); + } + /** * Install signal handler. * @@ -1901,10 +1899,6 @@ public static function stopAll(int $code = 0, mixed $log = ''): void } } Timer::add(1, static::checkIfChildRunning(...)); - // Remove statistics file. - if (is_file(static::$statisticsFile)) { - @unlink(static::$statisticsFile); - } } // For child processes. else { // Execute exit. @@ -1976,48 +1970,47 @@ protected static function writeStatisticsToStatusFile(): void $allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } - - file_put_contents(static::$statisticsFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); + file_put_contents(static::$processStatusFile, ''); + chmod(static::$processStatusFile, 0722); + file_put_contents(static::$processStatusFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map(round(...), sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, 'start time:' . date('Y-m-d H:i:s', + file_put_contents(static::$processStatusFile, 'start time:' . date('Y-m-d H:i:s', static::$globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); $loadStr = 'load average: ' . implode(", ", $loadavg); - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad((string)$workerExitStatus, 16) . " $workerExitCount\n", FILE_APPEND); } } else { - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad('0', 16) . " 0\n", FILE_APPEND); } } - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, + file_put_contents(static::$processStatusFile, "pid\tmemory " . str_pad('listening', static::$maxSocketNameLength) . " " . str_pad('worker_name', static::$maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . str_pad('total_request', 13) . " qps status\n", FILE_APPEND); - chmod(static::$statisticsFile, 0722); - foreach (static::getAllWorkerPids() as $workerPid) { posix_kill($workerPid, SIGIOT); } @@ -2038,7 +2031,7 @@ protected static function writeStatisticsToStatusFile(): void . " " . str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) . " " . str_pad((string)static::$globalEvent->getTimerCount(), 7) . " " . str_pad((string)ConnectionInterface::$statistics['total_request'], 13) . "\n"; - file_put_contents(static::$statisticsFile, $workerStatusStr, FILE_APPEND); + file_put_contents(static::$processStatusFile, $workerStatusStr, FILE_APPEND); } /** @@ -2050,9 +2043,10 @@ protected static function writeConnectionsStatisticsToStatusFile(): void { // For master process. if (static::$masterPid === posix_getpid()) { - file_put_contents(static::$statisticsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); - chmod(static::$statisticsFile, 0722); + file_put_contents(static::$connectionStatusFile, ''); + chmod(static::$connectionStatusFile, 0722); + file_put_contents(static::$connectionStatusFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(static::$connectionStatusFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); foreach (static::getAllWorkerPids() as $workerPid) { posix_kill($workerPid, SIGIO); } @@ -2113,7 +2107,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void . str_pad($state, 14) . ' ' . str_pad($localAddress, 22) . ' ' . str_pad($remoteAddress, 22) . "\n"; } if ($str) { - file_put_contents(static::$statisticsFile, $str, FILE_APPEND); + file_put_contents(static::$connectionStatusFile, $str, FILE_APPEND); } } From a144894b74f5985a70bca0d096a47ad1280e33f4 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 5 Nov 2023 22:24:46 +0800 Subject: [PATCH 0980/1216] Udp and websocket server code stubs moved out to Stub directory --- tests/Feature/HttpConnectionTest.php | 5 +- tests/Feature/Stub/HttpServer.php | 4 +- tests/Feature/Stub/UdpServer.php | 20 +++++ tests/Feature/Stub/WebsocketClient.php | 23 ++++++ tests/Feature/Stub/WebsocketServer.php | 20 +++++ tests/Feature/UdpConnectionTest.php | 27 ++---- tests/Feature/WebsocketServiceTest.php | 92 ++++++--------------- tests/Unit/Connection/UdpConnectionTest.php | 2 +- 8 files changed, 100 insertions(+), 93 deletions(-) create mode 100644 tests/Feature/Stub/UdpServer.php create mode 100644 tests/Feature/Stub/WebsocketClient.php create mode 100644 tests/Feature/Stub/WebsocketServer.php diff --git a/tests/Feature/HttpConnectionTest.php b/tests/Feature/HttpConnectionTest.php index de2063833..592809723 100644 --- a/tests/Feature/HttpConnectionTest.php +++ b/tests/Feature/HttpConnectionTest.php @@ -7,10 +7,9 @@ $process = null; beforeAll(function () use (&$process) { - $code = file_get_contents(__DIR__ . '/Stub/HttpServer.php'); - $process = new PhpProcess($code); + $process = new PhpProcess(file_get_contents(__DIR__ . '/Stub/HttpServer.php')); $process->start(); - sleep(1); + usleep(250000); }); afterAll(function () use (&$process) { diff --git a/tests/Feature/Stub/HttpServer.php b/tests/Feature/Stub/HttpServer.php index fb047cb3f..6d5caa63f 100644 --- a/tests/Feature/Stub/HttpServer.php +++ b/tests/Feature/Stub/HttpServer.php @@ -1,5 +1,7 @@ onMessage = function ($connection, $data) { + $connection->send('received: ' . $data); +}; + +Worker::$command = 'start'; +Worker::runAll(); diff --git a/tests/Feature/Stub/WebsocketClient.php b/tests/Feature/Stub/WebsocketClient.php new file mode 100644 index 000000000..8a440346a --- /dev/null +++ b/tests/Feature/Stub/WebsocketClient.php @@ -0,0 +1,23 @@ +onWorkerStart = function($worker) { + $con = new AsyncTcpConnection('ws://127.0.0.1:8081'); + //%action% + $con->connect(); +}; + +Worker::$pidFile = sprintf('%s/test-websocket-client.pid', sys_get_temp_dir()); +Worker::$command = 'start'; +Worker::runAll(); diff --git a/tests/Feature/Stub/WebsocketServer.php b/tests/Feature/Stub/WebsocketServer.php new file mode 100644 index 000000000..038e8db03 --- /dev/null +++ b/tests/Feature/Stub/WebsocketServer.php @@ -0,0 +1,20 @@ +onMessage = function (\$connection, \$data) { - \$connection->send('received: '.\$data); - }; - Worker::\$command = 'start'; - Worker::runAll(); - PHP - ); +beforeAll(function () use (&$process) { + $process = new PhpProcess(file_get_contents(__DIR__ . '/Stub/UdpServer.php')); $process->start(); - sleep(1); + usleep(250000); }); afterAll(function () use (&$process) { @@ -31,8 +14,8 @@ $process->stop(); }); -it('tests udp connection', function () use ($serverAddress) { - $socket = stream_socket_client($serverAddress, $errno, $errstr, 1); +it('tests udp connection', function () { + $socket = stream_socket_client('udp://127.0.0.1:8083', $errno, $errstr, 1); expect($errno)->toBeInt()->toBe(0); fwrite($socket, 'xiami'); $data = fread($socket, 1024); diff --git a/tests/Feature/WebsocketServiceTest.php b/tests/Feature/WebsocketServiceTest.php index cf1e342a2..420038805 100644 --- a/tests/Feature/WebsocketServiceTest.php +++ b/tests/Feature/WebsocketServiceTest.php @@ -2,60 +2,26 @@ use Symfony\Component\Process\PhpProcess; -$serverCode = <<onWorkerStart = function(\$worker){ - \$con = new AsyncTcpConnection('ws://127.0.0.1:8081'); - %s - \$con->connect(); -}; -Worker::\$pidFile = __DIR__ . '/WebsocketClient.pid'; -Worker::\$command = 'start'; -Worker::runAll(); -PHP; +$serverCode = file_get_contents(__DIR__ . '/Stub/WebsocketServer.php'); +$clientCode = file_get_contents(__DIR__ . '/Stub/WebsocketClient.php'); it('tests websocket connection', function () use ($serverCode, $clientCode) { - $serverProcess = new PhpProcess(sprintf($serverCode, <<onWebSocketConnect = function () { echo "connected"; }; \$worker->onMessage = function () {}; - PHP - )); + PHP)); $serverProcess->start(); - sleep(1); + usleep(250000); - $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { \$con->send('connect'); }; - PHP - )); + PHP)); $clientProcess->start(); - sleep(1); + usleep(250000); expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('connected') ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe(''); @@ -65,27 +31,25 @@ }); it('tests server and client sending and receiving messages', function () use ($serverCode, $clientCode) { - $serverProcess = new PhpProcess(sprintf($serverCode, <<onMessage = function (TcpConnection \$connection, \$data) { echo \$data; \$connection->send('Hi'); }; - PHP - )); + PHP)); $serverProcess->start(); - sleep(1); + usleep(250000); - $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { \$con->send('Hello Chance'); }; \$con->onMessage = function(\$con, \$data) { echo \$data; }; - PHP - )); + PHP)); $clientProcess->start(); - sleep(1); + usleep(250000); expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('Hello Chance') ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('Hi'); @@ -95,28 +59,26 @@ }); it('tests server close connection', function () use ($serverCode, $clientCode) { - $serverProcess = new PhpProcess(sprintf($serverCode, <<onWebSocketConnect = function (TcpConnection \$connection) { echo 'close connection'; \$connection->close(); }; \$worker->onMessage = function () {}; - PHP - )); + PHP)); $serverProcess->start(); - sleep(1); + usleep(250000); - $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { \$con->send('connect'); }; \$con->onClose = function () { echo 'closed'; }; - PHP - )); + PHP)); $clientProcess->start(); - sleep(1); + usleep(250000); expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('close connection') ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('closed'); @@ -126,26 +88,24 @@ }); it('tests client close connection', function () use ($serverCode, $clientCode) { - $serverProcess = new PhpProcess(sprintf($serverCode, <<onMessage = function () {}; \$worker->onClose = function () { echo 'closed'; }; - PHP - )); + PHP)); $serverProcess->start(); - sleep(1); + usleep(250000); - $clientProcess = new PhpProcess(sprintf($clientCode, <<onWebSocketConnect = function(AsyncTcpConnection \$con) { \$con->send('connect'); echo 'close connection'; \$con->close(); }; - PHP - )); + PHP)); $clientProcess->start(); - sleep(1); + usleep(250000); expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('closed') ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('close connection'); diff --git a/tests/Unit/Connection/UdpConnectionTest.php b/tests/Unit/Connection/UdpConnectionTest.php index 706581915..0a0c8522a 100644 --- a/tests/Unit/Connection/UdpConnectionTest.php +++ b/tests/Unit/Connection/UdpConnectionTest.php @@ -16,7 +16,7 @@ PHP ); $process->start(); - sleep(1); + usleep(250000); }); afterAll(function () use (&$process) { From afcc4fda07bbd1bfde4795e0022490632a73587c Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 7 Nov 2023 00:10:26 +0800 Subject: [PATCH 0981/1216] Output stream can now be set with $outputStream property --- src/Worker.php | 181 +++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 95 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 52a3847e6..aac588435 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -255,6 +255,13 @@ class Worker */ public static bool $daemonize = false; + /** + * Standard output stream + * + * @var resource + */ + public static $outputStream; + /** * Stdout file. * @@ -527,17 +534,12 @@ class Worker */ protected static bool $gracefulStop = false; - /** - * Standard output stream - * @var ?resource - */ - protected static $outputStream = null; - /** * If $outputStream support decorated + * * @var bool */ - protected static bool $outputDecorated = false; + protected static bool $outputDecorated; /** * Worker object's hash id(unique identifier). @@ -556,6 +558,7 @@ public static function runAll(): void { try { static::checkSapiEnv(); + self::initStdOut(); static::init(); static::parseCommand(); static::lock(); @@ -582,8 +585,46 @@ protected static function checkSapiEnv(): void { // Only for cli and micro. if (!in_array(\PHP_SAPI, ['cli', 'micro'])) { - throw new \RuntimeException("Only run in command line mode"); + exit("Only run in command line mode\n"); + } + } + + private static function initStdOut(): void + { + $defaultStream = fn () => \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); + static::$outputStream ??= $defaultStream(); //@phpstan-ignore-line + if (!\is_resource(self::$outputStream) || get_resource_type(self::$outputStream) !== 'stream') { + $type = get_debug_type(self::$outputStream); + static::$outputStream = $defaultStream(); + throw new \RuntimeException(sprintf('The $outputStream must to be a stream, %s given', $type)); } + + static::$outputDecorated ??= self::hasColorSupport(); + } + + /** + * Borrowed from the symfony console + * @link https://github.com/symfony/console/blob/0d14a9f6d04d4ac38a8cea1171f4554e325dae92/Output/StreamOutput.php#L92 + */ + private static function hasColorSupport(): bool + { + // Follow https://no-color.org/ + if (getenv('NO_COLOR') !== false) { + return false; + } + + if (getenv('TERM_PROGRAM') === 'Hyper') { + return true; + } + + if (\DIRECTORY_SEPARATOR === '\\') { + return (\function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(self::$outputStream)) + || getenv('ANSICON') !== false + || getenv('ConEmuANSI') === 'ON' + || getenv('TERM') === 'xterm'; + } + + return stream_isatty(self::$outputStream); } /** @@ -1275,50 +1316,32 @@ protected static function daemonize(): void } /** - * Redirect standard input and output. + * Redirect standard output to stdoutFile. * - * @param bool $throwException * @return void - * @throws Exception */ - public static function resetStd(bool $throwException = true): void + public static function resetStd(): void { if (!static::$daemonize || DIRECTORY_SEPARATOR !== '/') { return; } - global $STDOUT, $STDERR; - $handle = fopen(static::$stdoutFile, "a"); - if ($handle) { - unset($handle); - set_error_handler(static fn (): bool => true); - if ($STDOUT) { - fclose($STDOUT); - } - if ($STDERR) { - fclose($STDERR); - } - if (is_resource(STDOUT)) { - fclose(STDOUT); - } - if (is_resource(STDERR)) { - fclose(STDERR); - } - $STDOUT = fopen(static::$stdoutFile, "a"); - $STDERR = fopen(static::$stdoutFile, "a"); - // Fix standard output cannot redirect of PHP 8.1.8's bug - if (function_exists('posix_isatty') && posix_isatty(2)) { - ob_start(function ($string) { - file_put_contents(static::$stdoutFile, $string, FILE_APPEND); - }, 1); - } - // change output stream - static::$outputStream = null; - self::outputStream($STDOUT); - restore_error_handler(); + + set_error_handler(static fn (): bool => true); + $stdOutStream = fopen(static::$stdoutFile, 'a'); + restore_error_handler(); + + if ($stdOutStream === false) { return; } - if ($throwException) { - throw new RuntimeException('Can not open stdoutFile ' . static::$stdoutFile); + + fclose(static::$outputStream); + static::$outputStream = $stdOutStream; + + // Fix standard output cannot redirect of PHP 8.1.8's bug + if (function_exists('posix_isatty') && posix_isatty(2)) { + ob_start(function (string $string) { + file_put_contents(static::$stdoutFile, $string, FILE_APPEND); + }, 1); } } @@ -1807,7 +1830,7 @@ protected static function reload(): void static::log("Workerman[" . basename(static::$startFile) . "] reloading"); static::$status = static::STATUS_RELOADING; - static::resetStd(false); + static::resetStd(); // Try to emit onMasterReload callback. if (static::$onMasterReload) { try { @@ -1864,7 +1887,7 @@ protected static function reload(): void if ($worker->reloadable) { static::stopAll(); } else { - static::resetStd(false); + static::resetStd(); } } } @@ -2175,62 +2198,30 @@ public static function log(\Stringable|string $msg, bool $decorated = false): vo * Safe Echo. * * @param string $msg - * @param bool $decorated - * @return bool - */ - public static function safeEcho(string $msg, bool $decorated = false): bool - { - $stream = self::outputStream(); - if (!$stream) { - return false; - } - if (!$decorated) { - $line = $white = $green = $end = ''; - if (static::$outputDecorated) { - $line = "\033[1A\n\033[K"; - $white = "\033[47;30m"; - $green = "\033[32;40m"; - $end = "\033[0m"; - } - $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); - $msg = str_replace(['', '
', '
'], $end, $msg); - } elseif (!static::$outputDecorated) { - return false; - } - fwrite($stream, $msg); - fflush($stream); - return true; - } - - /** - * set and get output stream. - * - * @param resource|null $stream - * @return false|resource + * @return void */ - private static function outputStream($stream = null): mixed + public static function safeEcho(string $msg, bool $decorated = false): void { - if (!$stream) { - $stream = static::$outputStream ?: STDOUT; - } - // @phpstan-ignore-next-line Negated boolean expression is always false. - if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) { - return false; - } - $stat = fstat($stream); - if (!$stat) { - return false; + if (!(static::$outputDecorated ?? false) && $decorated) { + return; } - if (($stat['mode'] & 0170000) === 0100000) { // whether is regular file - static::$outputDecorated = false; + if (static::$outputDecorated ?? false) { + $line = "\033[1A\n\033[K"; + $white = "\033[47;30m"; + $green = "\033[32;40m"; + $end = "\033[0m"; } else { - static::$outputDecorated = - DIRECTORY_SEPARATOR === '/' && // linux or unix - function_exists('posix_isatty') && - posix_isatty($stream); // whether is interactive terminal + $line = ''; + $white = ''; + $green = ''; + $end = ''; } - return static::$outputStream = $stream; + + $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); + $msg = str_replace(['', '
', '
'], $end, $msg); + fwrite(self::$outputStream, $msg); + fflush(self::$outputStream); } /** From 93dfdfca0a2db878411a74bf3df6b6329f71b1a5 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 8 Nov 2023 00:19:59 +0800 Subject: [PATCH 0982/1216] public $statusFile returned and default places to store files changed as before --- src/Worker.php | 82 +++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 20b3271e4..f284b05a4 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -281,14 +281,7 @@ class Worker * * @var string */ - public static string $processStatusFile; - - /** - * The file used to store connections status. - * - * @var string - */ - public static string $connectionStatusFile; + public static string $statusFile; /** * Log file. @@ -468,6 +461,20 @@ class Worker */ protected static int $maxStateNameLength = 1; + /** + * The file to store status info of current worker process. + * + * @var string + */ + protected static string $statisticsFile; + + /** + * The file to store status info of connections. + * + * @var string + */ + protected static string $connectionsFile; + /** * Start file. * @@ -645,13 +652,12 @@ protected static function init(): void $startFilePrefix = hash('xxh64', static::$startFile); // Pid file. - static::$pidFile ??= sprintf('%s/workerman.%s.pid', sys_get_temp_dir(), $startFilePrefix); - - // Process status file. - static::$processStatusFile ??= sprintf('%s/workerman.%s.process.status', sys_get_temp_dir(), $startFilePrefix); + static::$pidFile ??= sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix); - // Connections status file. - static::$connectionStatusFile ??= sprintf('%s/workerman.%s.connection.status', sys_get_temp_dir(), $startFilePrefix); + // Status file. + static::$statusFile ??= sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix); + static::$statisticsFile ??= static::$statusFile; + static::$connectionsFile ??= static::$statusFile . '.connection'; // Log file. static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); @@ -1021,7 +1027,7 @@ protected static function parseCommand(): void break; case 'status': // Delete status file on shutdown - register_shutdown_function(unlink(...), static::$processStatusFile); + register_shutdown_function(unlink(...), static::$statisticsFile); while (1) { // Master process will send SIGIOT signal to all child processes. posix_kill($masterPid, SIGIOT); @@ -1040,7 +1046,7 @@ protected static function parseCommand(): void } case 'connections': // Delete status file on shutdown - register_shutdown_function(unlink(...), static::$connectionStatusFile); + register_shutdown_function(unlink(...), static::$connectionsFile); // Master process will send SIGIO signal to all child processes. posix_kill($masterPid, SIGIO); // Waiting a moment. @@ -1121,10 +1127,10 @@ public static function getArgv(): array protected static function formatProcessStatusData(): string { static $totalRequestCache = []; - if (!is_readable(static::$processStatusFile)) { + if (!is_readable(static::$statisticsFile)) { return ''; } - $info = file(static::$processStatusFile, FILE_IGNORE_NEW_LINES); + $info = file(static::$statisticsFile, FILE_IGNORE_NEW_LINES); if (!$info) { return ''; } @@ -1202,7 +1208,7 @@ protected static function formatProcessStatusData(): string protected static function formatConnectionStatusData(): string { - return file_get_contents(static::$connectionStatusFile); + return file_get_contents(static::$connectionsFile); } /** @@ -1993,43 +1999,43 @@ protected static function writeStatisticsToStatusFile(): void $allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()]; } } - file_put_contents(static::$processStatusFile, ''); - chmod(static::$processStatusFile, 0722); - file_put_contents(static::$processStatusFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, ''); + chmod(static::$statisticsFile, 0722); + file_put_contents(static::$statisticsFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map(round(...), sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); - file_put_contents(static::$processStatusFile, 'start time:' . date('Y-m-d H:i:s', + file_put_contents(static::$statisticsFile, 'start time:' . date('Y-m-d H:i:s', static::$globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", FILE_APPEND); $loadStr = 'load average: ' . implode(", ", $loadavg); - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad((string)$workerExitStatus, 16) . " $workerExitCount\n", FILE_APPEND); } } else { - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad('0', 16) . " 0\n", FILE_APPEND); } } - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$processStatusFile, + file_put_contents(static::$statisticsFile, "pid\tmemory " . str_pad('listening', static::$maxSocketNameLength) . " " . str_pad('worker_name', static::$maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . str_pad('total_request', 13) . " qps status\n", FILE_APPEND); @@ -2054,7 +2060,7 @@ protected static function writeStatisticsToStatusFile(): void . " " . str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) . " " . str_pad((string)static::$globalEvent->getTimerCount(), 7) . " " . str_pad((string)ConnectionInterface::$statistics['total_request'], 13) . "\n"; - file_put_contents(static::$processStatusFile, $workerStatusStr, FILE_APPEND); + file_put_contents(static::$statisticsFile, $workerStatusStr, FILE_APPEND); } /** @@ -2066,10 +2072,10 @@ protected static function writeConnectionsStatisticsToStatusFile(): void { // For master process. if (static::$masterPid === posix_getpid()) { - file_put_contents(static::$connectionStatusFile, ''); - chmod(static::$connectionStatusFile, 0722); - file_put_contents(static::$connectionStatusFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$connectionStatusFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); + file_put_contents(static::$connectionsFile, ''); + chmod(static::$connectionsFile, 0722); + file_put_contents(static::$connectionsFile, "--------------------------------------------------------------------- WORKERMAN CONNECTION STATUS --------------------------------------------------------------------------------\n", FILE_APPEND); + file_put_contents(static::$connectionsFile, "PID Worker CID Trans Protocol ipv4 ipv6 Recv-Q Send-Q Bytes-R Bytes-W Status Local Address Foreign Address\n", FILE_APPEND); foreach (static::getAllWorkerPids() as $workerPid) { posix_kill($workerPid, SIGIO); } @@ -2130,7 +2136,7 @@ protected static function writeConnectionsStatisticsToStatusFile(): void . str_pad($state, 14) . ' ' . str_pad($localAddress, 22) . ' ' . str_pad($remoteAddress, 22) . "\n"; } if ($str) { - file_put_contents(static::$connectionStatusFile, $str, FILE_APPEND); + file_put_contents(static::$connectionsFile, $str, FILE_APPEND); } } From c1b0308e629466f2c225b328e6dbc0f4aab9fee3 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 8 Nov 2023 00:45:53 +0800 Subject: [PATCH 0983/1216] Fix in resetStd to close STDOUT and STDERR --- src/Worker.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index aac588435..ecb05ebcc 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1326,6 +1326,18 @@ public static function resetStd(): void return; } + if (is_resource(STDOUT)) { + fclose(STDOUT); + } + + if (is_resource(STDERR)) { + fclose(STDERR); + } + + if (is_resource(static::$outputStream)) { + fclose(static::$outputStream); + } + set_error_handler(static fn (): bool => true); $stdOutStream = fopen(static::$stdoutFile, 'a'); restore_error_handler(); @@ -1334,7 +1346,6 @@ public static function resetStd(): void return; } - fclose(static::$outputStream); static::$outputStream = $stdOutStream; // Fix standard output cannot redirect of PHP 8.1.8's bug From 586a517c5b51cf6aa9421e7c58e0c6a429959a4d Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Nov 2023 17:46:34 +0800 Subject: [PATCH 0984/1216] Fix sessionHander->read() return type --- src/Protocols/Http/Session/FileSessionHandler.php | 8 ++++---- src/Protocols/Http/Session/RedisClusterSessionHandler.php | 2 +- src/Protocols/Http/Session/RedisSessionHandler.php | 4 ++-- src/Protocols/Http/Session/SessionHandlerInterface.php | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Protocols/Http/Session/FileSessionHandler.php b/src/Protocols/Http/Session/FileSessionHandler.php index aea6d06e7..219171c0d 100644 --- a/src/Protocols/Http/Session/FileSessionHandler.php +++ b/src/Protocols/Http/Session/FileSessionHandler.php @@ -88,19 +88,19 @@ public function open(string $savePath, string $name): bool /** * {@inheritdoc} */ - public function read(string $sessionId): string + public function read(string $sessionId): string|false { $sessionFile = static::sessionFile($sessionId); clearstatcache(); if (is_file($sessionFile)) { if (time() - filemtime($sessionFile) > Session::$lifetime) { unlink($sessionFile); - return ''; + return false; } $data = file_get_contents($sessionFile); - return $data ?: ''; + return $data ?: false; } - return ''; + return false; } /** diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index 685dc0334..d1f93d9b1 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -48,7 +48,7 @@ public function __construct($config) /** * {@inheritdoc} */ - public function read(string $sessionId): string + public function read(string $sessionId): string|false { return $this->redis->get($sessionId); } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index f1fed758e..8733e068d 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -102,11 +102,11 @@ public function open(string $savePath, string $name): bool /** * {@inheritdoc} * @param string $sessionId - * @return string + * @return string|false * @throws RedisException * @throws Throwable */ - public function read(string $sessionId): string + public function read(string $sessionId): string|false { try { return $this->redis->get($sessionId); diff --git a/src/Protocols/Http/Session/SessionHandlerInterface.php b/src/Protocols/Http/Session/SessionHandlerInterface.php index 5e4a56eb5..03f6b35a0 100644 --- a/src/Protocols/Http/Session/SessionHandlerInterface.php +++ b/src/Protocols/Http/Session/SessionHandlerInterface.php @@ -74,14 +74,14 @@ public function open(string $savePath, string $name): bool; * Read session data * @link http://php.net/manual/en/sessionhandlerinterface.read.php * @param string $sessionId The session id to read data for. - * @return string

+ * @return string|false

* Returns an encoded string of the read data. - * If nothing was read, it must return an empty string. + * If nothing was read, it must return false. * Note this value is returned internally to PHP for processing. *

* @since 5.4.0 */ - public function read(string $sessionId): string; + public function read(string $sessionId): string|false; /** * Write session data From 85599acb824510e601694c8eaaf5a87704403ed2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Nov 2023 18:56:30 +0800 Subject: [PATCH 0985/1216] Fix --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index f450d4799..a42fa7f82 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -703,7 +703,7 @@ protected static function initGlobalEvent(): void return; } - if (isset(static::$eventLoopClass)) { + if (!empty(static::$eventLoopClass)) { if (!is_subclass_of(static::$eventLoopClass, EventInterface::class)) { throw new RuntimeException(sprintf('%s::$eventLoopClass must implement %s', static::class, EventInterface::class)); } From e54846a34e305c4d3588c69ebea1905b6c16262a Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 13 Nov 2023 19:34:00 +0800 Subject: [PATCH 0986/1216] Compatible with webman --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b4a86c139..08b7d7a6d 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -203,7 +203,7 @@ public function cookie(string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(string $name = null): array|null + public function file(string $name = null) { if (!isset($this->data['files'])) { $this->parsePost(); From 310f582f15abcf0b3140ccda16809ea53fcb5dd1 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 21 Nov 2023 09:31:24 +0800 Subject: [PATCH 0987/1216] Check $this->eventLoop empty --- src/Connection/AsyncTcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index e88b2c098..25b53d195 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -365,7 +365,7 @@ public function getRemoteURI(): string public function checkConnection(): void { // Remove EV_EXPECT for windows. - if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { + if (DIRECTORY_SEPARATOR === '\\' && $this->eventLoop && method_exists($this->eventLoop, 'offExcept')) { $this->eventLoop->offExcept($this->socket); } // Remove write listener. From 9c7fa879773bc07f5f53e2b523fd4e3a15bb4cda Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Tue, 28 Nov 2023 22:18:25 +0200 Subject: [PATCH 0988/1216] Fixed safeEcho never printing output when tty decoration is unavailable. --- src/Worker.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index a42fa7f82..c990bfab2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2209,15 +2209,12 @@ public static function log(\Stringable|string $msg, bool $decorated = false): vo * Safe Echo. * * @param string $msg + * @param bool $decorated * @return void */ public static function safeEcho(string $msg, bool $decorated = false): void { - if (!(static::$outputDecorated ?? false) && $decorated) { - return; - } - - if (static::$outputDecorated ?? false) { + if ((static::$outputDecorated ?? false) && $decorated) { $line = "\033[1A\n\033[K"; $white = "\033[47;30m"; $green = "\033[32;40m"; From e1b40e13e54cfb843d3ea4438e2964fdaa4904cb Mon Sep 17 00:00:00 2001 From: Vano Devium Date: Wed, 13 Dec 2023 20:20:37 +0200 Subject: [PATCH 0989/1216] worker: allow to set logFile as /dev/null --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index c990bfab2..f77bff741 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -662,7 +662,7 @@ protected static function init(): void // Log file. static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); - if (!is_file(static::$logFile)) { + if (!is_file(static::$logFile) && static::$logFile !== '/dev/null') { // if /runtime/logs default folder not exists if (!is_dir(dirname(static::$logFile))) { @mkdir(dirname(static::$logFile), 0777, true); From e562b07c25960f2cdad1b3c4aeee2c784ca2d884 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 17 Dec 2023 09:57:17 +0800 Subject: [PATCH 0990/1216] save --- src/Connection/AsyncTcpConnection.php | 2 +- src/Connection/TcpConnection.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 25b53d195..e88b2c098 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -365,7 +365,7 @@ public function getRemoteURI(): string public function checkConnection(): void { // Remove EV_EXPECT for windows. - if (DIRECTORY_SEPARATOR === '\\' && $this->eventLoop && method_exists($this->eventLoop, 'offExcept')) { + if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { $this->eventLoop->offExcept($this->socket); } // Remove write listener. diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index c5a0b81e7..96a7a023b 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1002,6 +1002,9 @@ public function destroy(): void // Remove event listener. $this->eventLoop->offReadable($this->socket); $this->eventLoop->offWritable($this->socket); + if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { + $this->eventLoop->offExcept($this->socket); + } // Close socket. try { From 8fa5b79cf6687e5c8bbe5d8565893f0e553df040 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 3 Jan 2024 15:15:37 +0800 Subject: [PATCH 0991/1216] Show bad package stack --- src/Connection/TcpConnection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 96a7a023b..35654099f 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -16,6 +16,7 @@ namespace Workerman\Connection; use JsonSerializable; +use RuntimeException; use stdClass; use Throwable; use Workerman\Events\EventInterface; @@ -684,7 +685,7 @@ public function baseRead($socket, bool $checkEof = true): void } } // Wrong package. else { - Worker::safeEcho('Error package. package_length=' . var_export($this->currentPackageLength, true)); + Worker::safeEcho((string)(new RuntimeException("Protocol $this->protocol Error package. package_length=" . var_export($this->currentPackageLength, true)))); $this->destroy(); return; } From 007814919a417a5f50e0d9412f1a319699a62d78 Mon Sep 17 00:00:00 2001 From: tourze Date: Thu, 11 Jan 2024 13:58:26 +0800 Subject: [PATCH 0992/1216] Fix error when unserialize return false Double check the workerInfo var. In some cases, the unserialize will notice some tips like: unserialize(): Error at offset 0 of 54 bytes in file, but dont throw any Exception. --- src/Worker.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index f77bff741..512df8761 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1142,6 +1142,9 @@ protected static function formatProcessStatusData(): string } catch (Throwable) { // do nothing } + if (!is_array($workerInfo)) { + $workerInfo = []; + } ksort($workerInfo, SORT_NUMERIC); unset($info[0]); $dataWaitingSort = []; From 7beb1e4871466956d076a0a523942d319d558ec7 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 Jan 2024 14:59:08 +0800 Subject: [PATCH 0993/1216] Log master pid not alive --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index f77bff741..9028a5730 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2597,6 +2597,7 @@ protected static function checkMasterIsAlive(int $masterPid): bool $masterIsAlive = posix_kill($masterPid, 0) && posix_getpid() !== $masterPid; if (!$masterIsAlive) { + static::log("Master pid:$masterPid is not alive"); return false; } From e945150d7bb9e9d68db6fd92c24d4dfcfd563f9b Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 10 Feb 2024 21:14:40 +0800 Subject: [PATCH 0994/1216] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 5c85026de..040607890 100644 --- a/README.md +++ b/README.md @@ -384,11 +384,7 @@ proxy supports TLS1.3, no Sniproxy channel ## Documentation -中文主页: [http://www.workerman.net](https://www.workerman.net) - -中文文档: [http://doc.workerman.net](https://www.workerman.net/doc/workerman/) - -Documentation: [https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/SUMMARY.md) +Documentation: [https://manual.workerman.net](https://manual.workerman.net) # Benchmarks https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r From 0356a57903b1e16542f7eef97bfd22c4bc7926eb Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 10 Feb 2024 21:15:17 +0800 Subject: [PATCH 0995/1216] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 040607890..b9cf95039 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Event extension recommended for better performance composer require workerman/workerman ``` +## Documentation + +Documentation: [https://manual.workerman.net](https://manual.workerman.net) + ## Basic Usage ### A websocket server @@ -382,10 +386,6 @@ proxy supports TLS1.3, no Sniproxy channel ```php start.php reload ``` ```php start.php reload -g ``` -## Documentation - -Documentation: [https://manual.workerman.net](https://manual.workerman.net) - # Benchmarks https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r From d4d8b01150b5b8dfb3c764409288c8621e5bdf3e Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 10 Feb 2024 21:15:41 +0800 Subject: [PATCH 0996/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9cf95039..a788207df 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ composer require workerman/workerman ## Documentation -Documentation: [https://manual.workerman.net](https://manual.workerman.net) +[https://manual.workerman.net](https://manual.workerman.net) ## Basic Usage From 3e304eee6837fb07877c2b191584ea8caa2db82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E4=B8=B6=E7=A7=8B=E7=A7=8B=E7=A7=8B=E7=A7=8B?= =?UTF-8?q?=E7=A7=8B?= <> Date: Mon, 19 Feb 2024 09:49:34 +0800 Subject: [PATCH 0997/1216] Add worker mode information to statistics file --- src/Worker.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index be0d3e3d4..b83ba083b 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2017,6 +2017,8 @@ protected static function writeStatisticsToStatusFile(): void chmod(static::$statisticsFile, 0722); file_put_contents(static::$statisticsFile, serialize($allWorkerInfo) . "\n", FILE_APPEND); $loadavg = function_exists('sys_getloadavg') ? array_map(round(...), sys_getloadavg(), [2, 2, 2]) : ['-', '-', '-']; + file_put_contents(static::$statisticsFile, + (static::$daemonize ? "Start worker in DAEMON mode." : "Start worker in DEBUG mode.") . "\n", FILE_APPEND); file_put_contents(static::$statisticsFile, "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); file_put_contents(static::$statisticsFile, From 3b7f39c3c2bae807dfaf1e5d8257d40e3c7dd865 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 19 Feb 2024 10:02:10 +0800 Subject: [PATCH 0998/1216] fix sameSite for cookie #1010 --- src/Protocols/Http/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 7a4c9e2f4..0dceca14f 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -357,10 +357,10 @@ public function withFile(string $file, int $offset = 0, int $length = 0): static * @param string $domain * @param bool $secure * @param bool $httpOnly - * @param bool $sameSite + * @param string $sameSite * @return $this */ - public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, bool $sameSite = false): static + public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, string $sameSite = ''): static { $this->headers['Set-Cookie'][] = $name . '=' . rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) From 7cbeb8036e815b794090a0d2763ae8219217b947 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 25 Feb 2024 10:06:59 +0800 Subject: [PATCH 0999/1216] Update --- src/Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 7ae2e4c43..565f8476c 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -361,7 +361,7 @@ public static function sendHandshake(AsyncTcpConnection $connection): void } // Get Host. $port = $connection->getRemotePort(); - $host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; + $host = $port === 80 || $port === 443 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port; // Handshake header. $connection->context->websocketSecKey = base64_encode(random_bytes(16)); $userHeader = $connection->headers ?? null; From c03c7e3765e02c51264e821b14f8f10c229f6815 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 26 Feb 2024 19:37:03 +0100 Subject: [PATCH 1000/1216] Add pids to .gitignore To hide when we have workerman running --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e64b947ec..b328cb6f4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ vendor/ composer.lock phpunit.xml /phpstan.neon +/*.pid +/*.pid.lock \ No newline at end of file From e5bd13e3cfc771749a3a7e8542dd8f53ab2f18c0 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Mon, 26 Feb 2024 20:32:01 +0100 Subject: [PATCH 1001/1216] Constant VERSION made final PHP8.1 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index be0d3e3d4..a01390f89 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -51,7 +51,7 @@ class Worker * * @var string */ - public const VERSION = '5.0.0-beta.7'; + final public const VERSION = '5.0.0-beta.7'; /** * Status starting. From 74137981741eabbecdf3df3511c5fc74ada20d8e Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 14 Mar 2024 11:30:55 +0200 Subject: [PATCH 1002/1216] Improved logging when process exits and php select exceeds file descriptor limit. --- src/Events/Select.php | 8 ++++---- src/Worker.php | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index f8ec7ec71..0bd0c24ad 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -187,9 +187,9 @@ public function onReadable($stream, callable $func): void { $count = count($this->readFds); if ($count >= 1024) { - echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; + trigger_error("System call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.", E_USER_WARNING); } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { - echo "Warning: system call select exceeded the maximum number of connections 256.\n"; + trigger_error("System call select exceeded the maximum number of connections 256.", E_USER_WARNING); } $fdKey = (int)$stream; $this->readEvents[$fdKey] = $func; @@ -216,9 +216,9 @@ public function onWritable($stream, callable $func): void { $count = count($this->writeFds); if ($count >= 1024) { - echo "Warning: system call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.\n"; + trigger_error("System call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.", E_USER_WARNING); } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { - echo "Warning: system call select exceeded the maximum number of connections 256.\n"; + trigger_error("System call select exceeded the maximum number of connections 256.", E_USER_WARNING); } $fdKey = (int)$stream; $this->writeEvents[$fdKey] = $func; diff --git a/src/Worker.php b/src/Worker.php index a01390f89..d441a288f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1265,12 +1265,12 @@ protected static function signalHandler(int $signal): void case SIGHUP: case SIGTSTP: static::$gracefulStop = false; - static::stopAll(); + static::stopAll(0, "received signal: $signal"); break; // Graceful stop. case SIGQUIT: static::$gracefulStop = true; - static::stopAll(); + static::stopAll(0, "received signal: $signal"); break; // Reload. case SIGUSR2: @@ -1791,8 +1791,8 @@ protected static function monitorWorkersForLinux(): void } } - // If shutdown state and all child processes exited then master process exit. - if (static::$status === static::STATUS_SHUTDOWN && !static::getAllWorkerPids()) { + // If shutdown state and all child processes exited, then master process exit. + if (static::$status === static::STATUS_SHUTDOWN && empty(static::getAllWorkerPids())) { static::exitAndClearAll(); } } @@ -1926,7 +1926,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void static::$status = static::STATUS_SHUTDOWN; // For master process. if (DIRECTORY_SEPARATOR === '/' && static::$masterPid === posix_getpid()) { - static::log("Workerman[" . basename(static::$startFile) . "] stopping ..."); + static::log("Workerman[" . basename(static::$startFile) . "] stopping, code [$code]"); $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. $sig = static::getGracefulStop() ? SIGQUIT : SIGINT; From 7043c1ad26266fb01c051bc22e0a1b66b49d2a65 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 22 Mar 2024 16:36:04 +0800 Subject: [PATCH 1003/1216] save --- src/Worker.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 533b88837..8ed426fda 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2233,8 +2233,12 @@ public static function safeEcho(string $msg, bool $decorated = false): void $msg = str_replace(['', '', ''], [$line, $white, $green], $msg); $msg = str_replace(['', '
', '
'], $end, $msg); - fwrite(self::$outputStream, $msg); - fflush(self::$outputStream); + set_error_handler(static fn (): bool => true); + if (!feof(self::$outputStream)) { + fwrite(self::$outputStream, $msg); + fflush(self::$outputStream); + } + restore_error_handler(); } /** From 1eda02e61b75678d562e86123eb24dcd8ce02894 Mon Sep 17 00:00:00 2001 From: roiwk Date: Thu, 11 Apr 2024 14:54:05 +0800 Subject: [PATCH 1004/1216] fix(async tcp): proxy --- src/Connection/AsyncTcpConnection.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index e88b2c098..14ff8a460 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -261,19 +261,10 @@ public function connect(): void $this->socketContext['ssl']['peer_name'] = $this->remoteHost; $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->proxySocks5", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); - fwrite($this->socket, chr(5) . chr(1) . chr(0)); - fread($this->socket, 512); - fwrite($this->socket, chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); - fread($this->socket, 512); } else if ($this->proxyHttp) { $this->socketContext['ssl']['peer_name'] = $this->remoteHost; $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->proxyHttp", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT, $context); - $str = "CONNECT $this->remoteHost:$this->remotePort HTTP/1.1\n"; - $str .= "Host: $this->remoteHost:$this->remotePort\n"; - $str .= "Proxy-Connection: keep-alive\n"; - fwrite($this->socket, $str); - fread($this->socket, 512); } else if ($this->socketContext) { $context = stream_context_create($this->socketContext); $this->socket = stream_socket_client("tcp://$this->remoteHost:$this->remotePort", @@ -377,6 +368,20 @@ public function checkConnection(): void // Check socket state. if ($address = stream_socket_get_name($this->socket, true)) { + // Proxy + if ($this->proxySocks5 && $address === $this->proxySocks5) { + fwrite($this->socket, chr(5) . chr(1) . chr(0)); + fread($this->socket, 512); + fwrite($this->socket, chr(5) . chr(1) . chr(0) . chr(3) . chr(strlen($this->remoteHost)) . $this->remoteHost . pack("n", $this->remotePort)); + fread($this->socket, 512); + } + if ($this->proxyHttp && $address === $this->proxyHttp) { + $str = "CONNECT $this->remoteHost:$this->remotePort HTTP/1.1\r\n"; + $str .= "Host: $this->remoteHost:$this->remotePort\r\n"; + $str .= "Proxy-Connection: keep-alive\r\n\r\n"; + fwrite($this->socket, $str); + fread($this->socket, 512); + } // Nonblocking. stream_set_blocking($this->socket, false); // Compatible with hhvm From 93416483458927512d8a0e17c06d714a2e27dc49 Mon Sep 17 00:00:00 2001 From: NitronPlus <1940394+NitronPlus@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:54:19 +0800 Subject: [PATCH 1005/1216] Update mime.types Add wasm mime type --- src/Protocols/Http/mime.types | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Protocols/Http/mime.types b/src/Protocols/Http/mime.types index e6ccf0ab1..57699149b 100644 --- a/src/Protocols/Http/mime.types +++ b/src/Protocols/Http/mime.types @@ -8,6 +8,7 @@ types { application/javascript js; application/atom+xml atom; application/rss+xml rss; + application/wasm wasm; text/mathml mml; text/plain txt; From 259aab0f07890792032a835a7b959af1ca1904f4 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 4 Jul 2024 16:07:37 +0800 Subject: [PATCH 1006/1216] HTTP protocol access to WebSocket returns a 400 error. --- src/Protocols/Websocket.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 00f5a3776..eb72e4a3f 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -362,7 +362,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $SecWebSocketKey = $match[1]; } else { $connection->close( - "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); + "HTTP/1.0 400 Bad Request\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); return 0; } // Calculation websocket key. @@ -414,7 +414,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $handshakeMessage .= "\r\n"; // Send handshake response. $connection->send($handshakeMessage, true); - // Mark handshake complete.. + // Mark handshake complete. $connection->context->websocketHandshake = true; // There are data waiting to be sent. @@ -429,7 +429,7 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } // Bad websocket handshake request. $connection->close( - "HTTP/1.0 200 OK\r\nServer: workerman\r\n\r\n

WebSocket


workerman
", true); + "HTTP/1.0 400 Bad Request\r\nServer: workerman\r\n\r\n

400 Bad Request


workerman
", true); return 0; } } From 14e66a8c7353395b23e1fb3103d7dc778b4c27e2 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 17 Jul 2024 19:28:10 +0800 Subject: [PATCH 1007/1216] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a788207df..611294c72 100644 --- a/README.md +++ b/README.md @@ -396,7 +396,7 @@ https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l= [AdapterMan](https://github.com/joanhey/AdapterMan) ## Donate - +PayPal ## LICENSE From b88eeb5f0053a0955b797a2e9d8465cccf1ae786 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 3 Aug 2024 17:41:36 +0200 Subject: [PATCH 1008/1216] Fix PHP 8.4 explicit nullable --- src/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timer.php b/src/Timer.php index 3398b40e2..c11db9d54 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -78,7 +78,7 @@ class Timer * @param EventInterface|null $event * @return void */ - public static function init(EventInterface $event = null): void + public static function init(?EventInterface $event = null): void { if ($event) { self::$event = $event; From 11d5ce49b8a11010b316b8dc9abcee319ec67cbd Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 3 Aug 2024 17:43:41 +0200 Subject: [PATCH 1009/1216] Fix nullable for PHP 8.4 #1046 --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 53d27778c..ef7355964 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -73,7 +73,7 @@ class Http * @param class-string|null $className * @return string */ - public static function requestClass(string $className = null): string + public static function requestClass(?string $className = null): string { if ($className !== null) { static::$requestClass = $className; From 597f6916d9a1e512bc3fb0597fbc2cfe264b4a28 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 22:11:04 +0200 Subject: [PATCH 1010/1216] Use property promotion --- src/Connection/UdpConnection.php | 22 +++------------------- src/Protocols/Http/Chunk.php | 15 ++------------- src/Protocols/Http/Request.php | 13 +------------ src/Protocols/Http/ServerSentEvents.php | 12 +----------- 4 files changed, 7 insertions(+), 55 deletions(-) diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 1a25af0af..dac804107 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -45,31 +45,15 @@ class UdpConnection extends ConnectionInterface implements JsonSerializable */ public string $transport = 'udp'; - /** - * Udp socket. - * - * @var resource - */ - protected $socket; - - /** - * Remote address. - * - * @var string - */ - protected string $remoteAddress = ''; - /** * Construct. * * @param resource $socket * @param string $remoteAddress */ - public function __construct($socket, string $remoteAddress) - { - $this->socket = $socket; - $this->remoteAddress = $remoteAddress; - } + public function __construct( + protected $socket, + protected string $remoteAddress) {} /** * Sends data on the connection. diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index f9a7394d7..5100ed2e0 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -27,30 +27,19 @@ */ class Chunk implements Stringable { - /** - * Chunk buffer. - * - * @var string - */ - protected string $buffer; /** * Chunk constructor. * - * @param string $buffer */ - public function __construct(string $buffer) - { - $this->buffer = $buffer; - } + public function __construct(protected string $buffer) {} /** * __toString * - * @return string */ public function __toString(): string { return dechex(strlen($this->buffer)) . "\r\n$this->buffer\r\n"; } -} \ No newline at end of file +} diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 08b7d7a6d..548735828 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -78,13 +78,6 @@ class Request implements Stringable */ public array $properties = []; - /** - * Http buffer. - * - * @var string - */ - protected string $buffer; - /** * Request data. * @@ -116,12 +109,8 @@ class Request implements Stringable /** * Request constructor. * - * @param string $buffer */ - public function __construct(string $buffer) - { - $this->buffer = $buffer; - } + public function __construct(protected string $buffer) {} /** * Get query. diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index ad4a4ffa4..ca75fcac5 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -26,21 +26,11 @@ */ class ServerSentEvents implements Stringable { - /** - * Data. - * @var array - */ - protected array $data; - /** * ServerSentEvents constructor. * $data for example ['event'=>'ping', 'data' => 'some thing', 'id' => 1000, 'retry' => 5000] - * @param array $data */ - public function __construct(array $data) - { - $this->data = $data; - } + public function __construct(protected array $data) {} /** * __toString. From 4b720a7941da8a90f12d5d5dad6bbddef157433f Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 22:11:50 +0200 Subject: [PATCH 1011/1216] Use string interpolation than is faster --- src/Protocols/Http/ServerSentEvents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index ca75fcac5..f200cd93a 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -56,6 +56,6 @@ public function __toString(): string if (isset($data['data'])) { $buffer .= 'data: ' . str_replace("\n", "\ndata: ", $data['data']) . "\n"; } - return $buffer . "\n"; + return "$buffer\n"; } } From 74525be38b5e53ea20b63fb259d929a90d54dd82 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 22:32:12 +0200 Subject: [PATCH 1012/1216] Delete redundant comments --- src/Protocols/Http/Chunk.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Protocols/Http/Chunk.php b/src/Protocols/Http/Chunk.php index 5100ed2e0..2c7a2a8f8 100644 --- a/src/Protocols/Http/Chunk.php +++ b/src/Protocols/Http/Chunk.php @@ -28,16 +28,8 @@ class Chunk implements Stringable { - /** - * Chunk constructor. - * - */ public function __construct(protected string $buffer) {} - /** - * __toString - * - */ public function __toString(): string { return dechex(strlen($this->buffer)) . "\r\n$this->buffer\r\n"; From ba85d2daf9b7f08b27fff00c869ab3f2c14c2a39 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 22:40:35 +0200 Subject: [PATCH 1013/1216] Response construct propery promotion --- src/Protocols/Http/Response.php | 37 ++++++--------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 0dceca14f..0df251983 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -39,19 +39,6 @@ */ class Response implements Stringable { - /** - * Header data. - * - * @var array - */ - protected array $headers = []; - - /** - * Http status. - * - * @var int - */ - protected int $status; /** * Http reason. @@ -67,13 +54,6 @@ class Response implements Stringable */ protected string $version = '1.1'; - /** - * Http body. - * - * @var string - */ - protected string $body = ''; - /** * Send file info * @@ -177,20 +157,15 @@ public static function init(): void /** * Response constructor. * - * @param int $status - * @param array|null $headers + * @param int $status + * @param array $headers * @param string $body */ public function __construct( - int $status = 200, - ?array $headers = [], - string $body = '' - ) - { - $this->status = $status; - $this->headers = $headers; - $this->body = $body; - } + protected int $status = 200, + protected array $headers = [], + protected string $body = '' + ) {} /** * Set header. From 870220d15bd83ada95902af64dbd332579ee2aad Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 22:59:22 +0200 Subject: [PATCH 1014/1216] Fix Http class to use Response headers as array --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index ef7355964..c528ee08b 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -248,7 +248,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin } $handler = fopen($file, 'r'); if (false === $handler) { - $connection->close(new Response(403, null, '403 Forbidden')); + $connection->close(new Response(403, [], '403 Forbidden')); return ''; } $connection->send((string)$response, true); From 1297111a60547b6c5ef355be6ce04a5b83a281e2 Mon Sep 17 00:00:00 2001 From: Joanhey Date: Tue, 6 Aug 2024 23:37:07 +0200 Subject: [PATCH 1015/1216] Remove redundant comment --- src/Protocols/Http/ServerSentEvents.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Protocols/Http/ServerSentEvents.php b/src/Protocols/Http/ServerSentEvents.php index f200cd93a..6b70b10a8 100644 --- a/src/Protocols/Http/ServerSentEvents.php +++ b/src/Protocols/Http/ServerSentEvents.php @@ -32,11 +32,6 @@ class ServerSentEvents implements Stringable */ public function __construct(protected array $data) {} - /** - * __toString. - * - * @return string - */ public function __toString(): string { $buffer = ''; From 3fe39397656b32b5386b8d44cfa992a3c791fa9e Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 8 Aug 2024 12:38:41 +0200 Subject: [PATCH 1016/1216] Add PHP 8.4 nightly to tests So we can find problems with time. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a310546b..4b8cc064d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.1", "8.2", "8.3"] + php: ["8.1", "8.2", "8.3", "8.4"] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} From 515217652a0969f1b02526df44a19b69163097f7 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Tue, 3 Sep 2024 02:00:31 +0300 Subject: [PATCH 1017/1216] Implemented WebSocket connected callback. --- src/Connection/TcpConnection.php | 9 ++++++++- src/Protocols/Websocket.php | 16 ++++++++++++++-- src/Worker.php | 9 ++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 35654099f..c76046b0d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -110,12 +110,19 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable public $onConnect = null; /** - * Emitted when websocket handshake completed (Only work when protocol is ws). + * Emitted before websocket handshake (Only works when protocol is ws). * * @var ?callable */ public $onWebSocketConnect = null; + /** + * Emitted after websocket handshake (Only works when protocol is ws). + * + * @var ?callable + */ + public $onWebSocketConnected = null; + /** * Emitted when data is received. * diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index eb72e4a3f..6255bde11 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -382,12 +382,14 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): $connection->context->websocketCurrentFrameBuffer = ''; // Consume handshake data. $connection->consumeRecvBuffer($headerLength); + // Request from buffer + $request = new Request($buffer); // Try to emit onWebSocketConnect callback. $onWebsocketConnect = $connection->onWebSocketConnect ?? $connection->worker->onWebSocketConnect ?? false; if ($onWebsocketConnect) { try { - $onWebsocketConnect($connection, new Request($buffer)); + $onWebsocketConnect($connection, $request); } catch (Throwable $e) { Worker::stopAll(250, $e); } @@ -413,10 +415,20 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } $handshakeMessage .= "\r\n"; // Send handshake response. - $connection->send($handshakeMessage, true); + $status = $connection->send($handshakeMessage, true); // Mark handshake complete. $connection->context->websocketHandshake = true; + // Try to emit onWebSocketConnected callback. + $onWebsocketConnected = $connection->onWebSocketConnected ?? $connection->worker->onWebSocketConnected ?? false; + if ($status && $onWebsocketConnected) { + try { + $onWebsocketConnected($connection, $request); + } catch (Throwable $e) { + Worker::stopAll(250, $e); + } + } + // There are data waiting to be sent. if (!empty($connection->context->tmpWebsocketData)) { $connection->send($connection->context->tmpWebsocketData, true); diff --git a/src/Worker.php b/src/Worker.php index 8ed426fda..a610609ad 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -159,12 +159,19 @@ class Worker public $onConnect = null; /** - * Emitted when websocket handshake did complete (Only called when protocol is ws). + * Emitted before websocket handshake (Only works when protocol is ws). * * @var ?callable */ public $onWebSocketConnect = null; + /** + * Emitted after websocket handshake (Only works when protocol is ws). + * + * @var ?callable + */ + public $onWebSocketConnected = null; + /** * Emitted when data is received. * From 6274c34179a8bea351093513541df170d208f392 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 3 Sep 2024 10:55:58 +0800 Subject: [PATCH 1018/1216] Log optimization --- src/Worker.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 8ed426fda..02bec977e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1032,7 +1032,7 @@ protected static function parseCommand(): void // Master process will send SIGIOT signal to all child processes. posix_kill($masterPid, SIGIOT); // Waiting a moment. - usleep(500000); + sleep(1); // Clear terminal. if ($mode === '-d') { static::safeEcho("\33[H\33[2J\33(B\33[m", true); @@ -1265,12 +1265,12 @@ protected static function signalHandler(int $signal): void case SIGHUP: case SIGTSTP: static::$gracefulStop = false; - static::stopAll(0, "received signal: $signal"); + static::stopAll(0, "received signal $signal"); break; // Graceful stop. case SIGQUIT: static::$gracefulStop = true; - static::stopAll(0, "received signal: $signal"); + static::stopAll(0, "received signal $signal"); break; // Reload. case SIGUSR2: @@ -1919,14 +1919,13 @@ protected static function reload(): void */ public static function stopAll(int $code = 0, mixed $log = ''): void { - if ($log) { - static::log($log); - } - static::$status = static::STATUS_SHUTDOWN; // For master process. if (DIRECTORY_SEPARATOR === '/' && static::$masterPid === posix_getpid()) { - static::log("Workerman[" . basename(static::$startFile) . "] stopping, code [$code]"); + if ($log) { + static::log("Workerman[" . basename(static::$startFile) . "] $log"); + } + static::log("Workerman[" . basename(static::$startFile) . "] stopping" . ($code ? ", code [$code]" : '')); $workerPidArray = static::getAllWorkerPids(); // Send stop signal to all child processes. $sig = static::getGracefulStop() ? SIGQUIT : SIGINT; @@ -1944,6 +1943,9 @@ public static function stopAll(int $code = 0, mixed $log = ''): void Timer::add(1, static::checkIfChildRunning(...)); } // For child processes. else { + if ($code && $log) { + static::log($log); + } // Execute exit. $workers = array_reverse(static::$workers); array_walk($workers, static fn (Worker $worker) => $worker->stop()); From 1d25e3f402d4f88771040adda552c6ada9398809 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 3 Sep 2024 12:45:39 +0800 Subject: [PATCH 1019/1216] Performance optimization --- src/Events/Event.php | 6 +++--- src/Events/Select.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index 51fcead36..33d59f6d8 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -140,7 +140,7 @@ public function repeat(float $interval, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; - $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, fn () => $this->safeCall($func, $args)); + $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, $func); if (!$event->addTimer($interval)) { throw new \RuntimeException("Event::addTimer($interval) failed"); } @@ -155,7 +155,7 @@ public function onReadable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; - $event = new $className($this->eventBase, $stream, $className::READ | $className::PERSIST, fn () => $this->safeCall($func, [$stream])); + $event = new $className($this->eventBase, $stream, $className::READ | $className::PERSIST, $func); if ($event->add()) { $this->readEvents[$fdKey] = $event; } @@ -182,7 +182,7 @@ public function onWritable($stream, callable $func): void { $className = $this->eventClassName; $fdKey = (int)$stream; - $event = new $className($this->eventBase, $stream, $className::WRITE | $className::PERSIST, fn () => $this->safeCall($func, [$stream])); + $event = new $className($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func); if ($event->add()) { $this->writeEvents[$fdKey] = $event; } diff --git a/src/Events/Select.php b/src/Events/Select.php index 0bd0c24ad..95f2fa77a 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -381,21 +381,21 @@ public function run(): void foreach ($read as $fd) { $fdKey = (int)$fd; if (isset($this->readEvents[$fdKey])) { - $this->safeCall($this->readEvents[$fdKey], [$fd]); + $this->readEvents[$fdKey]($fd); } } foreach ($write as $fd) { $fdKey = (int)$fd; if (isset($this->writeEvents[$fdKey])) { - $this->safeCall($this->writeEvents[$fdKey], [$fd]); + $this->writeEvents[$fdKey]($fd); } } foreach ($except as $fd) { $fdKey = (int)$fd; if (isset($this->exceptEvents[$fdKey])) { - $this->safeCall($this->exceptEvents[$fdKey], [$fd]); + $this->exceptEvents[$fdKey]($fd); } } From 83a6f915d257994e53ee41e8dae944aa76f9c163 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 7 Sep 2024 11:19:35 +0800 Subject: [PATCH 1020/1216] Display jit status --- src/Worker.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 02bec977e..2f36a6e70 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -861,16 +861,17 @@ protected static function displayUI(): void if (in_array('-q', $tmpArgv)) { return; } + $jitStatus = function_exists('opcache_get_status') && (opcache_get_status()['jit']['on'] ?? false) === true ? 'on' : 'off'; if (DIRECTORY_SEPARATOR !== '/') { static::safeEcho("---------------------------------------------- WORKERMAN -----------------------------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION. "\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION . " (Jit $jitStatus)\r\n"); static::safeEcho("----------------------------------------------- WORKERS ------------------------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; } //show version - $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . str_pad('Event-loop:', 16, ' ', STR_PAD_LEFT) . static::getEventLoopName() . PHP_EOL; + $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . " (Jit $jitStatus)" . str_pad('Event-loop:', 16, ' ', STR_PAD_LEFT) . static::getEventLoopName() . PHP_EOL; !defined('LINE_VERSION_LENGTH') && define('LINE_VERSION_LENGTH', strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); $lineOne = '' . str_pad(' WORKERMAN ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . '' . PHP_EOL; From 64657d271cf827e230909a4a0b9c13495c2e8e7d Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 7 Sep 2024 17:58:07 +0800 Subject: [PATCH 1021/1216] Replace numbers with constants --- src/Connection/TcpConnection.php | 20 +++++++++++++++++--- src/Protocols/Http.php | 12 ++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 35654099f..29367918d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -102,6 +102,20 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public const STATUS_CLOSED = 8; + /** + * Maximum string length for cache + * + * @var int + */ + public const MAX_CACHE_STRING_LENGTH = 2048; + + /** + * Maximum cache size. + * + * @var int + */ + public const MAX_CACHE_SIZE = 512; + /** * Emitted when socket connection is successfully established. * @@ -635,7 +649,7 @@ public function baseRead($socket, bool $checkEof = true): void } else { $this->bytesRead += strlen($buffer); if ($this->recvBuffer === '') { - if (static::$enableCache && !isset($buffer[512]) && isset($requests[$buffer])) { + if (static::$enableCache && isset($requests[$buffer])) { ++self::$statistics['total_request']; $request = $requests[$buffer]; if ($request instanceof Request) { @@ -710,9 +724,9 @@ public function baseRead($socket, bool $checkEof = true): void /** @var ProtocolInterface $parser */ $parser = $this->protocol; $request = $parser::decode($oneRequestBuffer, $this); - if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) { + if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { $requests[$oneRequestBuffer] = $request; - if (count($requests) > 512) { + if (count($requests) > static::MAX_CACHE_SIZE) { unset($requests[key($requests)]); } } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index c528ee08b..5eb3f0954 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -102,7 +102,7 @@ public static function enableCache(bool $value) public static function input(string $buffer, TcpConnection $connection): int { static $input = []; - if (!isset($buffer[512]) && isset($input[$buffer])) { + if (isset($input[$buffer])) { return $input[$buffer]; } $crlfPos = strpos($buffer, "\r\n\r\n"); @@ -148,9 +148,9 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } - if (!isset($buffer[512])) { + if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { $input[$buffer] = $length; - if (count($input) > 512) { + if (count($input) > TcpConnection::MAX_CACHE_SIZE) { unset($input[key($input)]); } } @@ -168,8 +168,8 @@ public static function input(string $buffer, TcpConnection $connection): int public static function decode(string $buffer, TcpConnection $connection): Request { static $requests = []; - $cacheable = static::$enableCache && !isset($buffer[512]); - if (true === $cacheable && isset($requests[$buffer])) { + $cacheable = static::$enableCache && !isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH]); + if (isset($requests[$buffer])) { $request = clone $requests[$buffer]; $request->connection = $connection; $connection->request = $request; @@ -181,7 +181,7 @@ public static function decode(string $buffer, TcpConnection $connection): Reques $connection->request = $request; if (true === $cacheable) { $requests[$buffer] = $request; - if (count($requests) > 512) { + if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { unset($requests[key($requests)]); } } From 563b159045f606e1a1ea88d2fa0437d3236f4669 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Sep 2024 22:52:00 +0800 Subject: [PATCH 1022/1216] Check upload file exsits --- src/Protocols/Http/Request.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 548735828..c9528ec34 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -194,6 +194,13 @@ public function cookie(string $name = null, mixed $default = null): mixed */ public function file(string $name = null) { + clearstatcache(); + foreach ($this->data['files'] ?? [] as $file) { + if (!is_file($file['tmp_name'])) { + unset($this->data['files']); + break; + } + } if (!isset($this->data['files'])) { $this->parsePost(); } From 0857164d335c016b7af0b55b3db8826445abfb58 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 9 Sep 2024 22:29:39 +0800 Subject: [PATCH 1023/1216] support permessage-deflate --- src/Protocols/Websocket.php | 84 +++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index eb72e4a3f..67ff1c4d3 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -50,6 +50,13 @@ class Websocket */ public const BINARY_TYPE_BLOB = "\x81"; + /** + * Websocket blob type. + * + * @var string + */ + const BINARY_TYPE_BLOB_DEFLATE = "\xc1"; + /** * Websocket arraybuffer type. * @@ -57,6 +64,13 @@ class Websocket */ public const BINARY_TYPE_ARRAYBUFFER = "\x82"; + /** + * Websocket arraybuffer type. + * + * @var string + */ + const BINARY_TYPE_ARRAYBUFFER_DEFLATE = "\xc2"; + /** * Check the integrity of the package. * @@ -250,12 +264,16 @@ public static function encode(mixed $buffer, TcpConnection $connection): string throw new Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to string. "); } - $len = strlen($buffer); if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; } + if (\ord($connection->websocketType) & 64) { + $buffer = static::deflate($connection, $buffer); + } + $firstByte = $connection->websocketType; + $len = strlen($buffer); if ($len <= 125) { $encodeBuffer = $firstByte . chr($len) . $buffer; @@ -308,8 +326,11 @@ public static function encode(mixed $buffer, TcpConnection $connection): string */ public static function decode(string $buffer, TcpConnection $connection): string { - $firstByte = ord($buffer[1]); - $len = $firstByte & 127; + $firstByte = ord($buffer[0]); + $secondByte = ord($buffer[1]); + $len = $secondByte & 127; + $isFinFrame = (bool)($firstByte >> 7); + $rsv1 = 64 === ($firstByte & 64); if ($len === 126) { $masks = substr($buffer, 4, 4); @@ -328,16 +349,71 @@ public static function decode(string $buffer, TcpConnection $connection): string $decoded = $data ^ $masks; if ($connection->context->websocketCurrentFrameLength) { $connection->context->websocketDataBuffer .= $decoded; + if ($rsv1) { + return static::inflate($connection, $connection->context->websocketDataBuffer, $isFinFrame); + } return $connection->context->websocketDataBuffer; } - if ($connection->context->websocketDataBuffer !== '') { $decoded = $connection->context->websocketDataBuffer . $decoded; $connection->context->websocketDataBuffer = ''; } + if ($rsv1) { + return static::inflate($connection, $decoded, $isFinFrame); + } return $decoded; } + /** + * Inflate. + * + * @param TcpConnection $connection + * @param string $buffer + * @param bool $isFinFrame + * @return false|string + */ + protected static function inflate(TcpConnection $connection, string $buffer, bool $isFinFrame) + { + if (!isset($connection->context->inflator)) { + $connection->context->inflator = \inflate_init( + \ZLIB_ENCODING_RAW, + [ + 'level' => -1, + 'memory' => 8, + 'window' => 15, + 'strategy' => \ZLIB_DEFAULT_STRATEGY + ] + ); + } + if ($isFinFrame) { + $buffer .= "\x00\x00\xff\xff"; + } + return \inflate_add($connection->context->inflator, $buffer); + } + + /** + * Deflate. + * + * @param TcpConnection $connection + * @param string $buffer + * @return false|string + */ + protected static function deflate(TcpConnection $connection, string $buffer) + { + if (!isset($connection->context->deflator)) { + $connection->context->deflator = \deflate_init( + \ZLIB_ENCODING_RAW, + [ + 'level' => -1, + 'memory' => 8, + 'window' => 15, + 'strategy' => \ZLIB_DEFAULT_STRATEGY + ] + ); + } + return \substr(\deflate_add($connection->context->deflator, $buffer), 0, -4); + } + /** * Websocket handshake. * From c7dba867c549d6e9369762c653c4740aae842528 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 13 Sep 2024 15:02:50 +0800 Subject: [PATCH 1024/1216] Add Timer::repeat() Timer::dealy() --- src/Timer.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Timer.php b/src/Timer.php index c11db9d54..acc39c060 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -89,6 +89,32 @@ public static function init(?EventInterface $event = null): void } } + /** + * Repeat. + * + * @param float $timeInterval + * @param callable $func + * @param array $args + * @return int + */ + public static function repeat(float $timeInterval, callable $func, array $args = []): int + { + return self::$event->repeat($timeInterval, $func, $args); + } + + /** + * Delay. + * + * @param float $timeInterval + * @param callable $func + * @param array $args + * @return int + */ + public static function delay(float $timeInterval, callable $func, array $args = []): int + { + return self::$event->delay($timeInterval, $func, $args); + } + /** * ALARM signal handler. * @@ -111,7 +137,7 @@ public static function signalHandle(): void * @param bool $persistent * @return int */ - public static function add(float $timeInterval, callable $func, null|array $args = [], bool $persistent = true): int + public static function add(float $timeInterval, callable $func, ?array $args = [], bool $persistent = true): int { if ($timeInterval < 0) { throw new RuntimeException('$timeInterval can not less than 0'); @@ -180,7 +206,7 @@ public static function sleep(float $delay): void * * @return void */ - public static function tick(): void + protected static function tick(): void { if (empty(self::$tasks)) { pcntl_alarm(0); From ca0199ee4e7be6a6c37775d5f923b060e957f8de Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 15 Sep 2024 18:06:38 +0800 Subject: [PATCH 1025/1216] Fix upload file exists check --- src/Protocols/Http/Request.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index c9528ec34..ad03c3752 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -195,13 +195,14 @@ public function cookie(string $name = null, mixed $default = null): mixed public function file(string $name = null) { clearstatcache(); - foreach ($this->data['files'] ?? [] as $file) { - if (!is_file($file['tmp_name'])) { - unset($this->data['files']); - break; - } + if (!empty($this->data['files'])) { + array_walk_recursive($this->data['files'], function ($value, $key) { + if ($key === 'tmp_name' && !is_file($value)) { + $this->data['files'] = []; + } + }); } - if (!isset($this->data['files'])) { + if (empty($this->data['files'])) { $this->parsePost(); } if (null === $name) { From 965a4cad25eaccbecc827b153d290b281de8e599 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Sep 2024 16:53:55 +0800 Subject: [PATCH 1026/1216] 5.0.0-rc.1 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 3599822d1..2c37b494b 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -51,7 +51,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-beta.7'; + final public const VERSION = '5.0.0-rc.1'; /** * Status starting. From eff0fa1c8b9ec236234053bfc0bf3f6e2152d4c0 Mon Sep 17 00:00:00 2001 From: chaz6chez Date: Wed, 2 Oct 2024 02:01:30 +0800 Subject: [PATCH 1027/1216] fix: all coroutines must be canceled before Event::exit --- src/Events/Swoole.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index e703d14b5..e61c9b7f4 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -15,6 +15,7 @@ namespace Workerman\Events; +use Swoole\Coroutine; use Swoole\Event; use Swoole\Process; use Swoole\Timer; @@ -211,6 +212,10 @@ public function run(): void */ public function stop(): void { + // cancel all coroutines before Event::exit + foreach (Coroutine::listCoroutines() as $coroutine) { + Coroutine::cancel($coroutine); + } Event::exit(); posix_kill(posix_getpid(), SIGINT); } From 7ba75977a2e85a665d2436ea099e8294d8a70891 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 8 Oct 2024 16:41:19 +0800 Subject: [PATCH 1028/1216] setGet setPost setHeaders --- src/Protocols/Http/Request.php | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index ad03c3752..fd8c41c29 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -92,6 +92,13 @@ class Request implements Stringable */ protected bool $isSafe = true; + /** + * Is dirty. + * + * @var bool + */ + protected bool $isDirty = false; + /** * Enable cache. * @@ -130,6 +137,19 @@ public function get(string $name = null, mixed $default = null): mixed return $this->data['get'][$name] ?? $default; } + /** + * Set get. + * + * @param array $get + * @return Request + */ + public function setGet(array $get): Request + { + $this->isDirty = true; + $this->data['get'] = $get; + return $this; + } + /** * Get post. * @@ -148,6 +168,19 @@ public function post(string $name = null, mixed $default = null): mixed return $this->data['post'][$name] ?? $default; } + /** + * Set post. + * + * @param array $post + * @return Request + */ + public function setPost(array $post): Request + { + $this->isDirty = true; + $this->data['post'] = $post; + return $this; + } + /** * Get header item by name. * @@ -167,6 +200,18 @@ public function header(string $name = null, mixed $default = null): mixed return $this->data['headers'][$name] ?? $default; } + /** + * Set headers. + * @param array $headers + * @return $this + */ + public function setHeaders(array $headers): Request + { + $this->isDirty = true; + $this->data['headers'] = $headers; + return $this; + } + /** * Get cookie item by name. * @@ -747,4 +792,15 @@ public function __destruct() }); } } + + /** + * @return void + */ + public function __clone() + { + if ($this->isDirty) { + unset($this->data['get'], $this->data['post'], $this->data['headers']); + } + } + } From d36eed3499c03303177b8004a839e8acbd8928c1 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 8 Oct 2024 16:44:02 +0800 Subject: [PATCH 1029/1216] Optimizations --- src/Events/Swoole.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index e61c9b7f4..91943abc1 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -217,7 +217,6 @@ public function stop(): void Coroutine::cancel($coroutine); } Event::exit(); - posix_kill(posix_getpid(), SIGINT); } /** From 9a95978f7a7f799791671adf048b0de136ab4e9e Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Wed, 9 Oct 2024 08:23:16 +0300 Subject: [PATCH 1030/1216] Fixed cookie parsing, parse_str replaces urlencoded characters. --- src/Protocols/Http/Request.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index fd8c41c29..7cc3ab0de 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -222,8 +222,17 @@ public function setHeaders(array $headers): Request public function cookie(string $name = null, mixed $default = null): mixed { if (!isset($this->data['cookie'])) { - $this->data['cookie'] = []; - parse_str(preg_replace('/; ?/', '&', $this->header('cookie', '')), $this->data['cookie']); + $cookies = explode(';', $this->header('cookie', '')); + $mapped = array(); + + foreach ($cookies as $cookie) { + $cookie = explode('=', $cookie); + if (count($cookie) !== 2) { + continue; + } + $mapped[trim($cookie[0])] = $cookie[1]; + } + $this->data['cookie'] = $mapped; } if ($name === null) { return $this->data['cookie']; From dc35e03f9f489bad844b7a8dde0ec3cf1deeb964 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Oct 2024 19:08:38 +0800 Subject: [PATCH 1031/1216] Remove unnecessary exception comments --- src/Connection/AsyncTcpConnection.php | 7 +-- src/Connection/AsyncUdpConnection.php | 9 ++-- src/Connection/ConnectionInterface.php | 8 +--- src/Connection/TcpConnection.php | 12 +---- src/Events/Select.php | 19 ++++---- src/Protocols/Http.php | 5 +- src/Protocols/Http/Request.php | 4 +- src/Protocols/Http/Session.php | 5 +- src/Protocols/Websocket.php | 35 +++++++------- src/Protocols/Ws.php | 17 +++---- src/Worker.php | 66 ++++++++------------------ 11 files changed, 68 insertions(+), 119 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 14ff8a460..3757003a2 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -154,7 +154,6 @@ class AsyncTcpConnection extends TcpConnection * * @param string $remoteAddress * @param array $socketContext - * @throws Exception */ public function __construct(string $remoteAddress, array $socketContext = []) { @@ -195,7 +194,7 @@ public function __construct(string $remoteAddress, array $socketContext = []) if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); + throw new RuntimeException("class \\Protocols\\$scheme not exist"); } } } else { @@ -216,7 +215,6 @@ public function __construct(string $remoteAddress, array $socketContext = []) * * @param int $after * @return void - * @throws Throwable */ public function reconnect(int $after = 0): void { @@ -236,7 +234,6 @@ public function reconnect(int $after = 0): void * Do connect. * * @return void - * @throws Throwable */ public function connect(): void { @@ -302,7 +299,6 @@ public function connect(): void * @param int $code * @param mixed $msg * @return void - * @throws Throwable */ protected function emitError(int $code, mixed $msg): void { @@ -351,7 +347,6 @@ public function getRemoteURI(): string * Check connection is successfully established or failed. * * @return void - * @throws Throwable */ public function checkConnection(): void { diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 512ab187b..d17fa5b31 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -17,6 +17,7 @@ namespace Workerman\Connection; use Exception; +use RuntimeException; use Throwable; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; @@ -70,7 +71,7 @@ class AsyncUdpConnection extends UdpConnection * Construct. * * @param string $remoteAddress - * @throws Exception + * @throws Throwable */ public function __construct($remoteAddress, $contextOption = []) { @@ -83,7 +84,7 @@ public function __construct($remoteAddress, $contextOption = []) if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\$scheme"; if (!class_exists($this->protocol)) { - throw new Exception("class \\Protocols\\$scheme not exist"); + throw new RuntimeException("class \\Protocols\\$scheme not exist"); } } } @@ -97,7 +98,6 @@ public function __construct($remoteAddress, $contextOption = []) * * @param resource $socket * @return void - * @throws Throwable */ public function baseRead($socket): void { @@ -127,7 +127,6 @@ public function baseRead($socket): void * @param mixed $data * @param bool $raw * @return void - * @throws Throwable */ public function close(mixed $data = null, bool $raw = false): void { @@ -154,7 +153,6 @@ public function close(mixed $data = null, bool $raw = false): void * @param mixed $sendBuffer * @param bool $raw * @return bool|null - * @throws Throwable */ public function send(mixed $sendBuffer, bool $raw = false): bool|null { @@ -176,7 +174,6 @@ public function send(mixed $sendBuffer, bool $raw = false): bool|null * Connect. * * @return void - * @throws Throwable */ public function connect(): void { diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index f496adafa..a12044271 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -170,7 +170,6 @@ abstract public function isIpV6(): bool; /** * @param Throwable $exception * @return void - * @throws Throwable */ public function error(Throwable $exception): void { @@ -181,11 +180,8 @@ public function error(Throwable $exception): void try { ($this->errorHandler)($exception); } catch (Throwable $exception) { - if ($this->eventLoop instanceof Event) { - echo $exception; - return; - } - throw $exception; + Worker::stopAll(250, $exception); + return; } } } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 6c640a5db..87bd56b53 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -400,7 +400,6 @@ public function getStatus(bool $rawOutput = true): int|string * @param mixed $sendBuffer * @param bool $raw * @return bool|null - * @throws Throwable */ public function send(mixed $sendBuffer, bool $raw = false): bool|null { @@ -414,7 +413,7 @@ public function send(mixed $sendBuffer, bool $raw = false): bool|null $parser = $this->protocol; try { $sendBuffer = $parser::encode($sendBuffer, $this); - } catch(\Throwable $e) { + } catch(Throwable $e) { $this->error($e); } if ($sendBuffer === '') { @@ -605,7 +604,6 @@ public function pauseRecv(): void * Resumes reading after a call to pauseRecv. * * @return void - * @throws Throwable */ public function resumeRecv(): void { @@ -623,7 +621,6 @@ public function resumeRecv(): void * @param resource $socket * @param bool $checkEof * @return void - * @throws Throwable */ public function baseRead($socket, bool $checkEof = true): void { @@ -764,7 +761,6 @@ public function baseRead($socket, bool $checkEof = true): void * Base write handler. * * @return void - * @throws Throwable */ public function baseWrite(): void { @@ -811,7 +807,6 @@ public function baseWrite(): void * * @param resource $socket * @return bool|int - * @throws Throwable */ public function doSslHandshake($socket): bool|int { @@ -898,7 +893,6 @@ public function consumeRecvBuffer(int $length): void * @param mixed $data * @param bool $raw * @return void - * @throws Throwable */ public function close(mixed $data = null, bool $raw = false): void { @@ -964,7 +958,6 @@ public function getSocket() * Check whether send buffer will be full. * * @return void - * @throws Throwable */ protected function checkBufferWillFull(): void { @@ -981,7 +974,6 @@ protected function checkBufferWillFull(): void * Whether send buffer is full. * * @return bool - * @throws Throwable */ protected function bufferIsFull(): bool { @@ -1013,7 +1005,6 @@ public function bufferIsEmpty(): bool * Destroy connection. * * @return void - * @throws Throwable */ public function destroy(): void { @@ -1101,7 +1092,6 @@ public function jsonSerialize(): array * Destruct. * * @return void - * @throws Throwable */ public function __destruct() { diff --git a/src/Events/Select.php b/src/Events/Select.php index 95f2fa77a..8467f6bff 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -16,6 +16,8 @@ namespace Workerman\Events; +use SplPriorityQueue; +use Throwable; use function count; use function max; use function microtime; @@ -86,9 +88,9 @@ final class Select implements EventInterface * Timer scheduler. * {['data':timer_id, 'priority':run_timestamp], ..} * - * @var \SplPriorityQueue + * @var SplPriorityQueue */ - private \SplPriorityQueue $scheduler; + private SplPriorityQueue $scheduler; /** * All timer event listeners. @@ -122,8 +124,8 @@ final class Select implements EventInterface */ public function __construct() { - $this->scheduler = new \SplPriorityQueue(); - $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new SplPriorityQueue(); + $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); } /** @@ -299,7 +301,6 @@ public function offSignal(int $signal): bool * Tick for timer. * * @return void - * @throws \Throwable */ protected function tick(): void { @@ -349,8 +350,8 @@ protected function tick(): void */ public function deleteAllTimer(): void { - $this->scheduler = new \SplPriorityQueue(); - $this->scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduler = new SplPriorityQueue(); + $this->scheduler->setExtractFlags(SplPriorityQueue::EXTR_BOTH); $this->eventTimer = []; } @@ -367,7 +368,7 @@ public function run(): void // Waiting read/write/signal/timeout events. try { @stream_select($read, $write, $except, 0, $this->selectTimeout); - } catch (\Throwable) { + } catch (Throwable) { // do nothing } } else { @@ -450,7 +451,7 @@ private function safeCall(callable $func, array $args = []): void { try { $func(...$args); - } catch (\Throwable $e) { + } catch (Throwable $e) { if ($this->errorHandler === null) { echo $e; } else { diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 5eb3f0954..ddc1ccfe9 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -86,7 +86,7 @@ public static function requestClass(?string $className = null): string * * @param bool $value */ - public static function enableCache(bool $value) + public static function enableCache(bool $value): void { static::$enableCache = $value; } @@ -97,7 +97,6 @@ public static function enableCache(bool $value) * @param string $buffer * @param TcpConnection $connection * @return int - * @throws Throwable */ public static function input(string $buffer, TcpConnection $connection): int { @@ -194,7 +193,6 @@ public static function decode(string $buffer, TcpConnection $connection): Reques * @param string|Response $response * @param TcpConnection $connection * @return string - * @throws Throwable */ public static function encode(mixed $response, TcpConnection $connection): string { @@ -266,7 +264,6 @@ public static function encode(mixed $response, TcpConnection $connection): strin * @param resource $handler * @param int $offset * @param int $length - * @throws Throwable */ protected static function sendStream(TcpConnection $connection, $handler, int $offset = 0, int $length = 0): void { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 7cc3ab0de..b2331c5ac 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -226,7 +226,7 @@ public function cookie(string $name = null, mixed $default = null): mixed $mapped = array(); foreach ($cookies as $cookie) { - $cookie = explode('=', $cookie); + $cookie = explode('=', $cookie, 2); if (count($cookie) !== 2) { continue; } @@ -678,7 +678,7 @@ protected function parseUploadFile(string $boundary, int $sectionStartOffset, st break; case "webkitrelativepath": - $file['full_path'] = \trim($value); + $file['full_path'] = trim($value); break; } } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index c463630e8..5d92f0b86 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -17,6 +17,7 @@ namespace Workerman\Protocols\Http; use Exception; +use Random\RandomException; use RuntimeException; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; @@ -153,7 +154,7 @@ class Session * * @var bool */ - protected $isSafe = true; + protected bool $isSafe = true; /** * Session constructor. @@ -437,7 +438,7 @@ public function __wakeup() * __destruct. * * @return void - * @throws Exception + * @throws RandomException */ public function __destruct() { diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index f4d086613..bf31ad46e 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -16,7 +16,6 @@ namespace Workerman\Protocols; -use Exception; use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; @@ -24,8 +23,11 @@ use Workerman\Worker; use function base64_encode; use function chr; +use function deflate_add; +use function deflate_init; use function floor; -use function gettype; +use function inflate_add; +use function inflate_init; use function is_scalar; use function ord; use function pack; @@ -37,6 +39,8 @@ use function strpos; use function substr; use function unpack; +use const ZLIB_DEFAULT_STRATEGY; +use const ZLIB_ENCODING_RAW; /** * WebSocket protocol. @@ -77,7 +81,6 @@ class Websocket * @param string $buffer * @param TcpConnection $connection * @return int - * @throws Throwable */ public static function input(string $buffer, TcpConnection $connection): int { @@ -256,19 +259,18 @@ public static function input(string $buffer, TcpConnection $connection): int * @param mixed $buffer * @param TcpConnection $connection * @return string - * @throws Throwable */ public static function encode(mixed $buffer, TcpConnection $connection): string { if (!is_scalar($buffer)) { - throw new Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to string. "); + $buffer = json_encode($buffer, JSON_UNESCAPED_UNICODE); } if (empty($connection->websocketType)) { $connection->websocketType = static::BINARY_TYPE_BLOB; } - if (\ord($connection->websocketType) & 64) { + if (ord($connection->websocketType) & 64) { $buffer = static::deflate($connection, $buffer); } @@ -372,23 +374,23 @@ public static function decode(string $buffer, TcpConnection $connection): string * @param bool $isFinFrame * @return false|string */ - protected static function inflate(TcpConnection $connection, string $buffer, bool $isFinFrame) + protected static function inflate(TcpConnection $connection, string $buffer, bool $isFinFrame): bool|string { if (!isset($connection->context->inflator)) { - $connection->context->inflator = \inflate_init( - \ZLIB_ENCODING_RAW, + $connection->context->inflator = inflate_init( + ZLIB_ENCODING_RAW, [ 'level' => -1, 'memory' => 8, 'window' => 15, - 'strategy' => \ZLIB_DEFAULT_STRATEGY + 'strategy' => ZLIB_DEFAULT_STRATEGY ] ); } if ($isFinFrame) { $buffer .= "\x00\x00\xff\xff"; } - return \inflate_add($connection->context->inflator, $buffer); + return inflate_add($connection->context->inflator, $buffer); } /** @@ -398,20 +400,20 @@ protected static function inflate(TcpConnection $connection, string $buffer, boo * @param string $buffer * @return false|string */ - protected static function deflate(TcpConnection $connection, string $buffer) + protected static function deflate(TcpConnection $connection, string $buffer): bool|string { if (!isset($connection->context->deflator)) { - $connection->context->deflator = \deflate_init( - \ZLIB_ENCODING_RAW, + $connection->context->deflator = deflate_init( + ZLIB_ENCODING_RAW, [ 'level' => -1, 'memory' => 8, 'window' => 15, - 'strategy' => \ZLIB_DEFAULT_STRATEGY + 'strategy' => ZLIB_DEFAULT_STRATEGY ] ); } - return \substr(\deflate_add($connection->context->deflator, $buffer), 0, -4); + return substr(deflate_add($connection->context->deflator, $buffer), 0, -4); } /** @@ -420,7 +422,6 @@ protected static function deflate(TcpConnection $connection, string $buffer) * @param string $buffer * @param TcpConnection $connection * @return int - * @throws Throwable */ public static function dealHandshake(string $buffer, TcpConnection $connection): int { diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 565f8476c..91c4e0798 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -16,7 +16,6 @@ namespace Workerman\Protocols; -use Exception; use Throwable; use Workerman\Connection\AsyncTcpConnection; use Workerman\Connection\ConnectionInterface; @@ -25,10 +24,8 @@ use Workerman\Worker; use function base64_encode; use function bin2hex; +use function explode; use function floor; -use function gettype; -use function is_array; -use function is_scalar; use function ord; use function pack; use function preg_match; @@ -65,7 +62,6 @@ class Ws * @param string $buffer * @param AsyncTcpConnection $connection * @return int|false - * @throws Throwable */ public static function input(string $buffer, AsyncTcpConnection $connection): bool|int { @@ -393,7 +389,6 @@ public static function sendHandshake(AsyncTcpConnection $connection): void * @param string $buffer * @param AsyncTcpConnection $connection * @return bool|int - * @throws Throwable */ public static function dealHandshake(string $buffer, AsyncTcpConnection $connection): bool|int { @@ -455,9 +450,9 @@ public static function dealHandshake(string $buffer, AsyncTcpConnection $connect */ protected static function parseResponse(string $buffer): Response { - [$http_header, ] = \explode("\r\n\r\n", $buffer, 2); - $header_data = \explode("\r\n", $http_header); - [$protocol, $status, $phrase] = \explode(' ', $header_data[0], 3); + [$http_header, ] = explode("\r\n\r\n", $buffer, 2); + $header_data = explode("\r\n", $http_header); + [$protocol, $status, $phrase] = explode(' ', $header_data[0], 3); $protocolVersion = substr($protocol, 5); unset($header_data[0]); $headers = []; @@ -466,8 +461,8 @@ protected static function parseResponse(string $buffer): Response if (empty($content)) { continue; } - list($key, $value) = \explode(':', $content, 2); - $value = \trim($value); + list($key, $value) = explode(':', $content, 2); + $value = trim($value); $headers[$key] = $value; } return (new Response())->withStatus((int)$status, $phrase)->withHeaders($headers)->withProtocolVersion($protocolVersion); diff --git a/src/Worker.php b/src/Worker.php index 2c37b494b..9663b0b70 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -21,6 +21,7 @@ use Revolt\EventLoop; use RuntimeException; use stdClass; +use Stringable; use Throwable; use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; @@ -30,6 +31,9 @@ use Workerman\Events\Revolt; use Workerman\Events\Select; use Workerman\Protocols\ProtocolInterface; +use function defined; +use function function_exists; +use function is_resource; use function method_exists; use function restore_error_handler; use function set_error_handler; @@ -38,6 +42,10 @@ use function substr; use function array_walk; use function get_class; +use const DIRECTORY_SEPARATOR; +use const PHP_SAPI; +use const PHP_VERSION; +use const STDOUT; /** * Worker class @@ -368,14 +376,6 @@ class Worker */ protected string $socketName = ''; - /** - * parse from socketName avoid parse again in master or worker - * LocalSocket The format is like tcp://0.0.0.0:8080 - * - * @var ?string - */ - protected ?string $localSocket = null; - /** * Context of socket. * @@ -566,7 +566,6 @@ class Worker * Run all worker instances. * * @return void - * @throws Throwable */ public static function runAll(): void { @@ -585,7 +584,7 @@ public static function runAll(): void static::forkWorkers(); static::resetStd(); static::monitorWorkers(); - } catch (\Throwable $e) { + } catch (Throwable $e) { static::log($e); } } @@ -598,19 +597,19 @@ public static function runAll(): void protected static function checkSapiEnv(): void { // Only for cli and micro. - if (!in_array(\PHP_SAPI, ['cli', 'micro'])) { + if (!in_array(PHP_SAPI, ['cli', 'micro'])) { exit("Only run in command line mode\n"); } } private static function initStdOut(): void { - $defaultStream = fn () => \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); + $defaultStream = fn () => defined('STDOUT') ? STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); static::$outputStream ??= $defaultStream(); //@phpstan-ignore-line - if (!\is_resource(self::$outputStream) || get_resource_type(self::$outputStream) !== 'stream') { + if (!is_resource(self::$outputStream) || get_resource_type(self::$outputStream) !== 'stream') { $type = get_debug_type(self::$outputStream); static::$outputStream = $defaultStream(); - throw new \RuntimeException(sprintf('The $outputStream must to be a stream, %s given', $type)); + throw new RuntimeException(sprintf('The $outputStream must to be a stream, %s given', $type)); } static::$outputDecorated ??= self::hasColorSupport(); @@ -631,8 +630,8 @@ private static function hasColorSupport(): bool return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(self::$outputStream)) + if (DIRECTORY_SEPARATOR === '\\') { + return (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(self::$outputStream)) || getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON' || getenv('TERM') === 'xterm'; @@ -755,7 +754,6 @@ protected static function lock(int $flag = LOCK_EX): void * Init All worker instances. * * @return void - * @throws Exception */ protected static function initWorkers(): void { @@ -871,7 +869,7 @@ protected static function displayUI(): void $jitStatus = function_exists('opcache_get_status') && (opcache_get_status()['jit']['on'] ?? false) === true ? 'on' : 'off'; if (DIRECTORY_SEPARATOR !== '/') { static::safeEcho("---------------------------------------------- WORKERMAN -----------------------------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. \PHP_VERSION . " (Jit $jitStatus)\r\n"); + static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION . " (Jit $jitStatus)\r\n"); static::safeEcho("----------------------------------------------- WORKERS ------------------------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; @@ -1244,7 +1242,6 @@ protected static function installSignal(): void * Reinstall signal handler. * * @return void - * @throws Throwable */ protected static function reinstallSignal(): void { @@ -1262,7 +1259,6 @@ protected static function reinstallSignal(): void * Signal handler. * * @param int $signal - * @throws Throwable */ protected static function signalHandler(int $signal): void { @@ -1303,8 +1299,6 @@ protected static function signalHandler(int $signal): void /** * Run as daemon mode. - * - * @throws Exception */ protected static function daemonize(): void { @@ -1373,8 +1367,6 @@ public static function resetStd(): void /** * Save pid. - * - * @throws Exception */ protected static function saveMasterPid(): void { @@ -1418,7 +1410,6 @@ protected static function getAllWorkerPids(): array * Fork some worker processes. * * @return void - * @throws Throwable */ protected static function forkWorkers(): void { @@ -1433,7 +1424,6 @@ protected static function forkWorkers(): void * Fork some worker processes. * * @return void - * @throws Throwable */ protected static function forkWorkersForLinux(): void { @@ -1458,7 +1448,6 @@ protected static function forkWorkersForLinux(): void * Fork some worker processes. * * @return void - * @throws Throwable */ protected static function forkWorkersForWindows(): void { @@ -1509,7 +1498,7 @@ protected static function forkWorkersForWindows(): void $worker->run(); static::$globalEvent->run(); if (static::$status !== self::STATUS_SHUTDOWN) { - $err = new Exception('event-loop exited'); + $err = new RuntimeException('event-loop exited'); static::log($err); exit(250); } @@ -1589,7 +1578,6 @@ protected static function checkWorkerStatusForWindows(): void * Fork one worker process. * * @param self $worker - * @throws Exception|Throwable */ protected static function forkOneWorkerForLinux(self $worker): void { @@ -1736,7 +1724,6 @@ protected static function monitorWorkers(): void * Monitor all child processes. * * @return void - * @throws Throwable */ protected static function monitorWorkersForLinux(): void { @@ -1810,7 +1797,6 @@ protected static function monitorWorkersForLinux(): void * Monitor all child processes. * * @return void - * @throws Throwable */ protected static function monitorWorkersForWindows(): void { @@ -1844,7 +1830,6 @@ protected static function exitAndClearAll(): void * Execute reload. * * @return void - * @throws Throwable */ protected static function reload(): void { @@ -1923,7 +1908,6 @@ protected static function reload(): void * * @param int $code * @param mixed $log - * @throws Throwable */ public static function stopAll(int $code = 0, mixed $log = ''): void { @@ -1966,7 +1950,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void // Ignore Swoole ExitException: Swoole exit. exit($code); /** @phpstan-ignore-next-line */ - } catch (\Exception) { + } catch (Throwable) { // do nothing } } @@ -2202,11 +2186,11 @@ protected static function getErrorType(int $type): string /** * Log. * - * @param \Stringable|string $msg + * @param Stringable|string $msg * @param bool $decorated * @return void */ - public static function log(\Stringable|string $msg, bool $decorated = false): void + public static function log(Stringable|string $msg, bool $decorated = false): void { $msg = trim((string)$msg); @@ -2298,8 +2282,6 @@ public function __construct(string $socketName = null, array $socketContext = [] /** * Listen. - * - * @throws Exception */ public function listen(): void { @@ -2323,7 +2305,7 @@ public function listen(): void // Create an Internet or Unix domain server socket. $this->mainSocket = stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->socketContext); if (!$this->mainSocket) { - throw new Exception($errmsg); + throw new RuntimeException($errmsg); } if ($this->transport === 'ssl') { @@ -2372,8 +2354,6 @@ public function unlisten(): void /** * Parse local socket address. - * - * @throws Exception */ protected function parseSocketAddress(): ?string { @@ -2448,7 +2428,6 @@ public function getSocketName(): string * Run worker instance. * * @return void - * @throws Throwable */ public function run(): void { @@ -2470,7 +2449,6 @@ public function run(): void * Stop current worker instance. * * @return void - * @throws Throwable */ public function stop(): void { @@ -2509,7 +2487,6 @@ public function stop(): void * * @param resource $socket * @return void - * @throws Throwable */ protected function acceptTcpConnection(mixed $socket): void { @@ -2550,7 +2527,6 @@ protected function acceptTcpConnection(mixed $socket): void * * @param resource $socket * @return void - * @throws Throwable */ protected function acceptUdpConnection(mixed $socket): void { From 43f9aadcfc8ed42cf73ea3cf74dbbb8b3242be9e Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 10 Oct 2024 06:59:00 +0800 Subject: [PATCH 1032/1216] Check pidFile empty --- src/Worker.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 9663b0b70..deb2b2c24 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -658,15 +658,15 @@ protected static function init(): void $startFilePrefix = hash('xxh64', static::$startFile); // Pid file. - static::$pidFile ??= sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix); + static::$pidFile = empty(static::$pidFile) ? sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix) : static::$pidFile; // Status file. - static::$statusFile ??= sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix); + static::$statusFile = empty(static::$statusFile) ? sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix) : static::$statusFile; static::$statisticsFile ??= static::$statusFile; static::$connectionsFile ??= static::$statusFile . '.connection'; // Log file. - static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); + static::$logFile = empty(static::$logFile) ? sprintf('%s/workerman.log', dirname(__DIR__, 2)) : static::$logFile; if (!is_file(static::$logFile) && static::$logFile !== '/dev/null') { // if /runtime/logs default folder not exists From a3bf4be3421d8deda4cd0123692b98dd0a2f2989 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 10 Oct 2024 09:31:31 +0300 Subject: [PATCH 1033/1216] Fixed SSL connection send returning null and onWebsocketConnected isn't called. --- src/Protocols/Websocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index bf31ad46e..89b44d47f 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -492,13 +492,13 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): } $handshakeMessage .= "\r\n"; // Send handshake response. - $status = $connection->send($handshakeMessage, true); + $connection->send($handshakeMessage, true); // Mark handshake complete. $connection->context->websocketHandshake = true; // Try to emit onWebSocketConnected callback. $onWebsocketConnected = $connection->onWebSocketConnected ?? $connection->worker->onWebSocketConnected ?? false; - if ($status && $onWebsocketConnected) { + if ($onWebsocketConnected) { try { $onWebsocketConnected($connection, $request); } catch (Throwable $e) { From 7f6b51f275bdc4578100cdc94f581e708749b4e8 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 19 Oct 2024 13:00:01 +0200 Subject: [PATCH 1034/1216] Small change to rerun CI --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b8cc064d..0ca57a9a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.1", "8.2", "8.3", "8.4"] + php: ["8.1", "8.2", "8.3", "8.4"] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} From bab53ee9699e2ca18ae4b9711cd0b41e0b420547 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 19 Oct 2024 13:08:40 +0200 Subject: [PATCH 1035/1216] Fix Request.php to use explicit nullable for PHP8.4 --- src/Protocols/Http/Request.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 548735828..2ff2c2855 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -119,7 +119,7 @@ public function __construct(protected string $buffer) {} * @param mixed $default * @return mixed */ - public function get(string $name = null, mixed $default = null): mixed + public function get(?string $name = null, mixed $default = null): mixed { if (!isset($this->data['get'])) { $this->parseGet(); @@ -137,7 +137,7 @@ public function get(string $name = null, mixed $default = null): mixed * @param mixed $default * @return mixed */ - public function post(string $name = null, mixed $default = null): mixed + public function post(?string $name = null, mixed $default = null): mixed { if (!isset($this->data['post'])) { $this->parsePost(); @@ -155,7 +155,7 @@ public function post(string $name = null, mixed $default = null): mixed * @param mixed $default * @return mixed */ - public function header(string $name = null, mixed $default = null): mixed + public function header(?string $name = null, mixed $default = null): mixed { if (!isset($this->data['headers'])) { $this->parseHeaders(); @@ -174,7 +174,7 @@ public function header(string $name = null, mixed $default = null): mixed * @param mixed $default * @return mixed */ - public function cookie(string $name = null, mixed $default = null): mixed + public function cookie(?string $name = null, mixed $default = null): mixed { if (!isset($this->data['cookie'])) { $this->data['cookie'] = []; @@ -192,7 +192,7 @@ public function cookie(string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(string $name = null) + public function file(?string $name = null) { if (!isset($this->data['files'])) { $this->parsePost(); @@ -295,7 +295,7 @@ public function session(): Session * @return string * @throws Exception */ - public function sessionId(string $sessionId = null): string + public function sessionId(?string $sessionId = null): string { if ($sessionId) { unset($this->sid); From cf2baf32fdb926a89f24cf64d96e4bfa5a639f37 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 19 Oct 2024 13:14:01 +0200 Subject: [PATCH 1036/1216] Update Pest.php to use explicit nullable --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 7db6ab1bc..f2a84413a 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -42,7 +42,7 @@ function something() // .. } -function testWithConnectionClose(Closure $closure, string $dataContains = null, $connectionClass = TcpConnection::class): void +function testWithConnectionClose(Closure $closure, ?string $dataContains = null, $connectionClass = TcpConnection::class): void { $tcpConnection = Mockery::spy($connectionClass); $closure($tcpConnection); From 103239825920d6e5456aeeb694979e780b99dc6d Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 19 Oct 2024 13:29:34 +0200 Subject: [PATCH 1037/1216] Update Response.php with explicit nullable --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 0df251983..2f73e30af 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -244,7 +244,7 @@ public function getHeaders(): array * @param string|null $reasonPhrase * @return $this */ - public function withStatus(int $code, string $reasonPhrase = null): static + public function withStatus(int $code, ?string $reasonPhrase = null): static { $this->status = $code; $this->reason = $reasonPhrase; From 7c458a9e4fd8fca9ae1329a06ec237027222a788 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 Oct 2024 15:28:45 +0800 Subject: [PATCH 1038/1216] Http optimizations --- src/Connection/TcpConnection.php | 18 ++++++++++--- src/Protocols/Http.php | 32 ----------------------- src/Protocols/Http/Request.php | 44 +++++++++++++++----------------- 3 files changed, 35 insertions(+), 59 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 87bd56b53..e02cc6cc7 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -657,11 +657,15 @@ public function baseRead($socket, bool $checkEof = true): void ++self::$statistics['total_request']; $request = $requests[$buffer]; if ($request instanceof Request) { - $request = clone $request; - $requests[$buffer] = $request; $request->connection = $this; $this->request = $request; - $request->properties = []; + try { + ($this->onMessage)($this, $request); + } catch (Throwable $e) { + $this->error($e); + } + $requests[$buffer] = clone $request; + return; } try { ($this->onMessage)($this, $request); @@ -729,10 +733,16 @@ public function baseRead($socket, bool $checkEof = true): void $parser = $this->protocol; $request = $parser::decode($oneRequestBuffer, $this); if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { - $requests[$oneRequestBuffer] = $request; + ($this->onMessage)($this, $request); + if ($request instanceof Request) { + $requests[$oneRequestBuffer] = clone $request; + } else { + $requests[$oneRequestBuffer] = $request; + } if (count($requests) > static::MAX_CACHE_SIZE) { unset($requests[key($requests)]); } + return; } ($this->onMessage)($this, $request); } catch (Throwable $e) { diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index ddc1ccfe9..02cafdee6 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -60,13 +60,6 @@ class Http */ protected static string $uploadTmpDir = ''; - /** - * Cache. - * - * @var bool. - */ - protected static bool $enableCache = true; - /** * Get or set the request class name. * @@ -81,16 +74,6 @@ public static function requestClass(?string $className = null): string return static::$requestClass; } - /** - * Enable or disable Cache. - * - * @param bool $value - */ - public static function enableCache(bool $value): void - { - static::$enableCache = $value; - } - /** * Check the integrity of the package. * @@ -166,24 +149,9 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function decode(string $buffer, TcpConnection $connection): Request { - static $requests = []; - $cacheable = static::$enableCache && !isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH]); - if (isset($requests[$buffer])) { - $request = clone $requests[$buffer]; - $request->connection = $connection; - $connection->request = $request; - $request->properties = []; - return $request; - } $request = new static::$requestClass($buffer); $request->connection = $connection; $connection->request = $request; - if (true === $cacheable) { - $requests[$buffer] = $request; - if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { - unset($requests[key($requests)]); - } - } return $request; } diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index e31165584..be43a59d7 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -71,6 +71,20 @@ class Request implements Stringable */ public static int $maxFileUploads = 1024; + /** + * Maximum string length for cache + * + * @var int + */ + public const MAX_CACHE_STRING_LENGTH = 4096; + + /** + * Maximum cache size. + * + * @var int + */ + public const MAX_CACHE_SIZE = 256; + /** * Properties. * @@ -99,13 +113,6 @@ class Request implements Stringable */ protected bool $isDirty = false; - /** - * Enable cache. - * - * @var bool - */ - protected static bool $enableCache = true; - /** * Session id. * @@ -431,16 +438,6 @@ public function rawBuffer(): string return $this->buffer; } - /** - * Enable or disable cache. - * - * @param bool $value - */ - public static function enableCache(bool $value): void - { - static::$enableCache = $value; - } - /** * Parse first line of http header buffer. * @@ -481,7 +478,7 @@ protected function parseHeaders(): void return; } $headBuffer = substr($rawHead, $endLinePosition + 2); - $cacheable = static::$enableCache && !isset($headBuffer[4096]); + $cacheable = !isset($headBuffer[static::MAX_CACHE_STRING_LENGTH]); if ($cacheable && isset($cache[$headBuffer])) { $this->data['headers'] = $cache[$headBuffer]; return; @@ -504,7 +501,7 @@ protected function parseHeaders(): void } if ($cacheable) { $cache[$headBuffer] = $this->data['headers']; - if (count($cache) > 128) { + if (count($cache) > static::MAX_CACHE_SIZE) { unset($cache[key($cache)]); } } @@ -523,7 +520,7 @@ protected function parseGet(): void if ($queryString === '') { return; } - $cacheable = static::$enableCache && !isset($queryString[1024]); + $cacheable = !isset($queryString[static::MAX_CACHE_STRING_LENGTH]); if ($cacheable && isset($cache[$queryString])) { $this->data['get'] = $cache[$queryString]; return; @@ -531,7 +528,7 @@ protected function parseGet(): void parse_str($queryString, $this->data['get']); if ($cacheable) { $cache[$queryString] = $this->data['get']; - if (count($cache) > 256) { + if (count($cache) > static::MAX_CACHE_SIZE) { unset($cache[key($cache)]); } } @@ -556,7 +553,7 @@ protected function parsePost(): void if ($bodyBuffer === '') { return; } - $cacheable = static::$enableCache && !isset($bodyBuffer[1024]); + $cacheable = !isset($bodyBuffer[static::MAX_CACHE_STRING_LENGTH]); if ($cacheable && isset($cache[$bodyBuffer])) { $this->data['post'] = $cache[$bodyBuffer]; return; @@ -568,7 +565,7 @@ protected function parsePost(): void } if ($cacheable) { $cache[$bodyBuffer] = $this->data['post']; - if (count($cache) > 256) { + if (count($cache) > static::MAX_CACHE_SIZE) { unset($cache[key($cache)]); } } @@ -807,6 +804,7 @@ public function __destruct() */ public function __clone() { + $this->properties = []; if ($this->isDirty) { unset($this->data['get'], $this->data['post'], $this->data['headers']); } From 57264fc3744278b4ad7e909d7e8e01f9752c089f Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 22 Oct 2024 20:12:59 +0800 Subject: [PATCH 1039/1216] 5.0.0-rc.2 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index deb2b2c24..c94c918d5 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.1'; + final public const VERSION = '5.0.0-rc.2'; /** * Status starting. From d459794e952c7e37fc82a7be9ede6bd8fbb98fc9 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 25 Oct 2024 09:06:24 +0800 Subject: [PATCH 1040/1216] Remove E_STRICT --- src/Worker.php | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index c94c918d5..c3f0351fa 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -524,21 +524,20 @@ class Worker * @var array */ public const ERROR_TYPE = [ - E_ERROR => 'E_ERROR', // 1 - E_WARNING => 'E_WARNING', // 2 - E_PARSE => 'E_PARSE', // 4 - E_NOTICE => 'E_NOTICE', // 8 - E_CORE_ERROR => 'E_CORE_ERROR', // 16 - E_CORE_WARNING => 'E_CORE_WARNING', // 32 - E_COMPILE_ERROR => 'E_COMPILE_ERROR', // 64 - E_COMPILE_WARNING => 'E_COMPILE_WARNING', // 128 - E_USER_ERROR => 'E_USER_ERROR', // 256 - E_USER_WARNING => 'E_USER_WARNING', // 512 - E_USER_NOTICE => 'E_USER_NOTICE', // 1024 - E_STRICT => 'E_STRICT', // 2048 - E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', // 4096 - E_DEPRECATED => 'E_DEPRECATED', // 8192 - E_USER_DEPRECATED => 'E_USER_DEPRECATED' // 16384 + E_ERROR => 'E_ERROR', + E_WARNING => 'E_WARNING', + E_PARSE => 'E_PARSE', + E_NOTICE => 'E_NOTICE', + E_CORE_ERROR => 'E_CORE_ERROR', + E_CORE_WARNING => 'E_CORE_WARNING', + E_COMPILE_ERROR => 'E_COMPILE_ERROR', + E_COMPILE_WARNING => 'E_COMPILE_WARNING', + E_USER_ERROR => 'E_USER_ERROR', + E_USER_WARNING => 'E_USER_WARNING', + E_USER_NOTICE => 'E_USER_NOTICE', + E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', + E_DEPRECATED => 'E_DEPRECATED', + E_USER_DEPRECATED => 'E_USER_DEPRECATED' ]; /** From 1a5f4ad3d6c5dcba22364b09af104526e10529ff Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 29 Oct 2024 16:47:27 +0800 Subject: [PATCH 1041/1216] Optimizations --- src/Protocols/Http.php | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 02cafdee6..228975cbb 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -83,10 +83,6 @@ public static function requestClass(?string $className = null): string */ public static function input(string $buffer, TcpConnection $connection): int { - static $input = []; - if (isset($input[$buffer])) { - return $input[$buffer]; - } $crlfPos = strpos($buffer, "\r\n\r\n"); if (false === $crlfPos) { // Judge whether the package length exceeds the limit. @@ -97,20 +93,13 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $firstLine = explode(" ", strstr($buffer, "\r\n", true), 3); - - if (!in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { + $method = strstr($buffer, ' ', true); + if (!in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } $header = substr($buffer, 0, $crlfPos); - - if (!str_contains($header, "\r\nHost: ") && $firstLine[2] === "HTTP/1.1") { - $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); - return 0; - } - if ($pos = stripos($header, "\r\nContent-Length: ")) { $length += (int)substr($header, $pos + 18, 10); $hasContentLength = true; @@ -130,13 +119,6 @@ public static function input(string $buffer, TcpConnection $connection): int return 0; } - if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { - $input[$buffer] = $length; - if (count($input) > TcpConnection::MAX_CACHE_SIZE) { - unset($input[key($input)]); - } - } - return $length; } From 3d9cac75aef0831e715133e51d9917d2cf50bf4c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 29 Oct 2024 17:18:07 +0800 Subject: [PATCH 1042/1216] Optimaztions --- src/Protocols/Http.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 228975cbb..379f24b74 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -93,13 +93,17 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $method = strstr($buffer, ' ', true); - if (!in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { + $firstLine = explode(" ", strstr($buffer, "\r\n", true), 3); + if (!in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } - $header = substr($buffer, 0, $crlfPos); + if (!str_contains($header, "\r\nHost: ") && $firstLine[2] === "HTTP/1.1") { + $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); + return 0; + } + if ($pos = stripos($header, "\r\nContent-Length: ")) { $length += (int)substr($header, $pos + 18, 10); $hasContentLength = true; @@ -131,9 +135,23 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function decode(string $buffer, TcpConnection $connection): Request { + static $requests = []; + if (isset($requests[$buffer])) { + $request = clone $requests[$buffer]; + $request->connection = $connection; + $connection->request = $request; + $request->properties = []; + return $request; + } $request = new static::$requestClass($buffer); $request->connection = $connection; $connection->request = $request; + if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { + $requests[$buffer] = $request; + if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { + unset($requests[key($requests)]); + } + } return $request; } From bbff564bcfe4feff9b27b3bdd53ee4c541a218fb Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 29 Oct 2024 19:40:26 +0800 Subject: [PATCH 1043/1216] Delete redundant code --- src/Protocols/Http.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 379f24b74..304313fc7 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -16,12 +16,10 @@ namespace Workerman\Protocols; -use Throwable; use Workerman\Connection\TcpConnection; use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; use function clearstatcache; -use function count; use function explode; use function filesize; use function fopen; @@ -32,7 +30,6 @@ use function ini_get; use function is_array; use function is_object; -use function key; use function preg_match; use function strlen; use function strpos; @@ -135,23 +132,9 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function decode(string $buffer, TcpConnection $connection): Request { - static $requests = []; - if (isset($requests[$buffer])) { - $request = clone $requests[$buffer]; - $request->connection = $connection; - $connection->request = $request; - $request->properties = []; - return $request; - } $request = new static::$requestClass($buffer); $request->connection = $connection; $connection->request = $request; - if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { - $requests[$buffer] = $request; - if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { - unset($requests[key($requests)]); - } - } return $request; } From 725dcffda00be3c84aae8966a9fa811acd0428ef Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 3 Nov 2024 20:23:16 +0800 Subject: [PATCH 1044/1216] Optimizations --- src/Connection/TcpConnection.php | 9 ++--- src/Protocols/Http.php | 52 +++++++++++++++++---------- src/Protocols/Http/Request.php | 56 ----------------------------- src/Protocols/ProtocolInterface.php | 6 ++-- src/Protocols/Ws.php | 6 ++-- tests/Unit/Protocols/HttpTest.php | 6 ---- 6 files changed, 44 insertions(+), 91 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index e02cc6cc7..ba7539c75 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -664,6 +664,7 @@ public function baseRead($socket, bool $checkEof = true): void } catch (Throwable $e) { $this->error($e); } + $request->properties = []; $requests[$buffer] = clone $request; return; } @@ -692,10 +693,10 @@ public function baseRead($socket, bool $checkEof = true): void } else { // Get current package length. try { - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; - $this->currentPackageLength = $parser::input($this->recvBuffer, $this); - } catch (Throwable) { + $this->currentPackageLength = $this->protocol::input($this->recvBuffer, $this); + } catch (Throwable $e) { + $this->currentPackageLength = -1; + Worker::safeEcho((string)$e); } // The packet length is unknown. if ($this->currentPackageLength === 0) { diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 304313fc7..1afaba1c2 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -90,18 +90,14 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $firstLine = explode(" ", strstr($buffer, "\r\n", true), 3); - if (!in_array($firstLine[0], ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { - $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); - return 0; - } - $header = substr($buffer, 0, $crlfPos); - if (!str_contains($header, "\r\nHost: ") && $firstLine[2] === "HTTP/1.1") { + $method = strstr($buffer, ' ', true); + if (!in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } - if ($pos = stripos($header, "\r\nContent-Length: ")) { + $header = substr($buffer, 0, $crlfPos); + if ($pos = strpos($header, "\r\nContent-Length: ")) { $length += (int)substr($header, $pos + 18, 10); $hasContentLength = true; } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { @@ -119,10 +115,10 @@ public static function input(string $buffer, TcpConnection $connection): int $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } - return $length; } + /** * Http decode. * @@ -132,7 +128,22 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function decode(string $buffer, TcpConnection $connection): Request { + static $requests = []; + if (isset($requests[$buffer])) { + $request = $requests[$buffer]; + $request->connection = $connection; + $connection->request = $request; + $request->properties = []; + return $request; + } $request = new static::$requestClass($buffer); + if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { + $requests[$buffer] = $request; + if (\count($requests) > TcpConnection::MAX_CACHE_SIZE) { + unset($requests[key($requests)]); + } + $request = clone $request; + } $request->connection = $connection; $connection->request = $request; return $request; @@ -154,21 +165,24 @@ public static function encode(mixed $response, TcpConnection $connection): strin if (!is_object($response)) { $extHeader = ''; - if ($connection->headers) { - foreach ($connection->headers as $name => $value) { - if (is_array($value)) { - foreach ($value as $item) { - $extHeader .= "$name: $item\r\n"; - } - } else { - $extHeader .= "$name: $value\r\n"; + $contentType = 'text/html;charset=utf-8'; + foreach ($connection->headers as $name => $value) { + if ($name === 'Content-Type') { + $contentType = $value; + continue; + } + if (is_array($value)) { + foreach ($value as $item) { + $extHeader .= "$name: $item\r\n"; } + } else { + $extHeader .= "$name: $value\r\n"; } - $connection->headers = []; } + $connection->headers = []; $response = (string)$response; $bodyLen = strlen($response); - return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: $bodyLen\r\n\r\n$response"; + return "HTTP/1.1 200 OK\r\nServer: workerman\r\n{$extHeader}Connection: keep-alive\r\nContent-Type: $contentType\r\nContent-Length: $bodyLen\r\n\r\n$response"; } if ($connection->headers) { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index be43a59d7..f3c877370 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -106,13 +106,6 @@ class Request implements Stringable */ protected bool $isSafe = true; - /** - * Is dirty. - * - * @var bool - */ - protected bool $isDirty = false; - /** * Session id. * @@ -144,19 +137,6 @@ public function get(?string $name = null, mixed $default = null): mixed return $this->data['get'][$name] ?? $default; } - /** - * Set get. - * - * @param array $get - * @return Request - */ - public function setGet(array $get): Request - { - $this->isDirty = true; - $this->data['get'] = $get; - return $this; - } - /** * Get post. * @@ -175,19 +155,6 @@ public function post(?string $name = null, mixed $default = null): mixed return $this->data['post'][$name] ?? $default; } - /** - * Set post. - * - * @param array $post - * @return Request - */ - public function setPost(array $post): Request - { - $this->isDirty = true; - $this->data['post'] = $post; - return $this; - } - /** * Get header item by name. * @@ -207,18 +174,6 @@ public function header(?string $name = null, mixed $default = null): mixed return $this->data['headers'][$name] ?? $default; } - /** - * Set headers. - * @param array $headers - * @return $this - */ - public function setHeaders(array $headers): Request - { - $this->isDirty = true; - $this->data['headers'] = $headers; - return $this; - } - /** * Get cookie item by name. * @@ -799,15 +754,4 @@ public function __destruct() } } - /** - * @return void - */ - public function __clone() - { - $this->properties = []; - if ($this->isDirty) { - unset($this->data['get'], $this->data['post'], $this->data['headers']); - } - } - } diff --git a/src/Protocols/ProtocolInterface.php b/src/Protocols/ProtocolInterface.php index ce2c29bb3..f60aa9587 100644 --- a/src/Protocols/ProtocolInterface.php +++ b/src/Protocols/ProtocolInterface.php @@ -27,13 +27,13 @@ interface ProtocolInterface * Check the integrity of the package. * Please return the length of package. * If length is unknown please return 0 that means waiting for more data. - * If the package has something wrong please return false the connection will be closed. + * If the package has something wrong please return -1 the connection will be closed. * * @param string $buffer * @param ConnectionInterface $connection - * @return int|false + * @return int */ - public static function input(string $buffer, ConnectionInterface $connection): bool|int; + public static function input(string $buffer, ConnectionInterface $connection): int; /** * Decode package and emit onMessage($message) callback, $message is the result that decode returned. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 91c4e0798..e958b70eb 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -61,13 +61,13 @@ class Ws * * @param string $buffer * @param AsyncTcpConnection $connection - * @return int|false + * @return int */ - public static function input(string $buffer, AsyncTcpConnection $connection): bool|int + public static function input(string $buffer, AsyncTcpConnection $connection): int { if (empty($connection->context->handshakeStep)) { Worker::safeEcho("recv data before handshake. Buffer:" . bin2hex($buffer) . "\n"); - return false; + return -1; } // Recv handshake response if ($connection->context->handshakeStep === 1) { diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index 0cd3db677..0dae90565 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -40,12 +40,6 @@ ->toBe(0); }, '400 Bad Request'); - //HTTP 1.1 without Host header - testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { - expect(Http::input(str_replace("Host: ", 'NotHost: ', $buffer), $tcpConnection)) - ->toBe(0); - }, '400 Bad Request'); - //content-length exceeds connection max package size testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { $tcpConnection->maxPackageSize = 10; From 7b52c036af042f2efe1a1a1f66c840242b39f52b Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Nov 2024 21:08:10 +0800 Subject: [PATCH 1045/1216] Optimizations --- src/Events/Select.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 8467f6bff..71f233193 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -364,7 +364,7 @@ public function run(): void $read = $this->readFds; $write = $this->writeFds; $except = $this->exceptFds; - if (!empty($read) || !empty($write) || !empty($except)) { + if ($read || $write || $except) { // Waiting read/write/signal/timeout events. try { @stream_select($read, $write, $except, 0, $this->selectTimeout); @@ -400,7 +400,7 @@ public function run(): void } } - if (!empty($this->signalEvents)) { + if ($this->signalEvents) { // Calls signal handlers for pending signals pcntl_signal_dispatch(); } From f1ec924a72b67ebe1c33ad150a065d853e21c1cc Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 4 Nov 2024 22:40:30 +0800 Subject: [PATCH 1046/1216] Optimizations --- src/Events/Select.php | 49 ++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 71f233193..c353cdb64 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -114,6 +114,13 @@ final class Select implements EventInterface */ private int $selectTimeout = 100000000; + /** + * Next run time of the timer. + * + * @var float + */ + private float $nextTickTime = 0; + /** * @var ?callable */ @@ -137,10 +144,8 @@ public function delay(float $delay, callable $func, array $args = []): int $runTime = microtime(true) + $delay; $this->scheduler->insert($timerId, -$runTime); $this->eventTimer[$timerId] = [$func, $args]; - $selectTimeout = ($runTime - microtime(true)) * 1000000; - $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; - if ($this->selectTimeout > $selectTimeout) { - $this->selectTimeout = $selectTimeout; + if ($this->nextTickTime == 0 || $this->nextTickTime > $runTime) { + $this->setNextTickTime($runTime); } return $timerId; } @@ -154,10 +159,8 @@ public function repeat(float $interval, callable $func, array $args = []): int $runTime = microtime(true) + $interval; $this->scheduler->insert($timerId, -$runTime); $this->eventTimer[$timerId] = [$func, $args, $interval]; - $selectTimeout = ($runTime - microtime(true)) * 1000000; - $selectTimeout = $selectTimeout <= 0 ? 1 : (int)$selectTimeout; - if ($this->selectTimeout > $selectTimeout) { - $this->selectTimeout = $selectTimeout; + if ($this->nextTickTime == 0 || $this->nextTickTime > $runTime) { + $this->setNextTickTime($runTime); } return $timerId; } @@ -338,11 +341,27 @@ protected function tick(): void if (!$this->scheduler->isEmpty()) { $schedulerData = $this->scheduler->top(); $nextRunTime = -$schedulerData['priority']; - $timeNow = microtime(true); - $this->selectTimeout = max((int)(($nextRunTime - $timeNow) * 1000000), 0); + $this->setNextTickTime($nextRunTime); + return; + } + $this->setNextTickTime(0); + } + + /** + * Set next tick time. + * + * @param float $nextTickTime + * @return void + */ + protected function setNextTickTime(float $nextTickTime): void + { + $this->nextTickTime = $nextTickTime; + if ($nextTickTime == 0) { + $this->selectTimeout = 10000000; return; } - $this->selectTimeout = 100000000; + $timeNow = microtime(true); + $this->selectTimeout = max((int)(($nextTickTime - $timeNow) * 1000000), 0); } /** @@ -375,10 +394,6 @@ public function run(): void $this->selectTimeout >= 1 && usleep($this->selectTimeout); } - if (!$this->scheduler->isEmpty()) { - $this->tick(); - } - foreach ($read as $fd) { $fdKey = (int)$fd; if (isset($this->readEvents[$fdKey])) { @@ -400,6 +415,10 @@ public function run(): void } } + if ($this->nextTickTime > 0 && microtime(true) >= $this->nextTickTime) { + $this->tick(); + } + if ($this->signalEvents) { // Calls signal handlers for pending signals pcntl_signal_dispatch(); From 392dc063ac817b2fe5fc49f7be639e4dd27e3d72 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Nov 2024 21:12:59 +0800 Subject: [PATCH 1047/1216] Optimizations --- src/Events/Select.php | 2 +- src/Worker.php | 139 +++++++++++++++++------------------------- 2 files changed, 57 insertions(+), 84 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index c353cdb64..811360ebb 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -192,7 +192,7 @@ public function onReadable($stream, callable $func): void { $count = count($this->readFds); if ($count >= 1024) { - trigger_error("System call select exceeded the maximum number of connections 1024, please install event/libevent extension for more connections.", E_USER_WARNING); + trigger_error("System call select exceeded the maximum number of connections 1024, please install event extension for more connections.", E_USER_WARNING); } else if (DIRECTORY_SEPARATOR !== '/' && $count >= 256) { trigger_error("System call select exceeded the maximum number of connections 256.", E_USER_WARNING); } diff --git a/src/Worker.php b/src/Worker.php index c3f0351fa..ae38954b0 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -263,6 +263,12 @@ class Worker */ public bool $stopping = false; + /** + * + * @var class-string + */ + public string $eventLoop; + /** * Daemonize. * @@ -427,46 +433,11 @@ class Worker protected static int $status = self::STATUS_STARTING; /** - * Maximum length of the worker names. + * UI data. * - * @var int + * @var array|int[] */ - protected static int $maxWorkerNameLength = 12; - - /** - * Maximum length of the socket names. - * - * @var int - */ - protected static int $maxSocketNameLength = 12; - - /** - * Maximum length of the process usernames. - * - * @var int - */ - protected static int $maxUserNameLength = 12; - - /** - * Maximum length of the Proto names. - * - * @var int - */ - protected static int $maxProtoNameLength = 4; - - /** - * Maximum length of the Processes names. - * - * @var int - */ - protected static int $maxProcessesNameLength = 9; - - /** - * Maximum length of the state names. - * - * @var int - */ - protected static int $maxStateNameLength = 1; + protected static array $uiLengthData = []; /** * The file to store status info of current worker process. @@ -778,6 +749,10 @@ protected static function initWorkers(): void // Socket name. $worker->context->statusSocket = $worker->getSocketName(); + // Event-loop name. + $eventLoopName = $worker->eventLoop ?? static::$eventLoopClass; + $worker->context->eventLoopName = str_starts_with($eventLoopName, 'Workerman\\Events\\') ? strtolower(substr($eventLoopName, 17)) : $eventLoopName; + // Status name. $worker->context->statusState = ' [OK] '; @@ -786,7 +761,7 @@ protected static function initWorkers(): void !isset($worker->$prop) && !isset($worker->context->$prop) && $worker->context->$prop = 'NNNN'; $propLength = strlen((string)($worker->$prop ?? $worker->context->$prop)); $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; - static::$$key = max(static::$$key, $propLength); + static::$uiLengthData[$key] = max(static::$uiLengthData[$key] ?? 2 * static::UI_SAFE_LENGTH, $propLength); } // Listen. @@ -875,7 +850,7 @@ protected static function displayUI(): void } //show version - $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . " (Jit $jitStatus)" . str_pad('Event-loop:', 16, ' ', STR_PAD_LEFT) . static::getEventLoopName() . PHP_EOL; + $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . " (Jit $jitStatus)" . PHP_EOL; !defined('LINE_VERSION_LENGTH') && define('LINE_VERSION_LENGTH', strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); $lineOne = '' . str_pad(' WORKERMAN ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . '' . PHP_EOL; @@ -888,7 +863,7 @@ protected static function displayUI(): void $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; //just keep compatible with listen name $columnName === 'socket' && $columnName = 'listen'; - $title .= "$columnName" . str_pad('', static::$$key + static::UI_SAFE_LENGTH - strlen($columnName)); + $title .= "$columnName" . str_pad('', static::getUiColumnLength($key) + static::UI_SAFE_LENGTH - strlen($columnName)); } $title && static::safeEcho($title . PHP_EOL); @@ -900,7 +875,7 @@ protected static function displayUI(): void $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; preg_match_all("/(|<\/n>||<\/w>||<\/g>)/i", $propValue, $matches); $placeHolderLength = !empty($matches) ? strlen(implode('', $matches[0])) : 0; - $content .= str_pad($propValue, static::$$key + static::UI_SAFE_LENGTH + $placeHolderLength); + $content .= str_pad($propValue, static::getUiColumnLength($key) + static::UI_SAFE_LENGTH + $placeHolderLength); } $content && static::safeEcho($content . PHP_EOL); } @@ -929,11 +904,12 @@ protected static function displayUI(): void public static function getUiColumns(): array { return [ + 'event' => 'eventLoopName', 'proto' => 'transport', 'user' => 'user', 'worker' => 'name', 'socket' => 'statusSocket', - 'processes' => 'count', + 'count' => 'count', 'state' => 'statusState', ]; } @@ -949,7 +925,7 @@ public static function getSingleLineTotalLength(): int foreach (static::getUiColumns() as $columnName => $prop) { $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; - $totalLength += static::$$key + static::UI_SAFE_LENGTH; + $totalLength += static::getUiColumnLength($key) + static::UI_SAFE_LENGTH; } //Keep beauty when show less columns @@ -1160,8 +1136,8 @@ protected static function formatProcessStatusData(): string $totalFails = 0; $totalMemory = 0; $totalTimers = 0; - $maxLen1 = static::$maxSocketNameLength; - $maxLen2 = static::$maxWorkerNameLength; + $maxLen1 = max(static::getUiColumnLength('maxSocketNameLength'), 2 * static::UI_SAFE_LENGTH); + $maxLen2 = max(static::getUiColumnLength('maxWorkerNameLength'), 2 * static::UI_SAFE_LENGTH); foreach ($info as $value) { if (!$readProcessStatus) { $statusStr .= $value . "\n"; @@ -1188,8 +1164,8 @@ protected static function formatProcessStatusData(): string foreach ($workerInfo as $pid => $info) { if (!isset($dataWaitingSort[$pid])) { $statusStr .= "$pid\t" . str_pad('N/A', 7) . " " - . str_pad($info['listen'], static::$maxSocketNameLength) . " " - . str_pad((string)$info['name'], static::$maxWorkerNameLength) . " " + . str_pad($info['listen'], static::getUiColumnLength('maxSocketNameLength')) . " " + . str_pad((string)$info['name'], static::getUiColumnLength('maxWorkerNameLength')) . " " . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; continue; @@ -1204,7 +1180,7 @@ protected static function formatProcessStatusData(): string $statusStr .= $dataWaitingSort[$pid] . " " . str_pad((string)$qps, 6) . " [idle]\n"; } $totalRequestCache = $currentTotalRequest; - $statusStr .= "----------------------------------------------PROCESS STATUS---------------------------------------------------\n"; + $statusStr .= "---------------------------------------------------PROCESS STATUS--------------------------------------------------------\n"; $statusStr .= "Summary\t" . str_pad($totalMemory . 'M', 7) . " " . str_pad('-', $maxLen1) . " " . str_pad('-', $maxLen2) . " " @@ -1379,16 +1355,6 @@ protected static function saveMasterPid(): void } } - /** - * Get event loop name. - * - * @return class-string - */ - protected static function getEventLoopName(): string - { - return static::$eventLoopClass; - } - /** * Get all pids of worker processes. * @@ -1431,12 +1397,7 @@ protected static function forkWorkersForLinux(): void if (empty($worker->name)) { $worker->name = $worker->getSocketName(); } - $workerNameLength = strlen($worker->name); - if (static::$maxWorkerNameLength < $workerNameLength) { - static::$maxWorkerNameLength = $workerNameLength; - } } - while (count(static::$pidMap[$worker->workerId]) < $worker->count) { static::forkOneWorkerForLinux($worker); } @@ -1473,7 +1434,7 @@ protected static function forkWorkersForWindows(): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = static::getEventLoopName(); + $eventLoopClass = $worker->eventLoop ?? static::$eventLoopClass; static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); @@ -1613,7 +1574,7 @@ protected static function forkOneWorkerForLinux(self $worker): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = static::getEventLoopName(); + $eventLoopClass = $worker->eventLoop ?? static::$eventLoopClass; static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); @@ -2013,40 +1974,41 @@ protected static function writeStatisticsToStatusFile(): void file_put_contents(static::$statisticsFile, (static::$daemonize ? "Start worker in DAEMON mode." : "Start worker in DEBUG mode.") . "\n", FILE_APPEND); file_put_contents(static::$statisticsFile, - "----------------------------------------------GLOBAL STATUS----------------------------------------------------\n", FILE_APPEND); + "---------------------------------------------------GLOBAL STATUS---------------------------------------------------------\n", FILE_APPEND); file_put_contents(static::$statisticsFile, 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); file_put_contents(static::$statisticsFile, 'start time:' . date('Y-m-d H:i:s', - static::$globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor(((time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) . " hours \n", - FILE_APPEND); - $loadStr = 'load average: ' . implode(", ", $loadavg); - file_put_contents(static::$statisticsFile, - str_pad($loadStr, 33) . 'event-loop:' . static::getEventLoopName() . "\n", FILE_APPEND); + static::$globalStatistics['start_timestamp']) + . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) + . ' days ' . floor(((time() - static::$globalStatistics['start_timestamp']) % (24 * 60 * 60)) / (60 * 60)) + . " hours " . 'load average: ' . implode(", ", $loadavg) . "\n", FILE_APPEND); file_put_contents(static::$statisticsFile, - count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", + count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); file_put_contents(static::$statisticsFile, - str_pad('worker_name', static::$maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); + str_pad('name', static::getUiColumnLength('maxWorkerNameLength')) . " event exit_status exit_count\n", FILE_APPEND); foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { file_put_contents(static::$statisticsFile, - str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad((string)$workerExitStatus, - 16) . " $workerExitCount\n", FILE_APPEND); + str_pad($worker->name, static::getUiColumnLength('maxWorkerNameLength')) . " " . + str_pad($worker->context->eventLoopName, 12) . " " . + str_pad((string)$workerExitStatus, 16) . str_pad((string)$workerExitCount, 16) . "\n", FILE_APPEND); } } else { file_put_contents(static::$statisticsFile, - str_pad($worker->name, static::$maxWorkerNameLength) . " " . str_pad('0', 16) . " 0\n", - FILE_APPEND); + str_pad($worker->name, static::getUiColumnLength('maxWorkerNameLength')) . " " . + str_pad($worker->context->eventLoopName, 12) . " " . + str_pad('0', 16) . str_pad('0', 16) . "\n", FILE_APPEND); } } file_put_contents(static::$statisticsFile, - "----------------------------------------------PROCESS STATUS---------------------------------------------------\n", + "---------------------------------------------------PROCESS STATUS--------------------------------------------------------\n", FILE_APPEND); file_put_contents(static::$statisticsFile, - "pid\tmemory " . str_pad('listening', static::$maxSocketNameLength) . " " . str_pad('worker_name', - static::$maxWorkerNameLength) . " connections " . str_pad('send_fail', 9) . " " + "pid\tmemory " . str_pad('listening', static::getUiColumnLength('maxSocketNameLength')) . " " . str_pad('name', + static::getUiColumnLength('maxWorkerNameLength')) . " connections " . str_pad('send_fail', 9) . " " . str_pad('timers', 8) . str_pad('total_request', 13) . " qps status\n", FILE_APPEND); foreach (static::getAllWorkerPids() as $workerPid) { @@ -2062,8 +2024,8 @@ protected static function writeStatisticsToStatusFile(): void /** @var static $worker */ $worker = current(static::$workers); $workerStatusStr = posix_getpid() . "\t" . str_pad(round(memory_get_usage() / (1024 * 1024), 2) . "M", 7) - . " " . str_pad($worker->getSocketName(), static::$maxSocketNameLength) . " " - . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::$maxWorkerNameLength) + . " " . str_pad($worker->getSocketName(), static::getUiColumnLength('maxSocketNameLength')) . " " + . str_pad(($worker->name === $worker->getSocketName() ? 'none' : $worker->name), static::getUiColumnLength('maxWorkerNameLength')) . " "; $workerStatusStr .= str_pad((string)ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad((string)ConnectionInterface::$statistics['send_fail'], 9) @@ -2072,6 +2034,17 @@ protected static function writeStatisticsToStatusFile(): void file_put_contents(static::$statisticsFile, $workerStatusStr, FILE_APPEND); } + /** + * Get UI column length + * + * @param $name + * @return int + */ + protected static function getUiColumnLength($name): int + { + return static::$uiLengthData[$name] ?? 0; + } + /** * Write statistics data to disk. * From 2fe3ce762c52801c06a4e5bee7962d3cdb2cfff2 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 5 Nov 2024 21:24:02 +0800 Subject: [PATCH 1048/1216] Optimizations --- src/Worker.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index ae38954b0..ade130db8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -259,15 +259,17 @@ class Worker /** * Is worker stopping ? + * * @var bool */ public bool $stopping = false; /** + * EventLoop class. * - * @var class-string + * @var ?string */ - public string $eventLoop; + public ?string $eventLoop = null; /** * Daemonize. @@ -750,7 +752,7 @@ protected static function initWorkers(): void $worker->context->statusSocket = $worker->getSocketName(); // Event-loop name. - $eventLoopName = $worker->eventLoop ?? static::$eventLoopClass; + $eventLoopName = $worker->eventLoop ?: static::$eventLoopClass; $worker->context->eventLoopName = str_starts_with($eventLoopName, 'Workerman\\Events\\') ? strtolower(substr($eventLoopName, 17)) : $eventLoopName; // Status name. @@ -1434,7 +1436,7 @@ protected static function forkWorkersForWindows(): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = $worker->eventLoop ?? static::$eventLoopClass; + $eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); @@ -1574,7 +1576,7 @@ protected static function forkOneWorkerForLinux(self $worker): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = $worker->eventLoop ?? static::$eventLoopClass; + $eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; static::$globalEvent = new $eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); From 18955a1aca337daead7652f9a910be1ca9a83f04 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 16:42:36 +0800 Subject: [PATCH 1049/1216] Fix Swoole driver not releasing callbacks. --- src/Events/Swoole.php | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 91943abc1..847bcb354 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -105,14 +105,14 @@ public function onReadable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ); + Event::add($stream, fn () => $this->callRead($fd), null, SWOOLE_EVENT_READ); } elseif (isset($this->writeEvents[$fd])) { - Event::set($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); + Event::set($stream, fn () => $this->callRead($fd), null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE); } else { - Event::set($stream, fn () => $this->safeCall($func, [$stream]), null, SWOOLE_EVENT_READ); + Event::set($stream, fn () => $this->callRead($fd), null, SWOOLE_EVENT_READ); } - $this->readEvents[$fd] = $stream; + $this->readEvents[$fd] = [$func, [$stream]]; } /** @@ -140,14 +140,14 @@ public function onWritable($stream, callable $func): void { $fd = (int)$stream; if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { - Event::add($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE); + Event::add($stream, null, fn () => $this->callWrite($fd), SWOOLE_EVENT_WRITE); } elseif (isset($this->readEvents[$fd])) { - Event::set($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); + Event::set($stream, null, fn () => $this->callWrite($func, [$stream]), SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); } else { - Event::set($stream, null, fn () => $this->safeCall($func, [$stream]), SWOOLE_EVENT_WRITE); + Event::set($stream, null, fn () => $this->callWrite($func, [$stream]), SWOOLE_EVENT_WRITE); } - $this->writeEvents[$fd] = $stream; + $this->writeEvents[$fd] = [$func, [$stream]]; } /** @@ -237,6 +237,28 @@ public function setErrorHandler(callable $errorHandler): void $this->errorHandler = $errorHandler; } + /** + * @param $fd + * @return void + */ + private function callRead($fd) + { + if (isset($this->readEvents[$fd])) { + $this->safeCall($this->readEvents[$fd][0], $this->readEvents[$fd][1]); + } + } + + /** + * @param $fd + * @return void + */ + private function callWrite($fd) + { + if (isset($this->writeEvents[$fd])) { + $this->safeCall($this->writeEvents[$fd][0], $this->writeEvents[$fd][1]); + } + } + /** * @param callable $func * @param array $args From 25a820205c682a9635b0417ceaeb70f134aaecf9 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 16:42:54 +0800 Subject: [PATCH 1050/1216] Optimizations --- src/Worker.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index ade130db8..f63244ab4 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1905,9 +1905,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void array_walk($workers, static fn (Worker $worker) => $worker->stop()); if (!static::getGracefulStop() || ConnectionInterface::$statistics['connection_count'] <= 0) { - static::$workers = []; static::$globalEvent?->stop(); - try { // Ignore Swoole ExitException: Swoole exit. exit($code); @@ -2445,12 +2443,6 @@ public function stop(): void $connection->close(); } } - // Remove worker. - foreach (static::$workers as $key => $one_worker) { - if ($one_worker->workerId === $this->workerId) { - unset(static::$workers[$key]); - } - } // Clear callback. $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null; $this->stopping = true; From 842c3534918a230a9748694306d19ed898a2dddf Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 16:49:08 +0800 Subject: [PATCH 1051/1216] Fix swoole event --- src/Events/Swoole.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 847bcb354..80e3c56b3 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -142,9 +142,9 @@ public function onWritable($stream, callable $func): void if (!isset($this->readEvents[$fd]) && !isset($this->writeEvents[$fd])) { Event::add($stream, null, fn () => $this->callWrite($fd), SWOOLE_EVENT_WRITE); } elseif (isset($this->readEvents[$fd])) { - Event::set($stream, null, fn () => $this->callWrite($func, [$stream]), SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); + Event::set($stream, null, fn () => $this->callWrite($fd), SWOOLE_EVENT_WRITE | SWOOLE_EVENT_READ); } else { - Event::set($stream, null, fn () => $this->callWrite($func, [$stream]), SWOOLE_EVENT_WRITE); + Event::set($stream, null, fn () =>$this->callWrite($fd), SWOOLE_EVENT_WRITE); } $this->writeEvents[$fd] = [$func, [$stream]]; From f49f3d88b2b3d8656d9831e54ab2f8789934d624 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 16:54:07 +0800 Subject: [PATCH 1052/1216] Fix type comments --- src/Events/Swoole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 80e3c56b3..ff59d63d7 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -32,7 +32,7 @@ final class Swoole implements EventInterface /** * All listeners for read event. * - * @var array + * @var array */ private array $readEvents = []; From 124305dae476beb62a2f90275d6264c2709f6e12 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 17:46:30 +0800 Subject: [PATCH 1053/1216] Phpstan --- src/Connection/AsyncUdpConnection.php | 8 ++------ src/Connection/TcpConnection.php | 10 +++------- src/Connection/UdpConnection.php | 4 +--- src/Events/Swoole.php | 2 +- src/Protocols/Http.php | 1 + src/Protocols/Http/Session.php | 6 ++---- src/Worker.php | 4 +--- 7 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index d17fa5b31..0ffd3a674 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -108,9 +108,7 @@ public function baseRead($socket): void if ($this->onMessage) { if ($this->protocol) { - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; - $recvBuffer = $parser::decode($recvBuffer, $this); + $recvBuffer = $this->protocol::decode($recvBuffer, $this); } ++ConnectionInterface::$statistics['total_request']; try { @@ -157,9 +155,7 @@ public function close(mixed $data = null, bool $raw = false): void public function send(mixed $sendBuffer, bool $raw = false): bool|null { if (false === $raw && $this->protocol) { - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; - $sendBuffer = $parser::encode($sendBuffer, $this); + $sendBuffer = $this->protocol::encode($sendBuffer, $this); if ($sendBuffer === '') { return null; } diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index ba7539c75..b0bec4794 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -270,7 +270,7 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable /** * Cache. * - * @var bool. + * @var bool */ protected static bool $enableCache = true; @@ -409,10 +409,8 @@ public function send(mixed $sendBuffer, bool $raw = false): bool|null // Try to call protocol::encode($sendBuffer) before sending. if (false === $raw && $this->protocol !== null) { - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; try { - $sendBuffer = $parser::encode($sendBuffer, $this); + $sendBuffer = $this->protocol::encode($sendBuffer, $this); } catch(Throwable $e) { $this->error($e); } @@ -730,9 +728,7 @@ public function baseRead($socket, bool $checkEof = true): void $this->currentPackageLength = 0; try { // Decode request buffer before Emitting onMessage callback. - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; - $request = $parser::decode($oneRequestBuffer, $this); + $request = $this->protocol::decode($oneRequestBuffer, $this); if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { ($this->onMessage)($this, $request); if ($request instanceof Request) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index dac804107..7d301ffdf 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -65,9 +65,7 @@ public function __construct( public function send(mixed $sendBuffer, bool $raw = false): bool|null { if (false === $raw && $this->protocol) { - /** @var ProtocolInterface $parser */ - $parser = $this->protocol; - $sendBuffer = $parser::encode($sendBuffer, $this); + $sendBuffer = $this->protocol::encode($sendBuffer, $this); if ($sendBuffer === '') { return null; } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index ff59d63d7..6862a2ce5 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -39,7 +39,7 @@ final class Swoole implements EventInterface /** * All listeners for write event. * - * @var array + * @var array */ private array $writeEvents = []; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 1afaba1c2..4bf4381a8 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -241,6 +241,7 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o // Read file content from disk piece by piece and send to client. $doWrite = function () use ($connection, $handler, $length, $offsetEnd) { // Send buffer not full. + // @phpstan-ignore-next-line while ($connection->context->bufferFull === false) { // Read from disk. $size = 1024 * 1024; diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 5d92f0b86..6554e5f8a 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -262,10 +262,8 @@ public function forget(array|string $name): void $this->delete($name); return; } - if (is_array($name)) { - foreach ($name as $key) { - unset($this->data[$key]); - } + foreach ($name as $key) { + unset($this->data[$key]); } $this->needSave = true; } diff --git a/src/Worker.php b/src/Worker.php index f63244ab4..e802be1d1 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -876,7 +876,7 @@ protected static function displayUI(): void $propValue = (string)($worker->$prop ?? $worker->context->$prop); $key = 'max' . ucfirst(strtolower($columnName)) . 'NameLength'; preg_match_all("/(|<\/n>||<\/w>||<\/g>)/i", $propValue, $matches); - $placeHolderLength = !empty($matches) ? strlen(implode('', $matches[0])) : 0; + $placeHolderLength = !empty($matches[0]) ? strlen(implode('', $matches[0])) : 0; $content .= str_pad($propValue, static::getUiColumnLength($key) + static::UI_SAFE_LENGTH + $placeHolderLength); } $content && static::safeEcho($content . PHP_EOL); @@ -2509,9 +2509,7 @@ protected function acceptUdpConnection(mixed $socket): void if ($messageCallback) { try { if ($this->protocol !== null) { - /** @var ProtocolInterface $parser */ $parser = $this->protocol; - // @phpstan-ignore-next-line Left side of && is always true. if ($parser && method_exists($parser, 'input')) { while ($recvBuffer !== '') { $len = $parser::input($recvBuffer, $connection); From c061242779b25b0d75c529f3577dc8e5d5120daa Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 18:19:23 +0800 Subject: [PATCH 1054/1216] Optimizaitons --- src/Events/Swoole.php | 4 +++- src/Protocols/Http.php | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 6862a2ce5..f2daaacbb 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -212,10 +212,12 @@ public function run(): void */ public function stop(): void { - // cancel all coroutines before Event::exit + // Cancel all coroutines before Event::exit foreach (Coroutine::listCoroutines() as $coroutine) { Coroutine::cancel($coroutine); } + // Wait for coroutines to exit + usleep(20000); Event::exit(); } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 4bf4381a8..1afaba1c2 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -241,7 +241,6 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o // Read file content from disk piece by piece and send to client. $doWrite = function () use ($connection, $handler, $length, $offsetEnd) { // Send buffer not full. - // @phpstan-ignore-next-line while ($connection->context->bufferFull === false) { // Read from disk. $size = 1024 * 1024; From 7546e0699a931ca92721b8d15d190b11384b9c9f Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 7 Nov 2024 12:51:29 +0100 Subject: [PATCH 1055/1216] Update composer.json to use Mockery 1.6.x --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4afb589e0..43f44584d 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ }, "require-dev": { "pestphp/pest": "2.x-dev", - "mockery/mockery": "2.0.x-dev", + "mockery/mockery": "^1.6", "guzzlehttp/guzzle": "^7.0", "phpstan/phpstan": "1.11.x-dev" }, From 02c1ab6180922fc28224711406723318d608b866 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 7 Nov 2024 12:55:49 +0100 Subject: [PATCH 1056/1216] Update test.yml to show composer color It's easier to check the files installed. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ca57a9a8..fcaa4346a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis run: composer analyze From 177dacfd77a6a9be33448aba497bcac0d5c737a1 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 7 Nov 2024 13:12:01 +0100 Subject: [PATCH 1057/1216] Update test.yml to actions/checkout@v4 It's deprecated in github actions. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fcaa4346a..e9dd4f9eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 From 9d53a73aa107d07db17f3ddeb85cb1bccbe56469 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Thu, 7 Nov 2024 13:15:14 +0100 Subject: [PATCH 1058/1216] Update test.yml with nick-fields/retry@v3 Upgrades action to node 20 to fix warnings --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e9dd4f9eb..ca86088cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: coverage: xdebug - name: Install dependencies - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 with: timeout_minutes: 5 max_attempts: 5 From ca4bea1c53df5d3b7002375faacf4c03f06fe8e1 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 21:08:34 +0800 Subject: [PATCH 1059/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index e802be1d1..16091a0ab 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.2'; + final public const VERSION = '5.0.0'; /** * Status starting. From cae10bc211932b5d44147f3b5d2aa04160b7a838 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 7 Nov 2024 21:23:55 +0800 Subject: [PATCH 1060/1216] Update Swoole.php --- src/Events/Swoole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index f2daaacbb..815376d5b 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -217,7 +217,7 @@ public function stop(): void Coroutine::cancel($coroutine); } // Wait for coroutines to exit - usleep(20000); + usleep(200000); Event::exit(); } From cf35f9ce1f2d54b0df10f021ea1c6deba8e17d21 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Nov 2024 09:47:49 +0800 Subject: [PATCH 1061/1216] RFC3875 compliance for Workerman version #1066 --- src/Worker.php | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 16091a0ab..1f6d95249 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -574,6 +574,11 @@ protected static function checkSapiEnv(): void } } + /** + * Init stdout. + * + * @return void + */ private static function initStdOut(): void { $defaultStream = fn () => defined('STDOUT') ? STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); @@ -624,6 +629,9 @@ protected static function init(): void return true; }); + // $_SERVER. + $_SERVER['SERVER_SOFTWARE'] = 'Workerman/' . static::VERSION; + // Start file. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); static::$startFile ??= end($backtrace)['file']; @@ -842,17 +850,19 @@ protected static function displayUI(): void if (in_array('-q', $tmpArgv)) { return; } - $jitStatus = function_exists('opcache_get_status') && (opcache_get_status()['jit']['on'] ?? false) === true ? 'on' : 'off'; + + + $lineVersion = static::getVersionLine(); + // For windows if (DIRECTORY_SEPARATOR !== '/') { static::safeEcho("---------------------------------------------- WORKERMAN -----------------------------------------------\r\n"); - static::safeEcho('Workerman version:'. static::VERSION. ' PHP version:'. PHP_VERSION . " (Jit $jitStatus)\r\n"); + static::safeEcho($lineVersion); static::safeEcho("----------------------------------------------- WORKERS ------------------------------------------------\r\n"); static::safeEcho("worker listen processes status\r\n"); return; } - //show version - $lineVersion = 'Workerman version:' . static::VERSION . str_pad('PHP version:', 16, ' ', STR_PAD_LEFT) . PHP_VERSION . " (Jit $jitStatus)" . PHP_EOL; + // For unix !defined('LINE_VERSION_LENGTH') && define('LINE_VERSION_LENGTH', strlen($lineVersion)); $totalLength = static::getSingleLineTotalLength(); $lineOne = '' . str_pad(' WORKERMAN ', $totalLength + strlen(''), '-', STR_PAD_BOTH) . '' . PHP_EOL; @@ -895,6 +905,19 @@ protected static function displayUI(): void } } + /** + * @return string + */ + protected static function getVersionLine(): string + { + //Show version + $jitStatus = function_exists('opcache_get_status') && (opcache_get_status()['jit']['on'] ?? false) === true ? 'on' : 'off'; + $version = str_pad('Workerman/' . static::VERSION, 24); + $version .= str_pad('PHP/' . PHP_VERSION . ' (Jit ' . $jitStatus . ')', 30); + $version .= php_uname('s') . '/' . php_uname('r') . PHP_EOL; + return $version; + } + /** * Get UI columns to be shown in terminal * @@ -1975,8 +1998,7 @@ protected static function writeStatisticsToStatusFile(): void (static::$daemonize ? "Start worker in DAEMON mode." : "Start worker in DEBUG mode.") . "\n", FILE_APPEND); file_put_contents(static::$statisticsFile, "---------------------------------------------------GLOBAL STATUS---------------------------------------------------------\n", FILE_APPEND); - file_put_contents(static::$statisticsFile, - 'Workerman version:' . static::VERSION . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); + file_put_contents(static::$statisticsFile, static::getVersionLine(), FILE_APPEND); file_put_contents(static::$statisticsFile, 'start time:' . date('Y-m-d H:i:s', static::$globalStatistics['start_timestamp']) . ' run ' . floor((time() - static::$globalStatistics['start_timestamp']) / (24 * 60 * 60)) From 1f955a63a669b8f920a1d04fec1de48de61e0d01 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Nov 2024 10:28:29 +0800 Subject: [PATCH 1062/1216] Fix UI --- src/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 1f6d95249..f4a07bfb0 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1189,8 +1189,8 @@ protected static function formatProcessStatusData(): string foreach ($workerInfo as $pid => $info) { if (!isset($dataWaitingSort[$pid])) { $statusStr .= "$pid\t" . str_pad('N/A', 7) . " " - . str_pad($info['listen'], static::getUiColumnLength('maxSocketNameLength')) . " " - . str_pad((string)$info['name'], static::getUiColumnLength('maxWorkerNameLength')) . " " + . str_pad($info['listen'], $maxLen1) . " " + . str_pad((string)$info['name'], $maxLen2) . " " . str_pad('N/A', 11) . " " . str_pad('N/A', 9) . " " . str_pad('N/A', 7) . " " . str_pad('N/A', 13) . " N/A [busy] \n"; continue; From 5101b082e050bfb5957c396c53eb411f8deb8c62 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Nov 2024 15:42:20 +0800 Subject: [PATCH 1063/1216] Check disable_functions --- src/Worker.php | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index f4a07bfb0..fdd81e477 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -570,7 +570,53 @@ protected static function checkSapiEnv(): void { // Only for cli and micro. if (!in_array(PHP_SAPI, ['cli', 'micro'])) { - exit("Only run in command line mode\n"); + exit("Only run in command line mode" . PHP_EOL); + } + // Check pcntl and posix extension for unix. + if (DIRECTORY_SEPARATOR === '/') { + foreach (['pcntl', 'posix'] as $name) { + if (!extension_loaded($name)) { + exit("Please install $name extension" . PHP_EOL); + } + } + } + // Check disable functions. + $disabledFunctions = explode(',', ini_get('disable_functions')); + $disabledFunctions = array_map('trim', $disabledFunctions); + $functionsToCheck = [ + 'stream_socket_server', + 'stream_socket_accept', + 'stream_socket_client', + 'pcntl_signal_dispatch', + 'pcntl_signal', + 'pcntl_alarm', + 'pcntl_fork', + 'pcntl_wait', + 'posix_getuid', + 'posix_getpwuid', + 'posix_kill', + 'posix_setsid', + 'posix_getpid', + 'posix_getpwnam', + 'posix_getgrnam', + 'posix_getgid', + 'posix_setgid', + 'posix_initgroups', + 'posix_setuid', + 'posix_isatty', + 'proc_open', + 'proc_get_status', + 'proc_close', + 'shell_exec', + 'exec', + 'putenv', + 'getenv', + ]; + $disabled = array_intersect($functionsToCheck, $disabledFunctions); + if (!empty($disabled)) { + $iniFilePath = (string)php_ini_loaded_file(); + exit('Notice: '. implode(',', $disabled) . " are disabled by disable_functions. " . PHP_EOL + . "Please remove them from disable_functions in $iniFilePath" . PHP_EOL); } } From 0d75a171538fde32ab28859710c3c37ecbc7b520 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 8 Nov 2024 23:28:17 +0800 Subject: [PATCH 1064/1216] Fix session # --- src/Connection/TcpConnection.php | 3 ++- src/Protocols/Http.php | 4 ++-- src/Protocols/Http/Request.php | 40 +++++++++++++++++++++++--------- src/Protocols/Http/Session.php | 12 ---------- src/Worker.php | 2 +- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index b0bec4794..2ade13881 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -662,7 +662,7 @@ public function baseRead($socket, bool $checkEof = true): void } catch (Throwable $e) { $this->error($e); } - $request->properties = []; + $request->destroy(); $requests[$buffer] = clone $request; return; } @@ -732,6 +732,7 @@ public function baseRead($socket, bool $checkEof = true): void if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { ($this->onMessage)($this, $request); if ($request instanceof Request) { + $request->destroy(); $requests[$oneRequestBuffer] = clone $request; } else { $requests[$oneRequestBuffer] = $request; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 1afaba1c2..4623f865b 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -133,7 +133,7 @@ public static function decode(string $buffer, TcpConnection $connection): Reques $request = $requests[$buffer]; $request->connection = $connection; $connection->request = $request; - $request->properties = []; + $request->destroy(); return $request; } $request = new static::$requestClass($buffer); @@ -160,7 +160,7 @@ public static function encode(mixed $response, TcpConnection $connection): strin { if (isset($connection->request)) { $request = $connection->request; - $request->session = $request->connection = $connection->request = null; + $request->connection = $connection->request = null; } if (!is_object($response)) { diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index f3c877370..72b31e5b9 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -107,11 +107,11 @@ class Request implements Stringable protected bool $isSafe = true; /** - * Session id. + * Context. * - * @var mixed + * @var array */ - protected mixed $sid; + public array $context = []; /** * Request constructor. @@ -309,7 +309,7 @@ public function queryString(): string */ public function session(): Session { - return $this->session ??= new Session($this->sessionId()); + return $this->context['session'] ??= new Session($this->sessionId()); } /** @@ -322,12 +322,13 @@ public function session(): Session public function sessionId(?string $sessionId = null): string { if ($sessionId) { - unset($this->sid); + unset($this->context['sid']); } - if (!isset($this->sid)) { + if (!isset($this->context['sid'])) { $sessionName = Session::$name; $sid = $sessionId ? '' : $this->cookie($sessionName); - if ($sid === '' || $sid === null) { + $sid = $this->isValidSessionId($sid) ? $sid : ''; + if ($sid === '') { if (!$this->connection) { throw new RuntimeException('Request->session() fail, header already send'); } @@ -335,9 +336,20 @@ public function sessionId(?string $sessionId = null): string $cookieParams = Session::getCookieParams(); $this->setSidCookie($sessionName, $sid, $cookieParams); } - $this->sid = $sid; + $this->context['sid'] = $sid; } - return $this->sid; + return $this->context['sid']; + } + + /** + * Check if session id is valid. + * + * @param mixed $sessionId + * @return bool + */ + public function isValidSessionId(mixed $sessionId): bool + { + return is_string($sessionId) && preg_match('/^[a-zA-Z0-9"]+$/', $sessionId); } /** @@ -738,12 +750,18 @@ public function __wakeup(): void } /** - * __destruct. + * Destroy. * * @return void */ - public function __destruct() + public function destroy(): void { + if ($this->context) { + $this->context = []; + } + if ($this->properties) { + $this->properties = []; + } if (isset($this->data['files']) && $this->isSafe) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 6554e5f8a..7bdd53371 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -163,7 +163,6 @@ class Session */ public function __construct(string $sessionId) { - static::checkSessionId($sessionId); if (static::$handler === null) { static::initHandler(); } @@ -449,17 +448,6 @@ public function __destruct() } } - /** - * Check session id. - * - * @param string $sessionId - */ - protected static function checkSessionId(string $sessionId): void - { - if (!preg_match('/^[a-zA-Z0-9"]+$/', $sessionId)) { - throw new RuntimeException("session_id $sessionId is invalid"); - } - } } // Init session. diff --git a/src/Worker.php b/src/Worker.php index fdd81e477..0485db7a0 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0'; + final public const VERSION = '5.0.0-RC3'; /** * Status starting. From 91c4207e14a840876b08708eebb3c9954722715b Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Fri, 8 Nov 2024 18:35:08 +0100 Subject: [PATCH 1065/1216] Update Worker.php fix nullable for PHP8.4 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 0485db7a0..f145d9316 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2281,7 +2281,7 @@ public static function safeEcho(string $msg, bool $decorated = false): void * @param string|null $socketName * @param array $socketContext */ - public function __construct(string $socketName = null, array $socketContext = []) + public function __construct(?string $socketName = null, array $socketContext = []) { // Save all worker instances. $this->workerId = spl_object_hash($this); From fd270bf8ff9ed8f8b97d397b9429f32fdffa79af Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 9 Nov 2024 18:41:43 +0800 Subject: [PATCH 1066/1216] Add checkPortAvailable and move __construct to front #1069 --- src/Worker.php | 114 +++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index f145d9316..110c0db8a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -534,6 +534,29 @@ class Worker */ protected ?string $workerId = null; + /** + * Constructor. + * + * @param string|null $socketName + * @param array $socketContext + */ + public function __construct(?string $socketName = null, array $socketContext = []) + { + // Save all worker instances. + $this->workerId = spl_object_hash($this); + $this->context = new stdClass(); + static::$workers[$this->workerId] = $this; + static::$pidMap[$this->workerId] = []; + + // Context for socket. + if ($socketName) { + $this->socketName = $socketName; + $socketContext['socket']['backlog'] ??= static::DEFAULT_BACKLOG; + $this->socketContext = stream_context_create($socketContext); + } + + } + /** * Run all worker instances. * @@ -543,9 +566,10 @@ public static function runAll(): void { try { static::checkSapiEnv(); - self::initStdOut(); + static::initStdOut(); static::init(); static::parseCommand(); + static::checkPortAvailable(); static::lock(); static::daemonize(); static::initWorkers(); @@ -625,7 +649,7 @@ protected static function checkSapiEnv(): void * * @return void */ - private static function initStdOut(): void + protected static function initStdOut(): void { $defaultStream = fn () => defined('STDOUT') ? STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); static::$outputStream ??= $defaultStream(); //@phpstan-ignore-line @@ -2021,6 +2045,7 @@ public static function getGracefulStop(): bool } /** + * * Write statistics data to disk. * * @return void @@ -2275,51 +2300,6 @@ public static function safeEcho(string $msg, bool $decorated = false): void restore_error_handler(); } - /** - * Constructor. - * - * @param string|null $socketName - * @param array $socketContext - */ - public function __construct(?string $socketName = null, array $socketContext = []) - { - // Save all worker instances. - $this->workerId = spl_object_hash($this); - $this->context = new stdClass(); - static::$workers[$this->workerId] = $this; - static::$pidMap[$this->workerId] = []; - - // Context for socket. - if ($socketName) { - $this->socketName = $socketName; - $socketContext['socket']['backlog'] ??= static::DEFAULT_BACKLOG; - $this->socketContext = stream_context_create($socketContext); - } - - // Try to turn reusePort on. - /*if (\DIRECTORY_SEPARATOR === '/' // if linux - && $socketName - && \version_compare(php_uname('r'), '3.9', 'ge') // if kernel >=3.9 - && \strtolower(\php_uname('s')) !== 'darwin' // if not Mac OS - && strpos($socketName,'unix') !== 0 // if not unix socket - && strpos($socketName,'udp') !== 0) { // if not udp socket - - $address = \parse_url($socketName); - if (isset($address['host']) && isset($address['port'])) { - try { - \set_error_handler(static fn (): bool => true); - // If address not in use, turn reusePort on automatically. - $server = stream_socket_server("tcp://{$address['host']}:{$address['port']}"); - if ($server) { - $this->reusePort = true; - fclose($server); - } - \restore_error_handler(); - } catch (\Throwable $e) {} - } - }*/ - } - /** * Listen. */ @@ -2335,17 +2315,17 @@ public function listen(): void // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; - $errno = 0; - $errmsg = ''; + $errNo = 0; + $errMsg = ''; // SO_REUSEPORT. if ($this->reusePort) { stream_context_set_option($this->socketContext, 'socket', 'so_reuseport', 1); } // Create an Internet or Unix domain server socket. - $this->mainSocket = stream_socket_server($localSocket, $errno, $errmsg, $flags, $this->socketContext); + $this->mainSocket = stream_socket_server($localSocket, $errNo, $errMsg, $flags, $this->socketContext); if (!$this->mainSocket) { - throw new RuntimeException($errmsg); + throw new RuntimeException($errMsg); } if ($this->transport === 'ssl') { @@ -2392,6 +2372,38 @@ public function unlisten(): void } } + /** + * Check port available. + * + * @return void + */ + protected static function checkPortAvailable(): void + { + foreach (static::$workers as $worker) { + $socketName = $worker->getSocketName(); + if (DIRECTORY_SEPARATOR === '/' // if linux + && static::$status === static::STATUS_STARTING // only for starting status + && $worker->transport === 'tcp' // if tcp socket + && !str_starts_with($socketName, 'unix') // if not unix socket + && !str_starts_with($socketName, 'udp')) { // if not udp socket + + $address = parse_url($socketName); + if (isset($address['host']) && isset($address['port'])) { + $address = "tcp://{$address['host']}:{$address['port']}"; + $server = null; + set_error_handler(function ($code, $msg) { + throw new RuntimeException($msg); + }); + $server = stream_socket_server($address, $code, $msg); + if ($server) { + fclose($server); + } + restore_error_handler(); + } + } + } + } + /** * Parse local socket address. */ From b103862cd74ae21816c1fb442dd65db3f2c3aefe Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 9 Nov 2024 22:34:04 +0800 Subject: [PATCH 1067/1216] TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT option --- src/Connection/AsyncTcpConnection.php | 11 ++++++++--- src/Connection/TcpConnection.php | 6 ++++++ src/Protocols/Http/Request.php | 7 ------- src/Worker.php | 10 ++++++++++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 3757003a2..4ef415380 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -385,9 +385,14 @@ public function checkConnection(): void } // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { - $rawSocket = socket_import_stream($this->socket); - socket_set_option($rawSocket, SOL_SOCKET, SO_KEEPALIVE, 1); - socket_set_option($rawSocket, SOL_TCP, TCP_NODELAY, 1); + $socket = socket_import_stream($this->socket); + socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); + socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + if (defined('TCP_KEEPIDLE')) { + socket_set_option($socket, SOL_TCP, TCP_KEEPIDLE, static::TCP_KEEPALIVE_INTERVAL); + socket_set_option($socket, SOL_TCP, TCP_KEEPINTVL, static::TCP_KEEPALIVE_INTERVAL); + socket_set_option($socket, SOL_TCP, TCP_KEEPCNT, 1); + } } // SSL handshake. if ($this->transport === 'ssl') { diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 2ade13881..38b9f60db 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -116,6 +116,11 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public const MAX_CACHE_SIZE = 512; + /** + * Tcp keepalive interval. + */ + public const TCP_KEEPALIVE_INTERVAL = 55; + /** * Emitted when socket connection is successfully established. * @@ -1060,6 +1065,7 @@ public function destroy(): void if ($this->worker) { unset($this->worker->connections[$this->realId]); } + $this->worker = null; unset(static::$connections[$this->realId]); } } diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 72b31e5b9..bf338fab2 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -59,13 +59,6 @@ class Request implements Stringable */ public ?TcpConnection $connection = null; - /** - * Session instance. - * - * @var ?Session - */ - public ?Session $session = null; - /** * @var int */ diff --git a/src/Worker.php b/src/Worker.php index 110c0db8a..9ee595440 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -555,6 +555,11 @@ public function __construct(?string $socketName = null, array $socketContext = [ $this->socketContext = stream_context_create($socketContext); } + // Set an empty onMessage callback. + $this->onMessage = function () { + // Empty. + }; + } /** @@ -2346,6 +2351,11 @@ public function listen(): void $socket = socket_import_stream($this->mainSocket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + if (defined('TCP_KEEPIDLE')) { + socket_set_option($socket, SOL_TCP, TCP_KEEPIDLE, TcpConnection::TCP_KEEPALIVE_INTERVAL); + socket_set_option($socket, SOL_TCP, TCP_KEEPINTVL, TcpConnection::TCP_KEEPALIVE_INTERVAL); + socket_set_option($socket, SOL_TCP, TCP_KEEPCNT, 1); + } restore_error_handler(); } From 8c85f4da3cfadcd7f71a582105330ded5e06c67d Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Sat, 9 Nov 2024 19:48:06 +0100 Subject: [PATCH 1068/1216] Optimizations Worker.php Use Null coalescing assignment operator (PHP 7.4) First check if logFile is 'dev/null' and later check if is_file(), so we use one stat less if not necessary. --- src/Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 9ee595440..7c542b6e5 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -713,17 +713,17 @@ protected static function init(): void $startFilePrefix = hash('xxh64', static::$startFile); // Pid file. - static::$pidFile = empty(static::$pidFile) ? sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix) : static::$pidFile; + static::$pidFile ??= sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix); // Status file. - static::$statusFile = empty(static::$statusFile) ? sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix) : static::$statusFile; + static::$statusFile ??= sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix); static::$statisticsFile ??= static::$statusFile; static::$connectionsFile ??= static::$statusFile . '.connection'; // Log file. - static::$logFile = empty(static::$logFile) ? sprintf('%s/workerman.log', dirname(__DIR__, 2)) : static::$logFile; + static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); - if (!is_file(static::$logFile) && static::$logFile !== '/dev/null') { + if (static::$logFile !== '/dev/null' && !is_file(static::$logFile)) { // if /runtime/logs default folder not exists if (!is_dir(dirname(static::$logFile))) { @mkdir(dirname(static::$logFile), 0777, true); From 4cdd1ca631deaaef7d08ea34e50eedf5f44d5549 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 10 Nov 2024 10:08:34 +0800 Subject: [PATCH 1069/1216] Fix phpstan --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 7c542b6e5..89e5d98c6 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2351,7 +2351,7 @@ public function listen(): void $socket = socket_import_stream($this->mainSocket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); - if (defined('TCP_KEEPIDLE')) { + if (PHP_VERSION_ID >= 80200) { socket_set_option($socket, SOL_TCP, TCP_KEEPIDLE, TcpConnection::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPINTVL, TcpConnection::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPCNT, 1); From 18700258b589888d3ace99a1867fe6f30f7a230e Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 16 Nov 2024 20:35:43 +0800 Subject: [PATCH 1070/1216] Fix #1071 --- src/Connection/AsyncTcpConnection.php | 2 +- src/Worker.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 4ef415380..911b1465b 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -388,7 +388,7 @@ public function checkConnection(): void $socket = socket_import_stream($this->socket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); - if (defined('TCP_KEEPIDLE')) { + if (defined('TCP_KEEPIDLE') && defined('TCP_KEEPINTVL') && defined('TCP_KEEPCNT')) { socket_set_option($socket, SOL_TCP, TCP_KEEPIDLE, static::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPINTVL, static::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPCNT, 1); diff --git a/src/Worker.php b/src/Worker.php index 89e5d98c6..396ff2fe6 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2351,7 +2351,7 @@ public function listen(): void $socket = socket_import_stream($this->mainSocket); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); - if (PHP_VERSION_ID >= 80200) { + if (defined('TCP_KEEPIDLE') && defined('TCP_KEEPINTVL') && defined('TCP_KEEPCNT')) { socket_set_option($socket, SOL_TCP, TCP_KEEPIDLE, TcpConnection::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPINTVL, TcpConnection::TCP_KEEPALIVE_INTERVAL); socket_set_option($socket, SOL_TCP, TCP_KEEPCNT, 1); From e48b41054d98948afaa0efebb3269e6c482cd501 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 22 Nov 2024 15:42:37 +0800 Subject: [PATCH 1071/1216] Optimization --- src/Connection/AsyncTcpConnection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 911b1465b..787b7aea8 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -248,6 +248,7 @@ public function connect(): void $this->status = self::STATUS_CONNECTING; $this->connectStartTime = microtime(true); + set_error_handler(fn() => false); if ($this->transport !== 'unix') { if (!$this->remotePort) { $this->remotePort = $this->transport === 'ssl' ? 443 : 80; @@ -274,6 +275,7 @@ public function connect(): void $this->socket = stream_socket_client("$this->transport://$this->remoteAddress", $errno, $err_str, 0, STREAM_CLIENT_ASYNC_CONNECT); } + restore_error_handler(); // If failed attempt to emit onError callback. if (!$this->socket || !is_resource($this->socket)) { $this->emitError(static::CONNECT_FAIL, $err_str); From 517ef664db90946c731819fd09d26b26cfc12d85 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 23 Nov 2024 21:04:08 +0800 Subject: [PATCH 1072/1216] Check __destruct isSafe --- src/Connection/TcpConnection.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 38b9f60db..9f33f093f 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -244,6 +244,13 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public ?Request $request = null; + /** + * Is safe. + * + * @var bool + */ + protected bool $isSafe = true; + /** * Default send buffer size. * @@ -1102,6 +1109,16 @@ public function jsonSerialize(): array ]; } + /** + * __wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->isSafe = false; + } + /** * Destruct. * @@ -1110,6 +1127,9 @@ public function jsonSerialize(): array public function __destruct() { static $mod; + if (!$this->isSafe) { + return; + } self::$statistics['connection_count']--; if (Worker::getGracefulStop()) { $mod ??= ceil((self::$statistics['connection_count'] + 1) / 3); From 91575606eada631d9787a4c8b49f428020795334 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 23 Nov 2024 22:00:46 +0800 Subject: [PATCH 1073/1216] Optimization --- src/Worker.php | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 396ff2fe6..ec844fdbb 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -836,7 +836,7 @@ protected static function initWorkers(): void // Event-loop name. $eventLoopName = $worker->eventLoop ?: static::$eventLoopClass; - $worker->context->eventLoopName = str_starts_with($eventLoopName, 'Workerman\\Events\\') ? strtolower(substr($eventLoopName, 17)) : $eventLoopName; + $worker->context->eventLoopName = strtolower(substr($eventLoopName, strrpos($eventLoopName, '\\') + 1)); // Status name. $worker->context->statusState = ' [OK] '; @@ -1004,7 +1004,7 @@ protected static function getVersionLine(): string public static function getUiColumns(): array { return [ - 'event' => 'eventLoopName', + 'event-loop' => 'eventLoopName', 'proto' => 'transport', 'user' => 'user', 'worker' => 'name', @@ -1048,7 +1048,7 @@ protected static function parseCommand(): void // Check argv; $startFile = basename(static::$startFile); - $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in USER mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; + $usage = "Usage: php yourfile [mode]\nCommands: \nstart\t\tStart worker in DEBUG mode.\n\t\tUse mode -d to start in DAEMON mode.\nstop\t\tStop worker.\n\t\tUse mode -g to stop gracefully.\nrestart\t\tRestart workers.\n\t\tUse mode -d to start in DAEMON mode.\n\t\tUse mode -g to stop gracefully.\nreload\t\tReload codes.\n\t\tUse mode -g to reload gracefully.\nstatus\t\tGet worker status.\n\t\tUse mode -d to show live status.\nconnections\tGet worker connections.\n"; $availableCommands = [ 'start', 'stop', @@ -1081,7 +1081,7 @@ protected static function parseCommand(): void if ($mode === '-d' || static::$daemonize) { $modeStr = 'in DAEMON mode'; } else { - $modeStr = 'in USER mode'; + $modeStr = 'in DEBUG mode'; } } static::log("Workerman[$startFile] $command $modeStr"); @@ -1344,12 +1344,12 @@ protected static function signalHandler(int $signal): void case SIGHUP: case SIGTSTP: static::$gracefulStop = false; - static::stopAll(0, "received signal $signal"); + static::stopAll(0, 'received signal ' . static::getSignalName($signal)); break; // Graceful stop. case SIGQUIT: static::$gracefulStop = true; - static::stopAll(0, "received signal $signal"); + static::stopAll(0, 'received signal ' . static::getSignalName($signal)); break; // Reload. case SIGUSR2: @@ -1372,6 +1372,28 @@ protected static function signalHandler(int $signal): void } } + /** + * Get signal name. + * + * @param int $signal + * @return string + */ + protected static function getSignalName(int $signal): string + { + return match ($signal) { + SIGINT => 'SIGINT', + SIGTERM => 'SIGTERM', + SIGHUP => 'SIGHUP', + SIGTSTP => 'SIGTSTP', + SIGQUIT => 'SIGQUIT', + SIGUSR1 => 'SIGUSR1', + SIGUSR2 => 'SIGUSR2', + SIGIOT => 'SIGIOT', + SIGIO => 'SIGIO', + default => $signal, + }; + } + /** * Run as daemon mode. */ @@ -2084,20 +2106,20 @@ protected static function writeStatisticsToStatusFile(): void count(static::$pidMap) . ' workers ' . count(static::getAllWorkerPids()) . " processes\n", FILE_APPEND); file_put_contents(static::$statisticsFile, - str_pad('name', static::getUiColumnLength('maxWorkerNameLength')) . " event exit_status exit_count\n", FILE_APPEND); + str_pad('name', static::getUiColumnLength('maxWorkerNameLength')) . " event-loop exit_status exit_count\n", FILE_APPEND); foreach (static::$pidMap as $workerId => $workerPidArray) { $worker = static::$workers[$workerId]; if (isset(static::$globalStatistics['worker_exit_info'][$workerId])) { foreach (static::$globalStatistics['worker_exit_info'][$workerId] as $workerExitStatus => $workerExitCount) { file_put_contents(static::$statisticsFile, str_pad($worker->name, static::getUiColumnLength('maxWorkerNameLength')) . " " . - str_pad($worker->context->eventLoopName, 12) . " " . + str_pad($worker->context->eventLoopName, 14) . " " . str_pad((string)$workerExitStatus, 16) . str_pad((string)$workerExitCount, 16) . "\n", FILE_APPEND); } } else { file_put_contents(static::$statisticsFile, str_pad($worker->name, static::getUiColumnLength('maxWorkerNameLength')) . " " . - str_pad($worker->context->eventLoopName, 12) . " " . + str_pad($worker->context->eventLoopName, 14) . " " . str_pad('0', 16) . str_pad('0', 16) . "\n", FILE_APPEND); } } From b03c9ab71f893e03762e5004f7cb07262d437661 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Nov 2024 19:46:23 +0800 Subject: [PATCH 1074/1216] For php8.4 --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index bf338fab2..b8c3049aa 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -201,7 +201,7 @@ public function cookie(?string $name = null, mixed $default = null): mixed * @param string|null $name * @return array|null */ - public function file(?string $name = null) + public function file(?string $name = null): mixed { clearstatcache(); if (!empty($this->data['files'])) { From 44dcfa2eb88a8680861a8d04dfae1219fa88ec88 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Nov 2024 19:48:20 +0800 Subject: [PATCH 1075/1216] 5.0.0-rc.3 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index ec844fdbb..2f4f5849f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-RC3'; + final public const VERSION = '5.0.0-rc.3'; /** * Status starting. From e25dd32e487ccc21308fa4c33c4e8399d7285d0e Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 24 Nov 2024 20:26:22 +0800 Subject: [PATCH 1076/1216] For php8.4 --- src/Protocols/Http/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 2f73e30af..a54c18433 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -335,7 +335,7 @@ public function withFile(string $file, int $offset = 0, int $length = 0): static * @param string $sameSite * @return $this */ - public function cookie(string $name, string $value = '', int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, string $sameSite = ''): static + public function cookie(string $name, string $value = '', ?int $maxAge = null, string $path = '', string $domain = '', bool $secure = false, bool $httpOnly = false, string $sameSite = ''): static { $this->headers['Set-Cookie'][] = $name . '=' . rawurlencode($value) . (empty($domain) ? '' : '; Domain=' . $domain) From ed4b431938cd1e0a6a21ea5cca1efba9795004db Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 6 Dec 2024 15:54:46 +0800 Subject: [PATCH 1077/1216] 5.0.0-rc.4 --- src/Connection/TcpConnection.php | 23 ++++++++++++++++++++++- src/Worker.php | 5 ++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 9f33f093f..b9cbbc2df 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -19,7 +19,10 @@ use RuntimeException; use stdClass; use Throwable; +use Workerman\Events\Ev; +use Workerman\Events\Event; use Workerman\Events\EventInterface; +use Workerman\Events\Select; use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; @@ -349,6 +352,14 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public static array $connections = []; + + /** + * Reuse request. + * + * @var bool + */ + protected static bool $reuseRequest = false; + /** * Status to string. * @@ -675,7 +686,7 @@ public function baseRead($socket, bool $checkEof = true): void $this->error($e); } $request->destroy(); - $requests[$buffer] = clone $request; + $requests[$buffer] = static::$reuseRequest ? $request : clone $request; return; } try { @@ -1087,6 +1098,16 @@ public static function enableCache(bool $value = true): void static::$enableCache = $value; } + /** + * Init. + * + * @return void + */ + public static function init(): void + { + static::$reuseRequest = in_array(get_class(Worker::$globalEvent), [Event::class, Select::class, Ev::class]); + } + /** * Get the json_encode information. * diff --git a/src/Worker.php b/src/Worker.php index 2f4f5849f..3e25d690e 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.3'; + final public const VERSION = '5.0.0-rc.4'; /** * Status starting. @@ -1709,6 +1709,9 @@ protected static function forkOneWorkerForLinux(self $worker): void // Init Timer. Timer::init(static::$globalEvent); + // Init TcpConnection. + TcpConnection::init(); + restore_error_handler(); static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); From 7bd003bc37db42e4f2be739c215f5773eececa38 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 7 Dec 2024 22:18:53 +0800 Subject: [PATCH 1078/1216] Optimization --- src/Protocols/Http.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 4623f865b..669a4127b 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -20,6 +20,7 @@ use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; use function clearstatcache; +use function count; use function explode; use function filesize; use function fopen; @@ -80,6 +81,10 @@ public static function requestClass(?string $className = null): string */ public static function input(string $buffer, TcpConnection $connection): int { + static $input = []; + if (isset($input[$buffer])) { + return $input[$buffer]; + } $crlfPos = strpos($buffer, "\r\n\r\n"); if (false === $crlfPos) { // Judge whether the package length exceeds the limit. @@ -115,6 +120,14 @@ public static function input(string $buffer, TcpConnection $connection): int $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } + + if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { + $input[$buffer] = $length; + if (count($input) > TcpConnection::MAX_CACHE_SIZE) { + unset($input[key($input)]); + } + } + return $length; } @@ -139,7 +152,7 @@ public static function decode(string $buffer, TcpConnection $connection): Reques $request = new static::$requestClass($buffer); if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { $requests[$buffer] = $request; - if (\count($requests) > TcpConnection::MAX_CACHE_SIZE) { + if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { unset($requests[key($requests)]); } $request = clone $request; From 42de1184d9407b88108b06556fae1eb385675b1b Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 8 Dec 2024 23:10:29 +0800 Subject: [PATCH 1079/1216] PidFile optimization --- src/Worker.php | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 3e25d690e..0bd51a1ae 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -710,23 +710,33 @@ protected static function init(): void // Start file. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); static::$startFile ??= end($backtrace)['file']; - $startFilePrefix = hash('xxh64', static::$startFile); + $startFilePrefix = basename(static::$startFile); + $startFileDir = dirname(static::$startFile); + + // Compatible with older workerman versions for pid file. + if (empty(static::$pidFile)) { + $unique_prefix = \str_replace('/', '_', static::$startFile); + $file = __DIR__ . "/../../$unique_prefix.pid"; + if (is_file($file)) { + static::$pidFile = $file; + } + } // Pid file. - static::$pidFile ??= sprintf('%s/workerman.%s.pid', dirname(__DIR__), $startFilePrefix); + static::$pidFile ??= sprintf('%s/workerman.%s.pid', $startFileDir, $startFilePrefix); // Status file. - static::$statusFile ??= sprintf('%s/workerman.%s.status', dirname(__DIR__), $startFilePrefix); + static::$statusFile ??= sprintf('%s/workerman.%s.status', $startFileDir, $startFilePrefix); static::$statisticsFile ??= static::$statusFile; static::$connectionsFile ??= static::$statusFile . '.connection'; // Log file. - static::$logFile ??= sprintf('%s/workerman.log', dirname(__DIR__, 2)); + static::$logFile ??= sprintf('%s/workerman.log', $startFileDir); if (static::$logFile !== '/dev/null' && !is_file(static::$logFile)) { // if /runtime/logs default folder not exists if (!is_dir(dirname(static::$logFile))) { - @mkdir(dirname(static::$logFile), 0777, true); + mkdir(dirname(static::$logFile), 0777, true); } touch(static::$logFile); chmod(static::$logFile, 0644); @@ -749,6 +759,8 @@ protected static function init(): void // Timer init. Timer::init(); + + restore_error_handler(); } /** @@ -1895,15 +1907,20 @@ protected static function monitorWorkersForWindows(): void */ protected static function exitAndClearAll(): void { + clearstatcache(); foreach (static::$workers as $worker) { $socketName = $worker->getSocketName(); if ($worker->transport === 'unix' && $socketName) { [, $address] = explode(':', $socketName, 2); $address = substr($address, strpos($address, '/') + 2); - @unlink($address); + if (file_exists($address)) { + @unlink($address); + } } } - @unlink(static::$pidFile); + if (file_exists(static::$pidFile)) { + @unlink(static::$pidFile); + } static::log("Workerman[" . basename(static::$startFile) . "] has been stopped"); if (static::$onMasterStop) { (static::$onMasterStop)(); From 81a3175d4bface8a475d084500fab6df5894a399 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Dec 2024 23:16:32 +0800 Subject: [PATCH 1080/1216] Optimization --- src/Worker.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 0bd51a1ae..3c3962989 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.4'; + final public const VERSION = '5.0.0-rc.5'; /** * Status starting. @@ -297,21 +297,21 @@ class Worker * * @var string */ - public static string $pidFile; + public static string $pidFile = ''; /** * The file used to store the master process status. * * @var string */ - public static string $statusFile; + public static string $statusFile = ''; /** * Log file. * * @var string */ - public static string $logFile; + public static string $logFile = ''; /** * Global event loop. @@ -446,21 +446,21 @@ class Worker * * @var string */ - protected static string $statisticsFile; + protected static string $statisticsFile = ''; /** * The file to store status info of connections. * * @var string */ - protected static string $connectionsFile; + protected static string $connectionsFile = ''; /** * Start file. * * @var string */ - protected static string $startFile; + protected static string $startFile = ''; /** * Processes for windows. @@ -723,15 +723,15 @@ protected static function init(): void } // Pid file. - static::$pidFile ??= sprintf('%s/workerman.%s.pid', $startFileDir, $startFilePrefix); + static::$pidFile = static::$pidFile ?: sprintf('%s/workerman.%s.pid', $startFileDir, $startFilePrefix); // Status file. - static::$statusFile ??= sprintf('%s/workerman.%s.status', $startFileDir, $startFilePrefix); - static::$statisticsFile ??= static::$statusFile; - static::$connectionsFile ??= static::$statusFile . '.connection'; + static::$statusFile = static::$statusFile ?: sprintf('%s/workerman.%s.status', $startFileDir, $startFilePrefix); + static::$statisticsFile = static::$statisticsFile ?: static::$statusFile; + static::$connectionsFile = static::$connectionsFile ?: static::$statusFile . '.connection'; // Log file. - static::$logFile ??= sprintf('%s/workerman.log', $startFileDir); + static::$logFile = static::$logFile ?: sprintf('%s/workerman.log', $startFileDir); if (static::$logFile !== '/dev/null' && !is_file(static::$logFile)) { // if /runtime/logs default folder not exists From a33fb4d0934c3b9b184ae90cfb245598c15d174d Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Dec 2024 23:32:17 +0800 Subject: [PATCH 1081/1216] Optimization --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 3c3962989..1b08e2db4 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -709,7 +709,7 @@ protected static function init(): void // Start file. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - static::$startFile ??= end($backtrace)['file']; + static::$startFile = static::$startFile ?: end($backtrace)['file']; $startFilePrefix = basename(static::$startFile); $startFileDir = dirname(static::$startFile); From 9226e640f3d96267a5aca32c7c7b9190cde25f3c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 11 Dec 2024 23:54:23 +0800 Subject: [PATCH 1082/1216] Set pidFile and logFile for tests --- tests/Feature/Stub/HttpServer.php | 3 +++ tests/Feature/Stub/UdpServer.php | 2 ++ tests/Feature/Stub/WebsocketClient.php | 1 + tests/Feature/Stub/WebsocketServer.php | 1 + 4 files changed, 7 insertions(+) diff --git a/tests/Feature/Stub/HttpServer.php b/tests/Feature/Stub/HttpServer.php index 6d5caa63f..afde02700 100644 --- a/tests/Feature/Stub/HttpServer.php +++ b/tests/Feature/Stub/HttpServer.php @@ -51,4 +51,7 @@ }; Worker::$command = 'start'; + +Worker::$pidFile = sprintf('%s/test-http-server.pid', sys_get_temp_dir()); +Worker::$logFile = sprintf('%s/test-http-server.log', sys_get_temp_dir()); Worker::runAll(); diff --git a/tests/Feature/Stub/UdpServer.php b/tests/Feature/Stub/UdpServer.php index fe405b96c..20727eb99 100644 --- a/tests/Feature/Stub/UdpServer.php +++ b/tests/Feature/Stub/UdpServer.php @@ -16,5 +16,7 @@ $connection->send('received: ' . $data); }; +Worker::$pidFile = sprintf('%s/test-udp-server.pid', sys_get_temp_dir()); +Worker::$logFile = sprintf('%s/test-udp-server.log', sys_get_temp_dir()); Worker::$command = 'start'; Worker::runAll(); diff --git a/tests/Feature/Stub/WebsocketClient.php b/tests/Feature/Stub/WebsocketClient.php index 8a440346a..842dcf9a1 100644 --- a/tests/Feature/Stub/WebsocketClient.php +++ b/tests/Feature/Stub/WebsocketClient.php @@ -19,5 +19,6 @@ }; Worker::$pidFile = sprintf('%s/test-websocket-client.pid', sys_get_temp_dir()); +Worker::$logFile = sprintf('%s/test-websocket-client.log', sys_get_temp_dir()); Worker::$command = 'start'; Worker::runAll(); diff --git a/tests/Feature/Stub/WebsocketServer.php b/tests/Feature/Stub/WebsocketServer.php index 038e8db03..f21d7c241 100644 --- a/tests/Feature/Stub/WebsocketServer.php +++ b/tests/Feature/Stub/WebsocketServer.php @@ -16,5 +16,6 @@ //%action% Worker::$pidFile = sprintf('%s/test-websocket-server.pid', sys_get_temp_dir()); +Worker::$logFile = sprintf('%s/test-websocket-server.log', sys_get_temp_dir()); Worker::$command = 'start'; Worker::runAll(); From 32cd706985662898be3672d67adbe84f153c93bd Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Dec 2024 14:50:31 +0800 Subject: [PATCH 1083/1216] 5.0.0-rc.4 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 1b08e2db4..a7c77ad14 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.5'; + final public const VERSION = '5.0.0-rc.4'; /** * Status starting. From 42e73006eed7e6a41767a8176dfab08424d2fe98 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Dec 2024 14:51:09 +0800 Subject: [PATCH 1084/1216] v5.0.0 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index a7c77ad14..c71dd3069 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0-rc.4'; + final public const VERSION = '5.0.0'; /** * Status starting. From 3141b8cd4514f980457c707fafb6b53c2a6cb813 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 17 Dec 2024 17:09:44 +0800 Subject: [PATCH 1085/1216] SWOOLE_HOOK_ALL --- src/Events/Swoole.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 815376d5b..41f08214c 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -48,6 +48,14 @@ final class Swoole implements EventInterface */ private $errorHandler = null; + /** + * Constructor. + */ + public function __construct() + { + Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]); + } + /** * {@inheritdoc} */ From 3dbb2358bb7e423f81c69586b8581b59f21bb94f Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 18 Dec 2024 15:36:24 +0800 Subject: [PATCH 1086/1216] Optimization --- src/Protocols/Http.php | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 669a4127b..c5f8b1d47 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -81,10 +81,6 @@ public static function requestClass(?string $className = null): string */ public static function input(string $buffer, TcpConnection $connection): int { - static $input = []; - if (isset($input[$buffer])) { - return $input[$buffer]; - } $crlfPos = strpos($buffer, "\r\n\r\n"); if (false === $crlfPos) { // Judge whether the package length exceeds the limit. @@ -102,32 +98,15 @@ public static function input(string $buffer, TcpConnection $connection): int } $header = substr($buffer, 0, $crlfPos); - if ($pos = strpos($header, "\r\nContent-Length: ")) { - $length += (int)substr($header, $pos + 18, 10); - $hasContentLength = true; - } else if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { + if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { $length += (int)$match[1]; - $hasContentLength = true; - } else { - $hasContentLength = false; - if (str_contains($header, "\r\nTransfer-Encoding:")) { - $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); - return 0; - } } - if ($hasContentLength && $length > $connection->maxPackageSize) { + if ($length > $connection->maxPackageSize) { $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); return 0; } - if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { - $input[$buffer] = $length; - if (count($input) > TcpConnection::MAX_CACHE_SIZE) { - unset($input[key($input)]); - } - } - return $length; } From cf977120942ce18624ce5c3a4e13b5c6a9c99ee0 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 18 Dec 2024 21:24:55 +0800 Subject: [PATCH 1087/1216] Optimization --- src/Connection/TcpConnection.php | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index b9cbbc2df..e3536fd20 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -282,13 +282,6 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ protected static int $idRecorder = 1; - /** - * Cache. - * - * @var bool - */ - protected static bool $enableCache = true; - /** * Socket * @@ -674,7 +667,7 @@ public function baseRead($socket, bool $checkEof = true): void } else { $this->bytesRead += strlen($buffer); if ($this->recvBuffer === '') { - if (static::$enableCache && isset($requests[$buffer])) { + if (!isset($buffer[static::MAX_CACHE_STRING_LENGTH]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; $request = $requests[$buffer]; if ($request instanceof Request) { @@ -752,7 +745,7 @@ public function baseRead($socket, bool $checkEof = true): void try { // Decode request buffer before Emitting onMessage callback. $request = $this->protocol::decode($oneRequestBuffer, $this); - if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { + if ((!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { ($this->onMessage)($this, $request); if ($request instanceof Request) { $request->destroy(); @@ -1088,16 +1081,6 @@ public function destroy(): void } } - /** - * Enable or disable Cache. - * - * @param bool $value - */ - public static function enableCache(bool $value = true): void - { - static::$enableCache = $value; - } - /** * Init. * From d86dd6beef05d384b429b03a6495fbcf72223626 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Dec 2024 10:25:10 +0800 Subject: [PATCH 1088/1216] Optimization --- src/Worker.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index c71dd3069..42cf2f7f1 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1568,8 +1568,8 @@ protected static function forkWorkersForWindows(): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; - static::$globalEvent = new $eventLoopClass(); + static::$eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; + static::$globalEvent = new static::$eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); }); @@ -1708,8 +1708,8 @@ protected static function forkOneWorkerForLinux(self $worker): void // Create a global event loop. if (static::$globalEvent === null) { - $eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; - static::$globalEvent = new $eventLoopClass(); + static::$eventLoopClass = $worker->eventLoop ?: static::$eventLoopClass; + static::$globalEvent = new static::$eventLoopClass(); static::$globalEvent->setErrorHandler(function ($exception) { static::stopAll(250, $exception); }); From 9d84f4d6bb4161e32158c0fda93d4cc4d0063c80 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 19 Dec 2024 11:21:08 +0800 Subject: [PATCH 1089/1216] Optimization --- src/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Worker.php b/src/Worker.php index 42cf2f7f1..d9b140d9a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -706,6 +706,7 @@ protected static function init(): void // $_SERVER. $_SERVER['SERVER_SOFTWARE'] = 'Workerman/' . static::VERSION; + $_SERVER['SERVER_START_TIME'] = time(); // Start file. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); From b2e99500670ad65eed85681381bf17b06242cc0b Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Dec 2024 16:30:49 +0800 Subject: [PATCH 1090/1216] Code optimization --- src/Protocols/Http.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index c5f8b1d47..490ccfeff 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -98,8 +98,12 @@ public static function input(string $buffer, TcpConnection $connection): int } $header = substr($buffer, 0, $crlfPos); - if (preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) { - $length += (int)$match[1]; + if (preg_match('/\b(?:Transfer-Encoding\b.*)|(?:Content-Length:\s*(\d+)(?!.*\bTransfer-Encoding\b))/is', $header, $matches)) { + if (!isset($matches[1])) { + $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); + return 0; + } + $length += (int)$matches[1]; } if ($length > $connection->maxPackageSize) { From df67931cc602675e95fb2eace90948fa642a3024 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 30 Dec 2024 23:42:54 +0800 Subject: [PATCH 1091/1216] Code optimization --- src/Protocols/Http.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 490ccfeff..1c58b3379 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -32,6 +32,7 @@ use function is_array; use function is_object; use function preg_match; +use function str_starts_with; use function strlen; use function strpos; use function strstr; @@ -91,13 +92,21 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $method = strstr($buffer, ' ', true); - if (!in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) { + $header = substr($buffer, 0, $crlfPos); + + if ( + !str_starts_with($header, 'GET ') && + !str_starts_with($header, 'POST ') && + !str_starts_with($header, 'OPTIONS ') && + !str_starts_with($header, 'HEAD ') && + !str_starts_with($header, 'DELETE ') && + !str_starts_with($header, 'PUT ') && + !str_starts_with($header, 'PATCH ') + ) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } - $header = substr($buffer, 0, $crlfPos); if (preg_match('/\b(?:Transfer-Encoding\b.*)|(?:Content-Length:\s*(\d+)(?!.*\bTransfer-Encoding\b))/is', $header, $matches)) { if (!isset($matches[1])) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); From 48381615ebbabe8b185ab8de289e60105a7ef059 Mon Sep 17 00:00:00 2001 From: JasonnnW3000 Date: Wed, 1 Jan 2025 05:36:32 -0500 Subject: [PATCH 1092/1216] Update MIT-LICENSE.txt, fix license year Signed-off-by: JasonnnW3000 --- MIT-LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt index fd6b1c83f..6f6ce35f6 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2009-2015 walkor and contributors (see https://github.com/walkor/workerman/contributors) +Copyright (c) 2009-2025 walkor and contributors (see https://github.com/walkor/workerman/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 5018ab3c6307f299801717e898ef5441f4fc88b6 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Jan 2025 09:14:49 +0800 Subject: [PATCH 1093/1216] Optimization --- src/Events/Swoole.php | 6 ++++++ src/Events/Swow.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 41f08214c..9bdde9175 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -48,6 +48,8 @@ final class Swoole implements EventInterface */ private $errorHandler = null; + private bool $stopping = false; + /** * Constructor. */ @@ -220,6 +222,10 @@ public function run(): void */ public function stop(): void { + if ($this->stopping) { + return; + } + $this->stopping = true; // Cancel all coroutines before Event::exit foreach (Coroutine::listCoroutines() as $coroutine) { Coroutine::cancel($coroutine); diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 109b2211b..445763378 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -266,7 +266,7 @@ public function run(): void */ public function stop(): void { - Coroutine::killAll(); + exit(0); } /** From f148e67c1205790abc86d09168f8a0d8fbf54370 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Jan 2025 09:18:57 +0800 Subject: [PATCH 1094/1216] 5.0.1 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index d9b140d9a..63c21e457 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -59,7 +59,7 @@ class Worker * * @var string */ - final public const VERSION = '5.0.0'; + final public const VERSION = '5.0.1'; /** * Status starting. From 7318abf798eb4fdde76d253350541ddf7b28bd7a Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Jan 2025 14:47:13 +0800 Subject: [PATCH 1095/1216] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 611294c72..384ed5c24 100644 --- a/README.md +++ b/README.md @@ -390,6 +390,12 @@ proxy supports TLS1.3, no Sniproxy channel https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r + +### Supported by + +[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) + + ## Other links with workerman [webman](https://github.com/walkor/webman) From 2b906f6f91023713859c699e4d4a525d6bd6cc55 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 9 Jan 2025 22:44:02 +0800 Subject: [PATCH 1096/1216] Swow stop --- src/Events/Swow.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 445763378..109b2211b 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -266,7 +266,7 @@ public function run(): void */ public function stop(): void { - exit(0); + Coroutine::killAll(); } /** From 1e7bb17395deb69fdd5e397dff761b93c29dd5b7 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Jan 2025 15:54:43 +0800 Subject: [PATCH 1097/1216] Run callbacks using coroutines. --- src/Events/Swow.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 109b2211b..7917a8dc5 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -284,14 +284,16 @@ public function setErrorHandler(callable $errorHandler): void */ private function safeCall(callable $func, array $args = []): void { - try { - $func(...$args); - } catch (\Throwable $e) { - if ($this->errorHandler === null) { - echo $e; - } else { - ($this->errorHandler)($e); + Coroutine::run(function () use ($func, $args): void { + try { + $func(...$args); + } catch (\Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } } - } + }); } } From 0549bd85dea1911eec7e9758a0266cd7d24b4c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E3=80=81=E7=A7=8B=E7=A7=8B=E7=A7=8B=E7=A7=8B?= =?UTF-8?q?=E7=A7=8B=E7=A7=8B=E7=A7=8B?= <409703312@qq.com> Date: Sat, 18 Jan 2025 16:38:55 +0800 Subject: [PATCH 1098/1216] =?UTF-8?q?=E6=A3=80=E6=B5=8B=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E4=B8=BAnull?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Connection/TcpConnection.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index e3536fd20..71def175c 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -610,7 +610,9 @@ public function getRecvBufferQueueSize(): int */ public function pauseRecv(): void { - $this->eventLoop->offReadable($this->socket); + if($this->eventLoop !== null){ + $this->eventLoop->offReadable($this->socket); + } $this->isPaused = true; } @@ -1037,10 +1039,12 @@ public function destroy(): void return; } // Remove event listener. - $this->eventLoop->offReadable($this->socket); - $this->eventLoop->offWritable($this->socket); - if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { - $this->eventLoop->offExcept($this->socket); + if($this->eventLoop !== null){ + $this->eventLoop->offReadable($this->socket); + $this->eventLoop->offWritable($this->socket); + if (DIRECTORY_SEPARATOR === '\\' && method_exists($this->eventLoop, 'offExcept')) { + $this->eventLoop->offExcept($this->socket); + } } // Close socket. From 721cfbaef9cd6afcc2411483de66476c70aa3c41 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Jan 2025 21:42:13 +0800 Subject: [PATCH 1099/1216] 5.1.0 --- composer.json | 3 ++- src/Events/{Revolt.php => Fiber.php} | 25 ++++++++++++----- src/Events/Swoole.php | 19 +++++++------ src/Events/Swow.php | 3 ++- src/Timer.php | 17 +++++------- src/Worker.php | 40 +++++++++++++++++++++++----- 6 files changed, 73 insertions(+), 34 deletions(-) rename src/Events/{Revolt.php => Fiber.php} (90%) diff --git a/composer.json b/composer.json index 43f44584d..98865c2a3 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ }, "require": { "php": ">=8.1", - "ext-json": "*" + "ext-json": "*", + "workerman/coroutine": "^1.0 || dev-main" }, "suggest": { "ext-event": "For better performance. " diff --git a/src/Events/Revolt.php b/src/Events/Fiber.php similarity index 90% rename from src/Events/Revolt.php rename to src/Events/Fiber.php index 030457d01..133f2ccde 100644 --- a/src/Events/Revolt.php +++ b/src/Events/Fiber.php @@ -16,6 +16,7 @@ namespace Workerman\Events; +use Fiber as BaseFiber; use Revolt\EventLoop; use Revolt\EventLoop\Driver; use function count; @@ -25,7 +26,7 @@ /** * Revolt eventloop */ -final class Revolt implements EventInterface +final class Fiber implements EventInterface { /** * @var Driver @@ -115,7 +116,7 @@ public function delay(float $delay, callable $func, array $args = []): int $timerId = $this->timerId++; $closure = function () use ($func, $args, $timerId) { unset($this->eventTimer[$timerId]); - $func(...$args); + $this->safeCall($func, ...$args); }; $cbId = $this->driver->delay($delay, $closure); $this->eventTimer[$timerId] = $cbId; @@ -128,7 +129,7 @@ public function delay(float $delay, callable $func, array $args = []): int public function repeat(float $interval, callable $func, array $args = []): int { $timerId = $this->timerId++; - $cbId = $this->driver->repeat($interval, static fn () => $func(...$args)); + $cbId = $this->driver->repeat($interval, fn() => $this->safeCall($func, ...$args)); $this->eventTimer[$timerId] = $cbId; return $timerId; } @@ -141,10 +142,9 @@ public function onReadable($stream, callable $func): void $fdKey = (int)$stream; if (isset($this->readEvents[$fdKey])) { $this->driver->cancel($this->readEvents[$fdKey]); - unset($this->readEvents[$fdKey]); } - $this->readEvents[$fdKey] = $this->driver->onReadable($stream, static fn () => $func($stream)); + $this->readEvents[$fdKey] = $this->driver->onReadable($stream, fn() => $this->safeCall($func, $stream)); } /** @@ -171,7 +171,7 @@ public function onWritable($stream, callable $func): void $this->driver->cancel($this->writeEvents[$fdKey]); unset($this->writeEvents[$fdKey]); } - $this->writeEvents[$fdKey] = $this->driver->onWritable($stream, static fn () => $func($stream)); + $this->writeEvents[$fdKey] = $this->driver->onWritable($stream, fn() => $this->safeCall($func, $stream)); } /** @@ -198,7 +198,7 @@ public function onSignal(int $signal, callable $func): void $this->driver->cancel($this->eventSignal[$fdKey]); unset($this->eventSignal[$fdKey]); } - $this->eventSignal[$fdKey] = $this->driver->onSignal($signal, static fn () => $func($signal)); + $this->eventSignal[$fdKey] = $this->driver->onSignal($signal, fn() => $this->safeCall($func, $signal)); } /** @@ -262,4 +262,15 @@ public function setErrorHandler(callable $errorHandler): void { $this->driver->setErrorHandler($errorHandler); } + + /** + * @param callable $func + * @param ...$args + * @return void + * @throws \Throwable + */ + protected function safeCall(callable $func, ...$args): void + { + (new BaseFiber(fn() => $func(...$args)))->start(); + } } diff --git a/src/Events/Swoole.php b/src/Events/Swoole.php index 9bdde9175..329c87e9b 100644 --- a/src/Events/Swoole.php +++ b/src/Events/Swoole.php @@ -19,6 +19,7 @@ use Swoole\Event; use Swoole\Process; use Swoole\Timer; +use Throwable; final class Swoole implements EventInterface { @@ -282,14 +283,16 @@ private function callWrite($fd) */ private function safeCall(callable $func, array $args = []): void { - try { - $func(...$args); - } catch (\Throwable $e) { - if ($this->errorHandler === null) { - echo $e; - } else { - ($this->errorHandler)($e); + Coroutine::create(function() use ($func, $args) { + try { + $func(...$args); + } catch (Throwable $e) { + if ($this->errorHandler === null) { + echo $e; + } else { + ($this->errorHandler)($e); + } } - } + }); } } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 7917a8dc5..53f2b1d14 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -4,7 +4,7 @@ namespace Workerman\Events; -use Swow\Coroutine; +use Workerman\Coroutine\Swow as Coroutine; use Swow\Signal; use Swow\SignalException; use function Swow\Sync\waitAll; @@ -296,4 +296,5 @@ private function safeCall(callable $func, array $args = []): void } }); } + } diff --git a/src/Timer.php b/src/Timer.php index acc39c060..3a29fee29 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -19,9 +19,10 @@ use RuntimeException; use Throwable; use Workerman\Events\EventInterface; -use Workerman\Events\Revolt; +use Workerman\Events\Fiber; use Workerman\Events\Swoole; -use Workerman\Events\Swow; +use Revolt\EventLoop; +use Swoole\Coroutine\System; use function function_exists; use function pcntl_alarm; use function pcntl_signal; @@ -182,8 +183,8 @@ public static function sleep(float $delay): void { switch (Worker::$eventLoopClass) { // Fiber - case Revolt::class: - $suspension = \Revolt\EventLoop::getSuspension(); + case Fiber::class: + $suspension = EventLoop::getSuspension(); static::add($delay, function () use ($suspension) { $suspension->resume(); }, null, false); @@ -191,14 +192,10 @@ public static function sleep(float $delay): void return; // Swoole case Swoole::class: - \Swoole\Coroutine\System::sleep($delay); - return; - // Swow - case Swow::class: - usleep((int)($delay * 1000 * 1000)); + System::sleep($delay); return; } - throw new RuntimeException('Timer::sleep() require revolt/event-loop. Please run command "composer require revolt/event-loop" and restart workerman'); + usleep((int)($delay * 1000 * 1000)); } /** diff --git a/src/Worker.php b/src/Worker.php index 63c21e457..6cbcf3464 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -28,7 +28,7 @@ use Workerman\Connection\UdpConnection; use Workerman\Events\Event; use Workerman\Events\EventInterface; -use Workerman\Events\Revolt; +use Workerman\Events\Fiber; use Workerman\Events\Select; use Workerman\Protocols\ProtocolInterface; use function defined; @@ -59,7 +59,14 @@ class Worker * * @var string */ - final public const VERSION = '5.0.1'; + final public const VERSION = '5.1.0'; + + /** + * Status initial. + * + * @var int + */ + public const STATUS_INITIAL = 0; /** * Status starting. @@ -344,9 +351,9 @@ class Worker /** * EventLoopClass * - * @var class-string + * @var ?class-string */ - public static string $eventLoopClass; + public static ?string $eventLoopClass = null; /** * After sending the stop command to the child process stopTimeout seconds, @@ -432,7 +439,7 @@ class Worker * * @var int */ - protected static int $status = self::STATUS_STARTING; + protected static int $status = self::STATUS_INITIAL; /** * UI data. @@ -785,7 +792,6 @@ protected static function initGlobalEvent(): void } static::$eventLoopClass = match (true) { - class_exists(EventLoop::class) => Revolt::class, extension_loaded('event') => Event::class, default => Select::class, }; @@ -2541,7 +2547,17 @@ public function run(): void // Try to emit onWorkerStart callback. if ($this->onWorkerStart) { try { - ($this->onWorkerStart)($this); + switch (Worker::$eventLoopClass) { + case Events\Swoole::class: + \Swoole\Coroutine::create(fn() => ($this->onWorkerStart)($this)); + break; + case Events\Swow::class: + \Swow\Coroutine::run(fn() => ($this->onWorkerStart)($this)); + break; + default: + (new \Fiber($this->onWorkerStart))->start($this); + + } } catch (Throwable $e) { // Avoid rapid infinite loop exit. sleep(1); @@ -2705,4 +2721,14 @@ protected static function checkMasterIsAlive(int $masterPid): bool return str_contains($content, 'WorkerMan') || str_contains($content, 'php'); } + + /** + * If worker is running. + * + * @return bool + */ + public static function isRunning(): bool + { + return Worker::$status !== Worker::STATUS_INITIAL; + } } From 38eec45465ba37adec9fcd642401e0580e530b3f Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 19 Jan 2025 22:28:22 +0800 Subject: [PATCH 1100/1216] Fix phpstan --- phpstan.neon.dist | 13 ++++++++----- src/Worker.php | 3 --- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0721f602e..12610417b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -5,11 +5,11 @@ parameters: - tests ignoreErrors: - - path: src/Events/Revolt.php + path: src/Events/Fiber.php messages: - - '#Property Workerman\\Events\\Revolt::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' + - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - - '#Method Workerman\\Events\\Revolt::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' + - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - path: src/Events/Swow.php @@ -24,7 +24,8 @@ parameters: - '#Constant STREAM_POLLIN not found.#' - '#Constant STREAM_POLLNONE not found.#' - '#Constant STREAM_POLLOUT not found.#' - - '#Property Workerman\\Events\\Swow::.* has unknown class Swow\\Coroutine as its type.#' + - '#Property Workerman\\Events\\Swow::.* has unknown class Workerman\\Coroutine\\Swow as its type.#' + - '#Call to static method .* on an unknown class Workerman\\Coroutine\\Swow.#' - path: src/Events/Event.php reportUnmatched: false @@ -33,4 +34,6 @@ parameters: - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: src/Worker.php - message: '#Constant LINE_VERSION_LENGTH not found.#' + messages: + - '#Constant LINE_VERSION_LENGTH not found.#' + - '#Call to static method run\(\) on an unknown class Swow\\Coroutine.#' diff --git a/src/Worker.php b/src/Worker.php index 6cbcf3464..5d120892b 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -18,7 +18,6 @@ use AllowDynamicProperties; use Exception; -use Revolt\EventLoop; use RuntimeException; use stdClass; use Stringable; @@ -28,9 +27,7 @@ use Workerman\Connection\UdpConnection; use Workerman\Events\Event; use Workerman\Events\EventInterface; -use Workerman\Events\Fiber; use Workerman\Events\Select; -use Workerman\Protocols\ProtocolInterface; use function defined; use function function_exists; use function is_resource; From 695de62d333f800bf9a2f24cfa83d49d5b087780 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Jan 2025 11:14:33 +0800 Subject: [PATCH 1101/1216] Fix namespace --- src/Events/Swow.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 53f2b1d14..3af770506 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -4,7 +4,7 @@ namespace Workerman\Events; -use Workerman\Coroutine\Swow as Coroutine; +use Workerman\Coroutine\Coroutine\Swow as Coroutine; use Swow\Signal; use Swow\SignalException; use function Swow\Sync\waitAll; From 627b43d183acbafddf0388d9dd6775ad8b453db2 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Jan 2025 11:43:29 +0800 Subject: [PATCH 1102/1216] Fix phpstan --- phpstan.neon.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 12610417b..ee1876389 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -24,8 +24,8 @@ parameters: - '#Constant STREAM_POLLIN not found.#' - '#Constant STREAM_POLLNONE not found.#' - '#Constant STREAM_POLLOUT not found.#' - - '#Property Workerman\\Events\\Swow::.* has unknown class Workerman\\Coroutine\\Swow as its type.#' - - '#Call to static method .* on an unknown class Workerman\\Coroutine\\Swow.#' + - '#Property Workerman\\Events\\Swow::.* has unknown class Workerman\\Coroutine\\Coroutine\\Swow as its type.#' + - '#Call to static method .* on an unknown class Workerman\\Coroutine\\Coroutine\\Swow.#' - path: src/Events/Event.php reportUnmatched: false From 1d54c2c0d1779b4224620324cc458e98facc0beb Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 20 Jan 2025 12:29:26 +0800 Subject: [PATCH 1103/1216] Fix phpstan --- phpstan.neon.dist | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ee1876389..c4c5ab96f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,8 @@ parameters: paths: - src - tests + excludePaths: + - src/Events/Swow.php ignoreErrors: - path: src/Events/Fiber.php @@ -11,21 +13,6 @@ parameters: - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - - - path: src/Events/Swow.php - messages: - - '#Used function Swow\\Sync\\waitAll not found.#' - - '#Call to static method .* on an unknown class Swow\\.*.#' - - '#Function msleep not found.#' - - '#Function stream_poll_one not found.#' - - '#Caught class Swow\\SignalException not found.#' - - '#Function Swow\\Sync\\waitAll not found.#' - - '#Constant STREAM_POLLHUP not found.#' - - '#Constant STREAM_POLLIN not found.#' - - '#Constant STREAM_POLLNONE not found.#' - - '#Constant STREAM_POLLOUT not found.#' - - '#Property Workerman\\Events\\Swow::.* has unknown class Workerman\\Coroutine\\Coroutine\\Swow as its type.#' - - '#Call to static method .* on an unknown class Workerman\\Coroutine\\Coroutine\\Swow.#' - path: src/Events/Event.php reportUnmatched: false From 3eab92baafa92e713fd993ec2106935623db7e77 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 24 Jan 2025 20:14:56 +0800 Subject: [PATCH 1104/1216] Shorten timeout compatible with SWOW to receive signals. --- src/Events/Select.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 811360ebb..a6223b4de 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -112,7 +112,7 @@ final class Select implements EventInterface * * @var int */ - private int $selectTimeout = 100000000; + private int $selectTimeout = 800000; /** * Next run time of the timer. @@ -357,7 +357,7 @@ protected function setNextTickTime(float $nextTickTime): void { $this->nextTickTime = $nextTickTime; if ($nextTickTime == 0) { - $this->selectTimeout = 10000000; + $this->selectTimeout = 800000; return; } $timeNow = microtime(true); From ea829e3bea1a4444edda0880e9a67af378183cad Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 24 Jan 2025 20:29:49 +0800 Subject: [PATCH 1105/1216] Delete unnecessary code --- src/Events/Select.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index a6223b4de..0b26194e4 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -419,10 +419,8 @@ public function run(): void $this->tick(); } - if ($this->signalEvents) { - // Calls signal handlers for pending signals - pcntl_signal_dispatch(); - } + // Calls signal handlers for pending signals + pcntl_signal_dispatch(); } } From 6a98c9fe609f3b07572bafb476ec7e650f7abe01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E3=80=81=E7=A7=8B=E7=A7=8B=E7=A7=8B=E7=A7=8B?= =?UTF-8?q?=E7=A7=8B=E7=A7=8B=E7=A7=8B?= <409703312@qq.com> Date: Mon, 27 Jan 2025 18:12:53 +0800 Subject: [PATCH 1106/1216] =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E5=80=99=E5=8F=AF=E8=83=BD=E4=BC=9A=E6=8A=A5=E9=94=99substr():?= =?UTF-8?q?=20Argument=20#1=20($string)=20must=20be=20of=20type=20string,?= =?UTF-8?q?=20bool=20given?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Protocols/Http/Request.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b8c3049aa..cbb0dc358 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -419,8 +419,9 @@ protected function parseHeadFirstLine(): void protected function parseProtocolVersion(): void { $firstLine = strstr($this->buffer, "\r\n", true); - $protocolVersion = substr(strstr($firstLine, 'HTTP/'), 5); - $this->data['protocolVersion'] = $protocolVersion ?: '1.0'; + $httpStr = strstr($firstLine, 'HTTP/'); + $protocolVersion = $httpStr ? substr($httpStr, 5) : '1.0'; + $this->data['protocolVersion'] = $protocolVersion; } /** From 6dc10b36269f44e9eb8ea80c69d5862e3e2eecca Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 27 Jan 2025 23:39:16 +0800 Subject: [PATCH 1107/1216] Fix Timer::repeat for event --- src/Events/Event.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Events/Event.php b/src/Events/Event.php index 33d59f6d8..d7d908e1f 100644 --- a/src/Events/Event.php +++ b/src/Events/Event.php @@ -140,7 +140,9 @@ public function repeat(float $interval, callable $func, array $args = []): int { $className = $this->eventClassName; $timerId = $this->timerId++; - $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, $func); + $event = new $className($this->eventBase, -1, $className::TIMEOUT | $className::PERSIST, function () use ($func, $args) { + $this->safeCall($func, $args); + }); if (!$event->addTimer($interval)) { throw new \RuntimeException("Event::addTimer($interval) failed"); } From c08a211da4208077290c0e8007477c5ff7b6ea29 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 29 Jan 2025 10:24:42 +0800 Subject: [PATCH 1108/1216] Optimize the stop operation. --- src/Worker.php | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 5d120892b..0123cfde8 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2046,18 +2046,33 @@ public static function stopAll(int $code = 0, mixed $log = ''): void } // Execute exit. $workers = array_reverse(static::$workers); - array_walk($workers, static fn (Worker $worker) => $worker->stop()); + array_walk($workers, static fn (Worker $worker) => $worker->stop(false)); - if (!static::getGracefulStop() || ConnectionInterface::$statistics['connection_count'] <= 0) { - static::$globalEvent?->stop(); - try { - // Ignore Swoole ExitException: Swoole exit. - exit($code); - /** @phpstan-ignore-next-line */ - } catch (Throwable) { - // do nothing + $callback = function () use ($code, $workers) { + $allWorkerConnectionClosed = true; + if (!static::getGracefulStop()) { + foreach ($workers as $worker) { + foreach ($worker->connections as $connection) { + // Delay closing, waiting for data to be sent. + if (!$connection->getRecvBufferQueueSize() && !isset($connection->context->closeTimer)) { + $connection->context->closeTimer = Timer::delay(0.01, static fn () => $connection->close()); + } + $allWorkerConnectionClosed = false; + } + } } - } + if ((!static::getGracefulStop() && $allWorkerConnectionClosed) || ConnectionInterface::$statistics['connection_count'] <= 0) { + static::$globalEvent?->stop(); + try { + // Ignore Swoole ExitException: Swoole exit. + exit($code); + /** @phpstan-ignore-next-line */ + } catch (Throwable) { + // do nothing + } + } + }; + Timer::repeat(0.01, $callback); } } @@ -2566,9 +2581,10 @@ public function run(): void /** * Stop current worker instance. * + * @param bool $force * @return void */ - public function stop(): void + public function stop(bool $force = true): void { if ($this->stopping === true) { return; @@ -2586,7 +2602,9 @@ public function stop(): void // Close all connections for the worker. if (!static::getGracefulStop()) { foreach ($this->connections as $connection) { - $connection->close(); + if ($force || !$connection->getRecvBufferQueueSize()) { + $connection->close(); + } } } // Clear callback. From 7739a01ad15a490473897493c78bb3c77849af86 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 Feb 2025 22:06:29 +0800 Subject: [PATCH 1109/1216] Run onWorkerStart with coroutine --- src/Events/Fiber.php | 2 +- src/Worker.php | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Events/Fiber.php b/src/Events/Fiber.php index 133f2ccde..8629eba79 100644 --- a/src/Events/Fiber.php +++ b/src/Events/Fiber.php @@ -26,7 +26,7 @@ /** * Revolt eventloop */ -final class Fiber implements EventInterface +class Fiber implements EventInterface { /** * @var Driver diff --git a/src/Worker.php b/src/Worker.php index 0123cfde8..774a839a4 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -25,9 +25,13 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; +use Workerman\Coroutine\Coroutine; use Workerman\Events\Event; use Workerman\Events\EventInterface; +use Workerman\Events\Fiber; use Workerman\Events\Select; +use Workerman\Events\Swoole; +use Workerman\Events\Swow; use function defined; use function function_exists; use function is_resource; @@ -2551,30 +2555,35 @@ public function getSocketName(): string * Run worker instance. * * @return void + * @throws Throwable */ public function run(): void { $this->listen(); + if (!$this->onWorkerStart) { + return; + } + // Try to emit onWorkerStart callback. - if ($this->onWorkerStart) { + $callback = function() { try { - switch (Worker::$eventLoopClass) { - case Events\Swoole::class: - \Swoole\Coroutine::create(fn() => ($this->onWorkerStart)($this)); - break; - case Events\Swow::class: - \Swow\Coroutine::run(fn() => ($this->onWorkerStart)($this)); - break; - default: - (new \Fiber($this->onWorkerStart))->start($this); - - } + ($this->onWorkerStart)($this); } catch (Throwable $e) { // Avoid rapid infinite loop exit. sleep(1); static::stopAll(250, $e); } + }; + + switch (Worker::$eventLoopClass) { + case Swoole::class: + case Swow::class: + case Fiber::class: + Coroutine::create($callback); + break; + default: + (new \Fiber($callback))->start(); } } From 9e0de1dff40b529e95ee82d59636f05dfffdc2f7 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 Feb 2025 22:07:41 +0800 Subject: [PATCH 1110/1216] Do not call pcntl_signal_dispatch under windows --- src/Events/Select.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 0b26194e4..01faa1fce 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -419,8 +419,11 @@ public function run(): void $this->tick(); } - // Calls signal handlers for pending signals - pcntl_signal_dispatch(); + // The $this->signalEvents are empty under Windows, make sure not to call pcntl_signal_dispatch. + if ($this->signalEvents) { + // Calls signal handlers for pending signals + pcntl_signal_dispatch(); + } } } From 44df0b1e8d7755daaf3470186e728443e89cfdb0 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 Feb 2025 22:08:02 +0800 Subject: [PATCH 1111/1216] Final Fiber eventloop --- src/Events/Fiber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Events/Fiber.php b/src/Events/Fiber.php index 8629eba79..133f2ccde 100644 --- a/src/Events/Fiber.php +++ b/src/Events/Fiber.php @@ -26,7 +26,7 @@ /** * Revolt eventloop */ -class Fiber implements EventInterface +final class Fiber implements EventInterface { /** * @var Driver From 4deadc9403c1d784c1c0c46e8a0e0371d2f5c195 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 1 Feb 2025 22:13:17 +0800 Subject: [PATCH 1112/1216] Fix phpstan --- phpstan.neon.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index c4c5ab96f..c4c8a6478 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -23,4 +23,3 @@ parameters: - path: src/Worker.php messages: - '#Constant LINE_VERSION_LENGTH not found.#' - - '#Call to static method run\(\) on an unknown class Swow\\Coroutine.#' From 754861f0b65238b4e08b7955b3859d9d56e9c081 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 2 Feb 2025 13:09:16 +0800 Subject: [PATCH 1113/1216] swow --- src/Events/Select.php | 1 + src/Events/Swow.php | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 01faa1fce..385135a20 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -357,6 +357,7 @@ protected function setNextTickTime(float $nextTickTime): void { $this->nextTickTime = $nextTickTime; if ($nextTickTime == 0) { + // Set a shorter timeout so that swow can timely detect the signal. $this->selectTimeout = 800000; return; } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index 3af770506..ab07be9d2 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -4,6 +4,7 @@ namespace Workerman\Events; +use RuntimeException; use Workerman\Coroutine\Coroutine\Swow as Coroutine; use Swow\Signal; use Swow\SignalException; @@ -141,19 +142,21 @@ public function onReadable($stream, callable $func): void $this->offReadable($stream); break; } - $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP); + // Under Windows, setting a timeout is necessary; otherwise, the accept cannot be listened to. + // Setting it to 1000ms will result in a 1-second delay for the first accept under Windows. + $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP, 1000); if (!isset($this->readEvents[$fd]) || $this->readEvents[$fd] !== Coroutine::getCurrent()) { break; } if ($rEvent !== STREAM_POLLNONE) { $this->safeCall($func, [$stream]); } - if ($rEvent !== STREAM_POLLIN) { + if ($rEvent !== STREAM_POLLIN && $rEvent !== STREAM_POLLNONE) { $this->offReadable($stream); break; } } - } catch (\RuntimeException) { + } catch (RuntimeException) { $this->offReadable($stream); } }); @@ -198,7 +201,7 @@ public function onWritable($stream, callable $func): void break; } } - } catch (\RuntimeException) { + } catch (RuntimeException) { $this->offWritable($stream); } }); From d0e9b7599f754fcdf99686eb18708f2e9e3c9d01 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 3 Feb 2025 10:14:24 +0800 Subject: [PATCH 1114/1216] Comment --- src/Events/Select.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 385135a20..4b3dba727 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -357,7 +357,8 @@ protected function setNextTickTime(float $nextTickTime): void { $this->nextTickTime = $nextTickTime; if ($nextTickTime == 0) { - // Set a shorter timeout so that swow can timely detect the signal. + // Swow will affect the signal interruption characteristics of stream_select, + // so a shorter timeout should be used to detect signals. $this->selectTimeout = 800000; return; } From 3365ea2f46c9c59b46386a175994d5a6168270a4 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 3 Feb 2025 18:57:04 +0800 Subject: [PATCH 1115/1216] Fix selectTimeout --- src/Events/Select.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index 4b3dba727..db712b90a 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -112,7 +112,7 @@ final class Select implements EventInterface * * @var int */ - private int $selectTimeout = 800000; + private int $selectTimeout = self::MAX_SELECT_TIMOUT_US; /** * Next run time of the timer. @@ -126,6 +126,13 @@ final class Select implements EventInterface */ private $errorHandler = null; + /** + * Select timeout. + * + * @var int + */ + const MAX_SELECT_TIMOUT_US = 800000; + /** * Construct. */ @@ -359,11 +366,10 @@ protected function setNextTickTime(float $nextTickTime): void if ($nextTickTime == 0) { // Swow will affect the signal interruption characteristics of stream_select, // so a shorter timeout should be used to detect signals. - $this->selectTimeout = 800000; + $this->selectTimeout = self::MAX_SELECT_TIMOUT_US; return; } - $timeNow = microtime(true); - $this->selectTimeout = max((int)(($nextTickTime - $timeNow) * 1000000), 0); + $this->selectTimeout = min(max((int)(($nextTickTime - microtime(true)) * 1000000), 0), self::MAX_SELECT_TIMOUT_US); } /** From 9f11e98b7d7fcd874b49b0b9af8e2e33e2b5429c Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 4 Feb 2025 16:12:58 +0800 Subject: [PATCH 1116/1216] Coroutine examples --- README.md | 394 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 231 insertions(+), 163 deletions(-) diff --git a/README.md b/README.md index 384ed5c24..33de35c3f 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,12 @@ [![License](https://poser.pugx.org/workerman/workerman/license)](https://packagist.org/packages/workerman/workerman) ## What is it -Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. -Workerman supports HTTP, Websocket, SSL and other custom protocols. -Workerman supports event extension. +Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. It supports HTTP, WebSocket, custom protocols, coroutines, and connection pools, making it ideal for handling high-concurrency scenarios efficiently. ## Requires A POSIX compatible operating system (Linux, OSX, BSD) POSIX and PCNTL extensions required -Event extension recommended for better performance +Event/Swoole/Swow extension recommended for better performance ## Installation @@ -153,90 +151,6 @@ $ws_worker->onMessage = function ($connection, $data) { Worker::runAll(); ``` -### Custom protocol -Protocols/MyTextProtocol.php -```php - -namespace Protocols; - -/** - * User defined protocol - * Format Text+"\n" - */ -class MyTextProtocol -{ - public static function input($recv_buffer) - { - // Find the position of the first occurrence of "\n" - $pos = strpos($recv_buffer, "\n"); - - // Not a complete package. Return 0 because the length of package can not be calculated - if ($pos === false) { - return 0; - } - - // Return length of the package - return $pos + 1; - } - - public static function decode($recv_buffer) - { - return trim($recv_buffer); - } - - public static function encode($data) - { - return $data . "\n"; - } -} -``` - -```php -use Workerman\Worker; - -require_once __DIR__ . '/vendor/autoload.php'; - -// #### MyTextProtocol worker #### -$text_worker = new Worker('MyTextProtocol://0.0.0.0:5678'); - -$text_worker->onConnect = function ($connection) { - echo "New connection\n"; -}; - -$text_worker->onMessage = function ($connection, $data) { - // Send data to client - $connection->send("Hello world\n"); -}; - -$text_worker->onClose = function ($connection) { - echo "Connection closed\n"; -}; - -// Run all workers -Worker::runAll(); -``` - -### Timer -```php - -use Workerman\Worker; -use Workerman\Timer; - -require_once __DIR__ . '/vendor/autoload.php'; - -$task = new Worker(); -$task->onWorkerStart = function ($task) { - // 2.5 seconds - $time_interval = 2.5; - $timer_id = Timer::add($time_interval, function () { - echo "Timer run\n"; - }); -}; - -// Run all workers -Worker::runAll(); -``` - ### AsyncTcpConnection (tcp/ws/text/frame etc...) ```php @@ -267,112 +181,267 @@ $worker->onWorkerStart = function () { Worker::runAll(); ``` +### Coroutine - -#### Use HTTP proxy +Coroutine is used to create coroutines, enabling the execution of asynchronous tasks to improve concurrency performance. ```php onWorkerStart = function($worker){ - echo '开始链接' . PHP_EOL; - $url = 'ws://stream.binance.com:9443/ws'; - $con = new AsyncTcpConnection($url); - $con->transport = 'ssl'; -// $con->proxySocks5 = '127.0.0.1:1080'; - $con->proxyHttp = '127.0.0.1:25378'; - - $con->onConnect = function(AsyncTcpConnection $con) { - $ww = [ - 'id' => 1, - 'method' => 'SUBSCRIBE', - 'params' => [ - "btcusdt@aggTrade", - "btcusdt@depth" - ] - ]; - echo '链接成功'; - $con->send(json_encode($ww)); - echo 'ok'; - }; +$worker->eventLoop = Swoole::class; // Or Swow::class or Fiber::class - $con->onMessage = function(AsyncTcpConnection $con, $data) { - echo $data; - }; +$worker->onMessage = function (TcpConnection $connection, Request $request) { + Coroutine::create(function () { + echo file_get_contents("https://www.example.com/event/notify"); + }); + $connection->send('ok'); +}; - $con->onClose = function (AsyncTcpConnection $con) { - echo 'onClose' . PHP_EOL; - }; +Worker::runAll(); +``` - $con->onError = function (AsyncTcpConnection $con, $code, $msg) { - echo "error [ $code ] $msg\n"; - }; +> Note: Coroutine require Swoole extension or Swow extension or [Fiber revolt/event-loop](https://github.com/revoltphp/event-loop), and the same applies below + +### Barrier +Barrier is used to manage concurrency and synchronization in coroutines. It allows tasks to run concurrently and waits until all tasks are completed, ensuring process synchronization. + +```php +connect(); +// Http Server +$worker = new Worker('http://0.0.0.0:8001'); +$worker->eventLoop = Swoole::class; // Or Swow::class or Fiber::class +$worker->onMessage = function (TcpConnection $connection, Request $request) { + $barrier = Barrier::create(); + for ($i=1; $i<5; $i++) { + Coroutine::create(function () use ($barrier, $i) { + file_get_contents("http://127.0.0.1:8002?task_id=$i"); + }); + } + // Wait all coroutine done + Barrier::wait($barrier); + $connection->send('All Task Done'); }; -\Workerman\Worker::runAll(); + +// Task Server +$task = new Worker('http://0.0.0.0:8002'); +$task->onMessage = function (TcpConnection $connection, Request $request) { + $task_id = $request->get('task_id'); + $message = "Task $task_id Done"; + echo $message . PHP_EOL; + $connection->close($message); +}; + +Worker::runAll(); ``` +### Parallel +Parallel executes multiple tasks concurrently and collects results. Use add to add tasks and wait to wait for completion and get results. Unlike Barrier, Parallel directly returns the results of each task. +```php +eventLoop = Swoole::class; // Or Swow::class or Fiber::class +$worker->onMessage = function (TcpConnection $connection, Request $request) { + $parallel = new Parallel(); + for ($i=1; $i<5; $i++) { + $parallel->add(function () use ($i) { + return file_get_contents("http://127.0.0.1:8002?task_id=$i"); + }); + } + $results = $parallel->wait(); + $connection->send(json_encode($results)); // Response: ["Task 1 Done","Task 2 Done","Task 3 Done","Task 4 Done"] +}; -#### Use Socks5 proxy +// Task Server +$task = new Worker('http://0.0.0.0:8002'); +$task->onMessage = function (TcpConnection $connection, Request $request) { + $task_id = $request->get('task_id'); + $message = "Task $task_id Done"; + $connection->close($message); +}; + +Worker::runAll(); +``` + +### Channel + +Channel is a mechanism for communication between coroutines. One coroutine can push data into the channel, while another can pop data from it, enabling synchronization and data sharing between coroutines. ```php eventLoop = Swoole::class; // Or Swow::class or Fiber::class +$worker->onMessage = function (TcpConnection $connection, Request $request) { + $channel = new Channel(2); + Coroutine::create(function () use ($channel) { + $channel->push('Task 1 Done'); + }); + Coroutine::create(function () use ($channel) { + $channel->push('Task 2 Done'); + }); + $result = []; + for ($i = 0; $i < 2; $i++) { + $result[] = $channel->pop(); + } + $connection->send(json_encode($result)); // Response: ["Task 1 Done","Task 2 Done"] +}; +Worker::runAll(); +``` -use Workerman\Connection\AsyncTcpConnection; -$worker = new \Workerman\Worker(); -$worker->onWorkerStart = function($worker){ - echo '开始链接' . PHP_EOL; - $url = 'ws://stream.binance.com:9443/ws'; - $con = new AsyncTcpConnection($url); - $con->transport = 'ssl'; - $con->proxySocks5 = '127.0.0.1:1080'; -// $con->proxyHttp = '127.0.0.1:25378'; - - $con->onConnect = function(AsyncTcpConnection $con) { - $ww = [ - 'id' => 1, - 'method' => 'SUBSCRIBE', - 'params' => [ - "btcusdt@aggTrade", - "btcusdt@depth" - ] - ]; - echo '链接成功'; - $con->send(json_encode($ww)); - echo 'ok'; - }; +### Pool - $con->onMessage = function(AsyncTcpConnection $con, $data) { - echo $data; - }; +Pool is used to manage connection or resource pools, improving performance by reusing resources (e.g., database connections). It supports acquiring, returning, creating, and destroying resources. - $con->onClose = function (AsyncTcpConnection $con) { - echo 'onClose' . PHP_EOL; - }; +```php +onError = function (AsyncTcpConnection $con, $code, $msg) { - echo "error [ $code ] $msg\n"; - }; +class RedisPool +{ + private Pool $pool; + public function __construct($host, $port, $max_connections = 10) + { + $pool = new Pool($max_connections); + $pool->setConnectionCreator(function () use ($host, $port) { + $redis = new \Redis(); + $redis->connect($host, $port); + return $redis; + }); + $pool->setConnectionCloser(function ($redis) { + $redis->close(); + }); + $pool->setHeartbeatChecker(function ($redis) { + $redis->ping(); + }); + $this->pool = $pool; + } + public function get(): \Redis + { + return $this->pool->get(); + } + public function put($redis): void + { + $this->pool->put($redis); + } +} - $con->connect(); +// Http Server +$worker = new Worker('http://0.0.0.0:8001'); +$worker->eventLoop = Swoole::class; // Or Swow::class or Fiber::class +$worker->onMessage = function (TcpConnection $connection, Request $request) { + static $pool; + if (!$pool) { + $pool = new RedisPool('127.0.0.1', 6379, 10); + } + $redis = $pool->get(); + $redis->set('key', 'hello'); + $value = $redis->get('key'); + $pool->put($redis); + $connection->send($value); }; -\Workerman\Worker::runAll(); +Worker::runAll(); ``` +### Pool for automatic acquisition and release + +```php +get(); + Context::set('pdo', $pdo); + // When the coroutine is destroyed, return the connection to the pool + Coroutine::defer(function () use ($pdo) { + self::$pool->put($pdo); + }); + } + return call_user_func_array([$pdo, $name], $arguments); + } + private static function initializePool(): void + { + self::$pool = new Pool(10); + self::$pool->setConnectionCreator(function () { + return new \PDO('mysql:host=127.0.0.1;dbname=your_database', 'your_username', 'your_password'); + }); + self::$pool->setConnectionCloser(function ($pdo) { + $pdo = null; + }); + self::$pool->setHeartbeatChecker(function ($pdo) { + $pdo->query('SELECT 1'); + }); + } +} +// Http Server +$worker = new Worker('http://0.0.0.0:8001'); +$worker->eventLoop = Swoole::class; // Or Swow::class or Fiber::class +$worker->onMessage = function (TcpConnection $connection, Request $request) { + $value = Db::query('SELECT NOW() as now')->fetchAll(); + $connection->send(json_encode($value)); +}; +Worker::runAll(); +``` ## Available commands ```php start.php start ``` @@ -390,7 +459,6 @@ proxy supports TLS1.3, no Sniproxy channel https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r - ### Supported by [![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) From d325b248a91709d7f686fcc1922b61cfd2be1228 Mon Sep 17 00:00:00 2001 From: Fuzqing Date: Wed, 5 Feb 2025 00:04:55 +0800 Subject: [PATCH 1117/1216] Remove HHVM compatibility code Since HHVM no longer supports PHP and the dependencies have been updated. --- src/Connection/AsyncTcpConnection.php | 5 +---- src/Connection/TcpConnection.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 787b7aea8..0b9cc89d9 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -381,10 +381,7 @@ public function checkConnection(): void } // Nonblocking. stream_set_blocking($this->socket, false); - // Compatible with hhvm - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->socket, 0); - } + stream_set_read_buffer($this->socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $socket = socket_import_stream($this->socket); diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 71def175c..e396d9019 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -382,10 +382,7 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd } $this->socket = $socket; stream_set_blocking($this->socket, false); - // Compatible with hhvm - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->socket, 0); - } + stream_set_read_buffer($this->socket, 0); $this->eventLoop = $eventLoop; $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; From 520d10a9d7fddc8f411b726deee9a23f38b56adb Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 5 Feb 2025 21:46:39 +0800 Subject: [PATCH 1118/1216] Change Workerman\Coroutine\Coroutine to Workerman\Coroutine --- README.md | 10 +++++----- src/Worker.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 33de35c3f..58cc9a6e4 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Coroutine is used to create coroutines, enabling the execution of asynchronous t ```php eventLoop = Swoole::class; // Or Swow::class or Fiber::class $worker->onMessage = function (TcpConnection $connection, Request $request) { Coroutine::create(function () { - echo file_get_contents("https://www.example.com/event/notify"); + echo file_get_contents("http://www.example.com/event/notify"); }); $connection->send('ok'); }; @@ -217,7 +217,7 @@ Barrier is used to manage concurrency and synchronization in coroutines. It allo Date: Wed, 5 Feb 2025 22:12:49 +0800 Subject: [PATCH 1119/1216] require workerman/coroutine 1.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 98865c2a3..8fd345245 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "require": { "php": ">=8.1", "ext-json": "*", - "workerman/coroutine": "^1.0 || dev-main" + "workerman/coroutine": "^1.1 || dev-main" }, "suggest": { "ext-event": "For better performance. " From af55e500edc094255345729cdd35920896ee6d26 Mon Sep 17 00:00:00 2001 From: Fuzqing Date: Tue, 11 Feb 2025 13:34:49 +0800 Subject: [PATCH 1120/1216] Create bug_report.md Add ISSUE THEMPLATE --- .github/ISSUE_TEMPLATE/bug_report.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..a9897aa68 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +Please answer these questions before submitting your issue. + +1. What did you do? If possible, provide a simple script for reproducing the error. + + + +2. What did you expect to see? + + + +3. What did you see instead? + + + +4. What version of Workerman are you using (show your `composer info`)? + + + +5. What is your machine environment used (show your `uname -a` & `php -v` & `php -m`) ? + From 0c4bf47925f4c10b64b8ca2d10ced4d488bfeee6 Mon Sep 17 00:00:00 2001 From: Fuzqing Date: Tue, 11 Feb 2025 13:35:47 +0800 Subject: [PATCH 1121/1216] Create issue template config.yml --- .github/ISSUE_TEMPLATE/config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..6d9c7c4ea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +default: bug_report.md From a0cd3d479629f8ef8d6b3947772c5f6ef6f1f34b Mon Sep 17 00:00:00 2001 From: Fuzqing Date: Tue, 11 Feb 2025 13:40:27 +0800 Subject: [PATCH 1122/1216] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a9897aa68..3edede23f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,3 +1,10 @@ +--- +name: Bug Report +about: 报告一个 bug +title: "[BUG]" +labels: bug +--- + Please answer these questions before submitting your issue. 1. What did you do? If possible, provide a simple script for reproducing the error. From 5a4e59e05bdc865a782d27ec85852dfb43a8fc38 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 13 Mar 2025 17:53:15 +0800 Subject: [PATCH 1123/1216] Fix mime wasm --- src/Protocols/Http/mime.types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/mime.types b/src/Protocols/Http/mime.types index 57699149b..30aad832f 100644 --- a/src/Protocols/Http/mime.types +++ b/src/Protocols/Http/mime.types @@ -8,7 +8,7 @@ types { application/javascript js; application/atom+xml atom; application/rss+xml rss; - application/wasm wasm; + application/wasm wasm; text/mathml mml; text/plain txt; From 43695c4b1f5980a1a5e4b46d6547d23c0993bce0 Mon Sep 17 00:00:00 2001 From: Seyed mohammadreza seyed esmaeil <32652363+seyedmr@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:22:59 +0330 Subject: [PATCH 1124/1216] remove gc --- src/Worker.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index c3e4957da..e92816231 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2180,9 +2180,6 @@ protected static function writeStatisticsToStatusFile(): void return; } - // For child processes. - gc_collect_cycles(); - gc_mem_caches(); reset(static::$workers); /** @var static $worker */ $worker = current(static::$workers); From 8cad9295fca9fcb7dd1b70ef38fa01fb235ae55f Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 1 Apr 2025 17:37:14 +0800 Subject: [PATCH 1125/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index e396d9019..bbb4e5c36 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -23,6 +23,7 @@ use Workerman\Events\Event; use Workerman\Events\EventInterface; use Workerman\Events\Select; +use Workerman\Protocols\Http; use Workerman\Protocols\Http\Request; use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; @@ -668,8 +669,9 @@ public function baseRead($socket, bool $checkEof = true): void if ($this->recvBuffer === '') { if (!isset($buffer[static::MAX_CACHE_STRING_LENGTH]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; - $request = $requests[$buffer]; - if ($request instanceof Request) { + if ($this->protocol === Http::class) { + $request = static::$reuseRequest ? $requests[$buffer] : clone $requests[$buffer]; + $request->destroy(); $request->connection = $this; $this->request = $request; try { @@ -677,9 +679,12 @@ public function baseRead($socket, bool $checkEof = true): void } catch (Throwable $e) { $this->error($e); } - $request->destroy(); - $requests[$buffer] = static::$reuseRequest ? $request : clone $request; + if (!isset($requests[$buffer])) { + $requests[$buffer] = $request; + } return; + } else { + $request = $requests[$buffer]; } try { ($this->onMessage)($this, $request); From c1e90e4146fafcb14450ea0a2a2b0f475110494a Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Apr 2025 21:21:28 +0800 Subject: [PATCH 1126/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index e92816231..6fd989f47 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -60,7 +60,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.0'; + final public const VERSION = '5.1.1'; /** * Status initial. From 8677c74baba959d97806a95b0757f2bccc10783c Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Apr 2025 21:22:39 +0800 Subject: [PATCH 1127/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index bbb4e5c36..43b1186ee 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -670,7 +670,7 @@ public function baseRead($socket, bool $checkEof = true): void if (!isset($buffer[static::MAX_CACHE_STRING_LENGTH]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; if ($this->protocol === Http::class) { - $request = static::$reuseRequest ? $requests[$buffer] : clone $requests[$buffer]; + $request = clone $requests[$buffer]; $request->destroy(); $request->connection = $this; $this->request = $request; From 0538407636020f4a54d91b570f2e2103d5724ea8 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Apr 2025 21:25:17 +0800 Subject: [PATCH 1128/1216] Update Worker.php --- src/Worker.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 6fd989f47..fd9f127e2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1729,9 +1729,6 @@ protected static function forkOneWorkerForLinux(self $worker): void // Init Timer. Timer::init(static::$globalEvent); - // Init TcpConnection. - TcpConnection::init(); - restore_error_handler(); static::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); From 2a72182f50d92e5b30cc2e6a111e0b1cb47fc732 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Apr 2025 21:25:53 +0800 Subject: [PATCH 1129/1216] Update TcpConnection.php --- src/Connection/TcpConnection.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 43b1186ee..ea21b949b 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -346,14 +346,6 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public static array $connections = []; - - /** - * Reuse request. - * - * @var bool - */ - protected static bool $reuseRequest = false; - /** * Status to string. * @@ -1087,16 +1079,6 @@ public function destroy(): void } } - /** - * Init. - * - * @return void - */ - public static function init(): void - { - static::$reuseRequest = in_array(get_class(Worker::$globalEvent), [Event::class, Select::class, Ev::class]); - } - /** * Get the json_encode information. * From 72cafa19e488896abd2576ea67b3b1af1abf71c0 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 2 Apr 2025 22:01:24 +0800 Subject: [PATCH 1130/1216] Update --- src/Connection/TcpConnection.php | 8 ++------ src/Worker.php | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index ea21b949b..8ccc869f0 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -671,13 +671,9 @@ public function baseRead($socket, bool $checkEof = true): void } catch (Throwable $e) { $this->error($e); } - if (!isset($requests[$buffer])) { - $requests[$buffer] = $request; - } return; - } else { - $request = $requests[$buffer]; } + $request = $requests[$buffer]; try { ($this->onMessage)($this, $request); } catch (Throwable $e) { @@ -744,8 +740,8 @@ public function baseRead($socket, bool $checkEof = true): void if ((!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { ($this->onMessage)($this, $request); if ($request instanceof Request) { - $request->destroy(); $requests[$oneRequestBuffer] = clone $request; + $requests[$oneRequestBuffer]->destroy(); } else { $requests[$oneRequestBuffer] = $request; } diff --git a/src/Worker.php b/src/Worker.php index fd9f127e2..e2d5f20ba 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -872,6 +872,7 @@ protected static function initWorkers(): void // Listen. if (!$worker->reusePort) { $worker->listen(); + $worker->pauseAccept(); } } } From a4d831643d894b80d61a9d77e97cab0f5d8cfb21 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Wed, 9 Apr 2025 13:05:41 +0300 Subject: [PATCH 1131/1216] Improved onWebSocketClose with response message. --- src/Protocols/Ws.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index e958b70eb..e2d8abb18 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -116,7 +116,7 @@ public static function input(string $buffer, AsyncTcpConnection $connection): in // Try to emit onWebSocketClose callback. if (isset($connection->onWebSocketClose)) { try { - ($connection->onWebSocketClose)($connection); + ($connection->onWebSocketClose)($connection, self::decode($buffer, $connection)); } catch (Throwable $e) { Worker::stopAll(250, $e); } From d80eb0d92f34e7b51f4d9a4f32b6be34ff2064b8 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Wed, 9 Apr 2025 13:19:12 +0300 Subject: [PATCH 1132/1216] Added missing WS callable to TCP connection class. --- src/Connection/TcpConnection.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 8ccc869f0..aef42ac91 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -133,19 +133,26 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable public $onConnect = null; /** - * Emitted before websocket handshake (Only works when protocol is ws). + * Emitted before websocket handshake (Only called when protocol is ws). * * @var ?callable */ public $onWebSocketConnect = null; /** - * Emitted after websocket handshake (Only works when protocol is ws). + * Emitted after websocket handshake (Only called when protocol is ws). * * @var ?callable */ public $onWebSocketConnected = null; + /** + * Emitted when websocket connection is closed (Only called when protocol is ws). + * + * @var ?callable + */ + public $onWebSocketClose = null; + /** * Emitted when data is received. * From dfa551bbcb7ea8d9ee56cc942efcfede714cdee2 Mon Sep 17 00:00:00 2001 From: chaz6chez Date: Thu, 17 Apr 2025 15:41:35 +0800 Subject: [PATCH 1133/1216] 1. TcpConnection add properties websocketOrigin & websocketClientProtocol 2. Protocols/Ws::onConnect init websocketOrigin & websocketClientProtocol 3. Protocols/Websocket::input init websocketOrigin & websocketClientProtocol --- src/Connection/TcpConnection.php | 2 ++ src/Protocols/Websocket.php | 2 ++ src/Protocols/Ws.php | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index aef42ac91..175e64b8d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -61,6 +61,8 @@ /** * TcpConnection. * @property string $websocketType + * @property string|null websocketClientProtocol + * @property string|null websocketOrigin */ class TcpConnection extends ConnectionInterface implements JsonSerializable { diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 89b44d47f..9a5b33c03 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -84,6 +84,8 @@ class Websocket */ public static function input(string $buffer, TcpConnection $connection): int { + $connection->websocketOrigin = $connection->websocketOrigin ?? null; + $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; // Receive length. $recvLen = strlen($buffer); // We need more data. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index e2d8abb18..e51113e46 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -323,6 +323,8 @@ public static function decode(string $bytes, AsyncTcpConnection $connection): st */ public static function onConnect(AsyncTcpConnection $connection): void { + $connection->websocketOrigin = $connection->websocketOrigin ?? null; + $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; static::sendHandshake($connection); } @@ -372,8 +374,8 @@ public static function sendHandshake(AsyncTcpConnection $connection): void (!preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . - (isset($connection->websocketOrigin) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . - (isset($connection->websocketClientProtocol) ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . + ($connection?->websocketOrigin ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . + ($connection?->websocketClientProtocol ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . "Sec-WebSocket-Key: " . $connection->context->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); From 4c5b4d45e4764a3c2aa6047ee1f00e1640d58b54 Mon Sep 17 00:00:00 2001 From: chaz6chez Date: Thu, 17 Apr 2025 16:14:18 +0800 Subject: [PATCH 1134/1216] fix --- src/Protocols/Websocket.php | 4 ++-- src/Protocols/Ws.php | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 9a5b33c03..253f11908 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -84,8 +84,8 @@ class Websocket */ public static function input(string $buffer, TcpConnection $connection): int { - $connection->websocketOrigin = $connection->websocketOrigin ?? null; - $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; + $connection->websocketOrigin = $connection?->websocketOrigin; + $connection->websocketClientProtocol = $connection?->websocketClientProtocol; // Receive length. $recvLen = strlen($buffer); // We need more data. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index e51113e46..275f78467 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -239,6 +239,8 @@ public static function encode(string $payload, AsyncTcpConnection $connection): if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } + $connection->websocketOrigin = $connection->websocketOrigin ?? null; + $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; if (empty($connection->context->handshakeStep)) { static::sendHandshake($connection); } @@ -323,8 +325,8 @@ public static function decode(string $bytes, AsyncTcpConnection $connection): st */ public static function onConnect(AsyncTcpConnection $connection): void { - $connection->websocketOrigin = $connection->websocketOrigin ?? null; - $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; + $connection->websocketOrigin = $connection?->websocketOrigin; + $connection->websocketClientProtocol = $connection?->websocketClientProtocol; static::sendHandshake($connection); } From 801656bfcff244c1c5be5b7bfe0cb66b7bcb2e1e Mon Sep 17 00:00:00 2001 From: chaz6chez Date: Thu, 17 Apr 2025 16:20:59 +0800 Subject: [PATCH 1135/1216] fix --- src/Connection/TcpConnection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 175e64b8d..b66f617a1 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -61,8 +61,8 @@ /** * TcpConnection. * @property string $websocketType - * @property string|null websocketClientProtocol - * @property string|null websocketOrigin + * @property string|null $websocketClientProtocol + * @property string|null $websocketOrigin */ class TcpConnection extends ConnectionInterface implements JsonSerializable { From 9bc8254af7a41b5ae27ad0d991ee1d2c62f5a61a Mon Sep 17 00:00:00 2001 From: chaz6chez Date: Thu, 17 Apr 2025 16:28:07 +0800 Subject: [PATCH 1136/1216] fix --- src/Protocols/Websocket.php | 4 ++-- src/Protocols/Ws.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 253f11908..9a5b33c03 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -84,8 +84,8 @@ class Websocket */ public static function input(string $buffer, TcpConnection $connection): int { - $connection->websocketOrigin = $connection?->websocketOrigin; - $connection->websocketClientProtocol = $connection?->websocketClientProtocol; + $connection->websocketOrigin = $connection->websocketOrigin ?? null; + $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; // Receive length. $recvLen = strlen($buffer); // We need more data. diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 275f78467..199c7c998 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -325,8 +325,8 @@ public static function decode(string $bytes, AsyncTcpConnection $connection): st */ public static function onConnect(AsyncTcpConnection $connection): void { - $connection->websocketOrigin = $connection?->websocketOrigin; - $connection->websocketClientProtocol = $connection?->websocketClientProtocol; + $connection->websocketOrigin = $connection->websocketOrigin ?? null; + $connection->websocketClientProtocol = $connection->websocketClientProtocol ?? null; static::sendHandshake($connection); } @@ -376,8 +376,8 @@ public static function sendHandshake(AsyncTcpConnection $connection): void (!preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . - ($connection?->websocketOrigin ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . - ($connection?->websocketClientProtocol ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . + (($connection->websocketOrigin ?? null) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . + (($connection->websocketClientProtocol ?? null) ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . "Sec-WebSocket-Key: " . $connection->context->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); From f2ecd69b799560c290ccef9d247795046f255a98 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 6 May 2025 13:05:26 +0200 Subject: [PATCH 1137/1216] Fix typo change Jit for JIT [ci skip] The correct acronim is JIT. And it's a very good addition this information. --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index e2d5f20ba..edfea4137 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1009,7 +1009,7 @@ protected static function getVersionLine(): string //Show version $jitStatus = function_exists('opcache_get_status') && (opcache_get_status()['jit']['on'] ?? false) === true ? 'on' : 'off'; $version = str_pad('Workerman/' . static::VERSION, 24); - $version .= str_pad('PHP/' . PHP_VERSION . ' (Jit ' . $jitStatus . ')', 30); + $version .= str_pad('PHP/' . PHP_VERSION . ' (JIT ' . $jitStatus . ')', 30); $version .= php_uname('s') . '/' . php_uname('r') . PHP_EOL; return $version; } From fed35d859158905f71001e0a9c4949db4f730bbb Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 4 Jun 2025 09:54:50 +0800 Subject: [PATCH 1138/1216] Fix timer inaccuracy issue for Select event. --- src/Events/Select.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index db712b90a..d323c0ba5 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -423,8 +423,12 @@ public function run(): void } } - if ($this->nextTickTime > 0 && microtime(true) >= $this->nextTickTime) { - $this->tick(); + if ($this->nextTickTime > 0) { + if (microtime(true) >= $this->nextTickTime) { + $this->tick(); + } else { + $this->selectTimeout = (int)(($this->nextTickTime - microtime(true)) * 1000000); + } } // The $this->signalEvents are empty under Windows, make sure not to call pcntl_signal_dispatch. From c61641d9ce14a980bce287ec014b1d17a32cb8fa Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 4 Jun 2025 09:56:48 +0800 Subject: [PATCH 1139/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index edfea4137..33ee28959 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -60,7 +60,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.1'; + final public const VERSION = '5.1.2'; /** * Status initial. From 2ed1e0bf4f36a681c527a277e440d3a984896f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sat, 7 Jun 2025 19:58:54 +0800 Subject: [PATCH 1140/1216] Destroy the context in onWorkerStart --- src/Worker.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Worker.php b/src/Worker.php index 33ee28959..9103ed36c 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -26,6 +26,7 @@ use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; use Workerman\Coroutine; +use Workerman\Coroutine\Context; use Workerman\Events\Event; use Workerman\Events\EventInterface; use Workerman\Events\Fiber; @@ -2568,6 +2569,8 @@ public function run(): void // Avoid rapid infinite loop exit. sleep(1); static::stopAll(250, $e); + } finally { + Context::destroy(); } }; From 371f3a5decb28f1bd3464ae26d47ea1a4cf0a3c5 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 12 Jun 2025 21:34:04 +0800 Subject: [PATCH 1141/1216] Fix Swow first request hang on Windows --- src/Events/Select.php | 2 -- src/Events/Swow.php | 2 +- src/Worker.php | 14 ++++++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Events/Select.php b/src/Events/Select.php index d323c0ba5..b14b135d7 100644 --- a/src/Events/Select.php +++ b/src/Events/Select.php @@ -364,8 +364,6 @@ protected function setNextTickTime(float $nextTickTime): void { $this->nextTickTime = $nextTickTime; if ($nextTickTime == 0) { - // Swow will affect the signal interruption characteristics of stream_select, - // so a shorter timeout should be used to detect signals. $this->selectTimeout = self::MAX_SELECT_TIMOUT_US; return; } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index ab07be9d2..a1b541218 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -144,10 +144,10 @@ public function onReadable($stream, callable $func): void } // Under Windows, setting a timeout is necessary; otherwise, the accept cannot be listened to. // Setting it to 1000ms will result in a 1-second delay for the first accept under Windows. - $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP, 1000); if (!isset($this->readEvents[$fd]) || $this->readEvents[$fd] !== Coroutine::getCurrent()) { break; } + $rEvent = stream_poll_one($stream, STREAM_POLLIN | STREAM_POLLHUP, 1000); if ($rEvent !== STREAM_POLLNONE) { $this->safeCall($func, [$stream]); } diff --git a/src/Worker.php b/src/Worker.php index 9103ed36c..3c694aa0f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.2'; + final public const VERSION = '5.1.3'; /** * Status initial. @@ -1594,7 +1594,17 @@ protected static function forkWorkersForWindows(): void restore_error_handler(); // Add an empty timer to prevent the event-loop from exiting. - Timer::add(1000000, function (){}); + Timer::add(0.8, function (){}); + + // Compatibility with the bug in Swow where the first request on Windows fails to trigger stream_select. + if (extension_loaded('swow')) { + Timer::delay(0.1 , function(){ + $stream = fopen(__FILE__, 'r'); + static::$globalEvent->onReadable($stream, function($stream) { + static::$globalEvent->offReadable($stream); + }); + }); + } // Display UI. static::safeEcho(str_pad($worker->name, 48) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . " [ok]\n"); From b68df657b54a0aa853aa0e4597a75c34129634d2 Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Wed, 18 Jun 2025 14:22:54 +0300 Subject: [PATCH 1142/1216] Implemented max log file size with truncation. --- src/Worker.php | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 3c694aa0f..75b965a6f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -322,6 +322,13 @@ class Worker */ public static string $logFile = ''; + /** + * Log file maximum size in bytes, default 10M. + * + * @var int + */ + public static int $logFileMaxSize = 10_485_760; + /** * Global event loop. * @@ -330,7 +337,7 @@ class Worker public static ?EventInterface $globalEvent = null; /** - * Emitted when the master process get reload signal. + * Emitted when the master process gets a reload signal. * * @var ?callable */ @@ -2342,6 +2349,46 @@ public static function log(Stringable|string $msg, bool $decorated = false): voi if (isset(static::$logFile)) { $pid = DIRECTORY_SEPARATOR === '/' ? posix_getpid() : 1; file_put_contents(static::$logFile, sprintf("%s pid:%d %s\n", date('Y-m-d H:i:s'), $pid, $msg), FILE_APPEND | LOCK_EX); + + // Check the file size and truncate if it exceeds max size + if (!empty(static::$logFileMaxSize) && ($fileSize = filesize(static::$logFile)) > static::$logFileMaxSize) { + $newFile = static::$logFile . '.tmp'; + + // Open files + $source = fopen(static::$logFile, 'r'); + if (!flock($source, LOCK_EX)) { + fclose($source); + return; + } + $destination = fopen($newFile, 'w'); + + if ($source && $destination) { + // Move to the halfway point in the source file + $halfwayPoint = (int)($fileSize / 2); + fseek($source, $halfwayPoint); + + // Find the next newline character to ensure we don't cut in the middle of a line + while (($char = fgetc($source)) !== false) { + if ($char === "\n") { + break; + } + } + + // Copy the second half into the new file + while (!feof($source)) { + fwrite($destination, fread($source, 8192)); // Read and write 8KB chunks + } + + // Replace the old file with the new truncated file + rename($newFile, static::$logFile); + } + // Close both files + if ($source) { + flock($source, LOCK_UN); + fclose($source); + } + if ($destination) fclose($destination); + } } } From 85405c6d70d82b5810bf8479064f8465324b613d Mon Sep 17 00:00:00 2001 From: Ako Tulu Date: Thu, 19 Jun 2025 01:10:57 +0300 Subject: [PATCH 1143/1216] Improved max log file size handling. --- src/Worker.php | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 75b965a6f..dbef4b2c2 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2352,42 +2352,48 @@ public static function log(Stringable|string $msg, bool $decorated = false): voi // Check the file size and truncate if it exceeds max size if (!empty(static::$logFileMaxSize) && ($fileSize = filesize(static::$logFile)) > static::$logFileMaxSize) { - $newFile = static::$logFile . '.tmp'; - // Open files $source = fopen(static::$logFile, 'r'); - if (!flock($source, LOCK_EX)) { + + if (!$source) { + return; + } else if (!flock($source, LOCK_EX)) { fclose($source); return; } + + $newFile = static::$logFile . '.tmp'; $destination = fopen($newFile, 'w'); - if ($source && $destination) { - // Move to the halfway point in the source file - $halfwayPoint = (int)($fileSize / 2); - fseek($source, $halfwayPoint); + if (!$destination) { + flock($source, LOCK_UN); + fclose($source); + return; + } - // Find the next newline character to ensure we don't cut in the middle of a line - while (($char = fgetc($source)) !== false) { - if ($char === "\n") { - break; - } - } + // Move to the halfway point in the source file + $halfwayPoint = (int)($fileSize / 2); + fseek($source, $halfwayPoint); - // Copy the second half into the new file - while (!feof($source)) { - fwrite($destination, fread($source, 8192)); // Read and write 8KB chunks + // Find the next newline character to ensure we don't cut in the middle of a line + while (($char = fgetc($source)) !== false) { + if ($char === "\n") { + break; } + } - // Replace the old file with the new truncated file - rename($newFile, static::$logFile); + // Copy the second half into the new file + while (!feof($source)) { + fwrite($destination, fread($source, 8192)); // Read and write 8KB chunks } + + // Replace the old file with the new truncated file + rename($newFile, static::$logFile); + // Close both files - if ($source) { - flock($source, LOCK_UN); - fclose($source); - } - if ($destination) fclose($destination); + flock($source, LOCK_UN); + fclose($source); + fclose($destination); } } } From fd70b5b4e3b3e30d228abd0eefe25e6b95299a4d Mon Sep 17 00:00:00 2001 From: tourze Date: Wed, 25 Jun 2025 23:42:16 +0800 Subject: [PATCH 1144/1216] refactor: Replace dynamic MIME type loading with static array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 MIME 类型映射从动态文件加载改为静态数组定义,带来以下好处: - 消除运行时文件 I/O 操作,提升启动性能 - 减少文件系统依赖,提高代码可移植性 - 简化代码维护,MIME 类型映射直接可见 - 避免文件读取失败的潜在风险 - 减少不必要的函数导入 删除了 mime.types 文件和 initMimeTypeMap() 方法,将所有 MIME 类型 映射直接定义在 $mimeTypeMap 静态数组中。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/Protocols/Http/Response.php | 136 +++++++++++++++++++++++++------- src/Protocols/Http/mime.types | 91 --------------------- 2 files changed, 108 insertions(+), 119 deletions(-) delete mode 100644 src/Protocols/Http/mime.types diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index a54c18433..b6c918feb 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -19,19 +19,13 @@ use Stringable; use function array_merge_recursive; -use function explode; -use function file; use function filemtime; use function gmdate; use function is_array; use function is_file; use function pathinfo; -use function preg_match; use function rawurlencode; use function strlen; -use function substr; -use const FILE_IGNORE_NEW_LINES; -use const FILE_SKIP_EMPTY_LINES; /** * Class Response @@ -65,7 +59,113 @@ class Response implements Stringable * Mine type map. * @var array */ - protected static array $mimeTypeMap = []; + protected static array $mimeTypeMap = [ + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'css' => 'text/css', + 'xml' => 'text/xml', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'js' => 'application/javascript', + 'atom' => 'application/atom+xml', + 'rss' => 'application/rss+xml', + 'wasm' => 'application/wasm', + 'mml' => 'text/mathml', + 'txt' => 'text/plain', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'wml' => 'text/vnd.wap.wml', + 'htc' => 'text/x-component', + 'png' => 'image/png', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'wbmp' => 'image/vnd.wap.wbmp', + 'ico' => 'image/x-icon', + 'jng' => 'image/x-jng', + 'bmp' => 'image/x-ms-bmp', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'webp' => 'image/webp', + 'woff' => 'application/font-woff', + 'jar' => 'application/java-archive', + 'war' => 'application/java-archive', + 'ear' => 'application/java-archive', + 'json' => 'application/json', + 'hqx' => 'application/mac-binhex40', + 'doc' => 'application/msword', + 'pdf' => 'application/pdf', + 'ps' => 'application/postscript', + 'eps' => 'application/postscript', + 'ai' => 'application/postscript', + 'rtf' => 'application/rtf', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'xls' => 'application/vnd.ms-excel', + 'eot' => 'application/vnd.ms-fontobject', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wmlc' => 'application/vnd.wap.wmlc', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + '7z' => 'application/x-7z-compressed', + 'cco' => 'application/x-cocoa', + 'jardiff' => 'application/x-java-archive-diff', + 'jnlp' => 'application/x-java-jnlp-file', + 'run' => 'application/x-makeself', + 'pl' => 'application/x-perl', + 'pm' => 'application/x-perl', + 'prc' => 'application/x-pilot', + 'pdb' => 'application/x-pilot', + 'rar' => 'application/x-rar-compressed', + 'rpm' => 'application/x-redhat-package-manager', + 'sea' => 'application/x-sea', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tcl' => 'application/x-tcl', + 'tk' => 'application/x-tcl', + 'der' => 'application/x-x509-ca-cert', + 'pem' => 'application/x-x509-ca-cert', + 'crt' => 'application/x-x509-ca-cert', + 'xpi' => 'application/x-xpinstall', + 'xhtml' => 'application/xhtml+xml', + 'xspf' => 'application/xspf+xml', + 'zip' => 'application/zip', + 'bin' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'deb' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'iso' => 'application/octet-stream', + 'img' => 'application/octet-stream', + 'msi' => 'application/octet-stream', + 'msp' => 'application/octet-stream', + 'msm' => 'application/octet-stream', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'kar' => 'audio/midi', + 'mp3' => 'audio/mpeg', + 'ogg' => 'audio/ogg', + 'm4a' => 'audio/x-m4a', + 'ra' => 'audio/x-realaudio', + '3gpp' => 'video/3gpp', + '3gp' => 'video/3gpp', + 'ts' => 'video/mp2t', + 'mp4' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mov' => 'video/quicktime', + 'webm' => 'video/webm', + 'flv' => 'video/x-flv', + 'm4v' => 'video/x-m4v', + 'mng' => 'video/x-mng', + 'asx' => 'video/x-ms-asf', + 'asf' => 'video/x-ms-asf', + 'wmv' => 'video/x-ms-wmv', + 'avi' => 'video/x-msvideo', + 'ttf' => 'font/ttf', + ]; /** * Phrases. @@ -151,7 +251,7 @@ class Response implements Stringable */ public static function init(): void { - static::initMimeTypeMap(); + // Mime types are now statically defined } /** @@ -450,26 +550,6 @@ public function __toString(): string return $head . $this->body; } - /** - * Init mime map. - * - * @return void - */ - public static function initMimeTypeMap(): void - { - $mimeFile = __DIR__ . '/mime.types'; - $items = file($mimeFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - foreach ($items as $content) { - if (preg_match("/\s*(\S+)\s+(\S.+)/", $content, $match)) { - $mimeType = $match[1]; - $extensionVar = $match[2]; - $extensionArray = explode(' ', substr($extensionVar, 0, -1)); - foreach ($extensionArray as $fileExtension) { - static::$mimeTypeMap[$fileExtension] = $mimeType; - } - } - } - } } Response::init(); diff --git a/src/Protocols/Http/mime.types b/src/Protocols/Http/mime.types deleted file mode 100644 index 30aad832f..000000000 --- a/src/Protocols/Http/mime.types +++ /dev/null @@ -1,91 +0,0 @@ - -types { - text/html html htm shtml; - text/css css; - text/xml xml; - image/gif gif; - image/jpeg jpeg jpg; - application/javascript js; - application/atom+xml atom; - application/rss+xml rss; - application/wasm wasm; - - text/mathml mml; - text/plain txt; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/x-component htc; - - image/png png; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; - image/svg+xml svg svgz; - image/webp webp; - - application/font-woff woff; - application/java-archive jar war ear; - application/json json; - application/mac-binhex40 hqx; - application/msword doc; - application/pdf pdf; - application/postscript ps eps ai; - application/rtf rtf; - application/vnd.apple.mpegurl m3u8; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.wap.wmlc wmlc; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-perl pl pm; - application/x-pilot prc pdb; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert der pem crt; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xspf+xml xspf; - application/zip zip; - - application/octet-stream bin exe dll; - application/octet-stream deb; - application/octet-stream dmg; - application/octet-stream iso img; - application/octet-stream msi msp msm; - - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; - - audio/midi mid midi kar; - audio/mpeg mp3; - audio/ogg ogg; - audio/x-m4a m4a; - audio/x-realaudio ra; - - video/3gpp 3gpp 3gp; - video/mp2t ts; - video/mp4 mp4; - video/mpeg mpeg mpg; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-m4v m4v; - video/x-mng mng; - video/x-ms-asf asx asf; - video/x-ms-wmv wmv; - video/x-msvideo avi; - font/ttf ttf; -} From bb55453e8d4b454feddfc9a2b249f42a9d0099da Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 28 Jun 2025 14:50:54 +0800 Subject: [PATCH 1145/1216] Add avif mime type --- src/Protocols/Http/Response.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index b6c918feb..154b7e589 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -87,6 +87,7 @@ class Response implements Stringable 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', 'webp' => 'image/webp', + 'avif' => 'image/avif', 'woff' => 'application/font-woff', 'jar' => 'application/java-archive', 'war' => 'application/java-archive', From df13b9c2383dcba860d5fe101316d72c34d29984 Mon Sep 17 00:00:00 2001 From: joanhey Date: Tue, 1 Jul 2025 12:28:25 +0200 Subject: [PATCH 1146/1216] Separate myme types --- src/Protocols/Http/Response.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 154b7e589..624ab196c 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -60,23 +60,22 @@ class Response implements Stringable * @var array */ protected static array $mimeTypeMap = [ + // text 'html' => 'text/html', 'htm' => 'text/html', 'shtml' => 'text/html', 'css' => 'text/css', 'xml' => 'text/xml', - 'gif' => 'image/gif', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'js' => 'application/javascript', - 'atom' => 'application/atom+xml', - 'rss' => 'application/rss+xml', - 'wasm' => 'application/wasm', 'mml' => 'text/mathml', 'txt' => 'text/plain', 'jad' => 'text/vnd.sun.j2me.app-descriptor', 'wml' => 'text/vnd.wap.wml', 'htc' => 'text/x-component', + + // image + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', 'png' => 'image/png', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', @@ -88,6 +87,12 @@ class Response implements Stringable 'svgz' => 'image/svg+xml', 'webp' => 'image/webp', 'avif' => 'image/avif', + + // application + 'js' => 'application/javascript', + 'atom' => 'application/atom+xml', + 'rss' => 'application/rss+xml', + 'wasm' => 'application/wasm', 'woff' => 'application/font-woff', 'jar' => 'application/java-archive', 'war' => 'application/java-archive', @@ -143,6 +148,8 @@ class Response implements Stringable 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + + // audio 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'kar' => 'audio/midi', @@ -150,6 +157,8 @@ class Response implements Stringable 'ogg' => 'audio/ogg', 'm4a' => 'audio/x-m4a', 'ra' => 'audio/x-realaudio', + + // video '3gpp' => 'video/3gpp', '3gp' => 'video/3gpp', 'ts' => 'video/mp2t', @@ -165,6 +174,8 @@ class Response implements Stringable 'asf' => 'video/x-ms-asf', 'wmv' => 'video/x-ms-wmv', 'avi' => 'video/x-msvideo', + + // font 'ttf' => 'font/ttf', ]; From 6cb2c9aa344951787a115c8d425cb6aa16b69a04 Mon Sep 17 00:00:00 2001 From: joanhey Date: Tue, 1 Jul 2025 12:33:49 +0200 Subject: [PATCH 1147/1216] Change font woff and add woff2 --- src/Protocols/Http/Response.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 624ab196c..e3fb10874 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -93,7 +93,6 @@ class Response implements Stringable 'atom' => 'application/atom+xml', 'rss' => 'application/rss+xml', 'wasm' => 'application/wasm', - 'woff' => 'application/font-woff', 'jar' => 'application/java-archive', 'war' => 'application/java-archive', 'ear' => 'application/java-archive', @@ -177,6 +176,8 @@ class Response implements Stringable // font 'ttf' => 'font/ttf', + 'woff' => 'font/woff', + 'woff2' => 'font/woff2', ]; /** From e452e220cad087d16c92095eb863d06df1d8b922 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Tue, 8 Jul 2025 01:26:50 +0200 Subject: [PATCH 1148/1216] Change switch() for match() --- src/Worker.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index e92816231..ee9df1400 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2573,15 +2573,13 @@ public function run(): void } }; - switch (Worker::$eventLoopClass) { - case Swoole::class: - case Swow::class: - case Fiber::class: - Coroutine::create($callback); - break; - default: - (new \Fiber($callback))->start(); - } + match (Worker::$eventLoopClass) { + Swoole::class, + Swow::class, + Fiber::class => Coroutine::create($callback), + + default => (new \Fiber($callback))->start(), + }; } /** From 8dadbe74a0a563aa2506b05bc950e103dde87e75 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 9 Jul 2025 23:05:32 +0800 Subject: [PATCH 1149/1216] Check valid stream resource --- src/Connection/AsyncTcpConnection.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index 0b9cc89d9..ae50a27f6 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -379,6 +379,16 @@ public function checkConnection(): void fwrite($this->socket, $str); fread($this->socket, 512); } + if (!is_resource($this->socket)) { + $this->emitError(static::CONNECT_FAIL, 'connect ' . $this->remoteAddress . ' fail after ' . round(microtime(true) - $this->connectStartTime, 4) . ' seconds'); + if ($this->status === self::STATUS_CLOSING) { + $this->destroy(); + } + if ($this->status === self::STATUS_CLOSED) { + $this->onConnect = null; + } + return; + } // Nonblocking. stream_set_blocking($this->socket, false); stream_set_read_buffer($this->socket, 0); From 45f87c24ff75f75d85749920b7f2bdde1f3673b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sun, 13 Jul 2025 11:48:31 +0800 Subject: [PATCH 1150/1216] fix --- src/Connection/TcpConnection.php | 2 +- src/Events/Swow.php | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index b66f617a1..61f6f2235 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -661,7 +661,7 @@ public function baseRead($socket, bool $checkEof = true): void // Check connection closed. if ($buffer === '' || $buffer === false) { - if ($checkEof && (feof($socket) || !is_resource($socket) || $buffer === false)) { + if ($checkEof && (!is_resource($socket) || feof($socket) || $buffer === false)) { $this->destroy(); return; } diff --git a/src/Events/Swow.php b/src/Events/Swow.php index a1b541218..45c52102b 100644 --- a/src/Events/Swow.php +++ b/src/Events/Swow.php @@ -189,14 +189,18 @@ public function onWritable($stream, callable $func): void try { $this->writeEvents[$fd] = Coroutine::getCurrent(); while (true) { - $rEvent = stream_poll_one($stream, STREAM_POLLOUT | STREAM_POLLHUP); + if (!is_resource($stream)) { + $this->offWritable($stream); + break; + } if (!isset($this->writeEvents[$fd]) || $this->writeEvents[$fd] !== Coroutine::getCurrent()) { break; } + $rEvent = stream_poll_one($stream, STREAM_POLLOUT | STREAM_POLLHUP, 1000); if ($rEvent !== STREAM_POLLNONE) { $this->safeCall($func, [$stream]); } - if ($rEvent !== STREAM_POLLOUT) { + if ($rEvent !== STREAM_POLLOUT && $rEvent !== STREAM_POLLNONE) { $this->offWritable($stream); break; } From 55fb36ad68f9712448166cb3da01a5feb92c01c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sun, 13 Jul 2025 16:25:09 +0800 Subject: [PATCH 1151/1216] fix --- src/Connection/TcpConnection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 61f6f2235..3f2b901f0 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -835,7 +835,7 @@ public function baseWrite(): void */ public function doSslHandshake($socket): bool|int { - if (feof($socket)) { + if (!is_resource($socket) || feof($socket)) { $this->destroy(); return false; } From 520ed2c29024998c9c45abb37417847cc9f860a5 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Fri, 25 Jul 2025 20:13:44 +0300 Subject: [PATCH 1152/1216] [fix] worker with id 0 looses pid --- src/Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index c8e0304f2..b8b780860 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1884,7 +1884,9 @@ protected static function monitorWorkersForLinux(): void // Mark id is available. $id = static::getId($workerId, $pid); - static::$idMap[$workerId][$id] = 0; + if ($id !== false) { + static::$idMap[$workerId][$id] = 0; + } break; } From 4e377d9c6b5eb04e79ead2a0cd7ff6d60411464f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:45:01 +0800 Subject: [PATCH 1153/1216] fix: swow1.6.0 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 58109c01b..3683d7871 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -2449,7 +2449,7 @@ public function listen(): void $errNo = 0; $errMsg = ''; // SO_REUSEPORT. - if ($this->reusePort) { + if ($this->reusePort && DIRECTORY_SEPARATOR !== '\\') { stream_context_set_option($this->socketContext, 'socket', 'so_reuseport', 1); } From 3c543a36d7e165c1fd645ba25d7640603adccaf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:51:19 +0800 Subject: [PATCH 1154/1216] refactor: simplify pipe method anonymous functions --- src/Connection/TcpConnection.php | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 3f2b901f0..9e82dfb22 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -886,19 +886,10 @@ public function doSslHandshake($socket): bool|int */ public function pipe(self $dest): void { - $source = $this; - $this->onMessage = function ($source, $data) use ($dest) { - $dest->send($data); - }; - $this->onClose = function () use ($dest) { - $dest->close(); - }; - $dest->onBufferFull = function () use ($source) { - $source->pauseRecv(); - }; - $dest->onBufferDrain = function () use ($source) { - $source->resumeRecv(); - }; + $this->onMessage = fn ($source, $data) => $dest->send($data); + $this->onClose = fn () => $dest->close(); + $dest->onBufferFull = fn () => $this->pauseRecv(); + $dest->onBufferDrain = fn() => $this->resumeRecv(); } /** From 8a2ee94b33eda851c43967f8eed75408ceee7542 Mon Sep 17 00:00:00 2001 From: kriss <462679766@qq.com> Date: Thu, 21 Aug 2025 11:18:22 +0800 Subject: [PATCH 1155/1216] Support request Range fix: #1118 --- src/Protocols/Http.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 1c58b3379..15f3164df 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -163,8 +163,17 @@ public static function decode(string $buffer, TcpConnection $connection): Reques */ public static function encode(mixed $response, TcpConnection $connection): string { + $requestRange = [0, 0]; if (isset($connection->request)) { $request = $connection->request; + if ($value = $request->header('range')) { + if (str_starts_with($value, 'bytes=')) { + $arr = explode('-', substr($value, 6)); + if (count($arr) === 2) { + $requestRange = [(int)$arr[0], (int)$arr[1]]; + } + } + } $request->connection = $connection->request = null; } @@ -197,8 +206,8 @@ public static function encode(mixed $response, TcpConnection $connection): strin if (isset($response->file)) { $file = $response->file['file']; - $offset = $response->file['offset']; - $length = $response->file['length']; + $offset = $response->file['offset'] ?: $requestRange[0]; + $length = $response->file['length'] ?: $requestRange[1]; clearstatcache(); $fileSize = (int)filesize($file); $bodyLen = $length > 0 ? $length : $fileSize - $offset; @@ -206,9 +215,11 @@ public static function encode(mixed $response, TcpConnection $connection): strin 'Content-Length' => $bodyLen, 'Accept-Ranges' => 'bytes', ]); + if ($offset || $length) { $offsetEnd = $offset + $bodyLen - 1; $response->header('Content-Range', "bytes $offset-$offsetEnd/$fileSize"); + $response->withStatus(206); } if ($bodyLen < 2 * 1024 * 1024) { $connection->send($response . file_get_contents($file, false, null, $offset, $bodyLen), true); From 98dc7a630b3dbaf0b99fa920f9052768f8341787 Mon Sep 17 00:00:00 2001 From: kriss <462679766@qq.com> Date: Thu, 21 Aug 2025 17:34:11 +0800 Subject: [PATCH 1156/1216] Move code for performance --- src/Protocols/Http.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 15f3164df..40ebc70e2 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -163,17 +163,9 @@ public static function decode(string $buffer, TcpConnection $connection): Reques */ public static function encode(mixed $response, TcpConnection $connection): string { - $requestRange = [0, 0]; + $request = null; if (isset($connection->request)) { $request = $connection->request; - if ($value = $request->header('range')) { - if (str_starts_with($value, 'bytes=')) { - $arr = explode('-', substr($value, 6)); - if (count($arr) === 2) { - $requestRange = [(int)$arr[0], (int)$arr[1]]; - } - } - } $request->connection = $connection->request = null; } @@ -205,6 +197,16 @@ public static function encode(mixed $response, TcpConnection $connection): strin } if (isset($response->file)) { + $requestRange = [0, 0]; + if ($value = $request?->header('range')) { + if (str_starts_with($value, 'bytes=')) { + $arr = explode('-', substr($value, 6)); + if (count($arr) === 2) { + $requestRange = [(int)$arr[0], (int)$arr[1]]; + } + } + } + $file = $response->file['file']; $offset = $response->file['offset'] ?: $requestRange[0]; $length = $response->file['length'] ?: $requestRange[1]; From 098e2573afb56b8ea169bc00b6ea896947c807a8 Mon Sep 17 00:00:00 2001 From: Nathan Wu Date: Wed, 27 Aug 2025 14:22:59 +0800 Subject: [PATCH 1157/1216] add igbinary serializer handler support --- src/Protocols/Http/Session.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 7bdd53371..a0fc3fb37 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -25,11 +25,8 @@ use function ini_get; use function is_array; use function is_scalar; -use function preg_match; use function random_int; -use function serialize; use function session_get_cookie_params; -use function unserialize; /** * Class Session @@ -156,6 +153,12 @@ class Session */ protected bool $isSafe = true; + /** + * Session serialize_handler + * @var array|string[] + */ + protected array $serializer = ['serialize', 'unserialize']; + /** * Session constructor. * @@ -163,12 +166,15 @@ class Session */ public function __construct(string $sessionId) { + if (extension_loaded('igbinary') && ini_get('session.serialize_handler') == 'igbinary') { + $this->serializer = ['igbinary_serialize', 'igbinary_unserialize']; + } if (static::$handler === null) { static::initHandler(); } $this->sessionId = $sessionId; if ($data = static::$handler->read($sessionId)) { - $this->data = unserialize($data); + $this->data = $this->serializer[1]($data); } } @@ -321,7 +327,7 @@ public function save(): void if (empty($this->data)) { static::$handler->destroy($this->sessionId); } else { - static::$handler->write($this->sessionId, serialize($this->data)); + static::$handler->write($this->sessionId, $this->serializer[0]($this->data)); } } elseif (static::$autoUpdateTimestamp) { $this->refresh(); From e2d201cb26533838b060229f6c20132c72dfc112 Mon Sep 17 00:00:00 2001 From: Yevhen Date: Mon, 1 Sep 2025 17:37:45 +0300 Subject: [PATCH 1158/1216] fix custom protocols in Worker::$logFile skip invalid directory creation and permission changes for Worker::$logFile with custom protocol handlers like php://stdout --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 3683d7871..37971926a 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -750,7 +750,7 @@ protected static function init(): void // Log file. static::$logFile = static::$logFile ?: sprintf('%s/workerman.log', $startFileDir); - if (static::$logFile !== '/dev/null' && !is_file(static::$logFile)) { + if (static::$logFile !== '/dev/null' && !is_file(static::$logFile) && !str_contains(static::$logFile, '://')) { // if /runtime/logs default folder not exists if (!is_dir(dirname(static::$logFile))) { mkdir(dirname(static::$logFile), 0777, true); From 0d0d4639d0e627e6a1f36a9ffdc4de5e8dbc98da Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Oct 2025 15:11:25 +0800 Subject: [PATCH 1159/1216] Ensure onWorkerStart executes first --- src/Worker.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index 37971926a..af545a7ae 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.3'; + final public const VERSION = '5.1.4'; /** * Status initial. @@ -879,8 +879,7 @@ protected static function initWorkers(): void // Listen. if (!$worker->reusePort) { - $worker->listen(); - $worker->pauseAccept(); + $worker->listen(false); } } } @@ -1615,7 +1614,6 @@ protected static function forkWorkersForWindows(): void // Display UI. static::safeEcho(str_pad($worker->name, 48) . str_pad($worker->getSocketName(), 36) . str_pad('1', 10) . " [ok]\n"); - $worker->listen(); $worker->run(); static::$globalEvent->run(); if (static::$status !== self::STATUS_SHUTDOWN) { @@ -2433,8 +2431,11 @@ public static function safeEcho(string $msg, bool $decorated = false): void /** * Listen. + * + * @param $autoAccept + * @return void */ - public function listen(): void + public function listen($autoAccept = true): void { if (!$this->socketName) { return; @@ -2489,7 +2490,9 @@ public function listen(): void stream_set_blocking($this->mainSocket, false); } - $this->resumeAccept(); + if ($autoAccept) { + $this->resumeAccept(); + } } /** @@ -2620,7 +2623,7 @@ public function getSocketName(): string */ public function run(): void { - $this->listen(); + $this->listen(!$this->onWorkerStart); if (!$this->onWorkerStart) { return; @@ -2635,6 +2638,7 @@ public function run(): void sleep(1); static::stopAll(250, $e); } finally { + $this->resumeAccept(); Context::destroy(); } }; From f19e69b8337c016bfe697149e286b90a221ce1f2 Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Oct 2025 15:12:09 +0800 Subject: [PATCH 1160/1216] Support redis pool --- .../Session/RedisClusterSessionHandler.php | 28 +++-- .../Http/Session/RedisSessionHandler.php | 108 +++++++++++++----- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/src/Protocols/Http/Session/RedisClusterSessionHandler.php b/src/Protocols/Http/Session/RedisClusterSessionHandler.php index d1f93d9b1..8580d0da1 100644 --- a/src/Protocols/Http/Session/RedisClusterSessionHandler.php +++ b/src/Protocols/Http/Session/RedisClusterSessionHandler.php @@ -24,11 +24,22 @@ class RedisClusterSessionHandler extends RedisSessionHandler { /** - * @param $config + * @param array $config * @throws RedisClusterException * @throws RedisException */ - public function __construct($config) + public function __construct(array $config) + { + parent::__construct($config); + } + + /** + * Create redis connection. + * @param array $config + * @return Redis|RedisCluster + * @throws RedisClusterException + */ + protected function createRedisConnection(array $config): Redis|RedisCluster { $timeout = $config['timeout'] ?? 2; $readTimeout = $config['read_timeout'] ?? $timeout; @@ -38,18 +49,11 @@ public function __construct($config) if ($auth) { $args[] = $auth; } - $this->redis = new RedisCluster(...$args); + $redis = new RedisCluster(...$args); if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->redis->setOption(Redis::OPT_PREFIX, $config['prefix']); - } - - /** - * {@inheritdoc} - */ - public function read(string $sessionId): string|false - { - return $this->redis->get($sessionId); + $redis->setOption(Redis::OPT_PREFIX, $config['prefix']); + return $redis; } } diff --git a/src/Protocols/Http/Session/RedisSessionHandler.php b/src/Protocols/Http/Session/RedisSessionHandler.php index 8733e068d..e62af1335 100644 --- a/src/Protocols/Http/Session/RedisSessionHandler.php +++ b/src/Protocols/Http/Session/RedisSessionHandler.php @@ -21,8 +21,13 @@ use RedisException; use RuntimeException; use Throwable; +use Workerman\Coroutine\Utils\DestructionWatcher; +use Workerman\Events\Fiber; use Workerman\Protocols\Http\Session; use Workerman\Timer; +use Workerman\Coroutine\Pool; +use Workerman\Coroutine\Context; +use Workerman\Worker; /** * Class RedisSessionHandler @@ -33,13 +38,18 @@ class RedisSessionHandler implements SessionHandlerInterface /** * @var Redis|RedisCluster */ - protected Redis|RedisCluster $redis; + protected Redis|RedisCluster|null $connection = null; /** * @var array */ protected array $config; + /** + * @var Pool|null + */ + protected static ?Pool $pool = null; + /** * RedisSessionHandler constructor. * @param array $config = [ @@ -61,34 +71,87 @@ public function __construct(array $config) $config['timeout'] ??= 2; $this->config = $config; - $this->connect(); - - Timer::add($config['ping'] ?? 55, function () { - $this->redis->get('ping'); - }); } /** - * @throws RedisException + * Get connection. + * @return Redis + * @throws Throwable */ - public function connect() + protected function connection(): Redis|RedisCluster { - $config = $this->config; + // Cannot switch fibers in current execution context when PHP < 8.4 + if (Worker::$eventLoopClass === Fiber::class && PHP_VERSION_ID < 80400) { + if (!$this->connection) { + $this->connection = $this->createRedisConnection($this->config); + Timer::delay($this->config['pool']['heartbeat_interval'] ?? 55, function () { + $this->connection->ping(); + }); + } + return $this->connection; + } + + $key = 'session.redis.connection'; + /** @var Redis|null $connection */ + $connection = Context::get($key); + if (!$connection) { + if (!static::$pool) { + $poolConfig = $this->config['pool'] ?? []; + static::$pool = new Pool($poolConfig['max_connections'] ?? 10, $poolConfig); + static::$pool->setConnectionCreator(function () { + return $this->createRedisConnection($this->config); + }); + static::$pool->setConnectionCloser(function (Redis|RedisCluster $connection) { + $connection->close(); + }); + static::$pool->setHeartbeatChecker(function (Redis|RedisCluster $connection) { + $connection->ping(); + }); + } + try { + $connection = static::$pool->get(); + Context::set($key, $connection); + } finally { + $closure = function () use ($connection) { + try { + $connection && static::$pool && static::$pool->put($connection); + } catch (Throwable) { + // ignore + } + }; + $obj = Context::get('context.onDestroy'); + if (!$obj) { + $obj = new \stdClass(); + Context::set('context.onDestroy', $obj); + } + DestructionWatcher::watch($obj, $closure); + } + } + return $connection; + } - $this->redis = new Redis(); - if (false === $this->redis->connect($config['host'], $config['port'], $config['timeout'])) { + /** + * Create redis connection. + * @param array $config + * @return Redis + */ + protected function createRedisConnection(array $config): Redis|RedisCluster + { + $redis = new Redis(); + if (false === $redis->connect($config['host'], $config['port'], $config['timeout'])) { throw new RuntimeException("Redis connect {$config['host']}:{$config['port']} fail."); } if (!empty($config['auth'])) { - $this->redis->auth($config['auth']); + $redis->auth($config['auth']); } if (!empty($config['database'])) { - $this->redis->select($config['database']); + $redis->select((int)$config['database']); } if (empty($config['prefix'])) { $config['prefix'] = 'redis_session_'; } - $this->redis->setOption(Redis::OPT_PREFIX, $config['prefix']); + $redis->setOption(Redis::OPT_PREFIX, $config['prefix']); + return $redis; } /** @@ -108,16 +171,7 @@ public function open(string $savePath, string $name): bool */ public function read(string $sessionId): string|false { - try { - return $this->redis->get($sessionId); - } catch (Throwable $e) { - $msg = strtolower($e->getMessage()); - if ($msg === 'connection lost' || strpos($msg, 'went away')) { - $this->connect(); - return $this->redis->get($sessionId); - } - throw $e; - } + return $this->connection()->get($sessionId); } /** @@ -126,7 +180,7 @@ public function read(string $sessionId): string|false */ public function write(string $sessionId, string $sessionData): bool { - return true === $this->redis->setex($sessionId, Session::$lifetime, $sessionData); + return true === $this->connection()->setex($sessionId, Session::$lifetime, $sessionData); } /** @@ -135,7 +189,7 @@ public function write(string $sessionId, string $sessionData): bool */ public function updateTimestamp(string $sessionId, string $data = ""): bool { - return true === $this->redis->expire($sessionId, Session::$lifetime); + return true === $this->connection()->expire($sessionId, Session::$lifetime); } /** @@ -144,7 +198,7 @@ public function updateTimestamp(string $sessionId, string $data = ""): bool */ public function destroy(string $sessionId): bool { - $this->redis->del($sessionId); + $this->connection()->del($sessionId); return true; } From ff4e17babdc92b16b3252060233c88f6c2e9a61a Mon Sep 17 00:00:00 2001 From: walkor Date: Sun, 12 Oct 2025 15:54:18 +0800 Subject: [PATCH 1161/1216] Refactor pauseAccept property and related methods --- src/Worker.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index af545a7ae..d8e6641b3 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -264,7 +264,7 @@ class Worker * * @var bool */ - protected bool $pauseAccept = true; + protected ?bool $pauseAccept = null; /** * Is worker stopping ? @@ -2432,10 +2432,10 @@ public static function safeEcho(string $msg, bool $decorated = false): void /** * Listen. * - * @param $autoAccept + * @param bool $autoAccept * @return void */ - public function listen($autoAccept = true): void + public function listen(bool $autoAccept = true): void { if (!$this->socketName) { return; @@ -2581,7 +2581,7 @@ protected function parseSocketAddress(): ?string */ public function pauseAccept(): void { - if (static::$globalEvent !== null && $this->pauseAccept === false && $this->mainSocket !== null) { + if (static::$globalEvent !== null && !$this->pauseAccept && $this->mainSocket !== null) { static::$globalEvent->offReadable($this->mainSocket); $this->pauseAccept = true; } @@ -2595,7 +2595,7 @@ public function pauseAccept(): void public function resumeAccept(): void { // Register a listener to be notified when server socket is ready to read. - if (static::$globalEvent !== null && $this->pauseAccept === true && $this->mainSocket !== null) { + if (static::$globalEvent !== null && ($this->pauseAccept === null || $this->pauseAccept === true) && $this->mainSocket !== null) { if ($this->transport !== 'udp') { static::$globalEvent->onReadable($this->mainSocket, $this->acceptTcpConnection(...)); } else { @@ -2638,7 +2638,9 @@ public function run(): void sleep(1); static::stopAll(250, $e); } finally { - $this->resumeAccept(); + if ($this->pauseAccept === null) { + $this->resumeAccept(); + } Context::destroy(); } }; From c350db70ec90e91314b51e4c8fa1522287a8ed46 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Oct 2025 17:29:22 +0800 Subject: [PATCH 1162/1216] Fix #1124 --- src/Connection/TcpConnection.php | 1 + src/Protocols/Http/Request.php | 1 + src/Worker.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 9e82dfb22..1491ea0de 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1060,6 +1060,7 @@ public function destroy(): void $this->error($e); } } + $this->request = null; $this->sendBuffer = $this->recvBuffer = ''; $this->currentPackageLength = 0; $this->isPaused = $this->sslHandshakeCompleted = false; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index cbb0dc358..68aea9ef6 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -756,6 +756,7 @@ public function destroy(): void if ($this->properties) { $this->properties = []; } + $this->connection = null; if (isset($this->data['files']) && $this->isSafe) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { diff --git a/src/Worker.php b/src/Worker.php index d8e6641b3..16c610e34 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.4'; + final public const VERSION = '5.1.5'; /** * Status initial. From 812a074307f4d8967fe64eb025f58803588637fc Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Oct 2025 21:45:49 +0800 Subject: [PATCH 1163/1216] Update test deps, fix UDP socket handling --- composer.json | 4 +- src/Connection/AsyncUdpConnection.php | 10 +++- src/Connection/UdpConnection.php | 17 +++++- src/Protocols/Http.php | 3 +- src/Timer.php | 4 +- src/Worker.php | 2 +- tests/Feature/UdpConnectionTest.php | 20 +++++-- tests/Feature/WebsocketServiceTest.php | 72 ++++++++++++++------------ 8 files changed, 87 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index 8fd345245..850603d63 100644 --- a/composer.json +++ b/composer.json @@ -44,9 +44,9 @@ }, "require-dev": { "pestphp/pest": "2.x-dev", - "mockery/mockery": "^1.6", + "mockery/mockery": "2.0.x-dev", "guzzlehttp/guzzle": "^7.0", - "phpstan/phpstan": "1.11.x-dev" + "phpstan/phpstan": "2.1.x-dev" }, "config": { "allow-plugins": { diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index 0ffd3a674..d9bfa9fa3 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -22,6 +22,7 @@ use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; use function class_exists; +use function is_resource; use function explode; use function fclose; use function stream_context_create; @@ -131,8 +132,13 @@ public function close(mixed $data = null, bool $raw = false): void if ($data !== null) { $this->send($data, $raw); } - $this->eventLoop->offReadable($this->socket); - fclose($this->socket); + if ($this->eventLoop) { + $this->eventLoop->offReadable($this->socket); + } + if (is_resource($this->socket)) { + fclose($this->socket); + } + $this->socket = null; // intentionally nullable to mark closed state $this->connected = false; // Try to emit onClose callback. if ($this->onClose) { diff --git a/src/Connection/UdpConnection.php b/src/Connection/UdpConnection.php index 7d301ffdf..7adcb467b 100644 --- a/src/Connection/UdpConnection.php +++ b/src/Connection/UdpConnection.php @@ -51,8 +51,11 @@ class UdpConnection extends ConnectionInterface implements JsonSerializable * @param resource $socket * @param string $remoteAddress */ + /** + * @param resource|null $socket + */ public function __construct( - protected $socket, + /** @var resource|null */ protected $socket, protected string $remoteAddress) {} /** @@ -147,7 +150,7 @@ public function getLocalPort(): int */ public function getLocalAddress(): string { - return (string)@stream_socket_get_name($this->socket, false); + return is_resource($this->socket) ? (string)@stream_socket_get_name($this->socket, false) : ''; } @@ -163,6 +166,13 @@ public function close(mixed $data = null, bool $raw = false): void if ($data !== null) { $this->send($data, $raw); } + if ($this->eventLoop) { + $this->eventLoop->offReadable($this->socket); + } + if (is_resource($this->socket)) { + @fclose($this->socket); + } + $this->socket = null; $this->eventLoop = $this->errorHandler = null; } @@ -197,6 +207,9 @@ public function isIpV6(): bool * * @return resource */ + /** + * @return resource|null + */ public function getSocket() { return $this->socket; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 40ebc70e2..070c59848 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -136,9 +136,9 @@ public static function decode(string $buffer, TcpConnection $connection): Reques static $requests = []; if (isset($requests[$buffer])) { $request = $requests[$buffer]; + $request->destroy(); $request->connection = $connection; $connection->request = $request; - $request->destroy(); return $request; } $request = new static::$requestClass($buffer); @@ -259,6 +259,7 @@ protected static function sendStream(TcpConnection $connection, $handler, int $o // Read file content from disk piece by piece and send to client. $doWrite = function () use ($connection, $handler, $length, $offsetEnd) { // Send buffer not full. + /** @phpstan-ignore-next-line */ while ($connection->context->bufferFull === false) { // Read from disk. $size = 1024 * 1024; diff --git a/src/Timer.php b/src/Timer.php index 3a29fee29..0d5c9ad55 100644 --- a/src/Timer.php +++ b/src/Timer.php @@ -161,7 +161,7 @@ public static function add(float $timeInterval, callable $func, ?array $args = [ pcntl_alarm(1); } - $runTime = time() + $timeInterval; + $runTime = (int)floor(time() + $timeInterval); if (!isset(self::$tasks[$runTime])) { self::$tasks[$runTime] = []; } @@ -223,7 +223,7 @@ protected static function tick(): void Worker::safeEcho((string)$e); } if ($persistent && !empty(self::$status[$index])) { - $newRunTime = time() + $timeInterval; + $newRunTime = (int)floor(time() + $timeInterval); if (!isset(self::$tasks[$newRunTime])) { self::$tasks[$newRunTime] = []; } diff --git a/src/Worker.php b/src/Worker.php index 16c610e34..bc11fa6ea 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -25,7 +25,7 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; -use Workerman\Coroutine; +use Workerman\Coroutine\Coroutine as Coroutine; use Workerman\Coroutine\Context; use Workerman\Events\Event; use Workerman\Events\EventInterface; diff --git a/tests/Feature/UdpConnectionTest.php b/tests/Feature/UdpConnectionTest.php index acec86b56..14ccbc065 100644 --- a/tests/Feature/UdpConnectionTest.php +++ b/tests/Feature/UdpConnectionTest.php @@ -6,7 +6,7 @@ beforeAll(function () use (&$process) { $process = new PhpProcess(file_get_contents(__DIR__ . '/Stub/UdpServer.php')); $process->start(); - usleep(250000); + usleep(600000); }); afterAll(function () use (&$process) { @@ -17,9 +17,23 @@ it('tests udp connection', function () { $socket = stream_socket_client('udp://127.0.0.1:8083', $errno, $errstr, 1); expect($errno)->toBeInt()->toBe(0); + stream_set_timeout($socket, 1); fwrite($socket, 'xiami'); - $data = fread($socket, 1024); - expect($data)->toBeString('received: xiami'); + + // 使用 recvfrom 读取,循环等待最多 ~1s + $data = ''; + $start = microtime(true); + do { + $peer = null; + $chunk = @stream_socket_recvfrom($socket, 1024, 0, $peer); + if ($chunk !== false && $chunk !== '') { + $data = $chunk; + break; + } + usleep(50000); + } while ((microtime(true) - $start) < 1.0); + + expect($data)->toBe('received: xiami'); fclose($socket); }) ->skipOnWindows(); //require posix diff --git a/tests/Feature/WebsocketServiceTest.php b/tests/Feature/WebsocketServiceTest.php index 420038805..a5f52c61c 100644 --- a/tests/Feature/WebsocketServiceTest.php +++ b/tests/Feature/WebsocketServiceTest.php @@ -13,7 +13,7 @@ \$worker->onMessage = function () {}; PHP)); $serverProcess->start(); - usleep(250000); + usleep(600000); $clientProcess = new PhpProcess(str_replace(subject: $clientCode, search: '//%action%', replace: <<onWebSocketConnect = function(AsyncTcpConnection \$con) { @@ -21,13 +21,15 @@ }; PHP)); $clientProcess->start(); - usleep(250000); - - expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('connected') - ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe(''); - - $serverProcess->stop(); - $clientProcess->stop(); + usleep(600000); + + try { + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('connected') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe(''); + } finally { + $serverProcess->stop(); + $clientProcess->stop(); + } }); it('tests server and client sending and receiving messages', function () use ($serverCode, $clientCode) { @@ -38,7 +40,7 @@ }; PHP)); $serverProcess->start(); - usleep(250000); + usleep(600000); $clientProcess = new PhpProcess(str_replace(subject: $clientCode, search: '//%action%', replace: <<onWebSocketConnect = function(AsyncTcpConnection \$con) { @@ -49,13 +51,15 @@ }; PHP)); $clientProcess->start(); - usleep(250000); - - expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('Hello Chance') - ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('Hi'); - - $serverProcess->stop(); - $clientProcess->stop(); + usleep(600000); + + try { + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('Hello Chance') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('Hi'); + } finally { + $serverProcess->stop(); + $clientProcess->stop(); + } }); it('tests server close connection', function () use ($serverCode, $clientCode) { @@ -67,7 +71,7 @@ \$worker->onMessage = function () {}; PHP)); $serverProcess->start(); - usleep(250000); + usleep(600000); $clientProcess = new PhpProcess(str_replace(subject: $clientCode, search: '//%action%', replace: <<onWebSocketConnect = function(AsyncTcpConnection \$con) { @@ -78,13 +82,15 @@ }; PHP)); $clientProcess->start(); - usleep(250000); - - expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('close connection') - ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('closed'); - - $serverProcess->stop(); - $clientProcess->stop(); + usleep(600000); + + try { + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('close connection') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('closed'); + } finally { + $serverProcess->stop(); + $clientProcess->stop(); + } }); it('tests client close connection', function () use ($serverCode, $clientCode) { @@ -95,7 +101,7 @@ }; PHP)); $serverProcess->start(); - usleep(250000); + usleep(600000); $clientProcess = new PhpProcess(str_replace(subject: $clientCode, search: '//%action%', replace: <<onWebSocketConnect = function(AsyncTcpConnection \$con) { @@ -105,11 +111,13 @@ }; PHP)); $clientProcess->start(); - usleep(250000); - - expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('closed') - ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('close connection'); - - $serverProcess->stop(); - $clientProcess->stop(); + usleep(600000); + + try { + expect(getNonFrameOutput($serverProcess->getOutput()))->toBe('closed') + ->and(getNonFrameOutput($clientProcess->getOutput()))->toBe('close connection'); + } finally { + $serverProcess->stop(); + $clientProcess->stop(); + } }); From 05952235adbbee4d78daf8753311e3a295299764 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Oct 2025 21:55:54 +0800 Subject: [PATCH 1164/1216] Update test --- composer.json | 2 +- phpstan.neon.dist | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 850603d63..aad377571 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ } }, "scripts": { - "analyze": "phpstan", + "analyze": "php -d memory_limit=1G vendor/phpstan/phpstan/phpstan.phar", "test": "pest --colors=always" } } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index c4c8a6478..df6d59635 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,7 @@ parameters: level: 5 + bootstrapFiles: + - vendor/autoload.php paths: - src - tests From 0dc0de1dcd8fd374ec40ea678add6bdbc5e55172 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 14 Oct 2025 22:37:04 +0800 Subject: [PATCH 1165/1216] Fix analyze --- phpstan.neon.dist | 4 ++-- src/Protocols/Http/Session.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index df6d59635..09e1dd405 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,7 +1,5 @@ parameters: level: 5 - bootstrapFiles: - - vendor/autoload.php paths: - src - tests @@ -23,5 +21,7 @@ parameters: - path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: src/Worker.php + reportUnmatched: false messages: - '#Constant LINE_VERSION_LENGTH not found.#' + - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index a0fc3fb37..49b2a51b5 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -17,8 +17,8 @@ namespace Workerman\Protocols\Http; use Exception; -use Random\RandomException; use RuntimeException; +use Throwable; use Workerman\Protocols\Http\Session\FileSessionHandler; use Workerman\Protocols\Http\Session\SessionHandlerInterface; use function array_key_exists; @@ -441,7 +441,7 @@ public function __wakeup() * __destruct. * * @return void - * @throws RandomException + * @throws Throwable */ public function __destruct() { From 53c6dc373c6c7eb63e22189a3b666fc6fd441761 Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 4 Nov 2025 17:04:34 +0800 Subject: [PATCH 1166/1216] Simplify HTTP request handling --- src/Connection/TcpConnection.php | 15 +-------------- src/Protocols/Http.php | 22 ++-------------------- src/Protocols/Http/Request.php | 15 ++++++++++++--- src/Protocols/Http/Response.php | 5 ++++- 4 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 1491ea0de..f97703e7c 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -19,13 +19,9 @@ use RuntimeException; use stdClass; use Throwable; -use Workerman\Events\Ev; -use Workerman\Events\Event; use Workerman\Events\EventInterface; -use Workerman\Events\Select; use Workerman\Protocols\Http; use Workerman\Protocols\Http\Request; -use Workerman\Protocols\ProtocolInterface; use Workerman\Worker; use function ceil; @@ -252,11 +248,6 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public array $headers = []; - /** - * @var ?Request - */ - public ?Request $request = null; - /** * Is safe. * @@ -672,9 +663,7 @@ public function baseRead($socket, bool $checkEof = true): void ++self::$statistics['total_request']; if ($this->protocol === Http::class) { $request = clone $requests[$buffer]; - $request->destroy(); $request->connection = $this; - $this->request = $request; try { ($this->onMessage)($this, $request); } catch (Throwable $e) { @@ -750,7 +739,6 @@ public function baseRead($socket, bool $checkEof = true): void ($this->onMessage)($this, $request); if ($request instanceof Request) { $requests[$oneRequestBuffer] = clone $request; - $requests[$oneRequestBuffer]->destroy(); } else { $requests[$oneRequestBuffer] = $request; } @@ -771,7 +759,7 @@ public function baseRead($socket, bool $checkEof = true): void return; } - // Applications protocol is not set. + // Application protocol is not set. ++self::$statistics['total_request']; try { ($this->onMessage)($this, $this->recvBuffer); @@ -1060,7 +1048,6 @@ public function destroy(): void $this->error($e); } } - $this->request = null; $this->sendBuffer = $this->recvBuffer = ''; $this->currentPackageLength = 0; $this->isPaused = $this->sslHandshakeCompleted = false; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 070c59848..982b60643 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -136,9 +136,7 @@ public static function decode(string $buffer, TcpConnection $connection): Reques static $requests = []; if (isset($requests[$buffer])) { $request = $requests[$buffer]; - $request->destroy(); $request->connection = $connection; - $connection->request = $request; return $request; } $request = new static::$requestClass($buffer); @@ -150,7 +148,6 @@ public static function decode(string $buffer, TcpConnection $connection): Reques $request = clone $request; } $request->connection = $connection; - $connection->request = $request; return $request; } @@ -163,11 +160,6 @@ public static function decode(string $buffer, TcpConnection $connection): Reques */ public static function encode(mixed $response, TcpConnection $connection): string { - $request = null; - if (isset($connection->request)) { - $request = $connection->request; - $request->connection = $connection->request = null; - } if (!is_object($response)) { $extHeader = ''; @@ -197,19 +189,9 @@ public static function encode(mixed $response, TcpConnection $connection): strin } if (isset($response->file)) { - $requestRange = [0, 0]; - if ($value = $request?->header('range')) { - if (str_starts_with($value, 'bytes=')) { - $arr = explode('-', substr($value, 6)); - if (count($arr) === 2) { - $requestRange = [(int)$arr[0], (int)$arr[1]]; - } - } - } - $file = $response->file['file']; - $offset = $response->file['offset'] ?: $requestRange[0]; - $length = $response->file['length'] ?: $requestRange[1]; + $offset = $response->file['offset'] ?: 0; + $length = $response->file['length'] ?: 0; clearstatcache(); $fileSize = (int)filesize($file); $bodyLen = $length > 0 ? $length : $fileSize - $offset; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 68aea9ef6..4b631278e 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -734,7 +734,7 @@ public function __unset(string $name): void } /** - * __wakeup. + * Wakeup. * * @return void */ @@ -744,11 +744,11 @@ public function __wakeup(): void } /** - * Destroy. + * Clone. * * @return void */ - public function destroy(): void + public function __clone(): void { if ($this->context) { $this->context = []; @@ -757,6 +757,15 @@ public function destroy(): void $this->properties = []; } $this->connection = null; + } + + /** + * Destructor. + * + * @return void + */ + public function __destruct() + { if (isset($this->data['files']) && $this->isSafe) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index e3fb10874..1e88744a9 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -550,7 +550,10 @@ public function __toString(): string if (!isset($headers['Content-Type'])) { $head .= "Content-Type: text/html;charset=utf-8\r\n"; } else if ($headers['Content-Type'] === 'text/event-stream') { - return $head . $this->body; + // For Server-Sent Events, send headers once and keep the connection open. + // Headers must be terminated by an empty line; ignore any preset body to avoid + // polluting the event stream with extra bytes or OS-specific newlines. + return $head . "\r\n"; } if (!isset($headers['Transfer-Encoding'])) { From de884ea6825cf324d952684909c97b9b0077be2e Mon Sep 17 00:00:00 2001 From: walkor Date: Tue, 4 Nov 2025 17:27:54 +0800 Subject: [PATCH 1167/1216] Update Request.php --- src/Protocols/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index 4b631278e..e1b716d19 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -748,7 +748,7 @@ public function __wakeup(): void * * @return void */ - public function __clone(): void + public function __clone() { if ($this->context) { $this->context = []; From 1388b101a6055929922d08019fedbfe779c185d4 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 5 Nov 2025 15:29:14 +0800 Subject: [PATCH 1168/1216] Simplify HTTP request handling --- src/Connection/TcpConnection.php | 11 +++++++---- src/Protocols/Http.php | 18 ------------------ src/Protocols/Http/Request.php | 6 +++--- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index f97703e7c..09393ca92 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -662,13 +662,16 @@ public function baseRead($socket, bool $checkEof = true): void if (!isset($buffer[static::MAX_CACHE_STRING_LENGTH]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; if ($this->protocol === Http::class) { - $request = clone $requests[$buffer]; + $request = $requests[$buffer]; $request->connection = $this; try { ($this->onMessage)($this, $request); } catch (Throwable $e) { $this->error($e); } + $request = clone $request; + $request->destroy(); + $requests[$buffer] = $request; return; } $request = $requests[$buffer]; @@ -738,10 +741,10 @@ public function baseRead($socket, bool $checkEof = true): void if ((!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[static::MAX_CACHE_STRING_LENGTH])) { ($this->onMessage)($this, $request); if ($request instanceof Request) { - $requests[$oneRequestBuffer] = clone $request; - } else { - $requests[$oneRequestBuffer] = $request; + $request = clone $request; + $request->destroy(); } + $requests[$oneRequestBuffer] = $request; if (count($requests) > static::MAX_CACHE_SIZE) { unset($requests[key($requests)]); } diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 982b60643..04b03b4a7 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -20,14 +20,11 @@ use Workerman\Protocols\Http\Request; use Workerman\Protocols\Http\Response; use function clearstatcache; -use function count; -use function explode; use function filesize; use function fopen; use function fread; use function fseek; use function ftell; -use function in_array; use function ini_get; use function is_array; use function is_object; @@ -35,7 +32,6 @@ use function str_starts_with; use function strlen; use function strpos; -use function strstr; use function substr; use function sys_get_temp_dir; @@ -133,20 +129,7 @@ public static function input(string $buffer, TcpConnection $connection): int */ public static function decode(string $buffer, TcpConnection $connection): Request { - static $requests = []; - if (isset($requests[$buffer])) { - $request = $requests[$buffer]; - $request->connection = $connection; - return $request; - } $request = new static::$requestClass($buffer); - if (!isset($buffer[TcpConnection::MAX_CACHE_STRING_LENGTH])) { - $requests[$buffer] = $request; - if (count($requests) > TcpConnection::MAX_CACHE_SIZE) { - unset($requests[key($requests)]); - } - $request = clone $request; - } $request->connection = $connection; return $request; } @@ -160,7 +143,6 @@ public static function decode(string $buffer, TcpConnection $connection): Reques */ public static function encode(mixed $response, TcpConnection $connection): string { - if (!is_object($response)) { $extHeader = ''; $contentType = 'text/html;charset=utf-8'; diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index e1b716d19..b77b31db3 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -744,11 +744,11 @@ public function __wakeup(): void } /** - * Clone. + * Destroy. * * @return void */ - public function __clone() + public function destroy(): void { if ($this->context) { $this->context = []; @@ -766,7 +766,7 @@ public function __clone() */ public function __destruct() { - if (isset($this->data['files']) && $this->isSafe) { + if (!empty($this->data['files']) && $this->isSafe) { clearstatcache(); array_walk_recursive($this->data['files'], function ($value, $key) { if ($key === 'tmp_name' && is_file($value)) { From e0149a6093679d16defda4138af8f7a61c9cf260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <1569097443@qq.com> Date: Wed, 5 Nov 2025 18:50:46 +0800 Subject: [PATCH 1169/1216] fix: eventloop --- src/Connection/AsyncTcpConnection.php | 7 ++++--- src/Connection/AsyncUdpConnection.php | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Connection/AsyncTcpConnection.php b/src/Connection/AsyncTcpConnection.php index ae50a27f6..adae2678f 100644 --- a/src/Connection/AsyncTcpConnection.php +++ b/src/Connection/AsyncTcpConnection.php @@ -242,9 +242,7 @@ public function connect(): void return; } - if (!$this->eventLoop) { - $this->eventLoop = Worker::$globalEvent; - } + $this->eventLoop ??= Worker::getEventLoop(); $this->status = self::STATUS_CONNECTING; $this->connectStartTime = microtime(true); @@ -287,6 +285,9 @@ public function connect(): void } return; } + + $this->eventLoop ??= Worker::getEventLoop(); + // Add socket to global event loop waiting connection is successfully established or failed. $this->eventLoop->onWritable($this->socket, $this->checkConnection(...)); // For windows. diff --git a/src/Connection/AsyncUdpConnection.php b/src/Connection/AsyncUdpConnection.php index d9bfa9fa3..63fd4fa77 100644 --- a/src/Connection/AsyncUdpConnection.php +++ b/src/Connection/AsyncUdpConnection.php @@ -182,9 +182,9 @@ public function connect(): void if ($this->connected === true) { return; } - if (!$this->eventLoop) { - $this->eventLoop = Worker::$globalEvent; - } + + $this->eventLoop ??= Worker::getEventLoop(); + if ($this->contextOption) { $context = stream_context_create($this->contextOption); $this->socket = stream_socket_client("udp://$this->remoteAddress", $errno, $errmsg, @@ -199,6 +199,8 @@ public function connect(): void return; } + $this->eventLoop ??= Worker::getEventLoop(); + stream_set_blocking($this->socket, false); if ($this->onMessage) { $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); From 13469f3c4df4d02d401916609e7b74b7f487ddc3 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 8 Nov 2025 18:29:53 +0800 Subject: [PATCH 1170/1216] Improve protocol handling --- src/Protocols/Http/Response.php | 47 ++++++++++++++++++++++----------- src/Protocols/Websocket.php | 3 +++ src/Protocols/Ws.php | 21 ++++++++++++--- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 1e88744a9..5a20d986f 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -257,16 +257,6 @@ class Response implements Stringable 511 => 'Network Authentication Required', // RFC 6585 ]; - /** - * Init. - * - * @return void - */ - public static function init(): void - { - // Mime types are now statically defined - } - /** * Response constructor. * @@ -360,7 +350,7 @@ public function getHeaders(): array public function withStatus(int $code, ?string $reasonPhrase = null): static { $this->status = $code; - $this->reason = $reasonPhrase; + $this->reason = $reasonPhrase !== null ? str_replace(["\r", "\n"], '', $reasonPhrase) : null; return $this; } @@ -392,7 +382,7 @@ public function getReasonPhrase(): ?string */ public function withProtocolVersion(string $version): static { - $this->version = $version; + $this->version = str_replace(["\r", "\n"], '', $version); return $this; } @@ -476,12 +466,24 @@ protected function createHeadForFile(array $fileInfo): string $head .= "Server: workerman\r\n"; } foreach ($headers as $name => $value) { + // Skip unsafe header names + if (strpbrk($name, ":\r\n") !== false) { + continue; + } if (is_array($value)) { foreach ($value as $item) { + // Skip unsafe header values + if (strpbrk($item, "\r\n") !== false) { + continue; + } $head .= "$name: $item\r\n"; } continue; } + // Skip unsafe header values + if (strpbrk($value, "\r\n") !== false) { + continue; + } $head .= "$name: $value\r\n"; } @@ -492,6 +494,11 @@ protected function createHeadForFile(array $fileInfo): string $fileInfo = pathinfo($file); $extension = $fileInfo['extension'] ?? ''; $baseName = $fileInfo['basename'] ?: 'unknown'; + // Remove ASCII control characters (0x00-0x1F, 0x7F) and unsafe quotes/backslashes to avoid breaking header formatting + $baseName = preg_replace('/["\\\\\x00-\x1F\x7F]/', '', $baseName); + if ($baseName === '') { + $baseName = 'unknown'; + } if (!isset($headers['Content-Type'])) { if (isset(self::$mimeTypeMap[$extension])) { $head .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n"; @@ -534,12 +541,24 @@ public function __toString(): string $head .= "Server: workerman\r\n"; } foreach ($headers as $name => $value) { + // Skip unsafe header names + if (strpbrk($name, ":\r\n") !== false) { + continue; + } if (is_array($value)) { foreach ($value as $item) { + // Skip unsafe header values + if (strpbrk($item, "\r\n") !== false) { + continue; + } $head .= "$name: $item\r\n"; } continue; } + // Skip unsafe header values + if (strpbrk($value, "\r\n") !== false) { + continue; + } $head .= "$name: $value\r\n"; } @@ -559,7 +578,7 @@ public function __toString(): string if (!isset($headers['Transfer-Encoding'])) { $head .= "Content-Length: $bodyLen\r\n\r\n"; } else { - return $bodyLen ? "$head\r\n" . dechex($bodyLen) . "\r\n{$this->body}\r\n" : "$head\r\n"; + return $bodyLen ? "$head\r\n" . dechex($bodyLen) . "\r\n$this->body\r\n" : "$head\r\n"; } // The whole http package @@ -567,5 +586,3 @@ public function __toString(): string } } - -Response::init(); diff --git a/src/Protocols/Websocket.php b/src/Protocols/Websocket.php index 9a5b33c03..cc45a687b 100644 --- a/src/Protocols/Websocket.php +++ b/src/Protocols/Websocket.php @@ -483,6 +483,9 @@ public static function dealHandshake(string $buffer, TcpConnection $connection): if ($connection->headers) { foreach ($connection->headers as $header) { + if (strpbrk($header, "\r\n") !== false) { + continue; + } if (stripos($header, 'Server:') === 0) { $hasServerHeader = true; } diff --git a/src/Protocols/Ws.php b/src/Protocols/Ws.php index 199c7c998..3f1252ff4 100644 --- a/src/Protocols/Ws.php +++ b/src/Protocols/Ws.php @@ -368,16 +368,29 @@ public static function sendHandshake(AsyncTcpConnection $connection): void $userHeaderStr = ''; if (!empty($userHeader)) { foreach ($userHeader as $k => $v) { + // Skip unsafe header names or values containing CR/LF + if (strpbrk((string)$k, ":\r\n") !== false) { + continue; + } + if (strpbrk((string)$v, "\r\n") !== false) { + continue; + } $userHeaderStr .= "$k: $v\r\n"; } - $userHeaderStr = "\r\n" . trim($userHeaderStr); + $userHeaderStr = $userHeaderStr !== '' ? "\r\n" . trim($userHeaderStr) : ''; } - $header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n" . + $requestUri = str_replace(["\r", "\n"], '', $connection->getRemoteURI()); + // Sanitize Origin and Sec-WebSocket-Protocol + $origin = $connection->websocketOrigin ?? null; + $origin = $origin !== null ? str_replace(["\r", "\n"], '', $origin) : null; + $clientProtocol = $connection->websocketClientProtocol ?? null; + $clientProtocol = $clientProtocol !== null ? str_replace(["\r", "\n"], '', $clientProtocol) : null; + $header = 'GET ' . $requestUri . " HTTP/1.1\r\n" . (!preg_match("/\nHost:/i", $userHeaderStr) ? "Host: $host\r\n" : '') . "Connection: Upgrade\r\n" . "Upgrade: websocket\r\n" . - (($connection->websocketOrigin ?? null) ? "Origin: " . $connection->websocketOrigin . "\r\n" : '') . - (($connection->websocketClientProtocol ?? null) ? "Sec-WebSocket-Protocol: " . $connection->websocketClientProtocol . "\r\n" : '') . + ($origin ? "Origin: " . $origin . "\r\n" : '') . + ($clientProtocol ? "Sec-WebSocket-Protocol: " . $clientProtocol . "\r\n" : '') . "Sec-WebSocket-Version: 13\r\n" . "Sec-WebSocket-Key: " . $connection->context->websocketSecKey . $userHeaderStr . "\r\n\r\n"; $connection->send($header, true); From 937c3f2330f6cf4d94df510b4d61b8fc5af0a404 Mon Sep 17 00:00:00 2001 From: walkor Date: Sat, 8 Nov 2025 21:56:53 +0800 Subject: [PATCH 1171/1216] The first parameter of strpbrk needs to be a string. --- src/Protocols/Http/Response.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Protocols/Http/Response.php b/src/Protocols/Http/Response.php index 5a20d986f..3fc44ad67 100644 --- a/src/Protocols/Http/Response.php +++ b/src/Protocols/Http/Response.php @@ -467,13 +467,13 @@ protected function createHeadForFile(array $fileInfo): string } foreach ($headers as $name => $value) { // Skip unsafe header names - if (strpbrk($name, ":\r\n") !== false) { + if (strpbrk((string)$name, ":\r\n") !== false) { continue; } if (is_array($value)) { foreach ($value as $item) { // Skip unsafe header values - if (strpbrk($item, "\r\n") !== false) { + if (strpbrk((string)$item, "\r\n") !== false) { continue; } $head .= "$name: $item\r\n"; @@ -481,7 +481,7 @@ protected function createHeadForFile(array $fileInfo): string continue; } // Skip unsafe header values - if (strpbrk($value, "\r\n") !== false) { + if (strpbrk((string)$value, "\r\n") !== false) { continue; } $head .= "$name: $value\r\n"; @@ -542,13 +542,13 @@ public function __toString(): string } foreach ($headers as $name => $value) { // Skip unsafe header names - if (strpbrk($name, ":\r\n") !== false) { + if (strpbrk((string)$name, ":\r\n") !== false) { continue; } if (is_array($value)) { foreach ($value as $item) { // Skip unsafe header values - if (strpbrk($item, "\r\n") !== false) { + if (strpbrk((string)$item, "\r\n") !== false) { continue; } $head .= "$name: $item\r\n"; @@ -556,7 +556,7 @@ public function __toString(): string continue; } // Skip unsafe header values - if (strpbrk($value, "\r\n") !== false) { + if (strpbrk((string)$value, "\r\n") !== false) { continue; } $head .= "$name: $value\r\n"; From 9b83bdf9fd0eaff9419a240b47da870447583112 Mon Sep 17 00:00:00 2001 From: walkor Date: Wed, 12 Nov 2025 09:36:20 +0800 Subject: [PATCH 1172/1216] Fix "Workerman\Coroutine\Coroutine" not found --- src/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Worker.php b/src/Worker.php index bc11fa6ea..751b7230f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -25,7 +25,7 @@ use Workerman\Connection\ConnectionInterface; use Workerman\Connection\TcpConnection; use Workerman\Connection\UdpConnection; -use Workerman\Coroutine\Coroutine as Coroutine; +use Workerman\Coroutine; use Workerman\Coroutine\Context; use Workerman\Events\Event; use Workerman\Events\EventInterface; @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.5'; + final public const VERSION = '5.1.6'; /** * Status initial. From 3e49ef3068958cb53a797cc51d78e0d0e927a762 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 14 Nov 2025 17:21:04 +0800 Subject: [PATCH 1173/1216] Update version to 5.1.7 and document connections Increment version number to 5.1.7 and add internal API annotation. --- src/Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 751b7230f..54db49d85 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.6'; + final public const VERSION = '5.1.7'; /** * Status initial. @@ -248,6 +248,8 @@ class Worker /** * Store all connections of clients. * + * @internal Framework internal API + * * @var TcpConnection[] */ public array $connections = []; From e198341ba6e80cc3a730073dbef6438957318763 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 14 Nov 2025 17:21:36 +0800 Subject: [PATCH 1174/1216] Deprecate headers property in TcpConnection Mark headers property as deprecated and provide alternatives. --- src/Connection/TcpConnection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 09393ca92..c52c2e588 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -244,6 +244,10 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable public ?stdClass $context = null; /** + * Internal use only. Do not access or modify from application code. + * + * @internal Framework internal API + * @deprecated Do not set this property, use $response->header() or $response->widthHeaders() instead * @var array */ public array $headers = []; From d36d8ebd74d6c057038f252b979bbdfda84ce852 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 20 Nov 2025 12:02:43 +0800 Subject: [PATCH 1175/1216] Replace __wakeup with __unserialize --- src/Connection/TcpConnection.php | 5 +++-- src/Protocols/Http/Request.php | 5 +++-- src/Protocols/Http/Session.php | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index c52c2e588..fa642364d 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1093,11 +1093,12 @@ public function jsonSerialize(): array } /** - * __wakeup. + * __unserialize. * + * @param array $data * @return void */ - public function __wakeup() + public function __unserialize(array $data): void { $this->isSafe = false; } diff --git a/src/Protocols/Http/Request.php b/src/Protocols/Http/Request.php index b77b31db3..ccf759a07 100644 --- a/src/Protocols/Http/Request.php +++ b/src/Protocols/Http/Request.php @@ -734,11 +734,12 @@ public function __unset(string $name): void } /** - * Wakeup. + * __unserialize. * + * @param array $data * @return void */ - public function __wakeup(): void + public function __unserialize(array $data): void { $this->isSafe = false; } diff --git a/src/Protocols/Http/Session.php b/src/Protocols/Http/Session.php index 49b2a51b5..45c82b57b 100644 --- a/src/Protocols/Http/Session.php +++ b/src/Protocols/Http/Session.php @@ -428,11 +428,12 @@ public function gc(): void } /** - * __wakeup. + * __unserialize. * + * @param array $data * @return void */ - public function __wakeup() + public function __unserialize(array $data): void { $this->isSafe = false; } From 60f59224c0027d5e9793204206b97582271208e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=9C=88?= <102944161+lvluoyue@users.noreply.github.com> Date: Sat, 22 Nov 2025 20:31:59 +0800 Subject: [PATCH 1176/1216] fix: Cannot represent a stream of type phar stream as a select()able descriptor --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 54db49d85..a80842a36 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1607,7 +1607,7 @@ protected static function forkWorkersForWindows(): void // Compatibility with the bug in Swow where the first request on Windows fails to trigger stream_select. if (extension_loaded('swow')) { Timer::delay(0.1 , function(){ - $stream = fopen(__FILE__, 'r'); + $stream = fopen('php://memory', 'r'); static::$globalEvent->onReadable($stream, function($stream) { static::$globalEvent->offReadable($stream); }); From 7dfa8b9e3a58db73072d3db7e66f45fa60edfb56 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 12:49:38 +0100 Subject: [PATCH 1177/1216] Add PHP 8.5 to CI workflow matrix --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca86088cf..47d31986a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.1", "8.2", "8.3", "8.4"] + php: ["8.1", "8.2", "8.3", "8.4", "8.5"] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} @@ -48,3 +48,4 @@ jobs: - name: Execute tests run: composer test + From 35111abe111963ddffc7f135fabd1c3b7f0aa9e9 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 17:46:31 +0100 Subject: [PATCH 1178/1216] Update development dependencies in composer.json --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index aad377571..7c8179113 100644 --- a/composer.json +++ b/composer.json @@ -43,10 +43,10 @@ "ext-swow": " Date: Mon, 24 Nov 2025 18:05:28 +0100 Subject: [PATCH 1179/1216] Add ignore error for RedisClusterException in PHPStan --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 09e1dd405..d022c2045 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,6 +6,7 @@ parameters: excludePaths: - src/Events/Swow.php ignoreErrors: + - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' - path: src/Events/Fiber.php messages: From 3c32441a1fc25af1da26d4302e7409d6d549f3ea Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:07:32 +0100 Subject: [PATCH 1180/1216] Ignore error for RedisClusterException --- phpstan.neon.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index d022c2045..fa75728f6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,8 +6,8 @@ parameters: excludePaths: - src/Events/Swow.php ignoreErrors: - - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' - - + - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' + - path: src/Events/Fiber.php messages: - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' From 554e9d3e24c5b6873ac3d37299ec7ee99625e5c8 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:10:35 +0100 Subject: [PATCH 1181/1216] Refactor ignoreErrors section in phpstan.neon.dist --- phpstan.neon.dist | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fa75728f6..8d7dd9e04 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,22 +7,20 @@ parameters: - src/Events/Swow.php ignoreErrors: - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' - - - path: src/Events/Fiber.php - messages: - - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' - - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' - - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - - - path: src/Events/Event.php - reportUnmatched: false - messages: - - '#Call to an undefined method EventBase::+.#' + - path: src/Events/Fiber.php + messages: + - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' + - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' + - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' + - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' + - path: src/Events/Event.php + reportUnmatched: false + messages: + - '#Call to an undefined method EventBase::+.#' - path: src/Timer.php - message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' + message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - path: src/Worker.php - reportUnmatched: false - messages: - - '#Constant LINE_VERSION_LENGTH not found.#' - - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' + reportUnmatched: false + messages: + - '#Constant LINE_VERSION_LENGTH not found.#' + - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' From 3af02fe4941fdd52c8f06e7399c88e0b90486a52 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:11:48 +0100 Subject: [PATCH 1182/1216] Update phpstan.neon.dist From cf6a8472beb789b2a2917a0576c9c1e89aa7f6b4 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:17:12 +0100 Subject: [PATCH 1183/1216] Re-add ignored error for RedisClusterException type --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8d7dd9e04..1b5d34bb5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,7 +6,6 @@ parameters: excludePaths: - src/Events/Swow.php ignoreErrors: - - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' - path: src/Events/Fiber.php messages: - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' @@ -24,3 +23,4 @@ parameters: messages: - '#Constant LINE_VERSION_LENGTH not found.#' - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' + - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From 10bd804d6b11dfa58097caed33867c4ea9668e1c Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:29:29 +0100 Subject: [PATCH 1184/1216] Format ignoreErrors paths in phpstan.neon.dist --- phpstan.neon.dist | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1b5d34bb5..ee6ebf823 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,19 +6,23 @@ parameters: excludePaths: - src/Events/Swow.php ignoreErrors: - - path: src/Events/Fiber.php + - + path: src/Events/Fiber.php messages: - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - - path: src/Events/Event.php + - + path: src/Events/Event.php reportUnmatched: false messages: - '#Call to an undefined method EventBase::+.#' - - path: src/Timer.php + - + path: src/Timer.php message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - - path: src/Worker.php + - + path: src/Worker.php reportUnmatched: false messages: - '#Constant LINE_VERSION_LENGTH not found.#' From 3f5b6e36a7ef716783436f711e902a649dfdd688 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:34:24 +0100 Subject: [PATCH 1185/1216] Refactor ignoreErrors section in phpstan.neon.dist --- phpstan.neon.dist | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ee6ebf823..8b98cc2e8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,25 +6,23 @@ parameters: excludePaths: - src/Events/Swow.php ignoreErrors: - - - path: src/Events/Fiber.php - messages: - - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' - - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' - - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' - - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - - path: src/Events/Event.php - reportUnmatched: false - messages: - - '#Call to an undefined method EventBase::+.#' + path: src/Events/Fiber.php + messages: + - '#Property Workerman\\Events\\Fiber::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#' + - '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#' + - '#Method Workerman\\Events\\Fiber::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#' + - '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#' - - path: src/Timer.php - message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' - - - path: src/Worker.php - reportUnmatched: false - messages: - - '#Constant LINE_VERSION_LENGTH not found.#' - - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' + path: src/Events/Event.php + reportUnmatched: false + messages: + - '#Call to an undefined method EventBase::+.#' + - path: src/Timer.php + message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#' + - path: src/Worker.php + reportUnmatched: false + messages: + - '#Constant LINE_VERSION_LENGTH not found.#' + - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From f8cc623796799be2fe53f14591263a9f237a6730 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:36:29 +0100 Subject: [PATCH 1186/1216] Fix formatting issue in phpstan.neon.dist --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8b98cc2e8..62e8a6460 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,4 +25,4 @@ parameters: messages: - '#Constant LINE_VERSION_LENGTH not found.#' - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' - - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' + - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From 4eb4429953f9787f135bed59d62558469592e1f4 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:39:18 +0100 Subject: [PATCH 1187/1216] Fix PHPDoc tag @throws for RedisClusterException --- phpstan.neon.dist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 62e8a6460..849cd2e62 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,4 +25,5 @@ parameters: messages: - '#Constant LINE_VERSION_LENGTH not found.#' - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' - - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' + - + '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From 3e32e6124cf3fd460811671eaddcaa19a46e0ffe Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 18:41:02 +0100 Subject: [PATCH 1188/1216] Fix formatting in phpstan.neon.dist --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 849cd2e62..c7bf862fc 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,5 +25,5 @@ parameters: messages: - '#Constant LINE_VERSION_LENGTH not found.#' - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' - - + - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From 196a29f79b5be6de6ad876938dd17978f062cdd6 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 19:18:02 +0100 Subject: [PATCH 1189/1216] Disable analysis temporally --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47d31986a..63a6a3860 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,8 +44,9 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis - run: composer analyze + #run: composer analyze - name: Execute tests run: composer test + From c759a22270de64fedafca233c5a59fceb3ec0828 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 19:19:35 +0100 Subject: [PATCH 1190/1216] Restore test workflow with static analysis Reintroduce the test workflow configuration with static analysis step. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 63a6a3860..beecb0f72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,9 +44,10 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis - #run: composer analyze + run: composer analyze - name: Execute tests run: composer test + From 174025699a25feecc111b2f7abf98788e4c4c0c7 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 19:23:32 +0100 Subject: [PATCH 1191/1216] Update phpstan/phpstan version to 2.1.x-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7c8179113..ea719c5cf 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "pestphp/pest": "^4", "mockery/mockery": "^1.6", "guzzlehttp/guzzle": "^7.0", - "phpstan/phpstan": "^2.1" + "phpstan/phpstan": "2.1.x-dev" }, "config": { "allow-plugins": { From 8738cfcb0adc30604876c85c6cfdfd5dc4ab7652 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 19:24:39 +0100 Subject: [PATCH 1192/1216] Remove unused PHPDoc error message --- phpstan.neon.dist | 2 -- 1 file changed, 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index c7bf862fc..09e1dd405 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,5 +25,3 @@ parameters: messages: - '#Constant LINE_VERSION_LENGTH not found.#' - '#Call to static method create\(\) on an unknown class Workerman\\Coroutine\\Coroutine.#' - - - '#PHPDoc tag @throws with type RedisClusterException is not subtype of Throwable#' From 92968c936b57a1604905a9c37a25cff7fc3d1053 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 19:28:46 +0100 Subject: [PATCH 1193/1216] Downgrade pestphp/pest dependency to version 3 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ea719c5cf..6facfb61b 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 19:30:36 +0100 Subject: [PATCH 1194/1216] Downgrade pestphp/pest dependency to version 2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6facfb61b..252d6c52b 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 19:34:35 +0100 Subject: [PATCH 1195/1216] Update pestphp/pest version to 2.x-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 252d6c52b..726fd128a 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 19:39:01 +0100 Subject: [PATCH 1196/1216] Update pestphp/pest version constraint in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 726fd128a..c268bae5d 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 19:39:14 +0100 Subject: [PATCH 1197/1216] Fix formatting of pestphp/pest requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c268bae5d..252d6c52b 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 20:26:31 +0100 Subject: [PATCH 1198/1216] Upgrade test workflow to Ubuntu 24.04 Updated the PHP test workflow to use Ubuntu 24.04 and added continue-on-error for static analysis. --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index beecb0f72..85578f70b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ on: jobs: linux_tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -44,6 +44,7 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis + continue-on-error: true run: composer analyze - name: Execute tests @@ -51,3 +52,4 @@ jobs: + From 054ae0f0dd9c760a1a690d4be83669a37485c4c1 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 20:35:05 +0100 Subject: [PATCH 1199/1216] Bind TestCase class using uses() function --- tests/Pest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Pest.php b/tests/Pest.php index f2a84413a..066648232 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -11,6 +11,7 @@ | */ +uses(\Tests\TestCase::class); // uses(Tests\TestCase::class)->in('Feature'); /* From 42f20481f1bdeb67c81c46e32f49f0f3a42a3d22 Mon Sep 17 00:00:00 2001 From: Joan Miquel Date: Mon, 24 Nov 2025 20:38:28 +0100 Subject: [PATCH 1200/1216] Add PSR-4 autoloading for development tests --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 252d6c52b..c45ed78dd 100644 --- a/composer.json +++ b/composer.json @@ -38,6 +38,11 @@ "Workerman\\": "src" } }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, "minimum-stability": "dev", "conflict": { "ext-swow": " Date: Mon, 24 Nov 2025 20:51:17 +0100 Subject: [PATCH 1201/1216] Update pestphp/pest version constraints in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c45ed78dd..e17dd0a9f 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 21:47:57 +0100 Subject: [PATCH 1202/1216] Update pestphp/pest version constraint in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e17dd0a9f..c7cfe4898 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 21:50:49 +0100 Subject: [PATCH 1203/1216] Update pestphp/pest version constraint --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c7cfe4898..0787975b0 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "ext-swow": " Date: Mon, 24 Nov 2025 21:57:19 +0100 Subject: [PATCH 1204/1216] Update static analysis step in test workflow Removed comment for continue-on-error in static analysis step. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 85578f70b..a80c080f2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis - continue-on-error: true + #continue-on-error: true run: composer analyze - name: Execute tests @@ -53,3 +53,4 @@ jobs: + From d7330991c3b08f8f6875445b5cd7450ed7ba8b0d Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 11 Dec 2025 17:31:29 +0800 Subject: [PATCH 1205/1216] Fix #1131 --- src/Protocols/Http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 04b03b4a7..f01909afa 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -125,9 +125,9 @@ public static function input(string $buffer, TcpConnection $connection): int * * @param string $buffer * @param TcpConnection $connection - * @return Request + * @return mixed */ - public static function decode(string $buffer, TcpConnection $connection): Request + public static function decode(string $buffer, TcpConnection $connection): mixed { $request = new static::$requestClass($buffer); $request->connection = $connection; From 510eb286cf5254c626b08f94dc28adc6340d09b3 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 29 Dec 2025 11:44:19 +0800 Subject: [PATCH 1206/1216] Stricter HTTP header inspection --- src/Protocols/Http.php | 45 ++++++++---- tests/Unit/Protocols/HttpTest.php | 110 ++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 15 deletions(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index f01909afa..ce8eae1fc 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -88,26 +88,41 @@ public static function input(string $buffer, TcpConnection $connection): int } $length = $crlfPos + 4; - $header = substr($buffer, 0, $crlfPos); + // Only slice when necessary (avoid extra string copy). + // Keep the trailing "\r\n\r\n" in $header for simpler/faster validation patterns. + $header = isset($buffer[$length]) ? substr($buffer, 0, $length) : $buffer; - if ( - !str_starts_with($header, 'GET ') && - !str_starts_with($header, 'POST ') && - !str_starts_with($header, 'OPTIONS ') && - !str_starts_with($header, 'HEAD ') && - !str_starts_with($header, 'DELETE ') && - !str_starts_with($header, 'PUT ') && - !str_starts_with($header, 'PATCH ') - ) { + // Validate request line: METHOD SP request-target SP HTTP/1.0|1.1 CRLF + // Request-target validation: + // - Allow origin-form only (must start with "/") for all methods below. + // - Do NOT support asterisk-form ("*") for OPTIONS. + // - For compatibility, allow any bytes except ASCII control characters, spaces and DEL in request-target. + // (Strictly speaking, URI should be ASCII and non-ASCII should be percent-encoded; but many clients send UTF-8.) + // - Disallow "Transfer-Encoding" header (case-insensitive; line-start must be "\r\n" to avoid matching "x-Transfer-Encoding"). + // - Optionally capture Content-Length (case-insensitive; line-start must be "\r\n" to avoid matching "x-Content-Length"). + // - If Content-Length exists, it must be a valid decimal number and the whole field-value must be digits + optional OWS. + // - Disallow duplicate Content-Length headers. + // Note: All lookaheads are placed at \A so they can scan the entire header including the request line. + // Use [ \t]* instead of \s* to avoid matching across lines. + // The pattern uses case-insensitive modifier (~i) for header name matching. + $headerValidatePattern = '~\A' + // Optional: capture Content-Length value (must be at \A to scan entire header) + . '(?:(?=[\s\S]*\r\nContent-Length[ \t]*:[ \t]*(\d+)[ \t]*\r\n))?' + // Disallow Transfer-Encoding header + . '(?![\s\S]*\r\nTransfer-Encoding[ \t]*:)' + // If Content-Length header exists, its value must be pure digits + optional OWS + . '(?![\s\S]*\r\nContent-Length[ \t]*:(?![ \t]*\d+[ \t]*\r\n)[^\r]*\r\n)' + // Disallow duplicate Content-Length headers (adjacent or separated) + . '(?![\s\S]*\r\nContent-Length[ \t]*:[^\r\n]*\r\n(?:[\s\S]*?\r\n)?Content-Length[ \t]*:)' + // Match request line: METHOD SP request-target SP HTTP-version CRLF + . '(?:GET|POST|OPTIONS|HEAD|DELETE|PUT|PATCH) +\/[^\x00-\x20\x7f]* +HTTP\/1\.[01]\r\n~i'; + + if (!preg_match($headerValidatePattern, $header, $matches)) { $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); return 0; } - if (preg_match('/\b(?:Transfer-Encoding\b.*)|(?:Content-Length:\s*(\d+)(?!.*\bTransfer-Encoding\b))/is', $header, $matches)) { - if (!isset($matches[1])) { - $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); - return 0; - } + if (isset($matches[1])) { $length += (int)$matches[1]; } diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index 0dae90565..9b5f0479d 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -48,6 +48,116 @@ }, '413 Payload Too Large'); }); +it('tests ::input request-line and header validation matrix', function (string $buffer, int $expectedLength) { + /** @var TcpConnection&\Mockery\MockInterface $tcpConnection */ + $tcpConnection = Mockery::spy(TcpConnection::class); + $tcpConnection->maxPackageSize = 1024 * 1024; + expect(Http::input($buffer, $tcpConnection))->toBe($expectedLength); + $tcpConnection->shouldNotHaveReceived('close'); +})->with([ + 'minimal GET / HTTP/1.1' => [ + "GET / HTTP/1.1\r\n\r\n", + 18, // strlen("GET / HTTP/1.1\r\n\r\n") + ], + 'lowercase method and version is allowed' => [ + "get / http/1.1\r\n\r\n", + 18, + ], + 'all supported methods' => [ + "PATCH /a HTTP/1.0\r\n\r\n", + 21, // PATCH(5) + space + /a(2) + space + HTTP/1.0(8) + \r\n\r\n(4) = 21 + ], + 'GET with Content-Length is allowed and affects package length' => [ + "GET / HTTP/1.1\r\nContent-Length: 5\r\n\r\nhello", + strlen("GET / HTTP/1.1\r\nContent-Length: 5\r\n\r\n") + 5, // header length + body length + ], + 'request-target allows UTF-8 bytes (compatibility)' => [ + "GET /中文 HTTP/1.1\r\n\r\n", + strlen("GET /中文 HTTP/1.1\r\n\r\n"), + ], + 'pipeline: first request length is returned' => [ + "GET / HTTP/1.1\r\n\r\nGET /b HTTP/1.1\r\n\r\n", + 18, + ], + 'X-Transfer-Encoding does not trigger Transfer-Encoding ban' => [ + "GET / HTTP/1.1\r\nX-Transfer-Encoding: chunked\r\n\r\n", + 18 + strlen("X-Transfer-Encoding: chunked\r\n"), + ], +]); + +it('rejects invalid request-line cases in ::input', function (string $buffer) { + testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + expect(Http::input($buffer, $tcpConnection))->toBe(0); + }, '400 Bad Request'); +})->with([ + 'unknown method similar to valid one' => [ + "POSTS / HTTP/1.1\r\n\r\n", + ], + 'tab delimiter between method and path is not allowed' => [ + "GET\t/ HTTP/1.1\r\n\r\n", + ], + 'leading whitespace before method is not allowed' => [ + " GET / HTTP/1.1\r\n\r\n", + ], + 'absolute-form request-target is not supported' => [ + "GET http://example.com/ HTTP/1.1\r\n\r\n", + ], + 'asterisk-form request-target is not supported (including OPTIONS *)' => [ + "OPTIONS * HTTP/1.1\r\n\r\n", + ], + 'invalid http version' => [ + "GET / HTTP/2.0\r\n\r\n", + ], + 'invalid path contains space' => [ + "GET /a b HTTP/1.1\r\n\r\n", + ], + 'invalid path contains DEL' => [ + "GET /\x7f HTTP/1.1\r\n\r\n", + ], + 'CRLF injection attempt in request-target' => [ + "GET /foo\r\nX: y HTTP/1.1\r\n\r\n", + ], +]); + +it('rejects Transfer-Encoding and bad/duplicate Content-Length in ::input', function (string $buffer, ?string $expectedCloseContains = '400 Bad Request') { + testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + expect(Http::input($buffer, $tcpConnection))->toBe(0); + }, $expectedCloseContains); +})->with([ + 'Transfer-Encoding is forbidden (case-insensitive)' => [ + "GET / HTTP/1.1\r\ntransfer-encoding: chunked\r\n\r\n", + '400 Bad Request', + ], + 'Content-Length must be digits (not a number)' => [ + "GET / HTTP/1.1\r\nContent-Length: abc\r\n\r\n", + '400 Bad Request', + ], + 'Content-Length must be digits (digits + letters)' => [ + "GET / HTTP/1.1\r\nContent-Length: 12abc\r\n\r\n", + '400 Bad Request', + ], + 'Content-Length must be digits (empty value)' => [ + "GET / HTTP/1.1\r\nContent-Length: \r\n\r\n", + '400 Bad Request', + ], + 'Content-Length must be digits (comma list)' => [ + "GET / HTTP/1.1\r\nContent-Length: 1,2\r\n\r\n", + '400 Bad Request', + ], + 'duplicate Content-Length (adjacent)' => [ + "GET / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 1\r\n\r\nx", + '400 Bad Request', + ], + 'duplicate Content-Length (separated by other header, case-insensitive)' => [ + "GET / HTTP/1.1\r\ncontent-length: 1\r\nX: y\r\nContent-Length: 1\r\n\r\nx", + '400 Bad Request', + ], + 'very large numeric Content-Length should be rejected by maxPackageSize (413)' => [ + "GET / HTTP/1.1\r\nContent-Length: 999999999999999999999999999999999999\r\n\r\n", + '413 Payload Too Large', + ], +]); + it('tests ::encode for non-object response', function () { /** @var TcpConnection $tcpConnection */ $tcpConnection = Mockery::mock(TcpConnection::class); From 54749c341c6d471d94fbeeb2eed4475f133c7379 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 5 Jan 2026 16:36:13 +0800 Subject: [PATCH 1207/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index a80842a36..d6858c0a7 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1607,7 +1607,7 @@ protected static function forkWorkersForWindows(): void // Compatibility with the bug in Swow where the first request on Windows fails to trigger stream_select. if (extension_loaded('swow')) { Timer::delay(0.1 , function(){ - $stream = fopen('php://memory', 'r'); + $stream = tmpfile(); static::$globalEvent->onReadable($stream, function($stream) { static::$globalEvent->offReadable($stream); }); From a314755259375fbeb6051e27171fcdb46e7ba2ca Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 5 Jan 2026 16:36:38 +0800 Subject: [PATCH 1208/1216] Update Worker.php --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index d6858c0a7..0276eaf7f 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.7'; + final public const VERSION = '5.1.8'; /** * Status initial. From 21e154ffe4ff7fac807d388abb79cde94edb4044 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Jan 2026 13:25:51 +0800 Subject: [PATCH 1209/1216] Support connection->end() --- src/Connection/TcpConnection.php | 125 +++++++++++++++++++++++++++++- src/Protocols/Http.php | 4 +- tests/Pest.php | 13 ++++ tests/Unit/Protocols/HttpTest.php | 18 ++++- 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index fa642364d..612ffc3c4 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -22,6 +22,7 @@ use Workerman\Events\EventInterface; use Workerman\Protocols\Http; use Workerman\Protocols\Http\Request; +use Workerman\Timer; use Workerman\Worker; use function ceil; @@ -40,6 +41,7 @@ use function set_error_handler; use function stream_set_blocking; use function stream_set_read_buffer; +use function stream_socket_shutdown; use function stream_socket_enable_crypto; use function stream_socket_get_name; use function strlen; @@ -53,6 +55,7 @@ use const STREAM_CRYPTO_METHOD_SSLv23_SERVER; use const STREAM_CRYPTO_METHOD_SSLv2_CLIENT; use const STREAM_CRYPTO_METHOD_SSLv2_SERVER; +use const STREAM_SHUT_WR; /** * TcpConnection. @@ -90,6 +93,13 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public const STATUS_ESTABLISHED = 2; + /** + * Status ending (graceful close: write -> FIN -> linger/drain -> close). + * + * @var int + */ + public const STATUS_ENDING = 16; + /** * Status closing. * @@ -280,6 +290,20 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ public static int $defaultMaxPackageSize = 10485760; + /** + * Default linger timeout for graceful end (seconds). + * + * @var float + */ + public static float $defaultLingerTimeout = 1.0; + + /** + * Linger timeout for graceful end (seconds). + * + * @var float + */ + public float $lingerTimeout = 1.0; + /** * Id recorder. * @@ -322,6 +346,20 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable */ protected int $status = self::STATUS_ESTABLISHED; + /** + * Linger timer id for end(). + * + * @var int + */ + protected int $endLingerTimerId = 0; + + /** + * Whether write side has been shutdown (FIN sent) during end(). + * + * @var bool + */ + protected bool $endWriteShutdown = false; + /** * Remote address. * @@ -360,6 +398,7 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable self::STATUS_CONNECTING => 'CONNECTING', self::STATUS_ESTABLISHED => 'ESTABLISHED', self::STATUS_CLOSING => 'CLOSING', + self::STATUS_ENDING => 'ENDING', self::STATUS_CLOSED => 'CLOSED', ]; @@ -384,6 +423,7 @@ public function __construct(EventInterface $eventLoop, $socket, string $remoteAd $this->eventLoop->onReadable($this->socket, $this->baseRead(...)); $this->maxSendBufferSize = self::$defaultMaxSendBufferSize; $this->maxPackageSize = self::$defaultMaxPackageSize; + $this->lingerTimeout = self::$defaultLingerTimeout; $this->remoteAddress = $remoteAddress; static::$connections[$this->id] = $this; $this->context = new stdClass(); @@ -413,7 +453,7 @@ public function getStatus(bool $rawOutput = true): int|string */ public function send(mixed $sendBuffer, bool $raw = false): bool|null { - if ($this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { + if ($this->status === self::STATUS_ENDING || $this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { return false; } @@ -662,6 +702,9 @@ public function baseRead($socket, bool $checkEof = true): void } } else { $this->bytesRead += strlen($buffer); + if ($this->status === self::STATUS_ENDING) { + return; + } if ($this->recvBuffer === '') { if (!isset($buffer[static::MAX_CACHE_STRING_LENGTH]) && isset($requests[$buffer])) { ++self::$statistics['total_request']; @@ -805,6 +848,9 @@ public function baseWrite(): void $this->error($e); } } + if ($this->status === self::STATUS_ENDING) { + $this->endMaybeShutdownWrite(); + } if ($this->status === self::STATUS_CLOSING) { if (!empty($this->context->streamSending)) { return; @@ -907,7 +953,7 @@ public function consumeRecvBuffer(int $length): void */ public function close(mixed $data = null, bool $raw = false): void { - if ($this->status === self::STATUS_CONNECTING) { + if ($this->status === self::STATUS_INITIAL || $this->status === self::STATUS_CONNECTING) { $this->destroy(); return; } @@ -929,6 +975,80 @@ public function close(mixed $data = null, bool $raw = false): void } } + /** + * Graceful end connection. + * It tries to: send response -> wait sendBuffer empty -> shutdown write(FIN) -> linger/drain reads -> close(). + * + * @param mixed $data + * @param bool $raw + * @return void + */ + public function end(mixed $data = null, bool $raw = false): void + { + if ($this->status === self::STATUS_INITIAL || $this->status === self::STATUS_CONNECTING) { + $this->destroy(); + return; + } + + if ($this->status === self::STATUS_ENDING || $this->status === self::STATUS_CLOSING || $this->status === self::STATUS_CLOSED) { + return; + } + + if ($data !== null) { + $this->send($data, $raw); + } + + // Enter ending mode: stop protocol parsing and only drain incoming data. + $this->status = self::STATUS_ENDING; + // Disable business callback after end(). + $this->onMessage = static function (self $connection, mixed $data = null): void { + }; + $this->recvBuffer = ''; + $this->currentPackageLength = 0; + + // If already flushed to kernel, shutdown write now. Otherwise, baseWrite() will call endMaybeShutdownWrite() + // when sendBuffer becomes empty. + if ($this->sendBuffer === '') { + $this->endMaybeShutdownWrite(); + return; + } + } + + /** + * If in ENDING and sendBuffer is empty, shutdown write side and start linger timer. + * + * @return void + */ + protected function endMaybeShutdownWrite(): void + { + if ($this->status !== self::STATUS_ENDING || $this->endWriteShutdown || $this->sendBuffer !== '') { + return; + } + + if (is_resource($this->socket)) { + try { + @stream_socket_shutdown($this->socket, STREAM_SHUT_WR); + } catch (Throwable) { + // ignore + } + } + $this->endWriteShutdown = true; + + $timeout = $this->lingerTimeout; + if ($timeout <= 0) { + $this->close(); + return; + } + + $this->endLingerTimerId = Timer::delay($timeout, function (): void { + $this->endLingerTimerId = 0; + if ($this->status === self::STATUS_CLOSED) { + return; + } + $this->close(); + }); + } + /** * Is ipv4. * @@ -1058,6 +1178,7 @@ public function destroy(): void $this->sendBuffer = $this->recvBuffer = ''; $this->currentPackageLength = 0; $this->isPaused = $this->sslHandshakeCompleted = false; + $this->endWriteShutdown = false; if ($this->status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = $this->eventLoop = $this->errorHandler = null; diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index ce8eae1fc..3795ddda2 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -82,7 +82,7 @@ public static function input(string $buffer, TcpConnection $connection): int if (false === $crlfPos) { // Judge whether the package length exceeds the limit. if (strlen($buffer) >= 16384) { - $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); + $connection->end("HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", true); } return 0; } @@ -127,7 +127,7 @@ public static function input(string $buffer, TcpConnection $connection): int } if ($length > $connection->maxPackageSize) { - $connection->close("HTTP/1.1 413 Payload Too Large\r\n\r\n", true); + $connection->end("HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", true); return 0; } diff --git a/tests/Pest.php b/tests/Pest.php index 066648232..fffdbfc7b 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -56,6 +56,19 @@ function testWithConnectionClose(Closure $closure, ?string $dataContains = null, } } +function testWithConnectionEnd(Closure $closure, ?string $dataContains = null, $connectionClass = TcpConnection::class): void +{ + $tcpConnection = Mockery::spy($connectionClass); + $closure($tcpConnection); + if ($dataContains) { + $tcpConnection->shouldHaveReceived('end', function ($actual) use ($dataContains) { + return str_contains($actual, $dataContains); + }); + } else { + $tcpConnection->shouldHaveReceived('end'); + } +} + function getNonFrameOutput(string $output): string { $end = "Start success.\n"; diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index 9b5f0479d..def85f67a 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -21,7 +21,7 @@ it('tests ::input', function () { //test 413 payload too large - testWithConnectionClose(function (TcpConnection $tcpConnection) { + testWithConnectionEnd(function (TcpConnection $tcpConnection) { expect(Http::input(str_repeat('jhdxr', 3333), $tcpConnection)) ->toBe(0); }, '413 Payload Too Large'); @@ -41,13 +41,22 @@ }, '400 Bad Request'); //content-length exceeds connection max package size - testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionEnd(function (TcpConnection $tcpConnection) use ($buffer) { $tcpConnection->maxPackageSize = 10; expect(Http::input($buffer, $tcpConnection)) ->toBe(0); }, '413 Payload Too Large'); }); +it('sends 413 with Connection: close header', function () { + /** @var TcpConnection&\Mockery\MockInterface $tcpConnection */ + $tcpConnection = Mockery::spy(TcpConnection::class); + Http::input(str_repeat('a', 16384), $tcpConnection); + $tcpConnection->shouldHaveReceived('end', function ($actual) { + return str_contains($actual, '413 Payload Too Large') && str_contains($actual, "Connection: close\r\n"); + }); +}); + it('tests ::input request-line and header validation matrix', function (string $buffer, int $expectedLength) { /** @var TcpConnection&\Mockery\MockInterface $tcpConnection */ $tcpConnection = Mockery::spy(TcpConnection::class); @@ -120,7 +129,10 @@ ]); it('rejects Transfer-Encoding and bad/duplicate Content-Length in ::input', function (string $buffer, ?string $expectedCloseContains = '400 Bad Request') { - testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + $helper = ($expectedCloseContains && str_contains($expectedCloseContains, '413')) + ? 'testWithConnectionEnd' + : 'testWithConnectionClose'; + $helper(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input($buffer, $tcpConnection))->toBe(0); }, $expectedCloseContains); })->with([ From 3453c94e914ccb5d55a498b7a466552dad681952 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Jan 2026 13:27:45 +0800 Subject: [PATCH 1210/1216] Support connection->end() --- src/Connection/TcpConnection.php | 3 +- .../TcpConnectionEndOnMessageTest.php | 48 +++++++++++++++++++ .../Unit/Connection/TcpConnectionEndTest.php | 37 ++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Connection/TcpConnectionEndOnMessageTest.php create mode 100644 tests/Unit/Connection/TcpConnectionEndTest.php diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 612ffc3c4..5cdcc66fb 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -1001,8 +1001,7 @@ public function end(mixed $data = null, bool $raw = false): void // Enter ending mode: stop protocol parsing and only drain incoming data. $this->status = self::STATUS_ENDING; // Disable business callback after end(). - $this->onMessage = static function (self $connection, mixed $data = null): void { - }; + $this->onMessage = static function (self $connection, mixed $data = null): void {}; $this->recvBuffer = ''; $this->currentPackageLength = 0; diff --git a/tests/Unit/Connection/TcpConnectionEndOnMessageTest.php b/tests/Unit/Connection/TcpConnectionEndOnMessageTest.php new file mode 100644 index 000000000..6d32a35a4 --- /dev/null +++ b/tests/Unit/Connection/TcpConnectionEndOnMessageTest.php @@ -0,0 +1,48 @@ +not->toBeFalse(); + + $serverName = stream_socket_get_name($server, false); + expect($serverName)->not->toBeFalse(); + + $client = stream_socket_client('tcp://' . $serverName, $errno, $errstr, 1); + expect($client)->not->toBeFalse(); + + $accepted = stream_socket_accept($server, 1); + expect($accepted)->not->toBeFalse(); + + $remoteAddress = (string)stream_socket_get_name($accepted, true); + $connection = new TcpConnection($event, $accepted, $remoteAddress); + $connection->protocol = Text::class; + $connection->lingerTimeout = 0.01; + + $calls = 0; + $connection->onMessage = function (TcpConnection $c, string $msg) use (&$calls): void { + $calls++; + if ($msg === 'a') { + // Simulate app deciding to end() while there is another pipelined message in buffer. + $c->end(); + } + }; + + fwrite($client, "a\nb\n"); + + $event->delay(0.03, static fn () => $event->stop()); + $event->run(); + + expect($calls)->toBe(1); + + fclose($client); + fclose($server); +}); + diff --git a/tests/Unit/Connection/TcpConnectionEndTest.php b/tests/Unit/Connection/TcpConnectionEndTest.php new file mode 100644 index 000000000..d2ea22f0a --- /dev/null +++ b/tests/Unit/Connection/TcpConnectionEndTest.php @@ -0,0 +1,37 @@ +not->toBeFalse(); + + $serverName = stream_socket_get_name($server, false); + expect($serverName)->not->toBeFalse(); + + $client = stream_socket_client('tcp://' . $serverName, $errno, $errstr, 1); + expect($client)->not->toBeFalse(); + + $accepted = stream_socket_accept($server, 1); + expect($accepted)->not->toBeFalse(); + + $remoteAddress = (string)stream_socket_get_name($accepted, true); + $connection = new TcpConnection($event, $accepted, $remoteAddress); + $connection->lingerTimeout = 0.01; + + $connection->end(); + + $event->delay(0.03, static fn () => $event->stop()); + $event->run(); + + expect($connection->getStatus())->toBe(TcpConnection::STATUS_CLOSED); + + fclose($client); + fclose($server); +}); + From 56c4b6335a2a9557fcf47b14006852558365ae53 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Jan 2026 13:35:14 +0800 Subject: [PATCH 1211/1216] Update HttpTest.php --- tests/Unit/Protocols/HttpTest.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/Unit/Protocols/HttpTest.php b/tests/Unit/Protocols/HttpTest.php index def85f67a..5d8225f26 100644 --- a/tests/Unit/Protocols/HttpTest.php +++ b/tests/Unit/Protocols/HttpTest.php @@ -35,7 +35,7 @@ '{"key": "value", "foo": "bar"}'; //unrecognized method - testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionEnd(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input(str_replace('POST', 'MIAOWU', $buffer), $tcpConnection)) ->toBe(0); }, '400 Bad Request'); @@ -95,7 +95,7 @@ ]); it('rejects invalid request-line cases in ::input', function (string $buffer) { - testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionEnd(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input($buffer, $tcpConnection))->toBe(0); }, '400 Bad Request'); })->with([ @@ -129,10 +129,7 @@ ]); it('rejects Transfer-Encoding and bad/duplicate Content-Length in ::input', function (string $buffer, ?string $expectedCloseContains = '400 Bad Request') { - $helper = ($expectedCloseContains && str_contains($expectedCloseContains, '413')) - ? 'testWithConnectionEnd' - : 'testWithConnectionClose'; - $helper(function (TcpConnection $tcpConnection) use ($buffer) { + testWithConnectionEnd(function (TcpConnection $tcpConnection) use ($buffer) { expect(Http::input($buffer, $tcpConnection))->toBe(0); }, $expectedCloseContains); })->with([ From b400edb7e3a99527fe1951ee36b4a5ed13362f57 Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Jan 2026 13:36:00 +0800 Subject: [PATCH 1212/1216] Use connection->end to send response --- src/Protocols/Http.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocols/Http.php b/src/Protocols/Http.php index 3795ddda2..1cd77f425 100644 --- a/src/Protocols/Http.php +++ b/src/Protocols/Http.php @@ -118,7 +118,7 @@ public static function input(string $buffer, TcpConnection $connection): int . '(?:GET|POST|OPTIONS|HEAD|DELETE|PUT|PATCH) +\/[^\x00-\x20\x7f]* +HTTP\/1\.[01]\r\n~i'; if (!preg_match($headerValidatePattern, $header, $matches)) { - $connection->close("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n", true); + $connection->end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", true); return 0; } From 9e43049c245ada8cfc0ffe7eeb76af92ccb06b6b Mon Sep 17 00:00:00 2001 From: walkor Date: Thu, 8 Jan 2026 13:36:32 +0800 Subject: [PATCH 1213/1216] Bump version to 5.1.9 --- src/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Worker.php b/src/Worker.php index 0276eaf7f..ccfac34aa 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -61,7 +61,7 @@ class Worker * * @var string */ - final public const VERSION = '5.1.8'; + final public const VERSION = '5.1.9'; /** * Status initial. From fff0954628f8ceeccfe29d3e817f0fad87cfdbf2 Mon Sep 17 00:00:00 2001 From: walkor Date: Fri, 9 Jan 2026 11:26:15 +0800 Subject: [PATCH 1214/1216] Update TCP connection status constants --- src/Connection/TcpConnection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Connection/TcpConnection.php b/src/Connection/TcpConnection.php index 5cdcc66fb..e1aa16cac 100644 --- a/src/Connection/TcpConnection.php +++ b/src/Connection/TcpConnection.php @@ -98,21 +98,21 @@ class TcpConnection extends ConnectionInterface implements JsonSerializable * * @var int */ - public const STATUS_ENDING = 16; + public const STATUS_ENDING = 4; /** * Status closing. * * @var int */ - public const STATUS_CLOSING = 4; + public const STATUS_CLOSING = 8; /** * Status closed. * * @var int */ - public const STATUS_CLOSED = 8; + public const STATUS_CLOSED = 16; /** * Maximum string length for cache From 431b6148314c8947bf2c5d6dadc353b971208293 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 2 Feb 2026 20:13:44 +0800 Subject: [PATCH 1215/1216] Update test.yml --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a80c080f2..df72b653e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress --ansi + command: composer update --${{ matrix.stability }} --prefer-lowest --prefer-dist --no-interaction --no-progress --ansi - name: Static analysis #continue-on-error: true @@ -54,3 +54,4 @@ jobs: + From ec01de811258ab4690f5901440c9d4b5793fb418 Mon Sep 17 00:00:00 2001 From: walkor Date: Mon, 2 Feb 2026 20:18:11 +0800 Subject: [PATCH 1216/1216] Update PHP versions in GitHub Actions workflow --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df72b653e..2217be681 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.1", "8.2", "8.3", "8.4", "8.5"] + php: ["8.2", "8.3", "8.4", "8.5"] stability: [prefer-lowest, prefer-stable] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} @@ -55,3 +55,4 @@ jobs: +