增加websoket服务端

This commit is contained in:
lccsw
2025-11-15 15:04:20 +08:00
parent 3ef25ee828
commit 864be75e2f
36613 changed files with 3774010 additions and 1765 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
defined('BASEPATH') or exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
@@ -58,7 +58,7 @@ $autoload['packages'] = array();
|
| $autoload['libraries'] = array('user_agent' => 'ua');
*/
$autoload['libraries'] = array('database','myResponse');
$autoload['libraries'] = array('database', 'myResponse');
/*
| -------------------------------------------------------------------
@@ -89,7 +89,7 @@ $autoload['drivers'] = array();
|
| $autoload['helper'] = array('url', 'file');
*/
$autoload['helper'] = array('comm', 'sys', 'url','image');
$autoload['helper'] = array('comm', 'sys', 'url', 'image', 'authorization');
/*
| -------------------------------------------------------------------
+12
View File
@@ -0,0 +1,12 @@
<?php
/**
* websocket配置文件
*/
defined('BASEPATH') or exit('No direct script access allowed');
$config['url'] = "ws://api.ss.haodian.cn/wss";
$config['jwt_key_pingan'] = 'dvsr23423vsgAEDger'; //平安端生成用户秘钥
$config['jwt_key_system'] = '2343ljfwefefew';//后端生成用户秘钥
$config['jwt_algorithm'] = 'HS256';
+37 -20
View File
@@ -1,54 +1,71 @@
<?php
//enter
defined('BASEPATH') OR exit('No direct script access allowed');
defined('BASEPATH') or exit('No direct script access allowed');
class Welcome extends CI_Controller {
class Welcome extends CI_Controller
{
public function index()
{
public function index()
{
$this->load->model('sys/sys_notice_model');
$this->load->model('sys/sys_menu_model');
$list = $this->sys_menu_model->select(array('status' => 1), 'sort desc', 0, 0);
$this->load->model('sys/sys_role_model');
$role = $this->sys_role_model->get(array('id' => $this->role));
$menu_ids = explode(',', $role['menu_ids']);
foreach ($list as $item)
{
if($this->role != SUPER_ADMIN && !in_array($item['id'], $menu_ids))
{
foreach ($list as $item) {
if ($this->role != SUPER_ADMIN && !in_array($item['id'], $menu_ids)) {
continue;
}
$map[$item['id']] = $item;
}
foreach ($list as $item)
{
if($this->role != SUPER_ADMIN && !in_array($item['id'], $menu_ids))
{
foreach ($list as $item) {
if ($this->role != SUPER_ADMIN && !in_array($item['id'], $menu_ids)) {
continue;
}
if (isset($item['pid']) && isset($map[$item['pid']]))
{
if (isset($item['pid']) && isset($map[$item['pid']])) {
$map[$item['pid']]['sub'][] = &$map[$item['id']];
}
else
{
} else {
$this->data['menus'][] = &$map[$item['id']];
}
}
unset($map);
$_notice = [];
$where = [
'platform' => Sys_notice_model::PLAT_FORM_ADMIN,
'uid' => $this->uid,
];
$_noticeCount = $this->sys_notice_model->count($where);
if ($_noticeCount) {
$rows = $this->sys_notice_model->select($where, 'id desc', 1, 10);
foreach ($rows as $item) {
$_notice[] = [
'id' => $item['id'],
'icon' => Sys_notice_model::ICON_TYPE[$item['icon']] ?: Sys_notice_model::ICON_DEFAULT,
'content' => $item['content'],
'url' => $item['url'],
'read' => $item['read'],
'readCn' => $item['read'] ? '已读' : '未读',
'type' => $item['type'],
'c_time' => date('Y-m-d H:i:s')
];
}
}
$this->data['_username'] = $this->username;
$this->data['_role'] = $role['name'];
$this->data['_notice'] = $_notice;
$this->data['_noticeCount'] = $_noticeCount;
$this->load->view('index', $this->data);
return true;
}
}
public function nopage()
public function nopage()
{
$this->load->view('nopage');
+67
View File
@@ -0,0 +1,67 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Wss extends HD_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('ws/ws_conn_model');
$this->load->model('sys/sys_notice_model');
}
public function index()
{
$this->data['platformList'] = Sys_notice_model::PLATFORM_LIST;
$this->data['_title'] = '消息推送工具';
$this->show_view('sys/utils/wss/index', true);
}
public function lists()
{
}
public function add()
{
$info = $this->input->post();
if (!$info['uid'] || !$info['content'] || !$info['platform']) {
return $this->show_json(SYS_CODE_FAIL, '参数错误');
}
$params = [
'platform' => $info['platform'],
'uid' => $info['uid'],
'content' => $info['content'],
];
$endPlatform = Ws_conn_model::PLAT_FORM_SYS_ADMIN;
/** @var MyResponse $req */
$req = $this->sys_notice_model->addNotice($params, $endPlatform, 8888888, true);
if (!$req->isSuccess()) {
return $this->show_json(SYS_CODE_FAIL, $req->getMessage());
}
return $this->show_json(SYS_CODE_SUCCESS, '发送成功');
}
public function get()
{
}
public function edit()
{
}
public function batch()
{
}
public function export()
{
}
public function del()
{
}
}
+8 -1
View File
@@ -36,6 +36,8 @@ class Auth
$CI->load->model('sys/sys_city_model');
$CI->load->model('Area_model');
$CI->load->model("biz/biz_model");
$CI->load->model('ws/ws_conn_model');
$CI->load->config('wss');
if ($user_info = json_decode($user_info, true)) {
//登录ip判断
@@ -239,9 +241,14 @@ class Auth
$CI->admin_biz_str = $CI->admin_biz ? implode(',', $CI->admin_biz) : '';
$CI->limit_province_id = 0;
if ($CI->belong) {
$biz = $CI->biz_model->get(['id' => $other_json['belong_id']],'province_id');
$biz = $CI->biz_model->get(['id' => $other_json['belong_id']], 'province_id');
$CI->limit_province_id = $biz['province_id'];
}
$wss_url = $CI->config->item('url');
$wss_token = generateToken($CI->uid, 'jwt_key_system');
$wss_platform = Ws_conn_model::PLAT_FORM_ADMIN;
$CI->data['wss_url'] = "{$wss_url}?token={$wss_token}&platform={$wss_platform}";
} elseif ($ctrl != 'login') {
header('location:/login');
}
+231 -85
View File
@@ -25,7 +25,7 @@
<script type="text/javascript" src="/static/js/plugin/bootstrap-select/popper.min.js"></script>
<script type="text/javascript" src="/static/js/common/jquery-3.0.0.js"></script>
<script type="text/javascript" src="/static/js/common/vue.min.js"></script>
<script type="text/javascript" src="/AmazeUI/assets/js/amazeui.js"></script>
<script type="text/javascript" src="/AmazeUI/assets/js/amazeui.js"></script>
<script type="text/javascript" src="/static/js/plugin/layer/layer.js"></script>
<script type="text/javascript" src="/static/js/common/admin.js?t=20210208"></script>
<script type="text/javascript" src="/static/js/plugin/layerpage/laypage.js"></script>
@@ -43,7 +43,7 @@
<script>window.ROOT_URL = '';</script>
</head>
<body>
<div class="coms-layout-container theme-default">
<div class="coms-layout-container theme-default" id="index-vue-app">
<div class="coms-layout-header">
<div class="bars-nav"><i class="am-icon-bars"></i>导航</div>
<a href="" class="logo" style="">
@@ -53,77 +53,94 @@
<ul class="header-nav">
<? foreach ($menus as $v) { ?>
<?php if (!$v['sub']) { ?>
<li data-menu-node='m-<?=$v['id']?>' data-open="<?=$v['url']?>"><a href="javascript:void (0);"><?=$v['name']?></a></li>
<li data-menu-node='m-<?= $v['id'] ?>' data-open="<?= $v['url'] ?>"><a
href="javascript:void (0);"><?= $v['name'] ?></a></li>
<?php } else { ?>
<li data-menu-node='m-<?=$v['id']?>'><a href="javascript:void (0);"><?=$v['name']?></a>
<li data-menu-node='m-<?= $v['id'] ?>'><a href="javascript:void (0);"><?= $v['name'] ?></a>
</li>
<?php } ?>
<?php } ?>
</ul>
<?php } ?>
<div class="header-userinfo">
<a class="info-name" href="javascript:;"><?=$_username?><span class="arrow"></span></a>
<a class="info-name" href="javascript:;"><?= $_username ?><span class="arrow"></span></a>
<ul class="dropdown-list">
<li><a href="javascript:void (0);" data-open="/expfile" data-title="导出文件">导出文件</a></li>
<li><a href="javascript:void (0);" data-modal="/login/reset_pwd" data-title="修改秘密">修改密码</a></li>
<li><a href="javascript:void (0);" data-load="/login/logout" data-confirm="确定要退出登录吗?">退出</a></li>
<li><a href="javascript:void (0);" data-load="/login/logout" data-confirm="确定要退出登录吗?">退出</a>
</li>
</ul>
</div>
<!--div class="header-notice">
<a class="tit" href="javascript:;">通知<b><i>0</i></b></a>
<div class="header-notice">
<a class="tit" href="javascript:;">通知<b><i>{{ countNotice }}</i></b></a>
<ul class="dropdown-list">
<li><a href="#">新的订单</a></li>
<template v-if="notice.length > 0">
<li v-for="item in notice">
<a href="#">{{ item.content }}</a>
</li>
<a href="javascript:void(0);" style="color: #ff4d4f; border-top: 1px solid #eee;">
<i class="fa"></i> 清除所有
</a>
<a href="javascript:void(0);">
<i class="fa"></i> 查看更多
</a>
</template>
<li v-if="notice.length === 0">
<a href="javascript:void(0);" style="color: #999; cursor: default;">暂无通知</a>
</li>
</ul>
</div-->
</div>
</div>
<div class="coms-layout-aside fold" id="J_coms-layout-aside" style="display: none">
<div class="aside-menu-scroll">
<?php if($menus){ ?>
<div class="aside-unfold"><i class="iconfont f18">&#xe6d4;</i></div>
<?php foreach ($menus as $pmenu) { ?>
<?php if ($pmenu['sub']) { ?>
<ul class="aside-menu" data-menu-box="m-<?=$pmenu['id']?>">
<?php foreach ($pmenu['sub'] as $menu) { ?>
<?php if (!$menu['sub']) { ?>
<li class="treeview" data-menu-node='m-<?=$pmenu['id']?>-<?=$menu['id']?>' data-open="<?=$menu['url']?>">
<a style="text-align: center" href="javascript:void(0)"><i class="iconfont f14">&#xe65d;</i><span class="txt"><?=$menu['name']?></span></a>
</li>
<?php } else { ?>
<li class="treeview">
<a href="javascript:void(0)" style="text-align: center">
<?php if ($menus) { ?>
<div class="aside-unfold"><i class="iconfont f18">&#xe6d4;</i></div>
<?php foreach ($menus as $pmenu) { ?>
<?php if ($pmenu['sub']) { ?>
<ul class="aside-menu" data-menu-box="m-<?= $pmenu['id'] ?>">
<?php foreach ($pmenu['sub'] as $menu) { ?>
<?php if (!$menu['sub']) { ?>
<li class="treeview" data-menu-node='m-<?= $pmenu['id'] ?>-<?= $menu['id'] ?>'
data-open="<?= $menu['url'] ?>">
<a style="text-align: center" href="javascript:void(0)"><i class="iconfont f14">&#xe65d;</i><span
class="txt"><?= $menu['name'] ?></span></a>
</li>
<?php } else { ?>
<li class="treeview">
<a href="javascript:void(0)" style="text-align: center">
<?php if($menu['icon']){?>
<i class="<?=$menu['icon']?> "></i>
<?php }else{ ?>
<i class="iconfont f14">&#xe65d;</i>
<?php } ?>
<span class="txt"><?=$menu['name']?></span>
</a>
<ul class="list" style="display: none" data-menu-box='m-<?=$pmenu['id']?>-<?=$menu['id']?>'>
<?php foreach ($menu['sub'] as $submenu) {
$url = $submenu['url'];
$node = "{$pmenu['id']}-{$menu['id']}-{$submenu['id']}";
if((!$url || $url == '#') && $submenu['sub']) {
$url = $submenu['sub'][0]['url'];
$node .= "-{$submenu['sub'][0]['id']}";
}
?>
<li data-menu-node='m-<?=$node?>' data-open="<?=$url?>">
<a href="javascript:void (0);"><?=$submenu['name']?></a>
</li>
<?php } ?>
</ul>
</li>
<?php if ($menu['icon']) { ?>
<i class="<?= $menu['icon'] ?> "></i>
<?php } else { ?>
<i class="iconfont f14">&#xe65d;</i>
<?php } ?>
<span class="txt"><?= $menu['name'] ?></span>
</a>
<ul class="list" style="display: none"
data-menu-box='m-<?= $pmenu['id'] ?>-<?= $menu['id'] ?>'>
<?php foreach ($menu['sub'] as $submenu) {
$url = $submenu['url'];
$node = "{$pmenu['id']}-{$menu['id']}-{$submenu['id']}";
if ((!$url || $url == '#') && $submenu['sub']) {
$url = $submenu['sub'][0]['url'];
$node .= "-{$submenu['sub'][0]['id']}";
}
?>
<li data-menu-node='m-<?= $node ?>' data-open="<?= $url ?>">
<a href="javascript:void (0);"><?= $submenu['name'] ?></a>
</li>
<?php } ?>
</ul>
</li>
<?php } ?>
<?php } ?>
<?php } ?>
</ul>
</ul>
<?php } ?>
<?php } ?>
<div class="aside-menu-sub">
</div>
<?php } ?>
<div class="aside-menu-sub">
</div>
<?php }?>
</div>
</div>
@@ -131,26 +148,28 @@
<div class="coms-layout-body-inner">
<article class="am-article" style="display: none">
<div class="am-article-hd">
<h1 class="am-article-title">欢迎 [<?=$_role?>] <?=$_username?></h1>
<h1 class="am-article-title">欢迎 [<?= $_role ?>] <?= $_username ?></h1>
<p class="am-article-meta">
<?php
$no = date("H", time());
$week = array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日");
if ($no > 0 && $no <= 6){
echo "凌晨好!";
}elseif ($no > 6 && $no < 12){
echo "上午好!";
}elseif ($no >= 12 && $no <= 18){
echo "下午好!";
}else{
echo "晚上好!";
}
?>
<?php
$no = date("H", time());
$week = array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日");
if ($no > 0 && $no <= 6) {
echo "凌晨好!";
} elseif ($no > 6 && $no < 12) {
echo "上午好!";
} elseif ($no >= 12 && $no <= 18) {
echo "下午好!";
} else {
echo "晚上好!";
}
?>
</p>
</div>
<div class="am-article-bd">
<p class="am-article-lead">现在时间是:<?=date('Y年m月d日')?> <?=$week[date('w')]?> <?=date('H:i:s')?> 当前IP<?=get_client_ip()?></p>
<p class="am-article-lead">
现在时间是:<?= date('Y年m月d日') ?> <?= $week[date('w')] ?> <?= date('H:i:s') ?>
当前IP<?= get_client_ip() ?></p>
</div>
</article>
</div>
@@ -163,43 +182,61 @@
<script type="text/javascript" src="/static/js/common/app.js?v=1"></script>
<script type="text/javascript">
//查看图片控件
function showViewer(obj){
function showViewer(obj) {
new Viewer(document.getElementById(obj));
}
var _index_vue_obj;
var log_data = {};
var heartbeatInterval = null;
var pongTimeout = null;
(function ($) {
$(".coms-layout-header .bars-nav").on("click",function(event){
_index_vue_obj = new Vue({
el: '#index-vue-app',
data: {
countNotice: <?=$_noticeCount?>,
notice: <?=json_encode($_notice)?>
},
mounted: function () {
},
methods: {}
});
// 初始化 WebSocket 连接
initWebSocket();
$(".coms-layout-header .bars-nav").on("click", function (event) {
event.stopPropagation()
var $headNav=$(".header-nav");
if($headNav.hasClass("active")){
var $headNav = $(".header-nav");
if ($headNav.hasClass("active")) {
$headNav.removeClass("active")
}else{
} else {
$headNav.addClass("active")
}
});
$("body").on("touchstart",function(event){
if($(event.target).closest(".header-nav").length){
$("body").on("touchstart", function (event) {
if ($(event.target).closest(".header-nav").length) {
return;
}else{
} else {
$(".header-nav").removeClass("active");
}
})
$(function(){
var $aside=$("#J_coms-layout-aside"),
$fold=$aside.find(".aside-unfold"),
$mainBody=$("#J_coms-layout-body");
$fold.on("click",function(){
$(function () {
var $aside = $("#J_coms-layout-aside"),
$fold = $aside.find(".aside-unfold"),
$mainBody = $("#J_coms-layout-body");
$fold.on("click", function () {
if($aside.hasClass('fold')){
if ($aside.hasClass('fold')) {
$aside.removeClass('fold');
$mainBody.removeClass('unfold');
$('.coms-layout-body').css('left',220);
$(".coms-body-main-nav").css("left",220)
}else{
$('.coms-layout-body').css('left', 220);
$(".coms-body-main-nav").css("left", 220)
} else {
$aside.addClass('fold');
$mainBody.addClass('unfold');
$('.coms-layout-body').css('left',65);
$(".coms-body-main-nav").css("left",65);
$('.coms-layout-body').css('left', 65);
$(".coms-body-main-nav").css("left", 65);
}
});
@@ -215,6 +252,115 @@
});
})
})(jQuery)
function initWebSocket() {
// 构建 WebSocket 连接 URL
var wsUrl = "<?=$wss_url?>";
try {
// 创建 WebSocket 实例
var websocket = new WebSocket(wsUrl);
// 连接打开事件
websocket.onopen = function (event) {
console.log('websocket 连接成功');
// 在websocket.onopen回调中添加:
heartbeatInterval = setInterval(function () {
if (window.adminWebsocket && window.adminWebsocket.readyState === WebSocket.OPEN) {
window.adminWebsocket.send(JSON.stringify({type: 'heartbeat', content: 'ping'}));
// 设置等待pong响应的超时
pongTimeout = setTimeout(function () {
console.warn('Heartbeat timeout - closing connection');
window.adminWebsocket.close();
}, 5000); // 5秒内等待pong响应
}
}, 30000); // 每30秒发送一次ping
};
// 接收消息事件
websocket.onmessage = function (event) {
try {
console.log('websocket 接收到消息:', event.data);
var data = JSON.parse(event.data);
handleWebSocketMessage(data);
} catch (e) {
console.error('websocket 解析消息错误:', e);
}
};
// 错误处理事件
websocket.onerror = function (error) {
console.error('websocket 错误信息:', error);
};
// 连接关闭事件
websocket.onclose = function (event) {
console.log('websocket 关闭连接');
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
if (pongTimeout) {
clearTimeout(pongTimeout);
pongTimeout = null;
}
// 5秒后尝试重连
setTimeout(initWebSocket, 5000);
};
// 保存 WebSocket 实例供全局使用
window.adminWebsocket = websocket;
} catch (e) {
console.error('初始化 websocket 失败:', e);
}
}
/**
* 消息处理
* @param data
*/
function handleWebSocketMessage(data) {
// 处理不同类型的消息
switch (data.type) {
case 'notice':
// 显示通知消息
showNotification("您收到一条新的系统通知,请及时查看");
_index_vue_obj.countNotice++;
_index_vue_obj.notice = [data.data].concat(_index_vue_obj.notice);
break;
case 'heartbeat':
// 收到pong响应时清除超时定时器
if (pongTimeout) {
clearTimeout(pongTimeout);
pongTimeout = null;
}
console.log('websocket 心跳检测正常');
break;
default:
console.log('Received message:', data);
}
}
function showNotification(message) {
// 使用现有的 layer.js 显示通知
layer.msg(message, {
time: 5000,
icon: 1,
offset: 't', // t表示顶部显示
anim: 0, // 使用淡入淡出动画
isOutAnim: false // 关闭移出动画
});
}
// 提供全局发送消息的方法
window.sendWebSocketMessage = function (message) {
if (window.adminWebsocket &&
window.adminWebsocket.readyState === WebSocket.OPEN) {
window.adminWebsocket.send(JSON.stringify(message));
} else {
console.warn('websocket 未连接');
}
};
</script>
</html>
+66
View File
@@ -0,0 +1,66 @@
<form id="vue-edit" class="am-form am-form-horizontal" action="/sys/city/city/add" data-auto="true" method="post"
style="width: 90%;padding:25px 30px 20px 0;margin: 0 auto">
<div class="am-form-group">
<label class="am-para-label"><span class="com-must-star">*</span>推送平台:</label>
<div class="am-para-input">
<select name="platform" v-model="info.platform">
<option value="">选择推送平台</option>
<option v-for="(v,i) in platformList" :value="i">{{v}}</option>
</select>
</div>
</div>
<div class="am-form-group">
<label class="am-para-label">
<span class="com-must-star">*</span>推送用户id</label>
<div class="am-para-input">
<input type="text" placeholder="输入用户id" name="uid" v-model="info.uid"/>
</div>
</div>
<div class="am-form-group">
<label class="am-para-label">
<span class="com-must-star">*</span>推送内容:</label>
<div class="am-para-input">
<input type="text" placeholder="输入推送内容" name="content" v-model="info.content"/>
</div>
</div>
<div class="am-form-group" style="margin-bottom: 2rem">
<div class="am-para-input">
<button class="am-btn am-btn-secondary" type="button" @click="saveEdit">提交</button>
</div>
</div>
</form>
<script>
var loading = 0;
var vue_obj;
$(function () {
vue_obj = new Vue({
el: '#vue-edit',
data: {
info: {
platform: 1,
uid: '',
content: '',
},
platformList: <?=json_encode($platformList, JSON_UNESCAPED_UNICODE)?>,
},
mounted: function () {
},
methods: {
saveEdit() {
if (!this.info.uid || !this.info.content) {
layer.msg("参数错误", {icon: 2});
return false
}
$.post('sys/utils/wss/add', this.info, function (response) {
if (response.code == 1) {
layer.msg(response.msg, {'icon': 1})
} else {
layer.msg(response.msg, {'icon': 2});
}
})
}
},
watch: {}
});
});
</script>
+1 -1
View File
@@ -88,7 +88,7 @@ class Login extends BaseController
}
$user['roles'] = $roles;
$user['authorities'] = $authorities;
$data['access_token'] = Authorization::generateToken($re['userId']);
$data['access_token'] = generateToken($re['userId']);
$data['user'] = $user;
$this->record->loginRecord(['userId' => $re['userId'], 'username' => $re['username'], 'nickname' => $re['nickname']]);
$redis->delete($code_key);//删除验证码
+1 -1
View File
@@ -90,7 +90,7 @@ class Login extends BaseController
}
$responseData = $response->getData();
$data = [
'Authorization' => Authorization::generateToken([$responseData['id'], $responseData['orgId'] ?: 0], 'jwt_key_auto'),
'Authorization' => generateToken([$responseData['id'], $responseData['orgId'] ?: 0], 'jwt_key_auto'),
];
$this->return_response($data, API_CODE_SUCCESS);
} catch (Exception $e) {
+1 -1
View File
@@ -79,7 +79,7 @@ class Login extends BaseController
}
$user['roles'] = $roles;
$user['authorities'] = $authorities;
$data['access_token'] = Authorization::generateToken($re['id'], 'jwt_key_pingan');
$data['access_token'] = generateToken($re['id'], 'jwt_key_pingan');
$data['user'] = $user;
$this->load->library('api/record');
$this->record->loginRecordPinAn(['userId' => $re['id'], 'username' => $re['username'], 'nickname' => $re['nickname'] ?: '', 'mobile' => $re['mobile']]);
@@ -0,0 +1,95 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
require_once APPPATH . 'controllers/pingan/BaseController.php';
class Notice extends BaseController
{
public function __construct()
{
parent::__construct();
$this->load->model('sys/sys_notice_model');
$this->sys_notice_model->set_db('ssdb');
}
/**
* 列表
* @return void
*/
public function page_get()
{
$params = $this->input_param();
$page = $params['page'] ?: 1;
$limit = $params['limit'] ?: 20;
$where = [
'platform' => Sys_notice_model::PLAT_FORM_PINGAN,
'uid' => $_SESSION['id']
];
strlen($params['read']) && $where['read'] = intval($params['read']);
$count = $this->sys_notice_model->count($where);
$list = [];
if ($count) {
$rows = $this->sys_notice_model->select($where, 'id desc', $page, $limit);
foreach ($rows as $item) {
$list[] = [
'id' => $item['id'],
'icon' => Sys_notice_model::ICON_TYPE[$item['icon']] ?: Sys_notice_model::ICON_DEFAULT,
'content' => $item['content'],
'url' => $item['url'],
'read' => $item['read'],
'readCn' => $item['read'] ? '已读' : '未读',
'type' => $item['type'],
'c_time' => date('Y-m-d H:i:s')
];
}
}
$data = ['list' => $list, 'count' => $count];
$this->return_response_list($data);
}
/**
* 获取未读消息
* @return void
*/
public function unRead_get()
{
$where = [
'platform' => Sys_notice_model::PLAT_FORM_PINGAN,
'uid' => $_SESSION['id'],
'read' => Sys_notice_model::STATUS_UNREAD
];
$noticeCount = $this->sys_notice_model->count($where);
$data = [
'noticeCount' => $noticeCount
];
$this->return_response($data);
}
/**
* 设置已读
* @return void
*/
public function index_post()
{
$ids = $this->input_param('ids');
$type = $this->input_param('type');
$where = [
'platform' => Sys_notice_model::PLAT_FORM_PINGAN,
'uid' => $_SESSION['id'],
'read' => Sys_notice_model::STATUS_UNREAD
];
if ($type != 'all') {
if (!$ids) {
$this->return_json('参数错误');
}
$strIds = implode(',', $ids);
if ($strIds) {
$where["id in($strIds)"] = null;
}
}
$this->sys_notice_model->update(['read' => Sys_notice_model::STATUS_READ], $where);
$this->return_response();
}
}
+1 -1
View File
@@ -262,7 +262,7 @@ class ApiAuthHook
{
if ($jwt) {
try {
$token = Authorization::validateToken($jwt, $item);
$token = validateToken($jwt, $item);
return $token;
} catch (Exception $ex) {
$this->httpUnauthorizedResponse($ex->getMessage());
+12
View File
@@ -0,0 +1,12 @@
<?php
/**
* websocket配置文件
*/
defined('BASEPATH') or exit('No direct script access allowed');
$config['url'] = "ws://api.ss.haodian.cn/wss";
$config['jwt_key_pingan'] = 'dvsr23423vsgAEDger'; //平安端生成用户秘钥
$config['jwt_key_system'] = '2343ljfwefefew';//后端生成用户秘钥
$config['jwt_algorithm'] = 'HS256';
+287
View File
@@ -0,0 +1,287 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class HD_WS_Controller extends CI_Controller
{
protected $db_config;
protected $last_connect_time = 0;
protected $reconnect_count = 0;
protected $last_ping_time = 0;
public function __construct()
{
parent::__construct();
$this->output->enable_profiler(FALSE);
$this->loadDatabaseConfig();
// 加载类
$this->load->library('myResponse');
$this->load->library('websocket/wsResponse');
$this->load->library('websocket/validToken');
$this->load->library('websocket/message');
$this->load->model('ws/ws_conn_model');
}
/**
* 手动加载数据库配置
*/
private function loadDatabaseConfig()
{
$config_path = APPPATH . 'config/database.php';
if (file_exists($config_path)) {
include $config_path;
if (isset($db) && is_array($db) && isset($db['default'])) {
$this->db_config = $db['default'];
// 确保使用短连接
$this->db_config['pconnect'] = FALSE;
$this->db_config['db_debug'] = FALSE; // 关闭调试,避免自动输出错误
return;
} else {
echo "[" . date('Y-m-d H:i:s') . "] 找不到数据库default配置\n";
}
} else {
echo "[" . date('Y-m-d H:i:s') . "] 找不到数据库配置文件\n";
}
}
/**
* 获取数据库连接(带自动重连和连接检查)
*/
public function getDbConnection()
{
$now = time();
// 检查现有连接是否有效
if (isset($this->db) && $this->db->conn_id) {
try {
// 定期ping数据库(每30秒一次)
if ($now - $this->last_ping_time > 30) {
$this->db->query('SELECT 1');
$this->last_ping_time = $now;
}
return $this->db;
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接已断开: " . $e->getMessage() . "\n";
// 关闭无效连接
if ($this->db->conn_id) {
try {
$this->db->close();
} catch (Exception $e2) {
// 忽略关闭时的错误
}
}
unset($this->db);
}
}
// 限制重连频率
if ($now - $this->last_connect_time < 2) { // 2秒内只能重连一次
if ($this->reconnect_count > 5) {
throw new Exception('数据库重连过于频繁,请检查数据库状态');
}
}
echo "[" . date('Y-m-d H:i:s') . "] 创建新的数据库连接...\n";
try {
// 创建新连接
$this->db = $this->load->database($this->db_config, TRUE);
if (!$this->db->conn_id) {
throw new Exception('数据库连接失败');
}
// 测试新连接
$this->db->query('SELECT 1');
$this->last_connect_time = $now;
$this->last_ping_time = $now;
$this->reconnect_count++;
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接创建成功\n";
return $this->db;
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接失败: " . $e->getMessage() . "\n";
unset($this->db);
throw $e;
}
}
/**
* 安全的数据库查询(自动重试)
*/
public function safeDbQuery($callback, $max_retry = 3)
{
$retry = 0;
$last_error = '';
while ($retry <= $max_retry) {
try {
$db = $this->getDbConnection();
$result = call_user_func($callback, $db);
// 重置重连计数(成功查询后)
if ($retry == 0) {
$this->reconnect_count = 0;
}
return $result;
} catch (Exception $e) {
$last_error = $e->getMessage();
$retry++;
// 检查是否是连接错误
$is_connection_error = $this->isConnectionError($last_error);
if ($is_connection_error) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接错误,重试 {$retry}/{$max_retry}\n";
// 如果是连接错误,强制重置连接
if (isset($this->db) && $this->db->conn_id) {
try {
$this->db->close();
} catch (Exception $e2) {
// 忽略关闭错误
}
unset($this->db);
}
if ($retry > $max_retry) {
throw new Exception('数据库操作失败,重试次数用尽: ' . $last_error);
}
// 等待后重试(递增等待时间)
usleep(100000 * $retry); // 100ms * 重试次数
} else {
// 非连接错误,直接抛出
throw new Exception('数据库查询错误: ' . $last_error);
}
}
}
throw new Exception('数据库操作失败: ' . $last_error);
}
/**
* 判断错误是否为连接错误
*/
private function isConnectionError($error_message)
{
$connection_errors = [
'MySQL server has gone away',
'Lost connection to MySQL server',
'Connection refused',
'Too many connections',
'Query execution was interrupted',
'SSL connection has been closed',
'Error reading result set'
];
foreach ($connection_errors as $error) {
if (stripos($error_message, $error) !== false) {
return true;
}
}
return false;
}
/**
* 记录连接信息
*/
public function recordConnection($fd, $user_id, $platform, $token, $ip)
{
return $this->safeDbQuery(function ($db) use ($fd, $user_id, $platform, $token, $ip) {
// 先清理该用户可能存在的旧连接
$db->where('user_id', $user_id);
$db->where('platform', $platform);
$delete_result = $db->delete('lc_ws_conn');
// if (!$delete_result) {
// // 删除失败不一定是错误,可能记录不存在
// }
// 插入新连接记录
$connection_data = [
'fd' => $fd,
'platform' => $platform,
'user_id' => $user_id,
'token' => $token,
'ip' => $ip,
'connect_time' => date('Y-m-d H:i:s'),
'last_activity' => date('Y-m-d H:i:s'),
'status' => 1
];
$insert_result = $db->replace('lc_ws_conn', $connection_data);
if (!$insert_result) {
throw new Exception('插入连接记录失败');
}
return $db->insert_id();
});
}
/**
* 删除连接记录
*/
public function removeConnection($fd)
{
return $this->safeDbQuery(function ($db) use ($fd) {
$db->where('fd', $fd);
$result = $db->delete('lc_ws_conn');
return $result;
});
}
/**
* 更新最后活动时间
*/
public function updateActivity($fd)
{
return $this->safeDbQuery(function ($db) use ($fd) {
$db->where('fd', $fd);
$result = $db->update('lc_ws_conn', [
'last_activity' => date('Y-m-d H:i:s')
]);
return true;
});
}
/**
* 根据用户ID获取连接FD
*/
public function getConnectionByUserId($platform, $user_id)
{
return $this->safeDbQuery(function ($db) use ($platform, $user_id) {
$db->select('*');
$db->from('lc_ws_conn');
$db->where('platform', $platform);
$db->where('user_id', $user_id);
$db->where('status', 1);
$query = $db->get();
if (!$query) {
throw new Exception('查询失败');
}
if ($query->num_rows() > 0) {
return $query->row();
}
return null;
});
}
/**
* 手动关闭数据库连接
*/
public function closeDbConnection()
{
if (isset($this->db) && $this->db->conn_id) {
try {
$this->db->close();
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接已关闭\n";
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 关闭数据库连接时出错: " . $e->getMessage() . "\n";
}
unset($this->db);
}
}
}
+4 -1
View File
@@ -4,6 +4,9 @@
"tencentcloud/ocr": "^3.0",
"wechatpay/wechatpay-guzzle-middleware": "^0.2.2",
"mikehaertl/php-pdftk": "^0.11.0",
"lcobucci/jwt": "^3.4"
"lcobucci/jwt": "^3.4",
"tencentcloud/tencentcloud-sdk-php": "^3.0",
"overtrue/pinyin": "^4.0",
"textalk/websocket": "^1.3"
}
}
+231 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9f27737ffbf35aa1f124c7f62201bb1c",
"content-hash": "82089265202c2da0bb73321d6f38427e",
"packages": [
{
"name": "gregwar/cache",
@@ -265,6 +265,83 @@
],
"time": "2021-04-26T09:17:50+00:00"
},
{
"name": "lcobucci/jwt",
"version": "3.4.6",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/jwt.git",
"reference": "3ef8657a78278dfeae7707d51747251db4176240"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/3ef8657a78278dfeae7707d51747251db4176240",
"reference": "3ef8657a78278dfeae7707d51747251db4176240",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-openssl": "*",
"php": "^5.6 || ^7.0"
},
"require-dev": {
"mikey179/vfsstream": "~1.5",
"phpmd/phpmd": "~2.2",
"phpunit/php-invoker": "~1.1",
"phpunit/phpunit": "^5.7 || ^7.3",
"squizlabs/php_codesniffer": "~2.3"
},
"suggest": {
"lcobucci/clock": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"files": [
"compat/class-aliases.php",
"compat/json-exception-polyfill.php",
"compat/lcobucci-clock-polyfill.php"
],
"psr-4": {
"Lcobucci\\JWT\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Luís Otávio Cobucci Oblonczyk",
"email": "lcobucci@gmail.com",
"role": "Developer"
}
],
"description": "A simple library to work with JSON Web Token and JSON Web Signature",
"keywords": [
"JWS",
"jwt"
],
"support": {
"issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/3.4.6"
},
"funding": [
{
"url": "https://github.com/lcobucci",
"type": "github"
},
{
"url": "https://www.patreon.com/lcobucci",
"type": "patreon"
}
],
"time": "2021-09-28T19:18:28+00:00"
},
{
"name": "mikehaertl/php-pdftk",
"version": "0.11.0",
@@ -374,6 +451,58 @@
],
"time": "2021-03-01T18:26:25+00:00"
},
{
"name": "overtrue/pinyin",
"version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/overtrue/pinyin.git",
"reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/overtrue/pinyin/zipball/94fdb3ea6eca5677afd9548111d95bedcd5a4086",
"reference": "94fdb3ea6eca5677afd9548111d95bedcd5a4086",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "~7.5"
},
"type": "library",
"autoload": {
"files": [
"src/const.php"
],
"psr-4": {
"Overtrue\\Pinyin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Carlos",
"homepage": "http://github.com/overtrue"
}
],
"description": "Chinese to pinyin translator.",
"homepage": "https://github.com/overtrue/pinyin",
"keywords": [
"Chinese",
"Pinyin",
"cn2pinyin"
],
"support": {
"issues": "https://github.com/overtrue/pinyin/issues",
"source": "https://github.com/overtrue/pinyin/tree/master"
},
"time": "2019-09-20T12:43:45+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.20",
@@ -808,6 +937,105 @@
"homepage": "https://github.com/tencentcloud-sdk-php/ocr",
"time": "2021-07-16T01:13:52+00:00"
},
{
"name": "tencentcloud/tencentcloud-sdk-php",
"version": "3.0.1396",
"source": {
"type": "git",
"url": "https://github.com/TencentCloud/tencentcloud-sdk-php.git",
"reference": "6b47ab8109795bcf8a55956e995604038cb7ea26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/TencentCloud/tencentcloud-sdk-php/zipball/6b47ab8109795bcf8a55956e995604038cb7ea26",
"reference": "6b47ab8109795bcf8a55956e995604038cb7ea26",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.3 || ^7.0",
"php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"TencentCloud\\": "./src/TencentCloud"
},
"classmap": [
"src/QcloudApi/QcloudApi.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "coolli",
"email": "tencentcloudapi@tencent.com",
"homepage": "https://cloud.tencent.com/document/sdk/PHP",
"role": "Developer"
}
],
"description": "TencentCloudApi php sdk",
"homepage": "https://github.com/TencentCloud/tencentcloud-sdk-php",
"support": {
"issues": "https://github.com/TencentCloud/tencentcloud-sdk-php/issues",
"source": "https://github.com/TencentCloud/tencentcloud-sdk-php/tree/3.0.1396"
},
"time": "2025-06-08T20:08:00+00:00"
},
{
"name": "textalk/websocket",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/Textalk/websocket-php.git",
"reference": "fe348408a43cc646d08a3ae73e7877370441c7ee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Textalk/websocket-php/zipball/fe348408a43cc646d08a3ae73e7877370441c7ee",
"reference": "fe348408a43cc646d08a3ae73e7877370441c7ee",
"shasum": ""
},
"require": {
"php": "^5.4|^7.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^0.7",
"phpunit/phpunit": "^4.1",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"WebSocket\\": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Fredrik Liljegren",
"email": "fredrik.liljegren@textalk.se"
},
{
"name": "Sören Jensen",
"email": "soren@abicart.se"
}
],
"description": "WebSocket client and server",
"support": {
"issues": "https://github.com/Textalk/websocket-php/issues",
"source": "https://github.com/Textalk/websocket-php/tree/1.3.1"
},
"time": "2020-06-07T12:11:38+00:00"
},
{
"name": "wechatpay/wechatpay-guzzle-middleware",
"version": "0.2.2",
@@ -856,5 +1084,6 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
"platform-dev": [],
"plugin-api-version": "2.2.0"
}
@@ -1,28 +1,24 @@
<?php
require_once APPPATH . 'libraries/JWT.php';
defined('BASEPATH') or exit('No direct script access allowed');
require_once COMMPATH . 'libraries/JWT.php';
use \Firebase\JWT\JWT;
class Authorization
{
public static function validateToken($token, $item = 'jwt_key')
if (!function_exists('validateToken')) {
function validateToken($token, $item = 'jwt_key')
{
$CI =& get_instance();
$key = $CI->config->item($item);
$algorithm = $CI->config->item('jwt_algorithm');
return JWT::decode($token, $key, array($algorithm));
}
}
public static function generateToken($data, $item = 'jwt_key')
if (!function_exists('generateToken')) {
function generateToken($data, $item = 'jwt_key')
{
$CI =& get_instance();
$key = $CI->config->item($item);
return JWT::encode($data, $key);
}
}
}
@@ -0,0 +1,7 @@
<?php
namespace Firebase\JWT;
class BeforeValidException extends \UnexpectedValueException
{
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace Firebase\JWT;
class ExpiredException extends \UnexpectedValueException
{
}
+362
View File
@@ -0,0 +1,362 @@
<?php
namespace Firebase\JWT;
require_once COMMPATH . 'libraries/BeforeValidException.php';
require_once COMMPATH . 'libraries/ExpiredException.php';
require_once COMMPATH . 'libraries/SignatureInvalidException.php';
use \DomainException;
use \InvalidArgumentException;
use \UnexpectedValueException;
use \DateTime;
/**
* JSON Web Token implementation, based on this spec:
* http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
*
* PHP version 5
*
* @category Authentication
* @package Authentication_JWT
* @author Neuman Vong <neuman@twilio.com>
* @author Anant Narayanan <anant@php.net>
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
* @link https://github.com/firebase/php-jwt
*/
class JWT {
/**
* When checking nbf, iat or expiration times,
* we want to provide some extra leeway time to
* account for clock skew.
*/
public static $leeway = 0;
/**
* Allow the current timestamp to be specified.
* Useful for fixing a value within unit testing.
*
* Will default to PHP time() value if null.
*/
public static $timestamp = null;
public static $supported_algs = array(
'HS256' => array('hash_hmac', 'SHA256'),
'HS512' => array('hash_hmac', 'SHA512'),
'HS384' => array('hash_hmac', 'SHA384'),
'RS256' => array('openssl', 'SHA256'),
);
/**
* Decodes a JWT string into a PHP object.
*
* @param string $jwt The JWT
* @param string|array $key The key, or map of keys.
* If the algorithm used is asymmetric, this is the public key
* @param array $allowed_algs List of supported verification algorithms
* Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
*
* @return object The JWT's payload as a PHP object
*
* @throws UnexpectedValueException Provided JWT was invalid
* @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
* @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
* @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat'
* @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim
*
* @uses jsonDecode
* @uses urlsafeB64Decode
*/
public static function decode($jwt, $key, $allowed_algs = array()) {
$timestamp = is_null(static::$timestamp) ? time() : static::$timestamp;
if (empty($key)) {
throw new InvalidArgumentException('Key may not be empty');
}
if (!is_array($allowed_algs)) {
throw new InvalidArgumentException('Algorithm not allowed');
}
$tks = explode('.', $jwt);
if (count($tks) != 3) {
throw new UnexpectedValueException('Wrong number of segments');
}
list($headb64, $bodyb64, $cryptob64) = $tks;
if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) {
throw new UnexpectedValueException('Invalid header encoding');
}
if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) {
throw new UnexpectedValueException('Invalid claims encoding');
}
$sig = static::urlsafeB64Decode($cryptob64);
if (empty($header->alg)) {
throw new UnexpectedValueException('Empty algorithm');
}
if (empty(static::$supported_algs[$header->alg])) {
throw new UnexpectedValueException('Algorithm not supported');
}
if (!in_array($header->alg, $allowed_algs)) {
throw new UnexpectedValueException('Algorithm not allowed');
}
if (is_array($key) || $key instanceof \ArrayAccess) {
if (isset($header->kid)) {
$key = $key[$header->kid];
} else {
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}
}
// Check the signature
if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
throw new SignatureInvalidException('Signature verification failed');
}
// Check if the nbf if it is defined. This is the time that the
// token can actually be used. If it's not yet that time, abort.
if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) {
throw new BeforeValidException(
'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf)
);
}
// Check that this token has been created before 'now'. This prevents
// using tokens that have been created for later use (and haven't
// correctly used the nbf claim).
if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {
throw new BeforeValidException(
'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat)
);
}
// Check if this token has expired.
if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
throw new ExpiredException('Expired token');
}
return $payload;
}
/**
* Converts and signs a PHP object or array into a JWT string.
*
* @param object|array $payload PHP object or array
* @param string $key The secret key.
* If the algorithm used is asymmetric, this is the private key
* @param string $alg The signing algorithm.
* Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
* @param mixed $keyId
* @param array $head An array with header elements to attach
*
* @return string A signed JWT
*
* @uses jsonEncode
* @uses urlsafeB64Encode
*/
public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null) {
$header = array('typ' => 'JWT', 'alg' => $alg);
if ($keyId !== null) {
$header['kid'] = $keyId;
}
if (isset($head) && is_array($head)) {
$header = array_merge($head, $header);
}
$segments = array();
$segments[] = static::urlsafeB64Encode(static::jsonEncode($header));
$segments[] = static::urlsafeB64Encode(static::jsonEncode($payload));
$signing_input = implode('.', $segments);
$signature = static::sign($signing_input, $key, $alg);
$segments[] = static::urlsafeB64Encode($signature);
return implode('.', $segments);
}
/**
* Sign a string with a given key and algorithm.
*
* @param string $msg The message to sign
* @param string|resource $key The secret key
* @param string $alg The signing algorithm.
* Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
*
* @return string An encrypted message
*
* @throws DomainException Unsupported algorithm was specified
*/
public static function sign($msg, $key, $alg = 'HS256') {
if (empty(static::$supported_algs[$alg])) {
throw new DomainException('Algorithm not supported');
}
list($function, $algorithm) = static::$supported_algs[$alg];
switch ($function) {
case 'hash_hmac':
return hash_hmac($algorithm, $msg, $key, true);
case 'openssl':
$signature = '';
$success = openssl_sign($msg, $signature, $key, $algorithm);
if (!$success) {
throw new DomainException("OpenSSL unable to sign data");
} else {
return $signature;
}
}
}
/**
* Verify a signature with the message, key and method. Not all methods
* are symmetric, so we must have a separate verify and sign method.
*
* @param string $msg The original message (header and body)
* @param string $signature The original signature
* @param string|resource $key For HS*, a string key works. for RS*, must be a resource of an openssl public key
* @param string $alg The algorithm
*
* @return bool
*
* @throws DomainException Invalid Algorithm or OpenSSL failure
*/
private static function verify($msg, $signature, $key, $alg) {
if (empty(static::$supported_algs[$alg])) {
throw new DomainException('Algorithm not supported');
}
list($function, $algorithm) = static::$supported_algs[$alg];
switch ($function) {
case 'openssl':
$success = openssl_verify($msg, $signature, $key, $algorithm);
if (!$success) {
throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string());
} else {
return $signature;
}
case 'hash_hmac':
default:
$hash = hash_hmac($algorithm, $msg, $key, true);
if (function_exists('hash_equals')) {
return hash_equals($signature, $hash);
}
$len = min(static::safeStrlen($signature), static::safeStrlen($hash));
$status = 0;
for ($i = 0; $i < $len; $i++) {
$status |= (ord($signature[$i]) ^ ord($hash[$i]));
}
$status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash));
return ($status === 0);
}
}
/**
* Decode a JSON string into a PHP object.
*
* @param string $input JSON string
*
* @return object Object representation of JSON string
*
* @throws DomainException Provided string was invalid JSON
*/
public static function jsonDecode($input) {
if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
/** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
* to specify that large ints (like Steam Transaction IDs) should be treated as
* strings, rather than the PHP default behaviour of converting them to floats.
*/
$obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
} else {
/** Not all servers will support that, however, so for older versions we must
* manually detect large ints in the JSON string and quote them (thus converting
* them to strings) before decoding, hence the preg_replace() call.
*/
$max_int_length = strlen((string) PHP_INT_MAX) - 1;
$json_without_bigints = preg_replace('/:\s*(-?\d{' . $max_int_length . ',})/', ': "$1"', $input);
$obj = json_decode($json_without_bigints);
}
if (function_exists('json_last_error') && $errno = json_last_error()) {
static::handleJsonError($errno);
} elseif ($obj === null && $input !== 'null') {
throw new DomainException('Null result with non-null input');
}
return $obj;
}
/**
* Encode a PHP object into a JSON string.
*
* @param object|array $input A PHP object or array
*
* @return string JSON representation of the PHP object or array
*
* @throws DomainException Provided object could not be encoded to valid JSON
*/
public static function jsonEncode($input) {
$json = json_encode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
static::handleJsonError($errno);
} elseif ($json === 'null' && $input !== null) {
throw new DomainException('Null result with non-null input');
}
return $json;
}
/**
* Decode a string with URL-safe Base64.
*
* @param string $input A Base64 encoded string
*
* @return string A decoded string
*/
public static function urlsafeB64Decode($input) {
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* Encode a string with URL-safe Base64.
*
* @param string $input The string you want encoded
*
* @return string The base64 encode of what you passed in
*/
public static function urlsafeB64Encode($input) {
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
/**
* Helper method to create a JSON error.
*
* @param int $errno An error number from json_last_error()
*
* @return void
*/
private static function handleJsonError($errno) {
$messages = array(
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
);
throw new DomainException(
isset($messages[$errno]) ? $messages[$errno] : 'Unknown JSON error: ' . $errno
);
}
/**
* Get the number of bytes in cryptographic strings.
*
* @param string
*
* @return int
*/
private static function safeStrlen($str) {
if (function_exists('mb_strlen')) {
return mb_strlen($str, '8bit');
}
return strlen($str);
}
}
@@ -0,0 +1,7 @@
<?php
namespace Firebase\JWT;
class SignatureInvalidException extends \UnexpectedValueException
{
}
+73
View File
@@ -0,0 +1,73 @@
<?php
/**
* websocket消息处理类
*/
class Message
{
private $ci;
const MES_TYPE_NOTICE = 'notice'; //推送消息
const MST_TYPE_HEARTBEAT = 'heartbeat'; //心跳检测
public function __construct()
{
$this->ci = &get_instance();
}
/**
* 处理消息
* @param $server
* @param $fd
* @param $data
* @return MyResponse
*/
public function handleMessage($server, $fd, $data)
{
try {
$content = json_decode($data, true);
$type = $content['type'];
$requestId = $content['requestId'] ?: ''; //请求唯一id
$targetPlatform = $content['targetPlatform'] ?: ''; //推送平台
$targetUid = $content['targetUid'] ?: ''; //推送用户id 0000表示所有用户
$data = $content['data'] ?: ''; // 推送具体内容
switch ($type) {
case self::MST_TYPE_HEARTBEAT:
break;
case self::MES_TYPE_NOTICE://通知消息
if (!Ws_conn_model::REC_PLAT_FORM[$targetPlatform]) {
throw new Exception("不支持的推送平台");
}
if ($targetUid) { //发送给指定用户
$userRow = $this->ci->getConnectionByUserId($targetPlatform, $targetUid);
if (!$userRow) {
throw new Exception("用户不在线");
}
echo "发送给用户:" . $userRow->fd . "\n";
// 添加连接有效性检查
$connectionInfo = $server->connection_info($userRow->fd);
if ($connectionInfo) {
$server->push($userRow->fd, WsResponse::success($type, '新消息', $data));
} else {
// 清理无效连接
$this->ci->removeConnection($userRow->fd);
echo "用户 " . $userRow->fd . " 连接已失效,已清理记录\n";
throw new Exception("用户不在线");
}
} elseif ($targetUid == Ws_conn_model::SEND_ALL) { //发送给所有用户
throw new Exception("暂时不支持发送给所有用户");
} else {
throw new Exception("请指定推送用户");
}
break;
default:
throw new Exception("未知的消息类型");
}
$server->push($fd, WsResponse::success($type, '处理成功', $content));
return new MyResponse(WsResponse::CODE_SUCCESS, '处理消息成功');
} catch (Exception $e) {
return new MyResponse($e->getCode() ?: WsResponse::CODE_ERROR, $e->getMessage());
}
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
require_once COMMPATH . 'libraries/JWT.php';
use \Firebase\JWT\JWT;
/**
* 验证token
*/
class ValidToken
{
private $jwt_key_system; //系统推送token
private $jwt_key_pingan; //平安后台
private $jwt_algorithm;
public function __construct()
{
$this->ci = &get_instance();
$this->ci->config->load('wss');
$this->jwt_key_pingan = $this->ci->config->item('jwt_key_pingan');
$this->jwt_key_system = $this->ci->config->item('jwt_key_system');
$this->jwt_algorithm = $this->ci->config->item('jwt_algorithm');
}
public function validateToken($token, $platform)
{
try {
$uid = 0;
switch ($platform) {
case Ws_conn_model::PLAT_FORM_ADMIN:
$uid = JWT::decode($token, $this->jwt_key_system, array($this->jwt_algorithm));
if (!$uid) {
throw new Exception('授权失败', WsResponse::CODE_UNAUTHORIZED);
}
break;
case Ws_conn_model::PLAT_FORM_PINGAN:
$uid = JWT::decode($token, $this->jwt_key_pingan, array($this->jwt_algorithm));
if (!$uid) {
throw new Exception('授权失败', WsResponse::CODE_UNAUTHORIZED);
}
break;
case Ws_conn_model::PLAT_FORM_WXAPP:
throw new Exception('暂不支持微信小程序');
break;
//服务端 推送数据
case Ws_conn_model::PLAT_FORM_SYS_ADMIN:
case Ws_conn_model::PLAT_FORM_SYS_PINGAN:
case Ws_conn_model::PLAT_FORM_SYS_WXAPP:
$uid = JWT::decode($token, $this->jwt_key_system, array($this->jwt_algorithm));
if (!$uid) {
throw new Exception('授权失败', WsResponse::CODE_UNAUTHORIZED);
}
break;
default:
throw new Exception('平台参数错误');
}
return new MyResponse(WsResponse::CODE_SUCCESS, '验证成功', ['uid' => $uid]);
} catch (Exception $e) {
return new MyResponse($e->getCode() ?: WsResponse::CODE_ERROR, $e->getMessage());
}
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
require_once COMMPATH . 'libraries/JWT.php';
require_once COMMPATH . 'libraries/websocket/WsResponse.php';
use WebSocket\Client;
use \Firebase\JWT\JWT;
/**
* websocket 推送客户端
*/
class WsClient
{
private $client;
private $ci;
private $jwt_key_system;
public function __construct($params = [])
{
$this->ci = &get_instance();
$this->ci->load->library('myResponse');
$this->ci->config->load('wss');
$url = $this->ci->config->item('url');
$this->jwt_key_system = $this->ci->config->item('jwt_key_system');
$sendPlatform = $params['platform']; //推送消息平台
if (!$sendPlatform) {
throw new Exception('请指定推送平台');
}
$uid = $params['uid'];
if (!$uid) {
throw new Exception('请指定推送用户');
}
$token = $this->createToken($uid);
if (!$url) {
throw new Exception('请配置websocket服务地址');
}
$url = $url . '?platform=' . $sendPlatform . '&token=' . $token;
$this->client = new Client($url);
}
/**
* 发送websocket消息
* @param $requestId
* @param $targetPlatform 接收数据平台
* @param $targetUid 目标用户id
* @param $data 推送数据
* @return MyResponse
*/
public function sendMessage($requestId, $targetPlatform, $targetUid, $data)
{
try {
if (!$targetPlatform || !$targetUid || !$data) {
throw new Exception('参数错误');
}
$sendData = [
'requestId' => $requestId,
'type' => WsResponse::MST_TYPE_MSG,
'targetPlatform' => $targetPlatform,
'targetUid' => $targetUid,
'data' => $data
];
$this->client->send(json_encode($sendData, JSON_UNESCAPED_UNICODE));
$req = $this->client->receive();
$this->client->close();
$reqData = json_decode($req, true);
if (!isset($reqData['code']) || $reqData['code']) {
throw new Exception($reqData['msg'] ?: '发送失败');
}
return new MyResponse(EXIT_SUCCESS, '发送成功', $reqData);
} catch (Exception $e) {
return new MyResponse(EXIT_ERROR, $e->getMessage());
}
}
public function createToken($uid)
{
return JWT::encode($uid, $this->jwt_key_system);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
class WsResponse
{
// 定义标准响应码
const CODE_SUCCESS = 0;
const CODE_ERROR = 500;
const CODE_BAD_REQUEST = 400;
const CODE_UNAUTHORIZED = 401; //授权时错误
const CODE_FORBIDDEN = 403;
const CODE_NOT_FOUND = 404;
const MST_TYPE_MSG = 'notice'; //消息类型
const MST_TYPE_CONNECT = 'connect'; //连接类型
const MST_TYPE_PONG = 'heartbeat'; //心跳检测
/**
* 创建标准成功响应
*
* @param string $type 响应类型
* @param string $message 响应消息
* @param array $data 响应数据
* @return string 标准响应数组
*/
public static function success($type = '', $message = '操作成功', $data = [])
{
return self::toJson([
'code' => self::CODE_SUCCESS,
'type' => $type,
'msg' => $message,
'data' => $data
]);
}
/**
* 创建标准错误响应
*
* @param int $code 错误码
* @param string $message 错误消息
* @param string $type 错误类型
* @return string 标准错误响应数组
*/
public static function error($type = '', $message = '服务器内部错误', $code = self::CODE_ERROR, $data = [])
{
return self::toJson([
'code' => $code,
'type' => $type,
'msg' => $message,
'data' => $data
]);
}
/**
* 创建认证错误响应
*
* @param string $message 错误消息
* @return string 认证错误响应
*/
public static function unauthorized($message = '未授权访问')
{
return self::error(self::CODE_UNAUTHORIZED, $message, 'unauthorized');
}
/**
* 创建参数错误响应
*
* @param string $message 错误消息
* @return string 参数错误响应
*/
public static function badRequest($message = '请求参数错误')
{
return self::error(self::CODE_BAD_REQUEST, $message, 'bad_request');
}
/**
* 将响应转换为JSON格式
*
* @param array $response 响应数组
* @return string JSON格式的响应
*/
public static function toJson($response)
{
return json_encode($response, JSON_UNESCAPED_UNICODE);
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Sys_notice_model extends HD_Model
{
private $table_name = 'lc_sys_notice';
const PLAT_FORM_ADMIN = 1; //前端-管理后台
const PLAT_FORM_PINGAN = 2; //前端-平安
const PLAT_FORM_WXAPP = 3; //前端-微信小程序
const TYPE_SYS = 0; //系统通知
const ICON_DEFAULT = 'el-icon-s-comment';//默认图标
const ICON_TYPE = [
self::TYPE_SYS => 'el-icon-s-comment',
];
const STATUS_UNREAD = 0; //未读
const STATUS_READ = 1; //已读
const PLATFORM_LIST = [
self::PLAT_FORM_ADMIN => '管理后台',
self::PLAT_FORM_PINGAN => '平安',
self::PLAT_FORM_WXAPP => '微信小程序',
];
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
/**
* 添加系统通知
* @param $sendUid 推送消息账号
* @param $sendPlatform 发消息平台
* @param $params 其它参数
* @return MyResponse
*/
public function addNotice($params, $sendPlatform, $sendUid = 8888888, $showWssErr = false)
{
$logPath = 'websocket';
$logFile = 'sendError.txt';
try {
if (!$params['platform'] || !$params['uid'] || !$params['content'] || !$sendPlatform) {
throw new Exception('参数错误');
}
$addData = [
'platform' => $params['platform'],
'uid' => $params['uid'],
'content' => $params['content'],
'type' => $params['type'] ?: 0,
'url' => $params['url'] ?: '',
'c_time' => time()
];
$addData['icon'] = self::ICON_TYPE[$params['type']] ?: self::ICON_DEFAULT;
$req = $this->add($addData);
if (!is_numeric($req)) {
throw new Exception('添加失败');
}
$this->load->model('ws/ws_conn_model');
$this->load->library('websocket/wsClient', ['platform' => $sendPlatform, 'uid' => $sendUid]);
//websocket推送
$requestId = uniqid();
$data = [
'id' => $req,
'icon' => $addData['icon'],
'url' => $addData['url'],
'type' => $addData['type'],
'read' => 0,
'content' => $addData['content'],
'c_time' => date('Y-m-d H:i:s')
];
/** @var MyResponse $websocketRes */
$websocketRes = $this->wsclient->sendMessage($requestId, $addData['platform'], $addData['uid'], $data);
if (!$websocketRes->isSuccess()) {
if ($showWssErr) {
throw new Exception("发送socket消息失败:{$websocketRes->getMessage()}");
}
debug_log($websocketRes->getMessage(), $logFile, $logPath);
}
return new MyResponse(EXIT_SUCCESS, 'success');
} catch (Exception $e) {
return new MyResponse(EXIT_ERROR, $e->getMessage());
}
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Ws_conn_model extends HD_Model
{
private $table_name = 'lc_ws_conn';
//平台类型
const PLAT_FORM_ADMIN = 1; //前端-管理后台
const PLAT_FORM_PINGAN = 2; //前端-平安
const PLAT_FORM_WXAPP = 3; //前端-微信小程序
const PLAT_FORM_SYS_ADMIN = 4;//后端-管理后台
const PLAT_FORM_SYS_PINGAN = 5;//后端-平安
const PLAT_FORM_SYS_WXAPP = 6;//后端-微信小程序
//接收消息平台
const REC_PLAT_FORM = [
self::PLAT_FORM_WXAPP => '小程序',
self::PLAT_FORM_PINGAN => '平安后台',
self::PLAT_FORM_ADMIN => '空间站后台',
];
const SEND_ALL = '00000';//发送给所有用户
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
}
+7 -7
View File
@@ -1,7 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e::getLoader();
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e::getLoader();
+572 -445
View File
File diff suppressed because it is too large Load Diff
+360
View File
@@ -0,0 +1,360 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $required;
$copiedLocalDir = true;
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}
}
+21 -21
View File
@@ -1,21 +1,21 @@
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.
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.
+19 -17
View File
@@ -1,17 +1,19 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
);
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
'QcloudApi' => $vendorDir . '/tencentcloud/tencentcloud-sdk-php/src/QcloudApi/QcloudApi.php',
'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
);
+22 -18
View File
@@ -1,18 +1,22 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
);
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'256c1545158fc915c75e51a931bdba60' => $vendorDir . '/lcobucci/jwt/compat/class-aliases.php',
'0d273777b2b0d96e49fb3d800c6b0e81' => $vendorDir . '/lcobucci/jwt/compat/json-exception-polyfill.php',
'd6b246ac924292702635bb2349f4a64b' => $vendorDir . '/lcobucci/jwt/compat/lcobucci-clock-polyfill.php',
'dc1275c308c5b416beb314b6317daca2' => $vendorDir . '/overtrue/pinyin/src/const.php',
);
+11 -11
View File
@@ -1,11 +1,11 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Gregwar\\Image' => array($vendorDir . '/gregwar/image'),
'Gregwar\\Cache' => array($vendorDir . '/gregwar/cache'),
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Gregwar\\Image' => array($vendorDir . '/gregwar/image'),
'Gregwar\\Cache' => array($vendorDir . '/gregwar/cache'),
);
+25 -22
View File
@@ -1,22 +1,25 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'mikehaertl\\tmp\\' => array($vendorDir . '/mikehaertl/php-tmpfile/src'),
'mikehaertl\\shellcommand\\' => array($vendorDir . '/mikehaertl/php-shellcommand/src'),
'mikehaertl\\pdftk\\' => array($vendorDir . '/mikehaertl/php-pdftk/src'),
'WechatPay\\GuzzleMiddleware\\' => array($vendorDir . '/wechatpay/wechatpay-guzzle-middleware/src'),
'TencentCloud\\' => array($vendorDir . '/tencentcloud/common/src/TencentCloud', $vendorDir . '/tencentcloud/ocr/src/TencentCloud'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'mikehaertl\\tmp\\' => array($vendorDir . '/mikehaertl/php-tmpfile/src'),
'mikehaertl\\shellcommand\\' => array($vendorDir . '/mikehaertl/php-shellcommand/src'),
'mikehaertl\\pdftk\\' => array($vendorDir . '/mikehaertl/php-pdftk/src'),
'WechatPay\\GuzzleMiddleware\\' => array($vendorDir . '/wechatpay/wechatpay-guzzle-middleware/src'),
'WebSocket\\' => array($vendorDir . '/textalk/websocket/lib'),
'TencentCloud\\' => array($vendorDir . '/tencentcloud/common/src/TencentCloud', $vendorDir . '/tencentcloud/ocr/src/TencentCloud', $vendorDir . '/tencentcloud/tencentcloud-sdk-php/src/TencentCloud'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Overtrue\\Pinyin\\' => array($vendorDir . '/overtrue/pinyin/src'),
'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
);
+80 -70
View File
@@ -1,70 +1,80 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::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\ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequired0872984a1db7aa104ae1184a3170d3e($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequired0872984a1db7aa104ae1184a3170d3e($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e
{
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('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', '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\ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::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\ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequired0872984a1db7aa104ae1184a3170d3e($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequired0872984a1db7aa104ae1184a3170d3e($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}
+174 -146
View File
@@ -1,146 +1,174 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e
{
public static $files = array (
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
);
public static $prefixLengthsPsr4 = array (
'm' =>
array (
'mikehaertl\\tmp\\' => 15,
'mikehaertl\\shellcommand\\' => 24,
'mikehaertl\\pdftk\\' => 17,
),
'W' =>
array (
'WechatPay\\GuzzleMiddleware\\' => 27,
),
'T' =>
array (
'TencentCloud\\' => 13,
),
'S' =>
array (
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Php70\\' => 23,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
),
'P' =>
array (
'Psr\\Http\\Message\\' => 17,
),
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
);
public static $prefixDirsPsr4 = array (
'mikehaertl\\tmp\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-tmpfile/src',
),
'mikehaertl\\shellcommand\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-shellcommand/src',
),
'mikehaertl\\pdftk\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src',
),
'WechatPay\\GuzzleMiddleware\\' =>
array (
0 => __DIR__ . '/..' . '/wechatpay/wechatpay-guzzle-middleware/src',
),
'TencentCloud\\' =>
array (
0 => __DIR__ . '/..' . '/tencentcloud/common/src/TencentCloud',
1 => __DIR__ . '/..' . '/tencentcloud/ocr/src/TencentCloud',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Php70\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php70',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Idn\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
);
public static $prefixesPsr0 = array (
'G' =>
array (
'Gregwar\\Image' =>
array (
0 => __DIR__ . '/..' . '/gregwar/image',
),
'Gregwar\\Cache' =>
array (
0 => __DIR__ . '/..' . '/gregwar/cache',
),
),
);
public static $classMap = array (
'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixesPsr0;
$loader->classMap = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$classMap;
}, null, ClassLoader::class);
}
}
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e
{
public static $files = array (
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'256c1545158fc915c75e51a931bdba60' => __DIR__ . '/..' . '/lcobucci/jwt/compat/class-aliases.php',
'0d273777b2b0d96e49fb3d800c6b0e81' => __DIR__ . '/..' . '/lcobucci/jwt/compat/json-exception-polyfill.php',
'd6b246ac924292702635bb2349f4a64b' => __DIR__ . '/..' . '/lcobucci/jwt/compat/lcobucci-clock-polyfill.php',
'dc1275c308c5b416beb314b6317daca2' => __DIR__ . '/..' . '/overtrue/pinyin/src/const.php',
);
public static $prefixLengthsPsr4 = array (
'm' =>
array (
'mikehaertl\\tmp\\' => 15,
'mikehaertl\\shellcommand\\' => 24,
'mikehaertl\\pdftk\\' => 17,
),
'W' =>
array (
'WechatPay\\GuzzleMiddleware\\' => 27,
'WebSocket\\' => 10,
),
'T' =>
array (
'TencentCloud\\' => 13,
),
'S' =>
array (
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Php70\\' => 23,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
),
'P' =>
array (
'Psr\\Http\\Message\\' => 17,
),
'O' =>
array (
'Overtrue\\Pinyin\\' => 16,
),
'L' =>
array (
'Lcobucci\\JWT\\' => 13,
),
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
);
public static $prefixDirsPsr4 = array (
'mikehaertl\\tmp\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-tmpfile/src',
),
'mikehaertl\\shellcommand\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-shellcommand/src',
),
'mikehaertl\\pdftk\\' =>
array (
0 => __DIR__ . '/..' . '/mikehaertl/php-pdftk/src',
),
'WechatPay\\GuzzleMiddleware\\' =>
array (
0 => __DIR__ . '/..' . '/wechatpay/wechatpay-guzzle-middleware/src',
),
'WebSocket\\' =>
array (
0 => __DIR__ . '/..' . '/textalk/websocket/lib',
),
'TencentCloud\\' =>
array (
0 => __DIR__ . '/..' . '/tencentcloud/common/src/TencentCloud',
1 => __DIR__ . '/..' . '/tencentcloud/ocr/src/TencentCloud',
2 => __DIR__ . '/..' . '/tencentcloud/tencentcloud-sdk-php/src/TencentCloud',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Php70\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php70',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Idn\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Overtrue\\Pinyin\\' =>
array (
0 => __DIR__ . '/..' . '/overtrue/pinyin/src',
),
'Lcobucci\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/lcobucci/jwt/src',
),
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
);
public static $prefixesPsr0 = array (
'G' =>
array (
'Gregwar\\Image' =>
array (
0 => __DIR__ . '/..' . '/gregwar/image',
),
'Gregwar\\Cache' =>
array (
0 => __DIR__ . '/..' . '/gregwar/cache',
),
),
);
public static $classMap = array (
'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php',
'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php',
'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php',
'QcloudApi' => __DIR__ . '/..' . '/tencentcloud/tencentcloud-sdk-php/src/QcloudApi/QcloudApi.php',
'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php',
'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixesPsr0;
$loader->classMap = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$classMap;
}, null, ClassLoader::class);
}
}
+1142 -880
View File
File diff suppressed because it is too large Load Diff
+227
View File
@@ -0,0 +1,227 @@
<?php return array(
'root' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => null,
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => null,
'dev_requirement' => false,
),
'gregwar/cache' => array(
'pretty_version' => 'v1.0.13',
'version' => '1.0.13.0',
'type' => 'library',
'install_path' => __DIR__ . '/../gregwar/cache/Gregwar/Cache',
'aliases' => array(),
'reference' => '184cc341c25298ff7d584f86b55b6ca26626da4f',
'dev_requirement' => false,
),
'gregwar/image' => array(
'pretty_version' => 'v2.1.0',
'version' => '2.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../gregwar/image/Gregwar/Image',
'aliases' => array(),
'reference' => '1cf64c34cbb22933b36727c16b15ed4d925b6fc6',
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '6.5.5',
'version' => '6.5.5.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'reference' => '9d4290de1cfd701f38099ef7e183b64b4b7b0c5e',
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.4.1',
'version' => '1.4.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'reference' => '8e7d04f1f6450fef59366c399cfad4b9383aa30d',
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '1.8.2',
'version' => '1.8.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'reference' => 'dc960a912984efb74d0a90222870c72c87f10c91',
'dev_requirement' => false,
),
'lcobucci/jwt' => array(
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../lcobucci/jwt',
'aliases' => array(),
'reference' => '3ef8657a78278dfeae7707d51747251db4176240',
'dev_requirement' => false,
),
'mikehaertl/php-pdftk' => array(
'pretty_version' => '0.11.0',
'version' => '0.11.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mikehaertl/php-pdftk',
'aliases' => array(),
'reference' => '61ba14c08491c1bb7d479c87087f236389b4babf',
'dev_requirement' => false,
),
'mikehaertl/php-shellcommand' => array(
'pretty_version' => '1.6.4',
'version' => '1.6.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mikehaertl/php-shellcommand',
'aliases' => array(),
'reference' => '3488d7803df1e8f1a343d3d0ca452d527ad8d5e5',
'dev_requirement' => false,
),
'mikehaertl/php-tmpfile' => array(
'pretty_version' => '1.2.1',
'version' => '1.2.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mikehaertl/php-tmpfile',
'aliases' => array(),
'reference' => '70a5b70b17bc0d9666388e6a551ecc93d0b40a10',
'dev_requirement' => false,
),
'overtrue/pinyin' => array(
'pretty_version' => '4.0.5',
'version' => '4.0.5.0',
'type' => 'library',
'install_path' => __DIR__ . '/../overtrue/pinyin',
'aliases' => array(),
'reference' => '94fdb3ea6eca5677afd9548111d95bedcd5a4086',
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v2.0.20',
'version' => '2.0.20.0',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'reference' => '0f1f60250fccffeaf5dda91eea1c018aed1adc2a',
'dev_requirement' => false,
),
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'dev_requirement' => false,
),
'psr/http-message-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'reference' => '4ad5115c0f5d5172a9fe8147675ec6de266d8826',
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'reference' => '8db0ae7936b42feb370840cf24de1a144fb0ef27',
'dev_requirement' => false,
),
'symfony/polyfill-php70' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php70',
'aliases' => array(),
'reference' => '3fe414077251a81a1b15b1c709faf5c2fbae3d4e',
'dev_requirement' => false,
),
'symfony/polyfill-php72' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php72',
'aliases' => array(),
'reference' => 'beecef6b463b06954638f02378f52496cb84bacc',
'dev_requirement' => false,
),
'tencentcloud/common' => array(
'pretty_version' => '3.0.436',
'version' => '3.0.436.0',
'type' => 'library',
'install_path' => __DIR__ . '/../tencentcloud/common',
'aliases' => array(),
'reference' => '8e1742f06287accfd173141a919d3460d097ac03',
'dev_requirement' => false,
),
'tencentcloud/ocr' => array(
'pretty_version' => '3.0.436',
'version' => '3.0.436.0',
'type' => 'library',
'install_path' => __DIR__ . '/../tencentcloud/ocr',
'aliases' => array(),
'reference' => '3158bf1b0d4c89ca0623d0c4eda76a4a8eba656b',
'dev_requirement' => false,
),
'tencentcloud/tencentcloud-sdk-php' => array(
'pretty_version' => '3.0.1396',
'version' => '3.0.1396.0',
'type' => 'library',
'install_path' => __DIR__ . '/../tencentcloud/tencentcloud-sdk-php',
'aliases' => array(),
'reference' => '6b47ab8109795bcf8a55956e995604038cb7ea26',
'dev_requirement' => false,
),
'textalk/websocket' => array(
'pretty_version' => '1.3.1',
'version' => '1.3.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../textalk/websocket',
'aliases' => array(),
'reference' => 'fe348408a43cc646d08a3ae73e7877370441c7ee',
'dev_requirement' => false,
),
'wechatpay/wechatpay-guzzle-middleware' => array(
'pretty_version' => '0.2.2',
'version' => '0.2.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../wechatpay/wechatpay-guzzle-middleware',
'aliases' => array(),
'reference' => '6782ac33ed8cf97628609a71cdc5e84a6a40677a',
'dev_requirement' => false,
),
),
);
+26
View File
@@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 50600)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.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
);
}
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2014-2015, Luís Otávio Cobucci Oblonczyk
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 {organization} nor the names of its
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 HOLDER 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.
+4
View File
@@ -0,0 +1,4 @@
<?php
class_exists(\Lcobucci\JWT\Token\Plain::class, false) || class_alias(\Lcobucci\JWT\Token::class, \Lcobucci\JWT\Token\Plain::class);
class_exists(\Lcobucci\JWT\Token\Signature::class, false) || class_alias(\Lcobucci\JWT\Signature::class, \Lcobucci\JWT\Token\Signature::class);
@@ -0,0 +1,7 @@
<?php
if (PHP_VERSION_ID < 70300 && ! class_exists('JsonException')) {
class JsonException extends Exception
{
}
}
@@ -0,0 +1,70 @@
<?php
namespace Lcobucci\Clock;
use DateTimeImmutable;
use DateTimeZone;
use function interface_exists;
if (! interface_exists(Clock::class)) {
interface Clock
{
/** @return DateTimeImmutable */
public function now();
}
final class FrozenClock implements Clock
{
/** @var DateTimeImmutable */
private $now;
public function __construct(DateTimeImmutable $now)
{
$this->now = $now;
}
/** @return self */
public static function fromUTC()
{
return new self(new DateTimeImmutable('now', new DateTimeZone('UTC')));
}
public function setTo(DateTimeImmutable $now)
{
$this->now = $now;
}
public function now()
{
return $this->now;
}
}
final class SystemClock implements Clock
{
/** @var DateTimeZone */
private $timezone;
public function __construct(DateTimeZone $timezone)
{
$this->timezone = $timezone;
}
/** @return self */
public static function fromUTC()
{
return new self(new DateTimeZone('UTC'));
}
/** @return self */
public static function fromSystemTimezone()
{
return new self(new DateTimeZone(date_default_timezone_get()));
}
public function now()
{
return new DateTimeImmutable('now', $this->timezone);
}
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"name": "lcobucci/jwt",
"description": "A simple library to work with JSON Web Token and JSON Web Signature",
"type": "library",
"authors": [
{
"name": "Luís Otávio Cobucci Oblonczyk",
"email": "lcobucci@gmail.com",
"role": "Developer"
}
],
"keywords": [
"JWT",
"JWS"
],
"license": [
"BSD-3-Clause"
],
"require": {
"php": "^5.6 || ^7.0",
"ext-mbstring": "*",
"ext-openssl": "*"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^7.3",
"squizlabs/php_codesniffer": "~2.3",
"phpmd/phpmd": "~2.2",
"phpunit/php-invoker": "~1.1",
"mikey179/vfsstream": "~1.5"
},
"autoload": {
"psr-4": {
"Lcobucci\\JWT\\": "src"
},
"files": [
"compat/class-aliases.php",
"compat/json-exception-polyfill.php",
"compat/lcobucci-clock-polyfill.php"
]
},
"autoload-dev": {
"psr-4": {
"Lcobucci\\JWT\\": [
"test/unit",
"test/functional"
]
}
},
"suggest": {
"lcobucci/clock": "*"
},
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
}
}
+592
View File
@@ -0,0 +1,592 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use DateTimeImmutable;
use Lcobucci\JWT\Claim\Factory as ClaimFactory;
use Lcobucci\JWT\Parsing\Encoder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\Token\RegisteredClaimGiven;
use Lcobucci\JWT\Token\RegisteredClaims;
use function array_diff;
use function array_filter;
use function array_key_exists;
use function array_merge;
use function array_shift;
use function count;
use function current;
use function in_array;
use function is_array;
use function is_bool;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* This class makes easier the token creation process
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Builder
{
/**
* The token header
*
* @var array
*/
private $headers = ['typ'=> 'JWT', 'alg' => 'none'];
/**
* The token claim set
*
* @var array
*/
private $claims = [];
/**
* The data encoder
*
* @var Encoder
*/
private $encoder;
/**
* The factory of claims
*
* @var ClaimFactory
*/
private $claimFactory;
/**
* @var Signer|null
*/
private $signer;
/**
* @var Key|null
*/
private $key;
/**
* Initializes a new builder
*
* @param Encoder $encoder
* @param ClaimFactory $claimFactory
*/
public function __construct(
Encoder $encoder = null,
ClaimFactory $claimFactory = null
) {
$this->encoder = $encoder ?: new Encoder();
$this->claimFactory = $claimFactory ?: new ClaimFactory();
}
/**
* Configures the audience
*
* @deprecated This method has been wrongly added and doesn't exist on v4
* @see Builder::permittedFor()
*
* @param string $audience
* @param bool $replicateAsHeader
*
* @return Builder
*/
public function canOnlyBeUsedBy($audience, $replicateAsHeader = false)
{
return $this->permittedFor($audience, $replicateAsHeader);
}
/**
* Configures the audience
*
* @param list<string|bool> $audiences A list of audiences and, optionally, the instruction to replicate as header
*
* @return Builder
*/
public function permittedFor(...$audiences)
{
$claim = RegisteredClaims::AUDIENCE;
$replicateAsHeader = false;
if ($audiences !== [] && is_bool($audiences[count($audiences) - 1])) {
$replicateAsHeader = array_pop($audiences);
}
$audiences = array_filter($audiences, 'is_string');
$configured = array_key_exists($claim, $this->claims) ? $this->claims[$claim] : [];
$toAppend = array_diff($audiences, $configured);
return $this->setRegisteredClaim($claim, array_merge($configured, $toAppend), $replicateAsHeader);
}
/**
* Configures the audience
*
* @deprecated This method will be removed on v4
* @see Builder::permittedFor()
*
* @param string $audience
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setAudience($audience, $replicateAsHeader = false)
{
return $this->permittedFor($audience, $replicateAsHeader);
}
/**
* Configures the expiration time
*
* @param int|DateTimeImmutable $expiration
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function expiresAt($expiration, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('exp', $this->convertToDate($expiration), $replicateAsHeader);
}
/**
* @param int|DateTimeImmutable $value
*
* @return DateTimeImmutable
*/
private function convertToDate($value)
{
if (! $value instanceof DateTimeImmutable) {
trigger_error('Using integers for registered date claims is deprecated, please use DateTimeImmutable objects instead.', E_USER_DEPRECATED);
return new DateTimeImmutable('@' . $value);
}
return $value;
}
/**
* Configures the expiration time
*
* @deprecated This method will be removed on v4
* @see Builder::expiresAt()
*
* @param int|DateTimeImmutable $expiration
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setExpiration($expiration, $replicateAsHeader = false)
{
return $this->expiresAt($expiration, $replicateAsHeader);
}
/**
* Configures the token id
*
* @param string $id
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function identifiedBy($id, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('jti', (string) $id, $replicateAsHeader);
}
/**
* Configures the token id
*
* @deprecated This method will be removed on v4
* @see Builder::identifiedBy()
*
* @param string $id
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setId($id, $replicateAsHeader = false)
{
return $this->identifiedBy($id, $replicateAsHeader);
}
/**
* Configures the time that the token was issued
*
* @param int|DateTimeImmutable $issuedAt
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function issuedAt($issuedAt, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('iat', $this->convertToDate($issuedAt), $replicateAsHeader);
}
/**
* Configures the time that the token was issued
*
* @deprecated This method will be removed on v4
* @see Builder::issuedAt()
*
* @param int|DateTimeImmutable $issuedAt
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setIssuedAt($issuedAt, $replicateAsHeader = false)
{
return $this->issuedAt($issuedAt, $replicateAsHeader);
}
/**
* Configures the issuer
*
* @param string $issuer
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function issuedBy($issuer, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('iss', (string) $issuer, $replicateAsHeader);
}
/**
* Configures the issuer
*
* @deprecated This method will be removed on v4
* @see Builder::issuedBy()
*
* @param string $issuer
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setIssuer($issuer, $replicateAsHeader = false)
{
return $this->issuedBy($issuer, $replicateAsHeader);
}
/**
* Configures the time before which the token cannot be accepted
*
* @param int|DateTimeImmutable $notBefore
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function canOnlyBeUsedAfter($notBefore, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('nbf', $this->convertToDate($notBefore), $replicateAsHeader);
}
/**
* Configures the time before which the token cannot be accepted
*
* @deprecated This method will be removed on v4
* @see Builder::canOnlyBeUsedAfter()
*
* @param int|DateTimeImmutable $notBefore
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setNotBefore($notBefore, $replicateAsHeader = false)
{
return $this->canOnlyBeUsedAfter($notBefore, $replicateAsHeader);
}
/**
* Configures the subject
*
* @param string $subject
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function relatedTo($subject, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('sub', (string) $subject, $replicateAsHeader);
}
/**
* Configures the subject
*
* @deprecated This method will be removed on v4
* @see Builder::relatedTo()
*
* @param string $subject
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setSubject($subject, $replicateAsHeader = false)
{
return $this->relatedTo($subject, $replicateAsHeader);
}
/**
* Configures a registered claim
*
* @param string $name
* @param mixed $value
* @param boolean $replicate
*
* @return Builder
*/
protected function setRegisteredClaim($name, $value, $replicate)
{
$this->configureClaim($name, $value);
if ($replicate) {
trigger_error('Replicating claims as headers is deprecated and will removed from v4.0. Please manually set the header if you need it replicated.', E_USER_DEPRECATED);
$this->headers[$name] = $value;
}
return $this;
}
/**
* Configures a header item
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function withHeader($name, $value)
{
$this->headers[(string) $name] = $value;
return $this;
}
/**
* Configures a header item
*
* @deprecated This method will be removed on v4
* @see Builder::withHeader()
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function setHeader($name, $value)
{
return $this->withHeader($name, $value);
}
/**
* Configures a claim item
*
* @deprecated This method has been wrongly added and doesn't exist on v4
* @see Builder::withClaim()
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function with($name, $value)
{
return $this->withClaim($name, $value);
}
/**
* @param string $name
* @param mixed $value
*
* @return Builder
*/
private function configureClaim($name, $value)
{
$this->claims[(string) $name] = $value;
return $this;
}
/**
* Configures a claim item
*
* @param string $name
* @param mixed $value
*
* @return Builder
*
* @throws RegisteredClaimGiven
*/
public function withClaim($name, $value)
{
if (in_array($name, RegisteredClaims::ALL, true)) {
trigger_error('The use of the method "withClaim" is deprecated for registered claims. Please use dedicated method instead.', E_USER_DEPRECATED);
}
return $this->forwardCallToCorrectClaimMethod($name, $value);
}
private function forwardCallToCorrectClaimMethod($name, $value)
{
switch ($name) {
case RegisteredClaims::ID:
return $this->identifiedBy($value);
case RegisteredClaims::EXPIRATION_TIME:
return $this->expiresAt($value);
case RegisteredClaims::NOT_BEFORE:
return $this->canOnlyBeUsedAfter($value);
case RegisteredClaims::ISSUED_AT:
return $this->issuedAt($value);
case RegisteredClaims::ISSUER:
return $this->issuedBy($value);
case RegisteredClaims::AUDIENCE:
return $this->permittedFor($value);
default:
return $this->configureClaim($name, $value);
}
}
/**
* Configures a claim item
*
* @deprecated This method will be removed on v4
* @see Builder::withClaim()
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function set($name, $value)
{
return $this->forwardCallToCorrectClaimMethod($name, $value);
}
/**
* Signs the data
*
* @deprecated This method will be removed on v4
* @see Builder::getToken()
*
* @param Signer $signer
* @param Key|string $key
*
* @return Builder
*/
public function sign(Signer $signer, $key)
{
if (! $key instanceof Key) {
trigger_error('Implicit conversion of keys from strings is deprecated. Please use InMemory or LocalFileReference classes.', E_USER_DEPRECATED);
$key = new Key($key);
}
$this->signer = $signer;
$this->key = $key;
return $this;
}
/**
* Removes the signature from the builder
*
* @deprecated This method will be removed on v4
* @see Builder::getToken()
*
* @return Builder
*/
public function unsign()
{
$this->signer = null;
$this->key = null;
return $this;
}
/**
* Returns the resultant token
*
* @return Token
*/
public function getToken(Signer $signer = null, Key $key = null)
{
if ($signer === null || $key === null) {
trigger_error('Not specifying the signer and key to Builder#getToken() is deprecated. Please move the arguments from Builder#sign() to Builder#getToken().', E_USER_DEPRECATED);
}
$signer = $signer ?: $this->signer;
$key = $key ?: $this->key;
if ($signer instanceof Signer) {
$signer->modifyHeader($this->headers);
}
$headers = new DataSet(
$this->headers,
$this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->convertItems($this->headers)))
);
$claims = new DataSet(
$this->claims,
$this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->convertItems($this->claims)))
);
return new Token(
$headers,
$claims,
$this->createSignature($headers->toString() . '.' . $claims->toString(), $signer, $key),
['', ''],
$this->claimFactory
);
}
/**
* @param array<string, mixed> $items
*
* @return array<string, mixed>
*/
private function convertItems(array $items)
{
foreach (RegisteredClaims::DATE_CLAIMS as $name) {
if (! array_key_exists($name, $items) || ! $items[$name] instanceof DateTimeImmutable) {
continue;
}
$items[$name] = $items[$name]->getTimestamp();
}
$audience = RegisteredClaims::AUDIENCE;
if (array_key_exists($audience, $items) && is_array($items[$audience]) && count($items[$audience]) === 1) {
$items[$audience] = current($items[$audience]);
}
return $items;
}
/**
* @param string $payload
*
* @return Signature
*/
private function createSignature($payload, Signer $signer = null, Key $key = null)
{
if ($signer === null || $key === null) {
return Signature::fromEmptyData();
}
$hash = $signer->sign($payload, $key)->hash();
return new Signature($hash, $this->encoder->base64UrlEncode($hash));
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use JsonSerializable;
/**
* Basic interface for token claims
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
interface Claim extends JsonSerializable
{
/**
* Returns the claim name
*
* @return string
*/
public function getName();
/**
* Returns the claim value
*
* @return mixed
*/
public function getValue();
/**
* Returns the string representation of the claim
*
* @return string
*/
public function __toString();
}
+75
View File
@@ -0,0 +1,75 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
/**
* The default claim
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class Basic implements Claim
{
/**
* @var string
*/
private $name;
/**
* @var mixed
*/
private $value;
/**
* Initializes the claim
*
* @param string $name
* @param mixed $value
*/
public function __construct($name, $value)
{
$this->name = $name;
$this->value = $value;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getValue()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return (string) $this->value;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is strictly equals to the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class EqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() === $data->get($this->getName());
}
return true;
}
}
+131
View File
@@ -0,0 +1,131 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use DateTimeImmutable;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\Token\RegisteredClaims;
use function current;
use function in_array;
use function is_array;
/**
* Class that create claims
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class Factory
{
/**
* The list of claim callbacks
*
* @var array
*/
private $callbacks;
/**
* Initializes the factory, registering the default callbacks
*
* @param array $callbacks
*/
public function __construct(array $callbacks = [])
{
$this->callbacks = array_merge(
[
'iat' => [$this, 'createLesserOrEqualsTo'],
'nbf' => [$this, 'createLesserOrEqualsTo'],
'exp' => [$this, 'createGreaterOrEqualsTo'],
'iss' => [$this, 'createEqualsTo'],
'aud' => [$this, 'createEqualsTo'],
'sub' => [$this, 'createEqualsTo'],
'jti' => [$this, 'createEqualsTo']
],
$callbacks
);
}
/**
* Create a new claim
*
* @param string $name
* @param mixed $value
*
* @return Claim
*/
public function create($name, $value)
{
if ($value instanceof DateTimeImmutable && in_array($name, RegisteredClaims::DATE_CLAIMS, true)) {
$value = $value->getTimestamp();
}
if ($name === RegisteredClaims::AUDIENCE && is_array($value)) {
$value = current($value);
}
if (!empty($this->callbacks[$name])) {
return call_user_func($this->callbacks[$name], $name, $value);
}
return $this->createBasic($name, $value);
}
/**
* Creates a claim that can be compared (greator or equals)
*
* @param string $name
* @param mixed $value
*
* @return GreaterOrEqualsTo
*/
private function createGreaterOrEqualsTo($name, $value)
{
return new GreaterOrEqualsTo($name, $value);
}
/**
* Creates a claim that can be compared (greator or equals)
*
* @param string $name
* @param mixed $value
*
* @return LesserOrEqualsTo
*/
private function createLesserOrEqualsTo($name, $value)
{
return new LesserOrEqualsTo($name, $value);
}
/**
* Creates a claim that can be compared (equals)
*
* @param string $name
* @param mixed $value
*
* @return EqualsTo
*/
private function createEqualsTo($name, $value)
{
return new EqualsTo($name, $value);
}
/**
* Creates a basic claim
*
* @param string $name
* @param mixed $value
*
* @return Basic
*/
private function createBasic($name, $value)
{
return new Basic($name, $value);
}
}
@@ -0,0 +1,34 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is greater or equals the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class GreaterOrEqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() >= $data->get($this->getName());
}
return true;
}
}
@@ -0,0 +1,34 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is lesser or equals to the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class LesserOrEqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() <= $data->get($this->getName());
}
return true;
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Basic interface for validatable token claims
*
* @deprecated This interface will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
interface Validatable
{
/**
* Returns if claim is valid according with given data
*
* @param ValidationData $data
*
* @return boolean
*/
public function validate(ValidationData $data);
}
+178
View File
@@ -0,0 +1,178 @@
<?php
namespace Lcobucci\JWT;
use Closure;
use Lcobucci\JWT\Parsing\Decoder;
use Lcobucci\JWT\Parsing\Encoder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\None;
use Lcobucci\JWT\Validation\Constraint;
/**
* Configuration container for the JWT Builder and Parser
*
* Serves like a small DI container to simplify the creation and usage
* of the objects.
*/
final class Configuration
{
/** @var Parser */
private $parser;
/** @var Signer */
private $signer;
/** @var Key */
private $signingKey;
/** @var Key */
private $verificationKey;
/** @var Validator */
private $validator;
/** @var Closure(): Builder */
private $builderFactory;
/** @var Constraint[] */
private $validationConstraints = [];
private function __construct(
Signer $signer,
Key $signingKey,
Key $verificationKey,
Encoder $encoder = null,
Decoder $decoder = null
) {
$this->signer = $signer;
$this->signingKey = $signingKey;
$this->verificationKey = $verificationKey;
$this->parser = new Parser($decoder ?: new Decoder());
$this->validator = new Validation\Validator();
$this->builderFactory = static function () use ($encoder) {
return new Builder($encoder ?: new Encoder());
};
}
/** @return self */
public static function forAsymmetricSigner(
Signer $signer,
Key $signingKey,
Key $verificationKey,
Encoder $encoder = null,
Decoder $decoder = null
) {
return new self(
$signer,
$signingKey,
$verificationKey,
$encoder,
$decoder
);
}
/** @return self */
public static function forSymmetricSigner(
Signer $signer,
Key $key,
Encoder $encoder = null,
Decoder $decoder = null
) {
return new self(
$signer,
$key,
$key,
$encoder,
$decoder
);
}
/** @return self */
public static function forUnsecuredSigner(
Encoder $encoder = null,
Decoder $decoder = null
) {
$key = InMemory::plainText('');
return new self(
new None(),
$key,
$key,
$encoder,
$decoder
);
}
/** @param callable(): Builder $builderFactory */
public function setBuilderFactory(callable $builderFactory)
{
if (! $builderFactory instanceof Closure) {
$builderFactory = static function() use ($builderFactory) {
return $builderFactory();
};
}
$this->builderFactory = $builderFactory;
}
/** @return Builder */
public function builder()
{
$factory = $this->builderFactory;
return $factory();
}
/** @return Parser */
public function parser()
{
return $this->parser;
}
public function setParser(Parser $parser)
{
$this->parser = $parser;
}
/** @return Signer */
public function signer()
{
return $this->signer;
}
/** @return Key */
public function signingKey()
{
return $this->signingKey;
}
/** @return Key */
public function verificationKey()
{
return $this->verificationKey;
}
/** @return Validator */
public function validator()
{
return $this->validator;
}
public function setValidator(Validator $validator)
{
$this->validator = $validator;
}
/** @return Constraint[] */
public function validationConstraints()
{
return $this->validationConstraints;
}
public function setValidationConstraints(Constraint ...$validationConstraints)
{
$this->validationConstraints = $validationConstraints;
}
}
@@ -0,0 +1,26 @@
<?php
namespace Lcobucci\JWT\Encoding;
use JsonException;
use Lcobucci\JWT\Exception;
use RuntimeException;
final class CannotDecodeContent extends RuntimeException implements Exception
{
/**
* @param JsonException $previous
*
* @return self
*/
public static function jsonIssues(JsonException $previous)
{
return new self('Error while decoding from JSON', 0, $previous);
}
/** @return self */
public static function invalidBase64String()
{
return new self('Error while decoding from Base64Url, invalid base64 characters detected');
}
}
@@ -0,0 +1,20 @@
<?php
namespace Lcobucci\JWT\Encoding;
use JsonException;
use Lcobucci\JWT\Exception;
use RuntimeException;
final class CannotEncodeContent extends RuntimeException implements Exception
{
/**
* @param JsonException $previous
*
* @return self
*/
public static function jsonIssues(JsonException $previous)
{
return new self('Error while encoding to JSON', 0, $previous);
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace Lcobucci\JWT;
if (PHP_MAJOR_VERSION === 5) {
interface Exception
{
}
} else {
interface Exception extends \Throwable
{
}
}
+175
View File
@@ -0,0 +1,175 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use DateTimeImmutable;
use InvalidArgumentException;
use Lcobucci\JWT\Parsing\Decoder;
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\Token\InvalidTokenStructure;
use Lcobucci\JWT\Token\RegisteredClaims;
use Lcobucci\JWT\Token\UnsupportedHeaderFound;
use RuntimeException;
use function array_key_exists;
use function is_array;
/**
* This class parses the JWT strings and convert them into tokens
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Parser
{
/**
* The data decoder
*
* @var Decoder
*/
private $decoder;
/**
* Initializes the object
*
* @param Decoder $decoder
*/
public function __construct(Decoder $decoder = null)
{
$this->decoder = $decoder ?: new Decoder();
}
/**
* Parses the JWT and returns a token
*
* @param string $jwt
*
* @return Token
*
* @throws InvalidArgumentException When JWT is not a string or is invalid.
* @throws RuntimeException When something goes wrong while decoding
*/
public function parse($jwt)
{
$data = $this->splitJwt($jwt);
$header = $this->parseHeader($data[0]);
$claims = $this->parseClaims($data[1]);
$signature = $this->parseSignature($header, $data[2]);
foreach ($claims as $name => $value) {
if (isset($header[$name])) {
$header[$name] = $value;
}
}
return new Token(
new DataSet($header, $data[0]),
new DataSet($claims, $data[1]),
$signature,
['', '']
);
}
/**
* Splits the JWT string into an array
*
* @param string $jwt
*
* @return array
*
* @throws InvalidArgumentException When JWT is not a string or is invalid
*/
protected function splitJwt($jwt)
{
if (!is_string($jwt)) {
throw InvalidTokenStructure::missingOrNotEnoughSeparators();
}
$data = explode('.', $jwt);
if (count($data) != 3) {
throw InvalidTokenStructure::missingOrNotEnoughSeparators();
}
return $data;
}
/**
* Parses the header from a string
*
* @param string $data
*
* @return array
*
* @throws UnsupportedHeaderFound When an invalid header is informed
*/
protected function parseHeader($data)
{
$header = (array) $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
if (isset($header['enc'])) {
throw UnsupportedHeaderFound::encryption();
}
return $this->convertItems($header);
}
/**
* Parses the claim set from a string
*
* @param string $data
*
* @return array
*/
protected function parseClaims($data)
{
$claims = (array) $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
return $this->convertItems($claims);
}
/**
* @param array<string, mixed> $items
*
* @return array<string, mixed>
*/
private function convertItems(array $items)
{
foreach (RegisteredClaims::DATE_CLAIMS as $name) {
if (! array_key_exists($name, $items)) {
continue;
}
$items[$name] = new DateTimeImmutable('@' . ((int) $items[$name]));
}
if (array_key_exists(RegisteredClaims::AUDIENCE, $items) && ! is_array($items[RegisteredClaims::AUDIENCE])) {
$items[RegisteredClaims::AUDIENCE] = [$items[RegisteredClaims::AUDIENCE]];
}
return $items;
}
/**
* Returns the signature from given data
*
* @param array $header
* @param string $data
*
* @return Signature
*/
protected function parseSignature(array $header, $data)
{
if ($data == '' || !isset($header['alg']) || $header['alg'] == 'none') {
return Signature::fromEmptyData();
}
$hash = $this->decoder->base64UrlDecode($data);
return new Signature($hash, $data);
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Parsing;
use JsonException;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use RuntimeException;
use function json_decode;
use function json_last_error;
use function json_last_error_msg;
/**
* Class that decodes data according with the specs of RFC-4648
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*/
class Decoder
{
/**
* Decodes from JSON, validating the errors (will return an associative array
* instead of objects)
*
* @param string $json
* @return mixed
*
* @throws RuntimeException When something goes wrong while decoding
*/
public function jsonDecode($json)
{
if (PHP_VERSION_ID < 70300) {
$data = json_decode($json);
if (json_last_error() != JSON_ERROR_NONE) {
throw CannotDecodeContent::jsonIssues(new JsonException(json_last_error_msg()));
}
return $data;
}
try {
return json_decode($json, false, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw CannotDecodeContent::jsonIssues($exception);
}
}
/**
* Decodes from base64url
*
* @param string $data
* @return string
*/
public function base64UrlDecode($data)
{
if ($remainder = strlen($data) % 4) {
$data .= str_repeat('=', 4 - $remainder);
}
return base64_decode(strtr($data, '-_', '+/'));
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Parsing;
use JsonException;
use Lcobucci\JWT\Encoding\CannotEncodeContent;
use RuntimeException;
use function json_encode;
use function json_last_error;
use function json_last_error_msg;
/**
* Class that encodes data according with the specs of RFC-4648
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*/
class Encoder
{
/**
* Encodes to JSON, validating the errors
*
* @param mixed $data
* @return string
*
* @throws RuntimeException When something goes wrong while encoding
*/
public function jsonEncode($data)
{
if (PHP_VERSION_ID < 70300) {
$json = json_encode($data);
if (json_last_error() != JSON_ERROR_NONE) {
throw CannotEncodeContent::jsonIssues(new JsonException(json_last_error_msg()));
}
return $json;
}
try {
return json_encode($data, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw CannotEncodeContent::jsonIssues($exception);
}
}
/**
* Encodes to base64url
*
* @param string $data
* @return string
*/
public function base64UrlEncode($data)
{
return str_replace('=', '', strtr(base64_encode($data), '+/', '-_'));
}
}
+87
View File
@@ -0,0 +1,87 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use Lcobucci\JWT\Signer\Key;
/**
* This class represents a token signature
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Signature
{
/**
* The resultant hash
*
* @var string
*/
protected $hash;
/** @var string */
private $encoded;
/**
* Initializes the object
*
* @param string $hash
* @param string $encoded
*/
public function __construct($hash, $encoded = '')
{
$this->hash = $hash;
$this->encoded = $encoded;
}
/** @return self */
public static function fromEmptyData()
{
return new self('', '');
}
/**
* Verifies if the current hash matches with with the result of the creation of
* a new signature with given data
*
* @param Signer $signer
* @param string $payload
* @param Key|string $key
*
* @return boolean
*/
public function verify(Signer $signer, $payload, $key)
{
return $signer->verify($this->hash, $payload, $key);
}
/**
* Returns the current hash as a string representation of the signature
*
* @deprecated This method has been removed from the public API in v4
* @see Signature::hash()
*
* @return string
*/
public function __toString()
{
return $this->hash;
}
/** @return string */
public function hash()
{
return $this->hash;
}
/** @return string */
public function toString()
{
return $this->encoded;
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use InvalidArgumentException;
use Lcobucci\JWT\Signer\Key;
/**
* Basic interface for token signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
interface Signer
{
/**
* Returns the algorithm id
*
* @return string
*/
public function getAlgorithmId();
/**
* Apply changes on headers according with algorithm
*
* @param array $headers
*/
public function modifyHeader(array &$headers);
/**
* Returns a signature for given data
*
* @param string $payload
* @param Key|string $key
*
* @return Signature
*
* @throws InvalidArgumentException When given key is invalid
*/
public function sign($payload, $key);
/**
* Returns if the expected hash matches with the data and key
*
* @param string $expected
* @param string $payload
* @param Key|string $key
*
* @return boolean
*
* @throws InvalidArgumentException When given key is invalid
*/
public function verify($expected, $payload, $key);
}
+89
View File
@@ -0,0 +1,89 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signature;
use Lcobucci\JWT\Signer;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* Base class for signers
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
abstract class BaseSigner implements Signer
{
/**
* {@inheritdoc}
*/
public function modifyHeader(array &$headers)
{
$headers['alg'] = $this->getAlgorithmId();
}
/**
* {@inheritdoc}
*/
public function sign($payload, $key)
{
return new Signature($this->createHash($payload, $this->getKey($key)));
}
/**
* {@inheritdoc}
*/
public function verify($expected, $payload, $key)
{
return $this->doVerify($expected, $payload, $this->getKey($key));
}
/**
* @param Key|string $key
*
* @return Key
*/
private function getKey($key)
{
if (is_string($key)) {
trigger_error('Implicit conversion of keys from strings is deprecated. Please use InMemory or LocalFileReference classes.', E_USER_DEPRECATED);
$key = new Key($key);
}
return $key;
}
/**
* Creates a hash with the given data
*
* @internal
*
* @param string $payload
* @param Key $key
*
* @return string
*/
abstract public function createHash($payload, Key $key);
/**
* Performs the signature verification
*
* @internal
*
* @param string $expected
* @param string $payload
* @param Key $key
*
* @return boolean
*/
abstract public function doVerify($expected, $payload, Key $key);
}
@@ -0,0 +1,19 @@
<?php
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class CannotSignPayload extends InvalidArgumentException implements Exception
{
/**
* @pararm string $error
*
* @return self
*/
public static function errorHappened($error)
{
return new self('There was an error while creating the signature: ' . $error);
}
}
+69
View File
@@ -0,0 +1,69 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter;
use Lcobucci\JWT\Signer\Ecdsa\SignatureConverter;
use const OPENSSL_KEYTYPE_EC;
/**
* Base class for ECDSA signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
abstract class Ecdsa extends OpenSSL
{
/**
* @var SignatureConverter
*/
private $converter;
public function __construct(SignatureConverter $converter = null)
{
$this->converter = $converter ?: new MultibyteStringConverter();
}
/**
* {@inheritdoc}
*/
public function createHash($payload, Key $key)
{
return $this->converter->fromAsn1(
parent::createHash($payload, $key),
$this->getKeyLength()
);
}
/**
* {@inheritdoc}
*/
public function doVerify($expected, $payload, Key $key)
{
return parent::doVerify(
$this->converter->toAsn1($expected, $this->getKeyLength()),
$payload,
$key
);
}
/**
* Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
*
* @internal
*/
abstract public function getKeyLength();
/**
* {@inheritdoc}
*/
final public function getKeyType()
{
return OPENSSL_KEYTYPE_EC;
}
}
@@ -0,0 +1,27 @@
<?php
namespace Lcobucci\JWT\Signer\Ecdsa;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class ConversionFailed extends InvalidArgumentException implements Exception
{
/** @return self */
public static function invalidLength()
{
return new self('Invalid signature length.');
}
/** @return self */
public static function incorrectStartSequence()
{
return new self('Invalid data. Should start with a sequence.');
}
/** @return self */
public static function integerExpected()
{
return new self('Invalid data. Should contain an integer.');
}
}
@@ -0,0 +1,133 @@
<?php
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2018 Spomky-Labs
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*
* @link https://github.com/web-token/jwt-framework/blob/v1.2/src/Component/Core/Util/ECSignature.php
*/
namespace Lcobucci\JWT\Signer\Ecdsa;
use function bin2hex;
use function dechex;
use function hex2bin;
use function hexdec;
use function mb_strlen;
use function mb_substr;
use function str_pad;
use const STR_PAD_LEFT;
/**
* ECDSA signature converter using ext-mbstring
*
* @internal
*/
final class MultibyteStringConverter implements SignatureConverter
{
const ASN1_SEQUENCE = '30';
const ASN1_INTEGER = '02';
const ASN1_MAX_SINGLE_BYTE = 128;
const ASN1_LENGTH_2BYTES = '81';
const ASN1_BIG_INTEGER_LIMIT = '7f';
const ASN1_NEGATIVE_INTEGER = '00';
const BYTE_SIZE = 2;
public function toAsn1($signature, $length)
{
$signature = bin2hex($signature);
if (self::octetLength($signature) !== $length) {
throw ConversionFailed::invalidLength();
}
$pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit'));
$pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit'));
$lengthR = self::octetLength($pointR);
$lengthS = self::octetLength($pointS);
$totalLength = $lengthR + $lengthS + self::BYTE_SIZE + self::BYTE_SIZE;
$lengthPrefix = $totalLength > self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
$asn1 = hex2bin(
self::ASN1_SEQUENCE
. $lengthPrefix . dechex($totalLength)
. self::ASN1_INTEGER . dechex($lengthR) . $pointR
. self::ASN1_INTEGER . dechex($lengthS) . $pointS
);
return $asn1;
}
private static function octetLength($data)
{
return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
}
private static function preparePositiveInteger($data)
{
if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
return self::ASN1_NEGATIVE_INTEGER . $data;
}
while (mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) {
$data = mb_substr($data, 2, null, '8bit');
}
return $data;
}
public function fromAsn1($signature, $length)
{
$message = bin2hex($signature);
$position = 0;
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
throw ConversionFailed::incorrectStartSequence();
}
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
$position += self::BYTE_SIZE;
}
$pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
$pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
$points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
return $points;
}
private static function readAsn1Content($message, &$position, $length)
{
$content = mb_substr($message, $position, $length, '8bit');
$position += $length;
return $content;
}
private static function readAsn1Integer($message, &$position)
{
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) {
throw ConversionFailed::integerExpected();
}
$length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
}
private static function retrievePositiveInteger($data)
{
while (mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
$data = mb_substr($data, 2, null, '8bit');
}
return $data;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha256 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'ES256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha256';
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
{
return 64;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha384 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'ES384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha384';
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
{
return 96;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha512 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'ES512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha512';
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
{
return 132;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Lcobucci\JWT\Signer\Ecdsa;
/**
* Manipulates the result of a ECDSA signature (points R and S) according to the
* JWA specs.
*
* OpenSSL creates a signature using the ASN.1 format and, according the JWA specs,
* the signature for JWTs must be the concatenated values of points R and S (in
* big-endian octet order).
*
* @internal
*
* @see https://tools.ietf.org/html/rfc7518#page-9
* @see https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
*/
interface SignatureConverter
{
/**
* Converts the signature generated by OpenSSL into what JWA defines
*
* @param string $signature
* @param int $length
*
* @return string
*/
public function fromAsn1($signature, $length);
/**
* Converts the JWA signature into something OpenSSL understands
*
* @param string $points
* @param int $length
*
* @return string
*/
public function toAsn1($points, $length);
}
+46
View File
@@ -0,0 +1,46 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
/**
* Base class for hmac signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
abstract class Hmac extends BaseSigner
{
/**
* {@inheritdoc}
*/
public function createHash($payload, Key $key)
{
return hash_hmac($this->getAlgorithm(), $payload, $key->getContent(), true);
}
/**
* {@inheritdoc}
*/
public function doVerify($expected, $payload, Key $key)
{
if (!is_string($expected)) {
return false;
}
return hash_equals($expected, $this->createHash($payload, $key));
}
/**
* Returns the algorithm name
*
* @internal
*
* @return string
*/
abstract public function getAlgorithm();
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha256 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'HS256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha256';
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha384 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'HS384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha384';
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha512 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'HS512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return 'sha512';
}
}
@@ -0,0 +1,25 @@
<?php
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class InvalidKeyProvided extends InvalidArgumentException implements Exception
{
/**
* @param string $details
*
* @return self
*/
public static function cannotBeParsed($details)
{
return new self('It was not possible to parse your key, reason: ' . $details);
}
/** @return self */
public static function incompatibleKey()
{
return new self('This key is not compatible with this signer');
}
}
+117
View File
@@ -0,0 +1,117 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
use Exception;
use InvalidArgumentException;
use Lcobucci\JWT\Signer\Key\FileCouldNotBeRead;
use SplFileObject;
use function strpos;
use function substr;
/**
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 3.0.4
*/
class Key
{
/**
* @var string
*/
protected $content;
/**
* @var string
*/
private $passphrase;
/**
* @param string $content
* @param string $passphrase
*/
public function __construct($content, $passphrase = '')
{
$this->setContent($content);
$this->passphrase = $passphrase;
}
/**
* @param string $content
*
* @throws InvalidArgumentException
*/
private function setContent($content)
{
if (strpos($content, 'file://') === 0) {
$content = $this->readFile($content);
}
$this->content = $content;
}
/**
* @param string $content
*
* @return string
*
* @throws InvalidArgumentException
*/
private function readFile($content)
{
$path = substr($content, 7);
try {
$file = new SplFileObject($path);
} catch (Exception $exception) {
throw FileCouldNotBeRead::onPath($path, $exception);
}
$content = '';
while (! $file->eof()) {
$content .= $file->fgets();
}
return $content;
}
/** @return string */
public function contents()
{
return $this->content;
}
/** @return string */
public function passphrase()
{
return $this->passphrase;
}
/**
* @deprecated This method is no longer part of the public interface
* @see Key::contents()
*
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @deprecated This method is no longer part of the public interface
* @see Key::passphrase()
*
* @return string
*/
public function getPassphrase()
{
return $this->passphrase;
}
}
@@ -0,0 +1,39 @@
<?php
namespace Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Exception;
use InvalidArgumentException;
if (PHP_MAJOR_VERSION === 7) {
final class FileCouldNotBeRead extends InvalidArgumentException implements Exception
{
/** @return self */
public static function onPath(string $path, \Throwable $cause = null)
{
return new self(
'The path "' . $path . '" does not contain a valid key file',
0,
$cause
);
}
}
} else {
final class FileCouldNotBeRead extends InvalidArgumentException implements Exception
{
/**
* @param string $path
* @param \Exception|null $cause
*
* @return self
*/
public static function onPath($path, \Exception $cause = null)
{
return new self(
'The path "' . $path . '" does not contain a valid key file',
0,
$cause
);
}
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use Lcobucci\JWT\Signer\Key;
use function base64_decode;
final class InMemory extends Key
{
/**
* @param string $contents
* @param string $passphrase
*
* @return self
*/
public static function plainText($contents, $passphrase = '')
{
return new self($contents, $passphrase);
}
/**
* @param string $contents
* @param string $passphrase
*
* @return self
*/
public static function base64Encoded($contents, $passphrase = '')
{
$decoded = base64_decode($contents, true);
if ($decoded === false) {
throw CannotDecodeContent::invalidBase64String();
}
return new self($decoded, $passphrase);
}
/**
* @param string $path
* @param string $passphrase
*
* @return InMemory
*
* @throws FileCouldNotBeRead
*/
public static function file($path, $passphrase = '')
{
return new self('file://' . $path, $passphrase);
}
}
@@ -0,0 +1,32 @@
<?php
namespace Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key;
use function file_exists;
use function strpos;
use function substr;
/** @deprecated Use \Lcobucci\JWT\Signer\Key\InMemory::file() instead */
final class LocalFileReference extends Key
{
const PATH_PREFIX = 'file://';
/**
* @param string $path
* @param string $passphrase
*
* @return self
*
* @throws FileCouldNotBeRead
*/
public static function file($path, $passphrase = '')
{
if (strpos($path, self::PATH_PREFIX) === 0) {
$path = substr($path, 7);
}
return new self(self::PATH_PREFIX . $path, $passphrase);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
/**
* A utilitarian class that encapsulates the retrieval of public and private keys
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*
* @deprecated Since we've removed OpenSSL from ECDSA there's no reason to use this class
*/
class Keychain
{
/**
* Returns a private key from file path or content
*
* @param string $key
* @param string $passphrase
*
* @return Key
*/
public function getPrivateKey($key, $passphrase = null)
{
return new Key($key, $passphrase);
}
/**
* Returns a public key from file path or content
*
* @param string $certificate
*
* @return Key
*/
public function getPublicKey($certificate)
{
return new Key($certificate);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace Lcobucci\JWT\Signer;
final class None extends BaseSigner
{
public function getAlgorithmId()
{
return 'none';
}
public function createHash($payload, Key $key)
{
return '';
}
public function doVerify($expected, $payload, Key $key)
{
return $expected === '';
}
}
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use function is_resource;
use function openssl_error_string;
use function openssl_free_key;
use function openssl_pkey_get_details;
use function openssl_pkey_get_private;
use function openssl_pkey_get_public;
use function openssl_sign;
use function openssl_verify;
abstract class OpenSSL extends BaseSigner
{
public function createHash($payload, Key $key)
{
$privateKey = $this->getPrivateKey($key->getContent(), $key->getPassphrase());
try {
$signature = '';
if (! openssl_sign($payload, $signature, $privateKey, $this->getAlgorithm())) {
throw CannotSignPayload::errorHappened(openssl_error_string());
}
return $signature;
} finally {
openssl_free_key($privateKey);
}
}
/**
* @param string $pem
* @param string $passphrase
*
* @return resource
*/
private function getPrivateKey($pem, $passphrase)
{
$privateKey = openssl_pkey_get_private($pem, $passphrase);
$this->validateKey($privateKey);
return $privateKey;
}
/**
* @param $expected
* @param $payload
* @param $key
* @return bool
*/
public function doVerify($expected, $payload, Key $key)
{
$publicKey = $this->getPublicKey($key->getContent());
$result = openssl_verify($payload, $expected, $publicKey, $this->getAlgorithm());
openssl_free_key($publicKey);
return $result === 1;
}
/**
* @param string $pem
*
* @return resource
*/
private function getPublicKey($pem)
{
$publicKey = openssl_pkey_get_public($pem);
$this->validateKey($publicKey);
return $publicKey;
}
/**
* Raises an exception when the key type is not the expected type
*
* @param resource|bool $key
*
* @throws InvalidArgumentException
*/
private function validateKey($key)
{
if (! is_resource($key)) {
throw InvalidKeyProvided::cannotBeParsed(openssl_error_string());
}
$details = openssl_pkey_get_details($key);
if (! isset($details['key']) || $details['type'] !== $this->getKeyType()) {
throw InvalidKeyProvided::incompatibleKey();
}
}
/**
* Returns the type of key to be used to create/verify the signature (using OpenSSL constants)
*
* @internal
*/
abstract public function getKeyType();
/**
* Returns which algorithm to be used to create/verify the signature (using OpenSSL constants)
*
* @internal
*/
abstract public function getAlgorithm();
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
use const OPENSSL_KEYTYPE_RSA;
/**
* Base class for RSASSA-PKCS1 signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
abstract class Rsa extends OpenSSL
{
final public function getKeyType()
{
return OPENSSL_KEYTYPE_RSA;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha256 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'RS256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return OPENSSL_ALGO_SHA256;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha384 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'RS384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return OPENSSL_ALGO_SHA384;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha512 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
{
return 'RS512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
{
return OPENSSL_ALGO_SHA512;
}
}
+430
View File
@@ -0,0 +1,430 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use DateTimeImmutable;
use DateTimeInterface;
use Generator;
use Lcobucci\JWT\Claim\Factory;
use Lcobucci\JWT\Claim\Validatable;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\Token\RegisteredClaims;
use OutOfBoundsException;
use function current;
use function func_num_args;
use function in_array;
use function is_array;
use function sprintf;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* Basic structure of the JWT
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Token
{
/**
* The token headers
*
* @var DataSet
*/
private $headers;
/**
* The token claim set
*
* @var DataSet
*/
private $claims;
/**
* The token signature
*
* @var Signature
*/
private $signature;
/**
* @internal This serves just as compatibility layer
*
* @var Factory
*/
private $claimFactory;
/**
* Initializes the object
*
* @param array|DataSet $headers
* @param array|DataSet $claims
* @param Signature|null $signature
* @param array $payload
* @param Factory|null $claimFactory
*/
public function __construct(
$headers = ['alg' => 'none'],
$claims = [],
Signature $signature = null,
array $payload = ['', ''],
Factory $claimFactory = null
) {
$this->headers = $this->convertToDataSet($headers, $payload[0]);
$this->claims = $this->convertToDataSet($claims, $payload[1]);
$this->signature = $signature ?: Signature::fromEmptyData();
$this->claimFactory = $claimFactory ?: new Factory();
}
/**
* @param array|DataSet $data
* @param string $payload
*/
private function convertToDataSet($data, $payload)
{
if ($data instanceof DataSet) {
return $data;
}
return new DataSet($data, $payload);
}
/** @return DataSet */
public function headers()
{
return $this->headers;
}
/**
* Returns the token headers
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::headers()
*
* @return array
*/
public function getHeaders()
{
$items = [];
foreach ($this->headers->all() as $name => $value) {
if (! in_array($name, RegisteredClaims::ALL, true) || ! $this->claims->has($name)) {
$items[$name] = $value;
continue;
}
$items[$name] = $this->claimFactory->create($name, $value);
}
return $items;
}
/**
* Returns if the header is configured
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::headers()
* @see DataSet::has()
*
* @param string $name
*
* @return boolean
*/
public function hasHeader($name)
{
return $this->headers->has($name);
}
/**
* Returns the value of a token header
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::headers()
* @see DataSet::has()
*
* @param string $name
* @param mixed $default
*
* @return mixed
*
* @throws OutOfBoundsException
*/
public function getHeader($name, $default = null)
{
if (func_num_args() === 1 && ! $this->headers->has($name)) {
throw new OutOfBoundsException(sprintf('Requested header "%s" is not configured', $name));
}
return $this->headers->get($name, $default);
}
/** @return DataSet */
public function claims()
{
return $this->claims;
}
/**
* Returns the token claim set
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::claims()
*
* @return array
*/
public function getClaims()
{
$items = [];
foreach ($this->claims->all() as $name => $value) {
$items[$name] = $this->claimFactory->create($name, $value);
}
return $items;
}
/**
* Returns if the claim is configured
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::claims()
* @see DataSet::has()
*
* @param string $name
*
* @return boolean
*/
public function hasClaim($name)
{
return $this->claims->has($name);
}
/**
* Returns the value of a token claim
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::claims()
* @see DataSet::get()
*
* @param string $name
* @param mixed $default
*
* @return mixed
*
* @throws OutOfBoundsException
*/
public function getClaim($name, $default = null)
{
if (func_num_args() === 1 && ! $this->claims->has($name)) {
throw new OutOfBoundsException(sprintf('Requested header "%s" is not configured', $name));
}
$value = $this->claims->get($name, $default);
if ($value instanceof DateTimeImmutable && in_array($name, RegisteredClaims::DATE_CLAIMS, true)) {
return $value->getTimestamp();
}
if ($name === RegisteredClaims::AUDIENCE && is_array($value)) {
if (count($value) > 1) {
trigger_error('You will only get the first array entry as a string. Use Token::claims()->get() instead.', E_USER_DEPRECATED);
}
return current($value);
}
return $value;
}
/**
* Verify if the key matches with the one that created the signature
*
* @deprecated This method has been removed from the interface in v4.0
* @see \Lcobucci\JWT\Validation\Validator
*
* @param Signer $signer
* @param Key|string $key
*
* @return boolean
*/
public function verify(Signer $signer, $key)
{
if ($this->headers->get('alg') !== $signer->getAlgorithmId()) {
return false;
}
return $this->signature->verify($signer, $this->getPayload(), $key);
}
/**
* Validates if the token is valid
*
* @deprecated This method has been removed from the interface in v4.0
* @see \Lcobucci\JWT\Validation\Validator
*
* @param ValidationData $data
*
* @return boolean
*/
public function validate(ValidationData $data)
{
foreach ($this->getValidatableClaims() as $claim) {
if (!$claim->validate($data)) {
return false;
}
}
return true;
}
/**
* Determine if the token is expired.
*
* @param DateTimeInterface|null $now Defaults to the current time.
*
* @return bool
*/
public function isExpired(DateTimeInterface $now = null)
{
if (! $this->claims->has('exp')) {
return false;
}
if ($now === null) {
trigger_error('Not providing the current time is deprecated. Please pass an instance of DateTimeInterface.', E_USER_DEPRECATED);
}
$now = $now ?: new DateTimeImmutable();
return $now >= $this->claims->get(RegisteredClaims::EXPIRATION_TIME);
}
/**
* @param string $audience
*
* @return bool
*/
public function isPermittedFor($audience)
{
return in_array($audience, $this->claims->get(RegisteredClaims::AUDIENCE, []), true);
}
/**
* @param string $id
*
* @return bool
*/
public function isIdentifiedBy($id)
{
return $this->claims->get(RegisteredClaims::ID) === $id;
}
/**
* @param string $subject
*
* @return bool
*/
public function isRelatedTo($subject)
{
return $this->claims->get(RegisteredClaims::SUBJECT) === $subject;
}
/**
* @param list<string> $issuers
*
* @return bool
*/
public function hasBeenIssuedBy(...$issuers)
{
return in_array($this->claims->get(RegisteredClaims::ISSUER), $issuers, true);
}
/**
* @param DateTimeInterface $now
*
* @return bool
*/
public function hasBeenIssuedBefore(DateTimeInterface $now)
{
return $now >= $this->claims->get(RegisteredClaims::ISSUED_AT);
}
/**
* @param DateTimeInterface $now
*
* @return bool
*/
public function isMinimumTimeBefore(DateTimeInterface $now)
{
return $now >= $this->claims->get(RegisteredClaims::NOT_BEFORE);
}
/**
* Yields the validatable claims
*
* @return Generator
*/
private function getValidatableClaims()
{
foreach ($this->getClaims() as $claim) {
if ($claim instanceof Validatable) {
yield $claim;
}
}
}
/**
* Returns the token payload
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::payload()
*
* @return string
*/
public function getPayload()
{
return $this->payload();
}
/**
* Returns the token payload
*
* @return string
*/
public function payload()
{
return $this->headers->toString() . '.' . $this->claims->toString();
}
/** @return Signature */
public function signature()
{
return $this->signature;
}
/**
* Returns an encoded representation of the token
*
* @deprecated This method has been removed from the interface in v4.0
* @see Token::toString()
*
* @return string
*/
public function __toString()
{
return $this->toString();
}
/** @return string */
public function toString()
{
return $this->headers->toString() . '.'
. $this->claims->toString() . '.'
. $this->signature->toString();
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace Lcobucci\JWT\Token;
use function array_key_exists;
final class DataSet
{
/** @var array<string, mixed> */
private $data;
/** @var string */
private $encoded;
/**
* @param array<string, mixed> $data
* @param string $encoded
*/
public function __construct(array $data, $encoded)
{
$this->data = $data;
$this->encoded = $encoded;
}
/**
* @param string $name
* @param mixed|null $default
*
* @return mixed|null
*/
public function get($name, $default = null)
{
return $this->has($name) ? $this->data[$name] : $default;
}
/**
* @param string $name
*
* @return bool
*/
public function has($name)
{
return array_key_exists($name, $this->data);
}
/** @return array<string, mixed> */
public function all()
{
return $this->data;
}
/** @return string */
public function toString()
{
return $this->encoded;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class InvalidTokenStructure extends InvalidArgumentException implements Exception
{
/** @return self */
public static function missingOrNotEnoughSeparators()
{
return new self('The JWT string must have two dots');
}
/**
* @param string $part
*
* @return self
*/
public static function arrayExpected($part)
{
return new self($part . ' must be an array');
}
/**
* @param string $value
*
* @return self
*/
public static function dateIsNotParseable($value)
{
return new self('Value is not in the allowed date format: ' . $value);
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Lcobucci\JWT\Token;
use Lcobucci\JWT\Token;
use function class_alias;
class_exists(Plain::class, false) || class_alias(Token::class, Plain::class);
@@ -0,0 +1,24 @@
<?php
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
use function sprintf;
final class RegisteredClaimGiven extends InvalidArgumentException implements Exception
{
const DEFAULT_MESSAGE = 'Builder#withClaim() is meant to be used for non-registered claims, '
. 'check the documentation on how to set claim "%s"';
/**
* @param string $name
*
* @return self
*/
public static function forClaim($name)
{
return new self(sprintf(self::DEFAULT_MESSAGE, $name));
}
}
@@ -0,0 +1,76 @@
<?php
namespace Lcobucci\JWT\Token;
/**
* Defines the list of claims that are registered in the IANA "JSON Web Token Claims" registry
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1
*/
interface RegisteredClaims
{
const ALL = [
self::AUDIENCE,
self::EXPIRATION_TIME,
self::ID,
self::ISSUED_AT,
self::ISSUER,
self::NOT_BEFORE,
self::SUBJECT,
];
const DATE_CLAIMS = [
self::ISSUED_AT,
self::NOT_BEFORE,
self::EXPIRATION_TIME,
];
/**
* Identifies the recipients that the JWT is intended for
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.3
*/
const AUDIENCE = 'aud';
/**
* Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.4
*/
const EXPIRATION_TIME = 'exp';
/**
* Provides a unique identifier for the JWT
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.7
*/
const ID = 'jti';
/**
* Identifies the time at which the JWT was issued
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.6
*/
const ISSUED_AT = 'iat';
/**
* Identifies the principal that issued the JWT
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.1
*/
const ISSUER = 'iss';
/**
* Identifies the time before which the JWT MUST NOT be accepted for processing
*
* https://tools.ietf.org/html/rfc7519#section-4.1.5
*/
const NOT_BEFORE = 'nbf';
/**
* Identifies the principal that is the subject of the JWT.
*
* https://tools.ietf.org/html/rfc7519#section-4.1.2
*/
const SUBJECT = 'sub';
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Lcobucci\JWT\Token;
use Lcobucci\JWT\Signature as SignatureImpl;
use function class_alias;
class_exists(Signature::class, false) || class_alias(SignatureImpl::class, Signature::class);
@@ -0,0 +1,15 @@
<?php
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class UnsupportedHeaderFound extends InvalidArgumentException implements Exception
{
/** @return self */
public static function encryption()
{
return new self('Encryption is not supported yet');
}
}
@@ -0,0 +1,11 @@
<?php
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Token;
interface Constraint
{
/** @throws ConstraintViolation */
public function assert(Token $token);
}
@@ -0,0 +1,28 @@
<?php
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class IdentifiedBy implements Constraint
{
/** @var string */
private $id;
/** @param string $id */
public function __construct($id)
{
$this->id = $id;
}
public function assert(Token $token)
{
if (! $token->isIdentifiedBy($this->id)) {
throw new ConstraintViolation(
'The token is not identified with the expected ID'
);
}
}
}
@@ -0,0 +1,28 @@
<?php
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class IssuedBy implements Constraint
{
/** @var string[] */
private $issuers;
/** @param list<string> $issuers */
public function __construct(...$issuers)
{
$this->issuers = $issuers;
}
public function assert(Token $token)
{
if (! $token->hasBeenIssuedBy(...$this->issuers)) {
throw new ConstraintViolation(
'The token was not issued by the given issuers'
);
}
}
}
@@ -0,0 +1,15 @@
<?php
namespace Lcobucci\JWT\Validation\Constraint;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class LeewayCannotBeNegative extends InvalidArgumentException implements Exception
{
/** @return self */
public static function create()
{
return new self('Leeway cannot be negative');
}
}
@@ -0,0 +1,27 @@
<?php
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class PermittedFor implements Constraint
{
/** @var string */
private $audience;
public function __construct($audience)
{
$this->audience = $audience;
}
public function assert(Token $token)
{
if (! $token->isPermittedFor($this->audience)) {
throw new ConstraintViolation(
'The token is not allowed to be used by this audience'
);
}
}
}

Some files were not shown because too many files have changed in this diff Show More