├── public └── test.html ├── _lib ├── Workerman_linux │ ├── .gitignore │ ├── Lib │ │ ├── Constants.php │ │ └── Timer.php │ ├── composer.json │ ├── MIT-LICENSE.txt │ ├── Protocols │ │ ├── Frame.php │ │ ├── Game.php │ │ ├── ProtocolInterface.php │ │ ├── Text.php │ │ └── Http │ │ │ └── mime.types │ ├── Events │ │ ├── EventInterface.php │ │ ├── React │ │ │ ├── ExtEventLoop.php │ │ │ ├── LibEventLoop.php │ │ │ └── StreamSelectLoop.php │ │ ├── Ev.php │ │ ├── Event.php │ │ ├── Libevent.php │ │ └── Select.php │ ├── Connection │ │ ├── ConnectionInterface.php │ │ └── UdpConnection.php │ └── Autoloader.php ├── Workerman_win │ ├── .gitignore │ ├── Lib │ │ ├── Constants.php │ │ └── Timer.php │ ├── Protocols │ │ ├── Frame.php │ │ ├── Game.php │ │ ├── ProtocolInterface.php │ │ ├── Text.php │ │ └── Http │ │ │ └── mime.types │ ├── Autoloader.php │ ├── Events │ │ ├── EventInterface.php │ │ ├── React │ │ │ ├── ExtEventLoop.php │ │ │ ├── LibEventLoop.php │ │ │ └── StreamSelectLoop.php │ │ ├── Ev.php │ │ ├── Event.php │ │ ├── Libevent.php │ │ ├── React.php │ │ └── Select.php │ └── Connection │ │ ├── ConnectionInterface.php │ │ ├── UdpConnection.php │ │ └── AsyncUdpConnection.php ├── ape │ ├── base │ │ ├── BaseController.php │ │ ├── MYSQL │ │ └── DBBase.php │ ├── session │ │ └── Session.php │ ├── constant.php │ ├── register.php │ ├── http │ │ ├── mime.types │ │ └── Sendfile.php │ ├── Router.php │ ├── helper.php │ ├── view │ │ └── View.php │ ├── StatisticClient.php │ └── ApeWeb.php ├── Autoloader.php └── GlobalData │ ├── Server.php │ └── Client.php ├── z_api ├── views │ └── test2.html ├── filter.php ├── filter │ └── Filter.php └── controller │ └── TestController.php ├── config ├── database.php ├── filter.php └── config.php ├── main ├── model └── Admin.php ├── start_app.php ├── start_filemonitor.php └── README.md /public/test.html: -------------------------------------------------------------------------------- 1 | hello ape 2 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | .buildpath 3 | .project 4 | .settings 5 | .idea -------------------------------------------------------------------------------- /_lib/Workerman_win/.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .buildpath 3 | .settings/org.eclipse.php.core.prefs -------------------------------------------------------------------------------- /z_api/views/test2.html: -------------------------------------------------------------------------------- 1 | test2
2 | 3 | {foreach $admins k2=>n2} 4 | {$n2['name']}
5 | {/foreach} 6 | -------------------------------------------------------------------------------- /z_api/filter.php: -------------------------------------------------------------------------------- 1 | AddFilter ( "/api", \z_api\filter\Filter::login( $app ) ); 4 | -------------------------------------------------------------------------------- /_lib/ape/base/BaseController.php: -------------------------------------------------------------------------------- 1 | array( 4 | 'host' => "127.0.0.1", 5 | 'port' => "3306", 6 | 'username' => "www", 7 | 'password' => "www", 8 | 'db_name' => "test", 9 | 'cache' => false 10 | ) 11 | ); 12 | -------------------------------------------------------------------------------- /config/filter.php: -------------------------------------------------------------------------------- 1 | AddFilter ( "/", function(){ 8 | var_dump("全局拦截器-我在根目录下的filter.php中"); 9 | return true; 10 | } ); 11 | 12 | // 自定义404 13 | $apeWeb->on404 = function () { 14 | $this->send ( "page not found!" ); 15 | }; 16 | -------------------------------------------------------------------------------- /z_api/controller/TestController.php: -------------------------------------------------------------------------------- 1 | select ( '*' )->from ( static::$table )->where ( 'phone= :phone' )->where ( 'password= :password' )->where ( 'deleted_at is null' )->bindValues ( array ( 19 | 'phone' => $phone, 20 | 'password' => $password 21 | ) )->query (); 22 | if (is_array ( $admins) && count ( $admins) > 0) { 23 | return $admins[0]; 24 | } else { 25 | return null; 26 | } 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | "8081", 4 | // session模式 file存文件 database存入数据库 5 | "session_type" => "database", 6 | "session_name" => "ape_session", 7 | // 进程名字 8 | "worker_name" => "worker_ape", 9 | // 开启多少个进程,windows下只能开启一个 10 | "worker_count" => 1, 11 | // 每个进程最多接待多少个访客 12 | "max_request" => 10000, 13 | // 默认controller 14 | "default_module" => "api", 15 | // 默认controller 16 | "default_controller" => "Test", 17 | // 默认方法 18 | "default_method" => "test1", 19 | // 系统日志文件位置,相对与根目录下的log目录 20 | "logFile" => "info.log", 21 | // 重定向标准输出,即将所有echo、var_dump等终端输出写到对应文件中 22 | // 注意 此参数只有在以守护进程方式运行时有效 23 | "stdoutFile" => "echo.log" 24 | ); 25 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Lib/Constants.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | // Date.timezone 16 | if (! ini_get ( 'date.timezone' )) { 17 | date_default_timezone_set ( 'Asia/Shanghai' ); 18 | } 19 | // Display errors. 20 | ini_set ( 'display_errors', 'on' ); 21 | // Reporting all. 22 | error_reporting ( E_ALL ); 23 | 24 | // For onError callback. 25 | define ( 'WORKERMAN_CONNECT_FAIL', 1 ); 26 | // For onError callback. 27 | define ( 'WORKERMAN_SEND_FAIL', 2 ); 28 | 29 | // Compatible with php7 30 | if (! class_exists ( 'Error' )) { 31 | class Error extends Exception { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Lib/Constants.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | // Date.timezone 16 | if (!ini_get('date.timezone')) { 17 | date_default_timezone_set('Asia/Shanghai'); 18 | } 19 | // Display errors. 20 | ini_set('display_errors', 'on'); 21 | // Reporting all. 22 | error_reporting(E_ALL); 23 | 24 | // Reset opcache. 25 | if (function_exists('opcache_reset')) { 26 | opcache_reset(); 27 | } 28 | 29 | // For onError callback. 30 | define('WORKERMAN_CONNECT_FAIL', 1); 31 | // For onError callback. 32 | define('WORKERMAN_SEND_FAIL', 2); 33 | 34 | // Compatible with php7 35 | if(!class_exists('Error')) 36 | { 37 | class Error extends Exception 38 | { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "workerman/workerman", 3 | "type" : "library", 4 | "keywords": ["event-loop", "asynchronous"], 5 | "homepage": "http://www.workerman.net", 6 | "license" : "MIT", 7 | "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", 8 | "authors" : [ 9 | { 10 | "name" : "walkor", 11 | "email" : "walkor@workerman.net", 12 | "homepage" : "http://www.workerman.net", 13 | "role": "Developer" 14 | } 15 | ], 16 | "support" : { 17 | "email" : "walkor@workerman.net", 18 | "issues": "https://github.com/walkor/workerman/issues", 19 | "forum" : "http://wenda.workerman.net/", 20 | "wiki" : "http://doc3.workerman.net/index.html", 21 | "source": "https://github.com/walkor/workerman" 22 | }, 23 | "require": { 24 | "php": ">=5.3" 25 | }, 26 | "suggest": { 27 | "ext-event": "For better performance." 28 | }, 29 | "autoload": { 30 | "psr-4": {"Workerman\\": "./"} 31 | }, 32 | "minimum-stability":"dev" 33 | } 34 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009-2015 walkor and contributors (see https://github.com/walkor/workerman/contributors) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /_lib/Autoloader.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Frame Protocol. 20 | */ 21 | class Frame 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | if (strlen($buffer) < 4) { 33 | return 0; 34 | } 35 | $unpack_data = unpack('Ntotal_length', $buffer); 36 | return $unpack_data['total_length']; 37 | } 38 | 39 | /** 40 | * Decode. 41 | * 42 | * @param string $buffer 43 | * @return string 44 | */ 45 | public static function decode($buffer) 46 | { 47 | return substr($buffer, 4); 48 | } 49 | 50 | /** 51 | * Encode. 52 | * 53 | * @param string $buffer 54 | * @return string 55 | */ 56 | public static function encode($buffer) 57 | { 58 | $total_length = 4 + strlen($buffer); 59 | return pack('N', $total_length) . $buffer; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Protocols/Frame.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Frame Protocol. 20 | */ 21 | class Frame 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | if (strlen($buffer) < 4) { 33 | return 0; 34 | } 35 | $unpack_data = unpack('Ntotal_length', $buffer); 36 | return $unpack_data['total_length']; 37 | } 38 | 39 | /** 40 | * Decode. 41 | * 42 | * @param string $buffer 43 | * @return string 44 | */ 45 | public static function decode($buffer) 46 | { 47 | return substr($buffer, 4); 48 | } 49 | 50 | /** 51 | * Encode. 52 | * 53 | * @param string $buffer 54 | * @return string 55 | */ 56 | public static function encode($buffer) 57 | { 58 | $total_length = 4 + strlen($buffer); 59 | return pack('N', $total_length) . $buffer; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Protocols/Game.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright walkor 12 | * @link http://www.workerman.net/ 13 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 14 | */ 15 | namespace Workerman\Protocols; 16 | 17 | use Workerman\Connection\TcpConnection; 18 | 19 | /** 20 | * Frame Protocol. 21 | */ 22 | class Game { 23 | /** 24 | * 检查包的完整性 25 | * 如果能够得到包长,则返回包的在buffer中的长度,否则返回0继续等待数据 26 | * 如果协议有问题,则可以返回false,当前客户端连接会因此断开 27 | * 28 | * @param string $buffer 29 | * @return int 30 | */ 31 | public static function input($buffer, TcpConnection $connection) { 32 | if (strlen ( $buffer ) < 2) { 33 | return 0; 34 | } 35 | // unpack() 函数从二进制字符串对数据进行解包。 36 | $unpack_data = unpack ( 'Stotal_length', $buffer ); 37 | return ( int ) $unpack_data ['total_length'] + 2; 38 | } 39 | 40 | /** 41 | * 解包,当接收到的数据字节数等于input返回的值(大于0的值)自动调用 42 | * 并传递给onMessage回调函数的$data参数 43 | * 44 | * @param string $buffer 45 | * @return string 46 | */ 47 | public static function decode($buffer) { 48 | $buffer = substr ( $buffer, 2 ); 49 | return $buffer; 50 | } 51 | 52 | /** 53 | * 打包,当向客户端发送数据的时候会自动调用 54 | * 55 | * @param string $buffer 56 | * @return string 57 | */ 58 | public static function encode($buffer) { 59 | $bin_body = pack ( "a*", $buffer . "\0" ); 60 | $body_len = strlen ( $bin_body ); 61 | $bin_head = pack ( 'S*', $body_len ); 62 | 63 | $bin = $bin_head . $bin_body; 64 | 65 | return $bin; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Protocols/Game.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright walkor 12 | * @link http://www.workerman.net/ 13 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 14 | */ 15 | namespace Workerman\Protocols; 16 | 17 | use Workerman\Connection\TcpConnection; 18 | 19 | /** 20 | * Frame Protocol. 21 | */ 22 | class Game { 23 | /** 24 | * 检查包的完整性 25 | * 如果能够得到包长,则返回包的在buffer中的长度,否则返回0继续等待数据 26 | * 如果协议有问题,则可以返回false,当前客户端连接会因此断开 27 | * 28 | * @param string $buffer 29 | * @return int 30 | */ 31 | public static function input($buffer, TcpConnection $connection) { 32 | if (strlen ( $buffer ) < 2) { 33 | return 0; 34 | } 35 | // unpack() 函数从二进制字符串对数据进行解包。 36 | $unpack_data = unpack ( 'Stotal_length', $buffer ); 37 | return ( int ) $unpack_data ['total_length'] + 2; 38 | } 39 | 40 | /** 41 | * 解包,当接收到的数据字节数等于input返回的值(大于0的值)自动调用 42 | * 并传递给onMessage回调函数的$data参数 43 | * 44 | * @param string $buffer 45 | * @return string 46 | */ 47 | public static function decode($buffer) { 48 | $buffer = substr ( $buffer, 2 ); 49 | return $buffer; 50 | } 51 | 52 | /** 53 | * 打包,当向客户端发送数据的时候会自动调用 54 | * 55 | * @param string $buffer 56 | * @return string 57 | */ 58 | public static function encode($buffer) { 59 | $bin_body = pack ( "a*", $buffer . "\0" ); 60 | $body_len = strlen ( $bin_body ); 61 | $bin_head = pack ( 'S*', $body_len ); 62 | 63 | $bin = $bin_head . $bin_body; 64 | 65 | return $bin; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /start_app.php: -------------------------------------------------------------------------------- 1 | name = APE["config"] ["worker_name"]; 23 | $apeWeb->max_request = APE["config"] ["max_request"]; 24 | $apeWeb->count = APE["config"] ["worker_count"]; 25 | 26 | $apeWeb->onStart = function ($apeWeb) { 27 | // 创建数据库连接 28 | $config = APE["config"]; 29 | $database = APE["database"]; 30 | 31 | $mysqls = array(); 32 | foreach ($database as $k => $n) { 33 | $mysqls[$k] = new MySQL($n ['host'], $n ['port'], $n ['username'], $n ['password'], $n ['db_name']); 34 | } 35 | ApeWeb::$mysqls = $mysqls; 36 | ApeWeb::$view = new View(); 37 | 38 | // 删除所有垃圾视图,重新生成、 39 | if ($apeWeb->id==0) { 40 | foreach (glob(RUN_DIR . 'z_*/storage/views/*.php') as $start_file) { 41 | unlink($start_file); 42 | } 43 | } 44 | 45 | require_once RUN_DIR."config/filter.php"; 46 | foreach (glob(RUN_DIR . 'z_*/filter.php') as $file) { 47 | require_once($file); 48 | } 49 | 50 | //链接UDP日志服务器 start 51 | ApeWeb::$udp_log_client = new AsyncTcpConnection("udp://127.0.0.1:".APE['config']['port']); 52 | ApeWeb::$udp_log_client->connect(); 53 | //链接UDP日志服务器 end 54 | }; 55 | 56 | if(APE["WORKERMAN"] == "Workerman_win"){ 57 | Worker::runAll(); 58 | } -------------------------------------------------------------------------------- /_lib/Workerman_linux/Protocols/ProtocolInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\ConnectionInterface; 17 | 18 | /** 19 | * Protocol interface 20 | */ 21 | interface ProtocolInterface 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * Please return the length of package. 26 | * If length is unknow please return 0 that mean wating more data. 27 | * If the package has something wrong please return false the connection will be closed. 28 | * 29 | * @param ConnectionInterface $connection 30 | * @param string $recv_buffer 31 | * @return int|false 32 | */ 33 | public static function input($recv_buffer, ConnectionInterface $connection); 34 | 35 | /** 36 | * Decode package and emit onMessage($message) callback, $message is the result that decode returned. 37 | * 38 | * @param ConnectionInterface $connection 39 | * @param string $recv_buffer 40 | * @return mixed 41 | */ 42 | public static function decode($recv_buffer, ConnectionInterface $connection); 43 | 44 | /** 45 | * Encode package brefore sending to client. 46 | * 47 | * @param ConnectionInterface $connection 48 | * @param mixed $data 49 | * @return string 50 | */ 51 | public static function encode($data, ConnectionInterface $connection); 52 | } 53 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Protocols/ProtocolInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\ConnectionInterface; 17 | 18 | /** 19 | * Protocol interface 20 | */ 21 | interface ProtocolInterface 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * Please return the length of package. 26 | * If length is unknow please return 0 that mean wating more data. 27 | * If the package has something wrong please return false the connection will be closed. 28 | * 29 | * @param ConnectionInterface $connection 30 | * @param string $recv_buffer 31 | * @return int|false 32 | */ 33 | public static function input($recv_buffer, ConnectionInterface $connection); 34 | 35 | /** 36 | * Decode package and emit onMessage($message) callback, $message is the result that decode returned. 37 | * 38 | * @param ConnectionInterface $connection 39 | * @param string $recv_buffer 40 | * @return mixed 41 | */ 42 | public static function decode($recv_buffer, ConnectionInterface $connection); 43 | 44 | /** 45 | * Encode package brefore sending to client. 46 | * 47 | * @param ConnectionInterface $connection 48 | * @param mixed $data 49 | * @return string 50 | */ 51 | public static function encode($data, ConnectionInterface $connection); 52 | } 53 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Autoloader.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright walkor 12 | * @link http://www.workerman.net/ 13 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 14 | */ 15 | namespace Workerman; 16 | 17 | // 包含常量定义文件 18 | require_once __DIR__ . '/Lib/Constants.php'; 19 | 20 | /** 21 | * 自动加载类 22 | * 23 | * @author walkor 24 | */ 25 | class Autoloader { 26 | 27 | // 项目目录,默认是根目录 28 | protected static $_appInitPath= ''; 29 | // lib文件目录,如果用namespace在外面没找到,尝试在lib下寻找 30 | protected static $_libPath = '_lib'; 31 | 32 | /** 33 | * 设置应用初始化目录 34 | * 35 | * @param string $root_path 36 | * @return void 37 | */ 38 | public static function setRootPath($root_path) { 39 | self::$_appInitPath = $root_path; 40 | } 41 | 42 | /** 43 | * 根据命名空间加载文件 44 | * 45 | * @param string $name 46 | * @return boolean 47 | */ 48 | public static function loadByNamespace($name) { 49 | // 相对路径 50 | $class_path = str_replace ( '\\', DIRECTORY_SEPARATOR, $name ); 51 | 52 | // 先尝试通过namespace 匹配地址寻找 53 | $class_file = $class_path . '.php'; 54 | 55 | //如果没找到的话,再在_lib文件夹下寻找 56 | if (!is_file ( $class_file )) { 57 | $class_file = self::$_libPath. DIRECTORY_SEPARATOR . $class_path . '.php'; 58 | //echo "$class_file"."\n"; 59 | } 60 | // 找到文件 61 | if (is_file ( $class_file )) { 62 | // 加载 63 | require_once ($class_file); 64 | if (class_exists ( $name, false )) { 65 | return true; 66 | } 67 | } 68 | return false; 69 | } 70 | } 71 | 72 | // 设置类自动加载回调函数 73 | spl_autoload_register ( '\Workerman\Autoloader::loadByNamespace' ); 74 | -------------------------------------------------------------------------------- /start_filemonitor.php: -------------------------------------------------------------------------------- 1 | name = 'FileMonitor'; 24 | $worker->reloadable = false; 25 | $last_mtime = time (); 26 | 27 | $worker->onWorkerStart = function () { 28 | global $monitor_dir; 29 | // watch files only in daemon mode 30 | if (! Worker::$daemonize) { 31 | // chek mtime of files per second 32 | Timer::add ( 1, 'check_files_change', array ( 33 | $monitor_dir 34 | ) ); 35 | } 36 | }; 37 | 38 | // check files func 39 | function check_files_change($monitor_dir) { 40 | global $last_time_arr; 41 | // recursive traversal directory 42 | $dir_iterator = new RecursiveDirectoryIterator ( $monitor_dir ); 43 | $iterator = new RecursiveIteratorIterator ( $dir_iterator ); 44 | foreach ( $iterator as $file ) { 45 | // only check php files 46 | if (pathinfo ( $file, PATHINFO_EXTENSION ) != 'php') { 47 | continue; 48 | } 49 | if(!array_key_exists((string)$file,$last_time_arr)){ 50 | $last_time_arr[(string)$file] = $file->getMTime (); 51 | } 52 | if ($last_time_arr[(string)$file] < $file->getMTime ()) { 53 | echo $file . " update and reload\n"; 54 | // send SIGUSR1 signal to master process for reload 55 | posix_kill ( posix_getppid (), SIGUSR1 ); 56 | $last_time_arr[(string)$file] = $file->getMTime (); 57 | break; 58 | } 59 | } 60 | } 61 | 62 | if(APE["WORKERMAN"] == "Workerman_win"){ 63 | Worker::runAll(); 64 | } 65 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Protocols/Text.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Text Protocol. 20 | */ 21 | class Text 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | // Judge whether the package length exceeds the limit. 33 | if (strlen($buffer) >= TcpConnection::$maxPackageSize) { 34 | $connection->close(); 35 | return 0; 36 | } 37 | // Find the position of "\n". 38 | $pos = strpos($buffer, "\n"); 39 | // No "\n", packet length is unknown, continue to wait for the data so return 0. 40 | if ($pos === false) { 41 | return 0; 42 | } 43 | // Return the current package length. 44 | return $pos + 1; 45 | } 46 | 47 | /** 48 | * Encode. 49 | * 50 | * @param string $buffer 51 | * @return string 52 | */ 53 | public static function encode($buffer) 54 | { 55 | // Add "\n" 56 | return $buffer . "\n"; 57 | } 58 | 59 | /** 60 | * Decode. 61 | * 62 | * @param string $buffer 63 | * @return string 64 | */ 65 | public static function decode($buffer) 66 | { 67 | // Remove "\n" 68 | return trim($buffer); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Protocols/Text.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Text Protocol. 20 | */ 21 | class Text 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | // Judge whether the package length exceeds the limit. 33 | if (strlen($buffer) >= TcpConnection::$maxPackageSize) { 34 | $connection->close(); 35 | return 0; 36 | } 37 | // Find the position of "\n". 38 | $pos = strpos($buffer, "\n"); 39 | // No "\n", packet length is unknown, continue to wait for the data so return 0. 40 | if ($pos === false) { 41 | return 0; 42 | } 43 | // Return the current package length. 44 | return $pos + 1; 45 | } 46 | 47 | /** 48 | * Encode. 49 | * 50 | * @param string $buffer 51 | * @return string 52 | */ 53 | public static function encode($buffer) 54 | { 55 | // Add "\n" 56 | return $buffer . "\n"; 57 | } 58 | 59 | /** 60 | * Decode. 61 | * 62 | * @param string $buffer 63 | * @return string 64 | */ 65 | public static function decode($buffer) 66 | { 67 | // Remove "\n" 68 | return trim($buffer); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/EventInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | interface EventInterface 17 | { 18 | /** 19 | * Read event. 20 | * 21 | * @var int 22 | */ 23 | const EV_READ = 1; 24 | 25 | /** 26 | * Write event. 27 | * 28 | * @var int 29 | */ 30 | const EV_WRITE = 2; 31 | 32 | /** 33 | * Except event 34 | * 35 | * @var int 36 | */ 37 | const EV_EXCEPT = 3; 38 | 39 | /** 40 | * Signal event. 41 | * 42 | * @var int 43 | */ 44 | const EV_SIGNAL = 4; 45 | 46 | /** 47 | * Timer event. 48 | * 49 | * @var int 50 | */ 51 | const EV_TIMER = 8; 52 | 53 | /** 54 | * Timer once event. 55 | * 56 | * @var int 57 | */ 58 | const EV_TIMER_ONCE = 16; 59 | 60 | /** 61 | * Add event listener to event loop. 62 | * 63 | * @param mixed $fd 64 | * @param int $flag 65 | * @param callable $func 66 | * @param mixed $args 67 | * @return bool 68 | */ 69 | public function add($fd, $flag, $func, $args = null); 70 | 71 | /** 72 | * Remove event listener from event loop. 73 | * 74 | * @param mixed $fd 75 | * @param int $flag 76 | * @return bool 77 | */ 78 | public function del($fd, $flag); 79 | 80 | /** 81 | * Remove all timers. 82 | * 83 | * @return void 84 | */ 85 | public function clearAllTimer(); 86 | 87 | /** 88 | * Main loop. 89 | * 90 | * @return void 91 | */ 92 | public function loop(); 93 | } 94 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/EventInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | interface EventInterface 17 | { 18 | /** 19 | * Read event. 20 | * 21 | * @var int 22 | */ 23 | const EV_READ = 1; 24 | 25 | /** 26 | * Write event. 27 | * 28 | * @var int 29 | */ 30 | const EV_WRITE = 2; 31 | 32 | /** 33 | * Signal event. 34 | * 35 | * @var int 36 | */ 37 | const EV_SIGNAL = 4; 38 | 39 | /** 40 | * Timer event. 41 | * 42 | * @var int 43 | */ 44 | const EV_TIMER = 8; 45 | 46 | /** 47 | * Timer once event. 48 | * 49 | * @var int 50 | */ 51 | const EV_TIMER_ONCE = 16; 52 | 53 | /** 54 | * Add event listener to event loop. 55 | * 56 | * @param mixed $fd 57 | * @param int $flag 58 | * @param callable $func 59 | * @param mixed $args 60 | * @return bool 61 | */ 62 | public function add($fd, $flag, $func, $args = null); 63 | 64 | /** 65 | * Remove event listener from event loop. 66 | * 67 | * @param mixed $fd 68 | * @param int $flag 69 | * @return bool 70 | */ 71 | public function del($fd, $flag); 72 | 73 | /** 74 | * Remove all timers. 75 | * 76 | * @return void 77 | */ 78 | public function clearAllTimer(); 79 | 80 | /** 81 | * Main loop. 82 | * 83 | * @return void 84 | */ 85 | public function loop(); 86 | 87 | /** 88 | * Destroy loop. 89 | * 90 | * @return mixed 91 | */ 92 | public function destroy(); 93 | } 94 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Connection/ConnectionInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * ConnectionInterface. 18 | */ 19 | abstract class ConnectionInterface 20 | { 21 | /** 22 | * Statistics for status command. 23 | * 24 | * @var array 25 | */ 26 | public static $statistics = array( 27 | 'connection_count' => 0, 28 | 'total_request' => 0, 29 | 'throw_exception' => 0, 30 | 'send_fail' => 0, 31 | ); 32 | 33 | /** 34 | * Emitted when data is received. 35 | * 36 | * @var callback 37 | */ 38 | public $onMessage = null; 39 | 40 | /** 41 | * Emitted when the other end of the socket sends a FIN packet. 42 | * 43 | * @var callback 44 | */ 45 | public $onClose = null; 46 | 47 | /** 48 | * Emitted when an error occurs with connection. 49 | * 50 | * @var callback 51 | */ 52 | public $onError = null; 53 | 54 | /** 55 | * Sends data on the connection. 56 | * 57 | * @param string $send_buffer 58 | * @return void|boolean 59 | */ 60 | abstract public function send($send_buffer); 61 | 62 | /** 63 | * Get remote IP. 64 | * 65 | * @return string 66 | */ 67 | abstract public function getRemoteIp(); 68 | 69 | /** 70 | * Get remote port. 71 | * 72 | * @return int 73 | */ 74 | abstract public function getRemotePort(); 75 | 76 | /** 77 | * Close connection. 78 | * 79 | * @param $data 80 | * @return void 81 | */ 82 | abstract public function close($data = null); 83 | } 84 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Connection/ConnectionInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * ConnectionInterface. 18 | */ 19 | abstract class ConnectionInterface 20 | { 21 | /** 22 | * Statistics for status command. 23 | * 24 | * @var array 25 | */ 26 | public static $statistics = array( 27 | 'connection_count' => 0, 28 | 'total_request' => 0, 29 | 'throw_exception' => 0, 30 | 'send_fail' => 0, 31 | ); 32 | 33 | /** 34 | * Emitted when data is received. 35 | * 36 | * @var callback 37 | */ 38 | public $onMessage = null; 39 | 40 | /** 41 | * Emitted when the other end of the socket sends a FIN packet. 42 | * 43 | * @var callback 44 | */ 45 | public $onClose = null; 46 | 47 | /** 48 | * Emitted when an error occurs with connection. 49 | * 50 | * @var callback 51 | */ 52 | public $onError = null; 53 | 54 | /** 55 | * Sends data on the connection. 56 | * 57 | * @param string $send_buffer 58 | * @return void|boolean 59 | */ 60 | abstract public function send($send_buffer); 61 | 62 | /** 63 | * Get remote IP. 64 | * 65 | * @return string 66 | */ 67 | abstract public function getRemoteIp(); 68 | 69 | /** 70 | * Get remote port. 71 | * 72 | * @return int 73 | */ 74 | abstract public function getRemotePort(); 75 | 76 | /** 77 | * Close connection. 78 | * 79 | * @param $data 80 | * @return void 81 | */ 82 | abstract public function close($data = null); 83 | } 84 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Autoloader.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman; 15 | 16 | /** 17 | * Autoload. 18 | */ 19 | class Autoloader 20 | { 21 | /** 22 | * Autoload root path. 23 | * 24 | * @var string 25 | */ 26 | protected static $_autoloadRootPath = ''; 27 | 28 | /** 29 | * Set autoload root path. 30 | * 31 | * @param string $root_path 32 | * @return void 33 | */ 34 | public static function setRootPath($root_path) 35 | { 36 | self::$_autoloadRootPath = $root_path; 37 | } 38 | 39 | /** 40 | * Load files by namespace. 41 | * 42 | * @param string $name 43 | * @return boolean 44 | */ 45 | public static function loadByNamespace($name) 46 | { 47 | $class_path = str_replace('\\', DIRECTORY_SEPARATOR, $name); 48 | if (strpos($name, 'Workerman\\') === 0) { 49 | $class_file = __DIR__ . substr($class_path, strlen('Workerman')) . '.php'; 50 | } else { 51 | if (self::$_autoloadRootPath) { 52 | $class_file = self::$_autoloadRootPath . DIRECTORY_SEPARATOR . $class_path . '.php'; 53 | } 54 | if (empty($class_file) || !is_file($class_file)) { 55 | $class_file = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . "$class_path.php"; 56 | } 57 | } 58 | 59 | if (is_file($class_file)) { 60 | require_once($class_file); 61 | if (class_exists($name, false)) { 62 | return true; 63 | } 64 | } 65 | return false; 66 | } 67 | } 68 | 69 | spl_autoload_register('\Workerman\Autoloader::loadByNamespace'); -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/React/ExtEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | 16 | /** 17 | * Class ExtEventLoop 18 | * @package Workerman\Events\React 19 | */ 20 | class ExtEventLoop extends \React\EventLoop\ExtEventLoop 21 | { 22 | /** 23 | * Event base. 24 | * 25 | * @var EventBase 26 | */ 27 | protected $_eventBase = null; 28 | 29 | /** 30 | * All signal Event instances. 31 | * 32 | * @var array 33 | */ 34 | protected $_signalEvents = array(); 35 | 36 | /** 37 | * Construct 38 | */ 39 | public function __construct() 40 | { 41 | parent::__construct(); 42 | $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop'); 43 | $property = $class->getProperty('eventBase'); 44 | $property->setAccessible(true); 45 | $this->_eventBase = $property->getValue($this); 46 | } 47 | 48 | /** 49 | * Add signal handler. 50 | * 51 | * @param $signal 52 | * @param $callback 53 | * @return bool 54 | */ 55 | public function addSignal($signal, $callback) 56 | { 57 | $event = \Event::signal($this->_eventBase, $signal, $callback); 58 | if (!$event||!$event->add()) { 59 | return false; 60 | } 61 | $this->_signalEvents[$signal] = $event; 62 | } 63 | 64 | /** 65 | * Remove signal handler. 66 | * 67 | * @param $signal 68 | */ 69 | public function removeSignal($signal) 70 | { 71 | if (isset($this->_signalEvents[$signal])) { 72 | $this->_signalEvents[$signal]->del(); 73 | unset($this->_signalEvents[$signal]); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/React/LibEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | 16 | /** 17 | * Class LibEventLoop 18 | * @package Workerman\Events\React 19 | */ 20 | class LibEventLoop extends \React\EventLoop\LibEventLoop 21 | { 22 | /** 23 | * Event base. 24 | * 25 | * @var event_base resource 26 | */ 27 | protected $_eventBase = null; 28 | 29 | /** 30 | * All signal Event instances. 31 | * 32 | * @var array 33 | */ 34 | protected $_signalEvents = array(); 35 | 36 | /** 37 | * Construct. 38 | */ 39 | public function __construct() 40 | { 41 | parent::__construct(); 42 | $class = new \ReflectionClass('\React\EventLoop\LibEventLoop'); 43 | $property = $class->getProperty('eventBase'); 44 | $property->setAccessible(true); 45 | $this->_eventBase = $property->getValue($this); 46 | } 47 | 48 | /** 49 | * Add signal handler. 50 | * 51 | * @param $signal 52 | * @param $callback 53 | * @return bool 54 | */ 55 | public function addSignal($signal, $callback) 56 | { 57 | $event = event_new(); 58 | $this->_signalEvents[$signal] = $event; 59 | event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback); 60 | event_base_set($event, $this->_eventBase); 61 | event_add($event); 62 | } 63 | 64 | /** 65 | * Remove signal handler. 66 | * 67 | * @param $signal 68 | */ 69 | public function removeSignal($signal) 70 | { 71 | if (isset($this->_signalEvents[$signal])) { 72 | $event = $this->_signalEvents[$signal]; 73 | event_del($event); 74 | unset($this->_signalEvents[$signal]); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /_lib/ape/register.php: -------------------------------------------------------------------------------- 1 | count = 1; 10 | $worker->name = 'ape_register'; 11 | 12 | Worker::$logFile = __DIR__ . "/register_log.log"; 13 | Worker::$stdoutFile = __DIR__ . "/register_stdout.log"; 14 | 15 | // 保存所有客户端 16 | $clients = array(); 17 | $worker->onMessage = function ($connection, $buffer) { 18 | global $clients; 19 | // 客户端进行注册 20 | if (strpos($buffer, "register_") === 0) { 21 | $listen_address = str_replace("register_", "", $buffer); 22 | $listen_address = str_replace("0.0.0.0", "127.0.0.1", $listen_address); 23 | if (! array_key_exists($listen_address, $clients)) { 24 | if ($listen_address == "") { 25 | $connection->close(); 26 | return; 27 | } 28 | $clients [$listen_address] = true; 29 | var_dump($listen_address . " is reg~~~~~~~~ "); 30 | } 31 | $connection->close(); 32 | return; 33 | } 34 | if (count($clients) > 0) { 35 | global $_key; 36 | $_key = key($clients); 37 | if ($_key == false) { 38 | reset($clients); 39 | $_key = key($clients); 40 | } 41 | $remote_connection = new AsyncTcpConnection("tcp://" . $_key); 42 | next($clients); 43 | $remote_connection->onError = function ($remote_connection) use ($connection) { 44 | global $clients; 45 | global $_key; 46 | var_dump($_key . " is close!!!!!!!!! "); 47 | unset($clients [$_key]); 48 | $connection->send("HTTP/1.1 502 Connection Established\r\n\r\n"); 49 | $connection->close(); 50 | return; 51 | }; 52 | $remote_connection->send($buffer); 53 | // Pipe. 54 | $remote_connection->pipe($connection); 55 | $connection->pipe($remote_connection); 56 | $remote_connection->connect(); 57 | } else { 58 | $connection->send("HTTP/1.1 502 Connection Established\r\n\r\n"); 59 | $connection->close(); 60 | } 61 | }; 62 | 63 | // Run. 64 | Worker::runAll(); 65 | -------------------------------------------------------------------------------- /_lib/ape/base/MYSQL: -------------------------------------------------------------------------------- 1 | // 初始化db连接 2 | $db = new Workerman\MySQL\Connection('host', 'port', 'user', 'password', 'db_name'); 3 | 4 | // 获取所有数据 5 | $db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->query(); 6 | //等价于 7 | $db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->query(); 8 | //等价于 9 | $db->query("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 10 | 11 | 12 | // 获取一行数据 13 | $db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->row(); 14 | //等价于 15 | $db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->row(); 16 | //等价于 17 | $db->row("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 18 | 19 | 20 | // 获取一列数据 21 | $db->select('ID')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->column(); 22 | //等价于 23 | $db->select('ID')->from('Persons')->where("sex= 'F' ")->column(); 24 | //等价于 25 | $db->column("SELECT `ID` FROM `Persons` WHERE sex='M'"); 26 | 27 | // 获取单个值 28 | $db->select('ID,Sex')->from('Persons')->where('sex= :sex')->bindValues(array('sex'=>'M'))->single(); 29 | //等价于 30 | $db->select('ID,Sex')->from('Persons')->where("sex= 'F' ")->single(); 31 | //等价于 32 | $db->single("SELECT ID,Sex FROM `Persons` WHERE sex='M'"); 33 | 34 | // 复杂查询 35 | $db->select('*')->from('table1')->innerJoin('table2','table1.uid = table2.uid')->where('age > :age')->groupBy(array('aid'))->having('foo="foo"')->orderByASC/*orderByDESC*/(array('did')) 36 | ->limit(10)->offset(20)->bindValues(array('age' => 13)); 37 | // 等价于 38 | $db->query(SELECT * FROM `table1` INNER JOIN `table2` ON `table1`.`uid` = `table2`.`uid` 39 | WHERE age > 13 GROUP BY aid HAVING foo="foo" ORDER BY did LIMIT 10 OFFSET 20“); 40 | 41 | // 插入 42 | $insert_id = $db->insert('Persons')->cols(array( 43 | 'Firstname'=>'abc', 44 | 'Lastname'=>'efg', 45 | 'Sex'=>'M', 46 | 'Age'=>13))->query(); 47 | 等价于 48 | $insert_id = $db->query("INSERT INTO `Persons` ( `Firstname`,`Lastname`,`Sex`,`Age`) 49 | VALUES ( 'abc', 'efg', 'M', 13)"); 50 | 51 | // 更新 52 | $row_count = $db->update('Persons')->cols(array('sex'))->where('ID=1') 53 | ->bindValue('sex', 'F')->query(); 54 | // 等价于 55 | $row_count = $db->update('Persons')->cols(array('sex'=>'F'))->where('ID=1')->query(); 56 | // 等价于 57 | $row_count = $db->query("UPDATE `Persons` SET `sex` = 'F' WHERE ID=1"); 58 | 59 | // 删除 60 | $row_count = $db->delete('Persons')->where('ID=9')->query(); 61 | // 等价于 62 | $row_count = $db->query("DELETE FROM `Persons` WHERE ID=9"); 63 | 64 | // 事务 65 | $db->beginTrans(); 66 | .... 67 | $db->commitTrans(); // or $db->rollBackTrans(); -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/React/StreamSelectLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | 16 | /** 17 | * Class StreamSelectLoop 18 | * @package Workerman\Events\React 19 | */ 20 | class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop 21 | { 22 | /** 23 | * Add signal handler. 24 | * 25 | * @param $signal 26 | * @param $callback 27 | * @return bool 28 | */ 29 | public function addSignal($signal, $callback) 30 | { 31 | if(PHP_EOL !== "\r\n") { 32 | pcntl_signal($signal, $callback); 33 | } 34 | } 35 | 36 | /** 37 | * Remove signal handler. 38 | * 39 | * @param $signal 40 | */ 41 | public function removeSignal($signal) 42 | { 43 | if(PHP_EOL !== "\r\n") { 44 | pcntl_signal($signal, SIG_IGN); 45 | } 46 | } 47 | 48 | /** 49 | * Emulate a stream_select() implementation that does not break when passed 50 | * empty stream arrays. 51 | * 52 | * @param array &$read An array of read streams to select upon. 53 | * @param array &$write An array of write streams to select upon. 54 | * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. 55 | * 56 | * @return integer|false The total number of streams that are ready for read/write. 57 | * Can return false if stream_select() is interrupted by a signal. 58 | */ 59 | protected function streamSelect(array &$read, array &$write, $timeout) 60 | { 61 | if ($read || $write) { 62 | $except = null; 63 | // Calls signal handlers for pending signals 64 | pcntl_signal_dispatch(); 65 | // suppress warnings that occur, when stream_select is interrupted by a signal 66 | return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); 67 | } 68 | 69 | // Calls signal handlers for pending signals 70 | if(PHP_EOL !== "\r\n") { 71 | pcntl_signal_dispatch(); 72 | } 73 | $timeout && usleep($timeout); 74 | 75 | return 0; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /_lib/GlobalData/Server.php: -------------------------------------------------------------------------------- 1 | count = 1; 34 | $worker->name = 'globalDataServer'; 35 | $worker->onMessage = array ( 36 | $this, 37 | 'onMessage' 38 | ); 39 | $worker->reloadable = false; 40 | $this->_worker = $worker; 41 | } 42 | 43 | /** 44 | * onMessage. 45 | * 46 | * @param TcpConnection $connection 47 | * @param string $buffer 48 | */ 49 | public function onMessage($connection, $buffer) { 50 | if ($buffer === 'ping') { 51 | return; 52 | } 53 | $data = unserialize ( $buffer ); 54 | if (! $buffer || ! isset ( $data ['cmd'] ) || ! isset ( $data ['key'] )) { 55 | return $connection->close ( serialize ( 'bad request' ) ); 56 | } 57 | $cmd = $data ['cmd']; 58 | $key = $data ['key']; 59 | switch ($cmd) { 60 | case 'get' : 61 | if (! isset ( $this->_dataArray [$key] )) { 62 | return $connection->send ( 'N;' ); 63 | } 64 | return $connection->send ( serialize ( $this->_dataArray [$key] ) ); 65 | break; 66 | case 'set' : 67 | $this->_dataArray [$key] = $data ['value']; 68 | $connection->send ( 'b:1;' ); 69 | break; 70 | case 'add' : 71 | if (isset ( $this->_dataArray [$key] )) { 72 | return $connection->send ( 'b:0;' ); 73 | } 74 | $this->_dataArray [$key] = $data ['value']; 75 | return $connection->send ( 'b:1;' ); 76 | break; 77 | case 'increment' : 78 | if (! isset ( $this->_dataArray [$key] )) { 79 | return $connection->send ( 'b:0;' ); 80 | } 81 | if (! is_numeric ( $this->_dataArray [$key] )) { 82 | $this->_dataArray [$key] = 0; 83 | } 84 | $this->_dataArray [$key] = $this->_dataArray [$key] + $data ['step']; 85 | return $connection->send ( serialize ( $this->_dataArray [$key] ) ); 86 | break; 87 | case 'cas' : 88 | if (isset ( $this->_dataArray [$key] ) && md5 ( serialize ( $this->_dataArray [$key] ) ) === $data ['md5']) { 89 | $this->_dataArray [$key] = $data ['value']; 90 | return $connection->send ( 'b:1;' ); 91 | } 92 | $connection->send ( 'b:0;' ); 93 | break; 94 | case 'delete' : 95 | unset ( $this->_dataArray [$key] ); 96 | $connection->send ( 'b:1;' ); 97 | break; 98 | default : 99 | $connection->close ( serialize ( 'bad cmd ' . $cmd ) ); 100 | } 101 | } 102 | } 103 | 104 | 105 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Connection/UdpConnection.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * UdpConnection. 18 | */ 19 | class UdpConnection extends ConnectionInterface 20 | { 21 | /** 22 | * Application layer protocol. 23 | * The format is like this Workerman\\Protocols\\Http. 24 | * 25 | * @var \Workerman\Protocols\ProtocolInterface 26 | */ 27 | public $protocol = null; 28 | 29 | /** 30 | * Udp socket. 31 | * 32 | * @var resource 33 | */ 34 | protected $_socket = null; 35 | 36 | /** 37 | * Remote address. 38 | * 39 | * @var string 40 | */ 41 | protected $_remoteAddress = ''; 42 | 43 | /** 44 | * Construct. 45 | * 46 | * @param resource $socket 47 | * @param string $remote_address 48 | */ 49 | public function __construct($socket, $remote_address) 50 | { 51 | $this->_socket = $socket; 52 | $this->_remoteAddress = $remote_address; 53 | } 54 | 55 | /** 56 | * Sends data on the connection. 57 | * 58 | * @param string $send_buffer 59 | * @param bool $raw 60 | * @return void|boolean 61 | */ 62 | public function send($send_buffer, $raw = false) 63 | { 64 | if (false === $raw && $this->protocol) { 65 | $parser = $this->protocol; 66 | $send_buffer = $parser::encode($send_buffer, $this); 67 | if ($send_buffer === '') { 68 | return null; 69 | } 70 | } 71 | return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); 72 | } 73 | 74 | /** 75 | * Get remote IP. 76 | * 77 | * @return string 78 | */ 79 | public function getRemoteIp() 80 | { 81 | $pos = strrpos($this->_remoteAddress, ':'); 82 | if ($pos) { 83 | return trim(substr($this->_remoteAddress, 0, $pos), '[]'); 84 | } 85 | return ''; 86 | } 87 | 88 | /** 89 | * Get remote port. 90 | * 91 | * @return int 92 | */ 93 | public function getRemotePort() 94 | { 95 | if ($this->_remoteAddress) { 96 | return (int)substr(strrchr($this->_remoteAddress, ':'), 1); 97 | } 98 | return 0; 99 | } 100 | 101 | /** 102 | * Close connection. 103 | * 104 | * @param mixed $data 105 | * @param bool $raw 106 | * @return bool 107 | */ 108 | public function close($data = null, $raw = false) 109 | { 110 | if ($data !== null) { 111 | $this->send($data, $raw); 112 | } 113 | return true; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Connection/UdpConnection.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * UdpConnection. 18 | */ 19 | class UdpConnection extends ConnectionInterface 20 | { 21 | /** 22 | * Application layer protocol. 23 | * The format is like this Workerman\\Protocols\\Http. 24 | * 25 | * @var \Workerman\Protocols\ProtocolInterface 26 | */ 27 | public $protocol = null; 28 | 29 | /** 30 | * Udp socket. 31 | * 32 | * @var resource 33 | */ 34 | protected $_socket = null; 35 | 36 | /** 37 | * Remote address. 38 | * 39 | * @var string 40 | */ 41 | protected $_remoteAddress = ''; 42 | 43 | /** 44 | * Construct. 45 | * 46 | * @param resource $socket 47 | * @param string $remote_address 48 | */ 49 | public function __construct($socket, $remote_address) 50 | { 51 | $this->_socket = $socket; 52 | $this->_remoteAddress = $remote_address; 53 | } 54 | 55 | /** 56 | * Sends data on the connection. 57 | * 58 | * @param string $send_buffer 59 | * @param bool $raw 60 | * @return void|boolean 61 | */ 62 | public function send($send_buffer, $raw = false) 63 | { 64 | if (false === $raw && $this->protocol) { 65 | $parser = $this->protocol; 66 | $send_buffer = $parser::encode($send_buffer, $this); 67 | if ($send_buffer === '') { 68 | return null; 69 | } 70 | } 71 | return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); 72 | } 73 | 74 | /** 75 | * Get remote IP. 76 | * 77 | * @return string 78 | */ 79 | public function getRemoteIp() 80 | { 81 | $pos = strrpos($this->_remoteAddress, ':'); 82 | if ($pos) { 83 | return trim(substr($this->_remoteAddress, 0, $pos), '[]'); 84 | } 85 | return ''; 86 | } 87 | 88 | /** 89 | * Get remote port. 90 | * 91 | * @return int 92 | */ 93 | public function getRemotePort() 94 | { 95 | if ($this->_remoteAddress) { 96 | return (int)substr(strrchr($this->_remoteAddress, ':'), 1); 97 | } 98 | return 0; 99 | } 100 | 101 | /** 102 | * Close connection. 103 | * 104 | * @param mixed $data 105 | * @param bool $raw 106 | * @return bool 107 | */ 108 | public function close($data = null, $raw = false) 109 | { 110 | if ($data !== null) { 111 | $this->send($data, $raw); 112 | } 113 | return true; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Connection/AsyncUdpConnection.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | use Workerman\Events\EventInterface; 17 | use Workerman\Worker; 18 | use Exception; 19 | 20 | /** 21 | * AsyncTcpConnection. 22 | */ 23 | class AsyncUdpConnection extends UdpConnection 24 | { 25 | /** 26 | * Construct. 27 | * 28 | * @param string $remote_address 29 | * @throws Exception 30 | */ 31 | public function __construct($remote_address) 32 | { 33 | // Get the application layer communication protocol and listening address. 34 | list($scheme, $address) = explode(':', $remote_address, 2); 35 | // Check application layer protocol class. 36 | if ($scheme !== 'udp') { 37 | $scheme = ucfirst($scheme); 38 | $this->protocol = '\\Protocols\\' . $scheme; 39 | if (!class_exists($this->protocol)) { 40 | $this->protocol = "\\Workerman\\Protocols\\$scheme"; 41 | if (!class_exists($this->protocol)) { 42 | throw new Exception("class \\Protocols\\$scheme not exist"); 43 | } 44 | } 45 | } 46 | 47 | $this->_remoteAddress = substr($address, 2); 48 | $this->_socket = stream_socket_client("udp://{$this->_remoteAddress}"); 49 | Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); 50 | } 51 | 52 | /** 53 | * For udp package. 54 | * 55 | * @param resource $socket 56 | * @return bool 57 | */ 58 | public function baseRead($socket) 59 | { 60 | $recv_buffer = stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address); 61 | if (false === $recv_buffer || empty($remote_address)) { 62 | return false; 63 | } 64 | 65 | if ($this->onMessage) { 66 | if ($this->protocol) { 67 | $parser = $this->protocol; 68 | $recv_buffer = $parser::decode($recv_buffer, $this); 69 | } 70 | ConnectionInterface::$statistics['total_request']++; 71 | try { 72 | call_user_func($this->onMessage, $this, $recv_buffer); 73 | } catch (\Exception $e) { 74 | self::log($e); 75 | exit(250); 76 | } catch (\Error $e) { 77 | self::log($e); 78 | exit(250); 79 | } 80 | } 81 | return true; 82 | } 83 | 84 | 85 | /** 86 | * Close connection. 87 | * 88 | * @param mixed $data 89 | * @return bool 90 | */ 91 | public function close($data = null, $raw = false) 92 | { 93 | if ($data !== null) { 94 | $this->send($data, $raw); 95 | } 96 | Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); 97 | fclose($this->_socket); 98 | return true; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /_lib/ape/http/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/x-javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/java-archive jar war ear; 28 | application/mac-binhex40 hqx; 29 | application/msword doc; 30 | application/pdf pdf; 31 | application/postscript ps eps ai; 32 | application/rtf rtf; 33 | application/vnd.ms-excel xls; 34 | application/vnd.ms-powerpoint ppt; 35 | application/vnd.wap.wmlc wmlc; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/x-7z-compressed 7z; 39 | application/x-cocoa cco; 40 | application/x-java-archive-diff jardiff; 41 | application/x-java-jnlp-file jnlp; 42 | application/x-makeself run; 43 | application/x-perl pl pm; 44 | application/x-pilot prc pdb; 45 | application/x-rar-compressed rar; 46 | application/x-redhat-package-manager rpm; 47 | application/x-sea sea; 48 | application/x-shockwave-flash swf; 49 | application/x-stuffit sit; 50 | application/x-tcl tcl tk; 51 | application/x-x509-ca-cert der pem crt; 52 | application/x-xpinstall xpi; 53 | application/xhtml+xml xhtml; 54 | application/zip zip; 55 | 56 | application/octet-stream bin exe dll; 57 | application/octet-stream deb; 58 | application/octet-stream dmg; 59 | application/octet-stream eot; 60 | application/octet-stream iso img; 61 | application/octet-stream msi msp msm; 62 | 63 | audio/midi mid midi kar; 64 | audio/mpeg mp3; 65 | audio/ogg ogg; 66 | audio/x-m4a m4a; 67 | audio/x-realaudio ra; 68 | 69 | video/3gpp 3gpp 3gp; 70 | video/mp4 mp4; 71 | video/mpeg mpeg mpg; 72 | video/quicktime mov; 73 | video/webm webm; 74 | video/x-flv flv; 75 | video/x-m4v m4v; 76 | video/x-mng mng; 77 | video/x-ms-asf asx asf; 78 | video/x-ms-wmv wmv; 79 | video/x-msvideo avi; 80 | } 81 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Protocols/Http/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/x-javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/java-archive jar war ear; 28 | application/mac-binhex40 hqx; 29 | application/msword doc; 30 | application/pdf pdf; 31 | application/postscript ps eps ai; 32 | application/rtf rtf; 33 | application/vnd.ms-excel xls; 34 | application/vnd.ms-powerpoint ppt; 35 | application/vnd.wap.wmlc wmlc; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/x-7z-compressed 7z; 39 | application/x-cocoa cco; 40 | application/x-java-archive-diff jardiff; 41 | application/x-java-jnlp-file jnlp; 42 | application/x-makeself run; 43 | application/x-perl pl pm; 44 | application/x-pilot prc pdb; 45 | application/x-rar-compressed rar; 46 | application/x-redhat-package-manager rpm; 47 | application/x-sea sea; 48 | application/x-shockwave-flash swf; 49 | application/x-stuffit sit; 50 | application/x-tcl tcl tk; 51 | application/x-x509-ca-cert der pem crt; 52 | application/x-xpinstall xpi; 53 | application/xhtml+xml xhtml; 54 | application/zip zip; 55 | 56 | application/octet-stream bin exe dll; 57 | application/octet-stream deb; 58 | application/octet-stream dmg; 59 | application/octet-stream eot; 60 | application/octet-stream iso img; 61 | application/octet-stream msi msp msm; 62 | 63 | audio/midi mid midi kar; 64 | audio/mpeg mp3; 65 | audio/ogg ogg; 66 | audio/x-m4a m4a; 67 | audio/x-realaudio ra; 68 | 69 | video/3gpp 3gpp 3gp; 70 | video/mp4 mp4; 71 | video/mpeg mpeg mpg; 72 | video/quicktime mov; 73 | video/webm webm; 74 | video/x-flv flv; 75 | video/x-m4v m4v; 76 | video/x-mng mng; 77 | video/x-ms-asf asx asf; 78 | video/x-ms-wmv wmv; 79 | video/x-msvideo avi; 80 | } 81 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Protocols/Http/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/x-javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/java-archive jar war ear; 28 | application/mac-binhex40 hqx; 29 | application/msword doc; 30 | application/pdf pdf; 31 | application/postscript ps eps ai; 32 | application/rtf rtf; 33 | application/vnd.ms-excel xls; 34 | application/vnd.ms-powerpoint ppt; 35 | application/vnd.wap.wmlc wmlc; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/x-7z-compressed 7z; 39 | application/x-cocoa cco; 40 | application/x-java-archive-diff jardiff; 41 | application/x-java-jnlp-file jnlp; 42 | application/x-makeself run; 43 | application/x-perl pl pm; 44 | application/x-pilot prc pdb; 45 | application/x-rar-compressed rar; 46 | application/x-redhat-package-manager rpm; 47 | application/x-sea sea; 48 | application/x-shockwave-flash swf; 49 | application/x-stuffit sit; 50 | application/x-tcl tcl tk; 51 | application/x-x509-ca-cert der pem crt; 52 | application/x-xpinstall xpi; 53 | application/xhtml+xml xhtml; 54 | application/zip zip; 55 | 56 | application/octet-stream bin exe dll; 57 | application/octet-stream deb; 58 | application/octet-stream dmg; 59 | application/octet-stream eot; 60 | application/octet-stream iso img; 61 | application/octet-stream msi msp msm; 62 | 63 | audio/midi mid midi kar; 64 | audio/mpeg mp3; 65 | audio/ogg ogg; 66 | audio/x-m4a m4a; 67 | audio/x-realaudio ra; 68 | 69 | video/3gpp 3gpp 3gp; 70 | video/mp4 mp4; 71 | video/mpeg mpeg mpg; 72 | video/quicktime mov; 73 | video/webm webm; 74 | video/x-flv flv; 75 | video/x-m4v m4v; 76 | video/x-mng mng; 77 | video/x-ms-asf asx asf; 78 | video/x-ms-wmv wmv; 79 | video/x-msvideo avi; 80 | } 81 | -------------------------------------------------------------------------------- /_lib/ape/Router.php: -------------------------------------------------------------------------------- 1 | 2) { 62 | // 当前模块的路径 63 | ApeWeb::$MODULE_URL = ApeWeb::$HOME . $url_arr [0] . "/"; 64 | ApeWeb::$MODULE_NAME = "z_" . $url_arr [0]; 65 | 66 | $module_name = "z_" . $url_arr [0] . DS; 67 | $controller_path = "controller" . DS; 68 | 69 | for ($i = 1; $i < (count($url_arr) - 2); $i ++) { 70 | $controller_path = $controller_path . $url_arr [$i] . DS; 71 | } 72 | 73 | $controller_name = ucfirst($url_arr [count($url_arr) - 2]); 74 | // 将$controller_name里面的'_'后面的第一个字符换成大写的 75 | while (true) { 76 | if ($controller_name_index = strpos($controller_name, "_")) { 77 | $controller_name = substr_replace($controller_name, strtoupper($controller_name {$controller_name_index + 1}), $controller_name_index, 2); 78 | } else { 79 | break; 80 | } 81 | } 82 | $method_name = $url_arr [count($url_arr) - 1]; 83 | } 84 | 85 | // 检查拦截器 86 | foreach ($map as $route) { 87 | if (stripos($url, $route [0]) === 0) { 88 | $filter [] = $route [1]; 89 | } 90 | } 91 | 92 | // 循环中间件 93 | if (isset($filter)) { 94 | try { 95 | foreach ($filter as $cl) { 96 | $cuf_bool = call_user_func($cl, $data); 97 | // 如果拦截器终止了,那么退出整次解析 98 | if ($cuf_bool == false) { 99 | return false; 100 | } 101 | } 102 | } catch (\Exception $e) { 103 | // Jump_exit? 104 | if ($e->getMessage() != 'jump_exit') { 105 | $access_log [5] = $e; 106 | } 107 | $code = $e->getCode() ? $e->getCode() : 500; 108 | $access_log [6] = 500; 109 | } 110 | } 111 | return true; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /_lib/ape/http/Sendfile.php: -------------------------------------------------------------------------------- 1 | getRemoteIp (); 48 | $_SERVER ['REMOTE_PORT'] = $connection->getRemotePort (); 49 | include $file_path; 50 | } catch ( \Exception $e ) { 51 | // Jump_exit? 52 | if ($e->getMessage () != 'jump_exit') { 53 | echo $e; 54 | } 55 | } 56 | $content = ob_get_clean (); 57 | ini_set ( 'display_errors', 'on' ); 58 | if (strtolower ( $_SERVER ['HTTP_CONNECTION'] ) === "keep-alive") { 59 | $connection->send ( $content ); 60 | } else { 61 | $connection->close ( $content ); 62 | } 63 | return; 64 | } 65 | // Check 304. 66 | $info = stat ( $file_path ); 67 | $modified_time = $info ? date ( 'D, d M Y H:i:s', $info ['mtime'] ) . ' GMT' : ''; 68 | if (! empty ( $_SERVER ['HTTP_IF_MODIFIED_SINCE'] ) && $info) { 69 | // Http 304. 70 | if ($modified_time === $_SERVER ['HTTP_IF_MODIFIED_SINCE']) { 71 | // 304 72 | Http::header ( 'HTTP/1.1 304 Not Modified' ); 73 | // Send nothing but http headers.. 74 | $connection->close ( '' ); 75 | return; 76 | } 77 | } 78 | 79 | // Http header. 80 | if ($modified_time) { 81 | $modified_time = "Last-Modified: $modified_time\r\n"; 82 | } 83 | $file_size = filesize ( $file_path ); 84 | $file_info = pathinfo ( $file_path ); 85 | $extension = isset ( $file_info ['extension'] ) ? $file_info ['extension'] : ''; 86 | $file_name = isset ( $file_info ['filename'] ) ? $file_info ['filename'] : ''; 87 | $file_name = $file_name . $hz; 88 | $header = "HTTP/1.1 200 OK\r\n"; 89 | if (isset ( self::$mimeTypeMap [$extension] )) { 90 | $header .= "Content-Type: " . self::$mimeTypeMap [$extension] . "\r\n"; 91 | } else { 92 | $header .= "Content-Type: application/octet-stream\r\n"; 93 | $header .= "Content-Disposition: attachment; filename=\"$file_name\"\r\n"; 94 | } 95 | $header .= "Connection: keep-alive\r\n"; 96 | $header .= $modified_time; 97 | $header .= "Content-Length: $file_size\r\n\r\n"; 98 | $trunk_limit_size = 1024 * 1024 * 10; 99 | if ($file_size < $trunk_limit_size) { 100 | $connection->send ( $header . file_get_contents ( $file_path ), true ); 101 | //$connection->close(); 102 | return; 103 | } 104 | $connection->send ( $header, true ); 105 | 106 | // Read file content from disk piece by piece and send to client. 107 | $connection->fileHandler = fopen ( $file_path, 'r' ); 108 | $do_write = function () use ($connection) { 109 | // Send buffer not full. 110 | while ( empty ( $connection->bufferFull ) ) { 111 | // Read from disk. 112 | $buffer = fread ( $connection->fileHandler, 8192 ); 113 | // Read eof. 114 | if ($buffer === '' || $buffer === false) { 115 | return; 116 | } 117 | $connection->send ( $buffer, true ); 118 | } 119 | //$connection->close(); 120 | }; 121 | 122 | // Send buffer full. 123 | $connection->onBufferFull = function ($connection) { 124 | $connection->bufferFull = true; 125 | }; 126 | // Send buffer drain. 127 | $connection->onBufferDrain = function ($connection) use ($do_write) { 128 | $connection->bufferFull = false; 129 | $do_write (); 130 | }; 131 | $do_write (); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/Ev.php: -------------------------------------------------------------------------------- 1 | 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * ev eventloop 20 | */ 21 | class Ev implements EventInterface { 22 | /** 23 | * All listeners for read/write event. 24 | * 25 | * @var array 26 | */ 27 | protected $_allEvents = array (); 28 | 29 | /** 30 | * Event listeners of signal. 31 | * 32 | * @var array 33 | */ 34 | protected $_eventSignal = array (); 35 | 36 | /** 37 | * All timer event listeners. 38 | * [func, args, event, flag, time_interval] 39 | * 40 | * @var array 41 | */ 42 | protected $_eventTimer = array (); 43 | 44 | /** 45 | * Timer id. 46 | * 47 | * @var int 48 | */ 49 | protected static $_timerId = 1; 50 | 51 | /** 52 | * Add a timer. 53 | * 54 | * {@inheritdoc} 55 | * 56 | */ 57 | public function add($fd, $flag, $func, $args = null) { 58 | $callback = function ($event, $socket) use ($fd, $func) { 59 | try { 60 | call_user_func ( $func, $fd ); 61 | } catch ( \Exception $e ) { 62 | Worker::log ( $e ); 63 | exit ( 250 ); 64 | } catch ( \Error $e ) { 65 | Worker::log ( $e ); 66 | exit ( 250 ); 67 | } 68 | }; 69 | 70 | switch ($flag) { 71 | case self::EV_SIGNAL : 72 | $event = new \EvSignal ( $fd, $callback ); 73 | $this->_eventSignal [$fd] = $event; 74 | return true; 75 | case self::EV_TIMER : 76 | case self::EV_TIMER_ONCE : 77 | $repeat = $flag == self::EV_TIMER_ONCE ? 0 : $fd; 78 | $param = array ( 79 | $func, 80 | ( array ) $args, 81 | $flag, 82 | $fd, 83 | self::$_timerId 84 | ); 85 | $event = new \EvTimer ( $fd, $repeat, array ( 86 | $this, 87 | 'timerCallback' 88 | ), $param ); 89 | $this->_eventTimer [self::$_timerId] = $event; 90 | return self::$_timerId ++; 91 | default : 92 | $fd_key = ( int ) $fd; 93 | $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE; 94 | $event = new \EvIo ( $fd, $real_flag, $callback ); 95 | $this->_allEvents [$fd_key] [$flag] = $event; 96 | return true; 97 | } 98 | } 99 | 100 | /** 101 | * Remove a timer. 102 | * 103 | * {@inheritdoc} 104 | * 105 | */ 106 | public function del($fd, $flag) { 107 | switch ($flag) { 108 | case self::EV_READ : 109 | case self::EV_WRITE : 110 | $fd_key = ( int ) $fd; 111 | if (isset ( $this->_allEvents [$fd_key] [$flag] )) { 112 | $this->_allEvents [$fd_key] [$flag]->stop (); 113 | unset ( $this->_allEvents [$fd_key] [$flag] ); 114 | } 115 | if (empty ( $this->_allEvents [$fd_key] )) { 116 | unset ( $this->_allEvents [$fd_key] ); 117 | } 118 | break; 119 | case self::EV_SIGNAL : 120 | $fd_key = ( int ) $fd; 121 | if (isset ( $this->_eventSignal [$fd_key] )) { 122 | $this->_allEvents [$fd_key] [$flag]->stop (); 123 | unset ( $this->_eventSignal [$fd_key] ); 124 | } 125 | break; 126 | case self::EV_TIMER : 127 | case self::EV_TIMER_ONCE : 128 | if (isset ( $this->_eventTimer [$fd] )) { 129 | $this->_eventTimer [$fd]->stop (); 130 | unset ( $this->_eventTimer [$fd] ); 131 | } 132 | break; 133 | } 134 | return true; 135 | } 136 | 137 | /** 138 | * Timer callback. 139 | * 140 | * @param \EvWatcher $event 141 | */ 142 | public function timerCallback($event) { 143 | $param = $event->data; 144 | $timer_id = $param [4]; 145 | if ($param [2] === self::EV_TIMER_ONCE) { 146 | $this->_eventTimer [$timer_id]->stop (); 147 | unset ( $this->_eventTimer [$timer_id] ); 148 | } 149 | try { 150 | call_user_func_array ( $param [0], $param [1] ); 151 | } catch ( \Exception $e ) { 152 | Worker::log ( $e ); 153 | exit ( 250 ); 154 | } catch ( \Error $e ) { 155 | Worker::log ( $e ); 156 | exit ( 250 ); 157 | } 158 | } 159 | 160 | /** 161 | * Remove all timers. 162 | * 163 | * @return void 164 | */ 165 | public function clearAllTimer() { 166 | foreach ( $this->_eventTimer as $event ) { 167 | $event->stop (); 168 | } 169 | $this->_eventTimer = array (); 170 | } 171 | 172 | /** 173 | * Main loop. 174 | * 175 | * @see EventInterface::loop() 176 | */ 177 | public function loop() { 178 | \Ev::run (); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # workerman_web_ape 2 | 使用workerman封装的一个完整的web框架,不依赖任何其他服务,比如nginx等,自己实现了静态服务,MVC封装,支持分布式部署,性能强悍,框架优化很多细节,使用非常简单。   3 | 性能是传统php开发的10倍以上,传送门 http://www.workerman.net/bench 4 | 由于所有代码都是php实现,所以可控性非常好 5 | 6 | ## Requires 7 | PHP7 or 更高 8 | A POSIX compatible operating system (Linux, OSX, BSD) 9 | POSIX PCNTL extensions for PHP 10 | 11 | ## 路由详解 12 | 路由:根据url找寻controller下面的类和方法 13 | 规则 : http://路径/模块名字/类名/方法名 14 | ```http://127.0.0.1/admin/user_mm/all 对应z_admin模块下UserMmController类all方法``` 15 | ```http://127.0.0.1/user_mm/all 对应默认模块下UserMmController类all方法``` 16 | ```http://127.0.0.1/all 对应默认模块下默认Controller类all方法``` 17 | 首先会将url中带_后面的首字母大写,然后查找对应的类和方法 18 | 19 | 20 | ## 数据库操作详解 21 | 使用workerman提供的mysql操作类为基础,封装了find update delete count all page 等方法 22 | 可配置 真/假删除 $softDelete=true/false 23 | 数据库主键必须是id int类型 24 | 如果出现修改id的情况 使用Model::update("修改后数组",原id) 25 | 26 | ## 视图 27 | 封装了简单的输出 循环 判断 include标签,具体看例子,复杂的调用请使用php语法,或者自己扩展 28 | ``` 29 | //循环输出 30 | {foreach $n['list'] k2=>n2} 31 | //请使用单引号 32 | {$n2['name']} 33 | //判断 34 | {if $n2['id']==0} 35 | 测试 36 | {/if} 37 | {/foreach} 38 | 39 | //包含文件 40 | {include file="public.head"} 41 | 42 | ``` 43 | 44 | ## 日志 45 | 请使用dd_log("相对于log目录的文件夹","日志内容"); 46 | ``` 47 | 框架会使用和http端口相同的端口创建一个udp服务,所有日志操作都是udp操作,无阻塞。 48 | ``` 49 | ## 如何启动 50 | ```php main start ``` 51 | ```php main start -d ``` 52 | ```php main status ``` 53 | ```php main connections``` 54 | ```php main stop ``` 55 | ```php main restart ``` 56 | ```php main reload ``` 57 | ```windows环境下需要分别启动根目录下start_*.php文件 ``` 58 | 59 | # Workerman性能测试 60 | ``` 61 | CPU: Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz and 4 processors totally 62 | Memory: 8G 63 | OS: Ubuntu 14.04 LTS 64 | Software: ab 65 | PHP: 5.5.9 66 | ``` 67 | 68 | **Codes** 69 | ```php 70 | count=3; 74 | $worker->onMessage = function($connection, $data) 75 | { 76 | $connection->send("HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: workerman\r\nContent-Length: 5\r\n\r\nhello"); 77 | }; 78 | Worker::runAll(); 79 | ``` 80 | **Result** 81 | 82 | ```shell 83 | ab -n1000000 -c100 -k http://127.0.0.1:1234/ 84 | This is ApacheBench, Version 2.3 <$Revision: 1528965 $> 85 | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 86 | Licensed to The Apache Software Foundation, http://www.apache.org/ 87 | 88 | Benchmarking 127.0.0.1 (be patient) 89 | Completed 100000 requests 90 | Completed 200000 requests 91 | Completed 300000 requests 92 | Completed 400000 requests 93 | Completed 500000 requests 94 | Completed 600000 requests 95 | Completed 700000 requests 96 | Completed 800000 requests 97 | Completed 900000 requests 98 | Completed 1000000 requests 99 | Finished 1000000 requests 100 | 101 | 102 | Server Software: workerman/3.1.4 103 | Server Hostname: 127.0.0.1 104 | Server Port: 1234 105 | 106 | Document Path: / 107 | Document Length: 5 bytes 108 | 109 | Concurrency Level: 100 110 | Time taken for tests: 7.240 seconds 111 | Complete requests: 1000000 112 | Failed requests: 0 113 | Keep-Alive requests: 1000000 114 | Total transferred: 73000000 bytes 115 | HTML transferred: 5000000 bytes 116 | Requests per second: 138124.14 [#/sec] (mean) 117 | Time per request: 0.724 [ms] (mean) 118 | Time per request: 0.007 [ms] (mean, across all concurrent requests) 119 | Transfer rate: 9846.74 [Kbytes/sec] received 120 | 121 | Connection Times (ms) 122 | min mean[+/-sd] median max 123 | Connect: 0 0 0.0 0 5 124 | Processing: 0 1 0.2 1 9 125 | Waiting: 0 1 0.2 1 9 126 | Total: 0 1 0.2 1 9 127 | 128 | Percentage of the requests served within a certain time (ms) 129 | 50% 1 130 | 66% 1 131 | 75% 1 132 | 80% 1 133 | 90% 1 134 | 95% 1 135 | 98% 1 136 | 99% 1 137 | 100% 9 (longest request) 138 | 139 | ``` 140 | ## Workerman的使用方法 141 | 142 | 中文主页:[http://www.workerman.net](http://www.workerman.net) 143 | 144 | 中文文档: [http://doc.workerman.net](http://doc.workerman.net) 145 | 146 | Documentation:[https://github.com/walkor/workerman-manual](https://github.com/walkor/workerman-manual/blob/master/english/src/SUMMARY.md) 147 | 148 | 149 | 150 | ## 其他 151 | 因为workerman代码实例化一次并放在内存中运行 所以开发与传统php开发有些差别 152 | 由于使用workerman为基础,请先阅读workerman手册,一些workerman注意事项本文未提出。 153 | 参考:Navigation框架 https://github.com/xpader/Navigation 154 | 参考:WebWorker框架 https://github.com/xtgxiso/WebWorker 155 | 修改了ueediter部分代码,使其适应本框架 156 | 157 | 158 | ## 联系我 159 | 160 | QQ群: 1098698769 161 | 任何人都可以通过QQ群联系到我。 162 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Lib/Timer.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Lib; 15 | 16 | use Workerman\Events\EventInterface; 17 | use Exception; 18 | 19 | /** 20 | * Timer. 21 | * 22 | * example: 23 | * Workerman\Lib\Timer::add($time_interval, callback, array($arg1, $arg2..)); 24 | */ 25 | class Timer 26 | { 27 | /** 28 | * Tasks that based on ALARM signal. 29 | * [ 30 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 31 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 32 | * .. 33 | * ] 34 | * 35 | * @var array 36 | */ 37 | protected static $_tasks = array(); 38 | 39 | /** 40 | * event 41 | * 42 | * @var \Workerman\Events\EventInterface 43 | */ 44 | protected static $_event = null; 45 | 46 | /** 47 | * Init. 48 | * 49 | * @param \Workerman\Events\EventInterface $event 50 | * @return void 51 | */ 52 | public static function init($event = null) 53 | { 54 | if ($event) { 55 | self::$_event = $event; 56 | } else { 57 | pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); 58 | } 59 | } 60 | 61 | /** 62 | * ALARM signal handler. 63 | * 64 | * @return void 65 | */ 66 | public static function signalHandle() 67 | { 68 | if (!self::$_event) { 69 | pcntl_alarm(1); 70 | self::tick(); 71 | } 72 | } 73 | 74 | /** 75 | * Add a timer. 76 | * 77 | * @param int $time_interval 78 | * @param callback $func 79 | * @param mixed $args 80 | * @param bool $persistent 81 | * @return bool 82 | */ 83 | public static function add($time_interval, $func, $args = array(), $persistent = true) 84 | { 85 | if ($time_interval <= 0) { 86 | echo new Exception("bad time_interval"); 87 | return false; 88 | } 89 | 90 | if (self::$_event) { 91 | return self::$_event->add($time_interval, 92 | $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); 93 | } 94 | 95 | if (!is_callable($func)) { 96 | echo new Exception("not callable"); 97 | return false; 98 | } 99 | 100 | if (empty(self::$_tasks)) { 101 | pcntl_alarm(1); 102 | } 103 | 104 | $time_now = time(); 105 | $run_time = $time_now + $time_interval; 106 | if (!isset(self::$_tasks[$run_time])) { 107 | self::$_tasks[$run_time] = array(); 108 | } 109 | self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); 110 | return true; 111 | } 112 | 113 | 114 | /** 115 | * Tick. 116 | * 117 | * @return void 118 | */ 119 | public static function tick() 120 | { 121 | if (empty(self::$_tasks)) { 122 | pcntl_alarm(0); 123 | return; 124 | } 125 | 126 | $time_now = time(); 127 | foreach (self::$_tasks as $run_time => $task_data) { 128 | if ($time_now >= $run_time) { 129 | foreach ($task_data as $index => $one_task) { 130 | $task_func = $one_task[0]; 131 | $task_args = $one_task[1]; 132 | $persistent = $one_task[2]; 133 | $time_interval = $one_task[3]; 134 | try { 135 | call_user_func_array($task_func, $task_args); 136 | } catch (\Exception $e) { 137 | echo $e; 138 | } 139 | if ($persistent) { 140 | self::add($time_interval, $task_func, $task_args); 141 | } 142 | } 143 | unset(self::$_tasks[$run_time]); 144 | } 145 | } 146 | } 147 | 148 | /** 149 | * Remove a timer. 150 | * 151 | * @param mixed $timer_id 152 | * @return bool 153 | */ 154 | public static function del($timer_id) 155 | { 156 | if (self::$_event) { 157 | return self::$_event->del($timer_id, EventInterface::EV_TIMER); 158 | } 159 | 160 | return false; 161 | } 162 | 163 | /** 164 | * Remove all timers. 165 | * 166 | * @return void 167 | */ 168 | public static function delAll() 169 | { 170 | self::$_tasks = array(); 171 | pcntl_alarm(0); 172 | if (self::$_event) { 173 | self::$_event->clearAllTimer(); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Lib/Timer.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Lib; 15 | 16 | use Workerman\Events\EventInterface; 17 | use Exception; 18 | 19 | /** 20 | * Timer. 21 | * 22 | * example: 23 | * Workerman\Lib\Timer::add($time_interval, callback, array($arg1, $arg2..)); 24 | */ 25 | class Timer 26 | { 27 | /** 28 | * Tasks that based on ALARM signal. 29 | * [ 30 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 31 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 32 | * .. 33 | * ] 34 | * 35 | * @var array 36 | */ 37 | protected static $_tasks = array(); 38 | 39 | /** 40 | * event 41 | * 42 | * @var \Workerman\Events\EventInterface 43 | */ 44 | protected static $_event = null; 45 | 46 | /** 47 | * Init. 48 | * 49 | * @param \Workerman\Events\EventInterface $event 50 | * @return void 51 | */ 52 | public static function init($event = null) 53 | { 54 | if ($event) { 55 | self::$_event = $event; 56 | } else { 57 | pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); 58 | } 59 | } 60 | 61 | /** 62 | * ALARM signal handler. 63 | * 64 | * @return void 65 | */ 66 | public static function signalHandle() 67 | { 68 | if (!self::$_event) { 69 | pcntl_alarm(1); 70 | self::tick(); 71 | } 72 | } 73 | 74 | /** 75 | * Add a timer. 76 | * 77 | * @param int $time_interval 78 | * @param callback $func 79 | * @param mixed $args 80 | * @param bool $persistent 81 | * @return int/false 82 | */ 83 | public static function add($time_interval, $func, $args = array(), $persistent = true) 84 | { 85 | if ($time_interval <= 0) { 86 | echo new Exception("bad time_interval"); 87 | return false; 88 | } 89 | 90 | if (self::$_event) { 91 | return self::$_event->add($time_interval, 92 | $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); 93 | } 94 | 95 | if (!is_callable($func)) { 96 | echo new Exception("not callable"); 97 | return false; 98 | } 99 | 100 | if (empty(self::$_tasks)) { 101 | pcntl_alarm(1); 102 | } 103 | 104 | $time_now = time(); 105 | $run_time = $time_now + $time_interval; 106 | if (!isset(self::$_tasks[$run_time])) { 107 | self::$_tasks[$run_time] = array(); 108 | } 109 | self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); 110 | return 1; 111 | } 112 | 113 | 114 | /** 115 | * Tick. 116 | * 117 | * @return void 118 | */ 119 | public static function tick() 120 | { 121 | if (empty(self::$_tasks)) { 122 | pcntl_alarm(0); 123 | return; 124 | } 125 | 126 | $time_now = time(); 127 | foreach (self::$_tasks as $run_time => $task_data) { 128 | if ($time_now >= $run_time) { 129 | foreach ($task_data as $index => $one_task) { 130 | $task_func = $one_task[0]; 131 | $task_args = $one_task[1]; 132 | $persistent = $one_task[2]; 133 | $time_interval = $one_task[3]; 134 | try { 135 | call_user_func_array($task_func, $task_args); 136 | } catch (\Exception $e) { 137 | echo $e; 138 | } 139 | if ($persistent) { 140 | self::add($time_interval, $task_func, $task_args); 141 | } 142 | } 143 | unset(self::$_tasks[$run_time]); 144 | } 145 | } 146 | } 147 | 148 | /** 149 | * Remove a timer. 150 | * 151 | * @param mixed $timer_id 152 | * @return bool 153 | */ 154 | public static function del($timer_id) 155 | { 156 | if (self::$_event) { 157 | return self::$_event->del($timer_id, EventInterface::EV_TIMER); 158 | } 159 | 160 | return false; 161 | } 162 | 163 | /** 164 | * Remove all timers. 165 | * 166 | * @return void 167 | */ 168 | public static function delAll() 169 | { 170 | self::$_tasks = array(); 171 | pcntl_alarm(0); 172 | if (self::$_event) { 173 | self::$_event->clearAllTimer(); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/React/ExtEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class ExtEventLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class ExtEventLoop extends \React\EventLoop\ExtEventLoop 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var EventBase 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All signal Event instances. 32 | * 33 | * @var array 34 | */ 35 | protected $_signalEvents = array(); 36 | 37 | /** 38 | * @var array 39 | */ 40 | protected $_timerIdMap = array(); 41 | 42 | /** 43 | * @var int 44 | */ 45 | protected $_timerIdIndex = 0; 46 | 47 | /** 48 | * Add event listener to event loop. 49 | * 50 | * @param $fd 51 | * @param $flag 52 | * @param $func 53 | * @param array $args 54 | * @return bool 55 | */ 56 | public function add($fd, $flag, $func, $args = array()) 57 | { 58 | $args = (array)$args; 59 | switch ($flag) { 60 | case EventInterface::EV_READ: 61 | return $this->addReadStream($fd, $func); 62 | case EventInterface::EV_WRITE: 63 | return $this->addWriteStream($fd, $func); 64 | case EventInterface::EV_SIGNAL: 65 | return $this->addSignal($fd, $func); 66 | case EventInterface::EV_TIMER: 67 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 68 | call_user_func_array($func, $args); 69 | }); 70 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 71 | return $this->_timerIdIndex; 72 | case EventInterface::EV_TIMER_ONCE: 73 | $timer_obj = $this->addTimer($fd, function() use ($func, $args) { 74 | call_user_func_array($func, $args); 75 | }); 76 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 77 | return $this->_timerIdIndex; 78 | } 79 | return false; 80 | } 81 | 82 | /** 83 | * Remove event listener from event loop. 84 | * 85 | * @param mixed $fd 86 | * @param int $flag 87 | * @return bool 88 | */ 89 | public function del($fd, $flag) 90 | { 91 | switch ($flag) { 92 | case EventInterface::EV_READ: 93 | return $this->removeReadStream($fd); 94 | case EventInterface::EV_WRITE: 95 | return $this->removeWriteStream($fd); 96 | case EventInterface::EV_SIGNAL: 97 | return $this->removeSignal($fd); 98 | case EventInterface::EV_TIMER: 99 | case EventInterface::EV_TIMER_ONCE; 100 | if (isset($this->_timerIdMap[$fd])){ 101 | $timer_obj = $this->_timerIdMap[$fd]; 102 | unset($this->_timerIdMap[$fd]); 103 | $this->cancelTimer($timer_obj); 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | 110 | 111 | /** 112 | * Main loop. 113 | * 114 | * @return void 115 | */ 116 | public function loop() 117 | { 118 | $this->run(); 119 | } 120 | 121 | /** 122 | * Construct 123 | */ 124 | public function __construct() 125 | { 126 | parent::__construct(); 127 | $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop'); 128 | $property = $class->getProperty('eventBase'); 129 | $property->setAccessible(true); 130 | $this->_eventBase = $property->getValue($this); 131 | } 132 | 133 | /** 134 | * Add signal handler. 135 | * 136 | * @param $signal 137 | * @param $callback 138 | * @return bool 139 | */ 140 | public function addSignal($signal, $callback) 141 | { 142 | $event = \Event::signal($this->_eventBase, $signal, $callback); 143 | if (!$event||!$event->add()) { 144 | return false; 145 | } 146 | $this->_signalEvents[$signal] = $event; 147 | } 148 | 149 | /** 150 | * Remove signal handler. 151 | * 152 | * @param $signal 153 | */ 154 | public function removeSignal($signal) 155 | { 156 | if (isset($this->_signalEvents[$signal])) { 157 | $this->_signalEvents[$signal]->del(); 158 | unset($this->_signalEvents[$signal]); 159 | } 160 | } 161 | 162 | /** 163 | * Destroy loop. 164 | * 165 | * @return void 166 | */ 167 | public function destroy() 168 | { 169 | foreach ($this->_signalEvents as $event) { 170 | $event->del(); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/React/LibEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class LibEventLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class LibEventLoop extends \React\EventLoop\LibEventLoop 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var event_base resource 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All signal Event instances. 32 | * 33 | * @var array 34 | */ 35 | protected $_signalEvents = array(); 36 | 37 | /** 38 | * @var array 39 | */ 40 | protected $_timerIdMap = array(); 41 | 42 | /** 43 | * @var int 44 | */ 45 | protected $_timerIdIndex = 0; 46 | 47 | /** 48 | * Add event listener to event loop. 49 | * 50 | * @param $fd 51 | * @param $flag 52 | * @param $func 53 | * @param array $args 54 | * @return bool 55 | */ 56 | public function add($fd, $flag, $func, $args = array()) 57 | { 58 | $args = (array)$args; 59 | switch ($flag) { 60 | case EventInterface::EV_READ: 61 | return $this->addReadStream($fd, $func); 62 | case EventInterface::EV_WRITE: 63 | return $this->addWriteStream($fd, $func); 64 | case EventInterface::EV_SIGNAL: 65 | return $this->addSignal($fd, $func); 66 | case EventInterface::EV_TIMER: 67 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 68 | call_user_func_array($func, $args); 69 | }); 70 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 71 | return $this->_timerIdIndex; 72 | case EventInterface::EV_TIMER_ONCE: 73 | $timer_obj = $this->addTimer($fd, function() use ($func, $args) { 74 | call_user_func_array($func, $args); 75 | }); 76 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 77 | return $this->_timerIdIndex; 78 | } 79 | return false; 80 | } 81 | 82 | /** 83 | * Remove event listener from event loop. 84 | * 85 | * @param mixed $fd 86 | * @param int $flag 87 | * @return bool 88 | */ 89 | public function del($fd, $flag) 90 | { 91 | switch ($flag) { 92 | case EventInterface::EV_READ: 93 | return $this->removeReadStream($fd); 94 | case EventInterface::EV_WRITE: 95 | return $this->removeWriteStream($fd); 96 | case EventInterface::EV_SIGNAL: 97 | return $this->removeSignal($fd); 98 | case EventInterface::EV_TIMER: 99 | case EventInterface::EV_TIMER_ONCE; 100 | if (isset($this->_timerIdMap[$fd])){ 101 | $timer_obj = $this->_timerIdMap[$fd]; 102 | unset($this->_timerIdMap[$fd]); 103 | $this->cancelTimer($timer_obj); 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | 110 | 111 | /** 112 | * Main loop. 113 | * 114 | * @return void 115 | */ 116 | public function loop() 117 | { 118 | $this->run(); 119 | } 120 | 121 | /** 122 | * Construct. 123 | */ 124 | public function __construct() 125 | { 126 | parent::__construct(); 127 | $class = new \ReflectionClass('\React\EventLoop\LibEventLoop'); 128 | $property = $class->getProperty('eventBase'); 129 | $property->setAccessible(true); 130 | $this->_eventBase = $property->getValue($this); 131 | } 132 | 133 | /** 134 | * Add signal handler. 135 | * 136 | * @param $signal 137 | * @param $callback 138 | * @return bool 139 | */ 140 | public function addSignal($signal, $callback) 141 | { 142 | $event = event_new(); 143 | $this->_signalEvents[$signal] = $event; 144 | event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback); 145 | event_base_set($event, $this->_eventBase); 146 | event_add($event); 147 | } 148 | 149 | /** 150 | * Remove signal handler. 151 | * 152 | * @param $signal 153 | */ 154 | public function removeSignal($signal) 155 | { 156 | if (isset($this->_signalEvents[$signal])) { 157 | $event = $this->_signalEvents[$signal]; 158 | event_del($event); 159 | unset($this->_signalEvents[$signal]); 160 | } 161 | } 162 | 163 | /** 164 | * Destroy loop. 165 | * 166 | * @return void 167 | */ 168 | public function destroy() 169 | { 170 | foreach ($this->_signalEvents as $event) { 171 | event_del($event); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/React/StreamSelectLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class StreamSelectLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop 22 | { 23 | /** 24 | * @var array 25 | */ 26 | protected $_timerIdMap = array(); 27 | 28 | /** 29 | * @var int 30 | */ 31 | protected $_timerIdIndex = 0; 32 | 33 | /** 34 | * Add event listener to event loop. 35 | * 36 | * @param $fd 37 | * @param $flag 38 | * @param $func 39 | * @param array $args 40 | * @return bool 41 | */ 42 | public function add($fd, $flag, $func, $args = array()) 43 | { 44 | $args = (array)$args; 45 | switch ($flag) { 46 | case EventInterface::EV_READ: 47 | return $this->addReadStream($fd, $func); 48 | case EventInterface::EV_WRITE: 49 | return $this->addWriteStream($fd, $func); 50 | case EventInterface::EV_SIGNAL: 51 | return $this->addSignal($fd, $func); 52 | case EventInterface::EV_TIMER: 53 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 54 | call_user_func_array($func, $args); 55 | }); 56 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 57 | return $this->_timerIdIndex; 58 | case EventInterface::EV_TIMER_ONCE: 59 | $timer_obj = $this->addTimer($fd, function() use ($func, $args) { 60 | call_user_func_array($func, $args); 61 | }); 62 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 63 | return $this->_timerIdIndex; 64 | } 65 | return false; 66 | } 67 | 68 | /** 69 | * Remove event listener from event loop. 70 | * 71 | * @param mixed $fd 72 | * @param int $flag 73 | * @return bool 74 | */ 75 | public function del($fd, $flag) 76 | { 77 | switch ($flag) { 78 | case EventInterface::EV_READ: 79 | return $this->removeReadStream($fd); 80 | case EventInterface::EV_WRITE: 81 | return $this->removeWriteStream($fd); 82 | case EventInterface::EV_SIGNAL: 83 | return $this->removeSignal($fd); 84 | case EventInterface::EV_TIMER: 85 | case EventInterface::EV_TIMER_ONCE; 86 | if (isset($this->_timerIdMap[$fd])){ 87 | $timer_obj = $this->_timerIdMap[$fd]; 88 | unset($this->_timerIdMap[$fd]); 89 | $this->cancelTimer($timer_obj); 90 | return true; 91 | } 92 | } 93 | return false; 94 | } 95 | 96 | 97 | /** 98 | * Main loop. 99 | * 100 | * @return void 101 | */ 102 | public function loop() 103 | { 104 | $this->run(); 105 | } 106 | 107 | /** 108 | * Add signal handler. 109 | * 110 | * @param $signal 111 | * @param $callback 112 | * @return bool 113 | */ 114 | public function addSignal($signal, $callback) 115 | { 116 | if(PHP_EOL !== "\r\n") { 117 | pcntl_signal($signal, $callback); 118 | } 119 | } 120 | 121 | /** 122 | * Remove signal handler. 123 | * 124 | * @param $signal 125 | */ 126 | public function removeSignal($signal) 127 | { 128 | if(PHP_EOL !== "\r\n") { 129 | pcntl_signal($signal, SIG_IGN); 130 | } 131 | } 132 | 133 | /** 134 | * Emulate a stream_select() implementation that does not break when passed 135 | * empty stream arrays. 136 | * 137 | * @param array &$read An array of read streams to select upon. 138 | * @param array &$write An array of write streams to select upon. 139 | * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. 140 | * 141 | * @return integer|false The total number of streams that are ready for read/write. 142 | * Can return false if stream_select() is interrupted by a signal. 143 | */ 144 | protected function streamSelect(array &$read, array &$write, $timeout) 145 | { 146 | if ($read || $write) { 147 | $except = null; 148 | // Calls signal handlers for pending signals 149 | pcntl_signal_dispatch(); 150 | // suppress warnings that occur, when stream_select is interrupted by a signal 151 | return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); 152 | } 153 | 154 | // Calls signal handlers for pending signals 155 | if(PHP_EOL !== "\r\n") { 156 | pcntl_signal_dispatch(); 157 | } 158 | $timeout && usleep($timeout); 159 | 160 | return 0; 161 | } 162 | 163 | /** 164 | * Destroy loop. 165 | * 166 | * @return void 167 | */ 168 | public function destroy() 169 | { 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/Ev.php: -------------------------------------------------------------------------------- 1 | 10 | * @link http://www.workerman.net/ 11 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 12 | */ 13 | namespace Workerman\Events; 14 | 15 | use Workerman\Worker; 16 | 17 | /** 18 | * ev eventloop 19 | */ 20 | class Ev implements EventInterface 21 | { 22 | /** 23 | * All listeners for read/write event. 24 | * 25 | * @var array 26 | */ 27 | protected $_allEvents = array(); 28 | 29 | /** 30 | * Event listeners of signal. 31 | * 32 | * @var array 33 | */ 34 | protected $_eventSignal = array(); 35 | 36 | /** 37 | * All timer event listeners. 38 | * [func, args, event, flag, time_interval] 39 | * 40 | * @var array 41 | */ 42 | protected $_eventTimer = array(); 43 | 44 | /** 45 | * Timer id. 46 | * 47 | * @var int 48 | */ 49 | protected static $_timerId = 1; 50 | 51 | /** 52 | * Add a timer. 53 | * {@inheritdoc} 54 | */ 55 | public function add($fd, $flag, $func, $args = null) 56 | { 57 | $callback = function ($event, $socket) use ($fd, $func) { 58 | try { 59 | call_user_func($func, $fd); 60 | } catch (\Exception $e) { 61 | Worker::log($e); 62 | exit(250); 63 | } catch (\Error $e) { 64 | Worker::log($e); 65 | exit(250); 66 | } 67 | }; 68 | switch ($flag) { 69 | case self::EV_SIGNAL: 70 | $event = new \EvSignal($fd, $callback); 71 | $this->_eventSignal[$fd] = $event; 72 | return true; 73 | case self::EV_TIMER: 74 | case self::EV_TIMER_ONCE: 75 | $repeat = $flag == self::EV_TIMER_ONCE ? 0 : $fd; 76 | $param = array($func, (array)$args, $flag, $fd, self::$_timerId); 77 | $event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param); 78 | $this->_eventTimer[self::$_timerId] = $event; 79 | return self::$_timerId++; 80 | default : 81 | $fd_key = (int)$fd; 82 | $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE; 83 | $event = new \EvIo($fd, $real_flag, $callback); 84 | $this->_allEvents[$fd_key][$flag] = $event; 85 | return true; 86 | } 87 | 88 | } 89 | 90 | /** 91 | * Remove a timer. 92 | * {@inheritdoc} 93 | */ 94 | public function del($fd, $flag) 95 | { 96 | switch ($flag) { 97 | case self::EV_READ: 98 | case self::EV_WRITE: 99 | $fd_key = (int)$fd; 100 | if (isset($this->_allEvents[$fd_key][$flag])) { 101 | $this->_allEvents[$fd_key][$flag]->stop(); 102 | unset($this->_allEvents[$fd_key][$flag]); 103 | } 104 | if (empty($this->_allEvents[$fd_key])) { 105 | unset($this->_allEvents[$fd_key]); 106 | } 107 | break; 108 | case self::EV_SIGNAL: 109 | $fd_key = (int)$fd; 110 | if (isset($this->_eventSignal[$fd_key])) { 111 | $this->_eventSignal[$fd_key]->stop(); 112 | unset($this->_eventSignal[$fd_key]); 113 | } 114 | break; 115 | case self::EV_TIMER: 116 | case self::EV_TIMER_ONCE: 117 | if (isset($this->_eventTimer[$fd])) { 118 | $this->_eventTimer[$fd]->stop(); 119 | unset($this->_eventTimer[$fd]); 120 | } 121 | break; 122 | } 123 | return true; 124 | } 125 | 126 | /** 127 | * Timer callback. 128 | * 129 | * @param \EvWatcher $event 130 | */ 131 | public function timerCallback($event) 132 | { 133 | $param = $event->data; 134 | $timer_id = $param[4]; 135 | if ($param[2] === self::EV_TIMER_ONCE) { 136 | $this->_eventTimer[$timer_id]->stop(); 137 | unset($this->_eventTimer[$timer_id]); 138 | } 139 | try { 140 | call_user_func_array($param[0], $param[1]); 141 | } catch (\Exception $e) { 142 | Worker::log($e); 143 | exit(250); 144 | } catch (\Error $e) { 145 | Worker::log($e); 146 | exit(250); 147 | } 148 | } 149 | 150 | /** 151 | * Remove all timers. 152 | * 153 | * @return void 154 | */ 155 | public function clearAllTimer() 156 | { 157 | foreach ($this->_eventTimer as $event) { 158 | $event->stop(); 159 | } 160 | $this->_eventTimer = array(); 161 | } 162 | 163 | /** 164 | * Main loop. 165 | * 166 | * @see EventInterface::loop() 167 | */ 168 | public function loop() 169 | { 170 | \Ev::run(); 171 | } 172 | 173 | /** 174 | * Destroy loop. 175 | * 176 | * @return void 177 | */ 178 | public function destroy() 179 | { 180 | foreach ($this->_allEvents as $event) { 181 | $event->stop(); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/Event.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 有个鬼<42765633@qq.com> 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Event implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * @var object 26 | */ 27 | protected $_eventBase = null; 28 | 29 | /** 30 | * All listeners for read/write event. 31 | * @var array 32 | */ 33 | protected $_allEvents = array(); 34 | 35 | /** 36 | * Event listeners of signal. 37 | * @var array 38 | */ 39 | protected $_eventSignal = array(); 40 | 41 | /** 42 | * All timer event listeners. 43 | * [func, args, event, flag, time_interval] 44 | * @var array 45 | */ 46 | protected $_eventTimer = array(); 47 | 48 | /** 49 | * Timer id. 50 | * @var int 51 | */ 52 | protected static $_timerId = 1; 53 | 54 | /** 55 | * construct 56 | * @return void 57 | */ 58 | public function __construct() 59 | { 60 | $this->_eventBase = new \EventBase(); 61 | } 62 | 63 | /** 64 | * @see EventInterface::add() 65 | */ 66 | public function add($fd, $flag, $func, $args=array()) 67 | { 68 | switch ($flag) { 69 | case self::EV_SIGNAL: 70 | 71 | $fd_key = (int)$fd; 72 | $event = \Event::signal($this->_eventBase, $fd, $func); 73 | if (!$event||!$event->add()) { 74 | return false; 75 | } 76 | $this->_eventSignal[$fd_key] = $event; 77 | return true; 78 | 79 | case self::EV_TIMER: 80 | case self::EV_TIMER_ONCE: 81 | 82 | $param = array($func, (array)$args, $flag, $fd, self::$_timerId); 83 | $event = new \Event($this->_eventBase, -1, \Event::TIMEOUT|\Event::PERSIST, array($this, "timerCallback"), $param); 84 | if (!$event||!$event->addTimer($fd)) { 85 | return false; 86 | } 87 | $this->_eventTimer[self::$_timerId] = $event; 88 | return self::$_timerId++; 89 | 90 | default : 91 | $fd_key = (int)$fd; 92 | $real_flag = $flag === self::EV_READ ? \Event::READ | \Event::PERSIST : \Event::WRITE | \Event::PERSIST; 93 | $event = new \Event($this->_eventBase, $fd, $real_flag, $func, $fd); 94 | if (!$event||!$event->add()) { 95 | return false; 96 | } 97 | $this->_allEvents[$fd_key][$flag] = $event; 98 | return true; 99 | } 100 | } 101 | 102 | /** 103 | * @see Events\EventInterface::del() 104 | */ 105 | public function del($fd, $flag) 106 | { 107 | switch ($flag) { 108 | 109 | case self::EV_READ: 110 | case self::EV_WRITE: 111 | 112 | $fd_key = (int)$fd; 113 | if (isset($this->_allEvents[$fd_key][$flag])) { 114 | $this->_allEvents[$fd_key][$flag]->del(); 115 | unset($this->_allEvents[$fd_key][$flag]); 116 | } 117 | if (empty($this->_allEvents[$fd_key])) { 118 | unset($this->_allEvents[$fd_key]); 119 | } 120 | break; 121 | 122 | case self::EV_SIGNAL: 123 | 124 | $fd_key = (int)$fd; 125 | if (isset($this->_eventSignal[$fd_key])) { 126 | $this->_allEvents[$fd_key][$flag]->del(); 127 | unset($this->_eventSignal[$fd_key]); 128 | } 129 | break; 130 | 131 | case self::EV_TIMER: 132 | case self::EV_TIMER_ONCE: 133 | if (isset($this->_eventTimer[$fd])) { 134 | $this->_eventTimer[$fd]->del(); 135 | unset($this->_eventTimer[$fd]); 136 | } 137 | break; 138 | } 139 | return true; 140 | } 141 | 142 | /** 143 | * Timer callback. 144 | * @param null $fd 145 | * @param int $what 146 | * @param int $timer_id 147 | */ 148 | public function timerCallback($fd, $what, $param) 149 | { 150 | $timer_id = $param[4]; 151 | 152 | if ($param[2] === self::EV_TIMER_ONCE) { 153 | $this->_eventTimer[$timer_id]->del(); 154 | unset($this->_eventTimer[$timer_id]); 155 | } 156 | 157 | try { 158 | call_user_func_array($param[0], $param[1]); 159 | } catch (\Exception $e) { 160 | Worker::log($e); 161 | exit(250); 162 | } catch (\Error $e) { 163 | Worker::log($e); 164 | exit(250); 165 | } 166 | } 167 | 168 | /** 169 | * @see Events\EventInterface::clearAllTimer() 170 | * @return void 171 | */ 172 | public function clearAllTimer() 173 | { 174 | foreach ($this->_eventTimer as $event) { 175 | $event->del(); 176 | } 177 | $this->_eventTimer = array(); 178 | } 179 | 180 | 181 | /** 182 | * @see EventInterface::loop() 183 | */ 184 | public function loop() 185 | { 186 | $this->_eventBase->loop(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/Event.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 有个鬼<42765633@qq.com> 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Event implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * @var object 26 | */ 27 | protected $_eventBase = null; 28 | 29 | /** 30 | * All listeners for read/write event. 31 | * @var array 32 | */ 33 | protected $_allEvents = array(); 34 | 35 | /** 36 | * Event listeners of signal. 37 | * @var array 38 | */ 39 | protected $_eventSignal = array(); 40 | 41 | /** 42 | * All timer event listeners. 43 | * [func, args, event, flag, time_interval] 44 | * @var array 45 | */ 46 | protected $_eventTimer = array(); 47 | 48 | /** 49 | * Timer id. 50 | * @var int 51 | */ 52 | protected static $_timerId = 1; 53 | 54 | /** 55 | * construct 56 | * @return void 57 | */ 58 | public function __construct() 59 | { 60 | $this->_eventBase = new \EventBase(); 61 | } 62 | 63 | /** 64 | * @see EventInterface::add() 65 | */ 66 | public function add($fd, $flag, $func, $args=array()) 67 | { 68 | switch ($flag) { 69 | case self::EV_SIGNAL: 70 | 71 | $fd_key = (int)$fd; 72 | $event = \Event::signal($this->_eventBase, $fd, $func); 73 | if (!$event||!$event->add()) { 74 | return false; 75 | } 76 | $this->_eventSignal[$fd_key] = $event; 77 | return true; 78 | 79 | case self::EV_TIMER: 80 | case self::EV_TIMER_ONCE: 81 | 82 | $param = array($func, (array)$args, $flag, $fd, self::$_timerId); 83 | $event = new \Event($this->_eventBase, -1, \Event::TIMEOUT|\Event::PERSIST, array($this, "timerCallback"), $param); 84 | if (!$event||!$event->addTimer($fd)) { 85 | return false; 86 | } 87 | $this->_eventTimer[self::$_timerId] = $event; 88 | return self::$_timerId++; 89 | 90 | default : 91 | $fd_key = (int)$fd; 92 | $real_flag = $flag === self::EV_READ ? \Event::READ | \Event::PERSIST : \Event::WRITE | \Event::PERSIST; 93 | $event = new \Event($this->_eventBase, $fd, $real_flag, $func, $fd); 94 | if (!$event||!$event->add()) { 95 | return false; 96 | } 97 | $this->_allEvents[$fd_key][$flag] = $event; 98 | return true; 99 | } 100 | } 101 | 102 | /** 103 | * @see Events\EventInterface::del() 104 | */ 105 | public function del($fd, $flag) 106 | { 107 | switch ($flag) { 108 | 109 | case self::EV_READ: 110 | case self::EV_WRITE: 111 | 112 | $fd_key = (int)$fd; 113 | if (isset($this->_allEvents[$fd_key][$flag])) { 114 | $this->_allEvents[$fd_key][$flag]->del(); 115 | unset($this->_allEvents[$fd_key][$flag]); 116 | } 117 | if (empty($this->_allEvents[$fd_key])) { 118 | unset($this->_allEvents[$fd_key]); 119 | } 120 | break; 121 | 122 | case self::EV_SIGNAL: 123 | $fd_key = (int)$fd; 124 | if (isset($this->_eventSignal[$fd_key])) { 125 | $this->_eventSignal[$fd_key]->del(); 126 | unset($this->_eventSignal[$fd_key]); 127 | } 128 | break; 129 | 130 | case self::EV_TIMER: 131 | case self::EV_TIMER_ONCE: 132 | if (isset($this->_eventTimer[$fd])) { 133 | $this->_eventTimer[$fd]->del(); 134 | unset($this->_eventTimer[$fd]); 135 | } 136 | break; 137 | } 138 | return true; 139 | } 140 | 141 | /** 142 | * Timer callback. 143 | * @param null $fd 144 | * @param int $what 145 | * @param int $timer_id 146 | */ 147 | public function timerCallback($fd, $what, $param) 148 | { 149 | $timer_id = $param[4]; 150 | 151 | if ($param[2] === self::EV_TIMER_ONCE) { 152 | $this->_eventTimer[$timer_id]->del(); 153 | unset($this->_eventTimer[$timer_id]); 154 | } 155 | 156 | try { 157 | call_user_func_array($param[0], $param[1]); 158 | } catch (\Exception $e) { 159 | Worker::log($e); 160 | exit(250); 161 | } catch (\Error $e) { 162 | Worker::log($e); 163 | exit(250); 164 | } 165 | } 166 | 167 | /** 168 | * @see Events\EventInterface::clearAllTimer() 169 | * @return void 170 | */ 171 | public function clearAllTimer() 172 | { 173 | foreach ($this->_eventTimer as $event) { 174 | $event->del(); 175 | } 176 | $this->_eventTimer = array(); 177 | } 178 | 179 | 180 | /** 181 | * @see EventInterface::loop() 182 | */ 183 | public function loop() 184 | { 185 | $this->_eventBase->loop(); 186 | } 187 | 188 | /** 189 | * Destroy loop. 190 | * 191 | * @return void 192 | */ 193 | public function destroy() 194 | { 195 | foreach ($this->_eventSignal as $event) { 196 | $event->del(); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /_lib/ape/helper.php: -------------------------------------------------------------------------------- 1 | "; 88 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . ""; 89 | return true; 90 | } 91 | 92 | /** 93 | * 返回上一页的js脚本 94 | */ 95 | function history_back() { 96 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . ""; 97 | } 98 | 99 | // 重定向方法,url需要传递相对于views的路径 100 | function R($url, $arr = array()) { 101 | $en = strpos ( $url, "http" ); 102 | if ($en !== 0) { 103 | $url = ApeWeb::$MODULE_URL . $url; 104 | } 105 | // 跳转默认是当前模块 106 | if (count ( $arr ) <= 0) { 107 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . ""; 108 | } else { 109 | $str = ""; 110 | $str = "
"; 111 | foreach ( $arr as $key => $n ) { 112 | $str = $str . ""; 113 | } 114 | $str = $str . "
"; 115 | $str = $str . ""; 116 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . $str; 117 | } 118 | return true; 119 | } 120 | 121 | /** 122 | * 发送api 123 | */ 124 | function api($msg, $code, $content) { 125 | Http::header ( "Content-type: application/json" ); 126 | $arr ["msg"] = $msg; 127 | $arr ["code"] = $code; 128 | $arr ["content"] = $content; 129 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . json_encode ( $arr ); 130 | return true; 131 | } 132 | 133 | /** 134 | * 返回页面 135 | */ 136 | function view($tpl, &$arr = array()) { 137 | ApeWeb::$SEND_BODY = ApeWeb::$SEND_BODY . ApeWeb::$view->view ( $tpl, $arr ); 138 | return true; 139 | } 140 | 141 | /** 142 | * 随机数 143 | * 144 | * @param unknown $length 145 | * @param string $chars 146 | * @return string 147 | */ 148 | function random($length, $chars = '1234567890qwertyuiopasdfghjklzxcvbnm') { 149 | $hash = ''; 150 | $max = strlen ( $chars ) - 1; 151 | for($i = 0; $i < $length; $i ++) { 152 | $hash .= $chars [mt_rand ( 0, $max )]; 153 | } 154 | return $hash; 155 | } 156 | 157 | /** 158 | * 清理 HTML 中的 XSS 潜在威胁 159 | * 参考:https://github.com/xpader/Navigation 160 | * 千辛万苦写出来,捣鼓正则累死人 161 | * 162 | * @param string|array $string 163 | * @param bool $strict 164 | * 严格模式下,iframe 等元素也会被过滤 165 | * @return mixed 166 | */ 167 | function clean_xss($string, $strict = true) { 168 | if (is_array ( $string )) { 169 | return array_map ( 'cleanXss', $string ); 170 | } 171 | 172 | // 移除不可见的字符 173 | $string = preg_replace ( '/%0[0-8bcef]/', '', $string ); 174 | $string = preg_replace ( '/%1[0-9a-f]/', '', $string ); 175 | $string = preg_replace ( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $string ); 176 | 177 | $string = preg_replace ( '//is', '', $string ); // 过滤 meta 标签 178 | $string = preg_replace ( '//is', '', $string ); // 过滤 link 标签 179 | $string = preg_replace ( '//is', '', $string ); // 过滤 script 标签 180 | 181 | if ($strict) { 182 | $string = preg_replace ( '//is', '', $string ); // 过滤 style 标签 183 | $string = preg_replace ( '//is', '', $string ); // 过滤 iframe 标签 1 184 | $string = preg_replace ( '//is', '', $string ); // 过滤 iframe 标签 2 185 | } 186 | 187 | $string = preg_replace_callback ( '/(\<\w+\s)(.+?)(?=( \/)?\>)/is', function ($m) { 188 | // 去除标签上的 on.. 开头的 JS 事件,以下一个 xxx= 属性或者尾部为终点 189 | $m [2] = preg_replace ( '/\son[a-z]+\s*\=.+?(\s\w+\s*\=|$)/is', '\1', $m [2] ); 190 | 191 | // 去除 A 标签中 href 属性为 javascript: 开头的内容 192 | if (strtolower ( $m [1] ) == '|>)/is', '\1\2', $string ); // 过滤标签尾部多余的空格 201 | 202 | return $string; 203 | } 204 | 205 | /** 206 | * 打印 207 | * 208 | * @param unknown $arr 209 | */ 210 | function dd($arr) { 211 | var_dump ( $arr ); 212 | } 213 | 214 | function find($model, $id) { 215 | return call_user_func ( "\model\\" . $model . "::find", $id ); 216 | } 217 | 218 | /** 219 | * 日志打印 220 | */ 221 | function dd_log($msg, $dir = "default") { 222 | if(ApeWeb::$udp_log_client!=null){ 223 | $arr ["dir"] = $dir; 224 | $arr ["msg"] = $msg; 225 | ApeWeb::$udp_log_client->send ( json_encode ( $arr ) ); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /_lib/ape/view/View.php: -------------------------------------------------------------------------------- 1 | templatedir . $tpl, 'r'); 47 | $text = fread($fp, filesize($this->templatedir . $tpl)); 48 | fclose($fp); 49 | // repalce template tag to PHP tag // 50 | $text = str_replace('{/if}', '', $text); 51 | $text = str_replace('{/loop}', '', $text); 52 | $text = str_replace('{foreachelse}', '', $text); 53 | $text = str_replace('{/foreach}', '', $text); 54 | $text = str_replace('{else}', '', $text); 55 | $text = str_replace('{loopelse}', '', $text); 56 | // template pattern tags // 57 | $pattern = array( 58 | '/\$(\w*[a-zA-Z0-9_])/', 59 | '/\$this\-\>vars\[\'(\w*[a-zA-Z0-9_])\'\]+\.(\w*[a-zA-Z0-9])/', 60 | '/\{include file=(\"|\'|)(\w*[a-zA-Z0-9_\.][a-zA-Z]\w*)(\"|\'|)\}/', 61 | '/\{\$this\-\>vars(\[\'(\w*[a-zA-Z0-9_])\'\])(\[\'(\w*[a-zA-Z0-9_])\'\])?\}/', 62 | '/\{if (.*?)\}/', 63 | '/\{elseif (.*?)\}/', 64 | '/\{loop \$(.*) as (\w*[a-zA-Z0-9_])\}/', 65 | '/\{foreach \$(.*) (\w*[a-zA-Z0-9_])\=\>(\w*[a-zA-Z0-9_])\}/' 66 | ); 67 | // replacement PHP tags // 68 | $replacement = array( 69 | '$this->vars[\'\1\']', 70 | '$this->vars[\'\1\'][\'\2\']', 71 | 'display(\'\2\')?>', 72 | 'vars\1\3?>', 73 | '', 74 | '', 75 | 'vars[\'\2\']) {?>', 76 | 'vars[\'\2\']=>$this->vars[\'\3\']) {?>' 77 | ); 78 | // repalce template tags to PHP tags // 79 | $text = preg_replace($pattern, $replacement, $text); 80 | 81 | // create compile file // 82 | $compliefile = time() . random(10) ."_".posix_getpid(). ".php"; 83 | if ($fp = @fopen($this->compiledir . $compliefile, 'w')) { 84 | fputs($fp, $text); 85 | fclose($fp); 86 | } 87 | // 删除旧的模板 88 | @unlink($this->compiledir . $this->tpl_storage [ApeWeb::$MODULE_NAME . "/" . $tpl]); 89 | $this->tpl_storage [ApeWeb::$MODULE_NAME . "/" . $tpl] = $compliefile; 90 | } 91 | 92 | /* 93 | * assigns values to template variables 94 | * @param array|string $k the template variable name(s) 95 | * @param mixed $v the value to assign 96 | */ 97 | public function assign($k, $v = null) 98 | { 99 | $this->vars [$k] = $v; 100 | } 101 | 102 | /* 103 | * ste directory where templates are located 104 | * @param string $str (path) 105 | */ 106 | public function templateDir($path) 107 | { 108 | $this->templatedir = $this->pathCheck($path); 109 | } 110 | 111 | /* 112 | * set where compiled templates are located 113 | * @param string $str (path) 114 | */ 115 | public function compileDir($path) 116 | { 117 | $this->compiledir = $this->pathCheck($path); 118 | } 119 | 120 | /* 121 | * check the path last character 122 | * @param string $str (path) 123 | * @return string 124 | */ 125 | public function pathCheck($str) 126 | { 127 | return (preg_match('/\/$/', $str)) ? $str : $str . '/'; 128 | } 129 | 130 | /* 131 | * executes & displays the template results 132 | * @param string $tpl (template file) 133 | */ 134 | public function display($tpl) 135 | { 136 | // 将.替换成/ 137 | $tpl = str_replace('.', '/', $tpl); 138 | $tpl = $tpl . ".html"; 139 | 140 | if (! file_exists($this->templatedir . $tpl)) { 141 | return ('can not load template file : ' . $this->templatedir . $tpl); 142 | } 143 | // 判断是否存在这个模板缓存 144 | if (array_key_exists(ApeWeb::$MODULE_NAME . "/" . $tpl, $this->tpl_storage)) { 145 | // 获取模板模板缓存位置 146 | $compliefile = $this->compiledir . $this->tpl_storage [ApeWeb::$MODULE_NAME . "/" . $tpl]; 147 | if (! file_exists($compliefile) || filemtime($this->templatedir . $tpl) > filemtime($compliefile)) { 148 | $this->parse($tpl); 149 | } 150 | } else { 151 | // 如果不存在这个模板缓存 152 | $this->parse($tpl); 153 | } 154 | $compliefile = $this->compiledir . $this->tpl_storage [ApeWeb::$MODULE_NAME . "/" . $tpl]; 155 | foreach ($this->vars as $k=>$n) { 156 | $$k = $n; 157 | } 158 | // 打开缓存区 159 | ob_start(); 160 | include $compliefile; 161 | $contents = ob_get_contents(); 162 | ob_end_clean(); 163 | 164 | return $contents; 165 | } 166 | 167 | /** 168 | * 渲染 169 | */ 170 | public function view($tpl, &$vars = array()) 171 | { 172 | $this->templateDir(RUN_DIR . ApeWeb::$MODULE_NAME . "/" . "views/"); 173 | $this->compileDir(RUN_DIR . ApeWeb::$MODULE_NAME . "/" . 'storage/views/'); 174 | 175 | $this->vars = $vars; 176 | $this->vars ["HOME"] = ApeWeb::$HOME; 177 | $this->vars ["MODULE_URL"] = ApeWeb::$MODULE_URL; 178 | 179 | $ret = $this->display($tpl); 180 | $this->vars = null; 181 | return $ret; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /_lib/GlobalData/Client.php: -------------------------------------------------------------------------------- 1 | _globalServers = array_values ( ( array ) $servers ); 56 | } 57 | 58 | /** 59 | * Connect to global server. 60 | * 61 | * @throws \Exception 62 | */ 63 | protected function getConnection($key) { 64 | $offset = crc32 ( $key ) % count ( $this->_globalServers ); 65 | if ($offset < 0) { 66 | $offset = - $offset; 67 | } 68 | 69 | if (! isset ( $this->_globalConnections [$offset] ) || feof ( $this->_globalConnections [$offset] )) { 70 | $connection = stream_socket_client ( "tcp://{$this->_globalServers[$offset]}", $code, $msg, $this->timeout ); 71 | if (! $connection) { 72 | throw new \Exception ( $msg ); 73 | } 74 | stream_set_timeout ( $connection, $this->timeout ); 75 | if (class_exists ( '\Workerman\Lib\Timer' ) && php_sapi_name () === 'cli') { 76 | $timer_id = \Workerman\Lib\Timer::add ( $this->pingInterval, function ($connection) use (&$timer_id) { 77 | $buffer = pack ( 'N', 8 ) . "ping"; 78 | if (strlen ( $buffer ) !== @fwrite ( $connection, $buffer )) { 79 | @fclose ( $connection ); 80 | \Workerman\Lib\Timer::del ( $timer_id ); 81 | } 82 | }, array ( 83 | $connection 84 | ) ); 85 | } 86 | $this->_globalConnections [$offset] = $connection; 87 | } 88 | return $this->_globalConnections [$offset]; 89 | } 90 | 91 | /** 92 | * Magic methods __set. 93 | * 94 | * @param string $key 95 | * @param mixed $value 96 | * @throws \Exception 97 | */ 98 | public function __set($key, $value) { 99 | $connection = $this->getConnection ( $key ); 100 | $this->writeToRemote ( array ( 101 | 'cmd' => 'set', 102 | 'key' => $key, 103 | 'value' => $value 104 | ), $connection ); 105 | $this->readFromRemote ( $connection ); 106 | } 107 | 108 | /** 109 | * Magic methods __isset. 110 | * 111 | * @param string $key 112 | */ 113 | public function __isset($key) { 114 | return null !== $this->__get ( $key ); 115 | } 116 | 117 | /** 118 | * Magic methods __unset. 119 | * 120 | * @param string $key 121 | * @throws \Exception 122 | */ 123 | public function __unset($key) { 124 | $connection = $this->getConnection ( $key ); 125 | $this->writeToRemote ( array ( 126 | 'cmd' => 'delete', 127 | 'key' => $key 128 | ), $connection ); 129 | $this->readFromRemote ( $connection ); 130 | } 131 | 132 | /** 133 | * Magic methods __get. 134 | * 135 | * @param string $key 136 | * @throws \Exception 137 | */ 138 | public function __get($key) { 139 | $connection = $this->getConnection ( $key ); 140 | $this->writeToRemote ( array ( 141 | 'cmd' => 'get', 142 | 'key' => $key 143 | ), $connection ); 144 | return $this->readFromRemote ( $connection ); 145 | } 146 | 147 | /** 148 | * Cas. 149 | * 150 | * @param string $key 151 | * @param mixed $value 152 | * @throws \Exception 153 | */ 154 | public function cas($key, $old_value, $new_value) { 155 | $connection = $this->getConnection ( $key ); 156 | $this->writeToRemote ( array ( 157 | 'cmd' => 'cas', 158 | 'md5' => md5 ( serialize ( $old_value ) ), 159 | 'key' => $key, 160 | 'value' => $new_value 161 | ), $connection ); 162 | return $this->readFromRemote ( $connection ); 163 | } 164 | 165 | /** 166 | * Add. 167 | * 168 | * @param string $key 169 | * @throws \Exception 170 | */ 171 | public function add($key, $value) { 172 | $connection = $this->getConnection ( $key ); 173 | $this->writeToRemote ( array ( 174 | 'cmd' => 'add', 175 | 'key' => $key, 176 | 'value' => $value 177 | ), $connection ); 178 | return $this->readFromRemote ( $connection ); 179 | } 180 | 181 | /** 182 | * Increment. 183 | * 184 | * @param string $key 185 | * @throws \Exception 186 | */ 187 | public function increment($key, $step = 1) { 188 | $connection = $this->getConnection ( $key ); 189 | $this->writeToRemote ( array ( 190 | 'cmd' => 'increment', 191 | 'key' => $key, 192 | 'step' => $step 193 | ), $connection ); 194 | return $this->readFromRemote ( $connection ); 195 | } 196 | 197 | /** 198 | * Write data to global server. 199 | * 200 | * @param string $buffer 201 | */ 202 | protected function writeToRemote($data, $connection) { 203 | $buffer = serialize ( $data ); 204 | $buffer = pack ( 'N', 4 + strlen ( $buffer ) ) . $buffer; 205 | $len = fwrite ( $connection, $buffer ); 206 | if ($len !== strlen ( $buffer )) { 207 | throw new \Exception ( 'writeToRemote fail' ); 208 | } 209 | } 210 | 211 | /** 212 | * Read data from global server. 213 | * 214 | * @throws Exception 215 | */ 216 | protected function readFromRemote($connection) { 217 | $all_buffer = ''; 218 | $total_len = 4; 219 | $head_read = false; 220 | while ( 1 ) { 221 | $buffer = fread ( $connection, 8192 ); 222 | if ($buffer === '' || $buffer === false) { 223 | throw new \Exception ( 'readFromRemote fail' ); 224 | } 225 | $all_buffer .= $buffer; 226 | $recv_len = strlen ( $all_buffer ); 227 | if ($recv_len >= $total_len) { 228 | if ($head_read) { 229 | break; 230 | } 231 | $unpack_data = unpack ( 'Ntotal_length', $all_buffer ); 232 | $total_len = $unpack_data ['total_length']; 233 | if ($recv_len >= $total_len) { 234 | break; 235 | } 236 | $head_read = true; 237 | } 238 | } 239 | return unserialize ( substr ( $all_buffer, 4 ) ); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/Libevent.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Libevent implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var resource 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All listeners for read/write event. 32 | * 33 | * @var array 34 | */ 35 | protected $_allEvents = array(); 36 | 37 | /** 38 | * Event listeners of signal. 39 | * 40 | * @var array 41 | */ 42 | protected $_eventSignal = array(); 43 | 44 | /** 45 | * All timer event listeners. 46 | * [func, args, event, flag, time_interval] 47 | * 48 | * @var array 49 | */ 50 | protected $_eventTimer = array(); 51 | 52 | /** 53 | * construct 54 | */ 55 | public function __construct() 56 | { 57 | $this->_eventBase = event_base_new(); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function add($fd, $flag, $func, $args = array()) 64 | { 65 | switch ($flag) { 66 | case self::EV_SIGNAL: 67 | $fd_key = (int)$fd; 68 | $real_flag = EV_SIGNAL | EV_PERSIST; 69 | $this->_eventSignal[$fd_key] = event_new(); 70 | if (!event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { 71 | return false; 72 | } 73 | if (!event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { 74 | return false; 75 | } 76 | if (!event_add($this->_eventSignal[$fd_key])) { 77 | return false; 78 | } 79 | return true; 80 | case self::EV_TIMER: 81 | case self::EV_TIMER_ONCE: 82 | $event = event_new(); 83 | $timer_id = (int)$event; 84 | if (!event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { 85 | return false; 86 | } 87 | 88 | if (!event_base_set($event, $this->_eventBase)) { 89 | return false; 90 | } 91 | 92 | $time_interval = $fd * 1000000; 93 | if (!event_add($event, $time_interval)) { 94 | return false; 95 | } 96 | $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); 97 | return $timer_id; 98 | 99 | default : 100 | $fd_key = (int)$fd; 101 | $real_flag = $flag === self::EV_READ ? EV_READ | EV_PERSIST : EV_WRITE | EV_PERSIST; 102 | 103 | $event = event_new(); 104 | 105 | if (!event_set($event, $fd, $real_flag, $func, null)) { 106 | return false; 107 | } 108 | 109 | if (!event_base_set($event, $this->_eventBase)) { 110 | return false; 111 | } 112 | 113 | if (!event_add($event)) { 114 | return false; 115 | } 116 | 117 | $this->_allEvents[$fd_key][$flag] = $event; 118 | 119 | return true; 120 | } 121 | 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function del($fd, $flag) 128 | { 129 | switch ($flag) { 130 | case self::EV_READ: 131 | case self::EV_WRITE: 132 | $fd_key = (int)$fd; 133 | if (isset($this->_allEvents[$fd_key][$flag])) { 134 | event_del($this->_allEvents[$fd_key][$flag]); 135 | unset($this->_allEvents[$fd_key][$flag]); 136 | } 137 | if (empty($this->_allEvents[$fd_key])) { 138 | unset($this->_allEvents[$fd_key]); 139 | } 140 | break; 141 | case self::EV_SIGNAL: 142 | $fd_key = (int)$fd; 143 | if (isset($this->_eventSignal[$fd_key])) { 144 | event_del($this->_eventSignal[$fd_key]); 145 | unset($this->_eventSignal[$fd_key]); 146 | } 147 | break; 148 | case self::EV_TIMER: 149 | case self::EV_TIMER_ONCE: 150 | // 这里 fd 为timerid 151 | if (isset($this->_eventTimer[$fd])) { 152 | event_del($this->_eventTimer[$fd][2]); 153 | unset($this->_eventTimer[$fd]); 154 | } 155 | break; 156 | } 157 | return true; 158 | } 159 | 160 | /** 161 | * Timer callback. 162 | * 163 | * @param mixed $_null1 164 | * @param int $_null2 165 | * @param mixed $timer_id 166 | */ 167 | protected function timerCallback($_null1, $_null2, $timer_id) 168 | { 169 | if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { 170 | event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); 171 | } 172 | try { 173 | call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); 174 | } catch (\Exception $e) { 175 | Worker::log($e); 176 | exit(250); 177 | } catch (\Error $e) { 178 | Worker::log($e); 179 | exit(250); 180 | } 181 | if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { 182 | $this->del($timer_id, self::EV_TIMER_ONCE); 183 | } 184 | } 185 | 186 | /** 187 | * {@inheritdoc} 188 | */ 189 | public function clearAllTimer() 190 | { 191 | foreach ($this->_eventTimer as $task_data) { 192 | event_del($task_data[2]); 193 | } 194 | $this->_eventTimer = array(); 195 | } 196 | 197 | /** 198 | * {@inheritdoc} 199 | */ 200 | public function loop() 201 | { 202 | event_base_loop($this->_eventBase); 203 | } 204 | } 205 | 206 | -------------------------------------------------------------------------------- /_lib/ape/StatisticClient.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | /** 15 | * 统计客户端 16 | * @author workerman.net 17 | */ 18 | class StatisticClient 19 | { 20 | /** 21 | * [module=>[interface=>time_start, interface=>time_start ...], module=>[interface=>time_start ..], ... ] 22 | * @var array 23 | */ 24 | protected static $timeMap = array(); 25 | 26 | /** 27 | * 模块接口上报消耗时间记时 28 | * @param string $module 29 | * @param string $interface 30 | * @return void 31 | */ 32 | public static function tick($module = '', $interface = '') 33 | { 34 | return self::$timeMap[$module][$interface] = microtime(true); 35 | } 36 | 37 | /** 38 | * 上报统计数据 39 | * @param string $module 40 | * @param string $interface 41 | * @param bool $success 42 | * @param int $code 43 | * @param string $msg 44 | * @param string $report_address 45 | * @return boolean 46 | */ 47 | public static function report($module, $interface, $success, $code, $msg, $report_address = '') 48 | { 49 | $report_address = $report_address ? $report_address : 'udp://127.0.0.1:55656'; 50 | if(isset(self::$timeMap[$module][$interface]) && self::$timeMap[$module][$interface] > 0) 51 | { 52 | $time_start = self::$timeMap[$module][$interface]; 53 | self::$timeMap[$module][$interface] = 0; 54 | } 55 | else if(isset(self::$timeMap['']['']) && self::$timeMap[''][''] > 0) 56 | { 57 | $time_start = self::$timeMap['']['']; 58 | self::$timeMap[''][''] = 0; 59 | } 60 | else 61 | { 62 | $time_start = microtime(true); 63 | } 64 | 65 | $cost_time = microtime(true) - $time_start; 66 | 67 | $bin_data = StatisticProtocol::encode($module, $interface, $cost_time, $success, $code, $msg); 68 | 69 | return self::sendData($report_address, $bin_data); 70 | } 71 | 72 | /** 73 | * 发送数据给统计系统 74 | * @param string $address 75 | * @param string $buffer 76 | * @return boolean 77 | */ 78 | public static function sendData($address, $buffer) 79 | { 80 | $socket = stream_socket_client($address); 81 | if(!$socket) 82 | { 83 | return false; 84 | } 85 | return stream_socket_sendto($socket, $buffer) == strlen($buffer); 86 | } 87 | 88 | } 89 | 90 | /** 91 | * 92 | * struct statisticPortocol 93 | * { 94 | * unsigned char module_name_len; 95 | * unsigned char interface_name_len; 96 | * float cost_time; 97 | * unsigned char success; 98 | * int code; 99 | * unsigned short msg_len; 100 | * unsigned int time; 101 | * char[module_name_len] module_name; 102 | * char[interface_name_len] interface_name; 103 | * char[msg_len] msg; 104 | * } 105 | * 106 | * @author workerman.net 107 | */ 108 | class StatisticProtocol 109 | { 110 | /** 111 | * 包头长度 112 | * @var integer 113 | */ 114 | const PACKAGE_FIXED_LENGTH = 17; 115 | 116 | /** 117 | * udp 包最大长度 118 | * @var integer 119 | */ 120 | const MAX_UDP_PACKGE_SIZE = 65507; 121 | 122 | /** 123 | * char类型能保存的最大数值 124 | * @var integer 125 | */ 126 | const MAX_CHAR_VALUE = 255; 127 | 128 | /** 129 | * usigned short 能保存的最大数值 130 | * @var integer 131 | */ 132 | const MAX_UNSIGNED_SHORT_VALUE = 65535; 133 | 134 | /** 135 | * 编码 136 | * @param string $module 137 | * @param string $interface 138 | * @param float $cost_time 139 | * @param int $success 140 | * @param int $code 141 | * @param string $msg 142 | * @return string 143 | */ 144 | public static function encode($module, $interface , $cost_time, $success, $code = 0,$msg = '') 145 | { 146 | // 防止模块名过长 147 | if(strlen($module) > self::MAX_CHAR_VALUE) 148 | { 149 | $module = substr($module, 0, self::MAX_CHAR_VALUE); 150 | } 151 | 152 | // 防止接口名过长 153 | if(strlen($interface) > self::MAX_CHAR_VALUE) 154 | { 155 | $interface = substr($interface, 0, self::MAX_CHAR_VALUE); 156 | } 157 | 158 | // 防止msg过长 159 | $module_name_length = strlen($module); 160 | $interface_name_length = strlen($interface); 161 | $avalible_size = self::MAX_UDP_PACKGE_SIZE - self::PACKAGE_FIXED_LENGTH - $module_name_length - $interface_name_length; 162 | if(strlen($msg) > $avalible_size) 163 | { 164 | $msg = substr($msg, 0, $avalible_size); 165 | } 166 | 167 | // 打包 168 | return pack('CCfCNnN', $module_name_length, $interface_name_length, $cost_time, $success ? 1 : 0, $code, strlen($msg), time()).$module.$interface.$msg; 169 | } 170 | 171 | /** 172 | * 解包 173 | * @param string $bin_data 174 | * @return array 175 | */ 176 | public static function decode($bin_data) 177 | { 178 | // 解包 179 | $data = unpack("Cmodule_name_len/Cinterface_name_len/fcost_time/Csuccess/Ncode/nmsg_len/Ntime", $bin_data); 180 | $module = substr($bin_data, self::PACKAGE_FIXED_LENGTH, $data['module_name_len']); 181 | $interface = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'], $data['interface_name_len']); 182 | $msg = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'] + $data['interface_name_len']); 183 | return array( 184 | 'module' => $module, 185 | 'interface' => $interface, 186 | 'cost_time' => $data['cost_time'], 187 | 'success' => $data['success'], 188 | 'time' => $data['time'], 189 | 'code' => $data['code'], 190 | 'msg' => $msg, 191 | ); 192 | } 193 | 194 | } 195 | 196 | if(PHP_SAPI == 'cli' && isset($argv[0]) && $argv[0] == basename(__FILE__)) 197 | { 198 | StatisticClient::tick("TestModule", 'TestInterface'); 199 | usleep(rand(10000, 600000)); 200 | $success = rand(0,1); 201 | $code = rand(300, 400); 202 | $msg = '这个是测试消息'; 203 | var_export(StatisticClient::report('TestModule', 'TestInterface', $success, $code, $msg));; 204 | } 205 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/Libevent.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Libevent implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var resource 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All listeners for read/write event. 32 | * 33 | * @var array 34 | */ 35 | protected $_allEvents = array(); 36 | 37 | /** 38 | * Event listeners of signal. 39 | * 40 | * @var array 41 | */ 42 | protected $_eventSignal = array(); 43 | 44 | /** 45 | * All timer event listeners. 46 | * [func, args, event, flag, time_interval] 47 | * 48 | * @var array 49 | */ 50 | protected $_eventTimer = array(); 51 | 52 | /** 53 | * construct 54 | */ 55 | public function __construct() 56 | { 57 | $this->_eventBase = event_base_new(); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function add($fd, $flag, $func, $args = array()) 64 | { 65 | switch ($flag) { 66 | case self::EV_SIGNAL: 67 | $fd_key = (int)$fd; 68 | $real_flag = EV_SIGNAL | EV_PERSIST; 69 | $this->_eventSignal[$fd_key] = event_new(); 70 | if (!event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { 71 | return false; 72 | } 73 | if (!event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { 74 | return false; 75 | } 76 | if (!event_add($this->_eventSignal[$fd_key])) { 77 | return false; 78 | } 79 | return true; 80 | case self::EV_TIMER: 81 | case self::EV_TIMER_ONCE: 82 | $event = event_new(); 83 | $timer_id = (int)$event; 84 | if (!event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { 85 | return false; 86 | } 87 | 88 | if (!event_base_set($event, $this->_eventBase)) { 89 | return false; 90 | } 91 | 92 | $time_interval = $fd * 1000000; 93 | if (!event_add($event, $time_interval)) { 94 | return false; 95 | } 96 | $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); 97 | return $timer_id; 98 | 99 | default : 100 | $fd_key = (int)$fd; 101 | $real_flag = $flag === self::EV_READ ? EV_READ | EV_PERSIST : EV_WRITE | EV_PERSIST; 102 | 103 | $event = event_new(); 104 | 105 | if (!event_set($event, $fd, $real_flag, $func, null)) { 106 | return false; 107 | } 108 | 109 | if (!event_base_set($event, $this->_eventBase)) { 110 | return false; 111 | } 112 | 113 | if (!event_add($event)) { 114 | return false; 115 | } 116 | 117 | $this->_allEvents[$fd_key][$flag] = $event; 118 | 119 | return true; 120 | } 121 | 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function del($fd, $flag) 128 | { 129 | switch ($flag) { 130 | case self::EV_READ: 131 | case self::EV_WRITE: 132 | $fd_key = (int)$fd; 133 | if (isset($this->_allEvents[$fd_key][$flag])) { 134 | event_del($this->_allEvents[$fd_key][$flag]); 135 | unset($this->_allEvents[$fd_key][$flag]); 136 | } 137 | if (empty($this->_allEvents[$fd_key])) { 138 | unset($this->_allEvents[$fd_key]); 139 | } 140 | break; 141 | case self::EV_SIGNAL: 142 | $fd_key = (int)$fd; 143 | if (isset($this->_eventSignal[$fd_key])) { 144 | event_del($this->_eventSignal[$fd_key]); 145 | unset($this->_eventSignal[$fd_key]); 146 | } 147 | break; 148 | case self::EV_TIMER: 149 | case self::EV_TIMER_ONCE: 150 | // 这里 fd 为timerid 151 | if (isset($this->_eventTimer[$fd])) { 152 | event_del($this->_eventTimer[$fd][2]); 153 | unset($this->_eventTimer[$fd]); 154 | } 155 | break; 156 | } 157 | return true; 158 | } 159 | 160 | /** 161 | * Timer callback. 162 | * 163 | * @param mixed $_null1 164 | * @param int $_null2 165 | * @param mixed $timer_id 166 | */ 167 | protected function timerCallback($_null1, $_null2, $timer_id) 168 | { 169 | if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { 170 | event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); 171 | } 172 | try { 173 | call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); 174 | } catch (\Exception $e) { 175 | Worker::log($e); 176 | exit(250); 177 | } catch (\Error $e) { 178 | Worker::log($e); 179 | exit(250); 180 | } 181 | if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { 182 | $this->del($timer_id, self::EV_TIMER_ONCE); 183 | } 184 | } 185 | 186 | /** 187 | * {@inheritdoc} 188 | */ 189 | public function clearAllTimer() 190 | { 191 | foreach ($this->_eventTimer as $task_data) { 192 | event_del($task_data[2]); 193 | } 194 | $this->_eventTimer = array(); 195 | } 196 | 197 | /** 198 | * {@inheritdoc} 199 | */ 200 | public function loop() 201 | { 202 | event_base_loop($this->_eventBase); 203 | } 204 | 205 | /** 206 | * Destroy loop. 207 | * 208 | * @return void 209 | */ 210 | public function destroy() 211 | { 212 | foreach ($this->_eventSignal as $event) { 213 | event_del($event); 214 | } 215 | } 216 | } 217 | 218 | -------------------------------------------------------------------------------- /_lib/ape/base/DBBase.php: -------------------------------------------------------------------------------- 1 | insert(static::$table)->cols($arr)->query(); 33 | } else { 34 | $arr ["id"] = $mysql->insert(static::$table)->cols($arr)->query(); 35 | } 36 | // 添加存入缓存 37 | 38 | if ($mysql ->cache != null) { 39 | $arr = self::find($arr ["id"]); 40 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $arr ["id"]; 41 | $mysql ->cache->$_key = $arr; 42 | } 43 | } 44 | 45 | /** 46 | * 修改 47 | * $id可以不传,默认采用$arr里面的id 48 | * 49 | * @param unknown $arr 50 | */ 51 | public static function update(&$arr = null, $id = null) 52 | { 53 | $db_name = static::$db_name; 54 | $mysql = ApeWeb::$mysqls[$db_name]; 55 | if ($arr == null) { 56 | return false; 57 | } 58 | 59 | if (! isset($arr ["id"])) { 60 | return false; 61 | } 62 | if ($id == null) { 63 | $id = $arr ["id"]; 64 | } 65 | $whereStr = "id='" . $id . "'"; 66 | 67 | // 判断缓存的数据和新数据是否一模一样,一样的话,不更新 68 | if ($mysql ->cache != null) { 69 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $id; 70 | var_export($mysql ->cache->$_key, true); 71 | if (isset($mysql ->cache->$_key) && $id == $arr ["id"] && $mysql ->cache->$_key === $arr) { 72 | return true; 73 | } 74 | } 75 | 76 | // 设置更新时间 77 | $tm = date("Y-m-d H:i:s", time()); 78 | $arr [self::$updated_at] = $tm; 79 | 80 | if (array_key_exists(self::$deleted_at, $arr)) { 81 | if ($arr [self::$deleted_at] == null) { 82 | unset($arr [self::$deleted_at]); 83 | } 84 | } 85 | 86 | if ($mysql->update(static::$table)->cols($arr)->where($whereStr)->query() == null) { 87 | return false; 88 | } else { 89 | if ($mysql ->cache != null) { 90 | // 缓存删除修改前的数据 91 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $id; 92 | unset($mysql ->cache->$_key); 93 | // 缓存存入新的数据 94 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $arr ["id"]; 95 | $mysql ->cache->$_key = $arr; 96 | } 97 | return true; 98 | } 99 | } 100 | 101 | /** 102 | * 批量删除 103 | */ 104 | public static function delete_all($str = "") 105 | { 106 | if ($str=="") { 107 | return; 108 | } 109 | $as = self::all($str); 110 | foreach ($as as $n) { 111 | self::delete($n["id"]); 112 | } 113 | } 114 | 115 | /** 116 | * 删除 传入id删除 117 | */ 118 | public static function delete($id = null) 119 | { 120 | $db_name = static::$db_name; 121 | $mysql = ApeWeb::$mysqls[$db_name]; 122 | 123 | if ($id == null) { 124 | return false; 125 | } 126 | 127 | // 在缓存中删除 128 | if ($mysql ->cache != null) { 129 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $id; 130 | unset($mysql ->cache->$_key); 131 | } 132 | 133 | // 是否使用软删除 134 | if (static::$softDelete) { 135 | $tm = date("Y-m-d H:i:s", time()); 136 | $model = self::find($id); 137 | $model [self::$deleted_at] = $tm; 138 | return self::update($model); 139 | } 140 | 141 | // 真删除 142 | $mysql->delete(static::$table)->where("id='$id'")->query(); 143 | } 144 | 145 | /** 146 | * 通过id查 147 | */ 148 | public static function find($id = null) 149 | { 150 | $db_name = static::$db_name; 151 | $mysql = ApeWeb::$mysqls[$db_name]; 152 | 153 | if ($id == null) { 154 | return null; 155 | } 156 | // 如果是$where是数字类型,那么判断缓存中是否有 157 | // 如果有缓存,直接返回缓存值 158 | if ($mysql ->cache != null) { 159 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $id; 160 | if (isset($mysql ->cache->$_key)) { 161 | var_export($mysql ->cache->$_key, true); 162 | return $mysql ->cache->$_key; 163 | } 164 | } 165 | 166 | $q = $mysql->select('*')->from(static::$table); 167 | if (static::$softDelete) { 168 | $q->where(self::$deleted_at . " is null"); 169 | } 170 | $res = $q->where('id= :id')->bindValues(array('id'=>$id))->row(); 171 | if ($res) { 172 | // 将数据存入缓存 173 | if ($mysql ->cache != null) { 174 | $_key = static::$db_name . "_" . "id_cache_" . static::$table . "_" . $id; 175 | $mysql ->cache->$_key = $res; 176 | } 177 | return $res; 178 | } else { 179 | return null; 180 | } 181 | } 182 | 183 | /** 184 | * 查询全部 185 | */ 186 | public static function all($where = "1=1", $order = "id desc") 187 | { 188 | $db_name = static::$db_name; 189 | $mysql = ApeWeb::$mysqls[$db_name]; 190 | $mysql->query("SELECT * FROM t_admin WHERE id=:id ",array('id' => "1")); 191 | if (static::$softDelete) { 192 | $where = "$where and " . self::$deleted_at . " is null"; 193 | } 194 | $arr = $mysql-> ("select * FROM `" . static::$table . "` where $where order by $order"); 195 | if ($arr == null) { 196 | return array(); 197 | } else { 198 | return $arr; 199 | } 200 | } 201 | 202 | /** 203 | * 查询全部 204 | */ 205 | public static function count($where = "1=1") 206 | { 207 | $db_name = static::$db_name; 208 | $mysql = ApeWeb::$mysqls[$db_name]; 209 | 210 | if (static::$softDelete) { 211 | $where = "$where and " . self::$deleted_at . " is null"; 212 | } 213 | return $mysql->column("select count(*) FROM `" . static::$table . "` where $where") [0]; 214 | } 215 | 216 | /** 217 | * 分页查询 218 | */ 219 | public static function page($index = 0, $length = 0, $where = " 1=1 ", $order = "id desc") 220 | { 221 | $db_name = static::$db_name; 222 | $mysql = ApeWeb::$mysqls[$db_name]; 223 | 224 | if (static::$softDelete) { 225 | $where = "$where and " . self::$deleted_at . " is null"; 226 | } 227 | 228 | $cs = $mysql->query("select * FROM `" . static::$table . "` where $where order by $order LIMIT $length OFFSET $index"); 229 | $arr ["list"] = $cs; 230 | $allCount = $mysql->column("select count(*) FROM `" . static::$table . "` where $where") [0]; 231 | $arr ["all_count"] = $allCount; 232 | if ($length != 0) { 233 | $yu = 0; 234 | if ($allCount > $length) { 235 | if ($allCount % $length > 0) { 236 | $yu = $allCount / $length + 1; 237 | } else { 238 | $yu = $allCount / $length; 239 | } 240 | } else { 241 | $yu = 1; 242 | } 243 | $arr ["all_page_num"] = ( int ) $yu; 244 | } else { 245 | $arr ["all_page_num"] = 1; 246 | } 247 | return $arr; 248 | } 249 | 250 | /** 251 | * 传入正常where串,这个方法会将串分割成预编译模式的sql 252 | */ 253 | protected static function getWhereKeyValue($sql){ 254 | 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /_lib/Workerman_linux/Events/Select.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | /** 17 | * select eventloop 18 | */ 19 | class Select implements EventInterface 20 | { 21 | /** 22 | * All listeners for read/write event. 23 | * 24 | * @var array 25 | */ 26 | public $_allEvents = array(); 27 | 28 | /** 29 | * Event listeners of signal. 30 | * 31 | * @var array 32 | */ 33 | public $_signalEvents = array(); 34 | 35 | /** 36 | * Fds waiting for read event. 37 | * 38 | * @var array 39 | */ 40 | protected $_readFds = array(); 41 | 42 | /** 43 | * Fds waiting for write event. 44 | * 45 | * @var array 46 | */ 47 | protected $_writeFds = array(); 48 | 49 | /** 50 | * Timer scheduler. 51 | * {['data':timer_id, 'priority':run_timestamp], ..} 52 | * 53 | * @var \SplPriorityQueue 54 | */ 55 | protected $_scheduler = null; 56 | 57 | /** 58 | * All timer event listeners. 59 | * [[func, args, flag, timer_interval], ..] 60 | * 61 | * @var array 62 | */ 63 | protected $_task = array(); 64 | 65 | /** 66 | * Timer id. 67 | * 68 | * @var int 69 | */ 70 | protected $_timerId = 1; 71 | 72 | /** 73 | * Select timeout. 74 | * 75 | * @var int 76 | */ 77 | protected $_selectTimeout = 100000000; 78 | 79 | /** 80 | * Paired socket channels 81 | * 82 | * @var array 83 | */ 84 | protected $channel = array(); 85 | 86 | /** 87 | * Construct. 88 | */ 89 | public function __construct() 90 | { 91 | // Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling. 92 | $this->channel = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); 93 | if ($this->channel) { 94 | stream_set_blocking($this->channel[0], 0); 95 | $this->_readFds[0] = $this->channel[0]; 96 | } 97 | // Init SplPriorityQueue. 98 | $this->_scheduler = new \SplPriorityQueue(); 99 | $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); 100 | } 101 | 102 | /** 103 | * {@inheritdoc} 104 | */ 105 | public function add($fd, $flag, $func, $args = array()) 106 | { 107 | switch ($flag) { 108 | case self::EV_READ: 109 | $fd_key = (int)$fd; 110 | $this->_allEvents[$fd_key][$flag] = array($func, $fd); 111 | $this->_readFds[$fd_key] = $fd; 112 | break; 113 | case self::EV_WRITE: 114 | $fd_key = (int)$fd; 115 | $this->_allEvents[$fd_key][$flag] = array($func, $fd); 116 | $this->_writeFds[$fd_key] = $fd; 117 | break; 118 | case self::EV_SIGNAL: 119 | $fd_key = (int)$fd; 120 | $this->_signalEvents[$fd_key][$flag] = array($func, $fd); 121 | pcntl_signal($fd, array($this, 'signalHandler')); 122 | break; 123 | case self::EV_TIMER: 124 | case self::EV_TIMER_ONCE: 125 | $run_time = microtime(true) + $fd; 126 | $this->_scheduler->insert($this->_timerId, -$run_time); 127 | $this->_task[$this->_timerId] = array($func, (array)$args, $flag, $fd); 128 | $this->tick(); 129 | return $this->_timerId++; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | /** 136 | * Signal handler. 137 | * 138 | * @param int $signal 139 | */ 140 | public function signalHandler($signal) 141 | { 142 | call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal)); 143 | } 144 | 145 | /** 146 | * {@inheritdoc} 147 | */ 148 | public function del($fd, $flag) 149 | { 150 | $fd_key = (int)$fd; 151 | switch ($flag) { 152 | case self::EV_READ: 153 | unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]); 154 | if (empty($this->_allEvents[$fd_key])) { 155 | unset($this->_allEvents[$fd_key]); 156 | } 157 | return true; 158 | case self::EV_WRITE: 159 | unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]); 160 | if (empty($this->_allEvents[$fd_key])) { 161 | unset($this->_allEvents[$fd_key]); 162 | } 163 | return true; 164 | case self::EV_SIGNAL: 165 | unset($this->_signalEvents[$fd_key]); 166 | pcntl_signal($fd, SIG_IGN); 167 | break; 168 | case self::EV_TIMER: 169 | case self::EV_TIMER_ONCE; 170 | unset($this->_task[$fd_key]); 171 | return true; 172 | } 173 | return false; 174 | } 175 | 176 | /** 177 | * Tick for timer. 178 | * 179 | * @return void 180 | */ 181 | protected function tick() 182 | { 183 | while (!$this->_scheduler->isEmpty()) { 184 | $scheduler_data = $this->_scheduler->top(); 185 | $timer_id = $scheduler_data['data']; 186 | $next_run_time = -$scheduler_data['priority']; 187 | $time_now = microtime(true); 188 | $this->_selectTimeout = ($next_run_time - $time_now) * 1000000; 189 | if ($this->_selectTimeout <= 0) { 190 | $this->_scheduler->extract(); 191 | 192 | if (!isset($this->_task[$timer_id])) { 193 | continue; 194 | } 195 | 196 | // [func, args, flag, timer_interval] 197 | $task_data = $this->_task[$timer_id]; 198 | if ($task_data[2] === self::EV_TIMER) { 199 | $next_run_time = $time_now + $task_data[3]; 200 | $this->_scheduler->insert($timer_id, -$next_run_time); 201 | } 202 | call_user_func_array($task_data[0], $task_data[1]); 203 | if (isset($this->_task[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { 204 | $this->del($timer_id, self::EV_TIMER_ONCE); 205 | } 206 | continue; 207 | } 208 | return; 209 | } 210 | $this->_selectTimeout = 100000000; 211 | } 212 | 213 | /** 214 | * {@inheritdoc} 215 | */ 216 | public function clearAllTimer() 217 | { 218 | $this->_scheduler = new \SplPriorityQueue(); 219 | $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); 220 | $this->_task = array(); 221 | } 222 | 223 | /** 224 | * {@inheritdoc} 225 | */ 226 | public function loop() 227 | { 228 | $e = null; 229 | while (1) { 230 | // Calls signal handlers for pending signals 231 | pcntl_signal_dispatch(); 232 | 233 | $read = $this->_readFds; 234 | $write = $this->_writeFds; 235 | // Waiting read/write/signal/timeout events. 236 | $ret = @stream_select($read, $write, $e, 0, $this->_selectTimeout); 237 | 238 | if (!$this->_scheduler->isEmpty()) { 239 | $this->tick(); 240 | } 241 | 242 | if (!$ret) { 243 | continue; 244 | } 245 | 246 | foreach ($read as $fd) { 247 | $fd_key = (int)$fd; 248 | if (isset($this->_allEvents[$fd_key][self::EV_READ])) { 249 | call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], 250 | array($this->_allEvents[$fd_key][self::EV_READ][1])); 251 | } 252 | } 253 | 254 | foreach ($write as $fd) { 255 | $fd_key = (int)$fd; 256 | if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { 257 | call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], 258 | array($this->_allEvents[$fd_key][self::EV_WRITE][1])); 259 | } 260 | } 261 | } 262 | } 263 | 264 | /** 265 | * Destroy loop. 266 | * 267 | * @return void 268 | */ 269 | public function destroy() 270 | { 271 | 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/React.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | use React\EventLoop\LoopInterface; 16 | use React\EventLoop\Timer\TimerInterface; 17 | 18 | /** 19 | * select eventloop 20 | */ 21 | class React implements LoopInterface 22 | { 23 | /** 24 | * @var React\EventLoop\LoopInterface 25 | */ 26 | protected $_loop = null; 27 | 28 | /** 29 | * @var array 30 | */ 31 | protected $_timerIdMap = array(); 32 | 33 | /** 34 | * @var int 35 | */ 36 | protected $_timerIdIndex = 0; 37 | 38 | /** 39 | * React constructor. 40 | */ 41 | public function __construct() { 42 | if (function_exists('event_base_new')) { 43 | $this->_loop = new \Workerman\Events\React\LibEventLoop(); 44 | } elseif (class_exists('EventBase', false)) { 45 | $this->_loop = new \Workerman\Events\React\ExtEventLoop(); 46 | } else { 47 | $this->_loop = new \Workerman\Events\React\StreamSelectLoop(); 48 | } 49 | } 50 | 51 | /** 52 | * Add event listener to event loop. 53 | * 54 | * @param $fd 55 | * @param $flag 56 | * @param $func 57 | * @param array $args 58 | * @return bool 59 | */ 60 | public function add($fd, $flag, $func, $args = array()) 61 | { 62 | $args = (array)$args; 63 | switch ($flag) { 64 | case EventInterface::EV_READ: 65 | return $this->_loop->addReadStream($fd, $func); 66 | case EventInterface::EV_WRITE: 67 | return $this->_loop->addWriteStream($fd, $func); 68 | case EventInterface::EV_SIGNAL: 69 | return $this->_loop->addSignal($fd, $func); 70 | case EventInterface::EV_TIMER: 71 | $timer_obj = $this->_loop->addPeriodicTimer($fd, function() use ($func, $args) { 72 | call_user_func_array($func, $args); 73 | }); 74 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 75 | return $this->_timerIdIndex; 76 | case EventInterface::EV_TIMER_ONCE: 77 | $timer_obj = $this->_loop->addTimer($fd, function() use ($func, $args) { 78 | call_user_func_array($func, $args); 79 | }); 80 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 81 | return $this->_timerIdIndex; 82 | } 83 | return false; 84 | } 85 | 86 | /** 87 | * Remove event listener from event loop. 88 | * 89 | * @param mixed $fd 90 | * @param int $flag 91 | * @return bool 92 | */ 93 | public function del($fd, $flag) 94 | { 95 | switch ($flag) { 96 | case EventInterface::EV_READ: 97 | return $this->_loop->removeReadStream($fd); 98 | case EventInterface::EV_WRITE: 99 | return $this->_loop->removeWriteStream($fd); 100 | case EventInterface::EV_SIGNAL: 101 | return $this->_loop->removeSignal($fd); 102 | case EventInterface::EV_TIMER: 103 | case EventInterface::EV_TIMER_ONCE; 104 | if (isset($this->_timerIdMap[$fd])){ 105 | $timer_obj = $this->_timerIdMap[$fd]; 106 | unset($this->_timerIdMap[$fd]); 107 | $this->_loop->cancelTimer($timer_obj); 108 | return true; 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | 115 | /** 116 | * Main loop. 117 | * 118 | * @return void 119 | */ 120 | public function loop() 121 | { 122 | $this->_loop->run(); 123 | } 124 | 125 | /** 126 | * Register a listener to be notified when a stream is ready to read. 127 | * 128 | * @param resource $stream The PHP stream resource to check. 129 | * @param callable $listener Invoked when the stream is ready. 130 | */ 131 | public function addReadStream($stream, callable $listener) { 132 | return call_user_func(array($this->_loop, 'addReadStream'), $stream, $listener); 133 | } 134 | 135 | /** 136 | * Register a listener to be notified when a stream is ready to write. 137 | * 138 | * @param resource $stream The PHP stream resource to check. 139 | * @param callable $listener Invoked when the stream is ready. 140 | */ 141 | public function addWriteStream($stream, callable $listener) { 142 | return call_user_func(array($this->_loop, 'addWriteStream'), $stream, $listener); 143 | } 144 | 145 | /** 146 | * Remove the read event listener for the given stream. 147 | * 148 | * @param resource $stream The PHP stream resource. 149 | */ 150 | public function removeReadStream($stream) { 151 | return call_user_func(array($this->_loop, 'removeReadStream'), $stream); 152 | } 153 | 154 | /** 155 | * Remove the write event listener for the given stream. 156 | * 157 | * @param resource $stream The PHP stream resource. 158 | */ 159 | public function removeWriteStream($stream) { 160 | return call_user_func(array($this->_loop, 'removeWriteStream'), $stream); 161 | } 162 | 163 | /** 164 | * Remove all listeners for the given stream. 165 | * 166 | * @param resource $stream The PHP stream resource. 167 | */ 168 | public function removeStream($stream) { 169 | return call_user_func(array($this->_loop, 'removeStream'), $stream); 170 | } 171 | 172 | /** 173 | * Enqueue a callback to be invoked once after the given interval. 174 | * 175 | * The execution order of timers scheduled to execute at the same time is 176 | * not guaranteed. 177 | * 178 | * @param int|float $interval The number of seconds to wait before execution. 179 | * @param callable $callback The callback to invoke. 180 | * 181 | * @return TimerInterface 182 | */ 183 | public function addTimer($interval, callable $callback) { 184 | return call_user_func(array($this->_loop, 'addTimer'), $interval, $callback); 185 | } 186 | 187 | /** 188 | * Enqueue a callback to be invoked repeatedly after the given interval. 189 | * 190 | * The execution order of timers scheduled to execute at the same time is 191 | * not guaranteed. 192 | * 193 | * @param int|float $interval The number of seconds to wait before execution. 194 | * @param callable $callback The callback to invoke. 195 | * 196 | * @return TimerInterface 197 | */ 198 | public function addPeriodicTimer($interval, callable $callback) { 199 | return call_user_func(array($this->_loop, 'addPeriodicTimer'), $interval, $callback); 200 | } 201 | 202 | /** 203 | * Cancel a pending timer. 204 | * 205 | * @param TimerInterface $timer The timer to cancel. 206 | */ 207 | public function cancelTimer(TimerInterface $timer) { 208 | return call_user_func(array($this->_loop, 'cancelTimer'), $timer); 209 | } 210 | 211 | /** 212 | * Check if a given timer is active. 213 | * 214 | * @param TimerInterface $timer The timer to check. 215 | * 216 | * @return boolean True if the timer is still enqueued for execution. 217 | */ 218 | public function isTimerActive(TimerInterface $timer) { 219 | return call_user_func(array($this->_loop, 'isTimerActive'), $timer); 220 | } 221 | 222 | /** 223 | * Schedule a callback to be invoked on the next tick of the event loop. 224 | * 225 | * Callbacks are guaranteed to be executed in the order they are enqueued, 226 | * before any timer or stream events. 227 | * 228 | * @param callable $listener The callback to invoke. 229 | */ 230 | public function nextTick(callable $listener) { 231 | return call_user_func(array($this->_loop, 'nextTick'), $listener); 232 | } 233 | 234 | /** 235 | * Schedule a callback to be invoked on a future tick of the event loop. 236 | * 237 | * Callbacks are guaranteed to be executed in the order they are enqueued. 238 | * 239 | * @param callable $listener The callback to invoke. 240 | */ 241 | public function futureTick(callable $listener) { 242 | return call_user_func(array($this->_loop, 'futureTick'), $listener); 243 | } 244 | 245 | /** 246 | * Perform a single iteration of the event loop. 247 | */ 248 | public function tick() { 249 | return call_user_func(array($this->_loop, 'tick')); 250 | } 251 | 252 | /** 253 | * Run the event loop until there are no more tasks to perform. 254 | */ 255 | public function run() { 256 | return call_user_func(array($this->_loop, 'run')); 257 | } 258 | 259 | /** 260 | * Instruct a running event loop to stop. 261 | */ 262 | public function stop() { 263 | return call_user_func(array($this->_loop, 'stop')); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /_lib/ape/ApeWeb.php: -------------------------------------------------------------------------------- 1 | _sendfile = new Sendfile(); 35 | $this->_sendfile->useETag = true; 36 | $this->_sendfile->cacheControl = true; 37 | $this->_sendfile->use304status = true; 38 | // 默认session为null 39 | $_SESSION = null; 40 | parent::__construct($socket_name, $context_option); 41 | } 42 | 43 | /** 44 | * 添加拦截器 45 | */ 46 | public function AddFilter($url, callable $callback) 47 | { 48 | if (is_callable($callback)) { 49 | if ($callback instanceof \Closure) { 50 | $callback = \Closure::bind($callback, $this, get_class()); 51 | } 52 | } else { 53 | throw new \Exception('can not HandleFunc'); 54 | } 55 | $this->map [] = array( 56 | $url, 57 | $callback 58 | ); 59 | } 60 | 61 | /** 62 | * 发送404 63 | * 64 | * @param unknown $connection 65 | */ 66 | private function send_404($connection) 67 | { 68 | if ($this->on404) { 69 | $callback = \Closure::bind($this->on404, $this, get_class()); 70 | call_user_func($callback); 71 | } else { 72 | Http::header("HTTP/1.1 404 Not Found"); 73 | $html = 'page not found'; 74 | $connection->send($html); 75 | } 76 | } 77 | 78 | /** 79 | * 每次发送请求完,自动关闭连接 80 | */ 81 | private function auto_close(&$conn, &$static = false) 82 | { 83 | /** 84 | * 如果不是访问静态 85 | * 如果启用session了,还没有关闭,在这里关闭 86 | */ 87 | if (! $static) { 88 | if (HttpCache::$instance->sessionStarted) { 89 | HttpCache::$instance->sessionStarted = false; 90 | Http::sessionWriteClose(); 91 | } 92 | //$conn->close (); 93 | if (strtolower($_SERVER ["SERVER_PROTOCOL"]) == "http/1.1") { 94 | if (isset($_SERVER ["HTTP_CONNECTION"])) { 95 | if (strtolower($_SERVER ["HTTP_CONNECTION"]) == "close") { 96 | $conn->close(); 97 | } 98 | } 99 | } else { 100 | if ($_SERVER ["HTTP_CONNECTION"] != "keep-alive") { 101 | $conn->close(); 102 | } 103 | } 104 | } 105 | // 在这里自定义一些统计 106 | $this->access_log [7] = time() - $this->access_log [7]; 107 | // 向UDP日志服务发送日志数据 108 | dd_log(implode(" - ", $this->access_log), "request"); 109 | } 110 | 111 | /** 112 | * 当有静态文件访问时 113 | */ 114 | public function onStaticFile($connection, $data) 115 | { 116 | $uri = $data ["server"] ["REQUEST_URI"]; 117 | $pos = stripos($uri, "?"); 118 | if ($pos != false) { 119 | $uri = substr($uri, 0, $pos); 120 | } 121 | 122 | $file = RUN_DIR . 'public/' . $uri; 123 | $path = realpath($file); 124 | // 如果没有这个文件 125 | if (! $path) { 126 | Http::header('HTTP/1.1 400 Bad Request'); 127 | $connection->send('

400 Bad Request

'); 128 | return; 129 | } 130 | // 只允许访问public文件夹下面 131 | if (strpos($path, RUN_DIR . 'public/') != 0) { 132 | Http::header('HTTP/1.1 400 Bad Request'); 133 | $connection->send('

400 Bad Request

'); 134 | return; 135 | } 136 | Sendfile::sendFile($connection, $path); 137 | } 138 | 139 | /** 140 | * 获取客户端消息 141 | */ 142 | public function onMessage($connection, $data) 143 | { 144 | ApeWeb::$HOME = "http://".$_SERVER['HTTP_HOST']."/"; 145 | // 初始化SEND_BODY 146 | ApeWeb::$SEND_BODY = ""; 147 | $this->access_log [0] = $_SERVER ["REMOTE_ADDR"]; 148 | $this->access_log [1] = T(time()); 149 | $this->access_log [2] = $_SERVER ['REQUEST_METHOD']; 150 | $this->access_log [3] = $_SERVER ['REQUEST_URI']; 151 | $this->access_log [4] = $_SERVER ['SERVER_PROTOCOL']; 152 | $this->access_log [5] = "NULL"; 153 | $this->access_log [6] = 200; 154 | $this->access_log [7] = time(); 155 | //这块的作用是,如果访问的是/,默认增加模块 156 | // if ($data ["server"] ["REQUEST_URI"]=="/") { 157 | // $data ["server"] ["REQUEST_URI"] = $data ["server"] ["REQUEST_URI"] . APE['config'] ["default_module"]; 158 | // $_SERVER ['REQUEST_URI'] = $_SERVER ['REQUEST_URI'] . APE['config'] ["default_module"]; 159 | // } 160 | // 网站根目录 161 | $url = $data ["server"] ["REQUEST_URI"]; 162 | $pos = stripos($url, "?"); 163 | if ($pos != false) { 164 | $url = substr($url, 0, $pos); 165 | } 166 | if ($url != "/") { 167 | $url = strtolower(trim($url, "/")); 168 | } 169 | $data ["server"] ["REQUEST_URL"] = $url; 170 | $this->conn = $connection; 171 | 172 | if ($url == "/") { 173 | $url_arr = array(); 174 | } else { 175 | $url_arr = explode("/", $url); 176 | } 177 | $success = false; 178 | $static = false; 179 | // 如果是访问静态文件 180 | if (count($url_arr) > 0 && strpos($url_arr [(count($url_arr) - 1)], '.') != false) { 181 | $this->onStaticFile($connection, $data); 182 | $success = true; 183 | $static = true; 184 | } else { 185 | // 如果是访问controller,通过路由匹配控制器和方法 186 | $r_call = Router::router($data, $this->map, $this->access_log, $module_name, $controller_path, $controller_name, $method_name); 187 | // 如果通过拦截器检查 188 | if ($r_call) { 189 | $c_u_f_path = $module_name . $controller_path . $controller_name. "Controller"; 190 | $c_u_f_path = str_replace(DS, '\\', $c_u_f_path); 191 | 192 | //将-符号改为_ , 因为PHP方法名字不支持- 193 | $c_u_f_path = str_replace("-", '_', $c_u_f_path); 194 | $method_name = str_replace("-", '_', $method_name); 195 | 196 | // 寻找controller,并且验证是否类中包含指定方法,找到就执行方法 197 | if (is_file(RUN_DIR.$module_name . $controller_path . $controller_name . "Controller.php") 198 | &&method_exists('\\'.$c_u_f_path, $method_name)) { 199 | $success = true; 200 | //将方法名字拼接上 201 | $c_u_f_path = $c_u_f_path . "::" . $method_name; 202 | $f_call = null; 203 | try { 204 | $f_call = call_user_func($c_u_f_path, $this, $data); 205 | } catch (\Exception $e) { 206 | var_dump($e->getMessage()); 207 | } 208 | 209 | // 直接发送他的返回值 210 | if ($f_call !== null || ApeWeb::$SEND_BODY != "") { 211 | if (is_bool($f_call)) { 212 | $f_call = ""; 213 | } 214 | if (ApeWeb::$SEND_BODY != "") { 215 | $f_call = ApeWeb::$SEND_BODY . $f_call; 216 | } 217 | $this->send($f_call); 218 | } 219 | } 220 | } else { 221 | // 拦截器检查没通过,不报404,拦截器自己处理 222 | $success = true; 223 | $this->send(ApeWeb::$SEND_BODY); 224 | } 225 | } 226 | 227 | if (! $success) { 228 | // 没找到路由,直接404错误 229 | $this->send_404($connection); 230 | } 231 | // 每次发送完消息,自动关闭连接 232 | $this->auto_close($connection, $static); 233 | 234 | // 已经处理请求数 235 | static $request_count = 0; 236 | // 如果请求数达到max_request 237 | if (++ $request_count >= APE['config']["max_request"] && APE['config']["max_request"] > 0) { 238 | Worker::stopAll(); 239 | } 240 | } 241 | 242 | /** 243 | * 发送文本 244 | * 245 | * @param unknown $data 246 | */ 247 | public function send($data) 248 | { 249 | $this->conn->send($data); 250 | } 251 | 252 | /** 253 | * worker进程启动 254 | */ 255 | public function run() 256 | { 257 | // 设置当前worker是否开启监听端口复用(socket的SO_REUSEPORT选项),默认为false,不开启。 258 | $this->reusePort = false; 259 | $this->onWorkerStart = $this->onStart; 260 | 261 | // 一个已实例化的 object 的方法被作为 array 传递, 262 | // 下标 0 包含该 object,下标 1 包含方法名。 在同一个类里可以访问 protected 和 private 方法。 263 | $this->onMessage = array( 264 | $this, 265 | 'onMessage' 266 | ); 267 | parent::run(); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /_lib/Workerman_win/Events/Select.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | class Select implements EventInterface 17 | { 18 | /** 19 | * 所有的事件 20 | * @var array 21 | */ 22 | public $_allEvents = array(); 23 | 24 | /** 25 | * 所有信号事件 26 | * @var array 27 | */ 28 | public $_signalEvents = array(); 29 | 30 | /** 31 | * 监听这些描述符的读事件 32 | * @var array 33 | */ 34 | protected $_readFds = array(); 35 | 36 | /** 37 | * 监听这些描述符的写事件 38 | * @var array 39 | */ 40 | protected $_writeFds = array(); 41 | 42 | /** 43 | * 监听这些描述符的带外事件 44 | * @var array 45 | */ 46 | protected $_exceptFds = array(); 47 | 48 | /** 49 | * 任务调度器,最大堆 50 | * {['data':timer_id, 'priority':run_timestamp], ..} 51 | * @var SplPriorityQueue 52 | */ 53 | protected $_scheduler = null; 54 | 55 | /** 56 | * 定时任务 57 | * [[func, args, flag, timer_interval], ..] 58 | * @var array 59 | */ 60 | protected $_task = array(); 61 | 62 | /** 63 | * 定时器id 64 | * @var int 65 | */ 66 | protected $_timerId = 1; 67 | 68 | /** 69 | * select超时时间,单位:微秒 70 | * @var int 71 | */ 72 | protected $_selectTimeout = 100000000; 73 | 74 | /** 75 | * 构造函数 76 | * @return void 77 | */ 78 | public function __construct() 79 | { 80 | // 创建一个管道,放入监听读的描述符集合中,避免空轮询 81 | $this->channel = stream_socket_pair(STREAM_PF_INET, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); 82 | if($this->channel) 83 | { 84 | stream_set_blocking($this->channel[0], 0); 85 | $this->_readFds[0] = $this->channel[0]; 86 | } 87 | // 初始化优先队列(最大堆) 88 | $this->_scheduler = new \SplPriorityQueue(); 89 | $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); 90 | } 91 | 92 | /** 93 | * 添加事件及处理函数 94 | * @see Events\EventInterface::add() 95 | */ 96 | public function add($fd, $flag, $func, $args = array()) 97 | { 98 | switch ($flag) 99 | { 100 | case self::EV_READ: 101 | $fd_key = (int)$fd; 102 | $this->_allEvents[$fd_key][$flag] = array($func, $fd); 103 | $this->_readFds[$fd_key] = $fd; 104 | break; 105 | case self::EV_WRITE: 106 | $fd_key = (int)$fd; 107 | $this->_allEvents[$fd_key][$flag] = array($func, $fd); 108 | $this->_writeFds[$fd_key] = $fd; 109 | break; 110 | case self::EV_EXCEPT: 111 | $fd_key = (int)$fd; 112 | $this->_allEvents[$fd_key][$flag] = array($func, $fd); 113 | $this->_exceptFds[$fd_key] = $fd; 114 | break; 115 | case self::EV_SIGNAL: 116 | throw new \Exception("not support EV_SIGNAL on Windows"); 117 | break; 118 | case self::EV_TIMER: 119 | case self::EV_TIMER_ONCE: 120 | // $fd 为 定时的时间间隔,单位为秒,支持小数,能精确到0.001秒 121 | $run_time = microtime(true)+$fd; 122 | $this->_scheduler->insert($this->_timerId, -$run_time); 123 | $this->_task[$this->_timerId] = array($func, (array)$args, $flag, $fd); 124 | $this->tick(); 125 | return $this->_timerId++; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | /** 132 | * 信号处理函数 133 | * @param int $signal 134 | */ 135 | public function signalHandler($signal) 136 | { 137 | call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal)); 138 | } 139 | 140 | /** 141 | * 删除某个描述符的某类事件的监听 142 | * @see Events\EventInterface::del() 143 | */ 144 | public function del($fd ,$flag) 145 | { 146 | $fd_key = (int)$fd; 147 | switch ($flag) 148 | { 149 | case self::EV_READ: 150 | unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]); 151 | if(empty($this->_allEvents[$fd_key])) 152 | { 153 | unset($this->_allEvents[$fd_key]); 154 | } 155 | return true; 156 | case self::EV_WRITE: 157 | unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]); 158 | if(empty($this->_allEvents[$fd_key])) 159 | { 160 | unset($this->_allEvents[$fd_key]); 161 | } 162 | return true; 163 | case self::EV_EXCEPT: 164 | unset($this->_allEvents[$fd_key][$flag], $this->_exceptFds[$fd_key]); 165 | if(empty($this->_allEvents[$fd_key])) 166 | { 167 | unset($this->_allEvents[$fd_key]); 168 | } 169 | return true; 170 | case self::EV_SIGNAL: 171 | break; 172 | case self::EV_TIMER: 173 | case self::EV_TIMER_ONCE; 174 | // $fd_key为要删除的定时器id,即timerId 175 | unset($this->_task[$fd_key]); 176 | return true; 177 | } 178 | return false;; 179 | } 180 | 181 | /** 182 | * 检查是否有可执行的定时任务,有的话执行 183 | * @return void 184 | */ 185 | protected function tick() 186 | { 187 | while(!$this->_scheduler->isEmpty()) 188 | { 189 | $scheduler_data = $this->_scheduler->top(); 190 | $timer_id = $scheduler_data['data']; 191 | $next_run_time = -$scheduler_data['priority']; 192 | $time_now = microtime(true); 193 | $this->_selectTimeout = ($next_run_time - $time_now) * 1000000; 194 | if ($this->_selectTimeout <= 0) { 195 | $this->_scheduler->extract(); 196 | if (!isset($this->_task[$timer_id])) { 197 | continue; 198 | } 199 | // [func, args, flag, timer_interval] 200 | $task_data = $this->_task[$timer_id]; 201 | if ($task_data[2] === self::EV_TIMER) { 202 | $next_run_time = $time_now + $task_data[3]; 203 | $this->_scheduler->insert($timer_id, -$next_run_time); 204 | } 205 | call_user_func_array($task_data[0], $task_data[1]); 206 | if (isset($this->_task[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) { 207 | $this->del($timer_id, self::EV_TIMER_ONCE); 208 | } 209 | continue; 210 | } 211 | return; 212 | } 213 | $this->_selectTimeout = 100000000; 214 | } 215 | 216 | /** 217 | * 删除所有定时器 218 | * @return void 219 | */ 220 | public function clearAllTimer() 221 | { 222 | $this->_scheduler = new \SplPriorityQueue(); 223 | $this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); 224 | $this->_task = array(); 225 | } 226 | 227 | /** 228 | * 主循环 229 | * @see Events\EventInterface::loop() 230 | */ 231 | public function loop() 232 | { 233 | $e = null; 234 | while (1) 235 | { 236 | $read = $this->_readFds; 237 | $write = $this->_writeFds; 238 | $except = $this->_writeFds; 239 | 240 | // 等待可读或者可写事件 241 | stream_select($read, $write, $except, 0, (int)($this->_selectTimeout.'')); 242 | 243 | // 尝试执行定时任务 244 | if(!$this->_scheduler->isEmpty()) 245 | { 246 | $this->tick(); 247 | } 248 | 249 | // 这些描述符可读,执行对应描述符的读回调函数 250 | if($read) 251 | { 252 | foreach($read as $fd) 253 | { 254 | $fd_key = (int) $fd; 255 | if(isset($this->_allEvents[$fd_key][self::EV_READ])) 256 | { 257 | call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], array($this->_allEvents[$fd_key][self::EV_READ][1])); 258 | } 259 | } 260 | } 261 | 262 | // 这些描述符可写,执行对应描述符的写回调函数 263 | if($write) 264 | { 265 | foreach($write as $fd) 266 | { 267 | $fd_key = (int) $fd; 268 | if(isset($this->_allEvents[$fd_key][self::EV_WRITE])) 269 | { 270 | call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], array($this->_allEvents[$fd_key][self::EV_WRITE][1])); 271 | } 272 | } 273 | } 274 | 275 | // 这些描述符可写,执行对应描述符的写回调函数 276 | if($except) 277 | { 278 | foreach($except as $fd) 279 | { 280 | $fd_key = (int) $fd; 281 | if(isset($this->_allEvents[$fd_key][self::EV_EXCEPT])) 282 | { 283 | call_user_func_array($this->_allEvents[$fd_key][self::EV_EXCEPT][0], array($this->_allEvents[$fd_key][self::EV_EXCEPT][1])); 284 | } 285 | } 286 | } 287 | } 288 | } 289 | } 290 | --------------------------------------------------------------------------------