/**
* 获取当前时间戳带微秒
* @return float
*/
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
} /**
*获取当前网站域名
*/
function getUrlBefore()
{
$http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
return $http_type . $_SERVER['SERVER_NAME'];
} /**
* 截取查询结果中的字段
* @param array $data 查询出来的结果集
* @param string $field 需要截取的字段
* @param string $copy_field 存入的新的字段名(不写默认存回原字段)
* @param int $length 截取长度,默认10
* @param string $omit 省略的符号,默认 ……
* @return array 返回截取成功的结果集
*/
function cutField($data=array(),$field="",$copy_field="",$length=10,$omit="…"){
if (empty($data)){
return "请传入正确的数组";
}
if (empty($field)){
return "请传入需要截取的字段";
}
if (empty($copy_field)){
$copy_field=$field;
}
foreach ($data as &$v){
if (mb_strlen($v[$field],'utf-8')>$length){
$v[$copy_field]=mb_substr($v[$field],0,$length,'utf-8').$omit;
}
}
return $data;
} /**
* 生成随机码(默认六位)
* 一般放在common中
* @param unknown $length 生成的随机码的长度
* @return string 返回随机码
*/
function GetRand( $length = 6 ) {
// 密码字符集,可任意添加你需要的字符
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$password = '';
for ( $i = 0; $i < $length; $i++ ) {
// 使用 substr 截取$chars中的任意一位字符;
$password .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $password;
} /**
* 颜色十六进制转化为rgb
* 一般放在common中
*/
function hColor2RGB($hexColor)
{
$color = str_replace('#', '', $hexColor);
if (strlen($color) > 3) {
$rgb = array(
'r' => hexdec(substr($color, 0, 2)),
'g' => hexdec(substr($color, 2, 2)),
'b' => hexdec(substr($color, 4, 2))
);
} else {
$color = str_replace('#', '', $hexColor);
$r = substr($color, 0, 1) . substr($color, 0, 1);
$g = substr($color, 1, 1) . substr($color, 1, 1);
$b = substr($color, 2, 1) . substr($color, 2, 1);
$rgb = array(
'r' => hexdec($r),
'g' => hexdec($g),
'b' => hexdec($b)
);
}
return $rgb;
} 这个错误一般是数据库断开后不再自动连接导致的。
需要将 config['break_reconnect'] 的值设置为 true, 才会开启断线重连。
一般在database.php 配置文件中:
//断线重连 'break_reconnect' => true,
但有些版本不在此文件中,可以从thinkphp/library/think/db/Connection.php找到,再找不到,请全局搜索!
最后,一般造成这样的原因可能是因为数据库连接次数过多,还是要优化代码,可以考虑添加缓存,减少数据库的连接。
1、环境确认,仅支持 Linux(2.3.32 以上内核)、FreeBSD、MacOS 三种操作系统,低版本 Linux 系统(如 CentOS 6)可以使用 RedHat 提供的 devtools 编译,参考文档, 在 Windows 平台,可使用 WSL(Windows Subsystem for Linux) 或 CygWin。
2、系统软件:
php-7.2 或更高版本 gcc-4.8 或更高版本 make autoconf
3、下载swoole源码(三选一)
https://github.com/swoole/swoole-src/releases https://pecl.php.net/package/swoole https://gitee.com/swoole/swoole/tags
4、下载源代码包后,使用root权限的终端进入源码目录,执行下面的命令进行编译和安装(当前教程安装的是4.8.0版本)
①进入下载的安装目录中:
cd swoole
②执行下面命令进入安装模块:
phpize && \
③设置configure中的安装目录
./configure --with-php-config=/www/server/php/72/bin/php-config
④最后通过以下命令执行安装:
make && make install
⑤执行完成后看看安装目录下有无swoole.so文件,php.ini中有无extension=swoole.so
#我成功安装后,swoole.so所在目录: /www/server/php/72/lib/php/extensions/no-debug-non-zts-20170718/swoole.so
注:如果不知道第③步中的安装目录,则可以执行下面命令进行全局查找
find / -name php-config
PHP代码部分
//创建WebSocket Server对象,监听0.0.0.0:9502端口
$ws = new \Swoole\WebSocket\Server('0.0.0.0', 9502);
//监听WebSocket连接打开事件
$ws->on('Open', function ($ws, $request) {
$socket_id = $request->fd;
$nowtime = date("Y-m-d H:i:s");
echo "[{$nowtime}] {$socket_id}连接成功\n";
$ws->push($socket_id, "swoole连接成功!\n");
});
//监听WebSocket消息事件
$ws->on('Message', function ($ws, $frame) {
$socket_id = $frame->fd;
$data = $frame->data;
$nowtime = date("Y-m-d H:i:s");
echo "[{$nowtime}] 收到的客户端信息: {$data}\n";
$ws->push($socket_id, "收到的客户端信息: {$frame->data}");
});
//监听WebSocket连接关闭事件
$ws->on('Close', function ($ws, $fd) {
$nowtime = date("Y-m-d H:i:s");
echo "[{$nowtime}] socket_id为{$fd}的用户已关闭连接\n";
});
$ws->start();运行swoole
php swoole.php
客户端JS代码部分:
var wsServer = 'ws://服务器IP地址:9502';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
console.log("swoole连接成功!");
websocket.send('测试数据')
};
websocket.onclose = function (evt) {
console.log("swoole连接断开!");
};
websocket.onmessage = function (evt) {
console.log('服务器返回的数据为: ' + evt.data);
};
websocket.onerror = function (evt, e) {
console.log('发生错误: ' + evt.data);
};注(踩的坑):
①检查防火墙9502端口是否开放
②以上教程在有ssl证书的情况下会连接失败
想在ssl证书下运行swoole,需要到swoole目录下重新安装程序:
①进入安装目录,执行下面命令进入安装模块:
执行下面命令进入安装模块:
phpize && \
②设置configure中的安装目录,并带有ssl安装,找不到目录参考上面find命令
./configure --enable-openssl --with-php-config=/www/server/php/72/bin/php-config
③清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件
make clean
④最后通过以下命令执行安装
make && make install
⑤查看结果是否包含openssl
php --ri swoole
看结果中是否存在下面这行,时间可能不一致,但前半部分相同
openssl => OpenSSL 1.0.2k-fips 26 Jan 2017
①客户端修改访问地址
var wsServer = 'ws://服务器IP地址:9502'; //上面改为下面,其他代码不动即可 var wsServer = 'wss://域名/自定义模块名(不要和代码中的功能模块名重复)'; //例如 var wsServer = 'wss://shx1024.top/websocket/';
②Nginx配置代理(其实是将指向https的服务重定向到http):
#在代理服务器上的nginx配置文件中的server中增加如下配置项
location /websocket/ {
proxy_pass http://服务器IP地址:9502;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}③重新运行swoole
php swoole.php
①客户端修改访问地址
var wsServer = 'ws://服务器IP地址:9502'; //上面改为下面,其他代码不动即可 var wsServer = 'wss://服务器IP地址:9502';
②服务器端为WebSocket服务器增加ssl证书,这样就可以直接通过wss://来请求服务器了
//使用SSL必须在编译swoole时加入--enable-openssl选项
$server = new Swoole\WebSocket\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set(
[
'ssl_cert_file' => '证书cert地址',
'ssl_key_file' => '证书key地址',
]
);
//注:宝塔SSL证书所在目录:/www/server/panel/vhost/ssl/你的网站域名③重新运行swoole
php swoole.php
直接引入此类文件调用即可:
class Jwt
{
//头部
private static $header = array(
'alg' => 'HS256', //生成signature的算法
'typ' => 'JWT' //类型
);
//使用HMAC生成信息摘要时所使用的密钥
private static $key = 'Shx123456panshi123456';
/**
* 获取jwt token
* @param array $payload jwt载荷 格式如下非必须
* [
* 'iss'=>'jwt_admin', //该JWT的签发者
* 'iat'=>time(), //签发时间
* 'exp'=>time()+7200, //过期时间
* 'nbf'=>time()+60, //该时间之前不接收处理该Token
* 'user_id'=>md5(uniqid('JWT').time()) //该Token唯一标识
* ]
* @return bool|string
*/
public static function getToken(array $payload)
{
$arr = [
'iss' => 'shx', //该JWT的签发者
'iat' => time(), //签发时间
'exp' => time() + 3600 * 24 * 30, //过期时间
'nbf' => time(), //该时间之前不接收处理该Token
'user_id' => 0 //该Token唯一标识
];
$payload = array_merge($arr, $payload);
if (is_array($payload)) {
$base64header = self::base64UrlEncode(json_encode(self::$header, JSON_UNESCAPED_UNICODE));
$base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
$token = $base64header . '.' . $base64payload . '.' . self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']);
return $token;
} else {
return false;
}
}
/**
* 验证token是否有效,默认验证exp,nbf,iat时间
* @param string $Token 需要验证的token
* @return bool|string
*/
public static function verifyToken(string $Token)
{
$tokens = explode('.', $Token);
if (count($tokens) != 3)
return false;
list($base64header, $base64payload, $sign) = $tokens;
//获取jwt算法
$base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
if (empty($base64decodeheader['alg']))
return false;
//签名验证
if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decodeheader['alg']) !== $sign)
return false;
$payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);
//签发时间大于当前服务器时间验证失败
if (isset($payload['iat']) && $payload['iat'] > time())
return false;
//过期时间小宇当前服务器时间验证失败
if (isset($payload['exp']) && $payload['exp'] < time())
return false;
//该nbf时间之前不接收处理该Token
if (isset($payload['nbf']) && $payload['nbf'] > time())
return false;
return $payload;
}
/**
* base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现
* @param string $input 需要编码的字符串
* @return string
*/
private static function base64UrlEncode(string $input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
/**
* base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现
* @param string $input 需要解码的字符串
* @return bool|string
*/
private static function base64UrlDecode(string $input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$addlen = 4 - $remainder;
$input .= str_repeat('=', $addlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现
* @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
* @param string $key
* @param string $alg 算法方式
* @return mixed
*/
private static function signature(string $input, string $key, string $alg = 'HS256')
{
$alg_config = array(
'HS256' => 'sha256'
);
return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key, true));
}
} THINK_PATH 框架系统目录 ROOT_PATH 框架应用根目录 APP_PATH 应用目录(默认为application) CONF_PATH 配置目录(默认为APP_PATH) LIB_PATH 系统类库目录(默认为 THINK_PATH.'library/') CORE_PATH 系统核心类库目录 (默认为 LIB_PATH.'think/') TRAIT_PATH 系统trait目录(默认为 LIB_PATH.'traits/') EXTEND_PATH 扩展类库目录(默认为 ROOT_PATH . 'extend/') VENDOR_PATH 第三方类库目录(默认为 ROOT_PATH . 'vendor/') RUNTIME_PATH 应用运行时目录(默认为 ROOT_PATH.'runtime/') LOG_PATH 应用日志目录 (默认为 RUNTIME_PATH.'log/') CACHE_PATH 项目模板缓存目录(默认为 RUNTIME_PATH.'cache/') TEMP_PATH 应用缓存目录(默认为 RUNTIME_PATH.'temp/')
/**
* get请求
* @param $url 地址
* @return bool|string
*/
function get_url($url)
{
$curl = curl_init();
// header传送格式
$headers = array(
"token:1111111111111",
"over_time:22222222222",
);
//设置访问的url地址
curl_setopt($curl, CURLOPT_URL, $url);
// 不验证SSL
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
// 将 curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
// 添加头信息
//curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
//添加cookie信息
curl_setopt($curl, CURLOPT_COOKIE, 'cookie_name=cookie_value;');
// 执行
$result = curl_exec($curl);
//关闭连接
curl_close($curl);
return $result;
}/**
* POST请求
* @param string $url 地址
* @param string $data 提交的数据
* @return string 返回结果
*/
function post_url($url, $data)
{
$curl = curl_init(); // 启动一个CURL会话
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)'); // 模拟用户使用的浏览器
//curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
//curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包x
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制 防止死循环
curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
$tmpInfo = curl_exec($curl); // 执行操作
if (curl_errno($curl)) {
echo 'Errno' . curl_error($curl);//捕抓异常
}
curl_close($curl); // 关闭CURL会话
return $tmpInfo; // 返回数据
}