作者 开飞机的舒克

后台更新

正在显示 62 个修改的文件 包含 1313 行增加1279 行删除

要显示太多修改。

为保证性能只显示 62 of 62+ 个文件。

... ... @@ -51,15 +51,15 @@ class Study extends Backend
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->with(['team','user'])
->with(['user','team'])
->where($where)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
$row->getRelation('team')->visible(['title']);
$row->getRelation('user')->visible(['username']);
$row->getRelation('user')->visible(['username']);
$row->getRelation('team')->visible(['title']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
... ...
... ... @@ -10,13 +10,13 @@ return [
'Birth' => '生日',
'Grade' => '班级',
'School' => '学校',
'Bangle' => '手环ID',
'Studentid' => '学号',
'Unique' => '手环ID',
'Sno' => '学号',
'Team_id' => '所属战队',
'Score' => '积分',
'Earn_score' => '积分',
'Qrcode' => '条形码',
'Createtime' => '创建时间',
'Updatetime' => '更新时间',
'Team.title' => '战队昵称',
'User.username' => '用户名'
'User.username' => '用户名',
'Team.title' => '战队昵称'
];
... ...
... ... @@ -2,6 +2,8 @@
return [
'Title' => '战队昵称',
'Score' => '战队积分',
'Weigh' => '权重',
'Createtime' => '创建时间'
'Createtime' => '创建时间',
'Updatetime' => '更新时间'
];
... ...
... ... @@ -29,5 +29,12 @@ return [
'Updatetime' => '更新时间',
'Token' => 'Token',
'Status' => '状态',
'Is_teach' => '是否为老师',
'Is_teach 1' => '是',
'Is_teach 0' => '否',
'Teach_phone' => '老师手机号',
'Bind_study' => '是否绑定学生',
'Bind_study 1' => '是',
'Bind_study 0' => '否',
'Leave password blank if dont want to change' => '不修改密码请留空',
];
... ...
... ... @@ -7,6 +7,11 @@ use think\Model;
class Study extends Model
{
// 表名
protected $name = 'study';
... ... @@ -41,14 +46,14 @@ class Study extends Model
public function team()
public function user()
{
return $this->belongsTo('Team', 'team_id', 'id', [], 'LEFT')->setEagerlyType(0);
return $this->belongsTo('User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function user()
public function team()
{
return $this->belongsTo('User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
return $this->belongsTo('Team', 'team_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
}
... ...
... ... @@ -20,7 +20,7 @@ class Team extends Model
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
... ...
... ... @@ -10,11 +10,6 @@ class User extends Validate
* 验证规则
*/
protected $rule = [
'username' => 'require|regex:\w{3,30}|unique:user',
'nickname' => 'require|unique:user',
'password' => 'regex:\S{6,30}',
'email' => 'require|email|unique:user',
'mobile' => 'unique:user'
];
/**
... ... @@ -32,7 +27,7 @@ class User extends Validate
*/
protected $scene = [
'add' => [],
'edit' => ['username', 'nickname', 'password', 'email', 'mobile'],
'edit' => [],
];
public function __construct(array $rules = [], $message = [], $field = [])
... ...
... ... @@ -57,15 +57,15 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Bangle')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Unique')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-bangle" class="form-control" name="row[bangle]" type="number">
<input id="c-unique" class="form-control" name="row[unique]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Studentid')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Sno')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-studentID" class="form-control" name="row[studentID]" type="text">
<input id="c-sno" class="form-control" name="row[sno]" type="text">
</div>
</div>
<div class="form-group">
... ... @@ -75,9 +75,9 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Earn_score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-score" class="form-control" name="row[score]" type="number">
<input id="c-earn_score" class="form-control" step="0.01" name="row[earn_score]" type="number">
</div>
</div>
<div class="form-group">
... ...
... ... @@ -57,15 +57,15 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Bangle')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Unique')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-bangle" class="form-control" name="row[bangle]" type="number" value="{$row.bangle|htmlentities}">
<input id="c-unique" class="form-control" name="row[unique]" type="number" value="{$row.unique|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Studentid')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Sno')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-studentID" class="form-control" name="row[studentID]" type="text" value="{$row.studentID|htmlentities}">
<input id="c-sno" class="form-control" name="row[sno]" type="text" value="{$row.sno|htmlentities}">
</div>
</div>
<div class="form-group">
... ... @@ -75,9 +75,9 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Earn_score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-score" class="form-control" name="row[score]" type="number" value="{$row.score|htmlentities}">
<input id="c-earn_score" class="form-control" step="0.01" name="row[earn_score]" type="number" value="{$row.earn_score|htmlentities}">
</div>
</div>
<div class="form-group">
... ...
... ... @@ -7,6 +7,12 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-score" class="form-control" step="0.01" name="row[score]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-weigh" class="form-control" name="row[weigh]" type="number">
... ...
... ... @@ -7,6 +7,12 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-score" class="form-control" step="0.01" name="row[score]" type="number" value="{$row.score|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-weigh" class="form-control" name="row[weigh]" type="number" value="{$row.weigh|htmlentities}">
... ...
... ... @@ -20,18 +20,6 @@
</div>
</div>
<div class="form-group">
<label for="c-password" class="control-label col-xs-12 col-sm-2">{:__('Password')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-password" data-rule="password" class="form-control" name="row[password]" type="password" value="" placeholder="{:__('Leave password blank if dont want to change')}" autocomplete="new-password" />
</div>
</div>
<div class="form-group">
<label for="c-email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-email" data-rule="" class="form-control" name="row[email]" type="text" value="{$row.email|htmlentities}">
</div>
</div>
<div class="form-group">
<label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-mobile" data-rule="" class="form-control" name="row[mobile]" type="text" value="{$row.mobile|htmlentities}">
... ... @@ -52,87 +40,21 @@
</div>
</div>
<div class="form-group">
<label for="c-level" class="control-label col-xs-12 col-sm-2">{:__('Level')}:</label>
<label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Teach_phone')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-level" data-rule="required" class="form-control" name="row[level]" type="number" value="{$row.level}">
<input id="c-teach_phone" data-rule="" class="form-control" name="row[teach_phone]" type="text" value="{$row.teach_phone|htmlentities}">
</div>
</div>
<div class="form-group">
<label for="c-gender" class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label>
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Is_teach')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[gender]', ['1'=>__('Male'), '0'=>__('Female')], $row['gender'])}
</div>
</div>
<div class="form-group">
<label for="c-birthday" class="control-label col-xs-12 col-sm-2">{:__('Birthday')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-birthday" data-rule="" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-use-current="true" name="row[birthday]" type="text" value="{$row.birthday}">
{:build_radios('row[is_teach]', ['0'=>__('Is_teach 0'), '1'=>__('Is_teach 1')], $row['is_teach'])}
</div>
</div>
<div class="form-group">
<label for="c-bio" class="control-label col-xs-12 col-sm-2">{:__('Bio')}:</label>
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Bind_study')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-bio" data-rule="" class="form-control" name="row[bio]" type="text" value="{$row.bio|htmlentities}">
</div>
</div>
<div class="form-group">
<label for="c-money" class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-money" data-rule="required" class="form-control" name="row[money]" type="number" value="{$row.money}">
</div>
</div>
<div class="form-group">
<label for="c-score" class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score}">
</div>
</div>
<div class="form-group">
<label for="c-successions" class="control-label col-xs-12 col-sm-2">{:__('Successions')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-successions" data-rule="required" class="form-control" name="row[successions]" type="number" value="{$row.successions}">
</div>
</div>
<div class="form-group">
<label for="c-maxsuccessions" class="control-label col-xs-12 col-sm-2">{:__('Maxsuccessions')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-maxsuccessions" data-rule="required" class="form-control" name="row[maxsuccessions]" type="number" value="{$row.maxsuccessions}">
</div>
</div>
<div class="form-group">
<label for="c-prevtime" class="control-label col-xs-12 col-sm-2">{:__('Prevtime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-prevtime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[prevtime]" type="text" value="{$row.prevtime|datetime}">
</div>
</div>
<div class="form-group">
<label for="c-logintime" class="control-label col-xs-12 col-sm-2">{:__('Logintime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-logintime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[logintime]" type="text" value="{$row.logintime|datetime}">
</div>
</div>
<div class="form-group">
<label for="c-loginip" class="control-label col-xs-12 col-sm-2">{:__('Loginip')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-loginip" data-rule="required" class="form-control" name="row[loginip]" type="text" value="{$row.loginip}">
</div>
</div>
<div class="form-group">
<label for="c-loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-loginfailure" data-rule="required" class="form-control" name="row[loginfailure]" type="number" value="{$row.loginfailure}">
</div>
</div>
<div class="form-group">
<label for="c-joinip" class="control-label col-xs-12 col-sm-2">{:__('Joinip')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-joinip" data-rule="required" class="form-control" name="row[joinip]" type="text" value="{$row.joinip}">
</div>
</div>
<div class="form-group">
<label for="c-jointime" class="control-label col-xs-12 col-sm-2">{:__('Jointime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-jointime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[jointime]" type="text" value="{$row.jointime|datetime}">
{:build_radios('row[bind_study]', ['0'=>__('Bind_study 0'), '1'=>__('Bind_study 1')], $row['bind_study'])}
</div>
</div>
<div class="form-group">
... ...
... ... @@ -231,7 +231,7 @@ return [
//验证码配置
'captcha' => [
// 验证码字符集合
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
'codeSet' => '012345678',
// 验证码字体大小(px)
'fontSize' => 18,
// 是否画混淆曲线
... ...
... ... @@ -3,6 +3,9 @@
return [
'autoload' => false,
'hooks' => [
'app_init' => [
'barcode',
],
'user_delete_successed' => [
'third',
],
... ... @@ -24,6 +27,7 @@ return [
],
],
'route' => [
'/qrcode$' => 'barcode/study/add',
'/third$' => 'third/index/index',
'/third/connect/[:platform]' => 'third/index/connect',
'/third/callback/[:platform]' => 'third/index/callback',
... ...
... ... @@ -30,10 +30,15 @@
"ext-curl": "*",
"ext-pdo": "*",
"ext-bcmath": "*",
"txthinking/mailer": "^2.0"
"txthinking/mailer": "^2.0",
"chenbool/barcode": "^1.0"
},
"config": {
"preferred-install": "dist"
"preferred-install": "dist",
"allow-plugins": {
"topthink/think-installer": true,
"easywechat-composer/easywechat-composer": true
}
},
"repositories": [
{
... ...
... ... @@ -35,15 +35,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'birth', title: __('Birth'), operate: 'LIKE'},
{field: 'grade', title: __('Grade'), operate: 'LIKE'},
{field: 'school', title: __('School'), operate: 'LIKE'},
{field: 'bangle', title: __('Bangle')},
{field: 'studentID', title: __('Studentid'), operate: 'LIKE'},
{field: 'unique', title: __('Unique')},
{field: 'sno', title: __('Sno'), operate: 'LIKE'},
{field: 'team_id', title: __('Team_id')},
{field: 'score', title: __('Score')},
{field: 'earn_score', title: __('Earn_score'), operate:'BETWEEN'},
{field: 'qrcode', title: __('Qrcode'), operate: 'LIKE'},
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
{field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
{field: 'team.title', title: __('Team.title'), operate: 'LIKE'},
{field: 'user.username', title: __('User.username'), operate: 'LIKE'},
{field: 'team.title', title: __('Team.title'), operate: 'LIKE'},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
... ...
... ... @@ -21,14 +21,16 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'weigh',
sortName: 'score',
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'title', title: __('Title'), operate: 'LIKE'},
{field: 'score', title: __('Score'), operate:'BETWEEN'},
{field: 'weigh', title: __('Weigh'), operate: false},
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
//{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
// {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
... ...
... ... @@ -40,9 +40,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
// {field: 'loginip', title: __('Loginip'), formatter: Table.api.formatter.search},
// {field: 'jointime', title: __('Jointime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
// {field: 'joinip', title: __('Joinip'), formatter: Table.api.formatter.search},
{field: 'is_teach', title: __('是否为老师'),operate: 'LIKE' },
{field: 'teach_phone', title: __('老师手机号'),operate: 'LIKE'},
{field: 'bind_teach', title: __('是否绑定学生'),operate: 'LIKE'},
{field: 'is_teach', title: __('Is_teach'),searchList: {"0":__('Is_teach 0'),"1":__('Is_teach 1')},formatter: Table.api.formatter.normal},
{field: 'teach_phone', title: __('Teach_phone'),operate: 'LIKE'},
{field: 'bind_study', title: __('Bind_study'),searchList: {"0":__('Bind_study 0'),"1":__('Bind_study 1')},formatter: Table.api.formatter.normal},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status, searchList: {normal: __('Normal'), hidden: __('Hidden')}},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
... ...
... ... @@ -10,7 +10,7 @@ return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => $vendorDir . '/myclabs/php-enum/stubs/Stringable.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
... ...
... ... @@ -9,7 +9,8 @@ return array(
'think\\helper\\' => array($vendorDir . '/topthink/think-helper/src'),
'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
'think\\' => array($vendorDir . '/karsonzhang/fastadmin-addons/src', $vendorDir . '/topthink/think-queue/src', $baseDir . '/thinkphp/library/think'),
'think\\' => array($baseDir . '/thinkphp/library/think', $vendorDir . '/karsonzhang/fastadmin-addons/src', $vendorDir . '/topthink/think-queue/src'),
'chenbool\\' => array($vendorDir . '/chenbool/barcode/src'),
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
'Tx\\' => array($vendorDir . '/txthinking/mailer/src'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
... ... @@ -26,7 +27,7 @@ return array(
'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
... ...
... ... @@ -31,6 +31,10 @@ class ComposerStaticInit73f9e72fede2c36621e52f7b610bbb65
'think\\captcha\\' => 14,
'think\\' => 6,
),
'c' =>
array (
'chenbool\\' => 9,
),
'Z' =>
array (
'ZipStream\\' => 10,
... ... @@ -109,9 +113,13 @@ class ComposerStaticInit73f9e72fede2c36621e52f7b610bbb65
),
'think\\' =>
array (
0 => __DIR__ . '/..' . '/karsonzhang/fastadmin-addons/src',
1 => __DIR__ . '/..' . '/topthink/think-queue/src',
2 => __DIR__ . '/../..' . '/thinkphp/library/think',
0 => __DIR__ . '/../..' . '/thinkphp/library/think',
1 => __DIR__ . '/..' . '/karsonzhang/fastadmin-addons/src',
2 => __DIR__ . '/..' . '/topthink/think-queue/src',
),
'chenbool\\' =>
array (
0 => __DIR__ . '/..' . '/chenbool/barcode/src',
),
'ZipStream\\' =>
array (
... ... @@ -179,8 +187,8 @@ class ComposerStaticInit73f9e72fede2c36621e52f7b610bbb65
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-factory/src',
1 => __DIR__ . '/..' . '/psr/http-message/src',
0 => __DIR__ . '/..' . '/psr/http-message/src',
1 => __DIR__ . '/..' . '/psr/http-factory/src',
),
'Psr\\Http\\Client\\' =>
array (
... ... @@ -274,7 +282,7 @@ class ComposerStaticInit73f9e72fede2c36621e52f7b610bbb65
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => __DIR__ . '/..' . '/myclabs/php-enum/stubs/Stringable.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
... ...
{
"packages": [
{
"name": "chenbool/barcode",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/chenbool/barcode.git",
"reference": "4c1b8264527e8e53bfb059696d60c4e31fd63e24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/chenbool/barcode/zipball/4c1b8264527e8e53bfb059696d60c4e31fd63e24",
"reference": "4c1b8264527e8e53bfb059696d60c4e31fd63e24",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2019-07-31T09:34:38+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"chenbool\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "chenbool",
"email": "30024167@qq.com",
"homepage": "https://github.com/chenbool"
}
],
"description": "一个简单的条形码生成插件",
"homepage": "https://github.com/chenbool",
"keywords": [
"qrcode",
"二维码"
],
"support": {
"issues": "https://github.com/chenbool/barcode/issues",
"source": "https://github.com/chenbool/barcode/tree/1.0.0"
},
"install-path": "../chenbool/barcode"
},
{
"name": "easywechat-composer/easywechat-composer",
"version": "1.4.1",
"version_normalized": "1.4.1.0",
"source": {
"type": "git",
"url": "https://github.com/mingyoung/easywechat-composer.git",
"reference": "3fc6a7ab6d3853c0f4e2922539b56cc37ef361cd"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/easywechat-composer/easywechat-composer/1.4.1/easywechat-composer-easywechat-composer-1.4.1.zip",
"url": "https://api.github.com/repos/mingyoung/easywechat-composer/zipball/3fc6a7ab6d3853c0f4e2922539b56cc37ef361cd",
"reference": "3fc6a7ab6d3853c0f4e2922539b56cc37ef361cd",
"shasum": ""
},
... ... @@ -29,6 +83,7 @@
"EasyWeChatComposer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -39,15 +94,24 @@
}
],
"description": "The composer plugin for EasyWeChat",
"support": {
"issues": "https://github.com/mingyoung/easywechat-composer/issues",
"source": "https://github.com/mingyoung/easywechat-composer/tree/1.4.1"
},
"install-path": "../easywechat-composer/easywechat-composer"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.16.0",
"version_normalized": "4.16.0.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/ezyang/htmlpurifier/v4.16.0/ezyang-htmlpurifier-v4.16.0.zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8",
"shasum": ""
},
... ... @@ -78,6 +142,7 @@
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
... ... @@ -93,15 +158,24 @@
"keywords": [
"html"
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0"
},
"install-path": "../ezyang/htmlpurifier"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.5.0",
"version_normalized": "7.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/guzzlehttp/guzzle/7.5.0/guzzlehttp-guzzle-7.5.0.zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"shasum": ""
},
... ... @@ -148,6 +222,7 @@
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -200,15 +275,38 @@
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.5.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/guzzle"
},
{
"name": "guzzlehttp/promises",
"version": "1.5.2",
"version_normalized": "1.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "b94b2807d85443f9719887892882d0329d1e2598"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/guzzlehttp/promises/1.5.2/guzzlehttp-promises-1.5.2.zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598",
"reference": "b94b2807d85443f9719887892882d0329d1e2598",
"shasum": ""
},
... ... @@ -234,6 +332,7 @@
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -263,16 +362,39 @@
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.5.2"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/promises"
},
{
"name": "guzzlehttp/psr7",
"version": "2.4.3",
"version_normalized": "2.4.3.0",
"version": "2.4.4",
"version_normalized": "2.4.4.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/guzzlehttp/psr7/2.4.3/guzzlehttp-psr7-2.4.3.zip",
"reference": "67c26b443f348a51926030c83481b85718457d3d",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"shasum": ""
},
"require": {
... ... @@ -293,7 +415,7 @@
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"time": "2022-10-26T14:07:24+00:00",
"time": "2023-03-09T13:19:02+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
... ... @@ -310,6 +432,7 @@
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -361,15 +484,38 @@
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/psr7"
},
{
"name": "karsonzhang/fastadmin-addons",
"version": "1.3.3",
"version_normalized": "1.3.3.0",
"source": {
"type": "git",
"url": "https://github.com/karsonzhang/fastadmin-addons.git",
"reference": "f5bb4dabda55271b08371a8ae9355a205be48c56"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/karsonzhang/fastadmin-addons/1.3.3/karsonzhang-fastadmin-addons-1.3.3.zip",
"url": "https://api.github.com/repos/karsonzhang/fastadmin-addons/zipball/f5bb4dabda55271b08371a8ae9355a205be48c56",
"reference": "f5bb4dabda55271b08371a8ae9355a205be48c56",
"shasum": ""
},
... ... @@ -394,6 +540,7 @@
"think\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
... ... @@ -409,34 +556,40 @@
],
"description": "addons package for fastadmin",
"homepage": "https://github.com/karsonzhang/fastadmin-addons",
"support": {
"issues": "https://github.com/karsonzhang/fastadmin-addons/issues",
"source": "https://github.com/karsonzhang/fastadmin-addons/tree/v1.3.3"
},
"install-path": "../karsonzhang/fastadmin-addons"
},
{
"name": "maennchen/zipstream-php",
"version": "2.2.6",
"version_normalized": "2.2.6.0",
"version": "2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/maennchen/ZipStream-PHP.git",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/maennchen/zipstream-php/2.2.6/maennchen-zipstream-php-2.2.6.zip",
"reference": "30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58",
"shasum": ""
},
"require": {
"myclabs/php-enum": "^1.5",
"php": "^7.4 || ^8.0",
"php": ">= 7.1",
"psr/http-message": "^1.0",
"symfony/polyfill-mbstring": "^1.0"
},
"require-dev": {
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.9",
"guzzlehttp/guzzle": "^6.5.3 || ^7.2.0",
"guzzlehttp/guzzle": ">= 6.3",
"mikey179/vfsstream": "^1.6",
"php-coveralls/php-coveralls": "^2.4",
"phpunit/phpunit": "^8.5.8 || ^9.4.2",
"vimeo/psalm": "^4.1"
"phpunit/phpunit": ">= 7.5"
},
"time": "2022-11-25T18:57:19+00:00",
"time": "2020-05-30T13:11:16+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
... ... @@ -444,6 +597,7 @@
"ZipStream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -470,15 +624,34 @@
"stream",
"zip"
],
"support": {
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
"source": "https://github.com/maennchen/ZipStream-PHP/tree/2.1.0"
},
"funding": [
{
"url": "https://github.com/maennchen",
"type": "github"
},
{
"url": "https://opencollective.com/zipstream",
"type": "open_collective"
}
],
"install-path": "../maennchen/zipstream-php"
},
{
"name": "markbaker/complex",
"version": "3.0.2",
"version_normalized": "3.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/markbaker/complex/3.0.2/markbaker-complex-3.0.2.zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"shasum": ""
},
... ... @@ -499,6 +672,7 @@
"Complex\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -514,15 +688,24 @@
"complex",
"mathematics"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
},
"install-path": "../markbaker/complex"
},
{
"name": "markbaker/matrix",
"version": "3.0.1",
"version_normalized": "3.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/markbaker/matrix/3.0.1/markbaker-matrix-3.0.1.zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
"shasum": ""
},
... ... @@ -547,6 +730,7 @@
"Matrix\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -563,16 +747,25 @@
"matrix",
"vector"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
},
"install-path": "../markbaker/matrix"
},
{
"name": "monolog/monolog",
"version": "2.8.0",
"version_normalized": "2.8.0.0",
"version": "2.9.1",
"version_normalized": "2.9.1.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/monolog/monolog/2.8.0/monolog-monolog-2.8.0.zip",
"reference": "720488632c590286b88b80e62aa3d3d551ad4a50",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
"reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
"shasum": ""
},
"require": {
... ... @@ -587,7 +780,7 @@
"doctrine/couchdb": "~1.0@dev",
"elasticsearch/elasticsearch": "^7 || ^8",
"ext-json": "*",
"graylog2/gelf-php": "^1.4.2",
"graylog2/gelf-php": "^1.4.2 || ^2@dev",
"guzzlehttp/guzzle": "^7.4",
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
... ... @@ -618,7 +811,7 @@
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
},
"time": "2022-07-24T11:55:47+00:00",
"time": "2023-02-06T13:44:46+00:00",
"type": "library",
"extra": {
"branch-alias": {
... ... @@ -631,6 +824,7 @@
"Monolog\\": "src/Monolog"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -648,38 +842,55 @@
"logging",
"psr-3"
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/2.9.1"
},
"funding": [
{
"url": "https://github.com/Seldaek",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
"type": "tidelift"
}
],
"install-path": "../monolog/monolog"
},
{
"name": "myclabs/php-enum",
"version": "1.8.4",
"version_normalized": "1.8.4.0",
"version": "1.7.7",
"version_normalized": "1.7.7.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/php-enum.git",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/myclabs/php-enum/1.8.4/myclabs-php-enum-1.8.4.zip",
"reference": "a867478eae49c9f59ece437ae7f9506bfaa27483",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.3 || ^8.0"
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"phpunit/phpunit": "^7",
"squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^4.6.2"
"vimeo/psalm": "^3.8"
},
"time": "2022-08-04T09:53:51+00:00",
"time": "2020-11-14T18:14:52+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"MyCLabs\\Enum\\": "src/"
},
"classmap": [
"stubs/Stringable.php"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -694,15 +905,34 @@
"keywords": [
"enum"
],
"support": {
"issues": "https://github.com/myclabs/php-enum/issues",
"source": "https://github.com/myclabs/php-enum/tree/1.7.7"
},
"funding": [
{
"url": "https://github.com/mnapoli",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
"type": "tidelift"
}
],
"install-path": "../myclabs/php-enum"
},
{
"name": "nelexa/zip",
"version": "3.3.3",
"version_normalized": "3.3.3.0",
"source": {
"type": "git",
"url": "https://github.com/Ne-Lexa/php-zip.git",
"reference": "501b52f6fc393a599b44ff348a42740e1eaac7c6"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/nelexa/zip/3.3.3/nelexa-zip-3.3.3.zip",
"url": "https://api.github.com/repos/Ne-Lexa/php-zip/zipball/501b52f6fc393a599b44ff348a42740e1eaac7c6",
"reference": "501b52f6fc393a599b44ff348a42740e1eaac7c6",
"shasum": ""
},
... ... @@ -736,6 +966,7 @@
"PhpZip\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -757,15 +988,24 @@
"zipalign",
"ziparchive"
],
"support": {
"issues": "https://github.com/Ne-Lexa/php-zip/issues",
"source": "https://github.com/Ne-Lexa/php-zip/tree/3.3.3"
},
"install-path": "../nelexa/zip"
},
{
"name": "overtrue/pinyin",
"version": "3.0.6",
"version_normalized": "3.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/overtrue/pinyin.git",
"reference": "3b781d267197b74752daa32814d3a2cf5d140779"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/overtrue/pinyin/3.0.6/overtrue-pinyin-3.0.6.zip",
"url": "https://api.github.com/repos/overtrue/pinyin/zipball/3b781d267197b74752daa32814d3a2cf5d140779",
"reference": "3b781d267197b74752daa32814d3a2cf5d140779",
"shasum": ""
},
... ... @@ -783,6 +1023,7 @@
"Overtrue\\Pinyin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -799,15 +1040,24 @@
"Pinyin",
"cn2pinyin"
],
"support": {
"issues": "https://github.com/overtrue/pinyin/issues",
"source": "https://github.com/overtrue/pinyin/tree/master"
},
"install-path": "../overtrue/pinyin"
},
{
"name": "overtrue/socialite",
"version": "2.0.24",
"version_normalized": "2.0.24.0",
"source": {
"type": "git",
"url": "https://github.com/overtrue/socialite.git",
"reference": "ee7e7b000ec7d64f2b8aba1f6a2eec5cdf3f8bec"
},
"dist": {
"type": "zip",
"url": "https://mirrors.tencent.com/repository/composer/overtrue/socialite/2.0.24/overtrue-socialite-2.0.24.zip",
"url": "https://api.github.com/repos/overtrue/socialite/zipball/ee7e7b000ec7d64f2b8aba1f6a2eec5cdf3f8bec",
"reference": "ee7e7b000ec7d64f2b8aba1f6a2eec5cdf3f8bec",
"shasum": ""
},
... ... @@ -829,6 +1079,7 @@
"Overtrue\\Socialite\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -847,15 +1098,30 @@
"wechat",
"weibo"
],
"support": {
"issues": "https://github.com/overtrue/socialite/issues",
"source": "https://github.com/overtrue/socialite/tree/2.0.24"
},
"funding": [
{
"url": "https://www.patreon.com/overtrue",
"type": "patreon"
}
],
"install-path": "../overtrue/socialite"
},
{
"name": "overtrue/wechat",
"version": "4.7.0",
"version_normalized": "4.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/w7corp/easywechat.git",
"reference": "4accb0627803ffb6e45d2988898a0293d2a48e68"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/overtrue/wechat/4.7.0/overtrue-wechat-4.7.0.zip",
"url": "https://api.github.com/repos/w7corp/easywechat/zipball/4accb0627803ffb6e45d2988898a0293d2a48e68",
"reference": "4accb0627803ffb6e45d2988898a0293d2a48e68",
"shasum": ""
},
... ... @@ -894,6 +1160,7 @@
"EasyWeChat\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -911,15 +1178,31 @@
"weixin",
"weixin-sdk"
],
"support": {
"issues": "https://github.com/w7corp/easywechat/issues",
"source": "https://github.com/w7corp/easywechat/tree/4.7.0"
},
"funding": [
{
"url": "https://github.com/overtrue",
"type": "github"
}
],
"abandoned": "w7corp/easywechat",
"install-path": "../overtrue/wechat"
},
{
"name": "paragonie/random_compat",
"version": "v9.99.100",
"version_normalized": "9.99.100.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/paragonie/random_compat/v9.99.100/paragonie-random_compat-v9.99.100.zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
"shasum": ""
},
... ... @@ -936,6 +1219,7 @@
"time": "2020-10-15T08:29:30+00:00",
"type": "library",
"installation-source": "dist",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -953,15 +1237,25 @@
"pseudorandom",
"random"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/random_compat/issues",
"source": "https://github.com/paragonie/random_compat"
},
"install-path": "../paragonie/random_compat"
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.19.0",
"version_normalized": "1.19.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "a9ab55bfae02eecffb3df669a2e19ba0e2f04bbf"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/phpoffice/phpspreadsheet/1.19.0/phpoffice-phpspreadsheet-1.19.0.zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/a9ab55bfae02eecffb3df669a2e19ba0e2f04bbf",
"reference": "a9ab55bfae02eecffb3df669a2e19ba0e2f04bbf",
"shasum": ""
},
... ... @@ -1015,6 +1309,7 @@
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1050,15 +1345,24 @@
"xls",
"xlsx"
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.19.0"
},
"install-path": "../phpoffice/phpspreadsheet"
},
{
"name": "pimple/pimple",
"version": "v3.5.0",
"version_normalized": "3.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/silexphp/Pimple.git",
"reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed"
},
"dist": {
"type": "zip",
"url": "https://mirrors.tencent.com/repository/composer/pimple/pimple/v3.5.0/pimple-pimple-v3.5.0.zip",
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed",
"reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed",
"shasum": ""
},
... ... @@ -1082,6 +1386,7 @@
"Pimple": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1097,15 +1402,23 @@
"container",
"dependency injection"
],
"support": {
"source": "https://github.com/silexphp/Pimple/tree/v3.5.0"
},
"install-path": "../pimple/pimple"
},
{
"name": "psr/cache",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/cache/1.0.1/psr-cache-1.0.1.zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
... ... @@ -1125,6 +1438,7 @@
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1140,22 +1454,30 @@
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/master"
},
"install-path": "../psr/cache"
},
{
"name": "psr/container",
"version": "2.0.2",
"version_normalized": "2.0.2.0",
"version": "2.0.1",
"version_normalized": "2.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "2ae37329ee82f91efadc282cc2d527fd6065a5ef"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/container/2.0.2/psr-container-2.0.2.zip",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"url": "https://api.github.com/repos/php-fig/container/zipball/2ae37329ee82f91efadc282cc2d527fd6065a5ef",
"reference": "2ae37329ee82f91efadc282cc2d527fd6065a5ef",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
"php": ">=7.2.0"
},
"time": "2021-11-05T16:47:00+00:00",
"time": "2021-03-24T13:40:57+00:00",
"type": "library",
"extra": {
"branch-alias": {
... ... @@ -1168,6 +1490,7 @@
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1186,15 +1509,24 @@
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.1"
},
"install-path": "../psr/container"
},
{
"name": "psr/event-dispatcher",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/event-dispatcher/1.0.0/psr-event-dispatcher-1.0.0.zip",
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
... ... @@ -1214,6 +1546,7 @@
"Psr\\EventDispatcher\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1229,15 +1562,24 @@
"psr",
"psr-14"
],
"support": {
"issues": "https://github.com/php-fig/event-dispatcher/issues",
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
},
"install-path": "../psr/event-dispatcher"
},
{
"name": "psr/http-client",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/http-client/1.0.1/psr-http-client-1.0.1.zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": ""
},
... ... @@ -1258,6 +1600,7 @@
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1275,15 +1618,23 @@
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
},
"install-path": "../psr/http-client"
},
{
"name": "psr/http-factory",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/http-factory/1.0.1/psr-http-factory-1.0.1.zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"shasum": ""
},
... ... @@ -1304,6 +1655,7 @@
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1324,15 +1676,23 @@
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/master"
},
"install-path": "../psr/http-factory"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/http-message/1.0.1/psr-http-message-1.0.1.zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
... ... @@ -1352,6 +1712,7 @@
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1371,15 +1732,23 @@
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"install-path": "../psr/http-message"
},
{
"name": "psr/log",
"version": "1.1.4",
"version_normalized": "1.1.4.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/log/1.1.4/psr-log-1.1.4.zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
... ... @@ -1399,6 +1768,7 @@
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1415,15 +1785,23 @@
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"install-path": "../psr/log"
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/psr/simple-cache/1.0.1/psr-simple-cache-1.0.1.zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
... ... @@ -1443,6 +1821,7 @@
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1460,15 +1839,23 @@
"psr-16",
"simple-cache"
],
"support": {
"source": "https://github.com/php-fig/simple-cache/tree/master"
},
"install-path": "../psr/simple-cache"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"version_normalized": "3.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/ralouphie/getallheaders/3.0.3/ralouphie-getallheaders-3.0.3.zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
... ... @@ -1487,6 +1874,7 @@
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1497,16 +1885,25 @@
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"install-path": "../ralouphie/getallheaders"
},
{
"name": "symfony/cache",
"version": "v5.4.15",
"version_normalized": "5.4.15.0",
"version": "v5.4.21",
"version_normalized": "5.4.21.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "32cab695bf99c63aff7d27ac67919944c00530ed"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/cache/v5.4.15/symfony-cache-v5.4.15.zip",
"reference": "60e87188abbacd29ccde44d69c5392a33e888e98",
"url": "https://api.github.com/repos/symfony/cache/zipball/32cab695bf99c63aff7d27ac67919944c00530ed",
"reference": "32cab695bf99c63aff7d27ac67919944c00530ed",
"shasum": ""
},
"require": {
... ... @@ -1544,7 +1941,7 @@
"symfony/messenger": "^4.4|^5.0|^6.0",
"symfony/var-dumper": "^4.4|^5.0|^6.0"
},
"time": "2022-10-27T07:55:40+00:00",
"time": "2023-02-21T12:11:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
... ... @@ -1555,6 +1952,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1574,15 +1972,37 @@
"caching",
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v5.4.21"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/cache"
},
{
"name": "symfony/cache-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache-contracts.git",
"reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/cache-contracts/v2.5.2/symfony-cache-contracts-v2.5.2.zip",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
"reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
"shasum": ""
},
... ... @@ -1610,6 +2030,7 @@
"Symfony\\Contracts\\Cache\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1633,15 +2054,37 @@
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/cache-contracts/tree/v2.5.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/cache-contracts"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/deprecation-contracts/v2.5.2/symfony-deprecation-contracts-v2.5.2.zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
... ... @@ -1665,6 +2108,7 @@
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1680,16 +2124,38 @@
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/deprecation-contracts"
},
{
"name": "symfony/event-dispatcher",
"version": "v5.4.9",
"version_normalized": "5.4.9.0",
"version": "v5.4.21",
"version_normalized": "5.4.21.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "f0ae1383a8285dfc6752b8d8602790953118ff5a"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/event-dispatcher/v5.4.9/symfony-event-dispatcher-v5.4.9.zip",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f0ae1383a8285dfc6752b8d8602790953118ff5a",
"reference": "f0ae1383a8285dfc6752b8d8602790953118ff5a",
"shasum": ""
},
"require": {
... ... @@ -1719,7 +2185,7 @@
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2022-05-05T16:45:39+00:00",
"time": "2023-02-14T08:03:56+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
... ... @@ -1730,6 +2196,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1745,15 +2212,37 @@
],
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.21"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/event-dispatcher"
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/event-dispatcher-contracts/v2.5.2/symfony-event-dispatcher-contracts-v2.5.2.zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
"shasum": ""
},
... ... @@ -1781,6 +2270,7 @@
"Symfony\\Contracts\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1804,16 +2294,38 @@
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/event-dispatcher-contracts"
},
{
"name": "symfony/finder",
"version": "v5.4.11",
"version_normalized": "5.4.11.0",
"version": "v5.4.21",
"version_normalized": "5.4.21.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/finder/v5.4.11/symfony-finder-v5.4.11.zip",
"reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c",
"url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19",
"reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19",
"shasum": ""
},
"require": {
... ... @@ -1821,7 +2333,7 @@
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16"
},
"time": "2022-07-29T07:37:50+00:00",
"time": "2023-02-16T09:33:00+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
... ... @@ -1832,6 +2344,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1847,16 +2360,38 @@
],
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v5.4.21"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/finder"
},
{
"name": "symfony/http-foundation",
"version": "v5.4.16",
"version_normalized": "5.4.16.0",
"version": "v5.4.21",
"version_normalized": "5.4.21.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "3bb6ee5582366c4176d5ce596b380117c8200bbf"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/http-foundation/v5.4.16/symfony-http-foundation-v5.4.16.zip",
"reference": "5032c5849aef24741e1970cb03511b0dd131d838",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/3bb6ee5582366c4176d5ce596b380117c8200bbf",
"reference": "3bb6ee5582366c4176d5ce596b380117c8200bbf",
"shasum": ""
},
"require": {
... ... @@ -1877,7 +2412,7 @@
"suggest": {
"symfony/mime": "To use the file extension guesser"
},
"time": "2022-11-07T08:06:40+00:00",
"time": "2023-02-17T21:35:35+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
... ... @@ -1888,6 +2423,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1903,15 +2439,37 @@
],
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v5.4.21"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/http-foundation"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/polyfill-mbstring/v1.27.0/symfony-polyfill-mbstring-v1.27.0.zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
... ... @@ -1944,6 +2502,7 @@
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -1966,15 +2525,37 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-mbstring"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/polyfill-php73/v1.27.0/symfony-polyfill-php73-v1.27.0.zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"shasum": ""
},
... ... @@ -2004,6 +2585,7 @@
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2025,15 +2607,37 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-php73"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/polyfill-php80/v1.27.0/symfony-polyfill-php80-v1.27.0.zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": ""
},
... ... @@ -2063,6 +2667,7 @@
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2088,15 +2693,37 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-php80"
},
{
"name": "symfony/psr-http-message-bridge",
"version": "v2.1.4",
"version_normalized": "2.1.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
"reference": "a125b93ef378c492e274f217874906fb9babdebb"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/psr-http-message-bridge/v2.1.4/symfony-psr-http-message-bridge-v2.1.4.zip",
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/a125b93ef378c492e274f217874906fb9babdebb",
"reference": "a125b93ef378c492e274f217874906fb9babdebb",
"shasum": ""
},
... ... @@ -2134,6 +2761,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2155,15 +2783,38 @@
"psr-17",
"psr-7"
],
"support": {
"issues": "https://github.com/symfony/psr-http-message-bridge/issues",
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/psr-http-message-bridge"
},
{
"name": "symfony/service-contracts",
"version": "v1.1.2",
"version_normalized": "1.1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/service-contracts/v1.1.2/symfony-service-contracts-v1.1.2.zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/191afdcb5804db960d26d8566b7e9a2843cab3a0",
"reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0",
"shasum": ""
},
... ... @@ -2187,6 +2838,7 @@
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2210,15 +2862,23 @@
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v1.1.2"
},
"install-path": "../symfony/service-contracts"
},
{
"name": "symfony/var-exporter",
"version": "v4.4.43",
"version_normalized": "4.4.43.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/symfony/var-exporter/v4.4.43/symfony-var-exporter-v4.4.43.zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b",
"reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b",
"shasum": ""
},
... ... @@ -2240,6 +2900,7 @@
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2263,6 +2924,23 @@
"instantiate",
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v4.4.43"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/var-exporter"
},
{
... ... @@ -2272,7 +2950,7 @@
"source": {
"type": "git",
"url": "https://gitee.com/fastadminnet/framework.git",
"reference": "a5f1cedf07bb3489f7e3b5254496afbf600d4e65"
"reference": "096811899433eb0eb0988f1fe1db56ebb521bf34"
},
"require": {
"php": ">=7.1.0",
... ... @@ -2286,7 +2964,7 @@
"phpunit/phpunit": "4.8.*",
"sebastian/phpcpd": "2.*"
},
"time": "2022-12-05T14:00:16+00:00",
"time": "2022-12-19T02:13:42+00:00",
"default-branch": true,
"type": "think-framework",
"installation-source": "source",
... ... @@ -2317,9 +2995,14 @@
"name": "topthink/think-captcha",
"version": "v1.0.7",
"version_normalized": "1.0.7.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-captcha.git",
"reference": "0c55455df26a1626a60d0dc35d2d89002b741d44"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/topthink/think-captcha/v1.0.7/topthink-think-captcha-v1.0.7.zip",
"url": "https://api.github.com/repos/top-think/think-captcha/zipball/0c55455df26a1626a60d0dc35d2d89002b741d44",
"reference": "0c55455df26a1626a60d0dc35d2d89002b741d44",
"shasum": ""
},
... ... @@ -2334,6 +3017,7 @@
"think\\captcha\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
... ... @@ -2344,15 +3028,24 @@
}
],
"description": "captcha package for thinkphp5",
"support": {
"issues": "https://github.com/top-think/think-captcha/issues",
"source": "https://github.com/top-think/think-captcha/tree/master"
},
"install-path": "../topthink/think-captcha"
},
{
"name": "topthink/think-helper",
"version": "v1.0.7",
"version_normalized": "1.0.7.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-helper.git",
"reference": "5f92178606c8ce131d36b37a57c58eb71e55f019"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/topthink/think-helper/v1.0.7/topthink-think-helper-v1.0.7.zip",
"url": "https://api.github.com/repos/top-think/think-helper/zipball/5f92178606c8ce131d36b37a57c58eb71e55f019",
"reference": "5f92178606c8ce131d36b37a57c58eb71e55f019",
"shasum": ""
},
... ... @@ -2367,6 +3060,7 @@
"think\\helper\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
... ... @@ -2377,15 +3071,24 @@
}
],
"description": "The ThinkPHP5 Helper Package",
"support": {
"issues": "https://github.com/top-think/think-helper/issues",
"source": "https://github.com/top-think/think-helper/tree/master"
},
"install-path": "../topthink/think-helper"
},
{
"name": "topthink/think-installer",
"version": "v1.0.14",
"version_normalized": "1.0.14.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-installer.git",
"reference": "eae1740ac264a55c06134b6685dfb9f837d004d1"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/topthink/think-installer/v1.0.14/topthink-think-installer-v1.0.14.zip",
"url": "https://api.github.com/repos/top-think/think-installer/zipball/eae1740ac264a55c06134b6685dfb9f837d004d1",
"reference": "eae1740ac264a55c06134b6685dfb9f837d004d1",
"shasum": ""
},
... ... @@ -2406,6 +3109,7 @@
"think\\composer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
... ... @@ -2415,15 +3119,24 @@
"email": "448901948@qq.com"
}
],
"support": {
"issues": "https://github.com/top-think/think-installer/issues",
"source": "https://github.com/top-think/think-installer/tree/v1.0.14"
},
"install-path": "../topthink/think-installer"
},
{
"name": "topthink/think-queue",
"version": "v1.1.6",
"version_normalized": "1.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-queue.git",
"reference": "250650eb0e8ea5af4cfdc7ae46f3f4e0a24ac245"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/topthink/think-queue/v1.1.6/topthink-think-queue-v1.1.6.zip",
"url": "https://api.github.com/repos/top-think/think-queue/zipball/250650eb0e8ea5af4cfdc7ae46f3f4e0a24ac245",
"reference": "250650eb0e8ea5af4cfdc7ae46f3f4e0a24ac245",
"shasum": ""
},
... ... @@ -2450,6 +3163,7 @@
"think\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
... ... @@ -2460,15 +3174,24 @@
}
],
"description": "The ThinkPHP5 Queue Package",
"support": {
"issues": "https://github.com/top-think/think-queue/issues",
"source": "https://github.com/top-think/think-queue/tree/master"
},
"install-path": "../topthink/think-queue"
},
{
"name": "txthinking/mailer",
"version": "v2.0.1",
"version_normalized": "2.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/txthinking/Mailer.git",
"reference": "09013cf9dad3aac195f66ae5309e8c3343c018e9"
},
"dist": {
"type": "zip",
"url": "https://mirrors.cloud.tencent.com/repository/composer/txthinking/mailer/v2.0.1/txthinking-mailer-v2.0.1.zip",
"url": "https://api.github.com/repos/txthinking/Mailer/zipball/09013cf9dad3aac195f66ae5309e8c3343c018e9",
"reference": "09013cf9dad3aac195f66ae5309e8c3343c018e9",
"shasum": ""
},
... ... @@ -2488,6 +3211,7 @@
"Tx\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
... ... @@ -2509,6 +3233,10 @@
"mail",
"smtp"
],
"support": {
"issues": "https://github.com/txthinking/Mailer/issues",
"source": "https://github.com/txthinking/Mailer/tree/master"
},
"install-path": "../txthinking/mailer"
}
],
... ...
<?php return array(
'root' => array(
'name' => 'karsonzhang/fastadmin',
'pretty_version' => '1.3.5.x-dev',
'version' => '1.3.5.9999999-dev',
'reference' => 'f8292a8813201872005173b7d2ec3ca556a25cfd',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'cf512b490954a1f28e38e3588d8300ee784760b9',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'chenbool/barcode' => array(
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'reference' => '4c1b8264527e8e53bfb059696d60c4e31fd63e24',
'type' => 'library',
'install_path' => __DIR__ . '/../chenbool/barcode',
'aliases' => array(),
'dev_requirement' => false,
),
'easywechat-composer/easywechat-composer' => array(
'pretty_version' => '1.4.1',
'version' => '1.4.1.0',
... ... @@ -47,18 +56,18 @@
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.4.3',
'version' => '2.4.3.0',
'reference' => '67c26b443f348a51926030c83481b85718457d3d',
'pretty_version' => '2.4.4',
'version' => '2.4.4.0',
'reference' => '3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'karsonzhang/fastadmin' => array(
'pretty_version' => '1.3.5.x-dev',
'version' => '1.3.5.9999999-dev',
'reference' => 'f8292a8813201872005173b7d2ec3ca556a25cfd',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'cf512b490954a1f28e38e3588d8300ee784760b9',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
... ... @@ -74,9 +83,9 @@
'dev_requirement' => false,
),
'maennchen/zipstream-php' => array(
'pretty_version' => '2.2.6',
'version' => '2.2.6.0',
'reference' => '30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f',
'pretty_version' => '2.1.0',
'version' => '2.1.0.0',
'reference' => 'c4c5803cc1f93df3d2448478ef79394a5981cc58',
'type' => 'library',
'install_path' => __DIR__ . '/../maennchen/zipstream-php',
'aliases' => array(),
... ... @@ -101,18 +110,18 @@
'dev_requirement' => false,
),
'monolog/monolog' => array(
'pretty_version' => '2.8.0',
'version' => '2.8.0.0',
'reference' => '720488632c590286b88b80e62aa3d3d551ad4a50',
'pretty_version' => '2.9.1',
'version' => '2.9.1.0',
'reference' => 'f259e2b15fb95494c83f52d3caad003bbf5ffaa1',
'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog',
'aliases' => array(),
'dev_requirement' => false,
),
'myclabs/php-enum' => array(
'pretty_version' => '1.8.4',
'version' => '1.8.4.0',
'reference' => 'a867478eae49c9f59ece437ae7f9506bfaa27483',
'pretty_version' => '1.7.7',
'version' => '1.7.7.0',
'reference' => 'd178027d1e679832db9f38248fcc7200647dc2b7',
'type' => 'library',
'install_path' => __DIR__ . '/../myclabs/php-enum',
'aliases' => array(),
... ... @@ -197,9 +206,9 @@
),
),
'psr/container' => array(
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
'pretty_version' => '2.0.1',
'version' => '2.0.1.0',
'reference' => '2ae37329ee82f91efadc282cc2d527fd6065a5ef',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
... ... @@ -305,9 +314,9 @@
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v5.4.15',
'version' => '5.4.15.0',
'reference' => '60e87188abbacd29ccde44d69c5392a33e888e98',
'pretty_version' => 'v5.4.21',
'version' => '5.4.21.0',
'reference' => '32cab695bf99c63aff7d27ac67919944c00530ed',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
... ... @@ -338,9 +347,9 @@
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v5.4.9',
'version' => '5.4.9.0',
'reference' => '8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc',
'pretty_version' => 'v5.4.21',
'version' => '5.4.21.0',
'reference' => 'f0ae1383a8285dfc6752b8d8602790953118ff5a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
... ... @@ -362,18 +371,18 @@
),
),
'symfony/finder' => array(
'pretty_version' => 'v5.4.11',
'version' => '5.4.11.0',
'reference' => '7872a66f57caffa2916a584db1aa7f12adc76f8c',
'pretty_version' => 'v5.4.21',
'version' => '5.4.21.0',
'reference' => '078e9a5e1871fcfe6a5ce421b539344c21afef19',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-foundation' => array(
'pretty_version' => 'v5.4.16',
'version' => '5.4.16.0',
'reference' => '5032c5849aef24741e1970cb03511b0dd131d838',
'pretty_version' => 'v5.4.21',
'version' => '5.4.21.0',
'reference' => '3bb6ee5582366c4176d5ce596b380117c8200bbf',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
... ... @@ -436,7 +445,7 @@
'topthink/framework' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'a5f1cedf07bb3489f7e3b5254496afbf600d4e65',
'reference' => '096811899433eb0eb0988f1fe1db56ebb521bf34',
'type' => 'think-framework',
'install_path' => __DIR__ . '/../../thinkphp',
'aliases' => array(
... ...
... ... @@ -4,8 +4,8 @@
$issues = array();
if (!(PHP_VERSION_ID >= 70400)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
if (!(PHP_VERSION_ID >= 70205)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
... ...
... ... @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## 2.4.4 - 2023-03-09
### Changed
- Removed the need for `AllowDynamicProperties` in `LazyOpenStream`
## 2.4.3 - 2022-10-26
### Changed
... ...
... ... @@ -8,6 +8,12 @@ functionality like query string parsing.
![Static analysis](https://github.com/guzzle/psr7/workflows/Static%20analysis/badge.svg)
# Installation
```shell
composer require guzzlehttp/psr7
```
# Stream implementation
This package comes with a number of stream implementations and stream
... ... @@ -245,6 +251,8 @@ class EofCallbackStream implements StreamInterface
private $callback;
private $stream;
public function __construct(StreamInterface $stream, callable $cb)
{
$this->stream = $stream;
... ...
... ... @@ -10,7 +10,6 @@ use Psr\Http\Message\StreamInterface;
* Lazily reads or writes to a file that is opened only after an IO operation
* take place on the stream.
*/
#[\AllowDynamicProperties]
final class LazyOpenStream implements StreamInterface
{
use StreamDecoratorTrait;
... ... @@ -22,6 +21,11 @@ final class LazyOpenStream implements StreamInterface
private $mode;
/**
* @var StreamInterface
*/
private $stream;
/**
* @param string $filename File to lazily open
* @param string $mode fopen mode to use when opening the stream
*/
... ... @@ -29,6 +33,10 @@ final class LazyOpenStream implements StreamInterface
{
$this->filename = $filename;
$this->mode = $mode;
// unsetting the property forces the first access to go through
// __get().
unset($this->stream);
}
/**
... ...
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpdocumentor" version="^3.3.1" installed="3.3.1" location="./tools/phpdocumentor" copy="false"/>
</phive>
<?php
declare(strict_types=1);
/**
* PHP-CS-Fixer config for ZipStream-PHP
* @author Nicolas CARPi <nico-git@deltablot.email>
* @copyright 2022 Nicolas CARPi
* @see https://github.com/maennchen/ZipStream-PHP
* @license MIT
* @package maennchen/ZipStream-PHP
*/
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->exclude('.github')
->exclude('.phpdoc')
->exclude('docs')
->exclude('tools')
->exclude('vendor')
->in(__DIR__);
$config = new Config();
return $config->setRules([
'@PER' => true,
'@PER:risky' => true,
'@PHP81Migration' => true,
'@PHPUnit84Migration:risky' => true,
'array_syntax' => ['syntax' => 'short'],
'class_attributes_separation' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'is_null' => true,
'no_homoglyph_names' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'non_printable_character' => true,
'ordered_imports' => true,
'ordered_class_elements' => true,
'php_unit_construct' => true,
'pow_to_exponentiation' => true,
'psr_autoloading' => true,
'random_api_migration' => true,
'return_assignment' => true,
'self_accessor' => true,
'semicolon_after_instruction' => true,
'short_scalar_cast' => true,
'simplified_null_return' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'single_line_comment_style' => true,
'single_quote' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'strict_param' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_functions' => true,
'import_constants' => true,
],
])
->setFinder($finder)
->setRiskyAllowed(true);
\ No newline at end of file
{% extends 'layout.html.twig' %}
{% set topMenu = {
"menu": [
{ "name": "Guides", "url": "https://maennchen.dev/ZipStream-PHP/guide/index.html"},
{ "name": "API", "url": "https://maennchen.dev/ZipStream-PHP/classes/ZipStream-ZipStream.html"},
{ "name": "Issues", "url": "https://github.com/maennchen/ZipStream-PHP/issues"},
],
"social": [
{ "iconClass": "fab fa-github", "url": "https://github.com/maennchen/ZipStream-PHP"},
{ "iconClass": "fas fa-envelope-open-text", "url": "https://github.com/maennchen/ZipStream-PHP/discussions"},
{ "iconClass": "fas fa-money-bill", "url": "https://opencollective.com/zipstream"},
]
}
%}
\ No newline at end of file
# ZipStream-PHP
[![Main Branch](https://github.com/maennchen/ZipStream-PHP/actions/workflows/branch_main.yml/badge.svg)](https://github.com/maennchen/ZipStream-PHP/actions/workflows/branch_main.yml)
[![Coverage Status](https://coveralls.io/repos/github/maennchen/ZipStream-PHP/badge.svg?branch=main)](https://coveralls.io/github/maennchen/ZipStream-PHP?branch=main)
[![Build Status](https://travis-ci.org/maennchen/ZipStream-PHP.svg?branch=master)](https://travis-ci.org/maennchen/ZipStream-PHP)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/maennchen/ZipStream-PHP/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/maennchen/ZipStream-PHP/)
[![Code Coverage](https://scrutinizer-ci.com/g/maennchen/ZipStream-PHP/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/maennchen/ZipStream-PHP/)
[![Latest Stable Version](https://poser.pugx.org/maennchen/zipstream-php/v/stable)](https://packagist.org/packages/maennchen/zipstream-php)
[![Total Downloads](https://poser.pugx.org/maennchen/zipstream-php/downloads)](https://packagist.org/packages/maennchen/zipstream-php)
[![Financial Contributors on Open Collective](https://opencollective.com/zipstream/all/badge.svg?label=financial+contributors)](https://opencollective.com/zipstream) [![License](https://img.shields.io/github/license/maennchen/zipstream-php.svg)](LICENSE)
## Unstable Branch
The `main` branch is not stable. Please see the
[releases](https://github.com/maennchen/ZipStream-PHP/releases) for a stable
version.
## Overview
A fast and simple streaming zip file downloader for PHP. Using this library will save you from having to write the Zip to disk. You can directly send it to the user, which is much faster. It can work with S3 buckets or any PSR7 Stream.
... ... @@ -26,10 +21,7 @@ Simply add a dependency on maennchen/zipstream-php to your project's composer.js
composer require maennchen/zipstream-php
```
## Usage
For detailed instructions, please check the
[Documentation](https://maennchen.dev/ZipStream-PHP/).
## Usage and options
Here's a simple example:
... ... @@ -50,20 +42,39 @@ $zip->addFile('hello.txt', 'This is the contents of hello.txt');
// add a file named 'some_image.jpg' from a local file 'path/to/image.jpg'
$zip->addFileFromPath('some_image.jpg', 'path/to/image.jpg');
// add a file named 'goodbye.txt' from an open stream resource
$fp = tmpfile();
fwrite($fp, 'The quick brown fox jumped over the lazy dog.');
rewind($fp);
$zip->addFileFromStream('goodbye.txt', $fp);
fclose($fp);
// finish the zip stream
$zip->finish();
```
You can also add comments, modify file timestamps, and customize (or
disable) the HTTP headers. It is also possible to specify the storage method when adding files,
the current default storage method is 'deflate' i.e files are stored with Compression mode 0x08.
See the [Wiki](https://github.com/maennchen/ZipStream-PHP/wiki) for details.
## Known issue
The native Mac OS archive extraction tool might not open archives in some conditions. A workaround is to disable the Zip64 feature with the option `$opt->setEnableZip64(false)`. This limits the archive to 4 Gb and 64k files but will allow Mac OS users to open them without issue. See #116.
The linux `unzip` utility might not handle properly unicode characters. It is recommended to extract with another tool like [7-zip](https://www.7-zip.org/). See #146.
## Upgrade to version 2.0.0
- Only the self opened streams will be closed (#139)
If you were relying on ZipStream to close streams that the library didn't open,
you'll need to close them yourself now.
* Only the self opened streams will be closed (#139)
If you were relying on ZipStream to close streams that the library didn't open,
you'll need to close them yourself now.
## Upgrade to version 1.0.0
- All options parameters to all function have been moved from an `array` to structured option objects. See [the wiki](https://github.com/maennchen/ZipStream-PHP/wiki/Available-options) for examples.
- The whole library has been refactored. The minimal PHP requirement has been raised to PHP 7.1.
* All options parameters to all function have been moved from an `array` to structured option objects. See [the wiki](https://github.com/maennchen/ZipStream-PHP/wiki/Available-options) for examples.
* The whole library has been refactored. The minimal PHP requirement has been raised to PHP 7.1.
## Usage with Symfony and S3
... ... @@ -71,23 +82,21 @@ You can find example code on [the wiki](https://github.com/maennchen/ZipStream-P
## Contributing
ZipStream-PHP is a collaborative project. Please take a look at the
[.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) file.
ZipStream-PHP is a collaborative project. Please take a look at the [CONTRIBUTING.md](CONTRIBUTING.md) file.
## About the Authors
- Paul Duncan <pabs@pablotron.org> - https://pablotron.org/
- Jonatan Männchen <jonatan@maennchen.ch> - https://maennchen.dev
- Jesse G. Donat <donatj@gmail.com> - https://donatstudios.com
- Nicolas CARPi <nico-git@deltablot.email> - https://www.deltablot.com
- Nik Barham <nik@brokencube.co.uk> - https://www.brokencube.co.uk
* Paul Duncan <pabs@pablotron.org> - https://pablotron.org/
* Jonatan Männchen <jonatan@maennchen.ch> - https://maennchen.dev
* Jesse G. Donat <donatj@gmail.com> - https://donatstudios.com
* Nicolas CARPi <nico-git@deltablot.email> - https://www.deltablot.com
* Nik Barham <nik@brokencube.co.uk> - https://www.brokencube.co.uk
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute.
[[Contribute](.github/CONTRIBUTING.md)].
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/maennchen/ZipStream-PHP/graphs/contributors"><img src="https://opencollective.com/zipstream/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
... ...
... ... @@ -22,55 +22,20 @@
}
],
"require": {
"php": "^7.4 || ^8.0",
"php": ">= 7.1",
"symfony/polyfill-mbstring": "^1.0",
"psr/http-message": "^1.0",
"myclabs/php-enum": "^1.5"
},
"require-dev": {
"phpunit/phpunit": "^8.5.8 || ^9.4.2",
"guzzlehttp/guzzle": "^6.5.3 || ^7.2.0",
"phpunit/phpunit": ">= 7.5",
"guzzlehttp/guzzle": ">= 6.3",
"ext-zip": "*",
"mikey179/vfsstream": "^1.6",
"vimeo/psalm": "^4.1",
"php-coveralls/php-coveralls": "^2.4",
"friendsofphp/php-cs-fixer": "^3.9"
},
"scripts": {
"format": "php-cs-fixer fix",
"test": "composer run test:unit && composer run test:formatted && composer run test:lint",
"test:unit": "phpunit --coverage-clover=coverage.clover.xml",
"test:formatted": "composer run format -- --dry-run --stop-on-violation --using-cache=no",
"test:lint": "psalm --stats --show-info --find-unused-psalm-suppress",
"coverage:report": "php-coveralls --coverage_clover=coverage.clover.xml --json_path=coveralls-upload.json -v",
"install:tools": "phive install --trust-gpg-keys 0x67F861C3D889C656",
"docs:generate": "tools/phpdocumentor --sourcecode"
"mikey179/vfsstream": "^1.6"
},
"autoload": {
"psr-4": {
"ZipStream\\": "src/"
}
},
"archive": {
"exclude": [
"/composer.lock",
"/docs",
"/.gitattributes",
"/.github",
"/.gitignore",
"/guides",
"/.phive",
"/.php-cs-fixer.cache",
"/.php-cs-fixer.dist.php",
"/.phpdoc",
"/phpdoc.dist.xml",
"/.phpunit.result.cache",
"/phpunit.xml.dist",
"/psalm.xml",
"/test",
"/tools",
"/.tool-versions",
"/vendor"
]
}
}
... ...
Adding Content-Length header
=============
Adding a ``Content-Length`` header for ``ZipStream`` is not trivial since the
size is not known beforehand.
The following workaround adds an approximated header:
.. code-block:: php
class Zip
{
/** @var string */
private $name;
private $files = [];
public function __construct($name)
{
$this->name = $name;
}
public function addFile($name, $data)
{
$this->files[] = ['type' => 'addFile', 'name' => $name, 'data' => $data];
}
public function addFileFromPath($name, $path)
{
$this->files[] = ['type' => 'addFileFromPath', 'name' => $name, 'path' => $path];
}
public function getEstimate()
{
$estimate = 22;
foreach ($this->files as $file) {
$estimate += 76 + 2 * strlen($file['name']);
if ($file['type'] === 'addFile') {
$estimate += strlen($file['data']);
}
if ($file['type'] === 'addFileFromPath') {
$estimate += filesize($file['path']);
}
}
return $estimate;
}
public function finish()
{
header('Content-Length: ' . $this->getEstimate());
$options = new \ZipStream\Option\Archive();
$options->setSendHttpHeaders(true);
$options->setEnableZip64(false);
$options->setDeflateLevel(-1);
$zip = new \ZipStream\ZipStream($this->name, $options);
$fileOptions = new \ZipStream\Option\File();
$fileOptions->setMethod(\ZipStream\Option\Method::STORE());
foreach ($this->files as $file) {
if ($file['type'] === 'addFile') {
$zip->addFile($file['name'], $file['data'], $fileOptions);
}
if ($file['type'] === 'addFileFromPath') {
$zip->addFileFromPath($file['name'], $file['path'], $fileOptions);
}
}
$zip->finish();
exit;
}
}
It only works with the following constraints:
- All file content is known beforehand.
- Content Deflation is disabled
Thanks to
`partiellkorrekt <https://github.com/maennchen/ZipStream-PHP/issues/89#issuecomment-1047949274>`_
for this workaround.
\ No newline at end of file
Usage with FlySystem
===============
For saving or uploading the generated zip, you can use the
`Flysystem <https://flysystem.thephpleague.com>`_ package, and its many
adapters.
For that you will need to provide another stream than the ``php://output``
default one, and pass it to Flysystem ``putStream`` method.
.. code-block:: php
// Open Stream only once for read and write since it's a memory stream and
// the content is lost when closing the stream / opening another one
$tempStream = fopen('php://memory', 'w+');
// Init Options
$zipStreamOptions = new Archive();
$zipStreamOptions->setOutputStream($tempStream);
// Create Zip Archive
$zipStream = new ZipStream('test.zip', $zipStreamOptions);
$zipStream->addFile('test.txt', 'text');
$zipStream->finish();
// Store File (see Flysystem documentation, and all its framework integration)
$adapter = new Local(__DIR__.'/path/to/folder'); // Can be any adapter (AWS, Google, Ftp, etc.)
$filesystem = new Filesystem($adapter);
$filesystem->putStream('test.zip', $tempStream)
// Close Stream
fclose($tempStream);
\ No newline at end of file
Usage with nginx
=============
If you are using nginx as a webserver, it will try to buffer the response.
So you'll want to disable this with a custom header:
.. code-block:: php
header('X-Accel-Buffering: no');
# or with the Response class from Symfony
$response->headers->set('X-Accel-Buffering', 'no');
Alternatively, you can tweak the
`fastcgi cache parameters <https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_buffers>`_
within nginx config.
See `original issue <https://github.com/maennchen/ZipStream-PHP/issues/77>`_.
\ No newline at end of file
Available options
===============
Here is the full list of options available to you. You can also have a look at
``src/Option/Archive.php`` file.
First, an instance of ``ZipStream\Option\Archive`` needs to be created, and
after that you use setters methods to modify the values.
.. code-block:: php
use ZipStream\ZipStream;
use ZipStream\Option\Archive as ArchiveOptions;
require_once 'vendor/autoload.php';
$opt = new ArchiveOptions();
// Define output stream (argument is of type resource)
$opt->setOutputStream($fd);
// Set the deflate level (default is 6; use -1 to disable it)
$opt->setDeflateLevel(6);
// Add a comment to the zip file
$opt->setComment('This is a comment.');
// Size, in bytes, of the largest file to try and load into memory (used by addFileFromPath()). Large files may also be compressed differently; see the 'largeFileMethod' option.
$opt->setLargeFileSize(30000000);
// How to handle large files. Legal values are STORE (the default), or DEFLATE. Store sends the file raw and is significantly faster, while DEFLATE compresses the file and is much, much slower. Note that deflate must compress the file twice and is extremely slow.
$opt->setLargeFileMethod(ZipStream\Option\Method::STORE());
$opt->setLargeFileMethod(ZipStream\Option\Method::DEFLATE());
// Send http headers (default is false)
$opt->setSendHttpHeaders(false);
// HTTP Content-Disposition. Defaults to 'attachment', where FILENAME is the specified filename. Note that this does nothing if you are not sending HTTP headers.
$opt->setContentDisposition('attachment');
// Set the content type (does nothing if you are not sending HTTP headers)
$opt->setContentType('application/x-zip');
// Set the function called for setting headers. Default is the `header()` of PHP
$opt->setHttpHeaderCallback('header');
// Enable streaming files with single read where general purpose bit 3 indicates local file header contain zero values in crc and size fields, these appear only after file contents in data descriptor block. Default is false. Set to true if your input stream is remote (used with addFileFromStream()).
$opt->setZeroHeader(false);
// Enable reading file stat for determining file size. When a 32-bit system reads file size that is over 2 GB, invalid value appears in file size due to integer overflow. Should be disabled on 32-bit systems with method addFileFromPath if any file may exceed 2 GB. In this case file will be read in blocks and correct size will be determined from content. Default is true.
$opt->setStatFiles(true);
// Enable zip64 extension, allowing very large archives (> 4Gb or file count > 64k)
// default is true
$opt->setEnableZip64(true);
// Flush output buffer after every write
// default is false
$opt->setFlushOutput(true);
// Now that everything is set you can pass the options to the ZipStream instance
$zip = new ZipStream('example.zip', $opt);
Usage with PSR 7 Streams
===============
PSR-7 streams are `standardized streams <https://www.php-fig.org/psr/psr-7/>`_.
ZipStream-PHP supports working with these streams with the function
``addFileFromPsr7Stream``.
For all parameters of the function see the API documentation.
Example
---------------
.. code-block:: php
$stream = $response->getBody();
// add a file named 'streamfile.txt' from the content of the stream
$zip->addFileFromPsr7Stream('streamfile.txt', $stream);
Stream Output
===============
Stream to S3 Bucket
---------------
.. code-block:: php
use Aws\S3\S3Client;
use Aws\Credentials\CredentialProvider;
use ZipStream\Option\Archive;
use ZipStream\ZipStream;
$bucket = 'your bucket name';
$client = new S3Client([
'region' => 'your region',
'version' => 'latest',
'bucketName' => $bucket,
'credentials' => CredentialProvider::defaultProvider(),
]);
$client->registerStreamWrapper();
$zipFile = fopen("s3://$bucket/example.zip", 'w');
$options = new Archive();
$options->setEnableZip64(false);
$options->setOutputStream($zipFile);
$zip = new ZipStream(null, $options);
$zip->addFile('file1.txt', 'File1 data');
$zip->addFile('file2.txt', 'File2 data');
$zip->finish();
fclose($zipFile);
\ No newline at end of file
Usage with Symfony
===============
Overview for using ZipStream in Symfony
--------
Using ZipStream in Symfony requires use of Symfony's ``StreamedResponse`` when
used in controller actions.
Wrap your call to the relevant ``ZipStream`` stream method (i.e. ``addFile``,
``addFileFromPath``, ``addFileFromStream``) in Symfony's ``StreamedResponse``
function passing in any required arguments for your use case.
Using Symfony's ``StreamedResponse`` will allow Symfony to stream output from
ZipStream correctly to users' browsers and avoid a corrupted final zip landing
on the users' end.
Example for using ``ZipStream`` in a controller action to zip stream files
stored in an AWS S3 bucket by key:
.. code-block:: php
use Symfony\Component\HttpFoundation\StreamedResponse;
use Aws\S3\S3Client;
use ZipStream;
//...
/**
* @Route("/zipstream", name="zipstream")
*/
public function zipStreamAction()
{
//sample test file on s3
$s3keys = array(
"ziptestfolder/file1.txt"
);
$s3Client = $this->get('app.amazon.s3'); //s3client service
$s3Client->registerStreamWrapper(); //required
//using StreamedResponse to wrap ZipStream functionality for files on AWS s3.
$response = new StreamedResponse(function() use($s3keys, $s3Client)
{
// Define suitable options for ZipStream Archive.
$options = new \ZipStream\Option\Archive();
$options->setContentType('application/octet-stream');
// this is needed to prevent issues with truncated zip files
$options->setZeroHeader(true);
$options->setComment('test zip file.');
//initialise zipstream with output zip filename and options.
$zip = new ZipStream\ZipStream('test.zip', $options);
//loop keys - useful for multiple files
foreach ($s3keys as $key) {
// Get the file name in S3 key so we can save it to the zip
//file using the same name.
$fileName = basename($key);
//concatenate s3path.
$bucket = 'bucketname'; //replace with your bucket name or get from parameters file.
$s3path = "s3://" . $bucket . "/" . $key;
//addFileFromStream
if ($streamRead = fopen($s3path, 'r')) {
$zip->addFileFromStream($fileName, $streamRead);
} else {
die('Could not open stream for reading');
}
}
$zip->finish();
});
return $response;
}
In the above example, files on AWS S3 are being streamed from S3 to the Symfon
application via ``fopen`` call when the s3Client has ``registerStreamWrapper``
applied. This stream is then passed to ``ZipStream`` via the
``addFileFromStream`` function, which ZipStream then streams as a zip to the
client browser via Symfony's ``StreamedResponse``. No Zip is created server
side, which makes this approach a more efficient solution for streaming zips to
the client browser especially for larger files.
For the above use case you will need to have installed
`aws/aws-sdk-php-symfony <https://github.com/aws/aws-sdk-php-symfony>`_ to
support accessing S3 objects in your Symfony web application. This is not
required for locally stored files on you server you intend to stream via
``ZipStream``.
See official Symfony documentation for details on
`Symfony's StreamedResponse <https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response>`_
``Symfony\Component\HttpFoundation\StreamedResponse``.
Note from `S3 documentation <https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-stream-wrapper.html>`_:
Streams opened in "r" mode only allow data to be read from the stream, and
are not seekable by default. This is so that data can be downloaded from
Amazon S3 in a truly streaming manner, where previously read bytes do not
need to be buffered into memory. If you need a stream to be seekable, you
can pass seekable into the stream context options of a function.
Make sure to configure your S3 context correctly!
Uploading a file
--------
You need to add correct permissions
(see `#120 <https://github.com/maennchen/ZipStream-PHP/issues/120>`_)
**example code**
.. code-block:: php
$path = "s3://{$adapter->getBucket()}/{$this->getArchivePath()}";
// the important bit
$outputContext = stream_context_create([
's3' => ['ACL' => 'public-read'],
]);
fopen($path, 'w', null, $outputContext);
\ No newline at end of file
Usage with Varnish
=============
Serving a big zip with varnish in between can cause random stream close.
This can be solved by adding attached code to the vcl file.
To avoid the problem, add the following to your varnish config file:
.. code-block::
sub vcl_recv {
# Varnish can’t intercept the discussion anymore
# helps for streaming big zips
if (req.url ~ "\.(tar|gz|zip|7z|exe)$") {
return (pipe);
}
}
# Varnish can’t intercept the discussion anymore
# helps for streaming big zips
sub vcl_pipe {
set bereq.http.connection = "close";
return (pipe);
}
ZipStream PHP
=============
A fast and simple streaming zip file downloader for PHP. Using this library will
save you from having to write the Zip to disk. You can directly send it to the
user, which is much faster. It can work with S3 buckets or any PSR7 Stream.
.. toctree::
index
Symfony
Options
StreamOutput
FlySystem
PSR7Streams
Nginx
Varnish
ContentLength
Installation
---------------
Simply add a dependency on ``maennchen/zipstream-php`` to your project's
``composer.json`` file if you use Composer to manage the dependencies of your
project. Use following command to add the package to your project's dependencies:
.. code-block:: sh
composer require maennchen/zipstream-php
Usage Intro
---------------
Here's a simple example:
.. code-block:: php
// Autoload the dependencies
require 'vendor/autoload.php';
// enable output of HTTP headers
$options = new ZipStream\Option\Archive();
$options->setSendHttpHeaders(true);
// create a new zipstream object
$zip = new ZipStream\ZipStream('example.zip', $options);
// create a file named 'hello.txt'
$zip->addFile('hello.txt', 'This is the contents of hello.txt');
// add a file named 'some_image.jpg' from a local file 'path/to/image.jpg'
$zip->addFileFromPath('some_image.jpg', 'path/to/image.jpg');
// add a file named 'goodbye.txt' from an open stream resource
$fp = tmpfile();
fwrite($fp, 'The quick brown fox jumped over the lazy dog.');
rewind($fp);
$zip->addFileFromStream('goodbye.txt', $fp);
fclose($fp);
// finish the zip stream
$zip->finish();
You can also add comments, modify file timestamps, and customize (or
disable) the HTTP headers. It is also possible to specify the storage method
when adding files, the current default storage method is ``DEFLATE``
i.e files are stored with Compression mode 0x08.
Known Issues
---------------
The native Mac OS archive extraction tool prior to macOS 10.15 might not open
archives in some conditions. A workaround is to disable the Zip64 feature with
the option ``enableZip64: false``. This limits the archive to 4 Gb and 64k files
but will allow users on macOS 10.14 and below to open them without issue.
See `#116 <https://github.com/maennchen/ZipStream-PHP/issues/146>`_.
The linux ``unzip`` utility might not handle properly unicode characters.
It is recommended to extract with another tool like
`7-zip <https://www.7-zip.org/>`_.
See `#146 <https://github.com/maennchen/ZipStream-PHP/issues/146>`_.
It is the responsability of the client code to make sure that files are not
saved with the same path, as it is not possible for the library to figure it out
while streaming a zip.
See `#154 <https://github.com/maennchen/ZipStream-PHP/issues/154>`_.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<phpdocumentor
configVersion="3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://www.phpdoc.org"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd"
>
<title>ZipStream-PHP</title>
<paths>
<output>docs</output>
</paths>
<version number="3.0.0">
<folder>latest</folder>
<api>
<source dsn=".">
<path>src</path>
</source>
<output>api</output>
<ignore hidden="true" symlinks="true">
<path>tests/**/*</path>
<path>vendor/**/*</path>
</ignore>
<extensions>
<extension>php</extension>
</extensions>
<visibility>public</visibility>
<default-package-name>ZipStream</default-package-name>
<include-source>true</include-source>
</api>
<guide>
<source dsn=".">
<path>guides</path>
</source>
<output>guide</output>
</guide>
</version>
<setting name="guides.enabled" value="true"/>
<template name="default" />
</phpdocumentor>
\ No newline at end of file
<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="test/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Application">
<directory>test</directory>
</testsuite>
</testsuites>
<logging/>
<phpunit bootstrap="test/bootstrap.php">
<testsuites>
<testsuite name="Application">
<directory>test</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-clover" target="clover.xml"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
... ...
<?xml version="1.0"?>
<psalm
totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
... ... @@ -33,6 +34,7 @@
<MissingReturnType errorLevel="info" />
<MissingPropertyType errorLevel="info" />
<InvalidDocblock errorLevel="info" />
<MisplacedRequiredParam errorLevel="info" />
<PropertyNotSetInConstructor errorLevel="info" />
<MissingConstructor errorLevel="info" />
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
... ... @@ -24,6 +23,22 @@ class Bigint
}
/**
* Fill the bytes field with int
*
* @param int $value
* @param int $start
* @param int $count
* @return void
*/
protected function fillBytes(int $value, int $start, int $count): void
{
for ($i = 0; $i < $count; $i++) {
$this->bytes[$start + $i] = $i >= PHP_INT_SIZE ? 0 : $value & 0xFF;
$value >>= 8;
}
}
/**
* Get an instance
*
* @param int $value
... ... @@ -43,7 +58,7 @@ class Bigint
*/
public static function fromLowHigh(int $low, int $high): self
{
$bigint = new self();
$bigint = new Bigint();
$bigint->fillBytes($low, 0, 4);
$bigint->fillBytes($high, 4, 4);
return $bigint;
... ... @@ -93,7 +108,6 @@ class Bigint
/**
* Check if is over 32
*
* @psalm-suppress ArgumentTypeCoercion
* @param bool $force
* @return bool
*/
... ... @@ -135,7 +149,7 @@ class Bigint
* @param Bigint $other
* @return Bigint
*/
public function add(self $other): self
public function add(Bigint $other): Bigint
{
$result = clone $this;
$overflow = false;
... ... @@ -151,24 +165,8 @@ class Bigint
}
}
if ($overflow) {
throw new OverflowException();
throw new OverflowException;
}
return $result;
}
/**
* Fill the bytes field with int
*
* @param int $value
* @param int $start
* @param int $count
* @return void
*/
protected function fillBytes(int $value, int $start, int $count): void
{
for ($i = 0; $i < $count; $i++) {
$this->bytes[$start + $i] = $i >= PHP_INT_SIZE ? 0 : $value & 0xFF;
$value >>= 8;
}
}
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
... ... @@ -59,7 +58,7 @@ class DeflateStream extends Stream
'comment' => $options->getComment(),
'method' => $options->getMethod(),
'deflateLevel' => $options->getDeflateLevel(),
'time' => $options->getTime(),
'time' => $options->getTime()
];
$this->filter = stream_filter_append(
$this->stream,
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Exception;
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
use HashContext;
use Psr\Http\Message\StreamInterface;
use ZipStream\Exception\EncodingException;
use ZipStream\Exception\FileNotFoundException;
use ZipStream\Exception\FileNotReadableException;
use ZipStream\Exception\OverflowException;
... ... @@ -15,15 +14,13 @@ use ZipStream\Option\Version;
class File
{
public const HASH_ALGORITHM = 'crc32b';
public const BIT_ZERO_HEADER = 0x0008;
public const BIT_EFS_UTF8 = 0x0800;
const HASH_ALGORITHM = 'crc32b';
public const COMPUTE = 1;
const BIT_ZERO_HEADER = 0x0008;
const BIT_EFS_UTF8 = 0x0800;
public const SEND = 2;
const COMPUTE = 1;
const SEND = 2;
private const CHUNKED_READ_BLOCK_SIZE = 1048576;
... ... @@ -41,7 +38,6 @@ class File
* @var Bigint
*/
public $len;
/**
* @var Bigint
*/
... ... @@ -79,9 +75,8 @@ class File
* @var resource
*/
private $deflate;
/**
* @var HashContext
* @var resource
*/
private $hash;
... ... @@ -165,17 +160,21 @@ class File
// Sets Bit 11: Language encoding flag (EFS). If this bit is set,
// the filename and comment fields for this file
// MUST be encoded using UTF-8. (see APPENDIX D)
if (mb_check_encoding($name, 'UTF-8') &&
mb_check_encoding($comment, 'UTF-8')) {
$this->bits |= self::BIT_EFS_UTF8;
if (!mb_check_encoding($name, 'UTF-8') ||
!mb_check_encoding($comment, 'UTF-8')) {
throw new EncodingException(
'File name and comment should use UTF-8 ' .
'if one of them does not fit into ASCII range.'
);
}
$this->bits |= self::BIT_EFS_UTF8;
}
if ($this->method->equals(Method::DEFLATE())) {
$this->version = Version::DEFLATE();
}
$force = (bool)($this->bits & self::BIT_ZERO_HEADER) &&
$force = (boolean)($this->bits & self::BIT_ZERO_HEADER) &&
$this->zip->opt->isEnableZip64();
$footer = $this->buildZip64ExtraBlock($force);
... ... @@ -228,97 +227,6 @@ class File
}
/**
* Create and send data descriptor footer for this file.
*
* @return void
*/
public function addFileFooter(): void
{
if ($this->bits & self::BIT_ZERO_HEADER) {
// compressed and uncompressed size
$sizeFormat = 'V';
if ($this->zip->opt->isEnableZip64()) {
$sizeFormat = 'P';
}
$fields = [
['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE],
['V', $this->crc], // CRC32
[$sizeFormat, $this->zlen], // Length of compressed data
[$sizeFormat, $this->len], // Length of original data
];
$footer = ZipStream::packFields($fields);
$this->zip->send($footer);
} else {
$footer = '';
}
$this->totalLength = $this->hlen->add($this->zlen)->add(Bigint::init(strlen($footer)));
$this->zip->addToCdr($this);
}
public function processStream(StreamInterface $stream): void
{
$this->zlen = new Bigint();
$this->len = new Bigint();
if ($this->zip->opt->isZeroHeader()) {
$this->processStreamWithZeroHeader($stream);
} else {
$this->processStreamWithComputedHeader($stream);
}
}
/**
* Send CDR record for specified file.
*
* @return string
*/
public function getCdrFile(): string
{
$name = static::filterFilename($this->name);
// get attributes
$comment = $this->opt->getComment();
// get dos timestamp
$time = static::dosTime($this->opt->getTime()->getTimestamp());
$footer = $this->buildZip64ExtraBlock();
$fields = [
['V', ZipStream::CDR_FILE_SIGNATURE], // Central file header signature
['v', ZipStream::ZIP_VERSION_MADE_BY], // Made by version
['v', $this->version->getValue()], // Extract by version
['v', $this->bits], // General purpose bit flags - data descriptor flag set
['v', $this->method->getValue()], // Compression method
['V', $time], // Timestamp (DOS Format)
['V', $this->crc], // CRC32
['V', $this->zlen->getLowFF()], // Compressed Data Length
['V', $this->len->getLowFF()], // Original Data Length
['v', strlen($name)], // Length of filename
['v', strlen($footer)], // Extra data len (see above)
['v', strlen($comment)], // Length of comment
['v', 0], // Disk number
['v', 0], // Internal File Attributes
['V', 32], // External File Attributes
['V', $this->ofs->getLowFF()], // Relative offset of local header
];
// pack fields, then append name and comment
$header = ZipStream::packFields($fields);
return $header . $name . $footer . $comment;
}
/**
* @return Bigint
*/
public function getTotalLength(): Bigint
{
return $this->totalLength;
}
/**
* Convert a UNIX timestamp to a DOS timestamp.
*
* @param int $when
... ... @@ -331,14 +239,14 @@ class File
// set lower-bound on dates
if ($d['year'] < 1980) {
$d = [
$d = array(
'year' => 1980,
'mon' => 1,
'mday' => 1,
'hours' => 0,
'minutes' => 0,
'seconds' => 0,
];
'seconds' => 0
);
}
// remove extra years from 1980
... ... @@ -356,6 +264,7 @@ class File
protected function buildZip64ExtraBlock(bool $force = false): string
{
$fields = [];
if ($this->len->isOver32($force)) {
$fields[] = ['P', $this->len]; // Length of original data
... ... @@ -382,14 +291,50 @@ class File
$this->version = Version::ZIP64();
}
if ($this->bits & self::BIT_EFS_UTF8) {
// Put the tricky entry to
// force Linux unzip to lookup EFS flag.
$fields[] = ['v', 0x5653]; // Choose 'ZS' for proprietary usage
$fields[] = ['v', 0x0000]; // zero length
return ZipStream::packFields($fields);
}
/**
* Create and send data descriptor footer for this file.
*
* @return void
*/
public function addFileFooter(): void
{
if ($this->bits & self::BIT_ZERO_HEADER) {
// compressed and uncompressed size
$sizeFormat = 'V';
if ($this->zip->opt->isEnableZip64()) {
$sizeFormat = 'P';
}
$fields = [
['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE],
['V', $this->crc], // CRC32
[$sizeFormat, $this->zlen], // Length of compressed data
[$sizeFormat, $this->len], // Length of original data
];
$footer = ZipStream::packFields($fields);
$this->zip->send($footer);
} else {
$footer = '';
}
$this->totalLength = $this->hlen->add($this->zlen)->add(Bigint::init(strlen($footer)));
$this->zip->addToCdr($this);
}
return ZipStream::packFields($fields);
public function processStream(StreamInterface $stream): void
{
$this->zlen = new Bigint();
$this->len = new Bigint();
if ($this->zip->opt->isZeroHeader()) {
$this->processStreamWithZeroHeader($stream);
} else {
$this->processStreamWithComputedHeader($stream);
}
}
protected function processStreamWithZeroHeader(StreamInterface $stream): void
... ... @@ -409,7 +354,7 @@ class File
$data = $stream->read(self::CHUNKED_READ_BLOCK_SIZE);
$total += strlen($data);
if ($size > 0 && $total > $size) {
$data = substr($data, 0, strlen($data)-($total - $size));
$data = substr($data, 0 , strlen($data)-($total - $size));
}
$this->deflateData($stream, $data, $options);
if ($options & self::SEND) {
... ... @@ -421,8 +366,7 @@ class File
protected function deflateInit(): void
{
$hash = hash_init(self::HASH_ALGORITHM);
$this->hash = $hash;
$this->hash = hash_init(self::HASH_ALGORITHM);
if ($this->method->equals(Method::DEFLATE())) {
$this->deflate = deflate_init(
ZLIB_ENCODING_RAW,
... ... @@ -480,4 +424,54 @@ class File
$this->readStream($stream, self::SEND);
$this->addFileFooter();
}
/**
* Send CDR record for specified file.
*
* @return string
*/
public function getCdrFile(): string
{
$name = static::filterFilename($this->name);
// get attributes
$comment = $this->opt->getComment();
// get dos timestamp
$time = static::dosTime($this->opt->getTime()->getTimestamp());
$footer = $this->buildZip64ExtraBlock();
$fields = [
['V', ZipStream::CDR_FILE_SIGNATURE], // Central file header signature
['v', ZipStream::ZIP_VERSION_MADE_BY], // Made by version
['v', $this->version->getValue()], // Extract by version
['v', $this->bits], // General purpose bit flags - data descriptor flag set
['v', $this->method->getValue()], // Compression method
['V', $time], // Timestamp (DOS Format)
['V', $this->crc], // CRC32
['V', $this->zlen->getLowFF()], // Compressed Data Length
['V', $this->len->getLowFF()], // Original Data Length
['v', strlen($name)], // Length of filename
['v', strlen($footer)], // Extra data len (see above)
['v', strlen($comment)], // Length of comment
['v', 0], // Disk number
['v', 0], // Internal File Attributes
['V', 32], // External File Attributes
['V', $this->ofs->getLowFF()] // Relative offset of local header
];
// pack fields, then append name and comment
$header = ZipStream::packFields($fields);
return $header . $name . $footer . $comment;
}
/**
* @return Bigint
*/
public function getTotalLength(): Bigint
{
return $this->totalLength;
}
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Option;
use Psr\Http\Message\StreamInterface;
final class Archive
{
public const DEFAULT_DEFLATE_LEVEL = 6;
const DEFAULT_DEFLATE_LEVEL = 6;
/**
* @var string
*/
private $comment = '';
/**
* Size, in bytes, of the largest file to try
* and load into memory (used by
... ... @@ -25,7 +20,6 @@ final class Archive
* @var int
*/
private $largeFileSize = 20 * 1024 * 1024;
/**
* How to handle large files. Legal values are
* Method::STORE() (the default), or
... ... @@ -38,7 +32,6 @@ final class Archive
* @var Method
*/
private $largeFileMethod;
/**
* Boolean indicating whether or not to send
* the HTTP headers for this file.
... ... @@ -46,14 +39,12 @@ final class Archive
* @var bool
*/
private $sendHttpHeaders = false;
/**
* The method called to send headers
*
* @var Callable
*/
private $httpHeaderCallback = 'header';
/**
* Enable Zip64 extension, supporting very large
* archives (any size > 4 GB or file count > 64k)
... ... @@ -61,7 +52,6 @@ final class Archive
* @var bool
*/
private $enableZip64 = true;
/**
* Enable streaming files with single read where
* general purpose bit 3 indicates local file header
... ... @@ -72,7 +62,6 @@ final class Archive
* @var bool
*/
private $zeroHeader = false;
/**
* Enable reading file stat for determining file size.
* When a 32-bit system reads file size that is
... ... @@ -86,13 +75,11 @@ final class Archive
* @var bool
*/
private $statFiles = true;
/**
* Enable flush after every write to output stream.
* @var bool
*/
private $flushOutput = false;
/**
* HTTP Content-Disposition. Defaults to
* 'attachment', where
... ... @@ -104,7 +91,6 @@ final class Archive
* @var string
*/
private $contentDisposition = 'attachment';
/**
* Note that this does nothing if you are
* not sending HTTP headers.
... ... @@ -112,14 +98,13 @@ final class Archive
* @var string
*/
private $contentType = 'application/x-zip';
/**
* @var int
*/
private $deflateLevel = 6;
/**
* @var StreamInterface|resource
* @var resource
*/
private $outputStream;
... ... @@ -172,12 +157,12 @@ final class Archive
$this->sendHttpHeaders = $sendHttpHeaders;
}
public function getHttpHeaderCallback(): callable
public function getHttpHeaderCallback(): Callable
{
return $this->httpHeaderCallback;
}
public function setHttpHeaderCallback(callable $httpHeaderCallback): void
public function setHttpHeaderCallback(Callable $httpHeaderCallback): void
{
$this->httpHeaderCallback = $httpHeaderCallback;
}
... ... @@ -243,7 +228,7 @@ final class Archive
}
/**
* @return StreamInterface|resource
* @return resource
*/
public function getOutputStream()
{
... ... @@ -251,7 +236,7 @@ final class Archive
}
/**
* @param StreamInterface|resource $outputStream
* @param resource $outputStream
*/
public function setOutputStream($outputStream): void
{
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Option;
use DateTime;
use DateTimeInterface;
final class File
{
... ... @@ -13,22 +11,18 @@ final class File
* @var string
*/
private $comment = '';
/**
* @var Method
*/
private $method;
/**
* @var int
*/
private $deflateLevel;
/**
* @var DateTimeInterface
* @var DateTime
*/
private $time;
/**
* @var int
*/
... ... @@ -89,17 +83,17 @@ final class File
}
/**
* @return DateTimeInterface
* @return DateTime
*/
public function getTime(): DateTimeInterface
public function getTime(): DateTime
{
return $this->time;
}
/**
* @param DateTimeInterface $time
* @param DateTime $time
*/
public function setTime(DateTimeInterface $time): void
public function setTime(DateTime $time): void
{
$this->time = $time;
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Option;
... ... @@ -15,7 +14,6 @@ use MyCLabs\Enum\Enum;
*/
class Method extends Enum
{
public const STORE = 0x00;
public const DEFLATE = 0x08;
const STORE = 0x00;
const DEFLATE = 0x08;
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream\Option;
... ... @@ -17,9 +16,7 @@ use MyCLabs\Enum\Enum;
*/
class Version extends Enum
{
public const STORE = 0x000A; // 1.00
public const DEFLATE = 0x0014; // 2.00
public const ZIP64 = 0x002D; // 4.50
const STORE = 0x000A; // 1.00
const DEFLATE = 0x0014; // 2.00
const ZIP64 = 0x002D; // 4.50
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
use function mb_strlen;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
... ... @@ -26,29 +23,6 @@ class Stream implements StreamInterface
}
/**
* Reads all data from the stream into a string, from the beginning to end.
*
* This method MUST attempt to seek to the beginning of the stream before
* reading data and read the stream until the end is reached.
*
* Warning: This could attempt to load a large amount of data into memory.
*
* This method MUST NOT raise an exception in order to conform with PHP's
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string
*/
public function __toString(): string
{
try {
$this->seek(0);
} catch (RuntimeException $e) {
}
return (string) stream_get_contents($this->stream);
}
/**
* Closes the stream and any underlying resources.
*
* @return void
... ... @@ -76,6 +50,28 @@ class Stream implements StreamInterface
}
/**
* Reads all data from the stream into a string, from the beginning to end.
*
* This method MUST attempt to seek to the beginning of the stream before
* reading data and read the stream until the end is reached.
*
* Warning: This could attempt to load a large amount of data into memory.
*
* This method MUST NOT raise an exception in order to conform with PHP's
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string
*/
public function __toString(): string
{
try {
$this->seek(0);
} catch (\RuntimeException $e) {}
return (string) stream_get_contents($this->stream);
}
/**
* Seek to a position in the stream.
*
* @link http://www.php.net/manual/en/function.fseek.php
... ... @@ -85,15 +81,15 @@ class Stream implements StreamInterface
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
* offset bytes SEEK_CUR: Set position to current location plus offset
* SEEK_END: Set position to end-of-stream plus offset.
* @throws RuntimeException on failure.
* @throws \RuntimeException on failure.
*/
public function seek($offset, $whence = SEEK_SET): void
{
if (!$this->isSeekable()) {
throw new RuntimeException();
throw new RuntimeException;
}
if (fseek($this->stream, $offset, $whence) !== 0) {
throw new RuntimeException();
throw new RuntimeException;
}
}
... ... @@ -140,13 +136,13 @@ class Stream implements StreamInterface
* Returns the current position of the file read/write pointer
*
* @return int Position of the file pointer
* @throws RuntimeException on error.
* @throws \RuntimeException on error.
*/
public function tell(): int
{
$position = ftell($this->stream);
if ($position === false) {
throw new RuntimeException();
throw new RuntimeException;
}
return $position;
}
... ... @@ -169,7 +165,7 @@ class Stream implements StreamInterface
*
* @see seek()
* @link http://www.php.net/manual/en/function.fseek.php
* @throws RuntimeException on failure.
* @throws \RuntimeException on failure.
*/
public function rewind(): void
{
... ... @@ -181,17 +177,17 @@ class Stream implements StreamInterface
*
* @param string $string The string that is to be written.
* @return int Returns the number of bytes written to the stream.
* @throws RuntimeException on failure.
* @throws \RuntimeException on failure.
*/
public function write($string): int
{
if (!$this->isWritable()) {
throw new RuntimeException();
throw new RuntimeException;
}
if (fwrite($this->stream, $string) === false) {
throw new RuntimeException();
throw new RuntimeException;
}
return mb_strlen($string);
return \mb_strlen($string);
}
/**
... ... @@ -201,11 +197,7 @@ class Stream implements StreamInterface
*/
public function isWritable(): bool
{
$mode = $this->getMetadata('mode');
if (!is_string($mode)) {
throw new RuntimeException('Could not get stream mode from metadata!');
}
return preg_match('/[waxc+]/', $mode) === 1;
return preg_match('/[waxc+]/', $this->getMetadata('mode')) === 1;
}
/**
... ... @@ -216,16 +208,16 @@ class Stream implements StreamInterface
* call returns fewer bytes.
* @return string Returns the data read from the stream, or an empty string
* if no bytes are available.
* @throws RuntimeException if an error occurs.
* @throws \RuntimeException if an error occurs.
*/
public function read($length): string
{
if (!$this->isReadable()) {
throw new RuntimeException();
throw new RuntimeException;
}
$result = fread($this->stream, $length);
if ($result === false) {
throw new RuntimeException();
throw new RuntimeException;
}
return $result;
}
... ... @@ -237,28 +229,24 @@ class Stream implements StreamInterface
*/
public function isReadable(): bool
{
$mode = $this->getMetadata('mode');
if (!is_string($mode)) {
throw new RuntimeException('Could not get stream mode from metadata!');
}
return preg_match('/[r+]/', $mode) === 1;
return preg_match('/[r+]/', $this->getMetadata('mode')) === 1;
}
/**
* Returns the remaining contents in a string
*
* @return string
* @throws RuntimeException if unable to read or an error occurs while
* @throws \RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents(): string
{
if (!$this->isReadable()) {
throw new RuntimeException();
throw new RuntimeException;
}
$result = stream_get_contents($this->stream);
if ($result === false) {
throw new RuntimeException();
throw new RuntimeException;
}
return $result;
}
... ...
<?php
declare(strict_types=1);
namespace ZipStream;
... ... @@ -81,24 +80,19 @@ class ZipStream
* to prevent file permissions issues upon extract (see #84)
* 0x603 is 00000110 00000011 in binary, so 6 and 3
*/
public const ZIP_VERSION_MADE_BY = 0x603;
const ZIP_VERSION_MADE_BY = 0x603;
/**
* The following signatures end with 0x4b50, which in ASCII is PK,
* The following signatures end with 0x4b50, which in ASCII is PK,
* the initials of the inventor Phil Katz.
* See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
*/
public const FILE_HEADER_SIGNATURE = 0x04034b50;
public const CDR_FILE_SIGNATURE = 0x02014b50;
public const CDR_EOF_SIGNATURE = 0x06054b50;
public const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
public const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
public const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
const FILE_HEADER_SIGNATURE = 0x04034b50;
const CDR_FILE_SIGNATURE = 0x02014b50;
const CDR_EOF_SIGNATURE = 0x06054b50;
const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50;
const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50;
/**
* Global Options
... ... @@ -318,9 +312,12 @@ class ZipStream
*
* Examples:
*
* $stream = $response->getBody();
* // create a temporary file stream and write text to it
* $fp = tmpfile();
* fwrite($fp, 'The quick brown fox jumped over the lazy dog.');
*
* // add a file named 'streamfile.txt' from the content of the stream
* $x->addFileFromPsr7Stream('streamfile.txt', $stream);
* $x->addFileFromPsr7Stream('streamfile.txt', $fp);
*
* @return void
*/
... ... @@ -382,6 +379,34 @@ class ZipStream
}
/**
* Send ZIP64 CDR EOF (Central Directory Record End-of-File) record.
*
* @return void
*/
protected function addCdr64Eof(): void
{
$num_files = count($this->files);
$cdr_length = $this->cdr_ofs;
$cdr_offset = $this->ofs;
$fields = [
['V', static::ZIP64_CDR_EOF_SIGNATURE], // ZIP64 end of central file header signature
['P', 44], // Length of data below this header (length of block - 12) = 44
['v', static::ZIP_VERSION_MADE_BY], // Made by version
['v', Version::ZIP64], // Extract by version
['V', 0x00], // disk number
['V', 0x00], // no of disks
['P', $num_files], // no of entries on disk
['P', $num_files], // no of entries in cdr
['P', $cdr_length], // CDR size
['P', $cdr_offset], // CDR offset
];
$ret = static::packFields($fields);
$this->send($ret);
}
/**
* Create a format string and argument list for pack(), then call
* pack() and return the result.
*
... ... @@ -434,13 +459,7 @@ class ZipStream
}
$this->need_headers = false;
$outputStream = $this->opt->getOutputStream();
if ($outputStream instanceof StreamInterface) {
$outputStream->write($str);
} else {
fwrite($outputStream, $str);
}
fwrite($this->opt->getOutputStream(), $str);
if ($this->opt->isFlushOutput()) {
// flush output buffer if it is on and flushable
... ... @@ -455,62 +474,6 @@ class ZipStream
}
/**
* Is this file larger than large_file_size?
*
* @param string $path
* @return bool
*/
public function isLargeFile(string $path): bool
{
if (!$this->opt->isStatFiles()) {
return false;
}
$stat = stat($path);
return $stat['size'] > $this->opt->getLargeFileSize();
}
/**
* Save file attributes for trailing CDR record.
*
* @param File $file
* @return void
*/
public function addToCdr(File $file): void
{
$file->ofs = $this->ofs;
$this->ofs = $this->ofs->add($file->getTotalLength());
$this->files[] = $file->getCdrFile();
}
/**
* Send ZIP64 CDR EOF (Central Directory Record End-of-File) record.
*
* @return void
*/
protected function addCdr64Eof(): void
{
$num_files = count($this->files);
$cdr_length = $this->cdr_ofs;
$cdr_offset = $this->ofs;
$fields = [
['V', static::ZIP64_CDR_EOF_SIGNATURE], // ZIP64 end of central file header signature
['P', 44], // Length of data below this header (length of block - 12) = 44
['v', static::ZIP_VERSION_MADE_BY], // Made by version
['v', Version::ZIP64], // Extract by version
['V', 0x00], // disk number
['V', 0x00], // no of disks
['P', $num_files], // no of entries on disk
['P', $num_files], // no of entries in cdr
['P', $cdr_length], // CDR size
['P', $cdr_offset], // CDR offset
];
$ret = static::packFields($fields);
$this->send($ret);
}
/**
* Send HTTP headers for this stream.
*
* @return void
... ... @@ -529,13 +492,13 @@ class ZipStream
$disposition .= "; filename*=UTF-8''{$urlencoded}";
}
$headers = [
$headers = array(
'Content-Type' => $this->opt->getContentType(),
'Content-Disposition' => $disposition,
'Pragma' => 'public',
'Cache-Control' => 'public, must-revalidate',
'Content-Transfer-Encoding' => 'binary',
];
'Content-Transfer-Encoding' => 'binary'
);
$call = $this->opt->getHttpHeaderCallback();
foreach ($headers as $key => $val) {
... ... @@ -605,4 +568,32 @@ class ZipStream
$this->cdr_ofs = new Bigint();
$this->opt = new ArchiveOptions();
}
/**
* Is this file larger than large_file_size?
*
* @param string $path
* @return bool
*/
public function isLargeFile(string $path): bool
{
if (!$this->opt->isStatFiles()) {
return false;
}
$stat = stat($path);
return $stat['size'] > $this->opt->getLargeFileSize();
}
/**
* Save file attributes for trailing CDR record.
*
* @param File $file
* @return void
*/
public function addToCdr(File $file): void
{
$file->ofs = $this->ofs;
$this->ofs = $this->ofs->add($file->getTotalLength());
$this->files[] = $file->getCdrFile();
}
}
... ...
<?php
declare(strict_types=1);
namespace BigintTest;
... ...