更新vendor

修正生成sitemap
This commit is contained in:
yumo 2023-05-05 11:10:57 +08:00
parent c7deee9ae9
commit ccec51ad88
201 changed files with 2782 additions and 1156 deletions

View File

@ -116,6 +116,8 @@ abstract class BaseController
$url = $_SERVER["HTTP_REFERER"]; $url = $_SERVER["HTTP_REFERER"];
} elseif ($url) { } elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url); $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url);
}else{
$url = app('route')->buildUrl("/");
} }
$result = [ $result = [
@ -152,7 +154,6 @@ abstract class BaseController
} elseif ($url) { } elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url); $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
} }
$result = [ $result = [
'code' => 0, 'code' => 0,
'msg' => $msg, 'msg' => $msg,
@ -160,7 +161,6 @@ abstract class BaseController
'url' => $url, 'url' => $url,
'wait' => $wait, 'wait' => $wait,
]; ];
$type = $this->getResponseType(); $type = $this->getResponseType();
if ($type == 'html') { if ($type == 'html') {
$response = view(config('app.dispatch_success_tmpl'), $result); $response = view(config('app.dispatch_success_tmpl'), $result);

View File

@ -15,6 +15,7 @@ use Exception;
use think\db\exception\DataNotFoundException; use think\db\exception\DataNotFoundException;
use think\db\exception\DbException; use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException; use think\db\exception\ModelNotFoundException;
use think\facade\Request;
class Index extends AuthController class Index extends AuthController
{ {
@ -82,11 +83,9 @@ class Index extends AuthController
*/ */
public function sitemap() public function sitemap()
{ {
//获取协议
$protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ?
"https://" : "http://";
//获取域名 //获取域名
$domain = $protocol . $_SERVER['HTTP_HOST']; $domain = Request::domain();
//获取页码 //获取页码
$page = input('page/d'); $page = input('page/d');
if (!$page) { if (!$page) {
@ -114,10 +113,9 @@ class Index extends AuthController
->where('status', 1)->where('status', 1) ->where('status', 1)->where('status', 1)
->page($page, $pagesize) ->page($page, $pagesize)
->order('id desc')->select(); ->order('id desc')->select();
foreach ($categoryInfo as $v) { foreach ($categoryInfo as $v) {
$str .= '<url>'; $str .= '<url>';
$str .= '<loc>' . $domain . url('article/lists?id=' . $v['id']) . '</loc>'; $str .= '<loc>' . url('index/article/lists',["id"=>$v['id']],".html",$domain) . '</loc>';
$str .= '<lastmod>' . $v['create_time'] . '</lastmod>'; $str .= '<lastmod>' . $v['create_time'] . '</lastmod>';
$str .= '<changefreq>always</changefreq>'; $str .= '<changefreq>always</changefreq>';
$str .= '<priority>0.8</priority>'; $str .= '<priority>0.8</priority>';
@ -132,7 +130,7 @@ class Index extends AuthController
foreach ($documentInfo as $v) { foreach ($documentInfo as $v) {
$str .= '<url>'; $str .= '<url>';
$str .= '<loc>' . $domain . url('article/detail?id=' . $v['id']) . $v['id'] . '</loc>'; $str .= '<loc>' . url('/index/article/detail',["id"=>$v['id']],".html",$domain) . '</loc>';
$str .= '<lastmod>' . $v['create_time'] . '</lastmod>'; $str .= '<lastmod>' . $v['create_time'] . '</lastmod>';
$str .= '<changefreq>monthly</changefreq>'; $str .= '<changefreq>monthly</changefreq>';
$str .= '<priority>0.6</priority>'; $str .= '<priority>0.6</priority>';
@ -140,17 +138,13 @@ class Index extends AuthController
} }
if (count($categoryInfo) < $pagesize && count($documentInfo) < $pagesize) { if (count($categoryInfo) < $pagesize && count($documentInfo) < $pagesize) {
$str .= '</urlset>'; $str .= '</urlset>';
if (!(file_put_contents('sitemap.xml', $str, FILE_APPEND | LOCK_EX))) { return (!(file_put_contents('sitemap.xml', $str, FILE_APPEND | LOCK_EX))) ?
$this->error('站点地图更新失败!',"/admin/"); $this->failedNotice("站点地图更新失败!", "/admin/") :
} else { $this->successfulNotice("站点地图全部更新完成!", "/admin/");
$this->success('站点地图全部更新完成!', "/admin/");
}
} }
//写入 //写入
if (!(file_put_contents('sitemap.xml', $str, FILE_APPEND | LOCK_EX))) { return (!(file_put_contents('sitemap.xml', $str, FILE_APPEND | LOCK_EX))) ?
$this->error('站点地图更新失败!'); $this->failedNotice("站点地图更新失败!", "/admin/") :
} else { $this->successfulNotice('站点地图正在生成,请稍后(' . $page . '...', 'sitemap?page=' . ($page + 1));
$this->success('站点地图正在生成,请稍后(' . $page . '...', 'sitemap?page=' . ($page + 1));
}
} }
} }

View File

@ -38,9 +38,10 @@
<aside class="lyear-layout-sidebar"> <aside class="lyear-layout-sidebar">
<!-- logo --> <!-- logo -->
<div id="logo" class="sidebar-header"> <div id="logo" class="sidebar-header">
<a href="/admin/index/index.html"><img src="/static/admin/img/logo-sidebar.png" <a href="/admin/index/index.html">
title="{:system_config('title')}后台管理系统" <img src="/static/admin/img/logo-sidebar.png" title="{:system_config('title')}后台管理系统"
alt="{:system_config('title')}后台管理系统"/></a> alt="{:system_config('title')}后台管理系统"/>
</a>
</div> </div>
<div class="lyear-layout-sidebar-scroll"> <div class="lyear-layout-sidebar-scroll">
<nav class="sidebar-main"> <nav class="sidebar-main">

View File

@ -69,6 +69,22 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header"><h4>常用功能</h4></div>
<div class="card-body">
<div class="row">
<div class="example-box">
<div class="col-sm-3 col-md-2">
<a class="btn btn-primary btn-w-md" href="{:url('index/sitemap')}" type="button">网站地图</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="card"> <div class="card">

17
vendor/autoload.php vendored
View File

@ -3,8 +3,21 @@
// autoload.php @generated by Composer // autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) { if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; if (!headers_sent()) {
exit(1); header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
} }
require_once __DIR__ . '/composer/autoload_real.php'; require_once __DIR__ . '/composer/autoload_real.php';

View File

@ -42,6 +42,9 @@ namespace Composer\Autoload;
*/ */
class ClassLoader class ClassLoader
{ {
/** @var \Closure(string):void */
private static $includeFile;
/** @var ?string */ /** @var ?string */
private $vendorDir; private $vendorDir;
@ -106,6 +109,7 @@ class ClassLoader
public function __construct($vendorDir = null) public function __construct($vendorDir = null)
{ {
$this->vendorDir = $vendorDir; $this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
} }
/** /**
@ -425,7 +429,8 @@ class ClassLoader
public function loadClass($class) public function loadClass($class)
{ {
if ($file = $this->findFile($class)) { if ($file = $this->findFile($class)) {
includeFile($file); $includeFile = self::$includeFile;
$includeFile($file);
return true; return true;
} }
@ -555,18 +560,26 @@ class ClassLoader
return false; return false;
} }
}
/** /**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include. * Scope isolated include.
* *
* Prevents access to $this/self from included files. * Prevents access to $this/self from included files.
* *
* @param string $file * @param string $file
* @return void * @return void
* @private
*/ */
function includeFile($file) self::$includeFile = \Closure::bind(static function($file) {
{
include $file; include $file;
}, null, null);
}
} }

View File

@ -10,7 +10,7 @@ return array(
'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'), 'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'), 'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'), 'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src'), 'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-template/src'),
'mailer\\' => array($vendorDir . '/yzh52521/think-mail/src/mailer'), 'mailer\\' => array($vendorDir . '/yzh52521/think-mail/src/mailer'),
'liliuwei\\social\\' => array($vendorDir . '/liliuwei/thinkphp-social/src'), 'liliuwei\\social\\' => array($vendorDir . '/liliuwei/thinkphp-social/src'),
'liliuwei\\sitemap\\' => array($vendorDir . '/liliuwei/php-sitemap/src'), 'liliuwei\\sitemap\\' => array($vendorDir . '/liliuwei/php-sitemap/src'),
@ -39,6 +39,7 @@ return array(
'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
'FormBuilder\\' => array($vendorDir . '/xaboy/form-builder/src'), 'FormBuilder\\' => array($vendorDir . '/xaboy/form-builder/src'),
'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'), 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'),
'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'), 'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
); );

View File

@ -33,25 +33,18 @@ class ComposerAutoloaderInit4b57298e8d0e895486f3307a354a7e1a
$loader->register(true); $loader->register(true);
$includeFiles = \Composer\Autoload\ComposerStaticInit4b57298e8d0e895486f3307a354a7e1a::$files; $filesToLoad = \Composer\Autoload\ComposerStaticInit4b57298e8d0e895486f3307a354a7e1a::$files;
foreach ($includeFiles as $fileIdentifier => $file) { $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
composerRequire4b57298e8d0e895486f3307a354a7e1a($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequire4b57298e8d0e895486f3307a354a7e1a($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file; require $file;
} }
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
} }

View File

@ -82,6 +82,7 @@ class ComposerStaticInit4b57298e8d0e895486f3307a354a7e1a
), ),
'D' => 'D' =>
array ( array (
'Doctrine\\Deprecations\\' => 22,
'Doctrine\\Common\\Lexer\\' => 22, 'Doctrine\\Common\\Lexer\\' => 22,
'Doctrine\\Common\\Annotations\\' => 28, 'Doctrine\\Common\\Annotations\\' => 28,
), ),
@ -106,10 +107,10 @@ class ComposerStaticInit4b57298e8d0e895486f3307a354a7e1a
), ),
'think\\' => 'think\\' =>
array ( array (
0 => __DIR__ . '/..' . '/topthink/framework/src/think', 0 => __DIR__ . '/..' . '/topthink/think-helper/src',
1 => __DIR__ . '/..' . '/topthink/think-filesystem/src', 1 => __DIR__ . '/..' . '/topthink/think-orm/src',
2 => __DIR__ . '/..' . '/topthink/think-helper/src', 2 => __DIR__ . '/..' . '/topthink/framework/src/think',
3 => __DIR__ . '/..' . '/topthink/think-orm/src', 3 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
4 => __DIR__ . '/..' . '/topthink/think-template/src', 4 => __DIR__ . '/..' . '/topthink/think-template/src',
), ),
'mailer\\' => 'mailer\\' =>
@ -224,9 +225,13 @@ class ComposerStaticInit4b57298e8d0e895486f3307a354a7e1a
array ( array (
0 => __DIR__ . '/..' . '/egulias/email-validator/src', 0 => __DIR__ . '/..' . '/egulias/email-validator/src',
), ),
'Doctrine\\Deprecations\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations',
),
'Doctrine\\Common\\Lexer\\' => 'Doctrine\\Common\\Lexer\\' =>
array ( array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer', 0 => __DIR__ . '/..' . '/doctrine/lexer/src',
), ),
'Doctrine\\Common\\Annotations\\' => 'Doctrine\\Common\\Annotations\\' =>
array ( array (

View File

@ -2,17 +2,17 @@
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "1.13.3", "version": "1.14.3",
"version_normalized": "1.13.3.0", "version_normalized": "1.14.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/annotations.git", "url": "https://github.com/doctrine/annotations.git",
"reference": "648b0343343565c4a056bfc8392201385e8d89f0" "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af",
"reference": "648b0343343565c4a056bfc8392201385e8d89f0", "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -22,20 +22,23 @@
] ]
}, },
"require": { "require": {
"doctrine/lexer": "1.*", "doctrine/lexer": "^1 || ^2",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.1 || ^8.0", "php": "^7.1 || ^8.0",
"psr/cache": "^1 || ^2 || ^3" "psr/cache": "^1 || ^2 || ^3"
}, },
"require-dev": { "require-dev": {
"doctrine/cache": "^1.11 || ^2.0", "doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^6.0 || ^8.1", "doctrine/coding-standard": "^9 || ^10",
"phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpstan/phpstan": "~1.4.10 || ^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^4.4 || ^5.2", "symfony/cache": "^4.4 || ^5.4 || ^6",
"vimeo/psalm": "^4.10" "vimeo/psalm": "^4.10"
}, },
"time": "2022-07-02T10:48:51+00:00", "suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
},
"time": "2023-02-01T09:20:38+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -78,23 +81,23 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/annotations/issues", "issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.13.3" "source": "https://github.com/doctrine/annotations/tree/1.14.3"
}, },
"install-path": "../doctrine/annotations" "install-path": "../doctrine/annotations"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/deprecations",
"version": "1.2.3", "version": "v1.0.0",
"version_normalized": "1.2.3.0", "version_normalized": "1.0.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/lexer.git", "url": "https://github.com/doctrine/deprecations.git",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -104,20 +107,74 @@
] ]
}, },
"require": { "require": {
"php": "^7.1 || ^8.0" "php": "^7.1|^8.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9.0", "doctrine/coding-standard": "^9",
"phpstan/phpstan": "^1.3", "phpunit/phpunit": "^7.5|^8.5|^9.5",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psr/log": "^1|^2|^3"
"vimeo/psalm": "^4.11"
}, },
"time": "2022-02-28T11:07:21+00:00", "suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"time": "2022-05-02T15:47:09+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
},
"install-path": "../doctrine/deprecations"
},
{
"name": "doctrine/lexer",
"version": "2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9 || ^10",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.0"
},
"time": "2022-12-14T08:49:07+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -149,7 +206,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/lexer/issues", "issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/1.2.3" "source": "https://github.com/doctrine/lexer/tree/2.1.0"
}, },
"funding": [ "funding": [
{ {
@ -169,17 +226,17 @@
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "3.2.1", "version": "3.2.5",
"version_normalized": "3.2.1.0", "version_normalized": "3.2.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/egulias/EmailValidator.git", "url": "https://github.com/egulias/EmailValidator.git",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715" "reference": "b531a2311709443320c786feb4519cfaf94af796"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f88dcf4b14af14a98ad96b14b2b317969eab6715", "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b531a2311709443320c786feb4519cfaf94af796",
"reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715", "reference": "b531a2311709443320c786feb4519cfaf94af796",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -189,19 +246,18 @@
] ]
}, },
"require": { "require": {
"doctrine/lexer": "^1.2", "doctrine/lexer": "^1.2|^2",
"php": ">=7.2", "php": ">=7.2",
"symfony/polyfill-intl-idn": "^1.15" "symfony/polyfill-intl-idn": "^1.15"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5.8|^9.3.3", "phpunit/phpunit": "^8.5.8|^9.3.3",
"vimeo/psalm": "^4" "vimeo/psalm": "^4"
}, },
"suggest": { "suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
}, },
"time": "2022-06-18T20:57:19+00:00", "time": "2023-01-02T17:26:14+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -234,7 +290,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/egulias/EmailValidator/issues", "issues": "https://github.com/egulias/EmailValidator/issues",
"source": "https://github.com/egulias/EmailValidator/tree/3.2.1" "source": "https://github.com/egulias/EmailValidator/tree/3.2.5"
}, },
"funding": [ "funding": [
{ {
@ -544,17 +600,17 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.6.4", "version": "v6.7.1",
"version_normalized": "6.6.4.0", "version_normalized": "6.7.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b" "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b", "reference": "49cd7ea3d2563f028d7811f06864a53b1f15ff55",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -570,24 +626,26 @@
"php": ">=5.5.0" "php": ">=5.5.0"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.6.2", "squizlabs/php_codesniffer": "^3.7.1",
"yoast/phpunit-polyfills": "^1.0.0" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
}, },
"time": "2022-08-22T09:22:00+00:00", "time": "2022-12-08T13:30:06+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -619,7 +677,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.7.1"
}, },
"funding": [ "funding": [
{ {
@ -805,17 +863,17 @@
}, },
{ {
"name": "psr/http-message", "name": "psr/http-message",
"version": "1.0.1", "version": "1.1",
"version_normalized": "1.0.1.0", "version_normalized": "1.1.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/http-message.git", "url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -825,13 +883,13 @@
] ]
}, },
"require": { "require": {
"php": ">=5.3.0" "php": "^7.2 || ^8.0"
}, },
"time": "2016-08-06T14:39:51+00:00", "time": "2023-04-04T09:50:52+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.1.x-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@ -861,7 +919,7 @@
"response" "response"
], ],
"support": { "support": {
"source": "https://github.com/php-fig/http-message/tree/master" "source": "https://github.com/php-fig/http-message/tree/1.1"
}, },
"install-path": "../psr/http-message" "install-path": "../psr/http-message"
}, },
@ -1121,17 +1179,17 @@
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v5.4.9", "version": "v5.4.22",
"version_normalized": "5.4.9.0", "version_normalized": "5.4.22.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
"reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1167,7 +1225,7 @@
"symfony/dependency-injection": "", "symfony/dependency-injection": "",
"symfony/http-kernel": "" "symfony/http-kernel": ""
}, },
"time": "2022-05-05T16:45:39+00:00", "time": "2023-03-17T11:31:58+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1195,7 +1253,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22"
}, },
"funding": [ "funding": [
{ {
@ -1303,17 +1361,17 @@
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v5.4.15", "version": "v5.4.23",
"version_normalized": "5.4.15.0", "version_normalized": "5.4.23.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "75bd663ff2db90141bfb733682459d5bbe9e29c3" "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/75bd663ff2db90141bfb733682459d5bbe9e29c3", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/af9fbb378f5f956c8f29d4886644c84c193780ac",
"reference": "75bd663ff2db90141bfb733682459d5bbe9e29c3", "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1340,7 +1398,7 @@
"suggest": { "suggest": {
"symfony/mime": "To use the file extension guesser" "symfony/mime": "To use the file extension guesser"
}, },
"time": "2022-10-12T09:43:19+00:00", "time": "2023-04-18T06:30:11+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1368,7 +1426,7 @@
"description": "Defines an object-oriented layer for the HTTP specification", "description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-foundation/tree/v5.4.15" "source": "https://github.com/symfony/http-foundation/tree/v5.4.23"
}, },
"funding": [ "funding": [
{ {
@ -1388,17 +1446,17 @@
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
"version": "v5.4.15", "version": "v5.4.22",
"version_normalized": "5.4.15.0", "version_normalized": "5.4.22.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mailer.git", "url": "https://github.com/symfony/mailer.git",
"reference": "926f4deddb60d40024e6058fd8f94e70e4024930" "reference": "6330cd465dfd8b7a07515757a1c37069075f7b0b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/926f4deddb60d40024e6058fd8f94e70e4024930", "url": "https://api.github.com/repos/symfony/mailer/zipball/6330cd465dfd8b7a07515757a1c37069075f7b0b",
"reference": "926f4deddb60d40024e6058fd8f94e70e4024930", "reference": "6330cd465dfd8b7a07515757a1c37069075f7b0b",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1408,7 +1466,7 @@
] ]
}, },
"require": { "require": {
"egulias/email-validator": "^2.1.10|^3", "egulias/email-validator": "^2.1.10|^3|^4",
"php": ">=7.2.5", "php": ">=7.2.5",
"psr/event-dispatcher": "^1", "psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
@ -1422,10 +1480,10 @@
"symfony/http-kernel": "<4.4" "symfony/http-kernel": "<4.4"
}, },
"require-dev": { "require-dev": {
"symfony/http-client-contracts": "^1.1|^2|^3", "symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/messenger": "^4.4|^5.0|^6.0" "symfony/messenger": "^4.4|^5.0|^6.0"
}, },
"time": "2022-10-27T07:55:40+00:00", "time": "2023-03-10T10:15:32+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1453,7 +1511,7 @@
"description": "Helps sending emails", "description": "Helps sending emails",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/mailer/tree/v5.4.15" "source": "https://github.com/symfony/mailer/tree/v5.4.22"
}, },
"funding": [ "funding": [
{ {
@ -1473,17 +1531,17 @@
}, },
{ {
"name": "symfony/mime", "name": "symfony/mime",
"version": "v5.4.14", "version": "v5.4.23",
"version_normalized": "5.4.14.0", "version_normalized": "5.4.23.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mime.git", "url": "https://github.com/symfony/mime.git",
"reference": "1c118b253bb3495d81e95a6e3ec6c2766a98a0c4" "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/1c118b253bb3495d81e95a6e3ec6c2766a98a0c4", "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3",
"reference": "1c118b253bb3495d81e95a6e3ec6c2766a98a0c4", "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1507,14 +1565,14 @@
"symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6"
}, },
"require-dev": { "require-dev": {
"egulias/email-validator": "^2.1.10|^3.1", "egulias/email-validator": "^2.1.10|^3.1|^4",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/property-access": "^4.4|^5.1|^6.0", "symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0", "symfony/property-info": "^4.4|^5.1|^6.0",
"symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6"
}, },
"time": "2022-10-07T08:01:20+00:00", "time": "2023-04-19T09:49:13+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -1546,7 +1604,7 @@
"mime-type" "mime-type"
], ],
"support": { "support": {
"source": "https://github.com/symfony/mime/tree/v5.4.14" "source": "https://github.com/symfony/mime/tree/v5.4.23"
}, },
"funding": [ "funding": [
{ {
@ -2214,17 +2272,17 @@
}, },
{ {
"name": "topthink/framework", "name": "topthink/framework",
"version": "v6.1.1", "version": "v6.1.2",
"version_normalized": "6.1.1.0", "version_normalized": "6.1.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/framework.git", "url": "https://github.com/top-think/framework.git",
"reference": "2cb56f3e6f3c479fe90ea5f28d38d3b5ef6c4210" "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/framework/zipball/2cb56f3e6f3c479fe90ea5f28d38d3b5ef6c4210", "url": "https://api.github.com/repos/top-think/framework/zipball/67235be5b919aaaf1de5aed9839f65d8e766aca3",
"reference": "2cb56f3e6f3c479fe90ea5f28d38d3b5ef6c4210", "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2242,7 +2300,7 @@
"psr/log": "~1.0", "psr/log": "~1.0",
"psr/simple-cache": "^1.0", "psr/simple-cache": "^1.0",
"topthink/think-helper": "^3.1.1", "topthink/think-helper": "^3.1.1",
"topthink/think-orm": "^2.0" "topthink/think-orm": "^2.0|^3.0"
}, },
"require-dev": { "require-dev": {
"guzzlehttp/psr7": "^2.1.0", "guzzlehttp/psr7": "^2.1.0",
@ -2250,7 +2308,7 @@
"mockery/mockery": "^1.2", "mockery/mockery": "^1.2",
"phpunit/phpunit": "^7.0" "phpunit/phpunit": "^7.0"
}, },
"time": "2022-10-26T03:48:53+00:00", "time": "2023-02-08T02:24:01+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2282,23 +2340,23 @@
], ],
"support": { "support": {
"issues": "https://github.com/top-think/framework/issues", "issues": "https://github.com/top-think/framework/issues",
"source": "https://github.com/top-think/framework/tree/v6.1.1" "source": "https://github.com/top-think/framework/tree/v6.1.2"
}, },
"install-path": "../topthink/framework" "install-path": "../topthink/framework"
}, },
{ {
"name": "topthink/think-captcha", "name": "topthink/think-captcha",
"version": "v3.0.8", "version": "v3.0.9",
"version_normalized": "3.0.8.0", "version_normalized": "3.0.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-captcha.git", "url": "https://github.com/top-think/think-captcha.git",
"reference": "52fba122c953995bec3013c635025172491ae299" "reference": "b1ef360670578214edeebcf824aaf6ab7ee0528b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-captcha/zipball/52fba122c953995bec3013c635025172491ae299", "url": "https://api.github.com/repos/top-think/think-captcha/zipball/b1ef360670578214edeebcf824aaf6ab7ee0528b",
"reference": "52fba122c953995bec3013c635025172491ae299", "reference": "b1ef360670578214edeebcf824aaf6ab7ee0528b",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2308,9 +2366,9 @@
] ]
}, },
"require": { "require": {
"topthink/framework": "^6.0" "topthink/framework": "^6.0|^8.0"
}, },
"time": "2022-10-26T07:59:42+00:00", "time": "2023-04-27T07:18:40+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"think": { "think": {
@ -2344,23 +2402,23 @@
"description": "captcha package for thinkphp", "description": "captcha package for thinkphp",
"support": { "support": {
"issues": "https://github.com/top-think/think-captcha/issues", "issues": "https://github.com/top-think/think-captcha/issues",
"source": "https://github.com/top-think/think-captcha/tree/v3.0.8" "source": "https://github.com/top-think/think-captcha/tree/v3.0.9"
}, },
"install-path": "../topthink/think-captcha" "install-path": "../topthink/think-captcha"
}, },
{ {
"name": "topthink/think-filesystem", "name": "topthink/think-filesystem",
"version": "v2.0.0", "version": "v2.0.2",
"version_normalized": "2.0.0.0", "version_normalized": "2.0.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-filesystem.git", "url": "https://github.com/top-think/think-filesystem.git",
"reference": "63e525fd74f451b2df1df060c3194e9b6e724730" "reference": "c08503232fcae0c3c7fefae5e6b5c841ffe09f2f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-filesystem/zipball/63e525fd74f451b2df1df060c3194e9b6e724730", "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/c08503232fcae0c3c7fefae5e6b5c841ffe09f2f",
"reference": "63e525fd74f451b2df1df060c3194e9b6e724730", "reference": "c08503232fcae0c3c7fefae5e6b5c841ffe09f2f",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2371,14 +2429,14 @@
}, },
"require": { "require": {
"league/flysystem": "^2.0", "league/flysystem": "^2.0",
"topthink/framework": "^6.1" "topthink/framework": "^6.1|^8.0"
}, },
"require-dev": { "require-dev": {
"mikey179/vfsstream": "^1.6", "mikey179/vfsstream": "^1.6",
"mockery/mockery": "^1.2", "mockery/mockery": "^1.2",
"phpunit/phpunit": "^8.0" "phpunit/phpunit": "^8.0"
}, },
"time": "2022-10-26T04:51:41+00:00", "time": "2023-02-08T01:23:42+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2399,7 +2457,7 @@
"description": "The ThinkPHP6.1 Filesystem Package", "description": "The ThinkPHP6.1 Filesystem Package",
"support": { "support": {
"issues": "https://github.com/top-think/think-filesystem/issues", "issues": "https://github.com/top-think/think-filesystem/issues",
"source": "https://github.com/top-think/think-filesystem/tree/v2.0.0" "source": "https://github.com/top-think/think-filesystem/tree/v2.0.2"
}, },
"install-path": "../topthink/think-filesystem" "install-path": "../topthink/think-filesystem"
}, },
@ -2514,17 +2572,17 @@
}, },
{ {
"name": "topthink/think-multi-app", "name": "topthink/think-multi-app",
"version": "v1.0.15", "version": "v1.0.16",
"version_normalized": "1.0.15.0", "version_normalized": "1.0.16.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-multi-app.git", "url": "https://github.com/top-think/think-multi-app.git",
"reference": "387e0dac059c20f92cac5da41a871e10829c1c97" "reference": "07b9183855150455e1f76f8cbe9d77d6d1bc399f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-multi-app/zipball/387e0dac059c20f92cac5da41a871e10829c1c97", "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/07b9183855150455e1f76f8cbe9d77d6d1bc399f",
"reference": "387e0dac059c20f92cac5da41a871e10829c1c97", "reference": "07b9183855150455e1f76f8cbe9d77d6d1bc399f",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2535,9 +2593,9 @@
}, },
"require": { "require": {
"php": ">=7.1.0", "php": ">=7.1.0",
"topthink/framework": "^6.0" "topthink/framework": "^6.0|^8.0"
}, },
"time": "2022-10-26T08:03:06+00:00", "time": "2023-02-07T08:40:09+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"think": { "think": {
@ -2565,23 +2623,23 @@
"description": "thinkphp6 multi app support", "description": "thinkphp6 multi app support",
"support": { "support": {
"issues": "https://github.com/top-think/think-multi-app/issues", "issues": "https://github.com/top-think/think-multi-app/issues",
"source": "https://github.com/top-think/think-multi-app/tree/v1.0.15" "source": "https://github.com/top-think/think-multi-app/tree/v1.0.16"
}, },
"install-path": "../topthink/think-multi-app" "install-path": "../topthink/think-multi-app"
}, },
{ {
"name": "topthink/think-orm", "name": "topthink/think-orm",
"version": "v2.0.54", "version": "v2.0.61",
"version_normalized": "2.0.54.0", "version_normalized": "2.0.61.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-orm.git", "url": "https://github.com/top-think/think-orm.git",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e" "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/97b061b47616301ff29fbd4c35ed9184e1162e4e", "url": "https://api.github.com/repos/top-think/think-orm/zipball/10528ebf4a5106b19c3bac9c6deae7a67ff49de6",
"reference": "97b061b47616301ff29fbd4c35ed9184e1162e4e", "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2601,7 +2659,7 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7|^8|^9.5" "phpunit/phpunit": "^7|^8|^9.5"
}, },
"time": "2022-07-05T05:25:51+00:00", "time": "2023-04-20T14:27:51+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2629,23 +2687,23 @@
], ],
"support": { "support": {
"issues": "https://github.com/top-think/think-orm/issues", "issues": "https://github.com/top-think/think-orm/issues",
"source": "https://github.com/top-think/think-orm/tree/v2.0.54" "source": "https://github.com/top-think/think-orm/tree/v2.0.61"
}, },
"install-path": "../topthink/think-orm" "install-path": "../topthink/think-orm"
}, },
{ {
"name": "topthink/think-template", "name": "topthink/think-template",
"version": "v2.0.8", "version": "v2.0.9",
"version_normalized": "2.0.8.0", "version_normalized": "2.0.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/top-think/think-template.git", "url": "https://github.com/top-think/think-template.git",
"reference": "abfc293f74f9ef5127b5c416310a01fe42e59368" "reference": "6d25642ae0e306166742fd7073dc7a159e18073c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/top-think/think-template/zipball/abfc293f74f9ef5127b5c416310a01fe42e59368", "url": "https://api.github.com/repos/top-think/think-template/zipball/6d25642ae0e306166742fd7073dc7a159e18073c",
"reference": "abfc293f74f9ef5127b5c416310a01fe42e59368", "reference": "6d25642ae0e306166742fd7073dc7a159e18073c",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2658,7 +2716,7 @@
"php": ">=7.1.0", "php": ">=7.1.0",
"psr/simple-cache": "^1.0" "psr/simple-cache": "^1.0"
}, },
"time": "2020-12-10T07:52:03+00:00", "time": "2023-02-14T10:50:39+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2679,7 +2737,7 @@
"description": "the php template engine", "description": "the php template engine",
"support": { "support": {
"issues": "https://github.com/top-think/think-template/issues", "issues": "https://github.com/top-think/think-template/issues",
"source": "https://github.com/top-think/think-template/tree/v2.0.8" "source": "https://github.com/top-think/think-template/tree/v2.0.9"
}, },
"install-path": "../topthink/think-template" "install-path": "../topthink/think-template"
}, },

View File

@ -3,7 +3,7 @@
'name' => 'topthink/think', 'name' => 'topthink/think',
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'e3cf01d01f242927ac3fd497b0cbc88fad1c9df2', 'reference' => 'c7deee9ae9a946ac4af3f530791f720402b7692d',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@ -11,27 +11,36 @@
), ),
'versions' => array( 'versions' => array(
'doctrine/annotations' => array( 'doctrine/annotations' => array(
'pretty_version' => '1.13.3', 'pretty_version' => '1.14.3',
'version' => '1.13.3.0', 'version' => '1.14.3.0',
'reference' => '648b0343343565c4a056bfc8392201385e8d89f0', 'reference' => 'fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/annotations', 'install_path' => __DIR__ . '/../doctrine/annotations',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'doctrine/deprecations' => array(
'pretty_version' => 'v1.0.0',
'version' => '1.0.0.0',
'reference' => '0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/deprecations',
'aliases' => array(),
'dev_requirement' => false,
),
'doctrine/lexer' => array( 'doctrine/lexer' => array(
'pretty_version' => '1.2.3', 'pretty_version' => '2.1.0',
'version' => '1.2.3.0', 'version' => '2.1.0.0',
'reference' => 'c268e882d4dbdd85e36e4ad69e02dc284f89d229', 'reference' => '39ab8fcf5a51ce4b85ca97c7a7d033eb12831124',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/lexer', 'install_path' => __DIR__ . '/../doctrine/lexer',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'egulias/email-validator' => array( 'egulias/email-validator' => array(
'pretty_version' => '3.2.1', 'pretty_version' => '3.2.5',
'version' => '3.2.1.0', 'version' => '3.2.5.0',
'reference' => 'f88dcf4b14af14a98ad96b14b2b317969eab6715', 'reference' => 'b531a2311709443320c786feb4519cfaf94af796',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../egulias/email-validator', 'install_path' => __DIR__ . '/../egulias/email-validator',
'aliases' => array(), 'aliases' => array(),
@ -74,9 +83,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'phpmailer/phpmailer' => array( 'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.6.4', 'pretty_version' => 'v6.7.1',
'version' => '6.6.4.0', 'version' => '6.7.1.0',
'reference' => 'a94fdebaea6bd17f51be0c2373ab80d3d681269b', 'reference' => '49cd7ea3d2563f028d7811f06864a53b1f15ff55',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer', 'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(), 'aliases' => array(),
@ -116,9 +125,9 @@
), ),
), ),
'psr/http-message' => array( 'psr/http-message' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.1',
'version' => '1.0.1.0', 'version' => '1.1.0.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message', 'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(), 'aliases' => array(),
@ -161,9 +170,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/event-dispatcher' => array( 'symfony/event-dispatcher' => array(
'pretty_version' => 'v5.4.9', 'pretty_version' => 'v5.4.22',
'version' => '5.4.9.0', 'version' => '5.4.22.0',
'reference' => '8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc', 'reference' => '1df20e45d56da29a4b1d8259dd6e950acbf1b13f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(), 'aliases' => array(),
@ -185,27 +194,27 @@
), ),
), ),
'symfony/http-foundation' => array( 'symfony/http-foundation' => array(
'pretty_version' => 'v5.4.15', 'pretty_version' => 'v5.4.23',
'version' => '5.4.15.0', 'version' => '5.4.23.0',
'reference' => '75bd663ff2db90141bfb733682459d5bbe9e29c3', 'reference' => 'af9fbb378f5f956c8f29d4886644c84c193780ac',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation', 'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/mailer' => array( 'symfony/mailer' => array(
'pretty_version' => 'v5.4.15', 'pretty_version' => 'v5.4.22',
'version' => '5.4.15.0', 'version' => '5.4.22.0',
'reference' => '926f4deddb60d40024e6058fd8f94e70e4024930', 'reference' => '6330cd465dfd8b7a07515757a1c37069075f7b0b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mailer', 'install_path' => __DIR__ . '/../symfony/mailer',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/mime' => array( 'symfony/mime' => array(
'pretty_version' => 'v5.4.14', 'pretty_version' => 'v5.4.23',
'version' => '5.4.14.0', 'version' => '5.4.23.0',
'reference' => '1c118b253bb3495d81e95a6e3ec6c2766a98a0c4', 'reference' => 'ae0a1032a450a3abf305ee44fc55ed423fbf16e3',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime', 'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(), 'aliases' => array(),
@ -275,9 +284,9 @@
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'topthink/framework' => array( 'topthink/framework' => array(
'pretty_version' => 'v6.1.1', 'pretty_version' => 'v6.1.2',
'version' => '6.1.1.0', 'version' => '6.1.2.0',
'reference' => '2cb56f3e6f3c479fe90ea5f28d38d3b5ef6c4210', 'reference' => '67235be5b919aaaf1de5aed9839f65d8e766aca3',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/framework', 'install_path' => __DIR__ . '/../topthink/framework',
'aliases' => array(), 'aliases' => array(),
@ -286,25 +295,25 @@
'topthink/think' => array( 'topthink/think' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'e3cf01d01f242927ac3fd497b0cbc88fad1c9df2', 'reference' => 'c7deee9ae9a946ac4af3f530791f720402b7692d',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-captcha' => array( 'topthink/think-captcha' => array(
'pretty_version' => 'v3.0.8', 'pretty_version' => 'v3.0.9',
'version' => '3.0.8.0', 'version' => '3.0.9.0',
'reference' => '52fba122c953995bec3013c635025172491ae299', 'reference' => 'b1ef360670578214edeebcf824aaf6ab7ee0528b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-captcha', 'install_path' => __DIR__ . '/../topthink/think-captcha',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-filesystem' => array( 'topthink/think-filesystem' => array(
'pretty_version' => 'v2.0.0', 'pretty_version' => 'v2.0.2',
'version' => '2.0.0.0', 'version' => '2.0.2.0',
'reference' => '63e525fd74f451b2df1df060c3194e9b6e724730', 'reference' => 'c08503232fcae0c3c7fefae5e6b5c841ffe09f2f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-filesystem', 'install_path' => __DIR__ . '/../topthink/think-filesystem',
'aliases' => array(), 'aliases' => array(),
@ -329,27 +338,27 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-multi-app' => array( 'topthink/think-multi-app' => array(
'pretty_version' => 'v1.0.15', 'pretty_version' => 'v1.0.16',
'version' => '1.0.15.0', 'version' => '1.0.16.0',
'reference' => '387e0dac059c20f92cac5da41a871e10829c1c97', 'reference' => '07b9183855150455e1f76f8cbe9d77d6d1bc399f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-multi-app', 'install_path' => __DIR__ . '/../topthink/think-multi-app',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-orm' => array( 'topthink/think-orm' => array(
'pretty_version' => 'v2.0.54', 'pretty_version' => 'v2.0.61',
'version' => '2.0.54.0', 'version' => '2.0.61.0',
'reference' => '97b061b47616301ff29fbd4c35ed9184e1162e4e', 'reference' => '10528ebf4a5106b19c3bac9c6deae7a67ff49de6',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-orm', 'install_path' => __DIR__ . '/../topthink/think-orm',
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-template' => array( 'topthink/think-template' => array(
'pretty_version' => 'v2.0.8', 'pretty_version' => 'v2.0.9',
'version' => '2.0.8.0', 'version' => '2.0.9.0',
'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368', 'reference' => '6d25642ae0e306166742fd7073dc7a159e18073c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-template', 'install_path' => __DIR__ . '/../topthink/think-template',
'aliases' => array(), 'aliases' => array(),

View File

@ -1,3 +1,9 @@
⚠️ PHP 8 introduced
[attributes](https://www.php.net/manual/en/language.attributes.overview.php),
which are a native replacement for annotations. As such, this library is
considered feature complete, and should receive exclusively bugfixes and
security fixes.
# Doctrine Annotations # Doctrine Annotations
[![Build Status](https://github.com/doctrine/annotations/workflows/Continuous%20Integration/badge.svg?label=build)](https://github.com/doctrine/persistence/actions) [![Build Status](https://github.com/doctrine/annotations/workflows/Continuous%20Integration/badge.svg?label=build)](https://github.com/doctrine/persistence/actions)

View File

@ -34,17 +34,20 @@
"require": { "require": {
"php": "^7.1 || ^8.0", "php": "^7.1 || ^8.0",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"doctrine/lexer": "1.*", "doctrine/lexer": "^1 || ^2",
"psr/cache": "^1 || ^2 || ^3" "psr/cache": "^1 || ^2 || ^3"
}, },
"require-dev": { "require-dev": {
"doctrine/cache": "^1.11 || ^2.0", "doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^6.0 || ^8.1", "doctrine/coding-standard": "^9 || ^10",
"phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpstan/phpstan": "~1.4.10 || ^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^4.4 || ^5.2", "symfony/cache": "^4.4 || ^5.4 || ^6",
"vimeo/psalm": "^4.10" "vimeo/psalm": "^4.10"
}, },
"suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"

View File

@ -69,7 +69,7 @@ When using the ``@NamedArgumentConstructor`` tag, the first argument of the
constructor is considered as the default one. constructor is considered as the default one.
Usage with the ``@NamedArgumentContrustor`` tag Usage with the ``@NamedArgumentConstructor`` tag
.. code-block:: php .. code-block:: php

View File

@ -1,3 +1,12 @@
Deprecation notice
==================
PHP 8 introduced `attributes
<https://www.php.net/manual/en/language.attributes.overview.php>`_,
which are a native replacement for annotations. As such, this library is
considered feature complete, and should receive exclusively bugfixes and
security fixes.
Introduction Introduction
============ ============

View File

@ -18,9 +18,7 @@ class Annotation
*/ */
public $value; public $value;
/** /** @param array<string, mixed> $data Key-value for properties to be defined in this class. */
* @param array<string, mixed> $data Key-value for properties to be defined in this class.
*/
final public function __construct(array $data) final public function __construct(array $data)
{ {
foreach ($data as $key => $value) { foreach ($data as $key => $value) {

View File

@ -34,9 +34,9 @@ final class Enum
public $literal; public $literal;
/** /**
* @throws InvalidArgumentException
*
* @phpstan-param array{literal?: mixed[], value: list<scalar>} $values * @phpstan-param array{literal?: mixed[], value: list<scalar>} $values
*
* @throws InvalidArgumentException
*/ */
public function __construct(array $values) public function __construct(array $values)
{ {

View File

@ -21,9 +21,9 @@ final class IgnoreAnnotation
public $names; public $names;
/** /**
* @throws RuntimeException
*
* @phpstan-param array{value: string|list<string>} $values * @phpstan-param array{value: string|list<string>} $values
*
* @throws RuntimeException
*/ */
public function __construct(array $values) public function __construct(array $values)
{ {

View File

@ -56,9 +56,9 @@ final class Target
public $literal; public $literal;
/** /**
* @throws InvalidArgumentException
*
* @phpstan-param array{value?: string|list<string>} $values * @phpstan-param array{value?: string|list<string>} $values
*
* @throws InvalidArgumentException
*/ */
public function __construct(array $values) public function __construct(array $values)
{ {

View File

@ -133,10 +133,9 @@ class AnnotationException extends Exception
* @param string $annotationName * @param string $annotationName
* @param string $context * @param string $context
* @param mixed $given * @param mixed $given
* @phpstan-param list<string> $available
* *
* @return AnnotationException * @return AnnotationException
*
* @phpstan-param list<string> $available
*/ */
public static function enumeratorError($attributeName, $annotationName, $context, $available, $given) public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
{ {
@ -150,9 +149,7 @@ class AnnotationException extends Exception
)); ));
} }
/** /** @return AnnotationException */
* @return AnnotationException
*/
public static function optimizerPlusSaveComments() public static function optimizerPlusSaveComments()
{ {
return new self( return new self(
@ -160,9 +157,7 @@ class AnnotationException extends Exception
); );
} }
/** /** @return AnnotationException */
* @return AnnotationException
*/
public static function optimizerPlusLoadComments() public static function optimizerPlusLoadComments()
{ {
return new self( return new self(

View File

@ -38,9 +38,7 @@ final class CachedReader implements Reader
/** @var int[] */ /** @var int[] */
private $loadedFilemtimes = []; private $loadedFilemtimes = [];
/** /** @param bool $debug */
* @param bool $debug
*/
public function __construct(Reader $reader, Cache $cache, $debug = false) public function __construct(Reader $reader, Cache $cache, $debug = false)
{ {
$this->delegate = $reader; $this->delegate = $reader;

View File

@ -15,6 +15,8 @@ use function substr;
/** /**
* Simple lexer for docblock annotations. * Simple lexer for docblock annotations.
*
* @template-extends AbstractLexer<DocLexer::T_*, string>
*/ */
final class DocLexer extends AbstractLexer final class DocLexer extends AbstractLexer
{ {
@ -39,7 +41,7 @@ final class DocLexer extends AbstractLexer
public const T_COLON = 112; public const T_COLON = 112;
public const T_MINUS = 113; public const T_MINUS = 113;
/** @var array<string, int> */ /** @var array<string, self::T*> */
protected $noCase = [ protected $noCase = [
'@' => self::T_AT, '@' => self::T_AT,
',' => self::T_COMMA, ',' => self::T_COMMA,
@ -53,7 +55,7 @@ final class DocLexer extends AbstractLexer
'\\' => self::T_NAMESPACE_SEPARATOR, '\\' => self::T_NAMESPACE_SEPARATOR,
]; ];
/** @var array<string, int> */ /** @var array<string, self::T*> */
protected $withCase = [ protected $withCase = [
'true' => self::T_TRUE, 'true' => self::T_TRUE,
'false' => self::T_FALSE, 'false' => self::T_FALSE,
@ -126,4 +128,16 @@ final class DocLexer extends AbstractLexer
return $type; return $type;
} }
/** @return array{value: int|string, type:self::T_*|null, position:int} */
public function peek(): ?array
{
$token = parent::peek();
if ($token === null) {
return null;
}
return (array) $token;
}
} }

View File

@ -357,10 +357,10 @@ final class DocParser
* @param string $input The docblock string to parse. * @param string $input The docblock string to parse.
* @param string $context The parsing context. * @param string $context The parsing context.
* *
* @phpstan-return list<object> Array of annotations. If no annotations are found, an empty array is returned.
*
* @throws AnnotationException * @throws AnnotationException
* @throws ReflectionException * @throws ReflectionException
*
* @phpstan-return list<object> Array of annotations. If no annotations are found, an empty array is returned.
*/ */
public function parse($input, $context = '') public function parse($input, $context = '')
{ {
@ -426,9 +426,9 @@ final class DocParser
* If any of them matches, this method updates the lookahead token; otherwise * If any of them matches, this method updates the lookahead token; otherwise
* a syntax error is raised. * a syntax error is raised.
* *
* @throws AnnotationException
*
* @phpstan-param list<mixed[]> $tokens * @phpstan-param list<mixed[]> $tokens
*
* @throws AnnotationException
*/ */
private function matchAny(array $tokens): bool private function matchAny(array $tokens): bool
{ {
@ -613,6 +613,10 @@ final class DocParser
$metadata['default_property'] = reset($metadata['properties']); $metadata['default_property'] = reset($metadata['properties']);
} elseif ($metadata['has_named_argument_constructor']) { } elseif ($metadata['has_named_argument_constructor']) {
foreach ($constructor->getParameters() as $parameter) { foreach ($constructor->getParameters() as $parameter) {
if ($parameter->isVariadic()) {
break;
}
$metadata['constructor_args'][$parameter->getName()] = [ $metadata['constructor_args'][$parameter->getName()] = [
'position' => $parameter->getPosition(), 'position' => $parameter->getPosition(),
'default' => $parameter->isOptional() ? $parameter->getDefaultValue() : null, 'default' => $parameter->isOptional() ? $parameter->getDefaultValue() : null,
@ -674,10 +678,10 @@ final class DocParser
/** /**
* Annotations ::= Annotation {[ "*" ]* [Annotation]}* * Annotations ::= Annotation {[ "*" ]* [Annotation]}*
* *
* @phpstan-return list<object>
*
* @throws AnnotationException * @throws AnnotationException
* @throws ReflectionException * @throws ReflectionException
*
* @phpstan-return list<object>
*/ */
private function Annotations(): array private function Annotations(): array
{ {
@ -942,6 +946,23 @@ EXCEPTION
if (self::$annotationMetadata[$name]['has_named_argument_constructor']) { if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {
if (PHP_VERSION_ID >= 80000) { if (PHP_VERSION_ID >= 80000) {
foreach ($values as $property => $value) {
if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
throw AnnotationException::creationError(sprintf(
<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s"
that can be set through its named arguments constructor.
Available named arguments: %s
EXCEPTION
,
$originalName,
$this->context,
$property,
implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))
));
}
}
return $this->instantiateAnnotiation($originalName, $this->context, $name, $values); return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);
} }
@ -1166,9 +1187,7 @@ EXCEPTION
return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class'); return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class');
} }
/** /** @return int|false */
* @return int|false
*/
private function getClassConstantPositionInIdentifier(string $identifier) private function getClassConstantPositionInIdentifier(string $identifier)
{ {
return stripos($identifier, '::class'); return stripos($identifier, '::class');
@ -1357,10 +1376,10 @@ EXCEPTION
* KeyValuePair ::= Key ("=" | ":") PlainValue | Constant * KeyValuePair ::= Key ("=" | ":") PlainValue | Constant
* Key ::= string | integer | Constant * Key ::= string | integer | Constant
* *
* @phpstan-return array{mixed, mixed}
*
* @throws AnnotationException * @throws AnnotationException
* @throws ReflectionException * @throws ReflectionException
*
* @phpstan-return array{mixed, mixed}
*/ */
private function ArrayEntry(): array private function ArrayEntry(): array
{ {

View File

@ -46,9 +46,7 @@ class TokenParser
*/ */
private $pointer = 0; private $pointer = 0;
/** /** @param string $contents */
* @param string $contents
*/
public function __construct($contents) public function __construct($contents)
{ {
$this->tokens = token_get_all($contents); $this->tokens = token_get_all($contents);

19
vendor/doctrine/deprecations/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2020-2021 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

154
vendor/doctrine/deprecations/README.md vendored Normal file
View File

@ -0,0 +1,154 @@
# Doctrine Deprecations
A small (side-effect free by default) layer on top of
`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging.
- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under
- options to avoid having to rely on error handlers global state by using PSR-3 logging
- deduplicate deprecation messages to avoid excessive triggering and reduce overhead
We recommend to collect Deprecations using a PSR logger instead of relying on
the global error handler.
## Usage from consumer perspective:
Enable Doctrine deprecations to be sent to a PSR3 logger:
```php
\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
```
Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)`
messages.
```php
\Doctrine\Deprecations\Deprecation::enableWithTriggerError();
```
If you only want to enable deprecation tracking, without logging or calling `trigger_error` then call:
```php
\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
```
Tracking is enabled with all three modes and provides access to all triggered
deprecations and their individual count:
```php
$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations();
foreach ($deprecations as $identifier => $count) {
echo $identifier . " was triggered " . $count . " times\n";
}
```
### Suppressing Specific Deprecations
Disable triggering about specific deprecations:
```php
\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier");
```
Disable all deprecations from a package
```php
\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm");
```
### Other Operations
When used within PHPUnit or other tools that could collect multiple instances of the same deprecations
the deduplication can be disabled:
```php
\Doctrine\Deprecations\Deprecation::withoutDeduplication();
```
Disable deprecation tracking again:
```php
\Doctrine\Deprecations\Deprecation::disable();
```
## Usage from a library/producer perspective:
When you want to unconditionally trigger a deprecation even when called
from the library itself then the `trigger` method is the way to go:
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
If variable arguments are provided at the end, they are used with `sprintf` on
the message.
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://github.com/doctrine/orm/issue/1234",
"message %s %d",
"foo",
1234
);
```
When you want to trigger a deprecation only when it is called by a function
outside of the current package, but not trigger when the package itself is the cause,
then use:
```php
\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
Based on the issue link each deprecation message is only triggered once per
request.
A limited stacktrace is included in the deprecation message to find the
offending location.
Note: A producer/library should never call `Deprecation::enableWith` methods
and leave the decision how to handle deprecations to application and
frameworks.
## Usage in PHPUnit tests
There is a `VerifyDeprecations` trait that you can use to make assertions on
the occurrence of deprecations within a test.
```php
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
class MyTest extends TestCase
{
use VerifyDeprecations;
public function testSomethingDeprecation()
{
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithDeprecation();
}
public function testSomethingDeprecationFixed()
{
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithoutDeprecation();
}
}
```
## What is a deprecation identifier?
An identifier for deprecations is just a link to any resource, most often a
Github Issue or Pull Request explaining the deprecation and potentially its
alternative.

View File

@ -0,0 +1,32 @@
{
"name": "doctrine/deprecations",
"type": "library",
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"license": "MIT",
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3",
"doctrine/coding-standard": "^9"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"autoload": {
"psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"}
},
"autoload-dev": {
"psr-4": {
"DeprecationTests\\": "test_fixtures/src",
"Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -0,0 +1,266 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations;
use Psr\Log\LoggerInterface;
use function array_key_exists;
use function array_reduce;
use function debug_backtrace;
use function sprintf;
use function strpos;
use function strrpos;
use function substr;
use function trigger_error;
use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const DIRECTORY_SEPARATOR;
use const E_USER_DEPRECATED;
/**
* Manages Deprecation logging in different ways.
*
* By default triggered exceptions are not logged.
*
* To enable different deprecation logging mechanisms you can call the
* following methods:
*
* - Minimal collection of deprecations via getTriggeredDeprecations()
* \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
*
* - Uses @trigger_error with E_USER_DEPRECATED
* \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
*
* - Sends deprecation messages via a PSR-3 logger
* \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
*
* Packages that trigger deprecations should use the `trigger()` or
* `triggerIfCalledFromOutside()` methods.
*/
class Deprecation
{
private const TYPE_NONE = 0;
private const TYPE_TRACK_DEPRECATIONS = 1;
private const TYPE_TRIGGER_ERROR = 2;
private const TYPE_PSR_LOGGER = 4;
/** @var int */
private static $type = self::TYPE_NONE;
/** @var LoggerInterface|null */
private static $logger;
/** @var array<string,bool> */
private static $ignoredPackages = [];
/** @var array<string,int> */
private static $ignoredLinks = [];
/** @var bool */
private static $deduplication = true;
/**
* Trigger a deprecation for the given package and identfier.
*
* The link should point to a Github issue or Wiki entry detailing the
* deprecation. It is additionally used to de-duplicate the trigger of the
* same deprecation during a request.
*
* @param mixed $args
*/
public static function trigger(string $package, string $link, string $message, ...$args): void
{
if (self::$type === self::TYPE_NONE) {
return;
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* Trigger a deprecation for the given package and identifier when called from outside.
*
* "Outside" means we assume that $package is currently installed as a
* dependency and the caller is not a file in that package. When $package
* is installed as a root package then deprecations triggered from the
* tests folder are also considered "outside".
*
* This deprecation method assumes that you are using Composer to install
* the dependency and are using the default /vendor/ folder and not a
* Composer plugin to change the install location. The assumption is also
* that $package is the exact composer packge name.
*
* Compared to {@link trigger()} this method causes some overhead when
* deprecation tracking is enabled even during deduplication, because it
* needs to call {@link debug_backtrace()}
*
* @param mixed $args
*/
public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
{
if (self::$type === self::TYPE_NONE) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
$path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR;
if (strpos($backtrace[0]['file'], $path) === false) {
return;
}
if (strpos($backtrace[1]['file'], $path) !== false) {
return;
}
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* @param array<mixed> $backtrace
*/
private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
{
if ((self::$type & self::TYPE_PSR_LOGGER) > 0) {
$context = [
'file' => $backtrace[0]['file'],
'line' => $backtrace[0]['line'],
'package' => $package,
'link' => $link,
];
self::$logger->notice($message, $context);
}
if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) {
return;
}
$message .= sprintf(
' (%s:%d called by %s:%d, %s, package %s)',
self::basename($backtrace[0]['file']),
$backtrace[0]['line'],
self::basename($backtrace[1]['file']),
$backtrace[1]['line'],
$link,
$package
);
@trigger_error($message, E_USER_DEPRECATED);
}
/**
* A non-local-aware version of PHPs basename function.
*/
private static function basename(string $filename): string
{
$pos = strrpos($filename, DIRECTORY_SEPARATOR);
if ($pos === false) {
return $filename;
}
return substr($filename, $pos + 1);
}
public static function enableTrackingDeprecations(): void
{
self::$type |= self::TYPE_TRACK_DEPRECATIONS;
}
public static function enableWithTriggerError(): void
{
self::$type |= self::TYPE_TRIGGER_ERROR;
}
public static function enableWithPsrLogger(LoggerInterface $logger): void
{
self::$type |= self::TYPE_PSR_LOGGER;
self::$logger = $logger;
}
public static function withoutDeduplication(): void
{
self::$deduplication = false;
}
public static function disable(): void
{
self::$type = self::TYPE_NONE;
self::$logger = null;
self::$deduplication = true;
foreach (self::$ignoredLinks as $link => $count) {
self::$ignoredLinks[$link] = 0;
}
}
public static function ignorePackage(string $packageName): void
{
self::$ignoredPackages[$packageName] = true;
}
public static function ignoreDeprecations(string ...$links): void
{
foreach ($links as $link) {
self::$ignoredLinks[$link] = 0;
}
}
public static function getUniqueTriggeredDeprecationsCount(): int
{
return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) {
return $carry + $count;
}, 0);
}
/**
* Returns each triggered deprecation link identifier and the amount of occurrences.
*
* @return array<string,int>
*/
public static function getTriggeredDeprecations(): array
{
return self::$ignoredLinks;
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations\PHPUnit;
use Doctrine\Deprecations\Deprecation;
use function sprintf;
trait VerifyDeprecations
{
/** @var array<string,int> */
private $doctrineDeprecationsExpectations = [];
/** @var array<string,int> */
private $doctrineNoDeprecationsExpectations = [];
public function expectDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
public function expectNoDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
/**
* @before
*/
public function enableDeprecationTracking(): void
{
Deprecation::enableTrackingDeprecations();
}
/**
* @after
*/
public function verifyDeprecationsAreTriggered(): void
{
foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount > $expectation,
sprintf(
"Expected deprecation with identifier '%s' was not triggered by code executed in test.",
$identifier
)
);
}
foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount === $expectation,
sprintf(
"Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
$identifier
)
);
}
}
}

22
vendor/doctrine/deprecations/phpcs.xml vendored Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<ruleset>
<arg name="basepath" value="."/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="80"/>
<arg name="cache" value=".phpcs-cache"/>
<arg name="colors"/>
<!-- Ignore warnings, show progress of the run and show sniff names -->
<arg value="nps"/>
<config name="php_version" value="70100"/>
<!-- Directories to be checked -->
<file>lib</file>
<file>tests</file>
<!-- Include full Doctrine Coding Standard -->
<rule ref="Doctrine">
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint" />
</rule>
</ruleset>

14
vendor/doctrine/lexer/UPGRADE.md vendored Normal file
View File

@ -0,0 +1,14 @@
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
awareness about deprecated code.
- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
Static Analysis tools (like Psalm, phpstan)
- Use of our low-overhead runtime deprecation API, details:
https://github.com/doctrine/deprecations/
# Upgrade to 2.0.0
`AbstractLexer::glimpse()` and `AbstractLexer::peek()` now return
instances of `Doctrine\Common\Lexer\Token`, which is an array-like class
Using it as an array is deprecated in favor of using properties of that class.
Using `count()` on it is deprecated with no replacement.

View File

@ -1,7 +1,8 @@
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"type": "library",
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"license": "MIT",
"type": "library",
"keywords": [ "keywords": [
"php", "php",
"parser", "parser",
@ -9,27 +10,41 @@
"annotations", "annotations",
"docblock" "docblock"
], ],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"license": "MIT",
"authors": [ "authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, {
{"name": "Roman Borschel", "email": "roman@code-factory.org"}, "name": "Guilherme Blanco",
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} "email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
], ],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"require": { "require": {
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0",
"doctrine/deprecations": "^1.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9.0", "doctrine/coding-standard": "^9 || ^10",
"phpstan/phpstan": "^1.3", "phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.11" "psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.0"
}, },
"autoload": { "autoload": {
"psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } "psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
}
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" } "psr-4": {
"Doctrine\\Tests\\Common\\Lexer\\": "tests"
}
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

View File

@ -1,15 +0,0 @@
<?xml version="1.0"?>
<psalm
errorLevel="5"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="lib/Doctrine/Common/Lexer" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@ -5,9 +5,10 @@ declare(strict_types=1);
namespace Doctrine\Common\Lexer; namespace Doctrine\Common\Lexer;
use ReflectionClass; use ReflectionClass;
use UnitEnum;
use function get_class;
use function implode; use function implode;
use function in_array;
use function preg_split; use function preg_split;
use function sprintf; use function sprintf;
use function substr; use function substr;
@ -19,7 +20,8 @@ use const PREG_SPLIT_OFFSET_CAPTURE;
/** /**
* Base class for writing simple lexers, i.e. for creating small DSLs. * Base class for writing simple lexers, i.e. for creating small DSLs.
* *
* @psalm-type Token = array{value: int|string, type:string|int|null, position:int} * @template T of UnitEnum|string|int
* @template V of string|int
*/ */
abstract class AbstractLexer abstract class AbstractLexer
{ {
@ -33,14 +35,7 @@ abstract class AbstractLexer
/** /**
* Array of scanned tokens. * Array of scanned tokens.
* *
* Each token is an associative array containing three items: * @var list<Token<T, V>>
* - 'value' : the string value of the token in the input string
* - 'type' : the type of the token (identifier, numeric, string, input
* parameter, none)
* - 'position' : the position of the token in the input string
*
* @var mixed[][]
* @psalm-var list<Token>
*/ */
private $tokens = []; private $tokens = [];
@ -62,7 +57,7 @@ abstract class AbstractLexer
* The next token in the input. * The next token in the input.
* *
* @var mixed[]|null * @var mixed[]|null
* @psalm-var Token|null * @psalm-var Token<T, V>|null
*/ */
public $lookahead; public $lookahead;
@ -70,7 +65,7 @@ abstract class AbstractLexer
* The last matched/seen token. * The last matched/seen token.
* *
* @var mixed[]|null * @var mixed[]|null
* @psalm-var Token|null * @psalm-var Token<T, V>|null
*/ */
public $token; public $token;
@ -150,31 +145,37 @@ abstract class AbstractLexer
/** /**
* Checks whether a given token matches the current lookahead. * Checks whether a given token matches the current lookahead.
* *
* @param int|string $type * @param T $type
* *
* @return bool * @return bool
*
* @psalm-assert-if-true !=null $this->lookahead
*/ */
public function isNextToken($type) public function isNextToken($type)
{ {
return $this->lookahead !== null && $this->lookahead['type'] === $type; return $this->lookahead !== null && $this->lookahead->isA($type);
} }
/** /**
* Checks whether any of the given tokens matches the current lookahead. * Checks whether any of the given tokens matches the current lookahead.
* *
* @param list<int|string> $types * @param list<T> $types
* *
* @return bool * @return bool
*
* @psalm-assert-if-true !=null $this->lookahead
*/ */
public function isNextTokenAny(array $types) public function isNextTokenAny(array $types)
{ {
return $this->lookahead !== null && in_array($this->lookahead['type'], $types, true); return $this->lookahead !== null && $this->lookahead->isA(...$types);
} }
/** /**
* Moves to the next token in the input string. * Moves to the next token in the input string.
* *
* @return bool * @return bool
*
* @psalm-assert-if-true !null $this->lookahead
*/ */
public function moveNext() public function moveNext()
{ {
@ -189,13 +190,13 @@ abstract class AbstractLexer
/** /**
* Tells the lexer to skip input tokens until it sees a token with the given value. * Tells the lexer to skip input tokens until it sees a token with the given value.
* *
* @param string $type The token type to skip until. * @param T $type The token type to skip until.
* *
* @return void * @return void
*/ */
public function skipUntil($type) public function skipUntil($type)
{ {
while ($this->lookahead !== null && $this->lookahead['type'] !== $type) { while ($this->lookahead !== null && ! $this->lookahead->isA($type)) {
$this->moveNext(); $this->moveNext();
} }
} }
@ -203,7 +204,7 @@ abstract class AbstractLexer
/** /**
* Checks if given value is identical to the given token. * Checks if given value is identical to the given token.
* *
* @param mixed $value * @param string $value
* @param int|string $token * @param int|string $token
* *
* @return bool * @return bool
@ -217,7 +218,7 @@ abstract class AbstractLexer
* Moves the lookahead token forward. * Moves the lookahead token forward.
* *
* @return mixed[]|null The next token or NULL if there are no more tokens ahead. * @return mixed[]|null The next token or NULL if there are no more tokens ahead.
* @psalm-return Token|null * @psalm-return Token<T, V>|null
*/ */
public function peek() public function peek()
{ {
@ -232,7 +233,7 @@ abstract class AbstractLexer
* Peeks at the next token, returns it and immediately resets the peek. * Peeks at the next token, returns it and immediately resets the peek.
* *
* @return mixed[]|null The next token or NULL if there are no more tokens ahead. * @return mixed[]|null The next token or NULL if there are no more tokens ahead.
* @psalm-return Token|null * @psalm-return Token<T, V>|null
*/ */
public function glimpse() public function glimpse()
{ {
@ -270,26 +271,32 @@ abstract class AbstractLexer
foreach ($matches as $match) { foreach ($matches as $match) {
// Must remain before 'value' assignment since it can change content // Must remain before 'value' assignment since it can change content
$type = $this->getType($match[0]); $firstMatch = $match[0];
$type = $this->getType($firstMatch);
$this->tokens[] = [ $this->tokens[] = new Token(
'value' => $match[0], $firstMatch,
'type' => $type, $type,
'position' => $match[1], $match[1]
]; );
} }
} }
/** /**
* Gets the literal for a given token. * Gets the literal for a given token.
* *
* @param int|string $token * @param T $token
* *
* @return int|string * @return int|string
*/ */
public function getLiteral($token) public function getLiteral($token)
{ {
if ($token instanceof UnitEnum) {
return get_class($token) . '::' . $token->name;
}
$className = static::class; $className = static::class;
$reflClass = new ReflectionClass($className); $reflClass = new ReflectionClass($className);
$constants = $reflClass->getConstants(); $constants = $reflClass->getConstants();
@ -331,7 +338,9 @@ abstract class AbstractLexer
* *
* @param string $value * @param string $value
* *
* @return int|string|null * @return T|null
*
* @param-out V $value
*/ */
abstract protected function getType(&$value); abstract protected function getType(&$value);
} }

145
vendor/doctrine/lexer/src/Token.php vendored Normal file
View File

@ -0,0 +1,145 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Lexer;
use ArrayAccess;
use Doctrine\Deprecations\Deprecation;
use ReturnTypeWillChange;
use UnitEnum;
use function in_array;
/**
* @template T of UnitEnum|string|int
* @template V of string|int
* @implements ArrayAccess<string,mixed>
*/
final class Token implements ArrayAccess
{
/**
* The string value of the token in the input string
*
* @readonly
* @var V
*/
public $value;
/**
* The type of the token (identifier, numeric, string, input parameter, none)
*
* @readonly
* @var T|null
*/
public $type;
/**
* The position of the token in the input string
*
* @readonly
* @var int
*/
public $position;
/**
* @param V $value
* @param T|null $type
*/
public function __construct($value, $type, int $position)
{
$this->value = $value;
$this->type = $type;
$this->position = $position;
}
/** @param T ...$types */
public function isA(...$types): bool
{
return in_array($this->type, $types, true);
}
/**
* @deprecated Use the value, type or position property instead
* {@inheritDoc}
*/
public function offsetExists($offset): bool
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
self::class
);
return in_array($offset, ['value', 'type', 'position'], true);
}
/**
* @deprecated Use the value, type or position property instead
* {@inheritDoc}
*
* @param O $offset
*
* @return mixed
* @psalm-return (
* O is 'value'
* ? V
* : (
* O is 'type'
* ? T|null
* : (
* O is 'position'
* ? int
* : mixed
* )
* )
* )
*
* @template O of array-key
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
self::class
);
return $this->$offset;
}
/**
* @deprecated no replacement planned
* {@inheritDoc}
*/
public function offsetSet($offset, $value): void
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Setting %s properties via ArrayAccess is deprecated',
self::class
);
$this->$offset = $value;
}
/**
* @deprecated no replacement planned
* {@inheritDoc}
*/
public function offsetUnset($offset): void
{
Deprecation::trigger(
'doctrine/lexer',
'https://github.com/doctrine/lexer/pull/79',
'Setting %s properties via ArrayAccess is deprecated',
self::class
);
$this->$offset = null;
}
}

View File

@ -5,7 +5,7 @@
* Access to local part and domain part from EmailParser * Access to local part and domain part from EmailParser
* Validations outside of the scope of the RFC will be considered "extra" validations, thus opening the door for adding new; will live in their own folder "extra" (as requested in #248, #195, #183). * Validations outside of the scope of the RFC will be considered "extra" validations, thus opening the door for adding new; will live in their own folder "extra" (as requested in #248, #195, #183).
## Breacking changes ## Breaking changes
* PHP version upgraded to match Symfony's (as of 12/2020). * PHP version upgraded to match Symfony's (as of 12/2020).
* DNSCheckValidation now fails for missing MX records. While the RFC argues that the existence of only A records to be valid, starting in v3 they will be considered invalid. * DNSCheckValidation now fails for missing MX records. While the RFC argues that the existence of only A records to be valid, starting in v3 they will be considered invalid.

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2021 Eduardo Gulias Davis Copyright (c) 2013-2022 Eduardo Gulias Davis
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -14,11 +14,10 @@
}, },
"require": { "require": {
"php": ">=7.2", "php": ">=7.2",
"doctrine/lexer": "^1.2", "doctrine/lexer": "^1.2|^2",
"symfony/polyfill-intl-idn": "^1.15" "symfony/polyfill-intl-idn": "^1.15"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5.8|^9.3.3", "phpunit/phpunit": "^8.5.8|^9.3.3",
"vimeo/psalm": "^4" "vimeo/psalm": "^4"
}, },

View File

@ -3,58 +3,62 @@
namespace Egulias\EmailValidator; namespace Egulias\EmailValidator;
use Doctrine\Common\Lexer\AbstractLexer; use Doctrine\Common\Lexer\AbstractLexer;
use Doctrine\Common\Lexer\Token;
/**
* @extends AbstractLexer<int, string>
*/
class EmailLexer extends AbstractLexer class EmailLexer extends AbstractLexer
{ {
//ASCII values //ASCII values
const S_EMPTY = null; public const S_EMPTY = null;
const C_NUL = 0; public const C_NUL = 0;
const S_HTAB = 9; public const S_HTAB = 9;
const S_LF = 10; public const S_LF = 10;
const S_CR = 13; public const S_CR = 13;
const S_SP = 32; public const S_SP = 32;
const EXCLAMATION = 33; public const EXCLAMATION = 33;
const S_DQUOTE = 34; public const S_DQUOTE = 34;
const NUMBER_SIGN = 35; public const NUMBER_SIGN = 35;
const DOLLAR = 36; public const DOLLAR = 36;
const PERCENTAGE = 37; public const PERCENTAGE = 37;
const AMPERSAND = 38; public const AMPERSAND = 38;
const S_SQUOTE = 39; public const S_SQUOTE = 39;
const S_OPENPARENTHESIS = 40; public const S_OPENPARENTHESIS = 40;
const S_CLOSEPARENTHESIS = 41; public const S_CLOSEPARENTHESIS = 41;
const ASTERISK = 42; public const ASTERISK = 42;
const S_PLUS = 43; public const S_PLUS = 43;
const S_COMMA = 44; public const S_COMMA = 44;
const S_HYPHEN = 45; public const S_HYPHEN = 45;
const S_DOT = 46; public const S_DOT = 46;
const S_SLASH = 47; public const S_SLASH = 47;
const S_COLON = 58; public const S_COLON = 58;
const S_SEMICOLON = 59; public const S_SEMICOLON = 59;
const S_LOWERTHAN = 60; public const S_LOWERTHAN = 60;
const S_EQUAL = 61; public const S_EQUAL = 61;
const S_GREATERTHAN = 62; public const S_GREATERTHAN = 62;
const QUESTIONMARK = 63; public const QUESTIONMARK = 63;
const S_AT = 64; public const S_AT = 64;
const S_OPENBRACKET = 91; public const S_OPENBRACKET = 91;
const S_BACKSLASH = 92; public const S_BACKSLASH = 92;
const S_CLOSEBRACKET = 93; public const S_CLOSEBRACKET = 93;
const CARET = 94; public const CARET = 94;
const S_UNDERSCORE = 95; public const S_UNDERSCORE = 95;
const S_BACKTICK = 96; public const S_BACKTICK = 96;
const S_OPENCURLYBRACES = 123; public const S_OPENCURLYBRACES = 123;
const S_PIPE = 124; public const S_PIPE = 124;
const S_CLOSECURLYBRACES = 125; public const S_CLOSECURLYBRACES = 125;
const S_TILDE = 126; public const S_TILDE = 126;
const C_DEL = 127; public const C_DEL = 127;
const INVERT_QUESTIONMARK= 168; public const INVERT_QUESTIONMARK= 168;
const INVERT_EXCLAMATION = 173; public const INVERT_EXCLAMATION = 173;
const GENERIC = 300; public const GENERIC = 300;
const S_IPV6TAG = 301; public const S_IPV6TAG = 301;
const INVALID = 302; public const INVALID = 302;
const CRLF = 1310; public const CRLF = 1310;
const S_DOUBLECOLON = 5858; public const S_DOUBLECOLON = 5858;
const ASCII_INVALID_FROM = 127; public const ASCII_INVALID_FROM = 127;
const ASCII_INVALID_TO = 199; public const ASCII_INVALID_TO = 199;
/** /**
* US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3) * US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
@ -107,11 +111,11 @@ class EmailLexer extends AbstractLexer
'¡' => self::INVERT_EXCLAMATION, '¡' => self::INVERT_EXCLAMATION,
]; ];
const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu"; public const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu";
const VALID_UTF8_REGEX = '/\p{Cc}+/u'; public const VALID_UTF8_REGEX = '/\p{Cc}+/u';
const CATCHABLE_PATTERNS = [ public const CATCHABLE_PATTERNS = [
'[a-zA-Z]+[46]?', //ASCII and domain literal '[a-zA-Z]+[46]?', //ASCII and domain literal
'[^\x00-\x7F]', //UTF-8 '[^\x00-\x7F]', //UTF-8
'[0-9]+', '[0-9]+',
@ -121,11 +125,11 @@ class EmailLexer extends AbstractLexer
'.', '.',
]; ];
const NON_CATCHABLE_PATTERNS = [ public const NON_CATCHABLE_PATTERNS = [
'[\xA0-\xff]+', '[\xA0-\xff]+',
]; ];
const MODIFIERS = 'iu'; public const MODIFIERS = 'iu';
/** @var bool */ /** @var bool */
protected $hasInvalidTokens = false; protected $hasInvalidTokens = false;
@ -140,18 +144,20 @@ class EmailLexer extends AbstractLexer
/** /**
* The last matched/seen token. * The last matched/seen token.
* *
* @var array * @var array|Token
* *
* @psalm-suppress NonInvariantDocblockPropertyType * @psalm-suppress NonInvariantDocblockPropertyType
* @psalm-var array{value:string, type:null|int, position:int} * @psalm-var array{value:string, type:null|int, position:int}|Token<int, string>
* @psalm-suppress NonInvariantDocblockPropertyType
*/ */
public $token; public $token;
/** /**
* The next token in the input. * The next token in the input.
* *
* @var array{position: int, type: int|null|string, value: int|string}|null * @var array|Token|null
*
* @psalm-suppress NonInvariantDocblockPropertyType
* @psalm-var array{position: int, type: int|null|string, value: int|string}|Token<int, string>|null
*/ */
public $lookahead; public $lookahead;
@ -210,7 +216,9 @@ class EmailLexer extends AbstractLexer
$this->accumulator .= $this->token['value']; $this->accumulator .= $this->token['value'];
} }
$this->previous = $this->token; $this->previous = $this->token instanceof Token
? ['value' => $this->token->value, 'type' => $this->token->type, 'position' => $this->token->position]
: $this->token;
if($this->lookahead === null) { if($this->lookahead === null) {
$this->lookahead = self::$nullToken; $this->lookahead = self::$nullToken;

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator; namespace Egulias\EmailValidator;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\LocalPart; use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Parser\DomainPart; use Egulias\EmailValidator\Parser\DomainPart;
@ -13,7 +12,7 @@ use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class EmailParser extends Parser class EmailParser extends Parser
{ {
const EMAIL_MAX_LENGTH = 254; public const EMAIL_MAX_LENGTH = 254;
/** /**
* @var string * @var string

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator; namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\IDLeftPart; use Egulias\EmailValidator\Parser\IDLeftPart;
use Egulias\EmailValidator\Parser\IDRightPart; use Egulias\EmailValidator\Parser\IDRightPart;
@ -14,7 +13,7 @@ use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class MessageIDParser extends Parser class MessageIDParser extends Parser
{ {
const EMAILID_MAX_LENGTH = 254; public const EMAILID_MAX_LENGTH = 254;
/** /**
* @var string * @var string

View File

@ -59,7 +59,8 @@ class Comment extends PartParser
if($this->openedParenthesis >= 1) { if($this->openedParenthesis >= 1) {
return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']); return new InvalidEmail(new UnclosedComment(), $this->lexer->token['value']);
} else if ($this->openedParenthesis < 0) { }
if ($this->openedParenthesis < 0) {
return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']); return new InvalidEmail(new UnOpenedComment(), $this->lexer->token['value']);
} }

View File

@ -22,9 +22,9 @@ use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
class DomainLiteral extends PartParser class DomainLiteral extends PartParser
{ {
const IPV4_REGEX = '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/'; public const IPV4_REGEX = '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
const OBSOLETE_WARNINGS = [ public const OBSOLETE_WARNINGS = [
EmailLexer::INVALID, EmailLexer::INVALID,
EmailLexer::C_DEL, EmailLexer::C_DEL,
EmailLexer::S_LF, EmailLexer::S_LF,

View File

@ -2,6 +2,7 @@
namespace Egulias\EmailValidator\Parser; namespace Egulias\EmailValidator\Parser;
use Doctrine\Common\Lexer\Token;
use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Warning\TLD; use Egulias\EmailValidator\Warning\TLD;
use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Result\Result;
@ -24,8 +25,8 @@ use Egulias\EmailValidator\Parser\DomainLiteral as DomainLiteralParser;
class DomainPart extends PartParser class DomainPart extends PartParser
{ {
const DOMAIN_MAX_LENGTH = 253; public const DOMAIN_MAX_LENGTH = 253;
const LABEL_MAX_LENGTH = 63; public const LABEL_MAX_LENGTH = 63;
/** /**
* @var string * @var string
@ -212,7 +213,10 @@ class DomainPart extends PartParser
return new ValidEmail(); return new ValidEmail();
} }
private function checkNotAllowedChars(array $token) : Result /**
* @psalm-param array|Token<int, string> $token
*/
private function checkNotAllowedChars($token) : Result
{ {
$notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true];
if (isset($notAllowed[$token['type']])) { if (isset($notAllowed[$token['type']])) {

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator\Parser; namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Parser\Parser;
use Egulias\EmailValidator\Result\ValidEmail; use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Warning\CFWSWithFWS; use Egulias\EmailValidator\Warning\CFWSWithFWS;

View File

@ -15,7 +15,7 @@ use Egulias\EmailValidator\Result\ValidEmail;
class FoldingWhiteSpace extends PartParser class FoldingWhiteSpace extends PartParser
{ {
const FWS_TYPES = [ public const FWS_TYPES = [
EmailLexer::S_SP, EmailLexer::S_SP,
EmailLexer::S_HTAB, EmailLexer::S_HTAB,
EmailLexer::S_CR, EmailLexer::S_CR,

View File

@ -3,7 +3,6 @@
namespace Egulias\EmailValidator\Parser; namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\CommentsInIDRight; use Egulias\EmailValidator\Result\Reason\CommentsInIDRight;

View File

@ -15,7 +15,7 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
class LocalPart extends PartParser class LocalPart extends PartParser
{ {
const INVALID_TOKENS = [ public const INVALID_TOKENS = [
EmailLexer::S_COMMA => EmailLexer::S_COMMA, EmailLexer::S_COMMA => EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,

View File

@ -4,8 +4,8 @@ namespace Egulias\EmailValidator\Result\Reason;
class CRLFAtTheEnd implements Reason class CRLFAtTheEnd implements Reason
{ {
const CODE = 149; public const CODE = 149;
const REASON = "CRLF at the end"; public const REASON = "CRLF at the end";
public function code() : int public function code() : int
{ {

View File

@ -1,7 +1,6 @@
<?php <?php
namespace Egulias\EmailValidator\Result; namespace Egulias\EmailValidator\Result;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\SpoofEmail as ReasonSpoofEmail; use Egulias\EmailValidator\Result\Reason\SpoofEmail as ReasonSpoofEmail;
class SpoofEmail extends InvalidEmail class SpoofEmail extends InvalidEmail

View File

@ -2,7 +2,6 @@
namespace Egulias\EmailValidator\Validation; namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\Validation\DNSGetRecordWrapper;
use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\DomainAcceptsNoMail; use Egulias\EmailValidator\Result\Reason\DomainAcceptsNoMail;
@ -22,7 +21,7 @@ class DNSCheckValidation implements EmailValidation
* Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2), * Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2),
* mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G) * mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G)
*/ */
const RESERVED_DNS_TOP_LEVEL_NAMES = [ public const RESERVED_DNS_TOP_LEVEL_NAMES = [
// Reserved Top Level DNS Names // Reserved Top Level DNS Names
'test', 'test',
'example', 'example',
@ -61,7 +60,7 @@ class DNSCheckValidation implements EmailValidation
*/ */
private $dnsGetRecord; private $dnsGetRecord;
public function __construct(DNSGetRecordWrapper $dnsGetRecord = null) public function __construct(?DNSGetRecordWrapper $dnsGetRecord = null)
{ {
if (!function_exists('idn_to_ascii')) { if (!function_exists('idn_to_ascii')) {
throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__)); throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__));

View File

@ -9,7 +9,7 @@ class EmptyValidationList extends \InvalidArgumentException
/** /**
* @param int $code * @param int $code
*/ */
public function __construct($code = 0, Exception $previous = null) public function __construct($code = 0, ?Exception $previous = null)
{ {
parent::__construct("Empty validation list is not allowed", $code, $previous); parent::__construct("Empty validation list is not allowed", $code, $previous);
} }

View File

@ -13,13 +13,13 @@ class MultipleValidationWithAnd implements EmailValidation
* If one of validations fails, the remaining validations will be skipped. * If one of validations fails, the remaining validations will be skipped.
* This means MultipleErrors will only contain a single error, the first found. * This means MultipleErrors will only contain a single error, the first found.
*/ */
const STOP_ON_ERROR = 0; public const STOP_ON_ERROR = 0;
/** /**
* All of validations will be invoked even if one of them got failure. * All of validations will be invoked even if one of them got failure.
* So MultipleErrors will contain all causes. * So MultipleErrors will contain all causes.
*/ */
const ALLOW_ALL_ERRORS = 1; public const ALLOW_ALL_ERRORS = 1;
/** /**
* @var EmailValidation[] * @var EmailValidation[]

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class AddressLiteral extends Warning class AddressLiteral extends Warning
{ {
const CODE = 12; public const CODE = 12;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class CFWSNearAt extends Warning class CFWSNearAt extends Warning
{ {
const CODE = 49; public const CODE = 49;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class CFWSWithFWS extends Warning class CFWSWithFWS extends Warning
{ {
const CODE = 18; public const CODE = 18;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class Comment extends Warning class Comment extends Warning
{ {
const CODE = 17; public const CODE = 17;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class DeprecatedComment extends Warning class DeprecatedComment extends Warning
{ {
const CODE = 37; public const CODE = 37;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class DomainLiteral extends Warning class DomainLiteral extends Warning
{ {
const CODE = 70; public const CODE = 70;
public function __construct() public function __construct()
{ {

View File

@ -6,7 +6,7 @@ use Egulias\EmailValidator\EmailParser;
class EmailTooLong extends Warning class EmailTooLong extends Warning
{ {
const CODE = 66; public const CODE = 66;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6BadChar extends Warning class IPV6BadChar extends Warning
{ {
const CODE = 74; public const CODE = 74;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6ColonEnd extends Warning class IPV6ColonEnd extends Warning
{ {
const CODE = 77; public const CODE = 77;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6ColonStart extends Warning class IPV6ColonStart extends Warning
{ {
const CODE = 76; public const CODE = 76;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6Deprecated extends Warning class IPV6Deprecated extends Warning
{ {
const CODE = 13; public const CODE = 13;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6DoubleColon extends Warning class IPV6DoubleColon extends Warning
{ {
const CODE = 73; public const CODE = 73;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6GroupCount extends Warning class IPV6GroupCount extends Warning
{ {
const CODE = 72; public const CODE = 72;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class IPV6MaxGroups extends Warning class IPV6MaxGroups extends Warning
{ {
const CODE = 75; public const CODE = 75;
public function __construct() public function __construct()
{ {

View File

@ -4,8 +4,8 @@ namespace Egulias\EmailValidator\Warning;
class LocalTooLong extends Warning class LocalTooLong extends Warning
{ {
const CODE = 64; public const CODE = 64;
const LOCAL_PART_LENGTH = 64; public const LOCAL_PART_LENGTH = 64;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class NoDNSMXRecord extends Warning class NoDNSMXRecord extends Warning
{ {
const CODE = 6; public const CODE = 6;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class ObsoleteDTEXT extends Warning class ObsoleteDTEXT extends Warning
{ {
const CODE = 71; public const CODE = 71;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class QuotedPart extends Warning class QuotedPart extends Warning
{ {
const CODE = 36; public const CODE = 36;
/** /**
* @param scalar $prevToken * @param scalar $prevToken

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class QuotedString extends Warning class QuotedString extends Warning
{ {
const CODE = 11; public const CODE = 11;
/** /**
* @param scalar $prevToken * @param scalar $prevToken

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
class TLD extends Warning class TLD extends Warning
{ {
const CODE = 9; public const CODE = 9;
public function __construct() public function __construct()
{ {

View File

@ -4,7 +4,7 @@ namespace Egulias\EmailValidator\Warning;
abstract class Warning abstract class Warning
{ {
const CODE = 0; public const CODE = 0;
/** /**
* @var string * @var string

View File

@ -16,7 +16,7 @@
- Probably the world's most popular code for sending email from PHP! - Probably the world's most popular code for sending email from PHP!
- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more - Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! and many more
- Integrated SMTP support send without a local mail server - Integrated SMTP support send without a local mail server
- Send emails with multiple To, CC, BCC and Reply-to addresses - Send emails with multiple To, CC, BCC, and Reply-to addresses
- Multipart/alternative emails for mail clients that do not read HTML email - Multipart/alternative emails for mail clients that do not read HTML email
- Add attachments, including inline - Add attachments, including inline
- Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings - Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings
@ -25,7 +25,7 @@
- Protects against header injection attacks - Protects against header injection attacks
- Error messages in over 50 languages! - Error messages in over 50 languages!
- DKIM and S/MIME signing support - DKIM and S/MIME signing support
- Compatible with PHP 5.5 and later, including PHP 8.1 - Compatible with PHP 5.5 and later, including PHP 8.2
- Namespaced to prevent name clashes - Namespaced to prevent name clashes
- Much more! - Much more!
@ -38,7 +38,7 @@ The PHP `mail()` function usually sends via a local mail server, typically front
*Please* don't be tempted to do it yourself if you don't use PHPMailer, there are many other excellent libraries that *Please* don't be tempted to do it yourself if you don't use PHPMailer, there are many other excellent libraries that
you should look at before rolling your own. Try [SwiftMailer](https://swiftmailer.symfony.com/) you should look at before rolling your own. Try [SwiftMailer](https://swiftmailer.symfony.com/)
, [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail) etc. , [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail), etc.
## License ## License
This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution. This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution.
@ -47,7 +47,7 @@ This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lg
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file: PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
```json ```json
"phpmailer/phpmailer": "^6.5" "phpmailer/phpmailer": "^6.7.1"
``` ```
or run or run
@ -136,14 +136,14 @@ try {
} }
``` ```
You'll find plenty to play with in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder, which covers many common scenarios including sending through gmail, building contact forms, sending to mailing lists, and more. You'll find plenty to play with in the [examples](https://github.com/PHPMailer/PHPMailer/tree/master/examples) folder, which covers many common scenarios including sending through Gmail, building contact forms, sending to mailing lists, and more.
If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See [the mailing list example](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps) for further guidance. If you are re-using the instance (e.g. when sending to a mailing list), you may need to clear the recipient list to avoid sending duplicate messages. See [the mailing list example](https://github.com/PHPMailer/PHPMailer/blob/master/examples/mailing_list.phps) for further guidance.
That's it. You should now be ready to use PHPMailer! That's it. You should now be ready to use PHPMailer!
## Localization ## Localization
PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this: PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder, you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this:
```php ```php
//To load the French version //To load the French version
@ -178,9 +178,9 @@ Please disclose any vulnerabilities found responsibly report security issues
See [SECURITY](https://github.com/PHPMailer/PHPMailer/tree/master/SECURITY.md) and [PHPMailer's security advisories on GitHub](https://github.com/PHPMailer/PHPMailer/security). See [SECURITY](https://github.com/PHPMailer/PHPMailer/tree/master/SECURITY.md) and [PHPMailer's security advisories on GitHub](https://github.com/PHPMailer/PHPMailer/security).
## Contributing ## Contributing
Please submit bug reports, suggestions and pull requests to the [GitHub issue tracker](https://github.com/PHPMailer/PHPMailer/issues). Please submit bug reports, suggestions, and pull requests to the [GitHub issue tracker](https://github.com/PHPMailer/PHPMailer/issues).
We're particularly interested in fixing edge-cases, expanding test coverage and updating translations. We're particularly interested in fixing edge cases, expanding test coverage, and updating translations.
If you found a mistake in the docs, or want to add something, go ahead and amend the wiki anyone can edit it. If you found a mistake in the docs, or want to add something, go ahead and amend the wiki anyone can edit it.
@ -204,7 +204,7 @@ Donations are very welcome, whether in beer 🍺, T-shirts 👕, or cold, hard c
Available as part of the Tidelift Subscription. Available as part of the Tidelift Subscription.
The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial The maintainers of PHPMailer and thousands of other packages are working with Tidelift to deliver commercial
support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and support and maintenance for the open-source packages you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact packages you improve code health, while paying the maintainers of the exact packages you
use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-phpmailer?utm_source=packagist-phpmailer-phpmailer&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-phpmailer?utm_source=packagist-phpmailer-phpmailer&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
@ -222,9 +222,9 @@ See [changelog](changelog.md).
### What's changed since moving from SourceForge? ### What's changed since moving from SourceForge?
- Official successor to the SourceForge and Google Code projects. - Official successor to the SourceForge and Google Code projects.
- Test suite. - Test suite.
- Continuous integration with Github Actions. - Continuous integration with GitHub Actions.
- Composer support. - Composer support.
- Public development. - Public development.
- Additional languages and language strings. - Additional languages and language strings.
- CRAM-MD5 authentication support. - CRAM-MD5 authentication support.
- Preserves full repo history of authors, commits and branches from the original SourceForge project. - Preserves full repo history of authors, commits, and branches from the original SourceForge project.

View File

@ -1 +1 @@
6.6.4 6.7.1

View File

@ -37,21 +37,23 @@
"ext-hash": "*" "ext-hash": "*"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.6.2", "squizlabs/php_codesniffer": "^3.7.1",
"yoast/phpunit-polyfills": "^1.0.0" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging", "psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
}, },
"autoload": { "autoload": {

View File

@ -44,6 +44,8 @@ use League\OAuth2\Client\Provider\Google;
use Hayageek\OAuth2\Client\Provider\Yahoo; use Hayageek\OAuth2\Client\Provider\Yahoo;
//@see https://github.com/stevenmaguire/oauth2-microsoft //@see https://github.com/stevenmaguire/oauth2-microsoft
use Stevenmaguire\OAuth2\Client\Provider\Microsoft; use Stevenmaguire\OAuth2\Client\Provider\Microsoft;
//@see https://github.com/greew/oauth2-azure-provider
use Greew\OAuth2\Client\Provider\Azure;
if (!isset($_GET['code']) && !isset($_POST['provider'])) { if (!isset($_GET['code']) && !isset($_POST['provider'])) {
?> ?>
@ -57,11 +59,14 @@ if (!isset($_GET['code']) && !isset($_POST['provider'])) {
<label for="providerYahoo">Yahoo</label><br> <label for="providerYahoo">Yahoo</label><br>
<input type="radio" name="provider" value="Microsoft" id="providerMicrosoft"> <input type="radio" name="provider" value="Microsoft" id="providerMicrosoft">
<label for="providerMicrosoft">Microsoft</label><br> <label for="providerMicrosoft">Microsoft</label><br>
<input type="radio" name="provider" value="Azure" id="providerAzure">
<label for="providerAzure">Azure</label><br>
<h1>Enter id and secret</h1> <h1>Enter id and secret</h1>
<p>These details are obtained by setting up an app in your provider's developer console. <p>These details are obtained by setting up an app in your provider's developer console.
</p> </p>
<p>ClientId: <input type="text" name="clientId"><p> <p>ClientId: <input type="text" name="clientId"><p>
<p>ClientSecret: <input type="text" name="clientSecret"></p> <p>ClientSecret: <input type="text" name="clientSecret"></p>
<p>TenantID (only relevant for Azure): <input type="text" name="tenantId"></p>
<input type="submit" value="Continue"> <input type="submit" value="Continue">
</form> </form>
</body> </body>
@ -77,18 +82,22 @@ session_start();
$providerName = ''; $providerName = '';
$clientId = ''; $clientId = '';
$clientSecret = ''; $clientSecret = '';
$tenantId = '';
if (array_key_exists('provider', $_POST)) { if (array_key_exists('provider', $_POST)) {
$providerName = $_POST['provider']; $providerName = $_POST['provider'];
$clientId = $_POST['clientId']; $clientId = $_POST['clientId'];
$clientSecret = $_POST['clientSecret']; $clientSecret = $_POST['clientSecret'];
$tenantId = $_POST['tenantId'];
$_SESSION['provider'] = $providerName; $_SESSION['provider'] = $providerName;
$_SESSION['clientId'] = $clientId; $_SESSION['clientId'] = $clientId;
$_SESSION['clientSecret'] = $clientSecret; $_SESSION['clientSecret'] = $clientSecret;
$_SESSION['tenantId'] = $tenantId;
} elseif (array_key_exists('provider', $_SESSION)) { } elseif (array_key_exists('provider', $_SESSION)) {
$providerName = $_SESSION['provider']; $providerName = $_SESSION['provider'];
$clientId = $_SESSION['clientId']; $clientId = $_SESSION['clientId'];
$clientSecret = $_SESSION['clientSecret']; $clientSecret = $_SESSION['clientSecret'];
$tenantId = $_SESSION['tenantId'];
} }
//If you don't want to use the built-in form, set your client id and secret here //If you don't want to use the built-in form, set your client id and secret here
@ -130,6 +139,17 @@ switch ($providerName) {
] ]
]; ];
break; break;
case 'Azure':
$params['tenantId'] = $tenantId;
$provider = new Azure($params);
$options = [
'scope' => [
'https://outlook.office.com/SMTP.Send',
'offline_access'
]
];
break;
} }
if (null === $provider) { if (null === $provider) {

View File

@ -14,16 +14,22 @@ $PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data blev ikke accepteret.
$PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold'; $PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold';
$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; $PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: ';
$PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: '; $PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: ';
$PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: ';
$PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: '; $PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: ';
$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; $PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: ';
$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; $PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: ';
$PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.'; $PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.';
$PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: '; $PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: ';
$PHPMAILER_LANG['invalid_header'] = 'Ugyldig header navn eller værdi';
$PHPMAILER_LANG['invalid_hostentry'] = 'Ugyldig hostentry: ';
$PHPMAILER_LANG['invalid_host'] = 'Ugyldig vært: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; $PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.';
$PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.'; $PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; $PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere fejlede: ';
$PHPMAILER_LANG['signing'] = 'Signeringsfejl: '; $PHPMAILER_LANG['signing'] = 'Signeringsfejl: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP kode: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Yderligere SMTP info: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.'; $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalje: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: '; $PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: ';
$PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: '; $PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: ';
$PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: ';

View File

@ -4,6 +4,7 @@
* Spanish PHPMailer language file: refer to English translation for definitive list * Spanish PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer * @package PHPMailer
* @author Matt Sturdy <matt.sturdy@gmail.com> * @author Matt Sturdy <matt.sturdy@gmail.com>
* @author Crystopher Glodzienski Cardoso <crystopher.glodzienski@gmail.com>
*/ */
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.'; $PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
@ -25,3 +26,6 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: '; $PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: '; $PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: '; $PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['smtp_code'] = 'Código del servidor SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Información adicional del servidor SMTP: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';

View File

@ -9,19 +9,18 @@ $PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzi
$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.'; $PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.';
$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.'; $PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.';
$PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.'; $PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.';
$PHPMAILER_LANG['encoding'] = 'Nieznany sposób kodowania znaków: '; $PHPMAILER_LANG['encoding'] = 'Błędny sposób kodowania znaków: ';
$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: '; $PHPMAILER_LANG['execute'] = 'Nie można uruchomić: ';
$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: '; $PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: ';
$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: '; $PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: ';
$PHPMAILER_LANG['from_failed'] = 'Następujący adres Nadawcy jest nieprawidłowy: '; $PHPMAILER_LANG['from_failed'] = 'Następujący adres nadawcy jest nieprawidłowy lub nie istnieje: ';
$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.'; $PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.';
$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, ' . $PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, ' . 'następujący adres odbiorcy jest nieprawidłowy lub nie istnieje: ';
'następujący adres Odbiorcy jest nieprawidłowy: '; $PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email odbiorcy.';
$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email Odbiorcy.';
$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.'; $PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.';
$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: '; $PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi lub nie istnieją: ';
$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: '; $PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() zakończone niepowodzeniem.'; $PHPMAILER_LANG['smtp_connect_failed'] = 'Wywołanie funkcji SMTP Connect() zostało zakończone niepowodzeniem.';
$PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: '; $PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: '; $PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: ';
$PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: '; $PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: ';

View File

@ -750,7 +750,7 @@ class PHPMailer
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* Error severity: message only, continue processing. * Error severity: message only, continue processing.
@ -858,7 +858,7 @@ class PHPMailer
private function mailPassthru($to, $subject, $body, $header, $params) private function mailPassthru($to, $subject, $body, $header, $params)
{ {
//Check overloading of mail function to avoid double-encoding //Check overloading of mail function to avoid double-encoding
if (ini_get('mbstring.func_overload') & 1) { if ((int)ini_get('mbstring.func_overload') & 1) {
$subject = $this->secureHeader($subject); $subject = $this->secureHeader($subject);
} else { } else {
$subject = $this->encodeHeader($this->secureHeader($subject)); $subject = $this->encodeHeader($this->secureHeader($subject));
@ -1124,6 +1124,22 @@ class PHPMailer
return call_user_func_array([$this, 'addAnAddress'], $params); return call_user_func_array([$this, 'addAnAddress'], $params);
} }
/**
* Set the boundaries to use for delimiting MIME parts.
* If you override this, ensure you set all 3 boundaries to unique values.
* The default boundaries include a "=_" sequence which cannot occur in quoted-printable bodies,
* as suggested by https://www.rfc-editor.org/rfc/rfc2045#section-6.7
*
* @return void
*/
public function setBoundaries()
{
$this->uniqueid = $this->generateId();
$this->boundary[1] = 'b1=_' . $this->uniqueid;
$this->boundary[2] = 'b2=_' . $this->uniqueid;
$this->boundary[3] = 'b3=_' . $this->uniqueid;
}
/** /**
* Add an address to one of the recipient arrays or to the ReplyTo array. * Add an address to one of the recipient arrays or to the ReplyTo array.
* Addresses that have been added already return false, but do not throw exceptions. * Addresses that have been added already return false, but do not throw exceptions.
@ -1671,11 +1687,11 @@ class PHPMailer
return $this->mailSend($this->MIMEHeader, $this->MIMEBody); return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
} }
} catch (Exception $exc) { } catch (Exception $exc) {
if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true) {
$this->smtp->reset();
}
$this->setError($exc->getMessage()); $this->setError($exc->getMessage());
$this->edebug($exc->getMessage()); $this->edebug($exc->getMessage());
if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true && $this->smtp->connected()) {
$this->smtp->reset();
}
if ($this->exceptions) { if ($this->exceptions) {
throw $exc; throw $exc;
} }
@ -1863,7 +1879,7 @@ class PHPMailer
if (!static::isPermittedPath($path)) { if (!static::isPermittedPath($path)) {
return false; return false;
} }
$readable = file_exists($path); $readable = is_file($path);
//If not a UNC path (expected to start with \\), check read permission, see #2069 //If not a UNC path (expected to start with \\), check read permission, see #2069
if (strpos($path, '\\\\') !== 0) { if (strpos($path, '\\\\') !== 0) {
$readable = $readable && is_readable($path); $readable = $readable && is_readable($path);
@ -2101,6 +2117,9 @@ class PHPMailer
$this->smtp->setDebugLevel($this->SMTPDebug); $this->smtp->setDebugLevel($this->SMTPDebug);
$this->smtp->setDebugOutput($this->Debugoutput); $this->smtp->setDebugOutput($this->Debugoutput);
$this->smtp->setVerp($this->do_verp); $this->smtp->setVerp($this->do_verp);
if ($this->Host === null) {
$this->Host = 'localhost';
}
$hosts = explode(';', $this->Host); $hosts = explode(';', $this->Host);
$lastexception = null; $lastexception = null;
@ -2791,10 +2810,7 @@ class PHPMailer
{ {
$body = ''; $body = '';
//Create unique IDs and preset boundaries //Create unique IDs and preset boundaries
$this->uniqueid = $this->generateId(); $this->setBoundaries();
$this->boundary[1] = 'b1_' . $this->uniqueid;
$this->boundary[2] = 'b2_' . $this->uniqueid;
$this->boundary[3] = 'b3_' . $this->uniqueid;
if ($this->sign_key_file) { if ($this->sign_key_file) {
$body .= $this->getMailMIME() . static::$LE; $body .= $this->getMailMIME() . static::$LE;
@ -2830,7 +2846,7 @@ class PHPMailer
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE; $altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
} }
//Use this as a preamble in all multipart message types //Use this as a preamble in all multipart message types
$mimepre = 'This is a multi-part message in MIME format.' . static::$LE . static::$LE; $mimepre = '';
switch ($this->message_type) { switch ($this->message_type) {
case 'inline': case 'inline':
$body .= $mimepre; $body .= $mimepre;
@ -3066,6 +3082,18 @@ class PHPMailer
return $body; return $body;
} }
/**
* Get the boundaries that this message will use
* @return array
*/
public function getBoundaries()
{
if (empty($this->boundary)) {
$this->setBoundaries();
}
return $this->boundary;
}
/** /**
* Return the start of a message boundary. * Return the start of a message boundary.
* *
@ -4183,6 +4211,7 @@ class PHPMailer
* @param string $name Custom header name * @param string $name Custom header name
* @param string|null $value Header value * @param string|null $value Header value
* *
* @return bool True if a header was set successfully
* @throws Exception * @throws Exception
*/ */
public function addCustomHeader($name, $value = null) public function addCustomHeader($name, $value = null)
@ -4632,15 +4661,27 @@ class PHPMailer
} }
/** /**
* Remove trailing breaks from a string. * Remove trailing whitespace from a string.
*
* @param string $text
*
* @return string The text to remove whitespace from
*/
public static function stripTrailingWSP($text)
{
return rtrim($text, " \r\n\t");
}
/**
* Strip trailing line breaks from a string.
* *
* @param string $text * @param string $text
* *
* @return string The text to remove breaks from * @return string The text to remove breaks from
*/ */
public static function stripTrailingWSP($text) public static function stripTrailingBreaks($text)
{ {
return rtrim($text, " \r\n\t"); return rtrim($text, "\r\n");
} }
/** /**
@ -4806,7 +4847,7 @@ class PHPMailer
$body = static::normalizeBreaks($body, self::CRLF); $body = static::normalizeBreaks($body, self::CRLF);
//Reduce multiple trailing line breaks to a single one //Reduce multiple trailing line breaks to a single one
return static::stripTrailingWSP($body) . self::CRLF; return static::stripTrailingBreaks($body) . self::CRLF;
} }
/** /**

View File

@ -46,7 +46,7 @@ class POP3
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* Default POP3 port number. * Default POP3 port number.
@ -337,7 +337,12 @@ class POP3
*/ */
public function disconnect() public function disconnect()
{ {
$this->sendString('QUIT'); // If could not connect at all, no need to disconnect
if ($this->pop_conn === false) {
return;
}
$this->sendString('QUIT' . static::LE);
// RFC 1939 shows POP3 server sending a +OK response to the QUIT command. // RFC 1939 shows POP3 server sending a +OK response to the QUIT command.
// Try to get it. Ignore any failures here. // Try to get it. Ignore any failures here.

View File

@ -35,7 +35,7 @@ class SMTP
* *
* @var string * @var string
*/ */
const VERSION = '6.6.4'; const VERSION = '6.7.1';
/** /**
* SMTP line break constant. * SMTP line break constant.
@ -682,7 +682,6 @@ class SMTP
*/ */
public function close() public function close()
{ {
$this->setError('');
$this->server_caps = null; $this->server_caps = null;
$this->helo_rply = null; $this->helo_rply = null;
if (is_resource($this->smtp_conn)) { if (is_resource($this->smtp_conn)) {

View File

@ -10,4 +10,7 @@ interface that describes a HTTP message. See the specification for more details.
Usage Usage
----- -----
We'll certainly need some stuff in here. Before reading the usage guide we recommend reading the PSR-7 interfaces method list:
* [`PSR-7 Interfaces Method List`](docs/PSR7-Interfaces.md)
* [`PSR-7 Usage Guide`](docs/PSR7-Usage.md)

View File

@ -11,7 +11,7 @@
} }
], ],
"require": { "require": {
"php": ">=5.3.0" "php": "^7.2 || ^8.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -20,7 +20,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.1.x-dev"
} }
} }
} }

View File

@ -0,0 +1,130 @@
# Interfaces
The purpose of this list is to help in finding the methods when working with PSR-7. This can be considered as a cheatsheet for PSR-7 interfaces.
The interfaces defined in PSR-7 are the following:
| Class Name | Description |
|---|---|
| [Psr\Http\Message\MessageInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagemessageinterface) | Representation of a HTTP message |
| [Psr\Http\Message\RequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagerequestinterface) | Representation of an outgoing, client-side request. |
| [Psr\Http\Message\ServerRequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageserverrequestinterface) | Representation of an incoming, server-side HTTP request. |
| [Psr\Http\Message\ResponseInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageresponseinterface) | Representation of an outgoing, server-side response. |
| [Psr\Http\Message\StreamInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface) | Describes a data stream |
| [Psr\Http\Message\UriInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuriinterface) | Value object representing a URI. |
| [Psr\Http\Message\UploadedFileInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuploadedfileinterface) | Value object representing a file uploaded through an HTTP request. |
## `Psr\Http\Message\MessageInterface` Methods
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getProtocolVersion()` | Retrieve HTTP protocol version | 1.0 or 1.1 |
| `withProtocolVersion($version)` | Returns new message instance with given HTTP protocol version | |
| `getHeaders()` | Retrieve all HTTP Headers | [Request Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields), [Response Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields) |
| `hasHeader($name)` | Checks if HTTP Header with given name exists | |
| `getHeader($name)` | Retrieves a array with the values for a single header | |
| `getHeaderLine($name)` | Retrieves a comma-separated string of the values for a single header | |
| `withHeader($name, $value)` | Returns new message instance with given HTTP Header | if the header existed in the original instance, replaces the header value from the original message with the value provided when creating the new instance. |
| `withAddedHeader($name, $value)` | Returns new message instance with appended value to given header | If header already exists value will be appended, if not a new header will be created |
| `withoutHeader($name)` | Removes HTTP Header with given name| |
| `getBody()` | Retrieves the HTTP Message Body | Returns object implementing `StreamInterface`|
| `withBody(StreamInterface $body)` | Returns new message instance with given HTTP Message Body | |
## `Psr\Http\Message\RequestInterface` Methods
Same methods as `Psr\Http\Message\MessageInterface` + the following methods:
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getRequestTarget()` | Retrieves the message's request target | origin-form, absolute-form, authority-form, asterisk-form ([RFC7230](https://www.rfc-editor.org/rfc/rfc7230.txt)) |
| `withRequestTarget($requestTarget)` | Return a new message instance with the specific request-target | |
| `getMethod()` | Retrieves the HTTP method of the request. | GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE (defined in [RFC7231](https://tools.ietf.org/html/rfc7231)), PATCH (defined in [RFC5789](https://tools.ietf.org/html/rfc5789)) |
| `withMethod($method)` | Returns a new message instance with the provided HTTP method | |
| `getUri()` | Retrieves the URI instance | |
| `withUri(UriInterface $uri, $preserveHost = false)` | Returns a new message instance with the provided URI | |
## `Psr\Http\Message\ServerRequestInterface` Methods
Same methods as `Psr\Http\Message\RequestInterface` + the following methods:
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getServerParams() ` | Retrieve server parameters | Typically derived from `$_SERVER` |
| `getCookieParams()` | Retrieves cookies sent by the client to the server. | Typically derived from `$_COOKIES` |
| `withCookieParams(array $cookies)` | Returns a new request instance with the specified cookies | |
| `withQueryParams(array $query)` | Returns a new request instance with the specified query string arguments | |
| `getUploadedFiles()` | Retrieve normalized file upload data | |
| `withUploadedFiles(array $uploadedFiles)` | Returns a new request instance with the specified uploaded files | |
| `getParsedBody()` | Retrieve any parameters provided in the request body | |
| `withParsedBody($data)` | Returns a new request instance with the specified body parameters | |
| `getAttributes()` | Retrieve attributes derived from the request | |
| `getAttribute($name, $default = null)` | Retrieve a single derived request attribute | |
| `withAttribute($name, $value)` | Returns a new request instance with the specified derived request attribute | |
| `withoutAttribute($name)` | Returns a new request instance that without the specified derived request attribute | |
## `Psr\Http\Message\ResponseInterface` Methods:
Same methods as `Psr\Http\Message\MessageInterface` + the following methods:
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getStatusCode()` | Gets the response status code. | |
| `withStatus($code, $reasonPhrase = '')` | Returns a new response instance with the specified status code and, optionally, reason phrase. | |
| `getReasonPhrase()` | Gets the response reason phrase associated with the status code. | |
## `Psr\Http\Message\StreamInterface` Methods
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `__toString()` | Reads all data from the stream into a string, from the beginning to end. | |
| `close()` | Closes the stream and any underlying resources. | |
| `detach()` | Separates any underlying resources from the stream. | |
| `getSize()` | Get the size of the stream if known. | |
| `eof()` | Returns true if the stream is at the end of the stream.| |
| `isSeekable()` | Returns whether or not the stream is seekable. | |
| `seek($offset, $whence = SEEK_SET)` | Seek to a position in the stream. | |
| `rewind()` | Seek to the beginning of the stream. | |
| `isWritable()` | Returns whether or not the stream is writable. | |
| `write($string)` | Write data to the stream. | |
| `isReadable()` | Returns whether or not the stream is readable. | |
| `read($length)` | Read data from the stream. | |
| `getContents()` | Returns the remaining contents in a string | |
| `getMetadata($key = null)()` | Get stream metadata as an associative array or retrieve a specific key. | |
## `Psr\Http\Message\UriInterface` Methods
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getScheme()` | Retrieve the scheme component of the URI. | |
| `getAuthority()` | Retrieve the authority component of the URI. | |
| `getUserInfo()` | Retrieve the user information component of the URI. | |
| `getHost()` | Retrieve the host component of the URI. | |
| `getPort()` | Retrieve the port component of the URI. | |
| `getPath()` | Retrieve the path component of the URI. | |
| `getQuery()` | Retrieve the query string of the URI. | |
| `getFragment()` | Retrieve the fragment component of the URI. | |
| `withScheme($scheme)` | Return an instance with the specified scheme. | |
| `withUserInfo($user, $password = null)` | Return an instance with the specified user information. | |
| `withHost($host)` | Return an instance with the specified host. | |
| `withPort($port)` | Return an instance with the specified port. | |
| `withPath($path)` | Return an instance with the specified path. | |
| `withQuery($query)` | Return an instance with the specified query string. | |
| `withFragment($fragment)` | Return an instance with the specified URI fragment. | |
| `__toString()` | Return the string representation as a URI reference. | |
## `Psr\Http\Message\UploadedFileInterface` Methods
| Method Name | Description | Notes |
|------------------------------------| ----------- | ----- |
| `getStream()` | Retrieve a stream representing the uploaded file. | |
| `moveTo($targetPath)` | Move the uploaded file to a new location. | |
| `getSize()` | Retrieve the file size. | |
| `getError()` | Retrieve the error associated with the uploaded file. | |
| `getClientFilename()` | Retrieve the filename sent by the client. | |
| `getClientMediaType()` | Retrieve the media type sent by the client. | |
> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.

View File

@ -0,0 +1,159 @@
### PSR-7 Usage
All PSR-7 applications comply with these interfaces
They were created to establish a standard between middleware implementations.
> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.
The following examples will illustrate how basic operations are done in PSR-7.
##### Examples
For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc)
All PSR-7 implementations should have the same behaviour.
The following will be assumed:
`$request` is an object of `Psr\Http\Message\RequestInterface` and
`$response` is an object implementing `Psr\Http\Message\RequestInterface`
### Working with HTTP Headers
#### Adding headers to response:
```php
$response->withHeader('My-Custom-Header', 'My Custom Message');
```
#### Appending values to headers
```php
$response->withAddedHeader('My-Custom-Header', 'The second message');
```
#### Checking if header exists:
```php
$request->hasHeader('My-Custom-Header'); // will return false
$response->hasHeader('My-Custom-Header'); // will return true
```
> Note: My-Custom-Header was only added in the Response
#### Getting comma-separated values from a header (also applies to request)
```php
// getting value from request headers
$request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8"
// getting value from response headers
$response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message"
```
#### Getting array of value from a header (also applies to request)
```php
// getting value from request headers
$request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"]
// getting value from response headers
$response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"]
```
#### Removing headers from HTTP Messages
```php
// removing a header from Request, removing deprecated "Content-MD5" header
$request->withoutHeader('Content-MD5');
// removing a header from Response
// effect: the browser won't know the size of the stream
// the browser will download the stream till it ends
$response->withoutHeader('Content-Length');
```
### Working with HTTP Message Body
When working with the PSR-7 there are two methods of implementation:
#### 1. Getting the body separately
> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented.
```php
$body = $response->getBody();
// operations on body, eg. read, write, seek
// ...
// replacing the old body
$response->withBody($body);
// this last statement is optional as we working with objects
// in this case the "new" body is same with the "old" one
// the $body variable has the same value as the one in $request, only the reference is passed
```
#### 2. Working directly on response
> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required
```php
$response->getBody()->write('hello');
```
### Getting the body contents
The following snippet gets the contents of a stream contents.
> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream.
```php
$body = $response->getBody();
$body->rewind(); // or $body->seek(0);
$bodyText = $body->getContents();
```
> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended.
### Append to body
```php
$response->getBody()->write('Hello'); // writing directly
$body = $request->getBody(); // which is a `StreamInterface`
$body->write('xxxxx');
```
### Prepend to body
Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended.
The following example will explain the behaviour of streams.
```php
// assuming our response is initially empty
$body = $repsonse->getBody();
// writing the string "abcd"
$body->write('abcd');
// seeking to start of stream
$body->seek(0);
// writing 'ef'
$body->write('ef'); // at this point the stream contains "efcd"
```
#### Prepending by rewriting separately
```php
// assuming our response body stream only contains: "abcd"
$body = $response->getBody();
$body->rewind();
$contents = $body->getContents(); // abcd
// seeking the stream to beginning
$body->rewind();
$body->write('ef'); // stream contains "efcd"
$body->write($contents); // stream contains "efabcd"
```
> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`.
#### Prepending by using contents as a string
```php
$body = $response->getBody();
$body->rewind();
$contents = $body->getContents(); // efabcd
$contents = 'ef'.$contents;
$body->rewind();
$body->write($contents);
```

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -38,7 +40,7 @@ interface MessageInterface
* @param string $version HTTP protocol version * @param string $version HTTP protocol version
* @return static * @return static
*/ */
public function withProtocolVersion($version); public function withProtocolVersion(string $version);
/** /**
* Retrieves all message header values. * Retrieves all message header values.
@ -75,7 +77,7 @@ interface MessageInterface
* name using a case-insensitive string comparison. Returns false if * name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message. * no matching header name is found in the message.
*/ */
public function hasHeader($name); public function hasHeader(string $name);
/** /**
* Retrieves a message header value by the given case-insensitive name. * Retrieves a message header value by the given case-insensitive name.
@ -91,7 +93,7 @@ interface MessageInterface
* header. If the header does not appear in the message, this method MUST * header. If the header does not appear in the message, this method MUST
* return an empty array. * return an empty array.
*/ */
public function getHeader($name); public function getHeader(string $name);
/** /**
* Retrieves a comma-separated string of the values for a single header. * Retrieves a comma-separated string of the values for a single header.
@ -112,7 +114,7 @@ interface MessageInterface
* concatenated together using a comma. If the header does not appear in * concatenated together using a comma. If the header does not appear in
* the message, this method MUST return an empty string. * the message, this method MUST return an empty string.
*/ */
public function getHeaderLine($name); public function getHeaderLine(string $name);
/** /**
* Return an instance with the provided value replacing the specified header. * Return an instance with the provided value replacing the specified header.
@ -129,7 +131,7 @@ interface MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withHeader($name, $value); public function withHeader(string $name, $value);
/** /**
* Return an instance with the specified header appended with the given value. * Return an instance with the specified header appended with the given value.
@ -147,7 +149,7 @@ interface MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withAddedHeader($name, $value); public function withAddedHeader(string $name, $value);
/** /**
* Return an instance without the specified header. * Return an instance without the specified header.
@ -161,7 +163,7 @@ interface MessageInterface
* @param string $name Case-insensitive header field name to remove. * @param string $name Case-insensitive header field name to remove.
* @return static * @return static
*/ */
public function withoutHeader($name); public function withoutHeader(string $name);
/** /**
* Gets the body of the message. * Gets the body of the message.

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -55,10 +57,10 @@ interface RequestInterface extends MessageInterface
* *
* @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
* request-target forms allowed in request messages) * request-target forms allowed in request messages)
* @param mixed $requestTarget * @param string $requestTarget
* @return static * @return static
*/ */
public function withRequestTarget($requestTarget); public function withRequestTarget(string $requestTarget);
/** /**
* Retrieves the HTTP method of the request. * Retrieves the HTTP method of the request.
@ -82,7 +84,7 @@ interface RequestInterface extends MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException for invalid HTTP methods. * @throws \InvalidArgumentException for invalid HTTP methods.
*/ */
public function withMethod($method); public function withMethod(string $method);
/** /**
* Retrieves the URI instance. * Retrieves the URI instance.
@ -125,5 +127,5 @@ interface RequestInterface extends MessageInterface
* @param bool $preserveHost Preserve the original state of the Host header. * @param bool $preserveHost Preserve the original state of the Host header.
* @return static * @return static
*/ */
public function withUri(UriInterface $uri, $preserveHost = false); public function withUri(UriInterface $uri, bool $preserveHost = false);
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -49,7 +51,7 @@ interface ResponseInterface extends MessageInterface
* @return static * @return static
* @throws \InvalidArgumentException For invalid status code arguments. * @throws \InvalidArgumentException For invalid status code arguments.
*/ */
public function withStatus($code, $reasonPhrase = ''); public function withStatus(int $code, string $reasonPhrase = '');
/** /**
* Gets the response reason phrase associated with the status code. * Gets the response reason phrase associated with the status code.

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -224,7 +226,7 @@ interface ServerRequestInterface extends RequestInterface
* @param mixed $default Default value to return if the attribute does not exist. * @param mixed $default Default value to return if the attribute does not exist.
* @return mixed * @return mixed
*/ */
public function getAttribute($name, $default = null); public function getAttribute(string $name, $default = null);
/** /**
* Return an instance with the specified derived request attribute. * Return an instance with the specified derived request attribute.
@ -241,7 +243,7 @@ interface ServerRequestInterface extends RequestInterface
* @param mixed $value The value of the attribute. * @param mixed $value The value of the attribute.
* @return static * @return static
*/ */
public function withAttribute($name, $value); public function withAttribute(string $name, $value);
/** /**
* Return an instance that removes the specified derived request attribute. * Return an instance that removes the specified derived request attribute.
@ -257,5 +259,5 @@ interface ServerRequestInterface extends RequestInterface
* @param string $name The attribute name. * @param string $name The attribute name.
* @return static * @return static
*/ */
public function withoutAttribute($name); public function withoutAttribute(string $name);
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -84,7 +86,7 @@ interface StreamInterface
* SEEK_END: Set position to end-of-stream 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); public function seek(int $offset, int $whence = SEEK_SET);
/** /**
* Seek to the beginning of the stream. * Seek to the beginning of the stream.
@ -112,7 +114,7 @@ interface StreamInterface
* @return int Returns the number of bytes written to the stream. * @return int Returns the number of bytes written to the stream.
* @throws \RuntimeException on failure. * @throws \RuntimeException on failure.
*/ */
public function write($string); public function write(string $string);
/** /**
* Returns whether or not the stream is readable. * Returns whether or not the stream is readable.
@ -131,7 +133,7 @@ interface StreamInterface
* if no bytes are available. * if no bytes are available.
* @throws \RuntimeException if an error occurs. * @throws \RuntimeException if an error occurs.
*/ */
public function read($length); public function read(int $length);
/** /**
* Returns the remaining contents in a string * Returns the remaining contents in a string
@ -149,10 +151,10 @@ interface StreamInterface
* stream_get_meta_data() function. * stream_get_meta_data() function.
* *
* @link http://php.net/manual/en/function.stream-get-meta-data.php * @link http://php.net/manual/en/function.stream-get-meta-data.php
* @param string $key Specific metadata to retrieve. * @param string|null $key Specific metadata to retrieve.
* @return array|mixed|null Returns an associative array if no key is * @return array|mixed|null Returns an associative array if no key is
* provided. Returns a specific key value if a key is provided and the * provided. Returns a specific key value if a key is provided and the
* value is found, or null if the key is not found. * value is found, or null if the key is not found.
*/ */
public function getMetadata($key = null); public function getMetadata(?string $key = null);
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -62,7 +64,7 @@ interface UploadedFileInterface
* @throws \RuntimeException on any error during the move operation, or on * @throws \RuntimeException on any error during the move operation, or on
* the second or subsequent call to the method. * the second or subsequent call to the method.
*/ */
public function moveTo($targetPath); public function moveTo(string $targetPath);
/** /**
* Retrieve the file size. * Retrieve the file size.

View File

@ -1,4 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Psr\Http\Message; namespace Psr\Http\Message;
/** /**
@ -188,7 +191,7 @@ interface UriInterface
* @return static A new instance with the specified scheme. * @return static A new instance with the specified scheme.
* @throws \InvalidArgumentException for invalid or unsupported schemes. * @throws \InvalidArgumentException for invalid or unsupported schemes.
*/ */
public function withScheme($scheme); public function withScheme(string $scheme);
/** /**
* Return an instance with the specified user information. * Return an instance with the specified user information.
@ -204,7 +207,7 @@ interface UriInterface
* @param null|string $password The password associated with $user. * @param null|string $password The password associated with $user.
* @return static A new instance with the specified user information. * @return static A new instance with the specified user information.
*/ */
public function withUserInfo($user, $password = null); public function withUserInfo(string $user, ?string $password = null);
/** /**
* Return an instance with the specified host. * Return an instance with the specified host.
@ -218,7 +221,7 @@ interface UriInterface
* @return static A new instance with the specified host. * @return static A new instance with the specified host.
* @throws \InvalidArgumentException for invalid hostnames. * @throws \InvalidArgumentException for invalid hostnames.
*/ */
public function withHost($host); public function withHost(string $host);
/** /**
* Return an instance with the specified port. * Return an instance with the specified port.
@ -237,7 +240,7 @@ interface UriInterface
* @return static A new instance with the specified port. * @return static A new instance with the specified port.
* @throws \InvalidArgumentException for invalid ports. * @throws \InvalidArgumentException for invalid ports.
*/ */
public function withPort($port); public function withPort(?int $port);
/** /**
* Return an instance with the specified path. * Return an instance with the specified path.
@ -261,7 +264,7 @@ interface UriInterface
* @return static A new instance with the specified path. * @return static A new instance with the specified path.
* @throws \InvalidArgumentException for invalid paths. * @throws \InvalidArgumentException for invalid paths.
*/ */
public function withPath($path); public function withPath(string $path);
/** /**
* Return an instance with the specified query string. * Return an instance with the specified query string.
@ -278,7 +281,7 @@ interface UriInterface
* @return static A new instance with the specified query string. * @return static A new instance with the specified query string.
* @throws \InvalidArgumentException for invalid query strings. * @throws \InvalidArgumentException for invalid query strings.
*/ */
public function withQuery($query); public function withQuery(string $query);
/** /**
* Return an instance with the specified URI fragment. * Return an instance with the specified URI fragment.
@ -294,7 +297,7 @@ interface UriInterface
* @param string $fragment The fragment to use with the new instance. * @param string $fragment The fragment to use with the new instance.
* @return static A new instance with the specified fragment. * @return static A new instance with the specified fragment.
*/ */
public function withFragment($fragment); public function withFragment(string $fragment);
/** /**
* Return the string representation as a URI reference. * Return the string representation as a URI reference.

2
vendor/services.php vendored
View File

@ -1,5 +1,5 @@
<?php <?php
// This file is automatically generated at:2022-11-26 23:54:39 // This file is automatically generated at:2023-05-05 09:47:16
declare (strict_types = 1); declare (strict_types = 1);
return array ( return array (
0 => 'think\\captcha\\CaptchaService', 0 => 'think\\captcha\\CaptchaService',

View File

@ -49,7 +49,7 @@ final class WrappedListener
$r = new \ReflectionFunction($listener); $r = new \ReflectionFunction($listener);
if (str_contains($r->name, '{closure}')) { if (str_contains($r->name, '{closure}')) {
$this->pretty = $this->name = 'closure'; $this->pretty = $this->name = 'closure';
} elseif ($class = $r->getClosureScopeClass()) { } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
$this->name = $class->name; $this->name = $class->name;
$this->pretty = $this->name.'::'.$r->name; $this->pretty = $this->name.'::'.$r->name;
} else { } else {
@ -114,11 +114,13 @@ final class WrappedListener
$e = $this->stopwatch->start($this->name, 'event_listener'); $e = $this->stopwatch->start($this->name, 'event_listener');
try {
($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);
} finally {
if ($e->isStarted()) { if ($e->isStarted()) {
$e->stop(); $e->stop();
} }
}
if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
$this->stoppedPropagation = true; $this->stoppedPropagation = true;

View File

@ -122,7 +122,7 @@ class RegisterListenersPass implements CompilerPassInterface
$dispatcherDefinition = $globalDispatcherDefinition; $dispatcherDefinition = $globalDispatcherDefinition;
if (isset($event['dispatcher'])) { if (isset($event['dispatcher'])) {
$dispatcherDefinition = $container->getDefinition($event['dispatcher']); $dispatcherDefinition = $container->findDefinition($event['dispatcher']);
} }
$dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]); $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
@ -161,7 +161,7 @@ class RegisterListenersPass implements CompilerPassInterface
continue; continue;
} }
$dispatcherDefinitions[$attributes['dispatcher']] = $container->getDefinition($attributes['dispatcher']); $dispatcherDefinitions[$attributes['dispatcher']] = $container->findDefinition($attributes['dispatcher']);
} }
if (!$dispatcherDefinitions) { if (!$dispatcherDefinitions) {

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2022 Fabien Potencier Copyright (c) 2004-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -34,7 +34,7 @@ class BinaryFileResponse extends Response
protected $offset = 0; protected $offset = 0;
protected $maxlen = -1; protected $maxlen = -1;
protected $deleteFileAfterSend = false; protected $deleteFileAfterSend = false;
protected $chunkSize = 8 * 1024; protected $chunkSize = 16 * 1024;
/** /**
* @param \SplFileInfo|string $file The file to stream * @param \SplFileInfo|string $file The file to stream
@ -267,7 +267,7 @@ class BinaryFileResponse extends Response
$range = $request->headers->get('Range'); $range = $request->headers->get('Range');
if (str_starts_with($range, 'bytes=')) { if (str_starts_with($range, 'bytes=')) {
[$start, $end] = explode('-', substr($range, 6), 2) + [0]; [$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0];
$end = ('' === $end) ? $fileSize - 1 : (int) $end; $end = ('' === $end) ? $fileSize - 1 : (int) $end;
@ -341,14 +341,21 @@ class BinaryFileResponse extends Response
$length = $this->maxlen; $length = $this->maxlen;
while ($length && !feof($file)) { while ($length && !feof($file)) {
$read = ($length > $this->chunkSize) ? $this->chunkSize : $length; $read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
$length -= $read;
stream_copy_to_stream($file, $out, $read); if (false === $data = fread($file, $read)) {
if (connection_aborted()) {
break; break;
} }
while ('' !== $data) {
$read = fwrite($out, $data);
if (false === $read || connection_aborted()) {
break;
}
if (0 < $length) {
$length -= $read;
}
$data = substr($data, $read);
}
} }
fclose($out); fclose($out);

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