├── CREDITS ├── zphp_jg.jpg ├── .gitignore ├── ZPHP ├── Server │ ├── IServer.php │ ├── Adapter │ │ ├── Cli.php │ │ ├── Http.php │ │ ├── Rpc.php │ │ ├── Socket.php │ │ ├── Hprose.php │ │ └── Ant.php │ └── Factory.php ├── Protocol │ ├── IProtocol.php │ ├── Factory.php │ └── Adapter │ │ ├── Rpc.php │ │ ├── Cli.php │ │ ├── Json.php │ │ ├── Rest.php │ │ ├── Http.php │ │ ├── Zpack.php │ │ ├── Ant.php │ │ └── Zrpack.php ├── Socket │ ├── Route.php │ ├── IServer.php │ ├── Callback │ │ ├── SwooleUdp.php │ │ ├── SwooleWebSocket.php │ │ ├── Hprose.php │ │ ├── Mimes.php │ │ ├── SwooleHttp.php │ │ ├── HttpServer.php │ │ └── Swoole.php │ ├── Route │ │ ├── ZPHP.php │ │ ├── RPC.php │ │ ├── FCGI.php │ │ └── ZRpack.php │ ├── ICallback.php │ ├── Factory.php │ ├── Adapter │ │ ├── Hprose.php │ │ └── React.php │ └── Client.php ├── Controller │ └── IController.php ├── Serialize │ ├── Adapter │ │ ├── Php.php │ │ ├── Msgpack.php │ │ └── Igbinary.php │ └── Factory.php ├── View │ ├── IView.php │ ├── Base.php │ ├── Adapter │ │ ├── Amf.php │ │ ├── Str.php │ │ ├── String.php │ │ ├── Zpack.php │ │ ├── Zrpack.php │ │ ├── Json.php │ │ ├── Php.php │ │ ├── Xml.php │ │ └── Ant.php │ └── Factory.php ├── Queue │ ├── IQueue.php │ ├── Adapter │ │ ├── Beanstalk.php │ │ ├── Php.php │ │ └── Redis.php │ └── Factory.php ├── Cache │ ├── ICache.php │ ├── Factory.php │ └── Adapter │ │ ├── Apc.php │ │ ├── XCache.php │ │ ├── Redis.php │ │ ├── Yac.php │ │ ├── Php.php │ │ ├── Task.php │ │ └── Memcached.php ├── Common │ ├── Lang.php │ ├── Utils.php │ ├── Log.php │ ├── Dir.php │ ├── MessagePacker.php │ ├── Formater.php │ └── Debug.php ├── Manager │ ├── Beanstalk.php │ ├── Memcached.php │ ├── Redis.php │ └── Task.php ├── Rank │ ├── Factory.php │ ├── IRank.php │ └── Adapter │ │ └── Redis.php ├── Storage │ ├── Factory.php │ ├── IStorage.php │ └── Adapter │ │ ├── Redis.php │ │ └── TT.php ├── Log │ ├── Factory.php │ ├── Level.php │ ├── Adapter │ │ ├── WebSocket.php │ │ └── File.php │ └── Base.php ├── Conn │ ├── Factory.php │ ├── IConn.php │ └── Adapter │ │ ├── Swoole.php │ │ ├── Redis.php │ │ ├── Yac.php │ │ └── Task.php ├── Client │ ├── Async │ │ ├── Tcp.php │ │ └── Http.php │ ├── Sync │ │ ├── Tcp.php │ │ └── Http.php │ └── Rpc │ │ ├── Http.php │ │ └── Udp.php ├── Core │ ├── Factory.php │ ├── Route.php │ └── Config.php ├── Session │ ├── Adapter │ │ ├── Redis.php │ │ └── File.php │ ├── Factory.php │ └── Swoole.php └── Db │ └── Mongo.php ├── doc ├── 1.5.md ├── 1.1.md ├── 1.10.md ├── 1.9.md ├── index.md ├── 1.2.md ├── 1.4.md ├── 1.7.md ├── 1.6.md ├── 1.3.md └── 1.8.md ├── composer.json └── README.md /CREDITS: -------------------------------------------------------------------------------- 1 | shenzhe(shenzhe163@gmail.com) -------------------------------------------------------------------------------- /zphp_jg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenzhe/zphp/HEAD/zphp_jg.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | 4 | vendor 5 | demo_composer/vendor 6 | demo_composer/composer.lock -------------------------------------------------------------------------------- /ZPHP/Server/IServer.php: -------------------------------------------------------------------------------- 1 | [目录]() 4 | > 上一节: [特性](<1.4.md>) 5 | > 下一节: [开发流程](<1.6.md>) 6 | 7 | ![点击查看zphp流程图](https://raw.github.com/shenzhe/zphp/master/zphp_jg.jpg "zphp流程图") 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /doc/1.1.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | > [目录]() 4 | > 上一节: 5 | > 下一节: [基础](<1.2.md>) 6 | 7 | ZPHP是一个极轻的的,定位于后置SOA服务的框架,他和传统的MVC框架的明显区别在于,只有简单的路由功能,且专注于性能,并能提供高性能socket服务。 8 | 9 | ZPHP框架把业务逻辑和网络层完全隔离, 业务逻辑可以自适应 Cli, Fpm, Rpc, Socket等各种环境,网络层也可以自由扩展。 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/1.10.md: -------------------------------------------------------------------------------- 1 | # 聊天室开发 2 | 3 | > [目录]() 4 | > 上一节: [第三方库使用](<1.9.md>) 5 | > 下一节: [web开发](<1.11.md>) 6 | 7 | 聊天室开发 8 | ======== 9 | 10 | 本节将展示用zphp如何进行一个完整的简易聊天室开发。 11 | 12 | demo地址: http://zchat.45117.com 13 | 14 | 15 | 统一入口 16 | ========= 17 | -------------------------------------------------------------------------------- /doc/1.9.md: -------------------------------------------------------------------------------- 1 | # 第三方库使用 2 | 3 | > [目录]() 4 | > 上一节: [配置文件](<1.8.md>) 5 | > 下一节: [聊天室开发](<1.10.md>) 6 | 7 | 8 | 第三方库使用 9 | ======== 10 | 11 | 12 | ZPHP完全兼容 composer, composer已基本成为php界的一个标准库 13 | 14 | 地址:https://getcomposer.org/ https://packagist.org/ 15 | 16 | 里面有很多优秀成熟的库可以使用,避免重复造轮子 -------------------------------------------------------------------------------- /ZPHP/Protocol/IProtocol.php: -------------------------------------------------------------------------------- 1 | end('hello zphp'); 12 | } 13 | 14 | abstract public function onMessage($server, $frame); 15 | } 16 | -------------------------------------------------------------------------------- /ZPHP/Serialize/Adapter/Php.php: -------------------------------------------------------------------------------- 1 | 上一节:无 4 | > 下一节: [基础](<1.2.md>) 5 | 6 | 1. [入门] 7 | 1. [简介](1.1.md) 8 | 2. [环境](1.2.md) 9 | 3. [目录结构](1.3.md) 10 | 4. [特性](1.4.md) 11 | 5. [系统流程](1.5.md) 12 | 6. [开发流程](1.6.md) 13 | 14 | 2. [扩展] 15 | 1. [server扩展](2.1.md) 16 | 2. [protocal扩展](2.1.md) 17 | 3. [view扩展](2.3.md) 18 | 19 | 3. [第三方库] 20 | 1. [如何使用](3.1.md) -------------------------------------------------------------------------------- /ZPHP/Socket/Callback/Hprose.php: -------------------------------------------------------------------------------- 1 | serv = $serv; 15 | } 16 | 17 | public function onReceive() 18 | { 19 | 20 | } 21 | 22 | abstract public function onRegister(); 23 | } 24 | -------------------------------------------------------------------------------- /ZPHP/View/IView.php: -------------------------------------------------------------------------------- 1 | [目录]() 4 | > 上一节: [简介](<1.1.md>) 5 | > 下一节: [目录结构](<1.3.md>) 6 | 7 | 相关环境: 8 | 系统:linux 9 | php: >= 5.3.7 10 | 11 | 依赖扩展: 12 | swoole: https://github.com/swoole/swoole-src (提供高性能高并发支持) 13 | 14 | 15 | 推荐扩展: 16 | phpredis https://github.com/shenzhe/phpredis (php读取redis扩展) 17 | 18 | yac: https://github.com/laruence/yac (提供高性能共享内存) 19 | 20 | 推荐服务: 21 | redis: https://github.com/shenzhe/redis-storage (高性能可持久化的内存数据库) 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZPHP/Common/Lang.php: -------------------------------------------------------------------------------- 1 | setFd($fd); 21 | $server->parse($data); 22 | return Core\Route::route($server); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ZPHP/Socket/Route/RPC.php: -------------------------------------------------------------------------------- 1 | _rpc === null) { 21 | $this->_rpc = new \Yar_Client(ZConfig::getField('socket', 'rpc_host')); 22 | } 23 | return $this->_rpc->api($data); 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /doc/1.4.md: -------------------------------------------------------------------------------- 1 | # 特性 2 | 3 | > [目录]() 4 | > 上一节: [目录结构](<1.3.md>) 5 | > 下一节: [系统流程](<1.5.md>) 6 | 7 | 1) 性能强悍 (大部分api可以在10ms内处理完) 8 | 2) socket, http, rpc 完美融合,自由切换 9 | 3) 通信协议自由扩展 10 | 4) 可配置的自由的view层 11 | 5) 丰富的kv持久存储支持 (ttserver, redis, redis-storage) 12 | 6) 丰富的cache (apc, memcached, redis, xcache, yac) 13 | 7) 队列支持 (beanstalk, redis) 14 | 8) 实时排行榜支持 (redis) 15 | 9) 多进程支持 (pcntl, 类ph-fpm的进程管理 (处理一定的请求之后自动kill,然后master会fork一个新进程)) 16 | 10) 多线程支持 17 | 11) composer 安装 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ZPHP/Server/Adapter/Cli.php: -------------------------------------------------------------------------------- 1 | [目录]() 4 | > 上一节: [开发流程](<1.6.md>) 5 | > 下一节: [配置文件](<1.8.md>) 6 | 7 | 统一入口 8 | ======== 9 | 10 | 每个项目的每个app都可以配置一个统一入口文件,他的代码相对比较固定: 11 | 12 | 13 | 'jpg', 4 | 'image/bmp' => 'bmp', 5 | 'image/x-icon' => 'ico', 6 | 'image/gif' => 'gif', 7 | 'image/png' => 'png', 8 | 'application/octet-stream' => 'bin', 9 | 'application/javascript' => 'js', 10 | 'text/css' => 'css', 11 | 'text/html' => 'html', 12 | 'text/xml' => 'xml', 13 | 'application/x-tar' => 'tar', 14 | 'application/vnd.ms-powerpoint' => 'ppt', 15 | 'application/pdf' => 'pdf', 16 | 'application/x-shockwave-flash' => 'swf', 17 | 'application/x-zip-compressed' => 'zip', 18 | ); -------------------------------------------------------------------------------- /ZPHP/Server/Adapter/Rpc.php: -------------------------------------------------------------------------------- 1 | handle(); 20 | } 21 | 22 | public function api($params) 23 | { 24 | Protocol\Request::setServer(Protocol\Factory::getInstance('Rpc')); 25 | Protocol\Request::parse($params); 26 | return Core\Route::route(); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Route/FCGI.php: -------------------------------------------------------------------------------- 1 | _client === null) { 22 | $this->_client = new Client(ZConfig::getField('socket', 'fcgi_host', '127.0.0.1'), ZConfig::getField('socket', 'fcgi_port', 9000)); 23 | } 24 | return $this->_client->request($data); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ZPHP/Socket/ICallback.php: -------------------------------------------------------------------------------- 1 | addServer($server['host'], $server['port']); 21 | } 22 | self::$instances[$name] = $beanstalk; 23 | } 24 | return self::$instances[$name]; 25 | } 26 | } -------------------------------------------------------------------------------- /ZPHP/Rank/Factory.php: -------------------------------------------------------------------------------- 1 | model = $model; 17 | } 18 | 19 | public function getModel() 20 | { 21 | return $this->model; 22 | } 23 | 24 | //数据输出 25 | abstract public function display(); 26 | 27 | public function render() 28 | { 29 | \ob_start(); 30 | $this->display(); 31 | $content = \ob_get_contents(); 32 | \ob_end_clean(); 33 | return $content; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /ZPHP/View/Adapter/Amf.php: -------------------------------------------------------------------------------- 1 | model); 24 | if (Request::isLongServer()) { 25 | return $data; 26 | } 27 | echo $data; 28 | return null; 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Route/ZRpack.php: -------------------------------------------------------------------------------- 1 | setFd($fd); 21 | $result = array(); 22 | if (false === $server->parse($data)) { 23 | return $result; 24 | } 25 | $result[] = Core\Route::route($server); 26 | while ($server->parse("")) { 27 | $result[] = Core\Route::route($server); 28 | } 29 | return $result; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zphp/zphp", 3 | "type": "framework", 4 | "description": "ZPHP is a light that is dedicated to gaming, social networking, web, mobile server-side frameworks. Providing high performance real-time communication solutions.", 5 | "keywords": ["framework", "server", "socket", "multi", "progress" ,"thread"], 6 | "homepage": "https://github.com/shenzhe/zphp", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "shenzhe", 11 | "email": "shenzhe163@gmail.com" 12 | }, 13 | { 14 | "name": "cooper", 15 | "email": "myxiaoao@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.3.7" 20 | }, 21 | "autoload": { 22 | "psr-0": { "ZPHP\\": "" } 23 | } 24 | } -------------------------------------------------------------------------------- /ZPHP/Log/Factory.php: -------------------------------------------------------------------------------- 1 | 1, 14 | 'Cli' => 1, 15 | 'Hprose' => 1, 16 | 'Http' => 1, 17 | 'Rpc' => 1, 18 | 'Socket' => 1, 19 | ]; 20 | 21 | public static function getInstance($adapter = 'Http') 22 | { 23 | $adapter = ucfirst(strtolower($adapter)); 24 | if (isset(self::$_map[$adapter])) { 25 | $className = __NAMESPACE__ . "\\Adapter\\{$adapter}"; 26 | } else { 27 | $className = $adapter; 28 | } 29 | return CFactory::getInstance($className); 30 | } 31 | } -------------------------------------------------------------------------------- /ZPHP/Queue/Adapter/Beanstalk.php: -------------------------------------------------------------------------------- 1 | beanstalk)) { 18 | $this->beanstalk = Manager\Beanstalk::getInstance($config); 19 | } 20 | } 21 | 22 | public function add($key, $data) 23 | { 24 | return $this->beanstalk->put($key, $data); 25 | } 26 | 27 | public function get($key) 28 | { 29 | $job = $this->beanstalk->reserve($key); 30 | $this->beanstalk->delete($job['id'], $key); 31 | return $job; 32 | } 33 | } -------------------------------------------------------------------------------- /ZPHP/Serialize/Factory.php: -------------------------------------------------------------------------------- 1 | serialize($data); 23 | } 24 | 25 | public static function unserialize($adapter = 'Php', $data) 26 | { 27 | $class = self::getInstance($adapter); 28 | return $class->unserialize($data); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ZPHP/Log/Level.php: -------------------------------------------------------------------------------- 1 | 1, 25 | self::ALERT => 2, 26 | self::CRITICAL => 4, 27 | self::ERROR => 8, 28 | self::WARNING => 16, 29 | self::NOTICE => 32, 30 | self::INFO => 64, 31 | self::DEBUG => 128, 32 | ); 33 | 34 | const ALL = 0xff; 35 | } -------------------------------------------------------------------------------- /ZPHP/Protocol/Factory.php: -------------------------------------------------------------------------------- 1 | 1, 14 | 'Cli' => 1, 15 | 'Http' => 1, 16 | 'Json' => 1, 17 | 'Rpc' => 1, 18 | 'Zpack' => 1, 19 | 'Zrpack' => 1, 20 | ]; 21 | 22 | public static function getInstance($adapter = 'Http') 23 | { 24 | $adapter = ucfirst(strtolower($adapter)); 25 | if (isset(self::$_map[$adapter])) { 26 | $className = __NAMESPACE__ . "\\Adapter\\{$adapter}"; 27 | } else { 28 | $className = $adapter; 29 | } 30 | return CFactory::getInstance($className); 31 | } 32 | } -------------------------------------------------------------------------------- /ZPHP/Cache/Factory.php: -------------------------------------------------------------------------------- 1 | key !== $key) { 19 | $this->key = $key; 20 | $this->queue = msg_get_queue($this->key); 21 | } 22 | } 23 | 24 | public function add($key, $data) 25 | { 26 | $this->setKey($key); 27 | return msg_send($this->queue, 1, $data); 28 | } 29 | 30 | public function get($key) 31 | { 32 | $this->setKey($key); 33 | msg_receive($this->queue, 0, $messageType, 1024, $data, true, MSG_IPC_NOWAIT); 34 | return $data; 35 | } 36 | } -------------------------------------------------------------------------------- /ZPHP/Queue/Factory.php: -------------------------------------------------------------------------------- 1 | model) || \is_object($this->model)) { 25 | $data = json_encode($this->model); 26 | } else { 27 | $data = $this->model; 28 | } 29 | if (Request::isLongServer()) { 30 | return $data; 31 | } 32 | 33 | echo $data; 34 | return null; 35 | } 36 | } -------------------------------------------------------------------------------- /ZPHP/Manager/Memcached.php: -------------------------------------------------------------------------------- 1 | addServer($server['host'], $server['port']); 26 | } 27 | self::$instances[$name] = $memcached; 28 | } 29 | return self::$instances[$name]; 30 | } 31 | } -------------------------------------------------------------------------------- /ZPHP/View/Adapter/String.php: -------------------------------------------------------------------------------- 1 | model) || \is_object($this->model)) { 25 | $data = json_encode($this->model); 26 | } else { 27 | $data = $this->model; 28 | } 29 | if (Request::isLongServer()) { 30 | return $data; 31 | } 32 | 33 | echo $data; 34 | return null; 35 | } 36 | } -------------------------------------------------------------------------------- /ZPHP/View/Adapter/Zpack.php: -------------------------------------------------------------------------------- 1 | writeString(json_encode($this->model)); 22 | 23 | if (Request::isHttp()) { 24 | Response::sendHttpHeader(); 25 | Response::header("Content-Type", "application/zpack; charset=utf-8"); 26 | } 27 | 28 | if (Request::isLongServer()) { 29 | return array($this->model, $pack->getData()); 30 | } 31 | echo $pack->getData(); 32 | return null; 33 | 34 | 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /ZPHP/Socket/Callback/SwooleHttp.php: -------------------------------------------------------------------------------- 1 | onRequest($request, $response); 28 | Protocol\Request::setRequest(null); 29 | Protocol\Response::setResponse(null); 30 | } 31 | 32 | abstract public function onRequest($request, $response); 33 | } 34 | -------------------------------------------------------------------------------- /ZPHP/Queue/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 18 | $this->redis = Manager\Redis::getInstance($config); 19 | } 20 | } 21 | 22 | public function add($key, $data) 23 | { 24 | return $this->redis->rPush($key, $data); 25 | } 26 | 27 | public function get($key) 28 | { 29 | return $this->redis->lPop($key); 30 | } 31 | 32 | /** 33 | * 批量取出并清空所有的数据 34 | * 需最新redis-storage支持 35 | * @param $key 36 | * @return mixed 37 | */ 38 | public function getAll($key) 39 | { 40 | return $this->redis->lAll($key); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /ZPHP/Storage/IStorage.php: -------------------------------------------------------------------------------- 1 | 1, 15 | 'Ant' => 1, 16 | 'Json' => 1, 17 | 'Php' => 1, 18 | 'Str' => 1, 19 | 'String' => 1, 20 | 'Xml' => 1, 21 | 'Zpack' => 1, 22 | 'Zrpack' => 1, 23 | ]; 24 | 25 | public static function getInstance($adapter = 'Json') 26 | { 27 | $adapter = ucfirst(strtolower($adapter)); 28 | if ('String' == $adapter) { 29 | $adapter = 'Str'; 30 | } 31 | if (isset(self::$_map[$adapter])) { 32 | $className = __NAMESPACE__ . "\\Adapter\\{$adapter}"; 33 | } else { 34 | $className = $adapter; 35 | } 36 | return CFactory::getInstance($className); 37 | } 38 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Factory.php: -------------------------------------------------------------------------------- 1 | 1, 16 | 'Php' => 1, 17 | 'React' => 1, 18 | 'Swoole' => 1, 19 | ]; 20 | 21 | public static function getInstance($adapter = 'Swoole', $config = null) 22 | { 23 | if (empty($config)) { 24 | $config = ZConfig::get('socket'); 25 | if (!empty($config['adapter'])) { 26 | $adapter = $config['adapter']; 27 | } 28 | } 29 | $adapter = ucfirst(strtolower($adapter)); 30 | if (isset(self::$_map[$adapter])) { 31 | $className = __NAMESPACE__ . "\\Adapter\\{$adapter}"; 32 | } else { 33 | $className = $adapter; 34 | } 35 | return CFactory::getInstance($className, $config); 36 | } 37 | } -------------------------------------------------------------------------------- /ZPHP/Client/Async/Tcp.php: -------------------------------------------------------------------------------- 1 | connect($ip, $port); 41 | return $client; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /doc/1.6.md: -------------------------------------------------------------------------------- 1 | # 开发流程 2 | 3 | > [目录]() 4 | > 上一节: [系统流程](<1.5.md>) 5 | > 下一节: [统一入口](<1.7.md>) 6 | 7 | 推荐的项目结构 8 | ======== 9 | 10 | 11 | project // 自定义的项目名 12 | |- apps // (apps名可通过config的app_path配置, 一个项目可以有多个apps) 13 | |- ctrl // controller目录(目录名可通过config的ctrl_path配置), 一个请求经过zphp的route分发之后,会定位执行到此目录下的相应类的相应的方法 14 | |- service // service目录 (非必需, 名称可自定义 可以把一些业务逻辑提取出来放到此) 15 | |- dao // dao目录 (非必需, 名称可自定义 主要可以做数据处理相关的逻辑) 16 | |- socket // socket回调目录 (非必需, 可通过config配置 , socket回调业务处理可以放在此目录) 17 | |- webroot 18 | |- index.php //统一入口文件 19 | |- config 20 | |- default //配置目录, 不同的项目可以指定不同的配置 21 | |- config.php //配置文件 22 | |- public // (公用配置,可选,可把多个项目共用的配置放到此) 23 | |- pdo.php 24 | |- cache.php 25 | |- ..... -------------------------------------------------------------------------------- /ZPHP/Core/Factory.php: -------------------------------------------------------------------------------- 1 | setClient($client); 29 | } 30 | Request::setServer(ZProtocol::getInstance(Config::getField('socket', 'protocol'))); 31 | Request::setLongServer(); 32 | Request::setHttpServer(0); 33 | $socket->run(); 34 | } 35 | } -------------------------------------------------------------------------------- /ZPHP/Server/Adapter/Hprose.php: -------------------------------------------------------------------------------- 1 | setClient($client); 31 | } 32 | Request::setServer(ZProtocol::getInstance(Config::getField('socket', 'protocol'))); 33 | Request::setHttpServer(1); 34 | $socket->run(); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Rpc.php: -------------------------------------------------------------------------------- 1 | model); 21 | $data = gzencode($jsonData); 22 | $pack = new MessagePacker(); 23 | $len = strlen($data); 24 | $pack->writeInt($len + 16); 25 | $pack->writeInt($this->model['cmd']); 26 | $pack->writeInt($this->model['rid']); 27 | $pack->writeString($data, $len); 28 | if (Request::isHttp()) { 29 | Response::sendHttpHeader(); 30 | Response::header("Content-Type", "application/zrpack; charset=utf-8"); 31 | } 32 | if (Request::isLongServer()) { 33 | return array( 34 | $jsonData, $pack->getData() 35 | ); 36 | } 37 | echo $pack->getData(); 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ZPHP/Conn/IConn.php: -------------------------------------------------------------------------------- 1 | model, JSON_UNESCAPED_UNICODE); 21 | if (Request::isHttp()) { 22 | Response::sendHttpHeader(); 23 | $params = Request::getParams(); 24 | $key = Config::getField('project', 'jsonp', 'jsoncallback'); 25 | if (isset($params[$key])) { 26 | Response::header("Content-Type", 'application/x-javascript; charset=utf-8'); 27 | $data = $params[$key] . '(' . $data . ')'; 28 | } else { 29 | Response::header("Content-Type", "application/json; charset=utf-8"); 30 | } 31 | } 32 | if (Request::isLongServer()) { 33 | return $data; 34 | } 35 | echo $data; 36 | return null; 37 | 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Cli.php: -------------------------------------------------------------------------------- 1 | tplFile = $tpl; 24 | } 25 | 26 | public function display() 27 | { 28 | Response::sendHttpHeader(); 29 | $tplPath = ZPHP\Core\Config::getField('project', 'tpl_path', ZPHP\ZPHP::getRootPath() . DS . 'template' . DS . 'default' . DS); 30 | $fileName = $tplPath . $this->tplFile; 31 | if (!\is_file($fileName)) { 32 | throw new \Exception("no file {$fileName}"); 33 | } 34 | if (!empty($this->model) && is_array($this->model)) { 35 | \extract($this->model); 36 | } 37 | if (Request::isLongServer()) { 38 | \ob_start(); 39 | include "{$fileName}"; 40 | $content = ob_get_contents(); 41 | \ob_end_clean(); 42 | return $content; 43 | } 44 | include "{$fileName}"; 45 | return null; 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/XCache.php: -------------------------------------------------------------------------------- 1 | [目录]() 4 | > 上一节: [环境](<1.2.md>) 5 | > 下一节: [特性](<1.4.md>) 6 | 7 | ZPHP 8 | 9 | |- Cache (cache模块,目前支持:共享内存:apcu, Yac, XCache, 网络内存: Memcached, Redis) 10 | |- Common (公用模块,包括:调试(Debug.php), 目录读取(Dir.php), 数据格式化(Formater.php) 日志(Log.php) 二进制数据压缩(MessagePack.php)) 11 | |- Conn (Fd存取模块,目前支持:Yac, Redis) 12 | |- Controller (定义了controller接口) 13 | |- Core (核心模块) 14 | |- Config.php (配置读取) 15 | |- Factory.php (工厂模块) 16 | |- Route.php (路由读取) 17 | |- Db (数据库模块:目前支持:Pdo) 18 | |- Manager (管理模块,对一些公共服务进行统一注册和管理) 19 | |- Protocal (协议处理, 目前支持:Cli,Http,Json,Rpc,Zpack等协议,可随时扩展) 20 | |- Queue (队列模块,目前支持:Redis,Beanstalkd) 21 | |- Rank (排行榜模块,目前支持:Redis) 22 | |- Serialize (序列化模块,目前支持:Php, Igbinary, Msgpack) 23 | |- Session (Session模块,目前支持:Redis) 24 | |- Server (服务模式,目前支持:Cli, Http, Rpc, Socket) 25 | |- Cli (命令行模式) 26 | |- Http (Fpm模式) 27 | |- Rpc (rpc模式,需要https://github.com/laruence/yar支持) 28 | |- Socket (Socket模式, 支持:Swoole, React(https://github.com/reactphp/react), Php原生(libevent需要库)) 29 | |- Storage (Nosql持久存储,目前支持:Redis, TTserver, Redis-Storage) 30 | |- View (数据展示, 目前支持:Amf, Json, Php(文件模板), String, Xml,可随时扩展) 31 | |- ZPHP.php (ZPHP主文件,定义了autoloader, route, rootpath等框架所必需的数据和方法) 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ZPHP/View/Adapter/Xml.php: -------------------------------------------------------------------------------- 1 | '; 20 | $xml .= "\n\n"; 21 | $xml .= $this->dataToXml($this->model); 22 | $xml .= "\n"; 23 | return $xml; 24 | } 25 | 26 | private function dataToXml($data) 27 | { 28 | $xml = ""; 29 | foreach ($data as $key => $val) { 30 | \is_numeric(\substr($key, 0, 1)) && $key = "item id=\"$key\""; 31 | $xml .= "<{$key}>"; 32 | $xml .= (\is_array($val) || \is_object($val)) ? $this->dataToXml($val) : $val; 33 | list($key) = \explode(' ', $key); 34 | $xml .= "\n"; 35 | } 36 | 37 | return $xml; 38 | } 39 | 40 | public function display() 41 | { 42 | if (Request::isHttp()) { 43 | Response::sendHttpHeader(); 44 | Response::header("Content-Type", "text/xml; charset=utf-8"); 45 | } 46 | $data = $this->xmlEncode(); 47 | 48 | if (Request::isLongServer()) { 49 | return $data; 50 | } 51 | 52 | echo $data; 53 | return null; 54 | 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Rest.php: -------------------------------------------------------------------------------- 1 | _config = $config; 29 | } 30 | } 31 | 32 | /** 33 | * @param $level 34 | * @param $message 35 | * @param array $context 36 | * @return bool 37 | * @throws \Exception 38 | * @desc {type} | {timeStamp} |{dateTime} | {$message} 39 | */ 40 | public function log($level, $message, array $context = array()) 41 | { 42 | $logLevel = ZConfig::getField('project', 'log_level', Level::ALL); 43 | if (Level::$levels[$level] & $logLevel) { 44 | $str = $level . self::SEPARATOR . $message . self::SEPARATOR . \implode(self::SEPARATOR, array_map('\ZPHP\Common\Log::myJson', $context)); 45 | if (!$this->_client) { 46 | $this->_client = new WebSocketClient($this->_config['host'], $this->_config['port']); 47 | $this->_client->connect(); 48 | } 49 | $this->_client->send($str); 50 | } 51 | return false; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /ZPHP/Log/Adapter/File.php: -------------------------------------------------------------------------------- 1 | _config = $config; 27 | } 28 | } 29 | 30 | /** 31 | * @param $level 32 | * @param $message 33 | * @param array $context 34 | * @return bool 35 | * @throws \Exception 36 | * @desc {type} | {timeStamp} |{dateTime} | {$message} 37 | */ 38 | public function log($level, $message, array $context = array()) 39 | { 40 | $logLevel = ZConfig::getField('project', 'log_level', Level::ALL); 41 | if (Level::$levels[$level] & $logLevel) { 42 | $str = $level . self::SEPARATOR . $message . self::SEPARATOR . \implode(self::SEPARATOR, array_map('\ZPHP\Common\Log::myJson', $context)); 43 | if ($this->_config['type_file']) { 44 | $logFile = $this->_config['dir'] . \DS . $level . '.' . $this->_config['suffix']; 45 | } else { 46 | $logFile = $this->_config['dir'] . \DS . ZConfig::getField('project', 'project_name', 'log') . '.' . $this->_config['suffix']; 47 | } 48 | \file_put_contents($logFile, $str . "\n", FILE_APPEND | LOCK_EX); 49 | } 50 | return false; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /ZPHP/View/Adapter/Ant.php: -------------------------------------------------------------------------------- 1 | model, JSON_UNESCAPED_UNICODE); 23 | Response::sendHttpHeader(); 24 | $params = Request::getParams(); 25 | $key = Config::getField('project', 'jsonp', 'jsoncallback'); 26 | if (isset($params[$key])) { 27 | Response::header("Content-Type", 'application/x-javascript; charset=utf-8'); 28 | $data = $params[$key] . '(' . $data . ')'; 29 | } else { 30 | Response::header("Content-Type", "application/json; charset=utf-8"); 31 | } 32 | 33 | if (Request::isLongServer()) { 34 | return $data; 35 | } 36 | 37 | echo $data; 38 | return null; 39 | } 40 | 41 | //长驻服务,数据直接返回 42 | if (Request::isLongServer()) { 43 | if (class_exists('swoole_serialize')) { 44 | return \swoole_serialize::pack([Response::getHeaders(), $this->model]); 45 | } 46 | return \json_encode([Response::getHeaders(), $this->model], JSON_UNESCAPED_UNICODE); 47 | } 48 | 49 | //正常的php服务,直接echo 50 | echo \json_encode($this->model, JSON_UNESCAPED_UNICODE); 51 | return null; 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Http.php: -------------------------------------------------------------------------------- 1 | = 5.4 61 | 62 | ## 协议 63 | 64 | MIT license 65 | -------------------------------------------------------------------------------- /ZPHP/Client/Sync/Tcp.php: -------------------------------------------------------------------------------- 1 | connect($ip, $port); 41 | $config = [ 42 | 'open_length_check' => true, 43 | 'package_length_type' => 'N', 44 | 'package_length_offset' => 0, //第N个字节是包长度的值 45 | 'package_body_offset' => 4, //第几个字节开始计算长度 46 | 'package_max_length' => 2000000, //协议最大长度 47 | 'ctrl_name' => 'a', 48 | 'method_name' => 'm', 49 | ]; 50 | $socketConfig = Config::get('socket'); 51 | if (!empty($socketConfig)) { 52 | foreach ($config as $key => &$val) { 53 | if (isset($socketConfig[$key])) { 54 | $val = $socketConfig[$key]; 55 | } 56 | } 57 | } 58 | unset($val); 59 | $client->set($config); 60 | return $client; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /ZPHP/Server/Adapter/Ant.php: -------------------------------------------------------------------------------- 1 | setClient($client); 45 | } 46 | Request::setServer(ZProtocol::getInstance(Config::getField('socket', 'protocol', 'Ant'))); 47 | Request::setLongServer(); 48 | Request::setHttpServer(0); 49 | $socket->run(); 50 | } 51 | } -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 20 | $this->redis = Manager\Redis::getInstance($config); 21 | } 22 | } 23 | 24 | public function enable() 25 | { 26 | return true; 27 | } 28 | 29 | public function selectDb($db) 30 | { 31 | $this->redis->select($db); 32 | } 33 | 34 | public function add($key, $value, $expiration = 0) 35 | { 36 | return $this->redis->setNex($key, $expiration, $value); 37 | } 38 | 39 | public function set($key, $value, $expiration = 0) 40 | { 41 | if ($expiration) { 42 | return $this->redis->setex($key, $expiration, $value); 43 | } else { 44 | return $this->redis->set($key, $value); 45 | } 46 | } 47 | 48 | public function addToCache($key, $value, $expiration = 0) 49 | { 50 | return $this->set($key, $value, $expiration); 51 | } 52 | 53 | public function get($key) 54 | { 55 | return $this->redis->get($key); 56 | } 57 | 58 | public function getCache($key) 59 | { 60 | return $this->get($key); 61 | } 62 | 63 | public function delete($key) 64 | { 65 | return $this->redis->delete($key); 66 | } 67 | 68 | public function increment($key, $offset = 1) 69 | { 70 | return $this->redis->incrBy($key, $offset); 71 | } 72 | 73 | public function decrement($key, $offset = 1) 74 | { 75 | return $this->redis->decBy($key, $offset); 76 | } 77 | 78 | public function clear() 79 | { 80 | return $this->redis->flushDB(); 81 | } 82 | } -------------------------------------------------------------------------------- /ZPHP/Core/Route.php: -------------------------------------------------------------------------------- 1 | _before()) { 29 | $method = Request::getMethod(); 30 | if (!method_exists($class, $method)) { 31 | throw new \Exception("method error"); 32 | } 33 | $view = $class->$method(); 34 | } else { 35 | throw new \Exception($action . ':' . Request::getMethod() . ' _before() no return true'); 36 | } 37 | $class->_after(); 38 | if (Request::isLongServer()) { 39 | SSESSION::save(); 40 | } 41 | return Response::display($view); 42 | } 43 | } catch (\Exception $e) { 44 | if (Request::isLongServer()) { 45 | $result = \call_user_func(Config::getField('project', 'exception_handler', 'ZPHP\ZPHP::exceptionHandler'), $e); 46 | if ($class instanceof IController) { 47 | $class->_after(); 48 | } 49 | return $result; 50 | } 51 | if ($class instanceof IController) { 52 | $class->_after(); 53 | } 54 | throw $e; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ZPHP/Session/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 21 | $this->redis = Manager\Redis::getInstance($config); 22 | if (!empty($config['cache_expire'])) { 23 | $this->gcTime = $config['cache_expire'] * 60; 24 | } 25 | $this->config = $config; 26 | } 27 | } 28 | 29 | public function open($path, $sid) 30 | { 31 | return !empty($this->redis); 32 | } 33 | 34 | public function close() 35 | { 36 | return true; 37 | } 38 | 39 | public function gc($time) 40 | { 41 | return true; 42 | } 43 | 44 | public function read($sid) 45 | { 46 | if (!empty($this->config['sid_prefix'])) { 47 | $sid = str_replace($this->config['sid_prefix'], '', $sid); 48 | } 49 | $data = $this->redis->get($sid); 50 | if (!empty($data)) { 51 | $this->redis->setTimeout($sid, $this->gcTime); 52 | } 53 | return $data; 54 | } 55 | 56 | public function write($sid, $data) 57 | { 58 | if (empty($data)) { 59 | return true; 60 | } 61 | if (!empty($this->config['sid_prefix'])) { 62 | $sid = str_replace($this->config['sid_prefix'], '', $sid); 63 | } 64 | return $this->redis->setex($sid, $this->gcTime, $data); 65 | } 66 | 67 | public function destroy($sid) 68 | { 69 | if (!empty($this->config['sid_prefix'])) { 70 | $sid = str_replace($this->config['sid_prefix'], '', $sid); 71 | } 72 | return $this->redis->delete($sid); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /doc/1.8.md: -------------------------------------------------------------------------------- 1 | # 配置文件 2 | 3 | > [目录]() 4 | > 上一节: [统一入口](<1.7.md>) 5 | > 下一节: [第三方库使用](<1.9.md>) 6 | 7 | 配置文件 8 | ======== 9 | 10 | 配置文件是zphp的核心之一,zphp的server自适应,view自适应就是靠配置文件来完成的 11 | zphp的配置是标准的php数组形式。直观且高效。 12 | 13 | 必备配置 14 | ===== 15 | 16 | 17 | 'Http', //服务运行模式, http/socket/cli/socket等等 20 | 'app_path'=>'apps', //app目录 21 | 'ctrl_path'=>'ctrl', //controller目录 22 | 'project'=> array( //project业务配置 23 | 24 | ) 25 | ); 26 | 27 | 28 | 可选配置 29 | ======= 30 | 31 | 32 | '', //log目录, 默认为: 为project目录/log 35 | 'now_time'=>'', //现在时间,默认为time() 36 | 'time_zone'=> '', //时区,默认Asia/Shanghai 37 | 'lib_path'=> '', //第三方库目录,为全路径,默认为 ZPHP所以同级目录的lib目录(如ZPHP框架目录在/home, 则lib_path为/home/lib) 38 | project = array( 39 | 'ctrl_name'=> '', //ctrl参数key 默认为a (如参数里 a=chat, 则zphp会自动定位到到 app_path/ctrl_path下的chat.php文件), 40 | 'method_name'=> '', //method参数key 默认为m (如参数为 a=chat&m=send,则会执行 app_path/ctrl_path下的chat.php类中的send方法) 41 | 'debug_mode'=> 0 or 1, //调试模式是否开启,默认为0 42 | 'tpl_path'=>'', //模版目录,默认为: 为project目录/template/template 43 | ), 44 | ); 45 | 46 | 47 | 配置读取 48 | ======= 49 | 50 | ZPHP\Core\Config.php 提供两个方法进行配置读取 51 | 52 | Config::get($key, 'deufalt value'); 53 | 示例: 54 | Config::get('app_path', 'app1'); //返回 'apps',如果没有定义app_path,则返回默认值 :app1 55 | 56 | //当一个配置项是数组的时候,可以使用下面方法: 57 | Config::getField($key, $field, 'deufalt value'); 58 | 示例: 59 | Config::get('project', 'debug_mode', 1); //返回 0,如果没有定义debug_mode,则返回默认值 :1 60 | 61 | -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/Yac.php: -------------------------------------------------------------------------------- 1 | enable() && empty($this->yac)) { 19 | $this->yac = new \Yac(); 20 | } 21 | } 22 | 23 | public function enable() 24 | { 25 | return \extension_loaded('yac'); 26 | } 27 | 28 | public function selectDb($db) 29 | { 30 | return true; 31 | } 32 | 33 | public function add($key, $value, $timeOut = 0) 34 | { 35 | $data = $this->yac->get($key); 36 | if (!empty($data)) { 37 | throw new \Exception("{$key} exitst"); 38 | } 39 | return $this->yac->set($key, $value, $timeOut); 40 | } 41 | 42 | public function set($key, $value, $timeOut = 0) 43 | { 44 | return $this->yac->set($key, $value, $timeOut); 45 | } 46 | 47 | public function get($key) 48 | { 49 | return $this->yac->get($key); 50 | } 51 | 52 | public function delete($key) 53 | { 54 | return $this->yac->delete($key); 55 | } 56 | 57 | public function increment($key, $step = 1) 58 | { 59 | $data = $this->yac->get($key); 60 | if (empty($data)) { 61 | $this->yac->set($key, $step); 62 | } 63 | if (!\is_numeric($data)) { 64 | throw new \Exception("value no numeric"); 65 | } 66 | return $this->yac->set($key, ($data + $step)); 67 | } 68 | 69 | public function decrement($key, $step = 1) 70 | { 71 | $data = $this->yac->get($key); 72 | if (!\is_numeric($data)) { 73 | throw new \Exception("value no numeric"); 74 | } 75 | return $this->yac->set($key, ($data - $step)); 76 | } 77 | 78 | public function clear() 79 | { 80 | return $this->yac->flush(); 81 | } 82 | } -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Zpack.php: -------------------------------------------------------------------------------- 1 | 'main', 'k1'=>'v1'))); 21 | * server包格式:包总长+数据(json_encode) 22 | * @param $_data 23 | * @return bool 24 | */ 25 | public function parse($_data) 26 | { 27 | $ctrlName = Config::getField('project', 'default_ctrl_name', 'main\\main'); 28 | $methodName = Config::getField('project', 'default_method_name', 'main'); 29 | $fd = Request::getFd(); 30 | if (!empty($this->_buffer[$fd])) { 31 | $_data = $this->_buffer . $_data; 32 | } 33 | $packData = new MessagePacker($_data); 34 | $packLen = $packData->readInt(); 35 | $dataLen = \strlen($_data); 36 | if ($packLen > $dataLen) { 37 | $this->_buffer[$fd] = $_data; 38 | return false; 39 | } elseif ($packLen < $dataLen) { 40 | $this->_buffer[$fd] = \substr($_data, $packLen, $dataLen - $packLen); 41 | } else { 42 | if (!empty($this->_buffer[$fd])) { 43 | unset($this->_buffer[$fd]); 44 | } 45 | } 46 | $packData->resetOffset(); 47 | $params = $packData->readString(); 48 | $data = \json_decode($params, true); 49 | $apn = Config::getField('project', 'ctrl_name', 'a'); 50 | $mpn = Config::getField('project', 'method_name', 'm'); 51 | if (isset($params[$apn])) { 52 | $ctrlName = \str_replace('/', '\\', $params[$apn]); 53 | } 54 | if (isset($params[$mpn])) { 55 | $methodName = $params[$mpn]; 56 | } 57 | Request::init($ctrlName, $methodName, $data, Config::getField('project', 'view_mode', 'Zpack')); 58 | return true; 59 | } 60 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Adapter/Hprose.php: -------------------------------------------------------------------------------- 1 | config = $config; 24 | if (!isset($config['server_type'])) 25 | $config['server_type'] = 'http'; 26 | $this->serv = new Server("{$config['server_type']}://{$config['host']}:{$config['port']}"); 27 | 28 | $this->serv->setErrorTypes(E_ALL); 29 | $this->serv->setDebugEnabled(); 30 | 31 | $this->serv->set($config); 32 | } 33 | 34 | public function setClient($client) 35 | { 36 | if (!is_object($client)) { 37 | throw new \Exception('client must object'); 38 | } 39 | $this->client = $client; 40 | $this->client->setServ($this->serv); 41 | return true; 42 | } 43 | 44 | public function run() 45 | { 46 | $handlerArray = array( 47 | 'onWorkerStart', 48 | 'onWorkerStop', 49 | 'onWorkerError', 50 | 'onTask', 51 | 'onFinish', 52 | 'onWorkerError', 53 | 'onManagerStart', 54 | 'onManagerStop', 55 | 'onPipeMessage', 56 | ); 57 | $this->serv->on('Start', array($this->client, 'onStart')); 58 | $this->serv->on('Shutdown', array($this->client, 'onShutdown')); 59 | 60 | foreach ($handlerArray as $handler) { 61 | if (method_exists($this->client, $handler)) { 62 | $this->serv->on(\substr($handler, 2), array($this->client, $handler)); 63 | } 64 | } 65 | $this->client->onRegister(); 66 | $this->serv->start(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ZPHP/Socket/Client.php: -------------------------------------------------------------------------------- 1 | sockfp = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 17 | if (false === $this->sockfp) { 18 | $this->getError(); 19 | } else { 20 | socket_connect($this->sockfp, $host, $port); 21 | } 22 | return; 23 | } 24 | 25 | public function __destruct() 26 | { 27 | $this->disconnect(); 28 | } 29 | 30 | public function getError() 31 | { 32 | $code = socket_last_error($this->sockfp); 33 | throw new \Exception(socket_strerror($code), $code); 34 | } 35 | 36 | public function disconnect() 37 | { 38 | if ($this->sockfp) { 39 | socket_close($this->sockfp); 40 | $this->sockfp = null; 41 | } 42 | } 43 | 44 | public function send($data) 45 | { 46 | if (!$this->sockfp) { 47 | return false; 48 | } 49 | 50 | $dataLen = strlen($data); 51 | while (true) { 52 | $len = socket_write($this->sockfp, $data, $dataLen); 53 | if (false === $len) { 54 | $this->getError(); 55 | } elseif ($len < $dataLen) { 56 | $data = substr($data, $len); 57 | $dataLen -= $len; 58 | } else { 59 | break; 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | public function read() 67 | { 68 | if (!$this->sockfp) { 69 | return null; 70 | } 71 | $ret = ''; 72 | socket_set_nonblock($this->sockfp); 73 | while (true) { 74 | $tmp = socket_read($this->sockfp, 4096); 75 | if (false === $tmp) { 76 | $this->getError(); 77 | } 78 | 79 | if ('' === $tmp) { 80 | break; 81 | } 82 | 83 | $ret .= $tmp; 84 | } 85 | socket_set_block($this->sockfp); 86 | return $ret; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /ZPHP/Manager/Redis.php: -------------------------------------------------------------------------------- 1 | pconnect($config['host'], $config['port'], $timeOut); 31 | } else { 32 | $redis->connect($config['host'], $config['port'], $timeOut); 33 | } 34 | $redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_NONE); 35 | if (!empty($config['auth'])) { 36 | $redis->auth($config['auth']); 37 | } 38 | self::$instances[$name] = $redis; 39 | self::$configs[$name] = $config; 40 | } 41 | return self::$instances[$name]; 42 | } 43 | 44 | /** 45 | * 手动关闭链接 46 | * @param array $names 47 | * @return bool 48 | */ 49 | public static function closeInstance(array $names = array()) 50 | { 51 | if (empty(self::$instances)) { 52 | return true; 53 | } 54 | 55 | if (empty($names)) { 56 | foreach (self::$instances as $name => $redis) { 57 | if (self::$configs[$name]['pconnect']) { 58 | continue; 59 | } 60 | $redis->close(); 61 | unset(self::$configs[$name]); 62 | } 63 | } else { 64 | foreach ($names as $name) { 65 | if (isset(self::$instances[$name])) { 66 | if (self::$configs[$name]['pconnect']) { 67 | continue; 68 | } 69 | self::$instances[$name]->close(); 70 | unset(self::$configs[$name]); 71 | } 72 | } 73 | } 74 | 75 | return true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Ant.php: -------------------------------------------------------------------------------- 1 | header, true); 24 | $pathInfo = Request::getPathInfo(); 25 | if (!empty($pathInfo) && '/' !== $pathInfo) { 26 | $routeMap = ZRoute::match(Config::get('route', false), $pathInfo); 27 | if (is_array($routeMap)) { 28 | $ctrlName = \str_replace('/', '\\', $routeMap[0]); 29 | $methodName = $routeMap[1]; 30 | if (!empty($routeMap[2]) && is_array($routeMap[2])) { 31 | //参数优先 32 | $data = $data + $routeMap[2]; 33 | } 34 | } 35 | } 36 | $header = Request::getRequest()->header; 37 | if (!is_array($header)) { 38 | $header = []; 39 | } 40 | Request::addHeaders($header, true); 41 | } else { 42 | if (class_exists('swoole_serialize')) { 43 | $message = \swoole_serialize::unpack($_data); 44 | } else { 45 | $message = json_decode($_data, true); 46 | } 47 | if (is_array($message[0])) { 48 | Request::addHeaders($message[0], true); 49 | } else { 50 | Request::addHeaders([], true); 51 | } 52 | $data = is_array($message[1]) ? $message[1] : []; 53 | } 54 | $apn = Config::getField('project', 'ctrl_name', 'a'); 55 | $mpn = Config::getField('project', 'method_name', 'm'); 56 | if (isset($data[$apn])) { 57 | $ctrlName = \str_replace('/', '\\', $data[$apn]); 58 | } 59 | if (isset($data[$mpn])) { 60 | $methodName = $data[$mpn]; 61 | } 62 | 63 | Request::init($ctrlName, $methodName, $data, Config::getField('project', 'view_mode', 'Ant')); 64 | return true; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ZPHP/Protocol/Adapter/Zrpack.php: -------------------------------------------------------------------------------- 1 | _cache)) { 32 | $this->_cache = ZCache::getInstance('Php'); 33 | } 34 | $fd = Request::getFd(); 35 | $cacheData = $this->_cache->get($fd); 36 | if (!empty($cacheData)) { 37 | $_data = $cacheData . $_data; 38 | $this->_cache->delete($fd); 39 | } 40 | if (empty($_data)) { 41 | return false; 42 | } 43 | $packData = new MessagePacker($_data); 44 | $packLen = $packData->readInt(); 45 | $dataLen = \strlen($_data); 46 | if ($packLen > $dataLen) { 47 | $this->_cache->set($fd, $_data); 48 | return false; 49 | } elseif ($packLen < $dataLen) { 50 | $this->_cache->set($fd, \substr($_data, $packLen, $dataLen - $packLen)); 51 | } 52 | $packData->resetOffset(4); 53 | $data = []; 54 | $data['_cmd'] = $packData->readInt(); 55 | $pathinfo = Config::getField('cmdlist', $data['_cmd']); 56 | $data['_rid'] = $packData->readInt(); 57 | $params = $packData->readString(); 58 | $unpackData = \json_decode(gzdecode($params), true); 59 | if (!empty($unpackData) && \is_array($unpackData)) { 60 | $data += $unpackData; 61 | } 62 | $routeMap = ZRoute::match(Config::get('route', false), $pathinfo); 63 | if (is_array($routeMap)) { 64 | $ctrlName = $routeMap[0]; 65 | $methodName = $routeMap[1]; 66 | if (!empty($routeMap[2]) && is_array($routeMap[2])) { 67 | //参数优先 68 | $data = $data + $routeMap[2]; 69 | } 70 | } 71 | Request::init($ctrlName, $methodName, $data, Config::getField('project', 'view_mode', 'Zpack')); 72 | return true; 73 | } 74 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Adapter/React.php: -------------------------------------------------------------------------------- 1 | loop = $loop; 28 | $this->serv = new server($loop); 29 | $this->config = $config; 30 | } 31 | 32 | public function setClient($client) 33 | { 34 | $this->client = $client; 35 | } 36 | 37 | public function run() 38 | { 39 | if (3 === $this->config['work_mode']) { 40 | for ($i = 0; $i < $this->config['worker_num']; $i++) { 41 | $this->fork(); 42 | } 43 | } 44 | 45 | $client = $this->client; 46 | $client->onStart($this); 47 | $this->serv->on('connection', function ($conn) use ($client) { 48 | $client->onConnect($conn); 49 | $conn->on('data', function ($datas) use ($conn, $client) { 50 | $client->onReceive($conn, $datas); 51 | }); 52 | 53 | $conn->on('end', function () use ($conn, $client) { 54 | $conn->end(); 55 | }); 56 | 57 | $conn->on('close', function () use ($client, $conn) { 58 | $client->onClose($conn); 59 | }); 60 | }); 61 | $this->serv->listen($this->config['port'], $this->config['host']); 62 | $this->loop->run(); 63 | 64 | } 65 | 66 | public function fork() 67 | { 68 | if (($pid1 = pcntl_fork()) === 0) { //子进程 69 | $pid = posix_getpid(); 70 | $this->pids[$pid] = 0; 71 | $this->client->onWorkerStart(); 72 | exit(); 73 | } 74 | } 75 | 76 | public function addRequest($pid) 77 | { 78 | $this->pids[$pid]++; 79 | } 80 | 81 | public function check() 82 | { 83 | if (empty($this->config['max_request'])) { 84 | return; 85 | } 86 | foreach ($this->pids as $pid => $num) { 87 | if ($num >= $this->config['max_request']) { 88 | unset($this->pids[$pid]); 89 | posix_kill($pid, SIGTERM); 90 | $this->fork(); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /ZPHP/Rank/IRank.php: -------------------------------------------------------------------------------- 1 | isDot()) { 44 | continue; 45 | } 46 | $filename = $file->getFilename(); 47 | if ($file->isDir()) { 48 | if ($deep) { 49 | self::tree($dir . DS . $filename, $filter, $result, $deep); 50 | } 51 | } else { 52 | if (!empty($filter) && !\preg_match($filter, $filename)) { 53 | continue; 54 | } 55 | if ($deep) { 56 | $result[$dir] = $filename; 57 | } else { 58 | $result[] = $dir . DS . $filename; 59 | } 60 | } 61 | } 62 | return $result; 63 | } catch (\Exception $e) { 64 | return false; 65 | } 66 | } 67 | 68 | /** 69 | * 递归删除目录 70 | * @param $dir 71 | * @param $filter 72 | * @return bool 73 | */ 74 | public static function del($dir, $filter = '') 75 | { 76 | $files = new \DirectoryIterator($dir); 77 | foreach ($files as $file) { 78 | if ($file->isDot()) { 79 | continue; 80 | } 81 | $filename = $file->getFilename(); 82 | if (!empty($filter) && !\preg_match($filter, $filename)) { 83 | continue; 84 | } 85 | if ($file->isDir()) { 86 | self::del($dir . DS . $filename); 87 | } else { 88 | \unlink($dir . DS . $filename); 89 | } 90 | } 91 | return \rmdir($dir); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /ZPHP/Session/Factory.php: -------------------------------------------------------------------------------- 1 | log(Level::EMERGENCY, $message, $context); 24 | } 25 | 26 | /** 27 | * @param $message 28 | * @param array $context 29 | * @return bool 30 | * @throws \Exception 31 | */ 32 | public function alert($message, array $context = array()) 33 | { 34 | return $this->log(Level::ALERT, $message, $context); 35 | } 36 | 37 | /** 38 | * @param $message 39 | * @param array $context 40 | * @return bool 41 | * @throws \Exception 42 | */ 43 | public function critical($message, array $context = array()) 44 | { 45 | return $this->log(Level::CRITICAL, $message, $context); 46 | } 47 | 48 | /** 49 | * @param $message 50 | * @param array $context 51 | * @return bool 52 | * @throws \Exception 53 | */ 54 | public function error($message, array $context = array()) 55 | { 56 | return $this->log(Level::ERROR, $message, $context); 57 | } 58 | 59 | /** 60 | * @param $message 61 | * @param array $context 62 | * @return bool 63 | * @throws \Exception 64 | */ 65 | public function warning($message, array $context = array()) 66 | { 67 | return $this->log(Level::WARNING, $message, $context); 68 | } 69 | 70 | /** 71 | * @param $message 72 | * @param array $context 73 | * @return bool 74 | * @throws \Exception 75 | */ 76 | public function notice($message, array $context = array()) 77 | { 78 | return $this->log(Level::NOTICE, $message, $context); 79 | } 80 | 81 | /** 82 | * @param $message 83 | * @param array $context 84 | * @return bool 85 | * @throws \Exception 86 | */ 87 | public function info($message, array $context = array()) 88 | { 89 | return $this->log(Level::INFO, $message, $context); 90 | } 91 | 92 | /** 93 | * @param $message 94 | * @param array $context 95 | * @return bool 96 | * @throws \Exception 97 | */ 98 | public function debug($message, array $context = array()) 99 | { 100 | return $this->log(Level::DEBUG, $message, $context); 101 | } 102 | 103 | /** 104 | * @param $level 105 | * @param $message 106 | * @param array $context 107 | * @return bool 108 | * @throws \Exception 109 | * @desc {type} | {timeStamp} |{dateTime} | {$message} 110 | */ 111 | abstract public function log($level, $message, array $context = array()); 112 | 113 | } -------------------------------------------------------------------------------- /ZPHP/Session/Adapter/File.php: -------------------------------------------------------------------------------- 1 | gcTime = $config['cache_expire'] * 60; 22 | } 23 | $this->config = $config; 24 | } 25 | 26 | public function open($path, $sid) 27 | { 28 | $this->filename = $this->getFileName($path, $sid); 29 | } 30 | 31 | public function close() 32 | { 33 | return true; 34 | } 35 | 36 | public function gc($time) 37 | { 38 | $path = $this->getPath(); 39 | $files = \ZPHP\Common\Dir::tree($path); 40 | foreach ($files as $file) { 41 | if (false !== strpos($file, 'sess_')) { 42 | if (fileatime($file) < (time() - $this->gcTime)) { 43 | unlink($file); 44 | } 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | public function read($sid) 51 | { 52 | $this->filename = $this->getFileName($sid); 53 | if (is_file($this->filename)) { 54 | $content = file_get_contents($this->filename); 55 | if (strlen($content) < 10) { 56 | unlink($this->filename); 57 | return false; 58 | } 59 | $time = floatval(substr($content, 0, 10)); 60 | if ($time < (time() - $this->gcTime)) { 61 | unlink($this->filename); 62 | return false; 63 | } 64 | return substr($content, 10); 65 | } 66 | } 67 | 68 | public function write($sid, $data) 69 | { 70 | $this->filename = $this->getFileName($sid); 71 | $content = time() + $this->gcTime . $data; 72 | file_put_contents($this->filename, $content); 73 | return true; 74 | } 75 | 76 | public function destroy($sid) 77 | { 78 | $this->filename = $this->getFileName($sid); 79 | if (is_file($this->filename)) { 80 | unlink($this->filename); 81 | return false; 82 | } 83 | } 84 | 85 | private function getPath() 86 | { 87 | return isset($this->config['save_path']) ? $this->config['save_path'] : ZPHP::getRootPath() . DS . 'session_tmp'; 88 | } 89 | 90 | private function getFileName($sid) 91 | { 92 | $path = $this->getPath(); 93 | if (!is_dir($path)) { 94 | mkdir($path, 0777, true); 95 | } 96 | 97 | if (!empty($this->config['callback']) && is_callable($this->config['callback'])) { 98 | return call_user_func($this->config['callback'], $path, $sid); 99 | } 100 | 101 | return $path . DS . 'sess_' . $sid; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ZPHP/Rank/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 20 | $this->redis = Manager\Redis::getInstance($config); 21 | } 22 | } 23 | 24 | public function addRank($rankType, $key, $score, $length = 0) 25 | { 26 | $this->redis->zAdd($rankType, $score, $key); 27 | if ($length > 0) { //限个数 28 | $all = $this->redis->zCard($rankType); 29 | if ($all > $length) { 30 | $keys = $this->redis->zRange($rankType, 0, $all - $length); 31 | foreach ($keys as $key) { 32 | $this->redis->zDelete($rankType, $key); 33 | } 34 | } 35 | } 36 | 37 | return true; 38 | } 39 | 40 | public function getRank($rankType, $start = 0, $limit = 100, $score = true, $desc = 0) 41 | { 42 | if ($desc) { 43 | return $this->redis->zRevRange($rankType, $start, $start + $limit, $score); 44 | } 45 | return $this->redis->zRange($rankType, $start, $start + $limit, $score); 46 | } 47 | 48 | public function getRankByScore($rankType, $start, $end, $scores = true, $offset = 0, $count = 0) 49 | { 50 | if (!empty($offset) && !empty($count)) { 51 | return $this->redis->zRangeByScore($rankType, $start, $end, array('withscores' => $scores, 'limit' => array($offset, $count))); 52 | } 53 | return $this->redis->zRangeByScore($rankType, $start, $end, array('withscores' => $scores)); 54 | } 55 | 56 | public function getRankBetweenCount($rankType, $start, $end) 57 | { 58 | return $this->redis->zCount($rankType, $start, $end); 59 | } 60 | 61 | public function getRankCount($rankType) 62 | { 63 | return $this->redis->zCard($rankType); 64 | } 65 | 66 | public function getRankByKey($rankType, $key, $desc = 0) 67 | { 68 | if ($desc) { 69 | $rank = $this->redis->zRevRank($rankType, $key); 70 | } else { 71 | $rank = $this->redis->zRank($rankType, $key); 72 | } 73 | 74 | if (false === $rank) { 75 | return 0; 76 | } 77 | return ++$rank; 78 | } 79 | 80 | public function updateRankByKey($rankType, $key, $score) 81 | { 82 | return $this->redis->zIncrBy($rankType, $score, $key); 83 | } 84 | 85 | public function zDelete($rankType, $key) 86 | { 87 | return $this->redis->zDelete($rankType, $key); 88 | } 89 | 90 | public function deleteRank($rankType) 91 | { 92 | return $this->redis->delete($rankType); 93 | } 94 | 95 | public function getScoreByKey($rankType, $key) 96 | { 97 | return $this->redis->zScore($rankType, $key); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/Php.php: -------------------------------------------------------------------------------- 1 | _cache[$key])) { 34 | throw new \Exception("{$key} exitst"); 35 | } 36 | $timeOut = $timeOut ? (time() + $timeOut) : 0; 37 | $this->_cache[$key] = array( 38 | $value, $timeOut 39 | ); 40 | return true; 41 | } 42 | 43 | public function set($key, $value, $timeOut = 0) 44 | { 45 | $timeOut = $timeOut ? (time() + $timeOut) : 0; 46 | return $this->_cache[$key] = array( 47 | $value, $timeOut 48 | ); 49 | } 50 | 51 | public function get($key) 52 | { 53 | if (empty($this->_cache[$key])) { 54 | return null; 55 | } 56 | 57 | if (!empty($this->_cache[$key][1]) && $this->_cache[$key][1] <= time()) { //过期了 58 | unset($this->_cache[$key]); 59 | return null; 60 | } 61 | return $this->_cache[$key][0]; 62 | } 63 | 64 | public function delete($key) 65 | { 66 | unset($this->_cache[$key]); 67 | return true; 68 | } 69 | 70 | public function increment($key, $step = 1) 71 | { 72 | if (!empty($this->_cache[$key][0])) { 73 | if (!\is_numeric($this->_cache[$key][0])) { 74 | throw new \Exception("value no numeric"); 75 | } 76 | $this->_cache[$key][0] += $step; 77 | } else { 78 | 79 | $this->_cache[$key] = array( 80 | $step, 0 81 | ); 82 | } 83 | return $this->_cache[$key][0]; 84 | } 85 | 86 | public function decrement($key, $step = 1) 87 | { 88 | if (!empty($this->_cache[$key][0])) { 89 | if (!\is_numeric($this->_cache[$key][0])) { 90 | throw new \Exception("value no numeric"); 91 | } 92 | $this->_cache[$key][0] -= $step; 93 | } else { 94 | 95 | $this->_cache[$key] = array( 96 | 0 - $step, 0 97 | ); 98 | } 99 | return $this->_cache[$key][0]; 100 | } 101 | 102 | public function clear() 103 | { 104 | return $this->_cache = array(); 105 | } 106 | 107 | public function all() 108 | { 109 | return $this->_cache; 110 | } 111 | 112 | public function load($workerId) 113 | { 114 | \ZPHP\Manager\Task::load($workerId, 'cache'); 115 | } 116 | 117 | public function flush($workerId) 118 | { 119 | \ZPHP\Manager\Task::flush($workerId, 'cache', $this->_cache); 120 | } 121 | } -------------------------------------------------------------------------------- /ZPHP/Session/Swoole.php: -------------------------------------------------------------------------------- 1 | cookie[$sessionName])) { 44 | $sid = $request->cookie[$sessionName]; 45 | } 46 | if (!$sid && !empty($request->get[$sessionName])) { 47 | $sid = $request->get[$sessionName]; 48 | } 49 | if (!$sid && !empty($request->post[$sessionName])) { 50 | $sid = $request->post[$sessionName]; 51 | } 52 | if ($sid) { 53 | $handler = Factory::getInstance($sessionType, $config); 54 | $data = $handler->read($sid); 55 | if (!empty($data)) { 56 | $_SESSION = unserialize($data); 57 | } else { 58 | $_SESSION = array(); 59 | } 60 | } else { 61 | $sid = sha1($request->header['user-agent'] . $request->server['remote_addr'] . uniqid(Request::getSocket()->worker_pid . '_', true)); 62 | $path = empty($config['path']) ? '/' : $config['path']; 63 | $domain = empty($config['domain']) ? '' : $config['domain']; 64 | $secure = empty($config['secure']) ? false : $config['secure']; 65 | $httponly = !isset($config['httponly']) ? true : $config['httponly']; 66 | $lifetime = 0; 67 | if (!empty($config['cache_expire'])) { 68 | $lifetime = time() + $config['cache_expire'] * 60; 69 | } 70 | Response::getResponse()->cookie($sessionName, $sid, $lifetime, $path, $domain, $secure, $httponly); 71 | $_SESSION = array(); 72 | } 73 | self::$_sid = $sid; 74 | } 75 | 76 | public static function save() 77 | { 78 | if (self::$_sid) { 79 | $handler = Factory::getInstance(self::$_sessionType, self::$_config); 80 | if (!isset($_SESSION) || empty($_SESSION)) { //session清空 81 | $handler->destroy(self::$_sid); 82 | } else { 83 | $handler->write(self::$_sid, serialize($_SESSION)); 84 | unset($_SESSION); 85 | } 86 | self::$_sid = null; 87 | self::$_config = null; 88 | self::$_sessionType = null; 89 | } 90 | } 91 | 92 | public static function getSid() 93 | { 94 | return self::$_sid; 95 | } 96 | } -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/Task.php: -------------------------------------------------------------------------------- 1 | tid = $db; 45 | } 46 | 47 | private function packData($data) 48 | { 49 | return \ZPHP\Manager\Task::$map['cache'] . json_encode($data); 50 | } 51 | 52 | public function add($key, $value, $timeOut = 0) 53 | { 54 | $server = Request::getSocket(); 55 | $server->task($this->packData([ 56 | 'type' => 'add', 57 | 'key' => $value, 58 | 'ttl' => $timeOut, 59 | ]), $this->tid); 60 | return; 61 | } 62 | 63 | public function set($key, $value, $timeOut = 0) 64 | { 65 | $server = Request::getSocket(); 66 | $server->task($this->packData([ 67 | 'type' => 'set', 68 | 'key' => $key, 69 | 'value' => $value, 70 | 'ttl' => $timeOut, 71 | ]), $this->tid); 72 | } 73 | 74 | public function get($key) 75 | { 76 | $server = Request::getSocket(); 77 | return $server->taskwait($this->packData([ 78 | 'type' => 'get', 79 | 'key' => $key 80 | ]), 0.01, $this->tid); 81 | } 82 | 83 | public function delete($key) 84 | { 85 | $server = Request::getSocket(); 86 | $server->task($this->packData([ 87 | 'type' => 'delete', 88 | 'key' => $key 89 | ]), $this->tid); 90 | } 91 | 92 | public function increment($key, $step = 1) 93 | { 94 | $server = Request::getSocket(); 95 | $server->task($this->packData([ 96 | 'type' => 'increment', 97 | 'key' => $key 98 | ]), $this->tid); 99 | } 100 | 101 | public function decrement($key, $step = 1) 102 | { 103 | $server = Request::getSocket(); 104 | $server->task($this->packData([ 105 | 'type' => 'decrement', 106 | 'key' => $key 107 | ]), $this->tid); 108 | } 109 | 110 | public function clear() 111 | { 112 | $server = Request::getSocket(); 113 | $server->task($this->packData([ 114 | 'type' => 'clear' 115 | ]), $this->tid); 116 | } 117 | 118 | public function all() 119 | { 120 | $server = Request::getSocket(); 121 | return $server->taskwait($this->packData([ 122 | 'type' => 'all' 123 | ]), 0.01, $this->tid); 124 | } 125 | 126 | public function flush() 127 | { 128 | $server = Request::getSocket(); 129 | $server->task($this->packData([ 130 | 'type' => 'flush', 131 | 'workerId' => $this->tid, 132 | ]), $this->tid); 133 | } 134 | 135 | public function load() 136 | { 137 | $server = Request::getSocket(); 138 | $server->task($this->packData([ 139 | 'type' => 'load', 140 | 'workerId' => $this->tid, 141 | ]), $this->tid); 142 | } 143 | } -------------------------------------------------------------------------------- /ZPHP/Common/MessagePacker.php: -------------------------------------------------------------------------------- 1 | data = $data; 19 | $this->offset = 0; 20 | $this->dataLen = strlen($data); 21 | } 22 | 23 | public function resetForUnPack($data) 24 | { 25 | $this->data = $data; 26 | $this->offset = 0; 27 | $this->dataLen = strlen($data); 28 | } 29 | 30 | public function resetForPack() 31 | { 32 | $this->data = ''; 33 | $this->offset = 0; 34 | } 35 | 36 | public function resetOffset($len = 0) 37 | { 38 | $this->offset = $len; 39 | } 40 | 41 | public function writeByte($d) 42 | { 43 | $this->data .= pack("C1", $d); 44 | } 45 | 46 | public function writeString($s, $len = null) 47 | { 48 | //$s = rtrim($s, "\0") . "\0"; 49 | if (null === $len) { 50 | $len = strlen($s); 51 | } 52 | $this->writeInt($len); 53 | $this->data .= pack("a*", $s); 54 | } 55 | 56 | //写二进制数据 57 | public function writeBinary($b, $len = null) 58 | { 59 | if (null === $len) { 60 | $len = strlen($b); 61 | } 62 | $this->writeInt($len); 63 | $this->data .= $b; 64 | //$this->data .= pack('H*', $b); 65 | } 66 | 67 | public function writeBool($d) 68 | { 69 | $this->data .= pack("C1", $d); 70 | } 71 | 72 | public function writeInt($i) 73 | { 74 | //$this->data .= pack("N1", $i); 75 | $this->data .= pack("V1", $i); 76 | } 77 | 78 | public function writeInt16($i) 79 | { 80 | //$this->data .= pack("n1", $i); 81 | $this->data .= pack("v1", $i); 82 | } 83 | 84 | public function readByte() 85 | { 86 | $ret = unpack("C1ele", substr($this->data, $this->offset, 1)); 87 | $this->offset += 1; 88 | return $ret['ele']; 89 | } 90 | 91 | public function readInt() 92 | { 93 | //$ret = unpack("N1ele", substr($this->data, $this->offset, 4)); 94 | $ret = unpack("V1ele", substr($this->data, $this->offset, 4)); 95 | $this->offset += 4; 96 | 97 | return $ret['ele']; 98 | } 99 | 100 | public function readInt16() 101 | { 102 | //$ret = unpack("n1ele", substr($this->data, $this->offset, 2)); 103 | $ret = unpack("v1ele", substr($this->data, $this->offset, 2)); 104 | $this->offset += 2; 105 | 106 | return $ret['ele']; 107 | } 108 | 109 | public function readString() 110 | { 111 | $len = $this->readInt(); 112 | if(0 == $len) { 113 | return null; 114 | } 115 | $ret = unpack("a*ele", substr($this->data, $this->offset, $len)); 116 | $this->offset += $len; 117 | 118 | return $ret['ele']; 119 | } 120 | 121 | //读二进制 122 | public function readBinary() 123 | { 124 | $len = $this->readInt(); 125 | $ret = substr($this->data, $this->offset, $len); 126 | $this->offset += $len; 127 | return $ret; 128 | } 129 | 130 | public function readBool() 131 | { 132 | $ret = unpack("C1ele", substr($this->data, $this->offset, 1)); 133 | $this->offset += 1; 134 | 135 | return $ret['ele']; 136 | } 137 | 138 | public function output() 139 | { 140 | echo $this->data; 141 | } 142 | 143 | public function getData() 144 | { 145 | return $this->data; 146 | } 147 | 148 | public function getBuffer() 149 | { 150 | if ($this->offset < $this->dataLen) { 151 | return substr($this->data, $this->offset); 152 | } 153 | return null; 154 | } 155 | 156 | public function isEnd() 157 | { 158 | return $this->offset >= $this->dataLen; 159 | } 160 | } -------------------------------------------------------------------------------- /ZPHP/Client/Rpc/Http.php: -------------------------------------------------------------------------------- 1 | uri = $host . ':' . $port; 49 | $this->timeOut = $timeOut; 50 | if (empty($config)) { 51 | $config = [ 52 | 'ctrl_name' => 'a', 53 | 'method_name' => 'm', 54 | ]; 55 | } else { 56 | $config = $config + [ 57 | 'ctrl_name' => 'a', 58 | 'method_name' => 'm', 59 | ]; 60 | } 61 | $this->api = Config::getField('project', 'default_ctrl_name'); 62 | $this->config = $config; 63 | $this->isDot = 1; 64 | return true; 65 | } 66 | 67 | public function setApi($api) 68 | { 69 | $this->api = $api; 70 | return $this; 71 | } 72 | 73 | public function noSync() 74 | { 75 | $this->sync = 0; 76 | return $this; 77 | } 78 | 79 | public function getClient() 80 | { 81 | return null; 82 | } 83 | 84 | public function isConnected() 85 | { 86 | return true; 87 | } 88 | 89 | public function setDot($dot = 1) 90 | { 91 | $this->isDot = $dot; 92 | return $this; 93 | } 94 | 95 | abstract function pack($sendArr); 96 | 97 | abstract function unpack($result); 98 | 99 | /** 100 | * @param $method 101 | * @param array $params 102 | * @return string 103 | * @desc 远程rpc调用 104 | */ 105 | public function call($method, $params = []) 106 | { 107 | Request::setRequestId(); 108 | $this->startTime = microtime(true); 109 | $this->method = $method; 110 | $this->sendParams = [ 111 | '_recv' => $this->sync, 112 | $this->config['method_name'] => $method, 113 | ]; 114 | if ($this->api) { 115 | $this->sendParams[$this->config['ctrl_name']] = $this->api; 116 | } 117 | $this->sendParams += $params; 118 | $result = $this->unpack($this->rawCall($this->pack($this->sendParams))); 119 | $this->httpMethod = 'GET'; 120 | $this->isDot = 1; 121 | return $result; 122 | } 123 | 124 | /** 125 | * @param $sendData 126 | * @return string 127 | * @throws \Exception 128 | * @desc 直接发送原始远程rpc调用 129 | */ 130 | public function rawCall($sendData) 131 | { 132 | return HttpClient::getByUrl($this->uri, null, $this->httpMethod, $sendData, $this->timeOut, Request::getHeaders(), 1); 133 | } 134 | 135 | public function ping() 136 | { 137 | return HttpClient::getByUrl($this->uri . '/ant-ping'); 138 | } 139 | 140 | public function setHttpMethod($method) 141 | { 142 | if ($method) { 143 | $this->httpMethod = $method; 144 | } 145 | return $this; 146 | } 147 | 148 | public function __call($name, $arguments) 149 | { 150 | if (empty($arguments[0])) { 151 | $arguments[0] = []; 152 | } elseif (!is_array($arguments[0])) { 153 | throw new \Exception('arguments[0] must array'); 154 | } 155 | return $this->call($name, $arguments[0]); 156 | } 157 | } -------------------------------------------------------------------------------- /ZPHP/Client/Rpc/Udp.php: -------------------------------------------------------------------------------- 1 | api = Config::getField('project', 'default_ctrl_name'); 50 | if (empty($config)) { 51 | $config = [ 52 | 'ctrl_name' => 'a', 53 | 'method_name' => 'm', 54 | ]; 55 | } else { 56 | $config += [ 57 | 'ctrl_name' => 'a', 58 | 'method_name' => 'm', 59 | ]; 60 | } 61 | $config['host'] = $host; 62 | $config['port'] = $port; 63 | $client->connect($host, $port, $timeOut / 1000); 64 | self::$configs[$key] = $config; 65 | self::$clients[$key] = $client; 66 | } 67 | $this->client = self::$clients[$key]; 68 | $this->config = self::$configs[$key]; 69 | $this->isDot = 1; 70 | $this->isSync = 0; 71 | $this->key = $key; 72 | $this->timeOut = $timeOut; 73 | return true; 74 | } 75 | 76 | public function setApi($api) 77 | { 78 | $this->api = $api; 79 | return $this; 80 | } 81 | 82 | public function sync() 83 | { 84 | $this->isSync = 1; 85 | return $this; 86 | } 87 | 88 | public function getClient() 89 | { 90 | return $this->client; 91 | } 92 | 93 | public function isConnected() 94 | { 95 | if (empty($this->client)) { 96 | return false; 97 | } 98 | 99 | return $this->client->isConnected(); 100 | } 101 | 102 | public function setDot($dot = 1) 103 | { 104 | $this->isDot = $dot; 105 | return $this; 106 | } 107 | 108 | abstract function pack($sendArr); 109 | 110 | abstract function unpack($result); 111 | 112 | public function call($method, $data = []) 113 | { 114 | $this->startTime = microtime(true); 115 | $this->method = $method; 116 | $sendArr = [ 117 | '_recv' => $this->isSync, 118 | $this->config['method_name'] => $method, 119 | ]; 120 | if ($this->api) { 121 | $sendArr[$this->config['ctrl_name']] = $this->api; 122 | } 123 | $sendArr += $data; 124 | if ($this->isSync) { 125 | $this->rawCall($this->pack($sendArr)); 126 | $result = $this->unpack($this->client->recv()); 127 | $this->isSync = 0; 128 | return $result; 129 | } 130 | return null; 131 | } 132 | 133 | public function rawCall($sendData) 134 | { 135 | $this->client->sendto($this->config['host'], $this->config['port'], $sendData); 136 | } 137 | 138 | public function ping() 139 | { 140 | $this->rawCall('ant-ping'); 141 | return $this->client->recv(); 142 | } 143 | 144 | public function __call($name, $arguments) 145 | { 146 | if (empty($arguments[0])) { 147 | $arguments[0] = []; 148 | } elseif (!is_array($arguments[0])) { 149 | throw new \Exception('arguments[0] must array'); 150 | } 151 | return $this->call($name, $arguments[0]); 152 | } 153 | } -------------------------------------------------------------------------------- /ZPHP/Storage/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 23 | $this->redis = Manager\Redis::getInstance($config); 24 | $this->pconnect = $config['pconnect']; 25 | } 26 | } 27 | 28 | public function setSlave($config) 29 | { 30 | if (empty($this->sRedis)) { 31 | $this->sRedis = Manager\Redis::getInstance($config); 32 | } 33 | } 34 | 35 | public function setKeySuffix($suffix) 36 | { 37 | $this->suffix = $suffix; 38 | } 39 | 40 | private function uKey($userId) 41 | { 42 | return $userId . '_' . $this->suffix; 43 | } 44 | 45 | public function getMutilMD($userId, $keys, $slaveConfig = '') 46 | { 47 | $uKey = $this->uKey($userId); 48 | $datas = $this->redis->hMGet($uKey, $keys); 49 | foreach ($datas as $key => $val) { 50 | if (false === $val) { 51 | $val = $this->getSD($userId, $key, $slaveConfig); 52 | if (false !== $val) { 53 | $datas[$key] = $val; 54 | } 55 | } 56 | } 57 | return $datas; 58 | } 59 | 60 | public function getMD($userId, $key, $slaveConfig = "") 61 | { 62 | $uKey = $this->uKey($userId); 63 | $data = $this->redis->hGet($uKey, $key); 64 | return $data; 65 | } 66 | 67 | public function getSD($userId, $key, $slaveConfig = "") 68 | { 69 | $uKey = $this->uKey($userId); 70 | $this->setSlave($slaveConfig); 71 | $data = $this->sRedis->hGet($uKey, $key); 72 | return $data; 73 | } 74 | 75 | public function setSD($userId, $key, $data, $slaveConfig = "") 76 | { 77 | $uKey = $this->uKey($userId); 78 | $this->setSlave($slaveConfig); 79 | $data = $this->sRedis->hSet($uKey, $key, $data); 80 | return $data; 81 | } 82 | 83 | public function delSD($userId, $key, $slaveConfig = "") 84 | { 85 | $uKey = $this->uKey($userId); 86 | $this->setSlave($slaveConfig); 87 | $data = $this->sRedis->hDel($uKey, $key); 88 | return $data; 89 | } 90 | 91 | public function setMD($userId, $key, $data, $cas = false) 92 | { 93 | if ($cas) { 94 | return $this->setMDCAS($userId, $key, $data); 95 | } 96 | $uKey = $this->uKey($userId); 97 | return $this->redis->hSet($uKey, $key, $data); 98 | } 99 | 100 | public function addMD($userId, $key, $data) 101 | { 102 | $uKey = $this->uKey($userId); 103 | return $this->redis->hSetNx($uKey, $key, $data); 104 | } 105 | 106 | public function setMDCAS($userId, $key, $data) 107 | { 108 | $uKey = $this->uKey($userId); 109 | $this->redis->watch($uKey); 110 | $result = $this->redis->multi()->hSet($uKey, $key, $data)->exec(); 111 | if (false === $result) { 112 | throw new \Exception('cas error'); 113 | } 114 | return $result; 115 | } 116 | 117 | public function del($userId, $key) 118 | { 119 | $uKey = $this->uKey($userId); 120 | return $this->redis->hDel($uKey, $key); 121 | } 122 | 123 | public function setMultiMD($userId, $keys) 124 | { 125 | $uKey = $this->uKey($userId); 126 | return $this->redis->hMSet($uKey, $keys); 127 | } 128 | 129 | public function close() 130 | { 131 | if ($this->pconnect) { 132 | return true; 133 | } 134 | 135 | $this->redis->close(); 136 | 137 | if (!empty($this->sRedis)) { 138 | $this->sRedis->close(); 139 | } 140 | 141 | return true; 142 | } 143 | 144 | public function getMulti($cmds) 145 | { 146 | $this->redis->multi(\Redis::PIPELINE); 147 | foreach ($cmds as $userId => $key) { 148 | $uKey = $this->uKey($userId); 149 | $this->redis->hGet($uKey, $key); 150 | } 151 | 152 | return $this->redis->exec(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /ZPHP/Storage/Adapter/TT.php: -------------------------------------------------------------------------------- 1 | tt)) { 22 | $this->tt = Manager\Memcached::getInstance($config); 23 | } 24 | } 25 | 26 | public function setSlave($config) 27 | { 28 | if (empty($this->stt)) { 29 | $this->stt = Manager\Memcached::getInstance($config); 30 | } 31 | } 32 | 33 | public function getMutilMD($userId, $keys, $slaveConfig = '') 34 | { 35 | $newKeys = array(); 36 | foreach ($keys as $key) { 37 | $newKeys[] = $this->uKey($userId, $key); 38 | } 39 | $datas = $this->tt->getMulti($newKeys); 40 | foreach ($datas as $key => $val) { 41 | if (false === $val) { 42 | $val = $this->getSD($userId, $key, $slaveConfig); 43 | if (false !== $val) { 44 | $datas[$key] = $val; 45 | } 46 | } 47 | } 48 | return $datas; 49 | } 50 | 51 | public function getMD($userId, $key, $slaveName = "") 52 | { 53 | $key = $this->uKey($userId, $key); 54 | $data = $this->tt->get($key); 55 | 56 | if (false === $data) { 57 | $code = $this->tt->getResultCode(); 58 | if ($code == \Memcached::RES_NOTFOUND) { 59 | $this->setSlave($slaveName); 60 | $data = $this->stt->get($key); 61 | if (false === $data) { 62 | $code = $this->stt->getResultCode(); 63 | if ($code == \Memcached::RES_NOTFOUND) { 64 | return false; 65 | } else { 66 | throw new \Exception("null data: {$userId}, {$key}, {$code}"); 67 | } 68 | } 69 | } else { 70 | throw new \Exception("error data: {$userId}, {$key}, {$code}"); 71 | } 72 | } 73 | return $data; 74 | } 75 | 76 | public function del($userId, $key) 77 | { 78 | $key = $this->uKey($userId, $key); 79 | return $this->tt->del($key); 80 | } 81 | 82 | public function getSD($userId, $key, $slaveName = "") 83 | { 84 | $key = $this->uKey($userId, $key); 85 | $this->setSlave($slaveName); 86 | $data = $this->stt->get($key); 87 | if (false === $data) { 88 | $code = $this->stt->getResultCode(); 89 | if ($code == \Memcached::RES_NOTFOUND) { 90 | return false; 91 | } else { 92 | throw new \Exception("null data: {$userId}, {$key}, {$code}"); 93 | } 94 | } 95 | 96 | return $data; 97 | } 98 | 99 | public function setSD($userId, $key, $data, $slaveName = "") 100 | { 101 | $key = $this->uKey($userId, $key); 102 | $this->setSlave($slaveName); 103 | return $this->stt->set($key, $data); 104 | } 105 | 106 | public function delSD($userId, $key, $slaveName = "") 107 | { 108 | $key = $this->uKey($userId, $key); 109 | $this->setSlave($slaveName); 110 | return $this->stt->delete($key); 111 | } 112 | 113 | public function setMD($userId, $key, $data) 114 | { 115 | $key = $this->uKey($userId, $key); 116 | return $this->tt->set($key, $data); 117 | } 118 | 119 | public function setMDCAS($userId, $key, $data) 120 | { 121 | $key = $this->uKey($userId, $key); 122 | return $this->tt->set($key, $data); 123 | } 124 | 125 | public function setMultiMD($userId, $keys) 126 | { 127 | foreach ($keys as $key => $value) { 128 | $newKey = $this->uKey($userId, $key); 129 | $keys[$newKey] = $value; 130 | unset($key); 131 | } 132 | return $this->tt->setMulti($keys); 133 | } 134 | 135 | 136 | public function setKeySuffix($suffix) 137 | { 138 | $this->suffix = $suffix; 139 | } 140 | 141 | private function uKey($userId, $key) 142 | { 143 | return $userId . "_" . $this->suffix . "__" . $key; 144 | } 145 | 146 | public function close() 147 | { 148 | return true; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /ZPHP/Cache/Adapter/Memcached.php: -------------------------------------------------------------------------------- 1 | memcached = Manager\Memcached::getInstance($config); 25 | } 26 | 27 | public function enable() 28 | { 29 | return true; 30 | } 31 | 32 | /** 33 | * 取得Memcached对象 34 | * 35 | * @return \Memcached 36 | */ 37 | function getMemcached() 38 | { 39 | return $this->memcached; 40 | } 41 | 42 | public function selectDb($db) 43 | { 44 | return true; 45 | } 46 | 47 | /** 48 | * 添加新数据(如存在则失败) 49 | * 50 | * @param string $key 51 | * @param mixed $value 52 | * @param int $expiration 53 | * @return bool 54 | */ 55 | public function add($key, $value, $expiration = 0) 56 | { 57 | return $this->memcached ? $this->memcached->add($key, $value, $expiration) : false; 58 | } 59 | 60 | /** 61 | * 替换指定键名的数据(如不存在则失败) 62 | * 63 | * @param string $key 64 | * @param mixed $value 65 | * @param int $expiration 66 | * @return bool 67 | */ 68 | public function replace($key, $value, $expiration = 0) 69 | { 70 | return $this->memcached ? $this->memcached->replace($key, $value, $expiration) : false; 71 | } 72 | 73 | /** 74 | * 存储指定键名的数据(如存在则覆盖) 75 | * 76 | * @param string $key 77 | * @param mixed $value 78 | * @param int $expiration 79 | * @return bool 80 | */ 81 | public function set($key, $value, $expiration = 0) 82 | { 83 | return $this->memcached ? $this->memcached->set($key, $value, $expiration) : false; 84 | } 85 | 86 | /** 87 | * 存储指定数据序列(如存在则覆盖) 88 | * 89 | * @param array $items 90 | * @param int $expiration 91 | * @return bool 92 | */ 93 | public function setMulti($items, $expiration = 0) 94 | { 95 | return $this->memcached ? $this->memcached->setMulti($items, $expiration) : false; 96 | } 97 | 98 | /** 99 | * 获取指定键名的数据 100 | * 101 | * @param string $key 102 | * @return mixed 103 | */ 104 | public function get($key) 105 | { 106 | return $this->memcached ? $this->memcached->get($key) : null; 107 | } 108 | 109 | /** 110 | * 获取指定键名序列的数据 111 | * 112 | * @param array $keys 113 | * @return array 114 | */ 115 | public function getMulti($keys) 116 | { 117 | return $this->memcached ? $this->memcached->getMulti($keys) : null; 118 | } 119 | 120 | /** 121 | * 增加整数数据的值 122 | * 123 | * @param string $key 124 | * @param int $offset 125 | * @return bool 126 | */ 127 | public function increment($key, $offset = 1) 128 | { 129 | return $this->memcached ? $this->memcached->increment($key, $offset) : false; 130 | } 131 | 132 | /** 133 | * 减少整数数据的值 134 | * 135 | * @param string $key 136 | * @param int $offset 137 | * @return bool 138 | */ 139 | public function decrement($key, $offset = 1) 140 | { 141 | return $this->memcached ? $this->memcached->decrement($key, $offset) : false; 142 | } 143 | 144 | /** 145 | * 删除指定数据 146 | * 147 | * @param string $key 148 | * @return bool 149 | */ 150 | public function delete($key) 151 | { 152 | return $this->memcached ? $this->memcached->delete($key) : false; 153 | } 154 | 155 | /** 156 | * 删除指定键名序列的数据 157 | * 158 | * @param array $keys 159 | * @return bool 160 | */ 161 | public function deleteMulti($keys) 162 | { 163 | if (!$this->memcached || empty($keys)) { 164 | return false; 165 | } 166 | 167 | foreach ($keys as $key) { 168 | $this->memcached->delete($key); 169 | } 170 | 171 | return true; 172 | } 173 | 174 | /** 175 | * 无效化所有缓存数据(清空缓存,慎用) 176 | * 177 | * @return bool 178 | */ 179 | public function clear() 180 | { 181 | return $this->memcached ? $this->memcached->flush() : false; 182 | } 183 | 184 | /** 185 | * 获取服务器统计信息 186 | * 187 | * @return array 188 | */ 189 | public function stat() 190 | { 191 | return $this->memcached ? $this->memcached->getStats() : null; 192 | } 193 | } -------------------------------------------------------------------------------- /ZPHP/Common/Formater.php: -------------------------------------------------------------------------------- 1 | $name, 17 | 'message' => '[type:' . $error['type'] . '] ' . $error['message'], 18 | 'code' => ZConfig::getField('project', 'default_exception_code', -1), 19 | 'file' => $error['file'], 20 | 'line' => $error['line'], 21 | 'userAgent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', 22 | 'trace' => array(), 23 | ); 24 | 25 | if ($trace) { 26 | $traceItems = debug_backtrace(); 27 | foreach ($traceItems as $traceItem) { 28 | $traceHash = array( 29 | 'file' => isset($traceItem['file']) ? $traceItem['file'] : 'null', 30 | 'line' => isset($traceItem['line']) ? $traceItem['line'] : 'null', 31 | 'function' => isset($traceItem['function']) ? $traceItem['function'] : 'null', 32 | 'args' => array(), 33 | ); 34 | 35 | if (!empty($traceItem['class'])) { 36 | $traceHash['class'] = $traceItem['class']; 37 | } 38 | 39 | if (!empty($traceItem['type'])) { 40 | $traceHash['type'] = $traceItem['type']; 41 | } 42 | 43 | if (!empty($traceItem['args'])) { 44 | foreach ($traceItem['args'] as $argsItem) { 45 | $traceHash['args'][] = \preg_replace('/[^(\x20-\x7F)]*/', '', \var_export($argsItem, true)); 46 | } 47 | } 48 | 49 | $exceptionHash['trace'][] = $traceHash; 50 | } 51 | } 52 | $exceptionHash['_view_mode'] = 'Json'; 53 | return $exceptionHash; 54 | } 55 | 56 | /** 57 | * @param $exception \Exception | \Error 58 | * @param bool $trace 59 | * @param bool $args 60 | * @return array 61 | * @throws \Exception 62 | */ 63 | public static function exception($exception, $trace = true, $args = true) 64 | { 65 | $code = $exception->getCode(); 66 | $message = $exception->getMessage(); 67 | if (empty($code)) { 68 | $code = ZConfig::getField('project', 'default_exception_code', -1); 69 | } elseif (!is_numeric($code)) { 70 | $message .= "#code:[{$code}]"; 71 | $code = ZConfig::getField('project', 'default_exception_code', -1); 72 | } 73 | 74 | $exceptionHash = array( 75 | 'className' => get_class($exception), 76 | 'message' => $message, 77 | 'code' => $code, 78 | 'file' => $exception->getFile(), 79 | 'line' => $exception->getLine(), 80 | 'userAgent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', 81 | 'trace' => array(), 82 | 'server' => ZConfig::get('server_mode') == 'Http' ? $_SERVER : '', 83 | ); 84 | 85 | if ($trace) { 86 | $traceItems = $exception->getTrace(); 87 | foreach ($traceItems as $traceItem) { 88 | $traceHash = array( 89 | 'file' => isset($traceItem['file']) ? $traceItem['file'] : 'null', 90 | 'line' => isset($traceItem['line']) ? $traceItem['line'] : 'null', 91 | 'function' => isset($traceItem['function']) ? $traceItem['function'] : 'null', 92 | 'args' => array(), 93 | ); 94 | 95 | if (!empty($traceItem['class'])) { 96 | $traceHash['class'] = $traceItem['class']; 97 | } 98 | 99 | if (!empty($traceItem['type'])) { 100 | $traceHash['type'] = $traceItem['type']; 101 | } 102 | 103 | if ($args) { 104 | if (!empty($traceItem['args'])) { 105 | foreach ($traceItem['args'] as $argsItem) { 106 | $traceHash['args'][] = \preg_replace('/[^(\x20-\x7F)]*/', '', \var_export($argsItem, true)); 107 | } 108 | } 109 | } 110 | 111 | $exceptionHash['trace'][] = $traceHash; 112 | } 113 | } 114 | $exceptionHash['_view_mode'] = 'Json'; 115 | return $exceptionHash; 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /ZPHP/Conn/Adapter/Swoole.php: -------------------------------------------------------------------------------- 1 | table)) { 19 | $table = new swoole_table(1024); 20 | $table->column('data', swoole_table::TYPE_STRING, 64); 21 | $table->create(); 22 | $this->table = $table; 23 | } 24 | } 25 | 26 | 27 | public function addFd($fd, $uid = 0) 28 | { 29 | return $this->table->set($this->getKey($fd, 'fu'), ['data' => $uid]); 30 | } 31 | 32 | 33 | public function getUid($fd) 34 | { 35 | return $this->table->get($this->getKey($fd, 'fu')); 36 | } 37 | 38 | public function add($uid, $fd) 39 | { 40 | $uinfo = $this->get($uid); 41 | if (!empty($uinfo)) { 42 | $this->delete($uid); 43 | } 44 | $data = array( 45 | 'fd' => $fd, 46 | 'time' => time(), 47 | 'types' => array('ALL' => 1) 48 | ); 49 | 50 | $this->table->set($this->getKey($uid), \json_encode($data)); 51 | $this->table->hSet($this->getKey('ALL'), $uid, $fd); 52 | } 53 | 54 | public function addChannel($uid, $channel) 55 | { 56 | $uinfo = $this->get($uid); 57 | $uinfo['types'][$channel] = 1; 58 | if ($this->table->hSet($this->getKey($channel), $uid, $uinfo['fd'])) { 59 | $this->table->set($this->getKey($uid), json_encode($uinfo)); 60 | } 61 | } 62 | 63 | public function delChannel($uid, $channel) 64 | { 65 | if ($this->table->hDel($this->getKey($channel), $uid)) { 66 | $uinfo = $this->get($uid); 67 | if (isset($uinfo['types'][$channel])) { 68 | unset($uinfo['types'][$channel]); 69 | $this->table->set($this->getKey($uid), json_encode($uinfo)); 70 | } 71 | } 72 | return true; 73 | } 74 | 75 | public function getChannel($channel = 'ALL') 76 | { 77 | return $this->table->hGetAll($this->getKey($channel)); 78 | } 79 | 80 | public function get($uid) 81 | { 82 | $data = $this->table->get($this->getKey($uid)); 83 | if (empty($data)) { 84 | return array(); 85 | } 86 | 87 | return json_decode($data, true); 88 | } 89 | 90 | public function uphb($uid) 91 | { 92 | $uinfo = $this->get($uid); 93 | if (empty($uinfo)) { 94 | return false; 95 | } 96 | $uinfo['time'] = time(); 97 | return $this->table->set($this->getKey($uid), json_encode($uinfo)); 98 | } 99 | 100 | public function heartbeat($uid, $ntime = 60) 101 | { 102 | $uinfo = $this->get($uid); 103 | if (empty($uinfo)) { 104 | return false; 105 | } 106 | $time = time(); 107 | if ($time - $uinfo['time'] > $ntime) { 108 | $this->delete($uinfo['fd'], $uid); 109 | return false; 110 | } 111 | return true; 112 | } 113 | 114 | public function delete($fd, $uid = null, $old = true) 115 | { 116 | if (null === $uid) { 117 | $uid = $this->getUid($fd); 118 | } 119 | if ($old) { 120 | $this->table->delete($this->getKey($fd, 'fu')); 121 | } 122 | $this->table->delete($this->getKey($fd, 'buff')); 123 | if (empty($uid)) { 124 | return; 125 | } 126 | $uinfo = $this->get($uid); 127 | if (!empty($uinfo)) { 128 | $this->table->delete($this->getKey($uid)); 129 | foreach ($uinfo['types'] as $type => $val) { 130 | $this->table->hDel($this->getKey($type), $uid); 131 | } 132 | } 133 | } 134 | 135 | public function getBuff($fd, $prev = 'buff') 136 | { 137 | return $this->table->get($this->getKey($fd, $prev)); 138 | } 139 | 140 | public function setBuff($fd, $data, $prev = 'buff') 141 | { 142 | return $this->table->set($this->getKey($fd, $prev), $data); 143 | } 144 | 145 | public function delBuff($fd, $prev = 'buff') 146 | { 147 | return $this->table->delete($this->getKey($fd, $prev)); 148 | } 149 | 150 | private function getKey($uid, $prefix = 'uf') 151 | { 152 | return "{$prefix}_{$uid}_" . ZConfig::getField('connection', 'prefix'); 153 | } 154 | 155 | public function clear() 156 | { 157 | $this->table->flushDB(); 158 | } 159 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Callback/HttpServer.php: -------------------------------------------------------------------------------- 1 | cache = ZCache::getInstance($config['adapter'], $config); 32 | } 33 | 34 | public function onConnect() 35 | { 36 | 37 | $params = func_get_args(); 38 | $fd = $params[1]; 39 | //echo "{$fd} connected".PHP_EOL; 40 | 41 | } 42 | 43 | /** 44 | * 请求发起 45 | */ 46 | public function onReceive() 47 | { 48 | $params = func_get_args(); 49 | $_data = $params[3]; 50 | $serv = $params[0]; 51 | $fd = $params[1]; 52 | $parser = new HttpParser(); 53 | $buffer = $this->cache->getBuff($fd); 54 | $nparsed = (int)$this->cache->getBuff($fd, 'nparsed'); 55 | $buffer .= $_data; 56 | $nparsed = $parser->execute($buffer, $nparsed); 57 | if ($parser->hasError()) { 58 | $serv->close($fd, $params[2]); 59 | $this->_clearBuff($fd); 60 | } elseif ($parser->isFinished()) { 61 | $this->_clearBuff($fd); 62 | $this->onSend($fd, $this->_getData($parser->getEnvironment())); 63 | } else { 64 | $buffer = $this->cache->setBuff($fd, $buffer); 65 | $nparsed = (int)$this->cache->setBuff($fd, $nparsed, 'nparsed'); 66 | } 67 | } 68 | 69 | private function _getData($data) 70 | { 71 | $_SERVER = $data; 72 | switch ($data['REQUEST_METHOD']) { 73 | case 'POST': 74 | parse_str($data['QUERY_STRING'] . '&' . $data['REQUEST_BODY'], $param); 75 | return $param; 76 | break; 77 | case 'PUT': 78 | break; 79 | case 'DELETE': 80 | break; 81 | default: //GET 82 | if (empty($data['QUERY_STRING'])) { 83 | return array(); 84 | } 85 | 86 | parse_str($data['QUERY_STRING'], $param); 87 | return $param; 88 | break; 89 | } 90 | } 91 | 92 | private function _clearBuff($fd) 93 | { 94 | $this->cache->delBuff($fd, 'nparsed'); 95 | $this->cache->delBuff($fd); 96 | return true; 97 | } 98 | 99 | public function onClose() 100 | { 101 | $params = func_get_args(); 102 | //$fd = $params[1]; 103 | //echo "{$fd} closed".PHP_EOL; 104 | $this->cache->delBuff($params[1]); 105 | } 106 | 107 | public function onShutdown() 108 | { 109 | //echo "server shut dowm\n"; 110 | if ($this->cache) { 111 | $this->cache->clear(); 112 | } 113 | } 114 | 115 | 116 | public function onWorkerStart() 117 | { 118 | $params = func_get_args(); 119 | //$worker_id = $params[1]; 120 | //echo "WorkerStart[$worker_id]|pid=" . posix_getpid() . ".\n"; 121 | $config = ZConfig::getField('cache', 'locale'); 122 | $this->cache = ZCache::getInstance($config['adapter'], $config); 123 | $this->serv = $params[0]; 124 | if (is_file(__DIR__ . DS . 'Mimes.php')) { 125 | $mimes = include(__DIR__ . DS . 'Mimes.php'); 126 | $this->mimes = array_flip($mimes); 127 | } 128 | 129 | } 130 | 131 | public function onWorkerStop() 132 | { 133 | /* 134 | $params = func_get_args(); 135 | $worker_id = $params[1]; 136 | echo "WorkerStop[$worker_id]|pid=" . posix_getpid() . ".\n"; 137 | */ 138 | } 139 | 140 | public function onTask() 141 | { 142 | 143 | } 144 | 145 | public function onFinish() 146 | { 147 | 148 | } 149 | 150 | public function getMime($filename) 151 | { 152 | $ext = strtolower(trim(substr(strrchr($filename, '.'), 1))); 153 | if (isset($this->mimes[$ext])) { 154 | return $this->mimes[$ext]; 155 | } else { 156 | return 'text/html'; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /ZPHP/Client/Sync/Http.php: -------------------------------------------------------------------------------- 1 | $url, 128 | 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:13.0) Gecko/20100101 Firefox/13.0.1' 129 | ]; 130 | $headerStr = ''; 131 | foreach ($header as $key => $val) { 132 | $headerStr .= "{$key}: {$url}\r\n"; 133 | } 134 | $headerStr .= 'Header-Ext: ZPHP-Sync-Client'; 135 | $strm = stream_context_create(array( 136 | 'http' => array( 137 | 'timeout' => $timeOut, 138 | 'header' => $headerStr 139 | ) 140 | ) 141 | ); 142 | return file_get_contents($url, 0, $strm); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /ZPHP/Conn/Adapter/Redis.php: -------------------------------------------------------------------------------- 1 | redis)) { 20 | $this->redis = ZRedis::getInstance($config); 21 | $db = ZConfig::getField('connection', 'db', 0); 22 | if (!empty($db)) { 23 | $this->redis->select($db); 24 | } 25 | } 26 | } 27 | 28 | 29 | public function addFd($fd, $uid = 0) 30 | { 31 | return $this->redis->set($this->getKey($fd, 'fu'), $uid); 32 | } 33 | 34 | 35 | public function getUid($fd) 36 | { 37 | return $this->redis->get($this->getKey($fd, 'fu')); 38 | } 39 | 40 | public function add($uid, $fd) 41 | { 42 | $uinfo = $this->get($uid); 43 | if (!empty($uinfo)) { 44 | $ofd = $uinfo['fd']; 45 | $oid = $this->getUid($fd); 46 | if ($ofd == $uid) { 47 | $this->delete($ofd, $uid); 48 | } else { 49 | $uinfo = []; 50 | } 51 | } 52 | $data = array( 53 | 'fd' => $fd, 54 | 'time' => time(), 55 | 'types' => array('ALL' => 1) 56 | ); 57 | 58 | $this->redis->set($this->getKey($uid), \json_encode($data)); 59 | $this->redis->hSet($this->getKey('ALL'), $uid, $fd); 60 | return $uinfo; 61 | } 62 | 63 | public function addChannel($uid, $channel) 64 | { 65 | $uinfo = $this->get($uid); 66 | if (empty($uinfo)) return; 67 | $uinfo['types'][$channel] = 1; 68 | if ($this->redis->hSet($this->getKey($channel), $uid, $uinfo['fd'])) { 69 | $this->redis->set($this->getKey($uid), json_encode($uinfo)); 70 | } 71 | } 72 | 73 | public function delChannel($uid, $channel) 74 | { 75 | if ($this->redis->hDel($this->getKey($channel), $uid)) { 76 | $uinfo = $this->get($uid); 77 | if (!empty($uinfo['types'][$channel])) { 78 | unset($uinfo['types'][$channel]); 79 | $this->redis->set($this->getKey($uid), json_encode($uinfo)); 80 | } 81 | } 82 | return true; 83 | } 84 | 85 | public function getChannel($channel = 'ALL') 86 | { 87 | return $this->redis->hGetAll($this->getKey($channel)); 88 | } 89 | 90 | public function get($uid) 91 | { 92 | $data = $this->redis->get($this->getKey($uid)); 93 | if (empty($data)) { 94 | return array(); 95 | } 96 | 97 | return json_decode($data, true); 98 | } 99 | 100 | public function uphb($uid) 101 | { 102 | $uinfo = $this->get($uid); 103 | if (empty($uinfo)) { 104 | return false; 105 | } 106 | $uinfo['time'] = time(); 107 | return $this->redis->set($this->getKey($uid), json_encode($uinfo)); 108 | } 109 | 110 | public function heartbeat($uid, $ntime = 60) 111 | { 112 | $uinfo = $this->get($uid); 113 | if (empty($uinfo)) { 114 | return false; 115 | } 116 | $time = time(); 117 | if ($time - $uinfo['time'] > $ntime) { 118 | $this->delete($uinfo['fd'], $uid); 119 | return false; 120 | } 121 | return true; 122 | } 123 | 124 | public function delete($fd, $uid = null, $old = true) 125 | { 126 | if (null === $uid) { 127 | $uid = $this->getUid($fd); 128 | } 129 | if ($old) { 130 | $this->redis->delete($this->getKey($fd, 'fu')); 131 | } 132 | if (empty($uid)) { 133 | return; 134 | } 135 | $uinfo = $this->get($uid); 136 | if (!empty($uinfo)) { 137 | $this->redis->delete($this->getKey($uid)); 138 | foreach ($uinfo['types'] as $type => $val) { 139 | $this->redis->hDel($this->getKey($type), $uid); 140 | } 141 | } 142 | } 143 | 144 | public function getBuff($fd, $prev = 'buff') 145 | { 146 | return $this->redis->get($this->getKey($fd, $prev)); 147 | } 148 | 149 | public function setBuff($fd, $data, $prev = 'buff') 150 | { 151 | return $this->redis->set($this->getKey($fd, $prev), $data); 152 | } 153 | 154 | public function delBuff($fd, $prev = 'buff') 155 | { 156 | return $this->redis->delete($this->getKey($fd, $prev)); 157 | } 158 | 159 | private function getKey($uid, $prefix = 'uf') 160 | { 161 | return "{$prefix}_{$uid}_" . ZConfig::getField('connection', 'prefix'); 162 | } 163 | 164 | public function clear() 165 | { 166 | $this->redis->flushDB(); 167 | } 168 | } -------------------------------------------------------------------------------- /ZPHP/Core/Config.php: -------------------------------------------------------------------------------- 1 | ‘127.0.0.1' 服务器地址 25 | * ‘port’ => '27017' 端口地址 26 | * ‘option’ => array('connect' => true) 参数 27 | * 'db_name'=> 'test' 数据库名称 28 | * ‘username’=> '' 数据库用户名 29 | * ‘password’=> '' 数据库密码 30 | * ) 31 | * Enter description here ... 32 | */ 33 | public function connect($config = array()) 34 | { 35 | if (empty($this->mongo)) { 36 | $options = array(); 37 | if (!empty($config['options'])) { 38 | $options = $config['options']; 39 | } 40 | $this->mongo = new \MongoClient($config['dsn'], $options); 41 | 42 | } 43 | } 44 | 45 | public function setDBName($dbname) 46 | { 47 | $this->db = $this->mongo->selectDB($dbname); 48 | } 49 | 50 | /** 51 | * 选择一个集合,相当于选择一个数据表 52 | * @param string $collection 集合名称 53 | */ 54 | public function selectCollection($collection) 55 | { 56 | return $this->collection = $this->db->selectCollection($collection); 57 | } 58 | 59 | /** 60 | * 新增数据 61 | * @param array $data 需要新增的数据 例如:array('title' => '1000', 'username' => 'xcxx') 62 | * @param array $option 参数 63 | */ 64 | public function insert($data, $option = array()) 65 | { 66 | return $this->collection->insert($data, $option); 67 | } 68 | 69 | /** 70 | * 批量新增数据 71 | * @param array $data 需要新增的数据 例如:array(0=>array('title' => '1000', 'username' => 'xcxx')) 72 | * @param array $option 参数 73 | */ 74 | public function batchInsert($data, $option = array()) 75 | { 76 | return $this->collection->batchInsert($data, $option); 77 | } 78 | 79 | /** 80 | * 保存数据,如果已经存在在库中,则更新,不存在,则新增 81 | * @param array $data 需要新增的数据 例如:array(0=>array('title' => '1000', 'username' => 'xcxx')) 82 | * @param array $option 参数 83 | */ 84 | public function save($data, $option = array()) 85 | { 86 | return $this->collection->save($data, $option); 87 | } 88 | 89 | /** 90 | * 根据条件移除 91 | * @param array $query 条件 例如:array(('title' => '1000')) 92 | * @param array $option 参数 93 | */ 94 | public function remove($query, $option = array()) 95 | { 96 | return $this->collection->remove($query, $option); 97 | } 98 | 99 | /** 100 | * 根据条件更新数据 101 | * @param array $query 条件 例如:array(('title' => '1000')) 102 | * @param array $data 需要更新的数据 例如:array(0=>array('title' => '1000', 'username' => 'xcxx')) 103 | * @param array $option 参数 104 | */ 105 | public function update($query, $data, $option = array()) 106 | { 107 | return $this->collection->update($query, $data, $option); 108 | } 109 | 110 | /** 111 | * 根据条件查找一条数据 112 | * @param array $query 条件 例如:array(('title' => '1000')) 113 | * @param array $fields 参数 114 | */ 115 | public function findOne($query, $fields = array()) 116 | { 117 | return $this->collection->findOne($query, $fields); 118 | } 119 | 120 | /** 121 | * 根据条件查找多条数据 122 | * @param array $query 查询条件 123 | * @param array $sort 排序条件 array('age' => -1, 'username' => 1) 124 | * @param int $limit 页面 125 | * @param int $limit 查询到的数据条数 126 | * @param array $fields返回的字段 127 | */ 128 | public function find($query, $sort = array(), $skip = 0, $limit = 0, $fields = array()) 129 | { 130 | $cursor = $this->collection->find($query, $fields); 131 | $count = $cursor->count(); 132 | if (empty($count)) { 133 | return array(); 134 | } 135 | if ($sort) $cursor->sort($sort); 136 | if ($skip) $cursor->skip($skip); 137 | if ($limit) $cursor->limit($limit); 138 | return iterator_to_array($cursor); 139 | } 140 | 141 | public function explain($query) 142 | { 143 | return $this->collection->find($query)->explain(); 144 | } 145 | 146 | /** 147 | * 数据统计 148 | */ 149 | public function count() 150 | { 151 | return $this->collection->count(); 152 | } 153 | 154 | /** 155 | * 错误信息 156 | */ 157 | public function error() 158 | { 159 | return $this->db->lastError(); 160 | } 161 | 162 | /** 163 | * 获取集合对象 164 | */ 165 | public function getCollection() 166 | { 167 | return $this->collection; 168 | } 169 | 170 | /** 171 | * 获取DB对象 172 | */ 173 | public function getDb() 174 | { 175 | return $this->db; 176 | } 177 | 178 | 179 | } -------------------------------------------------------------------------------- /ZPHP/Common/Debug.php: -------------------------------------------------------------------------------- 1 | save_run($xhprof_data, 'random'); 43 | } 44 | $times = $endTime - self::$records[$key]['start_time']; 45 | $mem_use = memory_get_usage() - self::$records[$key]['memory_use']; 46 | unset(self::$records[$key]); 47 | if (empty($_SERVER['HTTP_HOST'])) { 48 | $_SERVER['HTTP_HOST'] = ''; 49 | } 50 | Log::info($logName, array($times, self::convert($mem_use), $run_id, $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], Request::getParams())); 51 | } 52 | 53 | 54 | private static function convert($size) 55 | { 56 | $unit = array('B', 'K', 'M', 'G', 'T', 'P'); 57 | return round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i]; 58 | } 59 | 60 | 61 | /** 62 | * Send print to terminal. 63 | */ 64 | private static function _log($msgType, $args) 65 | { 66 | if (!Config::getField('project', 'debug_mode', 0)) { 67 | return; 68 | } 69 | 70 | if (count($args) == 1) { 71 | $msg = is_scalar($args[0]) ? $args[0] : self::dump($args[0]); 72 | } else { 73 | $msg = self::dump($args); 74 | } 75 | 76 | if (self::$DEBUG_TRACE) { 77 | $trace = self::getTrace(); 78 | } else { 79 | $trace = array(); 80 | } 81 | if ($msgType == 'debug') { 82 | Terminal::drawStr($msg, 'magenta'); 83 | } else if ($msgType == 'error') { 84 | Terminal::drawStr($msg, 'red'); 85 | } else if ($msgType == 'info') { 86 | Terminal::drawStr($msg, 'brown'); 87 | } else { 88 | Terminal::drawStr($msg, 'default'); 89 | } 90 | //echo "\n"; 91 | !empty($trace) && Terminal::drawStr("\t" . implode(" <-- ", $trace) . "\n"); 92 | } 93 | 94 | private static function getTrace() 95 | { 96 | $traces = debug_backtrace(); 97 | // only display 2 to 6 backtrace 98 | for ($i = 2, $n = count($traces); $i < $n && $i < 7; $i++) { 99 | //for ($i = 3, $n = count($traces); $i < $n; $i++){ 100 | $trace = $traces[$i]; 101 | if (isset($trace['type'])) { 102 | $callInfo = $trace['class'] . $trace['type'] . $trace['function'] . '()'; 103 | } else { 104 | $callInfo = 'internal:' . $trace['function'] . '()'; 105 | } 106 | if (isset($trace['file'])) { 107 | $fileInfo = str_replace(ZPHP::getRootPath() . '/', '', $trace['file']) . ':' . $trace['line']; 108 | } else { 109 | $fileInfo = ''; 110 | } 111 | //$traces_data[] = $fileInfo . " " . $callInfo; 112 | $traces_data[] = $callInfo . " " . $fileInfo; 113 | } 114 | return $traces_data; 115 | } 116 | 117 | private static function dump() 118 | { 119 | ob_start(); 120 | 121 | foreach (func_get_args() as $v) { 122 | var_dump($v); 123 | } 124 | 125 | $dump = ob_get_contents(); 126 | ob_end_clean(); 127 | 128 | return $dump; 129 | } 130 | 131 | public static function log() 132 | { 133 | self::_log('log', func_get_args()); 134 | } 135 | 136 | public static function info() 137 | { 138 | self::_log('info', func_get_args()); 139 | } 140 | 141 | public static function debug($a) 142 | { 143 | self::_log('debug', func_get_args()); 144 | } 145 | 146 | public static function error() 147 | { 148 | self::_log('error', func_get_args()); 149 | } 150 | 151 | } 152 | 153 | -------------------------------------------------------------------------------- /ZPHP/Conn/Adapter/Yac.php: -------------------------------------------------------------------------------- 1 | yac)) { 20 | $this->yac = ZCache::getInstance($config['adapter'], $config); 21 | if (!$this->yac->enable()) { 22 | throw new \Exception("Yac no enable"); 23 | 24 | } 25 | } 26 | } 27 | 28 | 29 | public function addFd($fd, $uid = 0) 30 | { 31 | return $this->yac->set($this->getKey($fd, 'fu'), $uid); 32 | } 33 | 34 | 35 | public function getUid($fd) 36 | { 37 | return $this->yac->get($this->getKey($fd, 'fu')); 38 | } 39 | 40 | public function add($uid, $fd) 41 | { 42 | $uinfo = $this->get($uid); 43 | if (!empty($uinfo)) { 44 | $this->delete($uinfo['fd'], $uid); 45 | } 46 | $data = array( 47 | 'fd' => $fd, 48 | 'time' => time(), 49 | 'types' => array('ALL' => 1) 50 | ); 51 | 52 | $this->yac->set($this->getKey($uid), \json_encode($data)); 53 | $this->upChannel($uid, $fd); 54 | } 55 | 56 | public function addChannel($uid, $channel) 57 | { 58 | $uinfo = $this->get($uid); 59 | $uinfo['types'][$channel] = 1; 60 | if ($this->yac->upChannel($uid, $uinfo['fd'], $channel)) { 61 | $this->yac->set($this->getKey($uid), json_encode($uinfo)); 62 | } 63 | } 64 | 65 | public function delChannel($uid, $channel = 'ALL') 66 | { 67 | $channelInfo = $this->getChannel($channel); 68 | if (!empty($channelInfo[$uid])) { 69 | unset($channelInfo[$uid]); 70 | $this->yac->set($this->getKey($channel), json_encode($channelInfo)); 71 | $uinfo = $this->get($uid); 72 | if (!empty($uinfo['types'][$channel])) { 73 | unset($uinfo['types'][$channel]); 74 | $this->yac->set($this->getKey($uid), json_encode($uinfo)); 75 | } 76 | } 77 | 78 | return true; 79 | } 80 | 81 | private function upChannel($uid, $fd, $channel = 'ALL') 82 | { 83 | $channelInfo = $this->getChannel($channel); 84 | $channelInfo[$uid] = $fd; 85 | $this->yac->set($this->getKey($channel), json_encode($channelInfo)); 86 | return true; 87 | } 88 | 89 | public function getChannel($channel = 'ALL') 90 | { 91 | return json_decode($this->yac->get($this->getKey($channel)), true); 92 | } 93 | 94 | public function get($uid) 95 | { 96 | $data = $this->yac->get($this->getKey($uid)); 97 | if (empty($data)) { 98 | return array(); 99 | } 100 | 101 | return json_decode($data, true); 102 | } 103 | 104 | public function uphb($uid) 105 | { 106 | $uinfo = $this->get($uid); 107 | if (empty($uinfo)) { 108 | return false; 109 | } 110 | $uinfo['time'] = time(); 111 | return $this->yac->set($this->getKey($uid), json_encode($uinfo)); 112 | } 113 | 114 | public function heartbeat($uid, $ntime = 60) 115 | { 116 | $uinfo = $this->get($uid); 117 | if (empty($uinfo)) { 118 | return false; 119 | } 120 | $time = time(); 121 | if ($time - $uinfo['time'] > $ntime) { 122 | $this->delete($uinfo['fd'], $uid); 123 | return false; 124 | } 125 | return true; 126 | } 127 | 128 | public function delete($fd, $uid = null, $old = true) 129 | { 130 | if (null === $uid) { 131 | $uid = $this->getUid($fd); 132 | } 133 | if ($old) { 134 | $this->yac->delete($this->getKey($fd, 'fu')); 135 | } 136 | $this->yac->delete($this->getKey($fd, 'buff')); 137 | if (empty($uid)) { 138 | return; 139 | } 140 | $uinfo = $this->get($uid); 141 | if (!empty($uinfo)) { 142 | $this->yac->delete($this->getKey($uid)); 143 | foreach ($uinfo['types'] as $type => $val) { 144 | $this->delChannel($uid, $type); 145 | } 146 | } 147 | return true; 148 | } 149 | 150 | public function getBuff($fd, $prev = 'buff') 151 | { 152 | return $this->yac->get($this->getKey($fd, $prev)); 153 | } 154 | 155 | public function setBuff($fd, $data, $prev = 'buff') 156 | { 157 | return $this->yac->set($this->getKey($fd, $prev), $data); 158 | } 159 | 160 | public function delBuff($fd, $prev = 'buff') 161 | { 162 | return $this->yac->delete($this->getKey($fd, $prev)); 163 | } 164 | 165 | private function getKey($uid, $prefix = 'uf') 166 | { 167 | return "{$prefix}_{$uid}_" . ZConfig::getField('connection', 'prefix'); 168 | } 169 | 170 | public function clear() 171 | { 172 | $this->yac->clear(); 173 | } 174 | } -------------------------------------------------------------------------------- /ZPHP/Conn/Adapter/Task.php: -------------------------------------------------------------------------------- 1 | task($this->packData([ 31 | 'type' => 'addFd', 32 | 'fd' => $fd, 33 | 'uid' => $uid, 34 | ]), $this->tid); 35 | return; 36 | } 37 | 38 | 39 | public function getUid($fd) 40 | { 41 | /** 42 | * @var $server \swoole_server 43 | */ 44 | $server = Request::getSocket(); 45 | return $server->taskwait($this->packData([ 46 | 'type' => 'getUid', 47 | 'fd' => $fd 48 | ]), 0.01, $this->tid); 49 | } 50 | 51 | public function add($uid, $fd) 52 | { 53 | $server = Request::getSocket(); 54 | $server->task($this->packData([ 55 | 'type' => 'add', 56 | 'fd' => $fd, 57 | 'uid' => $uid, 58 | ]), $this->tid); 59 | } 60 | 61 | public function addChannel($uid, $channel) 62 | { 63 | $server = Request::getSocket(); 64 | $server->task($this->packData([ 65 | 'type' => 'addChannel', 66 | 'uid' => $uid, 67 | 'channel' => $channel, 68 | ]), $this->tid); 69 | } 70 | 71 | public function delChannel($uid, $channel) 72 | { 73 | $server = Request::getSocket(); 74 | $server->task($this->packData([ 75 | 'type' => 'delChannel', 76 | 'uid' => $uid, 77 | 'channel' => $channel, 78 | ]), $this->tid); 79 | } 80 | 81 | public function getChannel($channel = 'ALL') 82 | { 83 | $server = Request::getSocket(); 84 | return $server->taskwait($this->packData([ 85 | 'type' => 'getChannel', 86 | 'channel' => $channel, 87 | ]), 0.01, $this->tid); 88 | } 89 | 90 | public function get($uid) 91 | { 92 | $server = Request::getSocket(); 93 | return $server->taskwait($this->packData([ 94 | 'type' => 'get', 95 | 'uid' => $uid, 96 | ]), 0.01, $this->tid); 97 | } 98 | 99 | public function uphb($uid) 100 | { 101 | $server = Request::getSocket(); 102 | $server->task($this->packData([ 103 | 'type' => 'uphb', 104 | 'uid' => $uid, 105 | ]), $this->tid); 106 | return true; 107 | } 108 | 109 | public function heartbeat($uid, $ntime = 60) 110 | { 111 | $server = Request::getSocket(); 112 | $server->task($this->packData([ 113 | 'type' => 'heartbeat', 114 | 'uid' => $uid, 115 | 'ntime' => $ntime, 116 | ]), $this->tid); 117 | } 118 | 119 | public function delete($fd, $uid = null, $old = true) 120 | { 121 | $server = Request::getSocket(); 122 | $server->task($this->packData([ 123 | 'type' => 'delete', 124 | 'fd' => $fd, 125 | 'uid' => $uid, 126 | 'old' => $old, 127 | ]), $this->tid); 128 | } 129 | 130 | public function getBuff($fd, $prev = 'buff') 131 | { 132 | $server = Request::getSocket(); 133 | return $server->taskwait($this->packData([ 134 | 'type' => 'getBuff', 135 | 'fd' => $fd, 136 | ]), 0.01, $this->tid); 137 | } 138 | 139 | public function setBuff($fd, $data, $prev = 'buff') 140 | { 141 | $server = Request::getSocket(); 142 | $server->task($this->packData([ 143 | 'type' => 'setBuff', 144 | 'fd' => $fd, 145 | ]), $this->tid); 146 | return true; 147 | } 148 | 149 | public function delBuff($fd, $prev = 'buff') 150 | { 151 | $server = Request::getSocket(); 152 | $server->task($this->packData([ 153 | 'type' => 'delBuff', 154 | 'fd' => $fd, 155 | ]), $this->tid); 156 | return true; 157 | } 158 | 159 | public function clear() 160 | { 161 | $server = Request::getSocket(); 162 | $server->task($this->packData([ 163 | 'type' => 'clear', 164 | ]), $this->tid); 165 | } 166 | 167 | public function flush() 168 | { 169 | $server = Request::getSocket(); 170 | $server->task($this->packData([ 171 | 'type' => 'flush', 172 | 'workerId' => $this->tid, 173 | ]), $this->tid); 174 | } 175 | 176 | public function load() 177 | { 178 | $server = Request::getSocket(); 179 | $server->task($this->packData([ 180 | 'type' => 'load', 181 | 'workerId' => $this->tid, 182 | ]), $this->tid); 183 | } 184 | } -------------------------------------------------------------------------------- /ZPHP/Client/Async/Http.php: -------------------------------------------------------------------------------- 1 | setHeaders($header + [ 90 | 'Host' => $host ? $host : $ip, 91 | "User-Agent" => 'ZPHP-ASYNCHTTPCLIENT-' . \ZPHP\ZPHP::VERSION, 92 | 'Accept' => '*/*', 93 | 'Accept-Encoding' => 'gzip', 94 | ]); 95 | $timeId = \swoole_timer_after($timeOut, function () use ($cli, $callback) { 96 | $cli->close(); 97 | if (is_callable($callback)) { 98 | $callback(null, 1); 99 | } 100 | }); 101 | $cli->get($path, function ($cli) use ($timeId, $callback) { 102 | \swoole_timer_clear($timeId); 103 | $cli->close(); 104 | if (is_callable($callback)) { 105 | $callback($cli); 106 | } 107 | }); 108 | } 109 | 110 | /** 111 | * @param $ip //目标地址ip 112 | * @param $port //目标地址端口 113 | * @param $ssl //是否ssl 114 | * @param $path //请求路径 115 | * @param $data //请求的post数据 116 | * @param $callback //请求完成之后的回调函数 117 | * @param $timeOut //超时时间,单位:ms 118 | * @param $header //头信息 119 | * @param null $host //host地址 120 | */ 121 | public static function postByIp($ip, $port, $ssl, $path, $data, $callback, $timeOut = 15000, $header = [], $host = null) 122 | { 123 | self::check(); 124 | $cli = new \swoole_http_client($ip, $port, $ssl); 125 | $cli->setHeaders($header + [ 126 | 'Host' => $host ? $host : $ip, 127 | "User-Agent" => 'ZPHP-ASYNCHTTPCLIENT-' . \ZPHP\ZPHP::VERSION, 128 | 'Accept' => '*/*', 129 | 'Accept-Encoding' => 'gzip', 130 | ]); 131 | $timeId = \swoole_timer_after($timeOut, function () use ($cli, $callback) { 132 | $cli->close(); 133 | if (is_callable($callback)) { 134 | $callback($cli, 1); 135 | } 136 | }); 137 | $cli->post($path, $data, function ($cli) use ($timeId, $callback) { 138 | 139 | \swoole_timer_clear($timeId); 140 | $cli->close(); 141 | if (is_callable($callback)) { 142 | $callback($cli); 143 | } 144 | }); 145 | } 146 | } -------------------------------------------------------------------------------- /ZPHP/Manager/Task.php: -------------------------------------------------------------------------------- 1 | '_task_cache_', 20 | 'conn' => '_task_conn_', 21 | ]; 22 | 23 | public static function check($data) 24 | { 25 | foreach (self::$map as $key => $val) { 26 | $len = strlen($val); 27 | $pre = substr($data, 0, $len); 28 | if ($pre == $val) { 29 | return [ 30 | $key, substr($data, $len), 31 | ]; 32 | } 33 | } 34 | 35 | return false; 36 | } 37 | 38 | public static function handle($params) 39 | { 40 | if ('cache' == $params[0]) { 41 | return self::cache($params[1]); 42 | } 43 | 44 | if ('conn' == $params[0]) { 45 | return self::conn($params[1]); 46 | } 47 | } 48 | 49 | public static function cache($data) 50 | { 51 | $input = json_decode($data, true); 52 | $phpCache = ZCache::getInstance('Php', ['_prefix' => self::$map['cache']]); 53 | switch ($input['type']) { 54 | case 'add': 55 | $phpCache->add($input['key'], $input['value'], $input['ttl']); 56 | break; 57 | case 'set': 58 | $phpCache->add($input['key'], $input['value'], $input['ttl']); 59 | break; 60 | case 'get': 61 | return $phpCache->get($input['key']); 62 | break; 63 | case 'delete': 64 | $phpCache->delete($input['key']); 65 | break; 66 | case 'increment': 67 | $phpCache->increment($input['key'], $input['step']); 68 | break; 69 | case 'decrement': 70 | $phpCache->decrement($input['key'], $input['step']); 71 | break; 72 | case 'clear': 73 | $phpCache->clear(); 74 | break; 75 | case 'all': 76 | return $phpCache->all(); 77 | break; 78 | case 'load': 79 | $phpCache->load($input['workerId']); 80 | break; 81 | case 'flush': 82 | $phpCache->flush($input['workerId']); 83 | break; 84 | } 85 | } 86 | 87 | public static function conn($data) 88 | { 89 | $input = json_decode($data, true); 90 | $conn = ZConn::getInstance('Php', ['_prefix' => self::$map['conn']]); 91 | switch ($input['type']) { 92 | case 'get': 93 | return $conn->get($input['uid']); 94 | break; 95 | case 'getUid': 96 | return $conn->getUid($input['fd']); 97 | break; 98 | case 'add': 99 | $conn->add($input['uid'], $input['fd']); 100 | break; 101 | case 'addFd': 102 | $conn->addFd($input['fd'], $input['uid']); 103 | break; 104 | case 'addChannel': 105 | $conn->addChannel($input['fd'], $input['channel']); 106 | break; 107 | case 'delChannel': 108 | $conn->delChannel($input['fd'], $input['channel']); 109 | break; 110 | case 'getChannel': 111 | return $conn->getChannel($input['channel']); 112 | break; 113 | case 'clear': 114 | $conn->clear(); 115 | break; 116 | case 'delete': 117 | $conn->delete($input['fd'], $input['uid'], $input['oid']); 118 | break; 119 | case 'delBuff': 120 | $conn->delBuff($input['fd']); 121 | break; 122 | case 'setBuff': 123 | $conn->setBuff($input['fd'], $input['data']); 124 | break; 125 | case 'getBuff': 126 | return $conn->getBuff($input['fd']); 127 | break; 128 | case 'load': 129 | $conn->load($input['workerId']); 130 | break; 131 | case 'flush': 132 | $conn->flush($input['workerId']); 133 | break; 134 | } 135 | } 136 | 137 | public static function flush($workerId, $type, $data) 138 | { 139 | $dir = ZPHP::getRootPath() . DS . 'tmp'; 140 | if (!is_dir($dir)) { 141 | if (!mkdir($dir)) { 142 | return false; 143 | } 144 | } 145 | $filename = $dir . DS . '_tmp_' . $workerId . '_' . $type . '.tmp'; 146 | file_put_contents($filename, serialize($data)); 147 | } 148 | 149 | public static function load($workerId, $type) 150 | { 151 | $filename = ZPHP::getRootPath() . DS . 'tmp' . DS . '_tmp_' . $workerId . '_' . $type . '.tmp'; 152 | if (is_file($filename)) { 153 | $data = unserialize(file_get_contents($filename)); 154 | unlink($filename); 155 | return $data; 156 | } 157 | return false; 158 | } 159 | } -------------------------------------------------------------------------------- /ZPHP/Socket/Callback/Swoole.php: -------------------------------------------------------------------------------- 1 | master_pid); 34 | $pidPath = ZConfig::getField('project', 'pid_path'); 35 | if (!empty($pidPath)) { 36 | file_put_contents($pidPath . DS . ZConfig::get('project_name') . '_master.pid', $server->master_pid); 37 | } 38 | if ('Ant' == ZConfig::get('server_mode')) { 39 | $callback = ZConfig::getField('soa', 'register_callback', 'socket\Handler\Soa::register'); 40 | } else { 41 | $callback = ZConfig::getField('soa', 'register_callback'); 42 | } 43 | if (!empty($callback)) { 44 | echo call_user_func($callback, $server); 45 | } 46 | } 47 | 48 | /** 49 | * @throws \Exception 50 | */ 51 | public function onShutDown() 52 | { 53 | $server = func_get_args()[0]; 54 | $pidPath = ZConfig::getField('project', 'pid_path'); 55 | if (!empty($pidPath)) { 56 | $filename = $pidPath . DS . ZConfig::get('project_name') . '_master.pid'; 57 | if (is_file($filename)) { 58 | unlink($filename); 59 | } 60 | $filename = $pidPath . DS . ZConfig::get('project_name') . '_manager.pid'; 61 | if (is_file($filename)) { 62 | unlink($filename); 63 | } 64 | } 65 | if ('Ant' == ZConfig::get('server_mode')) { 66 | $callback = ZConfig::getField('soa', 'drop_callback', 'socket\Handler\Soa::drop'); 67 | } else { 68 | $callback = ZConfig::getField('soa', 'drop_callback'); 69 | } 70 | if (!empty($callback)) { 71 | echo call_user_func($callback, $server); 72 | } 73 | } 74 | 75 | /** 76 | * @param $server 77 | * @throws \Exception 78 | * @desc 服务启动,设置进程名 79 | */ 80 | public function onManagerStart($server) 81 | { 82 | swoole_set_process_name(ZConfig::get('project_name') . 83 | ZConfig::get('server_mode') . ' server manager:' . $server->manager_pid); 84 | $pidPath = ZConfig::getField('project', 'pid_path'); 85 | if (!empty($pidPath)) { 86 | file_put_contents($pidPath . DS . ZConfig::get('project_name') . '_manager.pid', $server->manager_pid); 87 | } 88 | } 89 | 90 | /** 91 | * @param $server 92 | * @throws \Exception 93 | * @desc 服务关闭,删除进程id文件 94 | */ 95 | public function onManagerStop($server) 96 | { 97 | $pidPath = ZConfig::getField('project', 'pid_path'); 98 | if (!empty($pidPath)) { 99 | $filename = $pidPath . DS . ZConfig::get('project_name') . '_manager.pid'; 100 | if (is_file($filename)) { 101 | unlink($filename); 102 | } 103 | } 104 | } 105 | 106 | public function onWorkerStart($server, $workerId) 107 | { 108 | $workNum = ZConfig::getField('socket', 'worker_num'); 109 | if ($workerId >= $workNum) { 110 | swoole_set_process_name(ZConfig::get('project_name') . " server tasker num: " . ($server->worker_id - $workNum) . " pid " . $server->worker_pid); 111 | } else { 112 | swoole_set_process_name(ZConfig::get('project_name') . " server worker num: {$server->worker_id} pid " . $server->worker_pid); 113 | } 114 | 115 | if (function_exists('opcache_reset')) { 116 | opcache_reset(); 117 | } 118 | Protocol\Request::setSocket($server); 119 | } 120 | 121 | public function onWorkerStop($server, $workerId) 122 | { 123 | } 124 | 125 | public function onWorkerError($server, $workerId, $workerPid, $errorCode) 126 | { 127 | 128 | } 129 | 130 | 131 | public function onConnect() 132 | { 133 | 134 | } 135 | 136 | public function doReceive($server, $fd, $from_id, $data) 137 | { 138 | Protocol\Request::setFd($fd); 139 | $this->onReceive($server, $fd, $from_id, $data); 140 | } 141 | 142 | abstract public function onReceive(); 143 | 144 | public function onPacket($server, $data, $clientInfo) 145 | { 146 | 147 | } 148 | 149 | public function onClose() 150 | { 151 | 152 | } 153 | 154 | 155 | public function onTask($server, $taskId, $fromId, $data) 156 | { 157 | 158 | } 159 | 160 | public function onFinish($server, $taskId, $data) 161 | { 162 | 163 | } 164 | 165 | public function onPipeMessage($server, $fromWorerId, $data) 166 | { 167 | 168 | } 169 | 170 | 171 | } 172 | --------------------------------------------------------------------------------