├── application ├── .htaccess ├── socketio │ ├── common.php │ ├── controller │ │ ├── Index.php │ │ └── Server.php │ ├── model │ │ └── Msg.php │ └── view │ │ └── index │ │ ├── chat.html │ │ └── index.html ├── common.php ├── command.php ├── provider.php ├── tags.php ├── build.php └── index │ └── controller │ └── Index.php ├── extend └── .gitignore ├── runtime └── .gitignore ├── public ├── robots.txt ├── favicon.ico ├── .htaccess ├── router.php ├── index.php ├── server.php └── static │ └── main.css ├── .gitignore ├── TODO.md ├── config ├── socketio │ └── param.php ├── trace.php ├── middleware.php ├── console.php ├── cache.php ├── session.php ├── cookie.php ├── log.php ├── template.php ├── database.php └── app.php ├── composer.json ├── think ├── route └── route.php ├── msg.sql ├── LICENSE.txt ├── .travis.yml ├── README.md └── composer.lock /application/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all -------------------------------------------------------------------------------- /extend/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | /vendor 4 | *.log 5 | thinkphp 6 | .env -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsu1943/thinksocketio/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - 聊天室人数统计(已完成2019-06-19) 2 | - 私聊消息提醒(已完成2019-06-19) 3 | - 自定义用户昵称(已完成2019-06-19) 4 | - 历史消息查看 5 | - 输入中状态提示 -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Options +FollowSymlinks -Multiviews 3 | RewriteEngine On 4 | 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] 8 | 9 | -------------------------------------------------------------------------------- /config/socketio/param.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'port' => 2021, // 服务端端口号 6 | 'apiHost' => 'http://127.0.0.1:2121', // http api监听地址 7 | ], 8 | 9 | 'save_msg' => true, // 是否将消息存储到mysql,请保证mysql正常连接,并导入项目根目录socketio.sql 10 | ]; -------------------------------------------------------------------------------- /application/socketio/common.php: -------------------------------------------------------------------------------- 1 | 0; $i--) { 16 | $string .= $char[mt_rand(0, strlen($char) - 1)]; 17 | } 18 | 19 | return $string; 20 | } -------------------------------------------------------------------------------- /application/common.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // 应用公共文件 13 | -------------------------------------------------------------------------------- /application/command.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | return []; 13 | -------------------------------------------------------------------------------- /application/provider.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // 应用容器绑定定义 13 | return [ 14 | ]; 15 | -------------------------------------------------------------------------------- /public/router.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | // $Id$ 12 | 13 | if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { 14 | return false; 15 | } else { 16 | require __DIR__ . "/index.php"; 17 | } 18 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "topthink/think", 3 | "description": "the new thinkphp framework", 4 | "type": "project", 5 | "keywords": [ 6 | "framework", 7 | "thinkphp", 8 | "ORM" 9 | ], 10 | "homepage": "http://thinkphp.cn/", 11 | "license": "Apache-2.0", 12 | "authors": [ 13 | { 14 | "name": "liu21st", 15 | "email": "liu21st@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.6.0", 20 | "topthink/framework": "5.1.*", 21 | "workerman/phpsocket.io": "^1.1" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "app\\": "application" 26 | } 27 | }, 28 | "extra": { 29 | "think-path": "thinkphp" 30 | }, 31 | "config": { 32 | "preferred-install": "dist" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // [ 应用入口文件 ] 13 | namespace think; 14 | 15 | // 加载基础文件 16 | require __DIR__ . '/../thinkphp/base.php'; 17 | 18 | // 支持事先使用静态方法设置Request对象和Config对象 19 | 20 | // 执行应用并响应 21 | Container::get('app')->run()->send(); 22 | -------------------------------------------------------------------------------- /think: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 11 | // +---------------------------------------------------------------------- 12 | 13 | namespace think; 14 | 15 | // 加载基础文件 16 | require __DIR__ . '/thinkphp/base.php'; 17 | 18 | // 应用初始化 19 | Container::get('app')->path(__DIR__ . '/application/')->initialize(); 20 | 21 | // 控制台初始化 22 | Console::init(); -------------------------------------------------------------------------------- /route/route.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | 13 | Route::get('hello/:name', 'index/index/hello'); 14 | 15 | Route::rule('socketio', 'socketio/index/index'); 16 | Route::rule('chat', 'socketio/index/chat'); 17 | Route::rule('system', 'socketio/index/system'); 18 | 19 | return [ 20 | 21 | ]; 22 | -------------------------------------------------------------------------------- /public/server.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // [ 应用入口文件 ] 13 | namespace think; 14 | 15 | // 加载基础文件 16 | require __DIR__ . '/../thinkphp/base.php'; 17 | 18 | // 支持事先使用静态方法设置Request对象和Config对象 19 | 20 | // 执行应用并响应(绑定) 21 | Container::get('app')->bind('socketio/Server/index')->run()->send(); -------------------------------------------------------------------------------- /config/trace.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | Trace设置 开启 app_trace 后 有效 14 | // +---------------------------------------------------------------------- 15 | return [ 16 | // 内置Html Console 支持扩展 17 | 'type' => 'Html', 18 | ]; 19 | -------------------------------------------------------------------------------- /config/middleware.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 中间件配置 14 | // +---------------------------------------------------------------------- 15 | return [ 16 | // 默认中间件命名空间 17 | 'default_namespace' => 'app\\http\\middleware\\', 18 | ]; 19 | -------------------------------------------------------------------------------- /application/socketio/controller/Index.php: -------------------------------------------------------------------------------- 1 | $username]); 29 | } 30 | 31 | public function system() 32 | { 33 | $data = Request::param(); 34 | $to = $data['to'] ?? ''; 35 | $content = $data['content'] ?? ''; 36 | $res = Msg::send($to, $content); 37 | return $res == 'ok' ? '系统消息推送成功' : '系统消息推送失败'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /config/console.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 控制台配置 14 | // +---------------------------------------------------------------------- 15 | return [ 16 | 'name' => 'Think Console', 17 | 'version' => '0.1', 18 | 'user' => null, 19 | ]; 20 | -------------------------------------------------------------------------------- /public/static/main.css: -------------------------------------------------------------------------------- 1 | .private-chat { 2 | color: #880000; 3 | } 4 | .open-chat { 5 | color: #4288ce; 6 | } 7 | 8 | .system-chat { 9 | color: blueviolet; 10 | } 11 | 12 | .user-name{ 13 | color: green; 14 | } 15 | 16 | body { 17 | width: 90%; 18 | margin: 5% auto; 19 | } 20 | 21 | .fright { 22 | float: right; 23 | } 24 | 25 | .to { 26 | color: brown; 27 | } 28 | 29 | #chats-list{ 30 | margin-left: -1em; 31 | } 32 | 33 | #chats-list li{ 34 | line-height: 2em; 35 | list-style: none; 36 | } 37 | 38 | /* #chats-list li span{ 39 | float: right; 40 | } */ 41 | 42 | .me-say{ 43 | float: right; 44 | color: #4288ce; 45 | } 46 | 47 | .clear { 48 | clear: both; 49 | } 50 | 51 | .header{ 52 | width: 50%; 53 | text-align: center; 54 | margin-left: 25%; 55 | } 56 | 57 | .message{ 58 | font-size: 1.5em; 59 | position: fixed; 60 | width: 90%; 61 | left: 5%; 62 | bottom: 1%; 63 | } -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 缓存设置 14 | // +---------------------------------------------------------------------- 15 | 16 | return [ 17 | // 驱动方式 18 | 'type' => 'File', 19 | // 缓存保存目录 20 | 'path' => '', 21 | // 缓存前缀 22 | 'prefix' => '', 23 | // 缓存有效期 0表示永久缓存 24 | 'expire' => 0, 25 | ]; 26 | -------------------------------------------------------------------------------- /application/tags.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // 应用行为扩展定义文件 13 | return [ 14 | // 应用初始化 15 | 'app_init' => [], 16 | // 应用开始 17 | 'app_begin' => [], 18 | // 模块初始化 19 | 'module_init' => [], 20 | // 操作开始执行 21 | 'action_begin' => [], 22 | // 视图内容过滤 23 | 'view_filter' => [], 24 | // 日志写入 25 | 'log_write' => [], 26 | // 应用结束 27 | 'app_end' => [], 28 | ]; 29 | -------------------------------------------------------------------------------- /application/build.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | return [ 13 | // 生成应用公共文件 14 | '__file__' => ['common.php'], 15 | // 定义socketio模块的自动生成 16 | 'socketio' => [ 17 | '__file__' => ['common.php'], 18 | '__dir__' => ['controller', 'model', 'view'], 19 | 'controller' => ['Index', 'Server'], 20 | 'model' => [], 21 | 'view' => ['index/index'], 22 | ], 23 | // 其他更多的模块定义 24 | ]; 25 | -------------------------------------------------------------------------------- /application/index/controller/Index.php: -------------------------------------------------------------------------------- 1 | *{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }

:)

ThinkPHP V5.1
12载初心不改(2006-2018) - 你值得信赖的PHP框架

'; 9 | } 10 | 11 | public function hello($name = 'ThinkPHP5') 12 | { 13 | return 'hello,' . $name; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 会话设置 14 | // +---------------------------------------------------------------------- 15 | 16 | return [ 17 | 'id' => '', 18 | // SESSION_ID的提交变量,解决flash上传跨域 19 | 'var_session_id' => '', 20 | // SESSION 前缀 21 | 'prefix' => 'think', 22 | // 驱动方式 支持redis memcache memcached 23 | 'type' => '', 24 | // 是否自动开启 SESSION 25 | 'auto_start' => true, 26 | ]; 27 | -------------------------------------------------------------------------------- /config/cookie.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | Cookie设置 14 | // +---------------------------------------------------------------------- 15 | return [ 16 | // cookie 名称前缀 17 | 'prefix' => '', 18 | // cookie 保存时间 19 | 'expire' => 0, 20 | // cookie 保存路径 21 | 'path' => '/', 22 | // cookie 有效域名 23 | 'domain' => '', 24 | // cookie 启用安全传输 25 | 'secure' => false, 26 | // httponly设置 27 | 'httponly' => '', 28 | // 是否使用 setcookie 29 | 'setcookie' => true, 30 | ]; 31 | -------------------------------------------------------------------------------- /config/log.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 日志设置 14 | // +---------------------------------------------------------------------- 15 | return [ 16 | // 日志记录方式,内置 file socket 支持扩展 17 | 'type' => 'File', 18 | // 日志保存目录 19 | 'path' => '../logs/', 20 | // 日志记录级别 21 | 'level' => [], 22 | // 单文件日志写入 23 | 'single' => false, 24 | // 独立日志级别 25 | 'apart_level' => [], 26 | // 最大日志文件数量 27 | 'max_files' => 30, 28 | // 是否关闭日志写入 29 | 'close' => false, 30 | ]; 31 | -------------------------------------------------------------------------------- /application/socketio/model/Msg.php: -------------------------------------------------------------------------------- 1 | "publish", 34 | "content" => $content ?: '推送消息为空', 35 | "to" => $to, 36 | ); 37 | $ch = curl_init(); 38 | curl_setopt($ch, CURLOPT_URL, $push_api_url); 39 | curl_setopt($ch, CURLOPT_POST, 1); 40 | curl_setopt($ch, CURLOPT_HEADER, 0); 41 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 42 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); 43 | curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:")); 44 | $return = curl_exec($ch); 45 | curl_close($ch); 46 | return $return; 47 | } 48 | } -------------------------------------------------------------------------------- /msg.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 100137 7 | Source Host : 127.0.0.1:3306 8 | Source Schema : socket 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 100137 12 | File Encoding : 65001 13 | 14 | Date: 19/12/2019 11:00:05 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for msg 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `msg`; 24 | CREATE TABLE `msg` ( 25 | `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 26 | `msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '消息', 27 | `from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来自用户', 28 | `to` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送给用户', 29 | `type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '消息类型', 30 | `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间', 31 | PRIMARY KEY (`id`) USING BTREE 32 | ) ENGINE = InnoDB AUTO_INCREMENT = 216 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '消息记录' ROW_FORMAT = Compact; 33 | 34 | SET FOREIGN_KEY_CHECKS = 1; 35 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 3 | 版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn) 4 | All rights reserved。 5 | ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 6 | 7 | Apache Licence是著名的非盈利开源组织Apache采用的协议。 8 | 该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, 9 | 允许代码修改,再作为开源或商业软件发布。需要满足 10 | 的条件: 11 | 1. 需要给代码的用户一份Apache Licence ; 12 | 2. 如果你修改了代码,需要在被修改的文件中说明; 13 | 3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 14 | 带有原来代码中的协议,商标,专利声明和其他原来作者规 15 | 定需要包含的说明; 16 | 4. 如果再发布的产品中包含一个Notice文件,则在Notice文 17 | 件中需要带有本协议内容。你可以在Notice中增加自己的 18 | 许可,但不可以表现为对Apache Licence构成更改。 19 | 具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /config/template.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 模板设置 14 | // +---------------------------------------------------------------------- 15 | 16 | return [ 17 | // 模板引擎类型 支持 php think 支持扩展 18 | 'type' => 'Think', 19 | // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 20 | 'auto_rule' => 1, 21 | // 模板路径 22 | 'view_path' => '', 23 | // 模板后缀 24 | 'view_suffix' => 'html', 25 | // 模板文件名分隔符 26 | 'view_depr' => DIRECTORY_SEPARATOR, 27 | // 模板引擎普通标签开始标记 28 | 'tpl_begin' => '{', 29 | // 模板引擎普通标签结束标记 30 | 'tpl_end' => '}', 31 | // 标签库标签开始标记 32 | 'taglib_begin' => '{', 33 | // 标签库标签结束标记 34 | 'taglib_end' => '}', 35 | 36 | 'tpl_replace_string' => [ 37 | '__STATIC__' => '/static' 38 | ], 39 | ]; 40 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | return [ 13 | // 数据库类型 14 | 'type' => 'mysql', 15 | // 服务器地址 16 | 'hostname' => 'localhost', 17 | // 数据库名 18 | 'database' => 'socket', 19 | // 用户名 20 | 'username' => 'root', 21 | // 密码 22 | 'password' => 'root', 23 | // 端口 24 | 'hostport' => '3306', 25 | // 连接dsn 26 | 'dsn' => '', 27 | // 数据库连接参数 28 | 'params' => [], 29 | // 数据库编码默认采用utf8 30 | 'charset' => 'utf8', 31 | // 数据库表前缀 32 | 'prefix' => '', 33 | // 数据库调试模式 34 | 'debug' => true, 35 | // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 36 | 'deploy' => 0, 37 | // 数据库读写是否分离 主从式有效 38 | 'rw_separate' => false, 39 | // 读写分离后 主服务器数量 40 | 'master_num' => 1, 41 | // 指定从服务器序号 42 | 'slave_no' => '', 43 | // 自动读取主库数据 44 | 'read_master' => false, 45 | // 是否严格检查字段是否存在 46 | 'fields_strict' => true, 47 | // 数据集返回类型 48 | 'resultset_type' => 'array', 49 | // 自动写入时间戳字段 50 | 'auto_timestamp' => false, 51 | // 时间字段取出后的默认时间格式 52 | 'datetime_format' => 'Y-m-d H:i:s', 53 | // 是否需要进行SQL性能分析 54 | 'sql_explain' => false, 55 | // Builder类 56 | 'builder' => '', 57 | // Query类 58 | 'query' => '\\think\\db\\Query', 59 | // 是否需要断线重连 60 | 'break_reconnect' => false, 61 | // 断线标识字符串 62 | 'break_match_str' => [], 63 | ]; 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: php 4 | 5 | branches: 6 | only: 7 | - stable 8 | 9 | cache: 10 | directories: 11 | - $HOME/.composer/cache 12 | 13 | before_install: 14 | - composer self-update 15 | 16 | install: 17 | - composer install --no-dev --no-interaction --ignore-platform-reqs 18 | - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip . 19 | - composer require --update-no-dev --no-interaction "topthink/think-image:^1.0" 20 | - composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0" 21 | - composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0" 22 | - composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0" 23 | - composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0" 24 | - composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0" 25 | - composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0" 26 | - composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0" 27 | - composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0" 28 | - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip . 29 | 30 | script: 31 | - php think unit 32 | 33 | deploy: 34 | provider: releases 35 | api_key: 36 | secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw= 37 | file: 38 | - ThinkPHP_Core.zip 39 | - ThinkPHP_Full.zip 40 | skip_cleanup: true 41 | on: 42 | tags: true 43 | -------------------------------------------------------------------------------- /application/socketio/view/index/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 与{$to}私聊 7 | 8 | 9 |

{$to}

10 | 11 |

当前用户【返回广场

13 | 14 | 消息: 15 | 16 | 17 |

消息列表:

18 |
19 | 22 |
23 | 24 | 25 | 26 | 27 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 一个使用PHPSocket.IOThinkPHP5.1,以及JQ实现的聊天室,包括功能有: 4 | 5 | - 公频广场聊天 6 | - 自定义用户名 7 | - 一对一私聊 8 | - 公频中私聊信息提醒 9 | - 新用户加入以及离开提醒 10 | - 在线用户列表,人数统计 11 | - 系统主动推送广播,或向指定用户推送消息 12 | 13 | ## 截图 14 | 15 | 广场公频聊天: 16 | 广场公频聊天 17 | 一对一私聊: 18 | 一对一私聊 19 | 广播推送系统消息: 20 | 广播推送系统消息 21 | 指定用户推送消息: 22 | 指定用户推送消息 23 | 24 | ## 使用说明 25 | 26 | 以下说明假定已经为项目`public`目录绑定了域名`test.com`并正确部署服务器,访问`test.com`能看到TP5默认首页。 27 | 28 | 如果修改了配置或者代码,请重新运行服务端,否则代码不生效。 29 | 30 | ### 安装 31 | 32 | ```bash 33 | git clone git@github.com:hsu1943/thinksocketio.git 34 | cd thinksocketio 35 | composer install -vvv 36 | ``` 37 | 38 | ### 配置 39 | 40 | 模板文件`/application/socketio/view/index/index.html`和`/application/socketio/view/index/chat.html`中`socket`修改为你的`socket`服务端地址,默认测试端口2021,端口号可以在`/config/socketio/param.php`中配置。这里是本机测试,用`http://127.0.0.1:2021`。 41 | 42 | ```bash 43 | var socket = io('http://127.0.0.1:2021'); 44 | ``` 45 | ### 使用数据库记录消息: 46 | 47 | 如果你需要使用数据库存储消息,按照下面的步骤打开配置,打开配置后系统会根据昵称将所有聊天记录写入数据库`msg`表中,包括主动推送的消息; 48 | 49 | 1. 在`config/database.php`中配置数据库,保证数据库能正确连接; 50 | 2. 导入根目录下`msg.sql`到数据库; 51 | 3. 在`config/socketio/param.php`中将`save_msg`修改为`true`(默认是`false`,不写入到数据库); 52 | 53 | 这里说明一下,请保证数据库能正确连接并且里面有正确的表结构(第二步导入表)再进行第三步配置。 54 | 55 | ### 主动推送系统消息接口 56 | 57 | 修改配置文件`/config/socketio/param.php`中的配置为监听消息推送地址,这里本地测试,使用本地2121端口; 58 | 59 | ```bash 60 | return [ 61 | 'ws' => [ 62 | 'apiHost' => 'http://127.0.0.1:2121', 63 | ], 64 | ]; 65 | ``` 66 | 67 | 该地址即系统推送消息地址,参数: 68 | 69 | ```html 70 | to:接收人 71 | content:消息 72 | ``` 73 | 74 | 两种用法: 75 | 76 | 1. 其他项目POST或GET请求接口即可推送消息 77 | 78 | ```html 79 | 向username推送系统消息 80 | http://test.com/system?to=username&content=系统推送消息测试 81 | 广播消息 82 | http://test.com/system?content=系统推送消息测试 83 | ``` 84 | 85 | `http://test.com/system`这是本项目使用上面的监听地址做的一个消息推送demo,详情看源代码。 86 | 87 | 2. 本项目中推送系统消息: 88 | 89 | 已将推送封装在Msg的模型中,使用: 90 | 91 | ```php 92 | $res = Msg::send($to, $content); 93 | return $res == 'ok' ? '系统消息推送成功' : '系统消息推送失败'; 94 | ``` 95 | 96 | ## 测试 97 | 98 | 运行服务端: 99 | 100 | ```bash 101 | php ./public/server.php 102 | ``` 103 | 这里可以将输出写到某个日志文件中,或者使用`supervisor`来管理服务端。 104 | 105 | 访问以下地址即可进入公频: 106 | 107 | ```bash 108 | http://test.com/socketio 109 | ``` 110 | 111 | 点击消息列表中的用户名即可进入私聊。 112 | 113 | ## 更新 114 | 115 | * 2019-12-19 增加服务端的输出,以及端口配置项,保存数据库加上错误处理,更新项目README; 116 | * 2019-06-19 增加在线人数统计,在线用户列表,修改昵称,添加系统主动推送接口(广播或私信); 117 | 118 | ## 开发记录 119 | 120 | 以下两篇文章是在开发过程中的记录,代码不是最新,最新代码以本项目`github`为准,有问题可以去文章里留言。 121 | 122 | [ThinkPHP 5.1+PHPSocket.IO实现websocket搭建聊天室+私聊](https://beltxman.com/archives/2329.html "ThinkPHP 5.1+PHPSocket.IO实现websocket搭建聊天室+私聊") 123 | 124 | [ThinkPHP 5.1下使用PHPSocket.IO实现websocket通讯](https://beltxman.com/archives/1885.html "ThinkPHP 5.1下使用PHPSocket.IO实现websocket通讯") 125 | 126 | ## 感谢 127 | 128 | * top-think/framework 129 | * walkor/phpsocket.io 130 | * walkor/web-msg-sender -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // +---------------------------------------------------------------------- 13 | // | 应用设置 14 | // +---------------------------------------------------------------------- 15 | 16 | return [ 17 | // 应用名称 18 | 'app_name' => '', 19 | // 应用地址 20 | 'app_host' => '', 21 | // 应用调试模式 22 | 'app_debug' => true, 23 | // 应用Trace 24 | 'app_trace' => false, 25 | // 是否支持多模块 26 | 'app_multi_module' => true, 27 | // 入口自动绑定模块 28 | 'auto_bind_module' => false, 29 | // 注册的根命名空间 30 | 'root_namespace' => [], 31 | // 默认输出类型 32 | 'default_return_type' => 'html', 33 | // 默认AJAX 数据返回格式,可选json xml ... 34 | 'default_ajax_return' => 'json', 35 | // 默认JSONP格式返回的处理方法 36 | 'default_jsonp_handler' => 'jsonpReturn', 37 | // 默认JSONP处理方法 38 | 'var_jsonp_handler' => 'callback', 39 | // 默认时区 40 | 'default_timezone' => 'Asia/Shanghai', 41 | // 是否开启多语言 42 | 'lang_switch_on' => false, 43 | // 默认全局过滤方法 用逗号分隔多个 44 | 'default_filter' => '', 45 | // 默认语言 46 | 'default_lang' => 'zh-cn', 47 | // 应用类库后缀 48 | 'class_suffix' => false, 49 | // 控制器类后缀 50 | 'controller_suffix' => false, 51 | 52 | // +---------------------------------------------------------------------- 53 | // | 模块设置 54 | // +---------------------------------------------------------------------- 55 | 56 | // 默认模块名 57 | 'default_module' => 'index', 58 | // 禁止访问模块 59 | 'deny_module_list' => ['common'], 60 | // 默认控制器名 61 | 'default_controller' => 'Index', 62 | // 默认操作名 63 | 'default_action' => 'index', 64 | // 默认验证器 65 | 'default_validate' => '', 66 | // 默认的空模块名 67 | 'empty_module' => '', 68 | // 默认的空控制器名 69 | 'empty_controller' => 'Error', 70 | // 操作方法前缀 71 | 'use_action_prefix' => false, 72 | // 操作方法后缀 73 | 'action_suffix' => '', 74 | // 自动搜索控制器 75 | 'controller_auto_search' => false, 76 | 77 | // +---------------------------------------------------------------------- 78 | // | URL设置 79 | // +---------------------------------------------------------------------- 80 | 81 | // PATHINFO变量名 用于兼容模式 82 | 'var_pathinfo' => 's', 83 | // 兼容PATH_INFO获取 84 | 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], 85 | // pathinfo分隔符 86 | 'pathinfo_depr' => '/', 87 | // HTTPS代理标识 88 | 'https_agent_name' => '', 89 | // IP代理获取标识 90 | 'http_agent_ip' => 'X-REAL-IP', 91 | // URL伪静态后缀 92 | 'url_html_suffix' => 'html', 93 | // URL普通方式参数 用于自动生成 94 | 'url_common_param' => false, 95 | // URL参数方式 0 按名称成对解析 1 按顺序解析 96 | 'url_param_type' => 0, 97 | // 是否开启路由延迟解析 98 | 'url_lazy_route' => false, 99 | // 是否强制使用路由 100 | 'url_route_must' => false, 101 | // 合并路由规则 102 | 'route_rule_merge' => false, 103 | // 路由是否完全匹配 104 | 'route_complete_match' => false, 105 | // 使用注解路由 106 | 'route_annotation' => false, 107 | // 域名根,如thinkphp.cn 108 | 'url_domain_root' => '', 109 | // 是否自动转换URL中的控制器和操作名 110 | 'url_convert' => true, 111 | // 默认的访问控制器层 112 | 'url_controller_layer' => 'controller', 113 | // 表单请求类型伪装变量 114 | 'var_method' => '_method', 115 | // 表单ajax伪装变量 116 | 'var_ajax' => '_ajax', 117 | // 表单pjax伪装变量 118 | 'var_pjax' => '_pjax', 119 | // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 120 | 'request_cache' => false, 121 | // 请求缓存有效期 122 | 'request_cache_expire' => null, 123 | // 全局请求缓存排除规则 124 | 'request_cache_except' => [], 125 | // 是否开启路由缓存 126 | 'route_check_cache' => false, 127 | // 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5 128 | 'route_check_cache_key' => '', 129 | // 路由缓存类型及参数 130 | 'route_cache_option' => [], 131 | 132 | // 默认跳转页面对应的模板文件 133 | 'dispatch_success_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl', 134 | 'dispatch_error_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl', 135 | 136 | // 异常页面的模板文件 137 | 'exception_tmpl' => Env::get('think_path') . 'tpl/think_exception.tpl', 138 | 139 | // 错误显示信息,非调试模式有效 140 | 'error_message' => '页面错误!请稍后再试~', 141 | // 显示错误信息 142 | 'show_error_msg' => false, 143 | // 异常处理handle类 留空使用 \think\exception\Handle 144 | 'exception_handle' => '', 145 | 146 | ]; 147 | -------------------------------------------------------------------------------- /application/socketio/view/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 测试WebSocket聊天室 7 | 8 | 9 |

广场

10 | 11 |

当前用户【

12 | 13 | 18 |

19 | 消息: 20 | 21 | 22 |
23 |
24 |

消息列表

25 | 28 |
29 |
30 |

动态

31 | 34 |

系统消息

35 | 38 |

在线(

39 |
40 | 41 |
42 |
43 |
44 | 45 | 46 | 47 | 194 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "c949e593f4d8e034a6be41c92b7b4871", 8 | "packages": [ 9 | { 10 | "name": "topthink/framework", 11 | "version": "v5.1.18", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/top-think/framework.git", 15 | "reference": "833fcaf0f29f23bdceaae655f64d10c18b9bf562" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://files.phpcomposer.com/files/top-think/framework/833fcaf0f29f23bdceaae655f64d10c18b9bf562.zip", 20 | "reference": "833fcaf0f29f23bdceaae655f64d10c18b9bf562", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.6.0", 25 | "topthink/think-installer": "2.*" 26 | }, 27 | "require-dev": { 28 | "johnkary/phpunit-speedtrap": "^1.0", 29 | "mikey179/vfsstream": "~1.6", 30 | "phpdocumentor/reflection-docblock": "^2.0", 31 | "phploc/phploc": "2.*", 32 | "phpunit/phpunit": "^5.0|^6.0", 33 | "sebastian/phpcpd": "2.*", 34 | "squizlabs/php_codesniffer": "2.*" 35 | }, 36 | "type": "think-framework", 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "Apache-2.0" 40 | ], 41 | "authors": [ 42 | { 43 | "name": "liu21st", 44 | "email": "liu21st@gmail.com" 45 | }, 46 | { 47 | "name": "yunwuxin", 48 | "email": "448901948@qq.com" 49 | } 50 | ], 51 | "description": "the new thinkphp framework", 52 | "homepage": "http://thinkphp.cn/", 53 | "keywords": [ 54 | "framework", 55 | "orm", 56 | "thinkphp" 57 | ], 58 | "time": "2018-07-02T05:29:17+00:00" 59 | }, 60 | { 61 | "name": "topthink/think-installer", 62 | "version": "v2.0.0", 63 | "source": { 64 | "type": "git", 65 | "url": "https://github.com/top-think/think-installer.git", 66 | "reference": "f5400a12c60e513911aef41fe443fa6920952675" 67 | }, 68 | "dist": { 69 | "type": "zip", 70 | "url": "https://files.phpcomposer.com/files/top-think/think-installer/f5400a12c60e513911aef41fe443fa6920952675.zip", 71 | "reference": "f5400a12c60e513911aef41fe443fa6920952675", 72 | "shasum": "" 73 | }, 74 | "require": { 75 | "composer-plugin-api": "^1.0" 76 | }, 77 | "require-dev": { 78 | "composer/composer": "1.0.*@dev" 79 | }, 80 | "type": "composer-plugin", 81 | "extra": { 82 | "class": "think\\composer\\Plugin" 83 | }, 84 | "autoload": { 85 | "psr-4": { 86 | "think\\composer\\": "src" 87 | } 88 | }, 89 | "notification-url": "https://packagist.org/downloads/", 90 | "license": [ 91 | "Apache-2.0" 92 | ], 93 | "authors": [ 94 | { 95 | "name": "yunwuxin", 96 | "email": "448901948@qq.com" 97 | } 98 | ], 99 | "time": "2018-05-11T06:45:42+00:00" 100 | }, 101 | { 102 | "name": "workerman/channel", 103 | "version": "v1.0.5", 104 | "source": { 105 | "type": "git", 106 | "url": "https://github.com/walkor/Channel.git", 107 | "reference": "0836a9a413c6e8425ee36307d95e2e49cc380f50" 108 | }, 109 | "dist": { 110 | "type": "zip", 111 | "url": "https://files.phpcomposer.com/files/walkor/Channel/0836a9a413c6e8425ee36307d95e2e49cc380f50.zip", 112 | "reference": "0836a9a413c6e8425ee36307d95e2e49cc380f50", 113 | "shasum": "" 114 | }, 115 | "require": { 116 | "workerman/workerman": ">=3.3.0" 117 | }, 118 | "type": "library", 119 | "autoload": { 120 | "psr-4": { 121 | "Channel\\": "./src" 122 | } 123 | }, 124 | "notification-url": "https://packagist.org/downloads/", 125 | "license": [ 126 | "MIT" 127 | ], 128 | "homepage": "http://www.workerman.net", 129 | "time": "2018-07-02T02:42:37+00:00" 130 | }, 131 | { 132 | "name": "workerman/phpsocket.io", 133 | "version": "v1.1.9", 134 | "source": { 135 | "type": "git", 136 | "url": "https://github.com/walkor/phpsocket.io.git", 137 | "reference": "8ee5fd56ea364e99c6428dd5df04b730f92e7d91" 138 | }, 139 | "dist": { 140 | "type": "zip", 141 | "url": "https://files.phpcomposer.com/files/walkor/phpsocket.io/8ee5fd56ea364e99c6428dd5df04b730f92e7d91.zip", 142 | "reference": "8ee5fd56ea364e99c6428dd5df04b730f92e7d91", 143 | "shasum": "" 144 | }, 145 | "require": { 146 | "workerman/channel": ">=1.0.0", 147 | "workerman/workerman": ">=3.1.8" 148 | }, 149 | "type": "library", 150 | "autoload": { 151 | "psr-4": { 152 | "PHPSocketIO\\": "./src" 153 | } 154 | }, 155 | "notification-url": "https://packagist.org/downloads/", 156 | "license": [ 157 | "MIT" 158 | ], 159 | "homepage": "http://www.workerman.net", 160 | "keywords": [ 161 | "Socket.io" 162 | ], 163 | "time": "2018-04-15T14:03:37+00:00" 164 | }, 165 | { 166 | "name": "workerman/workerman", 167 | "version": "v3.5.11", 168 | "source": { 169 | "type": "git", 170 | "url": "https://github.com/walkor/Workerman.git", 171 | "reference": "c83e189b5855d91f99a7d01ac58f5bbc7161b5e5" 172 | }, 173 | "dist": { 174 | "type": "zip", 175 | "url": "https://files.phpcomposer.com/files/walkor/Workerman/c83e189b5855d91f99a7d01ac58f5bbc7161b5e5.zip", 176 | "reference": "c83e189b5855d91f99a7d01ac58f5bbc7161b5e5", 177 | "shasum": "" 178 | }, 179 | "require": { 180 | "php": ">=5.3" 181 | }, 182 | "suggest": { 183 | "ext-event": "For better performance. " 184 | }, 185 | "type": "library", 186 | "autoload": { 187 | "psr-4": { 188 | "Workerman\\": "./" 189 | } 190 | }, 191 | "notification-url": "https://packagist.org/downloads/", 192 | "license": [ 193 | "MIT" 194 | ], 195 | "authors": [ 196 | { 197 | "name": "walkor", 198 | "email": "walkor@workerman.net", 199 | "homepage": "http://www.workerman.net", 200 | "role": "Developer" 201 | } 202 | ], 203 | "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", 204 | "homepage": "http://www.workerman.net", 205 | "keywords": [ 206 | "asynchronous", 207 | "event-loop" 208 | ], 209 | "time": "2018-06-07T09:36:14+00:00" 210 | } 211 | ], 212 | "packages-dev": [], 213 | "aliases": [], 214 | "minimum-stability": "stable", 215 | "stability-flags": [], 216 | "prefer-stable": false, 217 | "prefer-lowest": false, 218 | "platform": { 219 | "php": ">=5.6.0" 220 | }, 221 | "platform-dev": [] 222 | } 223 | -------------------------------------------------------------------------------- /application/socketio/controller/Server.php: -------------------------------------------------------------------------------- 1 | saveMsg = Config::get('param.save_msg'); 31 | } 32 | 33 | 34 | public function index() 35 | { 36 | $port = Config::get('param.ws.port'); 37 | $io = new SocketIO($port); 38 | $io->on('connection', function ($socket) use ($io) { 39 | $socket->on('chat message', function ($msg) use ($io) { 40 | $io->emit('chat message', $msg); 41 | }); 42 | 43 | $all = [ 44 | 'usersNum' => $this->usersNum, 45 | 'currentUsers' => $this->users, 46 | ]; 47 | 48 | $io->emit('sendMsg', json_encode($all, 256)); 49 | 50 | echo 'new connection' . PHP_EOL; 51 | 52 | // 监听客户端连接成功发送数据 53 | $socket->on('success', function ($msg) use ($io, $socket) { 54 | $username = $msg['username'] ?: ''; 55 | 56 | if (empty($username)) { 57 | $username = str_rand(12); 58 | } 59 | // 将当前客户端加入以他的用户名定义的group 60 | $socket->join($username); 61 | $socket->username = $username; 62 | 63 | // 记录用户,同一个用户打开多个页面算一个,记录页面数量 64 | if (!isset($this->users[$username])) { 65 | $this->users[$username] = 1; 66 | ++$this->usersNum; 67 | // 加入了聊天 68 | $bc = [ 69 | 'msg' => $username . ' join the chat', 70 | 'type' => 'join', 71 | 'usersNum' => $this->usersNum, 72 | 'currentUsers' => $this->users, 73 | ]; 74 | 75 | $io->emit('sendMsg', json_encode($bc, 256)); 76 | } else { 77 | ++$this->users[$username]; 78 | } 79 | 80 | $res = [ 81 | 'username' => $username, 82 | 'msg' => 'success', 83 | 'usersNum' => $this->usersNum, 84 | 'currentUsers' => $this->users, 85 | ]; 86 | $socket->emit('success', json_encode($res, 256)); 87 | echo date('Y-m-d H:i:s') . " $username join" . PHP_EOL; 88 | }); 89 | 90 | 91 | $socket->on('sendMsg', function ($msg) use ($io, $socket) { 92 | 93 | echo date('Y-m-d H:i:s') . " 收到广播消息:" . json_encode($msg, 256) . PHP_EOL; 94 | 95 | // 向所有客户端广播发送消息 *** SAY 96 | $bc = [ 97 | 'msg' => $msg['msg'], 98 | 'from' => $msg['username'], 99 | 'type' => 'say', 100 | ]; 101 | 102 | $io->emit('sendMsg', json_encode($bc, 256)); 103 | 104 | // 向以用户名定义的组推送消息,达到一对一的推送的效果 105 | // $io->to($msg['username'])->emit('sendMsg', json_encode($response, JSON_UNESCAPED_UNICODE)); 106 | 107 | // 向当前客户端推送消息 108 | // $socket->emit('sendMsg', json_encode($response)); 109 | 110 | // 不需要存储公频消息注释这句 111 | $data = [ 112 | 'msg' => $msg['msg'], 113 | 'from' => $msg['username'], 114 | 'to' => '', 115 | 'type' => 'public' 116 | ]; 117 | 118 | if ($this->saveMsg) { 119 | try { 120 | $this->insertMsg($data); 121 | } catch (\Exception $e) { 122 | echo "消息入库失败: " . $e->getMessage() . PHP_EOL; 123 | } 124 | } 125 | 126 | 127 | }); 128 | 129 | // 一对一私聊 130 | $socket->on('private chat', function ($msg) use ($io, $socket) { 131 | 132 | echo date('Y-m-d H:i:s') . " 收到私聊消息:" . json_encode($msg, 256) . PHP_EOL; 133 | 134 | if (!empty($msg['to']) && !empty($msg['from'])) { 135 | 136 | $io->to($msg['to'])->emit('private chat', json_encode($msg, 256)); 137 | 138 | if ($this->saveMsg) { 139 | try { 140 | $this->insertMsg($msg); 141 | } catch (DbException $e) { 142 | echo "消息入库失败: " . $e->getMessage() . PHP_EOL; 143 | } 144 | } 145 | 146 | } 147 | }); 148 | 149 | // 关闭页面/离开聊天室 150 | $socket->on('disconnect', function () use ($socket) { 151 | if (!isset($this->users[$socket->username])) { 152 | $this->users[$socket->username] = 0; 153 | } 154 | --$this->users[$socket->username]; 155 | if ($this->users[$socket->username] <= 0) { 156 | echo $socket->username . ' disconnect' . PHP_EOL; 157 | unset($this->users[$socket->username]); 158 | --$this->usersNum; 159 | $socket->leave($socket->username); 160 | $res = [ 161 | 'username' => $socket->username, 162 | 'usersNum' => $this->usersNum, 163 | 'currentUsers' => $this->users, 164 | 'type' => 'left', 165 | ]; 166 | $socket->broadcast->emit('sendMsg', json_encode($res, 256)); 167 | echo date('Y-m-d H:i:s') . " {$socket->username} leave" . PHP_EOL; 168 | } 169 | }); 170 | 171 | $socket->on('changeName', function ($msg) use ($io, $socket) { 172 | 173 | $username = $msg['username'] ?: ''; 174 | --$this->usersNum; 175 | $socket->leave($username); 176 | unset($this->users[$username]); 177 | echo $username . ' disconnect' . PHP_EOL; 178 | $res = [ 179 | 'username' => $username, 180 | 'usersNum' => $this->usersNum, 181 | 'currentUsers' => $this->users, 182 | 'type' => 'left', 183 | ]; 184 | $io->emit('sendMsg', json_encode($res, 256)); 185 | }); 186 | 187 | 188 | }); 189 | 190 | // 当$io启动后监听一个http端口,通过这个端口可以给任意user或者所有user推送数据 191 | $io->on('workerStart', function () use ($io) { 192 | // 监听一个http端口 193 | $api_url = Config::get('param.ws.apiHost'); 194 | $inner_http_worker = new Worker($api_url); 195 | // 当http客户端发来数据时触发 196 | $inner_http_worker->onMessage = function ($http_connection, $data) use ($io) { 197 | $params = $_POST ? $_POST : $_GET; 198 | // 推送数据的url格式 type=publish&to=user&content=xxxx 199 | switch (@$params['type']) { 200 | case 'publish': 201 | $to = @$params['to']; 202 | // 有指定user则向user所在socket组发送数据 203 | $msg = [ 204 | 'msg' => $params['content'], 205 | 'from' => 'system', 206 | 'type' => 'system', 207 | ]; 208 | echo date('Y-m-d H:i:s') . " api收到推送消息:" . json_encode($msg, 256) . PHP_EOL; 209 | if ($to) { 210 | $msg['to'] = $to ?: ''; 211 | if (isset($this->users[$to])) { 212 | $io->to($to)->emit('sendMsg', json_encode($msg, 256)); 213 | } else { 214 | return $http_connection->send($to . 'is offline'); 215 | } 216 | } else { 217 | $io->emit('sendMsg', json_encode($msg, 256)); 218 | } 219 | 220 | if ($this->saveMsg) { 221 | try { 222 | $this->insertMsg($msg); 223 | return $http_connection->send('ok'); 224 | } catch (DbException $e) { 225 | echo "消息入库失败: " . $e->getMessage() . PHP_EOL; 226 | return $http_connection->send('fail'); 227 | } 228 | } else { 229 | return $http_connection->send('ok'); 230 | } 231 | } 232 | return $http_connection->send('fail'); 233 | }; 234 | // 执行监听 235 | $inner_http_worker->listen(); 236 | }); 237 | 238 | Worker::runAll(); 239 | } 240 | 241 | 242 | private function insertMsg($data) 243 | { 244 | Db::name('msg')->insert($data); 245 | } 246 | } --------------------------------------------------------------------------------