Переглянути джерело

Merge pull request #1 from walkor/master

update
Littlefatty Wong 6 роки тому
батько
коміт
6b3703831f

+ 9 - 9
Autoloader.php

@@ -44,21 +44,21 @@ class Autoloader
      */
     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';
+                $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 (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 @@ class Autoloader
     }
 }
 
-spl_autoload_register('\Workerman\Autoloader::loadByNamespace');
+\spl_autoload_register('\Workerman\Autoloader::loadByNamespace');

+ 45 - 42
Connection/AsyncTcpConnection.php

@@ -16,7 +16,7 @@ namespace Workerman\Connection;
 use Workerman\Events\EventInterface;
 use Workerman\Lib\Timer;
 use Workerman\Worker;
-use Exception;
+use \Exception;
 
 /**
  * AsyncTcpConnection.
@@ -26,7 +26,7 @@ class AsyncTcpConnection extends TcpConnection
     /**
      * Emitted when socket connection is successfully established.
      *
-     * @var callback
+     * @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,11 +109,11 @@ 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 = array())
     {
-        $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'));
             }
@@ -137,16 +137,16 @@ class AsyncTcpConnection extends TcpConnection
         }
 
         $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)) {
+            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,24 +173,24 @@ class AsyncTcpConnection extends TcpConnection
             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}",
-                    $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, $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);
+                $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,
-                STREAM_CLIENT_ASYNC_CONNECT);
+            $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);
+        if (!$this->_socket || !\is_resource($this->_socket)) {
+            $this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr);
             if ($this->_status === self::STATUS_CLOSING) {
                 $this->destroy();
             }
@@ -202,7 +202,7 @@ class AsyncTcpConnection extends TcpConnection
         // 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'));
         }
     }
@@ -269,7 +269,7 @@ class AsyncTcpConnection extends TcpConnection
         $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);
@@ -288,36 +288,39 @@ class AsyncTcpConnection extends TcpConnection
      */
     public function checkConnection()
     {
-        if ($this->_status != self::STATUS_CONNECTING) {
-            return;
-        }
-
         // Remove EV_EXPECT for windows.
-        if(DIRECTORY_SEPARATOR === '\\') {
+        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)) {
+        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);
+            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);
             }
 
-            // Remove write listener.
-            Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
-
             // 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) {
@@ -334,7 +337,7 @@ class AsyncTcpConnection extends TcpConnection
             // 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);
@@ -344,9 +347,9 @@ class AsyncTcpConnection extends TcpConnection
                 }
             }
             // 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);
@@ -357,7 +360,7 @@ class AsyncTcpConnection extends TcpConnection
             }
         } 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();
             }

+ 22 - 19
Connection/AsyncUdpConnection.php

@@ -15,7 +15,7 @@ namespace Workerman\Connection;
 
 use Workerman\Events\EventInterface;
 use Workerman\Worker;
-use Exception;
+use \Exception;
 
 /**
  * AsyncTcpConnection.
@@ -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;
 
@@ -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 @@ class AsyncUdpConnection extends UdpConnection
      */
     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 @@ class AsyncUdpConnection extends UdpConnection
             }
             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);
@@ -121,13 +121,13 @@ class AsyncUdpConnection extends UdpConnection
             $parser      = $this->protocol;
             $send_buffer = $parser::encode($send_buffer, $this);
             if ($send_buffer === '') {
-                return null;
+                return;
             }
         }
         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 @@ class AsyncUdpConnection extends UdpConnection
             $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,17 +174,20 @@ class AsyncUdpConnection extends UdpConnection
             return;
         }
         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));
             return;
         }
+        
+        \stream_set_blocking($this->_socket, false);
+        
         if ($this->onMessage) {
             Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
         }
@@ -192,7 +195,7 @@ class AsyncUdpConnection extends UdpConnection
         // 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);

+ 4 - 4
Connection/ConnectionInterface.php

@@ -33,28 +33,28 @@ 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;
 
     /**
      * Sends data on the connection.
      *
-     * @param string $send_buffer
+     * @param mixed $send_buffer
      * @return void|boolean
      */
     abstract public function send($send_buffer);

+ 132 - 105
Connection/TcpConnection.php

@@ -15,7 +15,7 @@ namespace Workerman\Connection;
 
 use Workerman\Events\EventInterface;
 use Workerman\Worker;
-use Exception;
+use \Exception;
 
 /**
  * TcpConnection.
@@ -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;
 
@@ -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.
@@ -262,11 +269,11 @@ 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)) {
+        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);
@@ -287,17 +294,18 @@ class TcpConnection extends ConnectionInterface
     {
         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;
-        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;
+        $this->maxPackageSize           = self::$defaultMaxPackageSize;
         $this->_remoteAddress           = $remote_address;
         static::$connections[$this->id] = $this;
     }
@@ -307,7 +315,7 @@ class TcpConnection extends ConnectionInterface
      *
      * @param bool $raw_output
      *
-     * @return int
+     * @return int|string
      */
     public function getStatus($raw_output = true)
     {
@@ -320,7 +328,7 @@ class TcpConnection extends ConnectionInterface
     /**
      * Sends data on the connection.
      *
-     * @param string $send_buffer
+     * @param mixed $send_buffer
      * @param bool  $raw
      * @return bool|null
      */
@@ -335,22 +343,20 @@ class TcpConnection extends ConnectionInterface
             $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.
@@ -359,27 +365,27 @@ class TcpConnection extends ConnectionInterface
                 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);
-            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);
@@ -396,17 +402,17 @@ class TcpConnection extends ConnectionInterface
             Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
             // Check if the send buffer will be full.
             $this->checkBufferWillFull();
-            return null;
-        } else {
-            if ($this->bufferIsFull()) {
-                self::$statistics['send_fail']++;
-                return false;
-            }
+            return;
+        }
 
-            $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();
     }
 
     /**
@@ -416,9 +422,9 @@ class TcpConnection extends ConnectionInterface
      */
     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 '';
     }
@@ -431,7 +437,7 @@ class TcpConnection extends ConnectionInterface
     public function getRemotePort()
     {
         if ($this->_remoteAddress) {
-            return (int)substr(strrchr($this->_remoteAddress, ':'), 1);
+            return (int)\substr(\strrchr($this->_remoteAddress, ':'), 1);
         }
         return 0;
     }
@@ -454,11 +460,11 @@ class TcpConnection extends ConnectionInterface
     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);
     }
 
     /**
@@ -469,11 +475,11 @@ class TcpConnection extends ConnectionInterface
     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);
     }
 
     /**
@@ -483,7 +489,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function getLocalAddress()
     {
-        return (string)@stream_socket_get_name($this->_socket, false);
+        return (string)@\stream_socket_get_name($this->_socket, false);
     }
 
     /**
@@ -493,7 +499,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function getSendBufferQueueSize()
     {
-        return strlen($this->_sendBuffer);
+        return \strlen($this->_sendBuffer);
     }
 
     /**
@@ -503,7 +509,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function getRecvBufferQueueSize()
     {
-        return strlen($this->_recvBuffer);
+        return \strlen($this->_recvBuffer);
     }
 
     /**
@@ -516,7 +522,7 @@ class TcpConnection extends ConnectionInterface
         if ($this->transport === 'unix') {
             return false;
         }
-        return strpos($this->getRemoteIp(), ':') === false;
+        return \strpos($this->getRemoteIp(), ':') === false;
     }
 
     /**
@@ -529,7 +535,7 @@ class TcpConnection extends ConnectionInterface
         if ($this->transport === 'unix') {
             return false;
         }
-        return strpos($this->getRemoteIp(), ':') !== false;
+        return \strpos($this->getRemoteIp(), ':') !== false;
     }
 
     /**
@@ -580,18 +586,18 @@ class TcpConnection extends ConnectionInterface
             }
         }
 
-        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;
         }
 
@@ -602,27 +608,27 @@ class TcpConnection extends ConnectionInterface
                 // 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 <= static::$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;
                     }
@@ -631,14 +637,14 @@ class TcpConnection extends ConnectionInterface
                 // 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;
@@ -647,7 +653,7 @@ class TcpConnection extends ConnectionInterface
                 }
                 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);
@@ -670,7 +676,7 @@ class TcpConnection extends ConnectionInterface
             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);
@@ -689,21 +695,21 @@ class TcpConnection extends ConnectionInterface
      */
     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);
@@ -719,7 +725,7 @@ class TcpConnection extends ConnectionInterface
         }
         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();
@@ -733,36 +739,47 @@ class TcpConnection extends ConnectionInterface
      * @return bool
      */
     public function doSslHandshake($socket){
-        if (feof($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.
+          */
+        /*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;
+            $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, $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();
             return false;
         } elseif (0 === $ret) {
             // There isn't enough data and should try again.
-            return false;
+            return 0;
         }
         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);
@@ -777,10 +794,10 @@ class TcpConnection extends ConnectionInterface
     /**
      * 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) {
@@ -805,7 +822,7 @@ class TcpConnection extends ConnectionInterface
      */
     public function consumeRecvBuffer($length)
     {
-        $this->_recvBuffer = substr($this->_recvBuffer, $length);
+        $this->_recvBuffer = \substr($this->_recvBuffer, $length);
     }
 
     /**
@@ -817,16 +834,25 @@ class TcpConnection extends ConnectionInterface
      */
     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 {
-            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 {
+            $this->pauseRecv();
         }
     }
 
@@ -847,10 +873,10 @@ class TcpConnection extends ConnectionInterface
      */
     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);
@@ -870,10 +896,10 @@ class TcpConnection extends ConnectionInterface
     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);
@@ -913,15 +939,15 @@ class TcpConnection extends ConnectionInterface
         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);
@@ -931,9 +957,9 @@ class TcpConnection extends ConnectionInterface
             }
         }
         // 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);
@@ -942,6 +968,7 @@ class TcpConnection extends ConnectionInterface
                 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;
@@ -964,11 +991,11 @@ class TcpConnection extends ConnectionInterface
         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)');
+                Worker::log('worker[' . \posix_getpid() . '] remains ' . self::$statistics['connection_count'] . ' connection(s)');
             }
 
             if(0 === self::$statistics['connection_count']) {

+ 14 - 14
Connection/UdpConnection.php

@@ -65,10 +65,10 @@ class UdpConnection extends ConnectionInterface
             $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);
+        return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress);
     }
 
     /**
@@ -78,9 +78,9 @@ class UdpConnection extends ConnectionInterface
      */
     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 @@ class UdpConnection extends ConnectionInterface
     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 @@ class UdpConnection extends ConnectionInterface
     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 @@ class UdpConnection extends ConnectionInterface
     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,33 +145,33 @@ class UdpConnection extends ConnectionInterface
      */
     public function getLocalAddress()
     {
-        return (string)@stream_socket_get_name($this->_socket, false);
+        return (string)@\stream_socket_get_name($this->_socket, false);
     }
 
     /**
      * Is ipv4.
      *
-     * return bool.
+     * @return bool.
      */
     public function isIpV4()
     {
         if ($this->transport === 'unix') {
             return false;
         }
-        return strpos($this->getRemoteIp(), ':') === false;
+        return \strpos($this->getRemoteIp(), ':') === false;
     }
 
     /**
      * Is ipv6.
      *
-     * return bool.
+     * @return bool.
      */
     public function isIpV6()
     {
         if ($this->transport === 'unix') {
             return false;
         }
-        return strpos($this->getRemoteIp(), ':') !== false;
+        return \strpos($this->getRemoteIp(), ':') !== false;
     }
 
     /**

+ 7 - 6
Events/Ev.php

@@ -13,6 +13,7 @@
 namespace Workerman\Events;
 
 use Workerman\Worker;
+use \EvWatcher;
 
 /**
  * ev eventloop
@@ -56,7 +57,7 @@ class Ev implements EventInterface
     {
         $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);
@@ -72,7 +73,7 @@ class Ev implements EventInterface
                 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;
@@ -126,9 +127,9 @@ class Ev implements EventInterface
     /**
      * Timer callback.
      *
-     * @param \EvWatcher $event
+     * @param EvWatcher $event
      */
-    public function timerCallback($event)
+    public function timerCallback(EvWatcher $event)
     {
         $param    = $event->data;
         $timer_id = $param[4];
@@ -137,7 +138,7 @@ class Ev implements EventInterface
             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 +190,6 @@ class Ev implements EventInterface
      */
     public function getTimerCount()
     {
-        return count($this->_eventTimer);
+        return \count($this->_eventTimer);
     }
 }

+ 4 - 4
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 @@ class Event implements EventInterface
      */
     public function add($fd, $flag, $func, $args=array())
     {
-        if (class_exists('\\\\Event')) {
+        if (\class_exists('\\\\Event', false)) {
             $class_name = '\\\\Event';
         } else {
             $class_name = '\Event';
@@ -164,7 +164,7 @@ class Event implements EventInterface
         }
 
         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 @@ class Event implements EventInterface
      */
     public function getTimerCount()
     {
-        return count($this->_eventTimer);
+        return \count($this->_eventTimer);
     }
 }

+ 24 - 24
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,32 +65,32 @@ class Libevent implements EventInterface
         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)) {
+                $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)) {
+                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);
@@ -98,19 +98,19 @@ class Libevent implements EventInterface
 
             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();
+                $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 @@ class Libevent implements EventInterface
             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 @@ class Libevent implements EventInterface
             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 @@ class Libevent implements EventInterface
             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 @@ class Libevent implements EventInterface
     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 @@ class Libevent implements EventInterface
     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 @@ class Libevent implements EventInterface
      */
     public function loop()
     {
-        event_base_loop($this->_eventBase);
+        \event_base_loop($this->_eventBase);
     }
 
     /**
@@ -210,7 +210,7 @@ class Libevent implements EventInterface
     public function destroy()
     {
         foreach ($this->_eventSignal as $event) {
-            event_del($event);
+            \event_del($event);
         }
     }
 
@@ -221,7 +221,7 @@ class Libevent implements EventInterface
      */
     public function getTimerCount()
     {
-        return count($this->_eventTimer);
+        return \count($this->_eventTimer);
     }
 }
 

+ 8 - 6
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 @@ class Base implements \React\EventLoop\LoopInterface
      * @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) {
@@ -74,7 +76,7 @@ class Base implements \React\EventLoop\LoopInterface
                 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 +84,7 @@ class Base implements \React\EventLoop\LoopInterface
                 $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 +155,7 @@ class Base implements \React\EventLoop\LoopInterface
      */
     public function getTimerCount()
     {
-        return count($this->_timerIdMap);
+        return \count($this->_timerIdMap);
     }
 
     /**

+ 32 - 27
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,
-            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);
+            \stream_set_blocking($this->channel[0], 0);
             $this->_readFds[0] = $this->channel[0];
         }
         // Init SplPriorityQueue.
@@ -114,14 +114,20 @@ class Select implements EventInterface
     {
         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;
@@ -130,20 +136,20 @@ class Select implements EventInterface
                 break;
             case self::EV_SIGNAL:
                 // Windows not support signal.
-                if(DIRECTORY_SEPARATOR !== '/') {
+                if(\DIRECTORY_SEPARATOR !== '/') {
                     return false;
                 }
                 $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;   
                 }  
@@ -160,7 +166,7 @@ class Select implements EventInterface
      */
     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));
     }
 
     /**
@@ -190,11 +196,11 @@ class Select implements EventInterface
                 }
                 return true;
             case self::EV_SIGNAL:
-                if(DIRECTORY_SEPARATOR !== '/') {
+                if(\DIRECTORY_SEPARATOR !== '/') {
                     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;
@@ -215,7 +221,7 @@ class Select implements EventInterface
             $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();
@@ -230,7 +236,7 @@ class Select implements EventInterface
                     $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);
                 }
@@ -256,11 +262,10 @@ class Select implements EventInterface
      */
     public function loop()
     {
-        $e = null;
         while (1) {
-            if(DIRECTORY_SEPARATOR === '/') {
+            if(\DIRECTORY_SEPARATOR === '/') {
                 // Calls signal handlers for pending signals
-                pcntl_signal_dispatch();
+                \pcntl_signal_dispatch();
             }
 
             $read  = $this->_readFds;
@@ -268,9 +273,9 @@ class Select implements EventInterface
             $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();
+            \set_error_handler(function(){});
+            $ret = \stream_select($read, $write, $except, 0, $this->_selectTimeout);
+            \restore_error_handler();
 
 
             if (!$this->_scheduler->isEmpty()) {
@@ -285,7 +290,7 @@ class Select implements EventInterface
                 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]));
                     }
                 }
@@ -295,7 +300,7 @@ class Select implements EventInterface
                 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]));
                     }
                 }
@@ -305,7 +310,7 @@ class Select implements EventInterface
                 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]));
                     }
                 }
@@ -330,6 +335,6 @@ class Select implements EventInterface
      */
     public function getTimerCount()
     {
-        return count($this->_eventTimer);
+        return \count($this->_eventTimer);
     }
 }

+ 20 - 15
Events/Swoole.php

@@ -23,6 +23,8 @@ class Swoole implements EventInterface
 
     protected $_timerOnceMap = array();
 
+    protected $mapId = 0;
+
     protected $_fd = array();
 
     // milisecond
@@ -43,33 +45,36 @@ class Swoole implements EventInterface
         }
         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;
                 }
                 return $res;
             case self::EV_TIMER:
             case self::EV_TIMER_ONCE:
-                $method = self::EV_TIMER == $flag ? 'tick' : 'after';
-                $mapId = count($this->_timerOnceMap);
+                $method = self::EV_TIMER === $flag ? 'tick' : 'after';
+                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);
+                        \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)) {
+                            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) {
+                if ($flag === self::EV_TIMER_ONCE) {
                     $this->_timerOnceMap[$mapId] = $timer_id;
                     $this->_timer[$timer_id] = $mapId;
                 } else {
@@ -80,7 +85,7 @@ class Swoole implements EventInterface
             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 {
@@ -93,14 +98,14 @@ class Swoole implements EventInterface
                 } else {
                     $fd_val = $this->_fd[$fd_key];
                     $res = true;
-                    if ($flag == self::EV_READ) {
-                        if (($fd_val & SWOOLE_EVENT_READ) != SWOOLE_EVENT_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);
                             $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;
@@ -121,11 +126,11 @@ class Swoole implements EventInterface
     {
         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);
@@ -142,7 +147,7 @@ class Swoole implements EventInterface
                 $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;
@@ -211,6 +216,6 @@ class Swoole implements EventInterface
      */
     public function getTimerCount()
     {
-        return count($this->_timer);
+        return \count($this->_timer);
     }
 }

+ 7 - 11
Lib/Constants.php

@@ -8,14 +8,11 @@
  *
  * @author    walkor<walkor@workerman.net>
  * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ *
+ * @link      http://www.workerman.net/
  */
 
-// Date.timezone
-if (!ini_get('date.timezone')) {
-    date_default_timezone_set('Asia/Shanghai');
-}
 // Display errors.
 ini_set('display_errors', 'on');
 // Reporting all.
@@ -27,17 +24,16 @@ if (function_exists('opcache_reset')) {
 }
 
 // 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'))
-{
+if ( ! class_exists('Error')) {
     class Error extends Exception
     {
     }

+ 21 - 17
Lib/Timer.php

@@ -14,7 +14,8 @@
 namespace Workerman\Lib;
 
 use Workerman\Events\EventInterface;
-use Exception;
+use Workerman\Worker;
+use \Exception;
 
 /**
  * Timer.
@@ -39,24 +40,24 @@ 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)
     {
         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);
         }
     }
 
@@ -68,7 +69,7 @@ class Timer
     public static function signalHandle()
     {
         if (!self::$_event) {
-            pcntl_alarm(1);
+            \pcntl_alarm(1);
             self::tick();
         }
     }
@@ -80,7 +81,7 @@ class Timer
      * @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)
     {
@@ -89,22 +90,25 @@ class Timer
             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)) {
+        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();
-        $run_time = $time_now + $time_interval;
+        $run_time = \time() + $time_interval;
         if (!isset(self::$_tasks[$run_time])) {
             self::$_tasks[$run_time] = array();
         }
@@ -121,11 +125,11 @@ class Timer
     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) {
@@ -134,7 +138,7 @@ class Timer
                     $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);
                     }
@@ -170,7 +174,7 @@ class Timer
     public static function delAll()
     {
         self::$_tasks = array();
-        pcntl_alarm(0);
+        \pcntl_alarm(0);
         if (self::$_event) {
             self::$_event->clearAllTimer();
         }

+ 5 - 5
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 @@ class Frame
      */
     public static function decode($buffer)
     {
-        return substr($buffer, 4);
+        return \substr($buffer, 4);
     }
 
     /**
@@ -55,7 +55,7 @@ class Frame
      */
     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;
     }
 }

+ 197 - 157
Protocols/Http.php

@@ -14,6 +14,7 @@
 namespace Workerman\Protocols;
 
 use Workerman\Connection\TcpConnection;
+use Workerman\Protocols\Websocket;
 use Workerman\Worker;
 
 /**
@@ -36,24 +37,23 @@ 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);
-            return 0;
         }
+
+        $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n", true);
+        return 0;
     }
 
     /**
@@ -66,14 +66,14 @@ class Http
     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;
     }
 
     /**
@@ -86,11 +86,10 @@ class Http
     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   = array('Connection' => 'Connection: keep-alive');
-        HttpCache::$instance = new HttpCache();
+        HttpCache::reset();
         // $_SERVER
         $_SERVER = array(
             'QUERY_STRING'         => '',
@@ -109,14 +108,15 @@ class Http
             'CONTENT_TYPE'         => '',
             'REMOTE_ADDR'          => '',
             'REMOTE_PORT'          => '0',
-            'REQUEST_TIME'         => time()
+            'REQUEST_TIME'         => \time(),
+            'REQUEST_TIME_FLOAT'   => \microtime(true) //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($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 @@ class Http
             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 @@ class Http
                     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;
                         }
@@ -159,55 +159,61 @@ class Http
                 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;
             }
         }
-
+		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'])) {
-                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;
             }
         }
 
         // 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);
+                \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
@@ -226,32 +232,23 @@ class Http
      */
     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']);
-        }
+        // http-code status line.
+        $header = HttpCache::$status . "\r\n";
 
-        // Content-Type
-        if (!isset(HttpCache::$header['Content-Type'])) {
-            $header .= "Content-Type: text/html;charset=utf-8\r\n";
+        // Cookie headers
+        if(HttpCache::$cookie) {
+            $header .= \implode("\r\n", HttpCache::$cookie) . "\r\n";
         }
-
+        
         // 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";
-            }
-        }
+        $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);
+        }
         // 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();
@@ -261,37 +258,40 @@ class Http
     }
 
     /**
-     * 设置http头
-     *
+     * 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 = 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);
+        if (NO_CLI) {
+            \header($content, $replace, $http_response_code);
+            return;
         }
-        if (strpos($content, 'HTTP') === 0) {
-            $key = 'Http-Code';
-        } else {
-            $key = strstr($content, ":", true);
-            if (empty($key)) {
-                return false;
-            }
+
+        if (\strpos($content, 'HTTP') === 0) {
+            HttpCache::$status = $content;
+            return true;
         }
 
-        if ('location' === strtolower($key) && !$http_response_code) {
-            return self::header($content, true, 302);
+        $key = \strstr($content, ":", true);
+        if (empty($key)) {
+            return false;
         }
 
-        if (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 ('location' === \strtolower($key)) {
+            if (!$http_response_code) {
+            $http_response_code = 302;
             }
+            self::responseCode($http_response_code);
         }
 
         if ($key === 'Set-Cookie') {
-            HttpCache::$header[$key][] = $content;
+            HttpCache::$cookie[] = $content;
         } else {
             HttpCache::$header[$key] = $content;
         }
@@ -300,21 +300,39 @@ class Http
     }
 
     /**
-     * Remove header.
+     * Remove previously set headers
      *
      * @param string $name
      * @return void
      */
     public static function headerRemove($name)
     {
-        if (PHP_SAPI != 'cli') {
-            header_remove($name);
+        if (NO_CLI) {
+            \header_remove($name);
             return;
         }
         unset(HttpCache::$header[$name]);
     }
 
     /**
+     * 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
@@ -335,16 +353,18 @@ class Http
         $secure = false,
         $HTTPOnly = false
     ) {
-        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);
+        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;
     }
 
     /**
@@ -354,12 +374,12 @@ class Http
      */
     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)));
     }
 
     /**
-     * sessionId
+     * Get and/or set the current session id
      *
      * @param string  $id
      *
@@ -367,17 +387,17 @@ class Http
      */
     public static function sessionId($id = null)
     {
-        if (PHP_SAPI != 'cli') {
-            return $id ? session_id($id) : session_id();
+        if (NO_CLI) {
+            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 '';
     }
 
     /**
-     * sessionName
+     * Get and/or set the current session name
      *
      * @param string  $name
      *
@@ -385,8 +405,8 @@ class Http
      */
     public static function sessionName($name = null)
     {
-        if (PHP_SAPI != 'cli') {
-            return $name ? session_name($name) : session_name();
+        if (NO_CLI) {
+            return $name ? \session_name($name) : \session_name();
         }
         $session_name = HttpCache::$sessionName;
         if ($name && ! static::sessionStarted()) {
@@ -396,7 +416,7 @@ class Http
     }
 
     /**
-     * sessionSavePath
+     * Get and/or set the current session save path
      *
      * @param string  $path
      *
@@ -404,10 +424,10 @@ class Http
      */
     public static function sessionSavePath($path = null)
     {
-        if (PHP_SAPI != 'cli') {
-            return $path ? session_save_path($path) : session_save_path();
+        if (NO_CLI) {
+            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;
@@ -432,8 +452,8 @@ class Http
      */
     public static function sessionStart()
     {
-        if (PHP_SAPI != 'cli') {
-            return session_start();
+        if (NO_CLI) {
+            return \session_start();
         }
 
         self::tryGcSessions();
@@ -444,31 +464,31 @@ class Http
         }
         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(
                 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) {
-            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) {
-            $raw = file_get_contents(HttpCache::$instance->sessionFile);
+            $raw = \file_get_contents(HttpCache::$instance->sessionFile);
             if ($raw) {
-                $_SESSION = unserialize($raw);
+                $_SESSION = \unserialize($raw);
             }
         }
         return true;
@@ -481,13 +501,14 @@ class Http
      */
     public static function sessionWriteClose()
     {
-        if (PHP_SAPI != 'cli') {
-            return session_write_close();
+        if (NO_CLI) {
+            \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 (bool) \file_put_contents(HttpCache::$instance->sessionFile, $session_str);
             }
         }
         return empty($_SESSION);
@@ -501,7 +522,7 @@ class Http
      */
     public static function end($msg = '')
     {
-        if (PHP_SAPI != 'cli') {
+        if (NO_CLI) {
             exit($msg);
         }
         if ($msg) {
@@ -529,43 +550,43 @@ class Http
      */
     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),
                             );
-                            continue;
+                            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;
                 }
             }
@@ -581,14 +602,14 @@ class Http
     {
         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);
             }
         }
     }
@@ -645,11 +666,20 @@ 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'
+    );
+
     /**
      * @var 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          = '';
     public static $sessionGcProbability = 1;
@@ -658,32 +688,42 @@ 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) {
-            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;
         }
     }
 }
 
 HttpCache::init();
+
+define('NO_CLI', \PHP_SAPI !== 'cli');

+ 12 - 2
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;
 }

+ 4 - 4
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 @@ interface ProtocolInterface
     /**
      * 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);

+ 3 - 3
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 @@ class Text
     public static function decode($buffer)
     {
         // Remove "\n"
-        return trim($buffer);
+        return \rtrim($buffer, "\r\n");
     }
 }

+ 67 - 68
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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                     // 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);
@@ -102,7 +102,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                         }
                     } // Close connection.
                     else {
-                        $connection->close("\x88\x02\x27\x10", true);
+                        $connection->close("\x88\x02\x03\xe8", true);
                     }
                     return 0;
                 // Ping package.
@@ -125,7 +125,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 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,14 +133,14 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                     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;
-            if ($total_package_size > $connection::$maxPackageSize) {
+            $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();
                 return 0;
@@ -149,13 +149,13 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                         }
                         $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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                         }
                         $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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             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;
@@ -233,9 +233,9 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     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);
+        $len = \strlen($buffer);
         if (empty($connection->websocketType)) {
             $connection->websocketType = static::BINARY_TYPE_BLOB;
         }
@@ -243,12 +243,12 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
         $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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 $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 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             }
             $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,23 +304,22 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
      */
     public static function decode($buffer, ConnectionInterface $connection)
     {
-        $masks = $data = $decoded = '';
-        $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);
             }
         }
-        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;
@@ -337,15 +336,15 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
      * 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')) {
+        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;
             }
@@ -353,22 +352,22 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
 
             // 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 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Sec-WebSocket-Key not found.<br>This is a WebSocket service and can not be accessed via HTTP.<br>See <a href=\"http://wiki.workerman.net/Error1\">http://wiki.workerman.net/Error1</a> for detail.",
+                $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n<div style=\"text-align:center\"><h1>Websocket</h1><hr>powered by <a href=\"https://www.workerman.net\">workerman ".Worker::VERSION."</a></div>",
                     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 = '';
@@ -390,7 +389,7 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             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);
@@ -398,15 +397,15 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                     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";
@@ -429,19 +428,19 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                 $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, '<polic')) {
+        elseif (0 === \strpos($buffer, '<polic')) {
             $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . "\0";
             $connection->send($policy_xml, true);
-            $connection->consumeRecvBuffer(strlen($buffer));
+            $connection->consumeRecvBuffer(\strlen($buffer));
             return 0;
         }
         // Bad websocket handshake request.
-        $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Invalid handshake data for websocket. <br> See <a href=\"http://wiki.workerman.net/Error1\">http://wiki.workerman.net/Error1</a> for detail.",
+        $connection->send("HTTP/1.1 200 Websocket\r\nServer: workerman/".Worker::VERSION."\r\n\r\n<div style=\"text-align:center\"><h1>Websocket</h1><hr>powered by <a href=\"https://www.workerman.net\">workerman ".Worker::VERSION."</a></div>",
             true);
         $connection->close();
         return 0;
@@ -456,14 +455,14 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
     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]);
@@ -472,14 +471,14 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
             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];
@@ -487,16 +486,16 @@ class Websocket implements \Workerman\Protocols\ProtocolInterface
                     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'] = '';
         }

+ 69 - 67
Protocols/Ws.php

@@ -16,6 +16,7 @@ namespace Workerman\Protocols;
 use Workerman\Worker;
 use Workerman\Lib\Timer;
 use Workerman\Connection\TcpConnection;
+use Workerman\Connection\ConnectionInterface;
 
 /**
  * Websocket protocol for client.
@@ -43,17 +44,17 @@ 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");
+            Worker::safeEcho("recv data before handshake. Buffer:" . \bin2hex($buffer) . "\n");
             return false;
         }
         // Recv handshake response
         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 +67,8 @@ class Ws
             }
         } 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 +95,7 @@ class Ws
                     // 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,23 +122,23 @@ class Ws
             }
             // 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;
-            if ($total_package_size > $connection::$maxPackageSize) {
+            $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();
                 return 0;
@@ -146,13 +147,13 @@ class Ws
             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 +166,21 @@ class Ws
                         }
                         $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 +191,7 @@ class Ws
                         }
                         $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 +209,12 @@ class Ws
             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;
@@ -227,42 +228,41 @@ class Ws
      * @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;
         }
         $payload = (string)$payload;
         if (empty($connection->handshakeStep)) {
-            self::sendHandshake($connection);
+            static::sendHandshake($connection);
         }
         $mask = 1;
         $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:
-        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) {
+            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);
@@ -275,10 +275,10 @@ class Ws
             }
             $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);
@@ -300,16 +300,16 @@ class Ws
      * @param ConnectionInterface $connection
      * @return string
      */
-    public static function decode($bytes, $connection)
+    public static function decode($bytes, ConnectionInterface $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;
@@ -330,7 +330,7 @@ class Ws
      */
     public static function onConnect($connection)
     {
-        self::sendHandshake($connection);
+        static::sendHandshake($connection);
     }
 
     /**
@@ -353,10 +353,10 @@ class Ws
     /**
      * 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;
@@ -365,26 +365,28 @@ class Ws
         $port = $connection->getRemotePort();
         $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";
+        $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)){
+                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->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 . $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;
@@ -396,22 +398,22 @@ class Ws
      * 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");
+        $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;
             }
@@ -419,8 +421,8 @@ class Ws
             // 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;
@@ -428,7 +430,7 @@ class Ws
             // 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);
@@ -440,7 +442,7 @@ class Ws
             // 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;
                     }
@@ -452,8 +454,8 @@ class Ws
                 $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;
@@ -464,7 +466,7 @@ class Ws
     }
 
     public static function WSGetServerProtocol($connection) {
-	return (property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null);
+	return (\property_exists($connection, 'WSServerProtocol') ? $connection->WSServerProtocol : null);
     }
 
 }

+ 3 - 2
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
 

+ 66 - 49
WebServer.php

@@ -15,6 +15,7 @@ namespace Workerman;
 
 use Workerman\Protocols\Http;
 use Workerman\Protocols\HttpCache;
+use Workerman\Connection\TcpConnection;
 
 /**
  *  WebServer.
@@ -39,7 +40,7 @@ class WebServer extends Worker
     /**
      * Used to save user OnWorkerStart callback settings.
      *
-     * @var callback
+     * @var callable
      */
     protected $_onWorkerStart = null;
 
@@ -52,9 +53,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;
     }
 
@@ -64,9 +65,9 @@ class WebServer extends Worker
      * @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);
+        list(, $address) = \explode(':', $socket_name, 2);
         parent::__construct('http:' . $address, $context_option);
         $this->name = 'WebServer';
     }
@@ -102,7 +103,7 @@ class WebServer extends Worker
         // 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 +122,20 @@ class WebServer extends Worker
     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;
                 }
@@ -145,61 +146,69 @@ class WebServer extends Worker
     /**
      * 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']);
+        $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('<h1>400 Bad Request</h1>');
+            if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") {
+                $connection->send('<h1>400 Bad Request</h1>');
+            } else {
+                $connection->close('<h1>400 Bad Request</h1>');
+            }
             return;
         }
 
         $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';
         }
 
-        $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'])){
 			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');
-                $connection->close('<h1>400 Bad Request</h1>');
+                if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") {
+                    $connection->send('<h1>400 Bad Request</h1>');
+                } else {
+                    $connection->close('<h1>400 Bad Request</h1>');
+                }
                 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();
+                $workerman_cwd = \getcwd();
+                \chdir($workerman_root_dir);
+                \ini_set('display_errors', 'off');
+                \ob_start();
                 // Try to include php file.
                 try {
                     // $_SERVER.
@@ -208,18 +217,18 @@ class WebServer extends Worker
                     include $workerman_file;
                 } catch (\Exception $e) {
                     // Jump_exit?
-                    if ($e->getMessage() != '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") {
+                $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;
             }
 
@@ -228,12 +237,16 @@ class WebServer extends Worker
         } 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']);
+			if(isset($workerman_siteConfig['custom404']) && \file_exists($workerman_siteConfig['custom404'])){
+				$html404 = \file_get_contents($workerman_siteConfig['custom404']);
 			}else{
 				$html404 = '<html><head><title>404 File not found</title></head><body><center><h3>404 Not Found</h3></center></body></html>';
 			}
-            $connection->close($html404);
+            if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") {
+                $connection->send($html404);
+            } else {
+                $connection->close($html404);
+            }
             return;
         }
     }
@@ -241,15 +254,19 @@ class WebServer extends Worker
     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() : '';
+        $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..
-                $connection->close('');
+                if (\strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") {
+                    $connection->send('');
+                } else {
+                    $connection->close('');
+                }
                 return;
             }
         }
@@ -258,35 +275,35 @@ class WebServer extends Worker
         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";
         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);
+            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)
                 {

Різницю між файлами не показано, бо вона завелика
+ 330 - 171
Worker.php


+ 1 - 1
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": {

Деякі файли не було показано, через те що забагато файлів було змінено