提交 6ad3b943 作者: Hao

Initial commit

父级
.idea
composer.lock
*.log
runtime
.DS_Store
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true
MIT License
Copyright (c) 2022 白云飞
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1. 需要给代码的用户一份Apache Licence ;
2. 如果你修改了代码,需要在被修改的文件中说明;
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可,但不可以表现为对Apache Licence构成更改。
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
# dingdong
这里打个广告啊,大家有需要商城系统的,可关注我的:https://gitee.com/sparkshop/sparkshop
大家多多的打star!感谢。
#### 介绍
dingdong(叮咚客服)是一款在线的是实时的网页咨询系统,他类似于`美洽``合从` 等第三方网页客服系统,有力的帮助商城系统、
法务系统、聚合服务平台、教培系统等需要在线咨询的网站。同时还可以帮助更多的程序小白从此项目中汲取经验,应用在OA系统等需要沟通的内部系统中,了解websocket通信
从而提升自己的竞争力。
#### 软件架构
thinkphp6.1 + vue2 + elementui + phpsocket.io
#### 安装教程
安装手册: https://da19lg68p6.feishu.cn/docs/doccnQptUuuZJm1xb5z5bgFa3Db
#### 一睹为快
![](./screenshot/1.png)
![](./screenshot/2.png)
![](./screenshot/3.png)
![](./screenshot/4.png)
![](./screenshot/5.png)
![](./screenshot/6.png)
![](./screenshot/7.png)
![](./screenshot/8.png)
![](./screenshot/9.png)
![](./screenshot/10.png)
![](./screenshot/11.png)
![](./screenshot/12.png)
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 版权说明
禁止将本项目应用于木马、病毒、色情、赌博、诈骗等违反国家法律法规行业。
本项目仅供应用于合法的场景或学习参考,违反本协议引发的一切法律问题与本项目无关。
禁止直接出售本项目。
#### 特别鸣谢
thinkphp (https://www.thinkphp.cn)
phpsocket.io (https://www.workerman.net)
vue (https://cn.vuejs.org)
elementui (https://element.eleme.cn/#/zh-CN/component/installation)
正是基于这些优秀的开源项目,才有本项目的诞生。
\ No newline at end of file
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = 127.0.0.1 DATABASE = dingdong-free USERNAME = root PASSWORD = root HOSTPORT = 3306 CHARSET = utf8mb4 DEBUG = true PREFIX = df_ [LANG] default_lang = zh-cn [SSL] IS_OPEN = false LOCAL_CERT = LOCAL_PK = ALLOW_SELF_SIGNED = false
\ No newline at end of file
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = 127.0.0.1 DATABASE = test USERNAME = username PASSWORD = password HOSTPORT = 3306 CHARSET = utf8 DEBUG = true [LANG] default_lang = zh-cn
\ No newline at end of file
/.idea
/.vscode
*.log
\ No newline at end of file
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1. 需要给代码的用户一份Apache Licence ;
2. 如果你修改了代码,需要在被修改的文件中说明;
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可,但不可以表现为对Apache Licence构成更改。
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
ThinkPHP 6.0
===============
> 运行环境要求PHP7.2+,兼容PHP8.1
[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api)
ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。
## 主要新特性
* 采用`PHP7`强类型(严格模式)
* 支持更多的`PSR`规范
* 原生多应用支持
* 更强大和易用的查询
* 全新的事件系统
* 模型事件和数据库事件统一纳入事件系统
* 模板引擎分离出核心
* 内部功能中间件化
* SESSION/Cookie机制改进
* 对Swoole以及协程支持改进
* 对IDE更加友好
* 统一和精简大量用法
## 安装
~~~
composer create-project topthink/think tp 6.0.*
~~~
如果需要更新框架使用
~~~
composer update topthink/framework
~~~
## 文档
[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content)
## 参与开发
请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)
## 版权信息
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2006-2021 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
更多细节参阅 [LICENSE.txt](LICENSE.txt)
deny from all
\ No newline at end of file
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}
<?php
namespace app\command;
use app\command\service\GlobalData;
use app\command\service\Server;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class Socket extends Command
{
protected function configure()
{
$this->setName('socketio server')
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of workerman service.', null)
->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of workerman service.', null)
->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the workerman service in daemon mode.')
->setDescription('socketio服务器');
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
if (DIRECTORY_SEPARATOR !== '\\') {
if (!in_array($action, ['start', 'stop', 'reload', 'restart', 'status', 'connections'])) {
$output->writeln("<error>Invalid argument action:{$action}, Expected start|stop|restart|reload|status|connections .</error>");
return false;
}
global $argv;
array_shift($argv);
array_shift($argv);
array_shift($argv);
array_unshift($argv, 'think', $action);
}
$logo =<<<EOL
_ _ _
| (_) | |
__| |_ _ __ __ _ __| | ___ _ __ __ _
/ _` | | '_ \ / _` |/ _` |/ _ \| '_ \ / _` |
| (_| | | | | | (_| | (_| | (_) | | | | (_| |
\__,_|_|_| |_|\__, |\__,_|\___/|_| |_|\__, |
__/ | __/ |
|___/ |___/
EOL;
$output->writeln($logo . PHP_EOL);
GlobalData::start();
Server::start();
}
}
\ No newline at end of file
<?php
namespace app\command\service;
class Events
{
public static function customerLogin($ip, $db, $data, $socket, $onlineKeFu)
{
$location = getLocationByIp($ip, 2);
$has = $db->select('id')->from(env('database.prefix') . 'customer')
->where('customer_id="' . $data['customer_id'] . '"')->row();
if (!empty($has)) {
$db->update(env('database.prefix') . 'customer')->cols([
'customer_id' => $data['customer_id'],
'client_id' => $socket->id,
'customer_name' => $data['customer_name'],
'customer_avatar' => $data['customer_avatar'],
'customer_ip' => $ip,
'online_status' => 1,
'province' => $location['province'],
'city' => $location['city']
])->where('id=' . $has['id'])->query();
} else {
$db->insert(env('database.prefix') . 'customer')->cols([
'customer_id' => $data['customer_id'],
'client_id' => $socket->id,
'customer_name' => $data['customer_name'],
'customer_avatar' => $data['customer_avatar'],
'customer_ip' => $ip,
'create_time' => date('Y-m-d H:i:s'),
'online_status' => 1,
'province' => $location['province'],
'city' => $location['city']
])->query();
}
// 分配客服
if (empty($onlineKeFu)) {
return [];
}
$kefuInfo = self::distribution($db, $data, $onlineKeFu);
if (empty($kefuInfo)) {
return [];
}
// 记录服务日志
$logId = $db->insert(env('database.prefix') . 'service_log')->cols([
'customer_id' => $data['customer_id'],
'client_id' => $socket->uid,
'customer_name' => $data['customer_name'],
'customer_avatar' => $data['customer_avatar'],
'customer_ip' => $ip,
'kefu_code' => $kefuInfo['code'],
'kefu_name' => $kefuInfo['name'],
'start_time' => date('Y-m-d H:i:s')
])->query();
// 记录服务的客服
$db->update(env('database.prefix') . 'customer')
->cols([
'pre_kefu_id' => $kefuInfo['id']
])->where('customer_id=' . $data['customer_id'])->query();
// 检测服务数据是否存在
$has = $db->select('id')->from(env('database.prefix') . 'now_service')
->where('kefu_id="' . $kefuInfo['id'] . '" AND customer_id="' . $data['customer_id'] . '"')
->row();
if(!empty($has)) {
$db->update(env('database.prefix') . 'now_service')
->cols([
'kefu_id' => $kefuInfo['id'],
'client_id' => $socket->id,
'service_log_id' => $logId,
'create_time' => time()
])->where('id=' . $has['id'])->query();
} else {
$db->insert(env('database.prefix') . 'now_service')->cols([
'kefu_id' => $kefuInfo['id'],
'customer_id' => $data['customer_id'],
'client_id' => $socket->id,
'service_log_id' => $logId,
'create_time' => time()
])->query();
}
return $kefuInfo;
}
protected static function distribution($db, $data, $onlineKeFu)
{
// 上次服务的客服
$customerInfo = $db->select('kefu_code')->from(env('database.prefix') . 'service_log')
->where("customer_id= '" . $data['customer_id'] . "' ")->row();
if (!empty($customerInfo)) {
// 上次的客服不在线,重新分配
if (empty($customerInfo['kefu_code'])) {
return self::circleDistribution($db, $onlineKeFu);
} else {
if (isset($onlineKeFu[$customerInfo['kefu_code']])) {
return $onlineKeFu[$customerInfo['kefu_code']];
}
}
} else {
// 第一次访问,重新分配
return self::circleDistribution($db, $onlineKeFu);
}
}
protected static function circleDistribution($db, $onlineKeFu)
{
$db->beginTrans();
try {
// TODO 此处我的数组分配的情况放在mysql的,可以改成 redis 等更高效率的db中
$sql = 'SELECT `kefu_map` FROM `' . env('database.prefix') . 'kefu_distribution` FOR UPDATE';
$keFuInfo = $db->query($sql);
$diffMap = [];
foreach ($onlineKeFu as $vo) {
$diffMap[$vo['id']] = $vo;
}
if (empty($keFuInfo['0']['kefu_map'])) {
$kefuMap = [];
} else {
$kefuMap = json_decode($keFuInfo['0']['kefu_map'], true);
}
if (empty($kefuMap)) {
$oldMap = [];
// 刷新在线的客服列表
foreach ($kefuMap as $key => $vo) {
if (!isset($diffMap[$vo['id']])) {
unset($kefuMap[$key]);
} else {
$oldMap[$vo['id']] = 1;
$kefuMap[$key] = $diffMap[$vo['id']];
unset($diffMap[$vo['id']]);
}
}
// 将新加入的客服,补充到待接待的队列前端
foreach($diffMap as $key => $vo) {
if (!isset($oldMap[$key])) {
array_unshift($kefuMap, $vo);
}
}
unset($diffMap, $oldMap);
} else {
$kefuMap = $onlineKeFu;
}
$returnKeFu = array_shift($kefuMap);
array_push($kefuMap, $returnKeFu);
$sql = "UPDATE `" . env('database.prefix') . "kefu_distribution` SET `kefu_map` = '"
. json_encode($kefuMap, JSON_UNESCAPED_UNICODE) . "'";
$db->query($sql);
$db->commitTrans();
if (empty($returnKeFu)) {
return [];
}
return $returnKeFu;
} catch (\Exception $e) {
$db->rollBackTrans();
return [];
}
}
}
\ No newline at end of file
<?php
namespace app\command\service;
class GlobalData
{
public static function start()
{
$worker = new \GlobalData\Server('127.0.0.1', 2207);
}
}
\ No newline at end of file
<?php
// 应用公共文件
/**
* 根据ip定位
* @param $ip
* @param $type
* @return string | array
* @throws Exception
*/
function getLocationByIp($ip, $type = 1)
{
$ip2region = new \Ip2Region();
$info = $ip2region->btreeSearch($ip);
$info = explode('|', $info['region']);
$address = '';
foreach($info as $vo) {
if('0' !== $vo) {
$address .= $vo . '-';
}
}
if (2 == $type) {
return ['province' => $info['2'], 'city' => $info['3']];
}
return rtrim($address, '-');
}
/**
* 设置jwt
* @param $data
* @return string
*/
function setJWT($data) {
$jwt = new Firebase\JWT\JWT();
$token = [
// "iss" => "http://example.org", // 签发者
// "aud" => "http://example.com", // 认证者
'iat' => time(), // 签发时间
'nbf' => time(), // 生效时间
'exp' => (time() + 60 * 60 * 24 * 7), // 过期时间 7天后的时间戳
'data' => $data
];
$jwt = $jwt::encode($token, \config('dingdong.jwt_key'), 'HS256');
return $jwt;
}
/**
* 获取token中的信息
* @param $token
* @return array|null
*/
function getJWT($token) {
$jwt = new Firebase\JWT\JWT();
$data = [];
try {
$jwt_data = $jwt::decode($token, new Firebase\JWT\Key(\config('dingdong.jwt_key'), 'HS256'));
$data = (array) ($jwt_data->data);
} catch (\Exception $e) {
\think\facade\Log::write($e->getMessage(), 'error');
return null;
}
return $data;
}
/**
* 从头部获取token
* @return bool|string
*/
function getHeaderToken() {
$header = request()->header();
if (isset($header['authorization'])) {
return substr($header['authorization'], 7);
}
return '';
}
function jsonReturn($code, $msg = 'success', $data = []) {
return json(['code' => $code, 'data' => $data, 'msg' => $msg]);
}
function crossDomain() {
header("access-control-allow-headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With");
header("access-control-allow-methods: OPTIONS,GET, POST, PATCH, PUT, DELETE");
header("access-control-allow-origin: *");
}
/**
* 计算时长
* @param $seconds
* @return string
*/
function changeTimeType($seconds)
{
if ($seconds > 3600) {
$hours = intval($seconds / 3600);
$minutes = $seconds % 3600;
$time = $hours . ":" . gmstrftime('%M:%S', $minutes);
} else {
$time = gmstrftime('%H:%M:%S', $seconds);
}
return $time;
}
\ No newline at end of file
<?php
namespace app\controller;
use think\facade\Db;
class Api extends Base
{
public function getNowService()
{
$list = Db::name('now_service')->where('kefu_id', $this->userInfo['id'])->select()->toArray();
$customerIds = [];
foreach ($list as $key => $vo) {
$list[$key]['time'] = date('m-d H:i', $vo['create_time']);
$list[$key]['last_word'] = '';
$list[$key]['unread_msg'] = 0;
$list[$key]['online_status'] = 1;
$customerIds[] = $vo['customer_id'];
}
$customerList = Db::name('customer')->field('customer_id,customer_name,customer_avatar,online_status')
->whereIn('customer_id', $customerIds)->select();
$customerMap = [];
foreach ($customerList as $vo) {
$customerMap[$vo['customer_id']] = $vo;
}
foreach ($list as $key => $vo) {
if (isset($customerMap[$vo['customer_id']])) {
$list[$key]['customer_name'] = $customerMap[$vo['customer_id']]['customer_name'];
$list[$key]['avatar'] = $customerMap[$vo['customer_id']]['customer_avatar'];
}
}
return jsonReturn(0, 'success', $list);
}
public function getChatLog()
{
$customerId = input('param.customer_id');
$limit = input('param.limit', 15);
$log = Db::name('chat_log')->where(function ($query) use ($customerId) {
$where[] = [
'from_id', '=', $customerId
];
$where[] = [
'to_id', '=', $this->userInfo['code']
];
$query->where($where);
})->whereOr(function ($query) use ($customerId) {
$where[] = [
'from_id', '=', $this->userInfo['code']
];
$where[] = [
'to_id', '=', $customerId
];
$query->where($where);
})->order('id desc')->paginate($limit)->each(function($item, $key){
$item['time'] = date('m-d H:i', strtotime($item['create_time']));
return $item;
})->toArray();
sort($log['data']);
return jsonReturn(0, 'success', $log);
}
public function getCustomerInfo()
{
$customerId = input('param.customer_id');
$info = Db::name('customer')->where('customer_id', $customerId)->find();
return jsonReturn(0, 'success', $info);
}
}
\ No newline at end of file
<?php
namespace app\controller;
use app\BaseController;
class Base extends BaseController
{
protected $userInfo;
public function initialize()
{
crossDomain();
$this->userInfo = getJWT(getHeaderToken());
if(empty($this->userInfo)){
exit(json_encode(['code' => 406, 'data' => [], 'msg' => 'token无效']));
}
}
}
\ No newline at end of file
<?php
namespace app\controller;
use think\facade\Db;
class Customer extends Base
{
public function index()
{
$limit = input('param.limit');
$customerName = input('param.customer_name');
$where = [];
if (empty($name)) {
$where[] = ['customer_name', 'like', '%' . $customerName . '%'];
}
$list = Db::name('customer')->where($where)->order('id desc')->paginate($limit);
return jsonReturn(0, 'success', $list);
}
public function serviceLog()
{
$limit = input('param.limit');
$customerId = input('param.customer_id');
$where = [];
if (empty($name)) {
$where[] = ['customer_id', '=', $customerId];
}
$list = Db::name('service_log')->where($where)->order('id desc')->paginate($limit)->each(function ($item) {
$item['chat_time'] = changeTimeType($item['chat_time']);
return $item;
});
return jsonReturn(0, 'success', $list);
}
public function getChatLog()
{
$customerId = input('param.customer_id');
$limit = input('param.limit', 15);
$log = Db::name('chat_log')->where(function ($query) use ($customerId) {
$where[] = [
'from_id', '=', $customerId
];
$whereOr[] = [
'to_id', '=', $customerId
];
$query->where($where)->whereOr($whereOr);
})->order('id desc')->paginate($limit)->each(function($item, $key){
$item['time'] = date('m-d H:i', strtotime($item['create_time']));
return $item;
})->toArray();
sort($log['data']);
return jsonReturn(0, 'success', $log);
}
}
\ No newline at end of file
<?php
namespace app\controller;
use think\facade\Db;
class Index extends Base
{
public function index()
{
$onlineKeFuNum = number_format(Db::name('kefu')->where('status', 1)->count());
$serviceCustomerNum = number_format(Db::name('customer')->count());
$totalChatTime = changeTimeType(Db::name('service_log')->sum('chat_time'));
$todayServiceNum = number_format(Db::name('service_log')
->where('start_time', '>', date('Y-m-d') . ' 00:00:00')
->where('start_time', '<', date('Y-m-d') . ' 23:59:59')
->count());
$days7 = [];
for ($i = 7; $i > 0; $i--) {
$days7[] = date('Y-m-d', strtotime('-' . $i . ' days'));
}
$start = $days7[0];
$end = $days7[6] . ' 23:59:59';
$sevenNum = $this->census($start, $end, $days7);
return json(['code' => 0, 'data' => [
'sevenDays' => $days7,
'onlineKeFuNum' => $onlineKeFuNum,
'serviceCustomerNum' => $serviceCustomerNum,
'totalChatTime' => $totalChatTime,
'todayServiceNum' => $todayServiceNum,
'sevenNum' => array_values($sevenNum),
], 'msg' => 'success']);
}
private function census($start, $end, $days)
{
$sql = "SELECT DATE_FORMAT(start_time, '%Y-%m-%d') as create_time2,count(id) as s_num from df_service_log WHERE start_time > '"
. $start . "' and start_time < '" . $end . "' GROUP BY create_time2;";
$all = Db::query($sql);
$num = [];
foreach ($days as $vo) {
$num[$vo] = 0;
}
foreach ($all as $vo) {
if (isset($num[$vo['create_time2']])) {
$num[$vo['create_time2']] = $vo['s_num'];
}
}
return $num;
}
}
<?php
namespace app\controller;
use app\validate\KefuValidate;
use think\exception\ValidateException;
use think\facade\Db;
class Kefu extends Base
{
public function index()
{
$limit = input('param.limit');
$name = input('param.name');
$where[] = ['is_del', '=', 1];
if (empty($name)) {
$where[] = ['name', 'like', '%' . $name . '%'];
}
$list = Db::name('kefu')->where($where)->order('id desc')->paginate($limit);
return jsonReturn(0, 'success', $list);
}
public function add()
{
$param = input('post.');
try {
validate(KefuValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$has = Db::name('kefu')->field('id')->where([
'phone' => $param['phone']
])->find();
if (!empty($has)) {
return jsonReturn(-2, '该手机号已经存在');
}
$param['status'] = 2;
$param['code'] = uniqid();
$param['password'] = md5($param['password'] . config('dingdong.salt'));
$param['create_time'] = date('Y-m-d H:i:s');
Db::name('kefu')->insert($param);
return jsonReturn(0, '添加成功');
}
public function edit()
{
$param = input('post.');
try {
validate(KefuValidate::class)->scene('edit')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where[] = ['phone', '=', $param['phone']];
$where[] = ['id', '<>', $param['id']];
$has = Db::name('kefu')->field('id')->where($where)->find();
if (!empty($has)) {
return jsonReturn(-2, '该手机号已经存在');
}
if (isset($param['password'])) {
$param['password'] = md5($param['password'] . config('dingdong.salt'));
} else {
unset($param['password']);
}
$param['update_time'] = date('Y-m-d H:i:s');
Db::name('kefu')->where('id', $param['id'])->update($param);
return jsonReturn(0, '编辑成功');
}
public function del()
{
$id = input('param.id');
Db::name('kefu')->where('id', $id)->update([
'is_del' => 2,
'update_time' => date('Y-m-d H:i:s')
]);
return jsonReturn(0, '删除成功');
}
public function getMenuList()
{
$info = Db::name('kefu')->where('id', $this->userInfo['id'])->find();
$data = [
'id' => $this->userInfo['id'],
'name' => $this->userInfo['name'],
'avatar' => $info['avatar'],
'roleId' => 1,
'menu' => []
];
return jsonReturn(0, '获取成功', $data);
}
public function getUserInfo()
{
return jsonReturn(0, 'success', Db::name('kefu')
->field('id,code,name,avatar')->where('id', $this->userInfo['id'])->find());
}
}
\ No newline at end of file
<?php
namespace app\controller;
class Leavemsg extends Base
{
}
\ No newline at end of file
<?php
namespace app\controller;
use think\facade\Db;
class Login extends Base
{
public function initialize()
{
crossDomain();
}
public function index()
{
$param = input('post.');
$info = Db::name('kefu')->where('phone', $param['phone'])->where('is_del', 1)->find();
if (empty($info)) {
return jsonReturn(-1, '用户名密码错误');
}
if (md5($param['password'] . config('dingdong.salt')) != $info['password']) {
return jsonReturn(-2, '用户名密码错误');
}
$token = setJWT([
'id' => $info['id'],
'code' => $info['code'],
'name' => $info['name']
]);
Db::name('kefu')->where('id', $info['id'])->update([
'last_login_time' => date('Y-m-d H:i:s'),
'last_ip' => request()->ip()
]);
return jsonReturn(0, '登录成功', [
'token' => (string)$token,
'userInfo' => [
'id' => $info['id'],
'role_id' => 1,
'code' => $info['code'],
'name' => $info['name'],
'avatar' => $info['avatar'],
]
]);
}
public function getSocket()
{
$data = [
'socket' => config('dingdong.domain') . ':' . config('dingdong.ws_port')
];
return jsonReturn(0, 'success', $data);
}
public function getChatLog()
{
$customerId = input('param.customer_id');
$kefuCode = input('param.code');
$limit = input('param.limit', 15);
$log = Db::name('chat_log')->where(function ($query) use ($customerId, $kefuCode) {
$where[] = [
'from_id', '=', $customerId
];
$where[] = [
'to_id', '=', $kefuCode
];
$query->where($where);
})->whereOr(function ($query) use ($customerId, $kefuCode) {
$where[] = [
'from_id', '=', $kefuCode
];
$where[] = [
'to_id', '=', $customerId
];
$query->where($where);
})->order('id desc')->paginate($limit)->each(function($item, $key){
$item['time'] = date('m-d H:i', strtotime($item['create_time']));
return $item;
})->toArray();
sort($log['data']);
return jsonReturn(0, 'success', $log);
}
}
\ No newline at end of file
<?php
namespace app\controller;
use app\BaseController;
class Upload extends BaseController
{
// 上传图片
public function uploadImg()
{
$file = request()->file('file');
// 检测图片格式
$ext = $file->getOriginalExtension();
$extArr = explode('|', 'jpg|png|gif|jpeg');
if(!in_array($ext, $extArr)){
return json(['code' => -3, 'data' => '', 'msg' => '只能上传jpg|png|gif|jpeg的文件']);
}
// 存到本地
$saveName = \think\facade\Filesystem::disk('public')->putFile('upload', $file);
return json(['code' => 200, 'data' => ['src' => config('dingdong.domain') . '/storage/' . $saveName ], 'msg' => '']);
}
}
\ No newline at end of file
<?php
namespace app\controller;
use app\validate\KefuValidate;
use app\validate\WordValidate;
use think\exception\ValidateException;
use think\facade\Db;
class Word extends Base
{
public function index()
{
$cateId = input('param.cate_id');
$limit = input('param.limit');
$title = input('param.title');
$where[] = ['cate_id', '=', $cateId];
if (!empty($title)) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
$list = Db::name('word')->where($where)->order('id desc')->paginate($limit);
return jsonReturn(0, 'success', $list);
}
public function add()
{
$param = input('post.');
try {
validate(WordValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$has = Db::name('word')->field('id')->where([
'title' => $param['title']
])->find();
if (!empty($has)) {
return jsonReturn(-2, '该分类内容已经存在');
}
$param['create_time'] = date('Y-m-d H:i:s');
Db::name('word')->insert($param);
return jsonReturn(0, '添加成功');
}
public function edit()
{
$param = input('post.');
try {
validate(WordValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where[] = ['title', '=', $param['title']];
$where[] = ['id', '<>', $param['id']];
$has = Db::name('word')->field('id')->where($where)->find();
if (!empty($has)) {
return jsonReturn(-2, '该分类内容已经存在');
}
$param['update_time'] = date('Y-m-d H:i:s');
Db::name('word')->where('id', $param['id'])->update($param);
return jsonReturn(0, '编辑成功');
}
public function del()
{
$id = input('param.id');
Db::name('word')->where('id', $id)->delete();
return jsonReturn(0, '删除成功');
}
}
\ No newline at end of file
<?php
namespace app\controller;
use think\facade\Db;
class Wordcate extends Base
{
public function index()
{
$list = Db::name('word_cate')->select();
return jsonReturn(0, 'success', $list);
}
public function add()
{
$param = input('post.');
if (empty($param['cate_name'])) {
return jsonReturn(-1, '请输入分类名');
}
$has = Db::name('word_cate')->field('id')->where([
'cate_name' => $param['cate_name']
])->find();
if (!empty($has)) {
return jsonReturn(-2, '该分类已经存在');
}
$param['status'] = 1;
Db::name('word_cate')->insert($param);
return jsonReturn(0, '添加成功');
}
public function del()
{
$id = input('param.id');
$has = Db::name('word')->field('id')->where([
'cate_id' => $id
])->find();
if (!empty($has)) {
return jsonReturn(-1, '该分类下有常用语,不可删除');
}
Db::name('word_cate')->where('id', $id)->delete();
return jsonReturn(0, '删除成功');
}
}
\ No newline at end of file
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// 允许跨域
\think\middleware\AllowCrossDomain::class,
// Session初始化
// \think\middleware\SessionInit::class
];
<?php
use app\ExceptionHandle;
use app\Request;
// 容器Provider定义文件
return [
'think\Request' => Request::class,
'think\exception\Handle' => ExceptionHandle::class,
];
<?php
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
AppService::class,
];
<?php
namespace app\validate;
use think\Validate;
class KefuValidate extends Validate
{
protected $rule = [
'phone|手机号' => 'require|mobile',
'name|昵称' => 'require',
'avatar|头像' => 'require',
'password|密码' => 'require'
];
protected $scene = [
'edit' => ['phone', 'name', 'avatar']
];
}
\ No newline at end of file
<?php
namespace app\validate;
use think\Validate;
class WordValidate extends Validate
{
protected $rule = [
'title|标题' => 'require',
'word|内容' => 'require',
'cate_id|分类id' => 'require'
];
}
\ No newline at end of file
{
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "http://thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
},
{
"name": "yunwuxin",
"email": "448901948@qq.com"
}
],
"require": {
"php": ">=7.2.5",
"topthink/framework": "^6.0.0",
"topthink/think-orm": "^2.0",
"firebase/php-jwt": "^6.1",
"zoujingli/ip2region": "^1.0",
"workerman/phpsocket.io": "^1.1",
"workerman/mysql": "^1.0",
"ext-json": "*",
"workerman/globaldata": "^1.0"
},
"require-dev": {
"symfony/var-dumper": "^4.2",
"topthink/think-trace":"^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
}
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
return [
// 应用地址
'app_host' => env('app.host', ''),
// 应用的命名空间
'app_namespace' => '',
// 是否启用路由
'with_route' => true,
// 默认应用
'default_app' => 'index',
// 默认时区
'default_timezone' => 'Asia/Shanghai',
// 应用映射(自动多应用模式有效)
'app_map' => [],
// 域名绑定(自动多应用模式有效)
'domain_bind' => [],
// 禁止URL访问的应用列表(自动多应用模式有效)
'deny_app_list' => [],
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => false,
];
<?php
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
return [
// 默认缓存驱动
'default' => env('cache.driver', 'file'),
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => '',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// 更多的缓存连接
],
];
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'server' => 'app\\command\\Socket'
],
];
<?php
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
return [
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => false,
// 是否使用 setcookie
'setcookie' => true,
// samesite 设置,支持 'strict' 'lax'
'samesite' => '',
];
<?php
return [
// 默认使用的数据库连接配置
'default' => env('database.driver', 'mysql'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
// true为自动识别类型 false关闭
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 时间字段配置 配置格式:create_time,update_time
'datetime_field' => '',
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => env('database.type', 'mysql'),
// 服务器地址
'hostname' => env('database.hostname', '127.0.0.1'),
// 数据库名
'database' => env('database.database', ''),
// 用户名
'username' => env('database.username', 'root'),
// 密码
'password' => env('database.password', ''),
// 端口
'hostport' => env('database.hostport', '3306'),
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => env('database.charset', 'utf8'),
// 数据库表前缀
'prefix' => env('database.prefix', ''),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => env('app_debug', true),
// 开启字段缓存
'fields_cache' => false,
],
// 更多的数据库配置信息
],
];
<?php
return [
// 加密盐
'salt' => 'RKek2dUYSoigxD6',
// jwt 密码
'jwt_key' => 'zY6dBijuOjEpxr6',
// 项目域名
'domain' => 'http://www.df.com',
// 端口
'ws_port' => 9120,
// 是否开启ssl
'open_ssl' => env('SSL.IS_OPEN', false),
// ssl配置文件
'context' => [
'ssl' => [
'local_cert' => env('SSL.LOCAL_CERT', ''),
'local_pk' => env('SSL.LOCAL_PK', ''),
'verify_peer' => false,
]
]
];
\ No newline at end of file
<?php
return [
// 默认磁盘
'default' => env('filesystem.driver', 'local'),
// 磁盘列表
'disks' => [
'local' => [
'type' => 'local',
'root' => app()->getRuntimePath() . 'storage',
],
'public' => [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'public/storage',
// 磁盘路径对应的外部URL路径
'url' => '/storage',
// 可见性
'visibility' => 'public',
],
// 更多的磁盘配置信息
],
];
<?php
// +----------------------------------------------------------------------
// | 多语言设置
// +----------------------------------------------------------------------
return [
// 默认语言
'default_lang' => env('lang.default_lang', 'zh-cn'),
// 允许的语言列表
'allow_lang_list' => [],
// 多语言自动侦测变量名
'detect_var' => 'lang',
// 是否使用Cookie记录
'use_cookie' => true,
// 多语言cookie变量
'cookie_var' => 'think_lang',
// 多语言header变量
'header_var' => 'think-lang',
// 扩展语言包
'extend_list' => [],
// Accept-Language转义为对应语言包名称
'accept_language' => [
'zh-hans-cn' => 'zh-cn',
],
// 是否支持语言分组
'allow_group' => false,
];
<?php
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
return [
// 默认日志记录通道
'default' => env('log.channel', 'file'),
// 日志记录级别
'level' => [],
// 日志类型记录的通道 ['error'=>'email',...]
'type_channel' => [],
// 关闭全局日志写入
'close' => false,
// 全局日志处理 支持闭包
'processor' => null,
// 日志通道列表
'channels' => [
'file' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => '',
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => [],
// 最大日志文件数量
'max_files' => 0,
// 使用JSON格式记录
'json' => false,
// 日志处理
'processor' => null,
// 关闭通道日志写入
'close' => false,
// 日志输出格式化
'format' => '[%s][%s] %s',
// 是否实时写入
'realtime_write' => false,
],
// 其它日志通道配置
],
];
<?php
// 中间件配置
return [
// 别名或分组
'alias' => [],
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
'priority' => [],
];
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => 'html',
// URL普通方式参数 用于自动生成
'url_common_param' => true,
// 是否开启路由延迟解析
'url_lazy_route' => false,
// 是否强制使用路由
'url_route_must' => false,
// 合并路由规则
'route_rule_merge' => false,
// 路由是否完全匹配
'route_complete_match' => false,
// 访问控制器层名称
'controller_layer' => 'controller',
// 空控制器名
'empty_controller' => 'Error',
// 是否使用控制器后缀
'controller_suffix' => false,
// 默认的路由变量规则
'default_route_pattern' => '[\w\.]+',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache_key' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 操作方法后缀
'action_suffix' => '',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
];
<?php
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
return [
// session name
'name' => 'PHPSESSID',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// 驱动方式 支持file cache
'type' => 'file',
// 存储连接标识 当type使用cache的时候有效
'store' => null,
// 过期时间
'expire' => 1440,
// 前缀
'prefix' => '',
];
<?php
// +----------------------------------------------------------------------
// | Trace设置 开启调试模式后有效
// +----------------------------------------------------------------------
return [
// 内置Html和Console两种方式 支持扩展
'type' => 'Html',
// 读取的日志通道名
'channel' => '',
];
<?php
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
return [
// 模板引擎类型使用Think
'type' => 'Think',
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
'auto_rule' => 1,
// 模板目录名
'view_dir_name' => 'view',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DIRECTORY_SEPARATOR,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
];
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
namespace think;
require __DIR__ . '/../vendor/autoload.php';
// 执行HTTP应用并响应
$http = (new App())->http;
$response = $http->run();
$response->send();
$http->end($response);
User-agent: *
Disallow:
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id$
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
return false;
} else {
$_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php';
require __DIR__ . "/index.php";
}
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;
Route::get('think', function () {
return 'hello,ThinkPHP6!';
});
Route::get('hello/:name', 'index/hello');
#!/usr/bin/env php
<?php
namespace think;
// 命令行入口文件
// 加载基础文件
require __DIR__ . '/vendor/autoload.php';
// 应用初始化
(new App())->console->run();
\ No newline at end of file
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit9cfc229541c39f90347f54af72ca1407::getLoader();
../symfony/var-dumper/Resources/bin/var-dump-server
\ No newline at end of file
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Ip2Region' => $vendorDir . '/zoujingli/ip2region/Ip2Region.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'' => array($baseDir . '/extend'),
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src'),
'app\\' => array($baseDir . '/app'),
'Workerman\\MySQL\\' => array($vendorDir . '/workerman/mysql/src'),
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'PHPSocketIO\\' => array($vendorDir . '/workerman/phpsocket.io/src'),
'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'),
'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'),
'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
'GlobalData\\' => array($vendorDir . '/workerman/globaldata/src'),
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
'Channel\\' => array($vendorDir . '/workerman/channel/src'),
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit9cfc229541c39f90347f54af72ca1407
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit9cfc229541c39f90347f54af72ca1407', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit9cfc229541c39f90347f54af72ca1407', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit9cfc229541c39f90347f54af72ca1407::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit9cfc229541c39f90347f54af72ca1407::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire9cfc229541c39f90347f54af72ca1407($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire9cfc229541c39f90347f54af72ca1407($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit9cfc229541c39f90347f54af72ca1407
{
public static $files = array (
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
);
public static $prefixLengthsPsr4 = array (
't' =>
array (
'think\\trace\\' => 12,
'think\\' => 6,
),
'a' =>
array (
'app\\' => 4,
),
'W' =>
array (
'Workerman\\MySQL\\' => 16,
'Workerman\\' => 10,
),
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Component\\VarDumper\\' => 28,
),
'P' =>
array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8,
'Psr\\Http\\Message\\' => 17,
'Psr\\Container\\' => 14,
'Psr\\Cache\\' => 10,
'PHPSocketIO\\' => 12,
),
'L' =>
array (
'League\\MimeTypeDetection\\' => 25,
'League\\Flysystem\\Cached\\' => 24,
'League\\Flysystem\\' => 17,
),
'G' =>
array (
'GlobalData\\' => 11,
),
'F' =>
array (
'Firebase\\JWT\\' => 13,
),
'C' =>
array (
'Channel\\' => 8,
),
);
public static $prefixDirsPsr4 = array (
'think\\trace\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/think-trace/src',
),
'think\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/framework/src/think',
1 => __DIR__ . '/..' . '/topthink/think-helper/src',
2 => __DIR__ . '/..' . '/topthink/think-orm/src',
),
'app\\' =>
array (
0 => __DIR__ . '/../..' . '/app',
),
'Workerman\\MySQL\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/mysql/src',
),
'Workerman\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/workerman',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Component\\VarDumper\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',
),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'Psr\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/cache/src',
),
'PHPSocketIO\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/phpsocket.io/src',
),
'League\\MimeTypeDetection\\' =>
array (
0 => __DIR__ . '/..' . '/league/mime-type-detection/src',
),
'League\\Flysystem\\Cached\\' =>
array (
0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src',
),
'League\\Flysystem\\' =>
array (
0 => __DIR__ . '/..' . '/league/flysystem/src',
),
'GlobalData\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/globaldata/src',
),
'Firebase\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
),
'Channel\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/channel/src',
),
);
public static $fallbackDirsPsr0 = array (
0 => __DIR__ . '/../..' . '/extend',
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Ip2Region' => __DIR__ . '/..' . '/zoujingli/ip2region/Ip2Region.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit9cfc229541c39f90347f54af72ca1407::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit9cfc229541c39f90347f54af72ca1407::$prefixDirsPsr4;
$loader->fallbackDirsPsr0 = ComposerStaticInit9cfc229541c39f90347f54af72ca1407::$fallbackDirsPsr0;
$loader->classMap = ComposerStaticInit9cfc229541c39f90347f54af72ca1407::$classMap;
}, null, ClassLoader::class);
}
}
<?php return array (
'root' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '8430ffadd122d80c10a5d659566ff0e3251bf3b6',
'name' => 'topthink/think',
),
'versions' =>
array (
'firebase/php-jwt' =>
array (
'pretty_version' => 'v6.1.2',
'version' => '6.1.2.0',
'aliases' =>
array (
),
'reference' => 'c297139da7c6873dbd67cbd1093f09ec0bbd0c50',
),
'league/flysystem' =>
array (
'pretty_version' => '1.1.9',
'version' => '1.1.9.0',
'aliases' =>
array (
),
'reference' => '094defdb4a7001845300334e7c1ee2335925ef99',
),
'league/flysystem-cached-adapter' =>
array (
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'aliases' =>
array (
),
'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff',
),
'league/mime-type-detection' =>
array (
'pretty_version' => '1.11.0',
'version' => '1.11.0.0',
'aliases' =>
array (
),
'reference' => 'ff6248ea87a9f116e78edd6002e39e5128a0d4dd',
),
'psr/cache' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
),
'psr/container' =>
array (
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'aliases' =>
array (
),
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
),
'psr/http-message' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
),
'psr/log' =>
array (
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'aliases' =>
array (
),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
),
'psr/simple-cache' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
),
'symfony/polyfill-mbstring' =>
array (
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'aliases' =>
array (
),
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
),
'symfony/polyfill-php72' =>
array (
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'aliases' =>
array (
),
'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976',
),
'symfony/polyfill-php80' =>
array (
'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0',
'aliases' =>
array (
),
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
),
'symfony/var-dumper' =>
array (
'pretty_version' => 'v4.4.41',
'version' => '4.4.41.0',
'aliases' =>
array (
),
'reference' => '58eb36075c04aaf92a7a9f38ee9a8b97e24eb481',
),
'topthink/framework' =>
array (
'pretty_version' => 'v6.0.12',
'version' => '6.0.12.0',
'aliases' =>
array (
),
'reference' => 'e478316ac843c1a884a3b3a7a94db17c4001ff5c',
),
'topthink/think' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '8430ffadd122d80c10a5d659566ff0e3251bf3b6',
),
'topthink/think-helper' =>
array (
'pretty_version' => 'v3.1.6',
'version' => '3.1.6.0',
'aliases' =>
array (
),
'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
),
'topthink/think-orm' =>
array (
'pretty_version' => 'v2.0.52',
'version' => '2.0.52.0',
'aliases' =>
array (
),
'reference' => '407a60658f37fc57422ab95a9922c6f69af90f46',
),
'topthink/think-trace' =>
array (
'pretty_version' => 'v1.4',
'version' => '1.4.0.0',
'aliases' =>
array (
),
'reference' => '9a9fa8f767b6c66c5a133ad21ca1bc96ad329444',
),
'workerman/channel' =>
array (
'pretty_version' => 'v1.1.0',
'version' => '1.1.0.0',
'aliases' =>
array (
),
'reference' => '3df772d0d20d4cebfcfd621c33d1a1ab732db523',
),
'workerman/globaldata' =>
array (
'pretty_version' => 'v1.0.3',
'version' => '1.0.3.0',
'aliases' =>
array (
),
'reference' => 'baf3b7af338f329e88136ebe92266dfe40dd00a7',
),
'workerman/mysql' =>
array (
'pretty_version' => 'v1.0.6',
'version' => '1.0.6.0',
'aliases' =>
array (
),
'reference' => '28272aa68f9ea1a482f9bb0cf709d169f772d228',
),
'workerman/phpsocket.io' =>
array (
'pretty_version' => 'v1.1.14',
'version' => '1.1.14.0',
'aliases' =>
array (
),
'reference' => 'a5758da4d55b4744a4cc9c956816d88ce385601e',
),
'workerman/workerman' =>
array (
'pretty_version' => 'v4.0.36',
'version' => '4.0.36.0',
'aliases' =>
array (
),
'reference' => 'ecf8b791f1a4beb98c1e0e9d09988cd4b0d1c5ab',
),
'zoujingli/ip2region' =>
array (
'pretty_version' => 'v1.0.12',
'version' => '1.0.12.0',
'aliases' =>
array (
),
'reference' => '82cebc7a6be46524797454e98d3b165521065c26',
),
),
);
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70400)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}
Copyright (c) 2011, Neuman Vong
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the copyright holder nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"name": "firebase/php-jwt",
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"keywords": [
"php",
"jwt"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"license": "BSD-3-Clause",
"require": {
"php": "^7.1||^8.0"
},
"suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"require-dev": {
"phpunit/phpunit": "^7.5||9.5"
}
}
parameters:
level: 7
paths:
- src
treatPhpDocTypesAsCertain: false
<?php
namespace Firebase\JWT;
class BeforeValidException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
class ExpiredException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
use DomainException;
use InvalidArgumentException;
use UnexpectedValueException;
/**
* JSON Web Key implementation, based on this spec:
* https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
*
* PHP version 5
*
* @category Authentication
* @package Authentication_JWT
* @author Bui Sy Nguyen <nguyenbs@gmail.com>
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
* @link https://github.com/firebase/php-jwt
*/
class JWK
{
/**
* Parse a set of JWK keys
*
* @param array<mixed> $jwks The JSON Web Key Set as an associative array
*
* @return array<string, Key> An associative array of key IDs (kid) to Key objects
*
* @throws InvalidArgumentException Provided JWK Set is empty
* @throws UnexpectedValueException Provided JWK Set was invalid
* @throws DomainException OpenSSL failure
*
* @uses parseKey
*/
public static function parseKeySet(array $jwks): array
{
$keys = [];
if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
}
if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
}
foreach ($jwks['keys'] as $k => $v) {
$kid = isset($v['kid']) ? $v['kid'] : $k;
if ($key = self::parseKey($v)) {
$keys[(string) $kid] = $key;
}
}
if (0 === \count($keys)) {
throw new UnexpectedValueException('No supported algorithms found in JWK Set');
}
return $keys;
}
/**
* Parse a JWK key
*
* @param array<mixed> $jwk An individual JWK
*
* @return Key The key object for the JWK
*
* @throws InvalidArgumentException Provided JWK is empty
* @throws UnexpectedValueException Provided JWK was invalid
* @throws DomainException OpenSSL failure
*
* @uses createPemFromModulusAndExponent
*/
public static function parseKey(array $jwk): ?Key
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
}
if (!isset($jwk['kty'])) {
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
}
if (!isset($jwk['alg'])) {
// The "alg" parameter is optional in a KTY, but is required for parsing in
// this library. Add it manually to your JWK array if it doesn't already exist.
// @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
throw new UnexpectedValueException('JWK must contain an "alg" parameter');
}
switch ($jwk['kty']) {
case 'RSA':
if (!empty($jwk['d'])) {
throw new UnexpectedValueException('RSA private keys are not supported');
}
if (!isset($jwk['n']) || !isset($jwk['e'])) {
throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
}
$pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
$publicKey = \openssl_pkey_get_public($pem);
if (false === $publicKey) {
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
);
}
return new Key($publicKey, $jwk['alg']);
default:
// Currently only RSA is supported
break;
}
return null;
}
/**
* Create a public key represented in PEM format from RSA modulus and exponent information
*
* @param string $n The RSA modulus encoded in Base64
* @param string $e The RSA exponent encoded in Base64
*
* @return string The RSA public key represented in PEM format
*
* @uses encodeLength
*/
private static function createPemFromModulusAndExponent(
string $n,
string $e
): string {
$mod = JWT::urlsafeB64Decode($n);
$exp = JWT::urlsafeB64Decode($e);
$modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
$publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
$rsaPublicKey = \pack(
'Ca*a*a*',
48,
self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
$modulus,
$publicExponent
);
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$rsaPublicKey = \chr(0) . $rsaPublicKey;
$rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
$rsaPublicKey = \pack(
'Ca*a*',
48,
self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
$rsaOID . $rsaPublicKey
);
$rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
\chunk_split(\base64_encode($rsaPublicKey), 64) .
'-----END PUBLIC KEY-----';
return $rsaPublicKey;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @param int $length
* @return string
*/
private static function encodeLength(int $length): string
{
if ($length <= 0x7F) {
return \chr($length);
}
$temp = \ltrim(\pack('N', $length), \chr(0));
return \pack('Ca*', 0x80 | \strlen($temp), $temp);
}
}
<?php
namespace Firebase\JWT;
use OpenSSLAsymmetricKey;
use OpenSSLCertificate;
use TypeError;
use InvalidArgumentException;
class Key
{
/** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */
private $keyMaterial;
/** @var string */
private $algorithm;
/**
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @param string $algorithm
*/
public function __construct(
$keyMaterial,
string $algorithm
) {
if (
!is_string($keyMaterial)
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
&& !$keyMaterial instanceof OpenSSLCertificate
&& !is_resource($keyMaterial)
) {
throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
}
if (empty($keyMaterial)) {
throw new InvalidArgumentException('Key material must not be empty');
}
if (empty($algorithm)) {
throw new InvalidArgumentException('Algorithm must not be empty');
}
// TODO: Remove in PHP 8.0 in favor of class constructor property promotion
$this->keyMaterial = $keyMaterial;
$this->algorithm = $algorithm;
}
/**
* Return the algorithm valid for this key
*
* @return string
*/
public function getAlgorithm(): string
{
return $this->algorithm;
}
/**
* @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
*/
public function getKeyMaterial()
{
return $this->keyMaterial;
}
}
<?php
namespace Firebase\JWT;
class SignatureInvalidException extends \UnexpectedValueException
{
}
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = LF
[*.php]
indent_style = space
indent_size = 4
coverage
coverage.xml
composer.lock
vendor
\ No newline at end of file
<?php
return Symfony\CS\Config\Config::create()
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
->fixers(['-yoda_conditions', 'ordered_use', 'short_array_syntax'])
->finder(Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__.'/src/'));
\ No newline at end of file
filter:
paths: [src/*]
checks:
php:
code_rating: true
remove_extra_empty_lines: true
remove_php_closing_tag: true
remove_trailing_whitespace: true
fix_use_statements:
remove_unused: true
preserve_multiple: false
preserve_blanklines: true
order_alphabetically: true
fix_php_opening_tag: true
fix_linefeed: true
fix_line_ending: true
fix_identation_4spaces: true
fix_doc_comments: true
tools:
external_code_coverage:
timeout: 900
runs: 6
php_code_coverage: false
php_code_sniffer:
config:
standard: PSR2
filter:
paths: ['src']
php_loc:
enabled: true
excluded_dirs: [vendor, spec, stubs]
php_cpd:
enabled: true
excluded_dirs: [vendor, spec, stubs]
\ No newline at end of file
language: php
php:
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
matrix:
allow_failures:
- php: 5.5
env:
- COMPOSER_OPTS=""
- COMPOSER_OPTS="--prefer-lowest"
install:
- if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi
- if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require phpunit/phpunit:^6.0 --prefer-dist --update-with-dependencies; fi
- travis_retry composer update --prefer-dist $COMPOSER_OPTS
script:
- vendor/bin/phpspec run
- vendor/bin/phpunit
after_script:
- wget https://scrutinizer-ci.com/ocular.phar'
- php ocular.phar code-coverage:upload --format=php-clover ./clover/phpunit.xml'
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论