refactor(web): migrate to parsedown

This commit is contained in:
Baoshuo Ren 2022-10-10 07:35:48 +08:00
parent 63bce3f253
commit 4e4e45160d
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
55 changed files with 2219 additions and 1064 deletions

View File

@ -4,12 +4,9 @@ ARG CLONE_ADDFLAG
ENV DEBIAN_FRONTEND=noninteractive
RUN dpkg -s gnupg 2>/dev/null || (apt-get update && apt-get install -y gnupg) &&\
echo "deb http://ppa.launchpad.net/stesie/libv8/ubuntu bionic main" | tee /etc/apt/sources.list.d/stesie-libv8.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1A10946ED858A0DF &&\
echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu jammy main" | tee /etc/apt/sources.list.d/ondrej-php.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C &&\
apt-get update --allow-unauthenticated &&\
apt-get install -y --allow-unauthenticated -o Dpkg::Options::="--force-overwrite" libv8 php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd libseccomp-dev git vim ntp zip unzip curl wget libapache2-mod-xsendfile mysql-server php-pear cmake fp-compiler re2c libv8-7.5-dev libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk &&\
git clone https://github.com/phpv8/v8js.git --depth=1 -b 2.1.2 /tmp/pear/download/v8js-master && cd /tmp/pear/download/v8js-master &&\
phpize && ./configure --with-php-config=/usr/bin/php-config --with-v8js=/opt/libv8-7.5 && make install && cd -
apt-get install -y --allow-unauthenticated -o Dpkg::Options::="--force-overwrite" php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd libseccomp-dev git vim ntp zip unzip curl wget libapache2-mod-xsendfile mysql-server php-pear cmake fp-compiler re2c libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk
ADD . /opt/uoj
WORKDIR /opt/uoj

View File

@ -2,6 +2,15 @@
"require": {
"gregwar/captcha": "^1.1",
"phpmailer/phpmailer": "^6.6",
"ezyang/htmlpurifier": "^4.16"
}
"ezyang/htmlpurifier": "^4.16",
"erusev/parsedown": "^1.7",
"benjaminhoegh/parsedown-math": "dev-master"
},
"autoload": {
"classmap": [
"vendor/benjaminhoegh/parsedown-math/ParsedownMath.php"
]
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@ -143,7 +143,6 @@ class HTML {
}
public static function purifier() {
include_once $_SERVER['DOCUMENT_ROOT'] . '/app/vendor/htmlpurifier/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
//$config->set('HTML.Doctype', 'HTML 4.01 Transitional');
$config->set('Cache.DefinitionImpl', null);
@ -160,8 +159,6 @@ class HTML {
}
public static function purifier_inline() {
include_once $_SERVER['DOCUMENT_ROOT'] . '/app/vendor/htmlpurifier/HTMLPurifier.auto.php';
$allowed_html = [
'a' => ['href' => 'URI'],
'b' => [],

View File

@ -102,20 +102,19 @@ class UOJBlogEditor {
$this->post_data['is_hidden'] = isset($_POST["{$this->name}_is_hidden"]) ? 1 : 0;
$purifier = HTML::purifier();
$parsedown = new ParsedownMath([
'math' => [
'enabled' => true,
'matchSingleDollar' => true
]
]);
$this->post_data['title'] = HTML::escape($this->post_data['title']);
if ($this->show_editor) {
if ($this->type == 'blog') {
$content_md = $_POST[$this->name . '_content_md'];
try {
$v8 = new V8Js('POST');
$v8->content_md = $this->post_data['content_md'];
$v8->executeString(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/js/marked.js'), 'marked.js');
$this->post_data['content'] = $v8->executeString('marked(POST.content_md)');
} catch (V8JsException $e) {
die(json_encode(array('content_md' => '未知错误')));
}
$this->post_data['content'] = $parsedown->text($this->post_data['content_md']);
if (preg_match('/^.*<!--.*readmore.*-->.*$/m', $this->post_data['content'], $matches, PREG_OFFSET_CAPTURE)) {
$content_less = substr($this->post_data['content'], 0, $matches[0][1]);
@ -130,44 +129,17 @@ class UOJBlogEditor {
die(json_encode(array('content_md' => '不合法的 YAML 格式')));
}
try {
$v8 = new V8Js('PHP');
$v8->executeString(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/js/marked.js'), 'marked.js');
$v8->executeString(<<<EOD
marked.setOptions({
getLangClass: function(lang) {
lang = lang.toLowerCase();
switch (lang) {
case 'c': return 'c';
case 'c++': return 'cpp';
case 'pascal': return 'pascal';
default: return lang;
}
},
getElementClass: function(tok) {
switch (tok.type) {
case 'list_item_start':
return 'fragment';
case 'loose_item_start':
return 'fragment';
default:
return null;
}
}
})
EOD
);
} catch (V8JsException $e) {
die(json_encode(array('content_md' => '未知错误')));
}
$marked = function($md) use ($v8, $purifier) {
try {
$v8->md = $md;
return $purifier->purify($v8->executeString('marked(PHP.md)'));
} catch (V8JsException $e) {
die(json_encode(array('content_md' => '未知错误')));
$marked = function($md) use ($parsedown, $purifier) {
$dom = new DOMDocument;
$dom->loadHTML(mb_convert_encoding($parsedown->text($md), 'HTML-ENTITIES', 'UTF-8'));
$elements = $dom->getElementsByTagName('li');
foreach ($elements as $element) {
$element->setAttribute('class',
$element->getAttribute('class') . ' fragment');
}
return $purifier->purify($dom->saveHTML());
};
$config = array();

View File

@ -1,6 +1,6 @@
<?php
require $_SERVER['DOCUMENT_ROOT'].'/app/vendor/phpmailer/PHPMailerAutoload.php';
use PHPMailer\PHPMailer\PHPMailer;
class UOJMail {
public static function noreply() {

View File

@ -6,9 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'DynamicParent' => $vendorDir . '/benjaminhoegh/parsedown-math/ParsedownMath.php',
'ParsedownMath' => $vendorDir . '/benjaminhoegh/parsedown-math/ParsedownMath.php',
);

View File

@ -6,7 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
);

View File

@ -6,5 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'parsedownMath' => array($vendorDir . '/benjaminhoegh/parsedown-math'),
'Parsedown' => array($vendorDir . '/erusev/parsedown'),
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
);

View File

@ -6,7 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'Gregwar\\' => array($vendorDir . '/gregwar/captcha/src/Gregwar'),

View File

@ -7,15 +7,12 @@ namespace Composer\Autoload;
class ComposerStaticInit0d7c2cd5c2dbf2120e4372996869e900
{
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
);
public static $prefixLengthsPsr4 = array (
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Component\\Finder\\' => 25,
),
'P' =>
@ -29,10 +26,6 @@ class ComposerStaticInit0d7c2cd5c2dbf2120e4372996869e900
);
public static $prefixDirsPsr4 = array (
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Component\\Finder\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/finder',
@ -48,6 +41,20 @@ class ComposerStaticInit0d7c2cd5c2dbf2120e4372996869e900
);
public static $prefixesPsr0 = array (
'p' =>
array (
'parsedownMath' =>
array (
0 => __DIR__ . '/..' . '/benjaminhoegh/parsedown-math',
),
),
'P' =>
array (
'Parsedown' =>
array (
0 => __DIR__ . '/..' . '/erusev/parsedown',
),
),
'H' =>
array (
'HTMLPurifier' =>
@ -58,11 +65,8 @@ class ComposerStaticInit0d7c2cd5c2dbf2120e4372996869e900
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'DynamicParent' => __DIR__ . '/..' . '/benjaminhoegh/parsedown-math/ParsedownMath.php',
'ParsedownMath' => __DIR__ . '/..' . '/benjaminhoegh/parsedown-math/ParsedownMath.php',
);
public static function getInitializer(ClassLoader $loader)

View File

@ -1,4 +1,101 @@
[
{
"name": "benjaminhoegh/parsedown-math",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/BenjaminHoegh/ParsedownMath.git",
"reference": "668b11b80c7d1dc9812274405426cb62bbb4d78b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/BenjaminHoegh/ParsedownMath/zipball/668b11b80c7d1dc9812274405426cb62bbb4d78b",
"reference": "668b11b80c7d1dc9812274405426cb62bbb4d78b",
"shasum": ""
},
"require": {
"php": "^5.6||^8.0"
},
"time": "2022-05-17T18:37:50+00:00",
"type": "library",
"installation-source": "source",
"autoload": {
"psr-0": {
"parsedownMath": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "An extension of Parsedown that adds support for LaTeX.",
"homepage": "https://github.com/BenjaminHoegh/ParsedownMath",
"keywords": [
"latex",
"markdown",
"parsedown",
"parser"
],
"funding": [
{
"url": "https://paypal.me/BenjaminHoegh",
"type": "custom"
},
{
"url": "https://www.buymeacoffee.com/BenjaminHoegh",
"type": "custom"
}
]
},
{
"name": "erusev/parsedown",
"version": "1.7.4",
"version_normalized": "1.7.4.0",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"time": "2019-12-30T22:54:17+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
]
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.16.0",
@ -189,93 +286,28 @@
}
]
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-01-02T09:53:40+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
]
},
{
"name": "symfony/finder",
"version": "v5.4.11",
"version_normalized": "5.4.11.0",
"version": "v6.1.3",
"version_normalized": "6.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c"
"reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c",
"reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c",
"url": "https://api.github.com/repos/symfony/finder/zipball/39696bff2c2970b3779a5cac7bf9f0b88fc2b709",
"reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16"
"php": ">=8.1"
},
"time": "2022-07-29T07:37:50+00:00",
"require-dev": {
"symfony/filesystem": "^6.0"
},
"time": "2022-07-29T07:42:06+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -316,87 +348,5 @@
"type": "tidelift"
}
]
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version_normalized": "1.26.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-05-10T07:21:04+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
]
}
]

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013-2018 Emanuil Rusev, erusev.com
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.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
> I also make [Caret](https://caret.io?ref=parsedown) - a Markdown editor for Mac and PC.
## Parsedown
[![Build Status](https://img.shields.io/travis/erusev/parsedown/master.svg?style=flat-square)](https://travis-ci.org/erusev/parsedown)
<!--[![Total Downloads](http://img.shields.io/packagist/dt/erusev/parsedown.svg?style=flat-square)](https://packagist.org/packages/erusev/parsedown)-->
Better Markdown Parser in PHP
[Demo](http://parsedown.org/demo) |
[Benchmarks](http://parsedown.org/speed) |
[Tests](http://parsedown.org/tests/) |
[Documentation](https://github.com/erusev/parsedown/wiki/)
### Features
* One File
* No Dependencies
* Super Fast
* Extensible
* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown)
* Tested in 5.3 to 7.1 and in HHVM
* [Markdown Extra extension](https://github.com/erusev/parsedown-extra)
### Installation
Include `Parsedown.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown).
### Example
``` php
$Parsedown = new Parsedown();
echo $Parsedown->text('Hello _Parsedown_!'); # prints: <p>Hello <em>Parsedown</em>!</p>
```
More examples in [the wiki](https://github.com/erusev/parsedown/wiki/) and in [this video tutorial](http://youtu.be/wYZBY8DEikI).
### Security
Parsedown is capable of escaping user-input within the HTML that it generates. Additionally Parsedown will apply sanitisation to additional scripting vectors (such as scripting link destinations) that are introduced by the markdown syntax itself.
To tell Parsedown that it is processing untrusted user-input, use the following:
```php
$parsedown = new Parsedown;
$parsedown->setSafeMode(true);
```
If instead, you wish to allow HTML within untrusted user-input, but still want output to be free from XSS it is recommended that you make use of a HTML sanitiser that allows HTML tags to be whitelisted, like [HTML Purifier](http://htmlpurifier.org/).
In both cases you should strongly consider employing defence-in-depth measures, like [deploying a Content-Security-Policy](https://scotthelme.co.uk/content-security-policy-an-introduction/) (a browser security feature) so that your page is likely to be safe even if an attacker finds a vulnerability in one of the first lines of defence above.
#### Security of Parsedown Extensions
Safe mode does not necessarily yield safe results when using extensions to Parsedown. Extensions should be evaluated on their own to determine their specific safety against XSS.
### Escaping HTML
> ⚠️  **WARNING:** This method isn't safe from XSS!
If you wish to escape HTML **in trusted input**, you can use the following:
```php
$parsedown = new Parsedown;
$parsedown->setMarkupEscaped(true);
```
Beware that this still allows users to insert unsafe scripting vectors, such as links like `[xss](javascript:alert%281%29)`.
### Questions
**How does Parsedown work?**
It tries to read Markdown like a human. First, it looks at the lines. Its interested in how the lines start. This helps it recognise blocks. It knows, for example, that if a line starts with a `-` then perhaps it belongs to a list. Once it recognises the blocks, it continues to the content. As it reads, it watches out for special characters. This helps it recognise inline elements (or inlines).
We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages.
**Is it compliant with CommonMark?**
It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve.
**Who uses it?**
[Laravel Framework](https://laravel.com/), [Bolt CMS](http://bolt.cm/), [Grav CMS](http://getgrav.org/), [Herbie CMS](http://www.getherbie.org/), [Kirby CMS](http://getkirby.com/), [October CMS](http://octobercms.com/), [Pico CMS](http://picocms.org), [Statamic CMS](http://www.statamic.com/), [phpDocumentor](http://www.phpdoc.org/), [RaspberryPi.org](http://www.raspberrypi.org/), [Symfony demo](https://github.com/symfony/symfony-demo) and [more](https://packagist.org/packages/erusev/parsedown/dependents).
**How can I help?**
Use it, star it, share it and if you feel generous, [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).

View File

@ -0,0 +1,33 @@
{
"name": "erusev/parsedown",
"description": "Parser for Markdown.",
"keywords": ["markdown", "parser"],
"homepage": "http://parsedown.org",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"require": {
"php": ">=5.3.0",
"ext-mbstring": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"autoload": {
"psr-0": {"Parsedown": ""}
},
"autoload-dev": {
"psr-0": {
"TestParsedown": "test/",
"ParsedownTest": "test/",
"CommonMarkTest": "test/",
"CommonMarkTestWeak": "test/"
}
}
}

View File

@ -1,3 +0,0 @@
vendor/
composer.lock
phpunit.xml

View File

@ -1,5 +0,0 @@
CHANGELOG
=========
The changelog is maintained for all Symfony contracts at the following URL:
https://github.com/symfony/contracts/blob/main/CHANGELOG.md

View File

@ -1,19 +0,0 @@
Copyright (c) 2020-2022 Fabien Potencier
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.

View File

@ -1,26 +0,0 @@
Symfony Deprecation Contracts
=============================
A generic function and convention to trigger deprecation notices.
This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
The function requires at least 3 arguments:
- the name of the Composer package that is triggering the deprecation
- the version of the package that introduced the deprecation
- the message of the deprecation
- more arguments can be provided: they will be inserted in the message using `printf()` formatting
Example:
```php
trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
```
This will generate the following message:
`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty
`function trigger_deprecation() {}` in your application.

View File

@ -1,35 +0,0 @@
{
"name": "symfony/deprecation-contracts",
"type": "library",
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"autoload": {
"files": [
"function.php"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
}
}

View File

@ -1,27 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (!function_exists('trigger_deprecation')) {
/**
* Triggers a silenced deprecation notice.
*
* @param string $package The name of the Composer package that is triggering the deprecation
* @param string $version The version of the package that introduced the deprecation
* @param string $message The message of the deprecation
* @param mixed ...$args Values to insert in the message using printf() formatting
*
* @author Nicolas Grekas <p@tchwork.com>
*/
function trigger_deprecation(string $package, string $version, string $message, ...$args): void
{
@trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
}
}

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
6.0
---
* Remove `Comparator::setTarget()` and `Comparator::setOperator()`
5.4.0
-----

View File

@ -16,102 +16,47 @@ namespace Symfony\Component\Finder\Comparator;
*/
class Comparator
{
private $target;
private $operator = '==';
private string $target;
private string $operator;
public function __construct(string $target = null, string $operator = '==')
{
if (null === $target) {
trigger_deprecation('symfony/finder', '5.4', 'Constructing a "%s" without setting "$target" is deprecated.', __CLASS__);
}
$this->target = $target;
$this->doSetOperator($operator);
}
/**
* Gets the target value.
*
* @return string
*/
public function getTarget()
{
if (null === $this->target) {
trigger_deprecation('symfony/finder', '5.4', 'Calling "%s" without initializing the target is deprecated.', __METHOD__);
}
return $this->target;
}
/**
* @deprecated set the target via the constructor instead
*/
public function setTarget(string $target)
{
trigger_deprecation('symfony/finder', '5.4', '"%s" is deprecated. Set the target via the constructor instead.', __METHOD__);
$this->target = $target;
}
/**
* Gets the comparison operator.
*
* @return string
*/
public function getOperator()
{
return $this->operator;
}
/**
* Sets the comparison operator.
*
* @throws \InvalidArgumentException
*
* @deprecated set the operator via the constructor instead
*/
public function setOperator(string $operator)
{
trigger_deprecation('symfony/finder', '5.4', '"%s" is deprecated. Set the operator via the constructor instead.', __METHOD__);
$this->doSetOperator('' === $operator ? '==' : $operator);
}
/**
* Tests against the target.
*
* @param mixed $test A test value
*
* @return bool
*/
public function test($test)
{
if (null === $this->target) {
trigger_deprecation('symfony/finder', '5.4', 'Calling "%s" without initializing the target is deprecated.', __METHOD__);
}
switch ($this->operator) {
case '>':
return $test > $this->target;
case '>=':
return $test >= $this->target;
case '<':
return $test < $this->target;
case '<=':
return $test <= $this->target;
case '!=':
return $test != $this->target;
}
return $test == $this->target;
}
private function doSetOperator(string $operator): void
public function __construct(string $target, string $operator = '==')
{
if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
}
$this->target = $target;
$this->operator = $operator;
}
/**
* Gets the target value.
*/
public function getTarget(): string
{
return $this->target;
}
/**
* Gets the comparison operator.
*/
public function getOperator(): string
{
return $this->operator;
}
/**
* Tests against the target.
*/
public function test(mixed $test): bool
{
return match ($this->operator) {
'>' => $test > $this->target,
'>=' => $test >= $this->target,
'<' => $test < $this->target,
'<=' => $test <= $this->target,
'!=' => $test != $this->target,
default => $test == $this->target,
};
}
}

View File

@ -32,7 +32,7 @@ class DateComparator extends Comparator
try {
$date = new \DateTime($matches[2]);
$target = $date->format('U');
} catch (\Exception $e) {
} catch (\Exception) {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
}

View File

@ -45,27 +45,27 @@ class Finder implements \IteratorAggregate, \Countable
public const IGNORE_DOT_FILES = 2;
public const IGNORE_VCS_IGNORED_FILES = 4;
private $mode = 0;
private $names = [];
private $notNames = [];
private $exclude = [];
private $filters = [];
private $depths = [];
private $sizes = [];
private $followLinks = false;
private $reverseSorting = false;
private $sort = false;
private $ignore = 0;
private $dirs = [];
private $dates = [];
private $iterators = [];
private $contains = [];
private $notContains = [];
private $paths = [];
private $notPaths = [];
private $ignoreUnreadableDirs = false;
private int $mode = 0;
private array $names = [];
private array $notNames = [];
private array $exclude = [];
private array $filters = [];
private array $depths = [];
private array $sizes = [];
private bool $followLinks = false;
private bool $reverseSorting = false;
private \Closure|int|false $sort = false;
private int $ignore = 0;
private array $dirs = [];
private array $dates = [];
private array $iterators = [];
private array $contains = [];
private array $notContains = [];
private array $paths = [];
private array $notPaths = [];
private bool $ignoreUnreadableDirs = false;
private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
private static array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
public function __construct()
{
@ -74,10 +74,8 @@ class Finder implements \IteratorAggregate, \Countable
/**
* Creates a new Finder.
*
* @return static
*/
public static function create()
public static function create(): static
{
return new static();
}
@ -87,7 +85,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function directories()
public function directories(): static
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
@ -99,7 +97,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function files()
public function files(): static
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
@ -122,7 +120,7 @@ class Finder implements \IteratorAggregate, \Countable
* @see DepthRangeFilterIterator
* @see NumberComparator
*/
public function depth($levels)
public function depth(string|int|array $levels): static
{
foreach ((array) $levels as $level) {
$this->depths[] = new Comparator\NumberComparator($level);
@ -150,7 +148,7 @@ class Finder implements \IteratorAggregate, \Countable
* @see DateRangeFilterIterator
* @see DateComparator
*/
public function date($dates)
public function date(string|array $dates): static
{
foreach ((array) $dates as $date) {
$this->dates[] = new Comparator\DateComparator($date);
@ -175,7 +173,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilenameFilterIterator
*/
public function name($patterns)
public function name(string|array $patterns): static
{
$this->names = array_merge($this->names, (array) $patterns);
@ -191,7 +189,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilenameFilterIterator
*/
public function notName($patterns)
public function notName(string|array $patterns): static
{
$this->notNames = array_merge($this->notNames, (array) $patterns);
@ -213,7 +211,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilecontentFilterIterator
*/
public function contains($patterns)
public function contains(string|array $patterns): static
{
$this->contains = array_merge($this->contains, (array) $patterns);
@ -235,7 +233,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilecontentFilterIterator
*/
public function notContains($patterns)
public function notContains(string|array $patterns): static
{
$this->notContains = array_merge($this->notContains, (array) $patterns);
@ -259,7 +257,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilenameFilterIterator
*/
public function path($patterns)
public function path(string|array $patterns): static
{
$this->paths = array_merge($this->paths, (array) $patterns);
@ -283,7 +281,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see FilenameFilterIterator
*/
public function notPath($patterns)
public function notPath(string|array $patterns): static
{
$this->notPaths = array_merge($this->notPaths, (array) $patterns);
@ -305,7 +303,7 @@ class Finder implements \IteratorAggregate, \Countable
* @see SizeRangeFilterIterator
* @see NumberComparator
*/
public function size($sizes)
public function size(string|int|array $sizes): static
{
foreach ((array) $sizes as $size) {
$this->sizes[] = new Comparator\NumberComparator($size);
@ -327,7 +325,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see ExcludeDirectoryFilterIterator
*/
public function exclude($dirs)
public function exclude(string|array $dirs): static
{
$this->exclude = array_merge($this->exclude, (array) $dirs);
@ -343,7 +341,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see ExcludeDirectoryFilterIterator
*/
public function ignoreDotFiles(bool $ignoreDotFiles)
public function ignoreDotFiles(bool $ignoreDotFiles): static
{
if ($ignoreDotFiles) {
$this->ignore |= static::IGNORE_DOT_FILES;
@ -363,7 +361,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see ExcludeDirectoryFilterIterator
*/
public function ignoreVCS(bool $ignoreVCS)
public function ignoreVCS(bool $ignoreVCS): static
{
if ($ignoreVCS) {
$this->ignore |= static::IGNORE_VCS_FILES;
@ -381,7 +379,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function ignoreVCSIgnored(bool $ignoreVCSIgnored)
public function ignoreVCSIgnored(bool $ignoreVCSIgnored): static
{
if ($ignoreVCSIgnored) {
$this->ignore |= static::IGNORE_VCS_IGNORED_FILES;
@ -399,7 +397,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string|string[] $pattern VCS patterns to ignore
*/
public static function addVCSPattern($pattern)
public static function addVCSPattern(string|array $pattern)
{
foreach ((array) $pattern as $p) {
self::$vcsPatterns[] = $p;
@ -419,7 +417,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sort(\Closure $closure)
public function sort(\Closure $closure): static
{
$this->sort = $closure;
@ -435,7 +433,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sortByName(bool $useNaturalSort = false)
public function sortByName(bool $useNaturalSort = false): static
{
$this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME;
@ -451,7 +449,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sortByType()
public function sortByType(): static
{
$this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
@ -469,7 +467,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sortByAccessedTime()
public function sortByAccessedTime(): static
{
$this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
@ -481,7 +479,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function reverseSorting()
public function reverseSorting(): static
{
$this->reverseSorting = true;
@ -501,7 +499,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sortByChangedTime()
public function sortByChangedTime(): static
{
$this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
@ -519,7 +517,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see SortableIterator
*/
public function sortByModifiedTime()
public function sortByModifiedTime(): static
{
$this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
@ -536,7 +534,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @see CustomFilterIterator
*/
public function filter(\Closure $closure)
public function filter(\Closure $closure): static
{
$this->filters[] = $closure;
@ -548,7 +546,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function followLinks()
public function followLinks(): static
{
$this->followLinks = true;
@ -562,7 +560,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @return $this
*/
public function ignoreUnreadableDirs(bool $ignore = true)
public function ignoreUnreadableDirs(bool $ignore = true): static
{
$this->ignoreUnreadableDirs = $ignore;
@ -578,7 +576,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @throws DirectoryNotFoundException if one of the directories does not exist
*/
public function in($dirs)
public function in(string|array $dirs): static
{
$resolvedDirs = [];
@ -587,7 +585,7 @@ class Finder implements \IteratorAggregate, \Countable
$resolvedDirs[] = [$this->normalizeDir($dir)];
} elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) {
sort($glob);
$resolvedDirs[] = array_map([$this, 'normalizeDir'], $glob);
$resolvedDirs[] = array_map($this->normalizeDir(...), $glob);
} else {
throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
}
@ -607,8 +605,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @throws \LogicException if the in() method has not been called
*/
#[\ReturnTypeWillChange]
public function getIterator()
public function getIterator(): \Iterator
{
if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
@ -651,7 +648,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @throws \InvalidArgumentException when the given argument is not iterable
*/
public function append(iterable $iterator)
public function append(iterable $iterator): static
{
if ($iterator instanceof \IteratorAggregate) {
$this->iterators[] = $iterator->getIterator();
@ -673,10 +670,8 @@ class Finder implements \IteratorAggregate, \Countable
/**
* Check if any results were found.
*
* @return bool
*/
public function hasResults()
public function hasResults(): bool
{
foreach ($this->getIterator() as $_) {
return true;
@ -687,11 +682,8 @@ class Finder implements \IteratorAggregate, \Countable
/**
* Counts all the results collected by the iterators.
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
public function count(): int
{
return iterator_count($this->getIterator());
}

View File

@ -43,7 +43,7 @@ class Gitignore
foreach ($gitignoreLines as $line) {
$line = preg_replace('~(?<!\\\\)[ \t]+$~', '', $line);
if ('!' === substr($line, 0, 1)) {
if (str_starts_with($line, '!')) {
$line = substr($line, 1);
$isNegative = true;
} else {

View File

@ -37,10 +37,8 @@ class Glob
{
/**
* Returns a regexp which is the equivalent of the glob pattern.
*
* @return string
*/
public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#')
public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#'): string
{
$firstByte = true;
$escaping = false;

View File

@ -23,7 +23,7 @@ namespace Symfony\Component\Finder\Iterator;
*/
class CustomFilterIterator extends \FilterIterator
{
private $filters = [];
private array $filters = [];
/**
* @param \Iterator<string, \SplFileInfo> $iterator The Iterator to filter
@ -45,11 +45,8 @@ class CustomFilterIterator extends \FilterIterator
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
$fileinfo = $this->current();

View File

@ -22,7 +22,7 @@ use Symfony\Component\Finder\Comparator\DateComparator;
*/
class DateRangeFilterIterator extends \FilterIterator
{
private $comparators = [];
private array $comparators = [];
/**
* @param \Iterator<string, \SplFileInfo> $iterator
@ -37,11 +37,8 @@ class DateRangeFilterIterator extends \FilterIterator
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
$fileinfo = $this->current();

View File

@ -23,7 +23,7 @@ namespace Symfony\Component\Finder\Iterator;
*/
class DepthRangeFilterIterator extends \FilterIterator
{
private $minDepth = 0;
private int $minDepth = 0;
/**
* @param \RecursiveIteratorIterator<\RecursiveIterator<TKey, TValue>> $iterator The Iterator to filter
@ -40,11 +40,8 @@ class DepthRangeFilterIterator extends \FilterIterator
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
}

View File

@ -11,24 +11,27 @@
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\SplFileInfo;
/**
* ExcludeDirectoryFilterIterator filters out directories.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @extends \FilterIterator<string, \SplFileInfo>
* @implements \RecursiveIterator<string, \SplFileInfo>
* @extends \FilterIterator<string, SplFileInfo>
* @implements \RecursiveIterator<string, SplFileInfo>
*/
class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
{
private $iterator;
private $isRecursive;
private $excludedDirs = [];
private $excludedPattern;
/** @var \Iterator<string, SplFileInfo> */
private \Iterator $iterator;
private bool $isRecursive;
private array $excludedDirs = [];
private ?string $excludedPattern = null;
/**
* @param \Iterator $iterator The Iterator to filter
* @param string[] $directories An array of directories to exclude
* @param \Iterator<string, SplFileInfo> $iterator The Iterator to filter
* @param string[] $directories An array of directories to exclude
*/
public function __construct(\Iterator $iterator, array $directories)
{
@ -52,11 +55,8 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
return false;
@ -72,20 +72,12 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
return true;
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function hasChildren()
public function hasChildren(): bool
{
return $this->isRecursive && $this->iterator->hasChildren();
}
/**
* @return self
*/
#[\ReturnTypeWillChange]
public function getChildren()
public function getChildren(): self
{
$children = new self($this->iterator->getChildren(), []);
$children->excludedDirs = $this->excludedDirs;

View File

@ -23,11 +23,11 @@ class FileTypeFilterIterator extends \FilterIterator
public const ONLY_FILES = 1;
public const ONLY_DIRECTORIES = 2;
private $mode;
private int $mode;
/**
* @param \Iterator $iterator The Iterator to filter
* @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
* @param \Iterator<string, \SplFileInfo> $iterator The Iterator to filter
* @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
*/
public function __construct(\Iterator $iterator, int $mode)
{
@ -38,11 +38,8 @@ class FileTypeFilterIterator extends \FilterIterator
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
$fileinfo = $this->current();
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {

View File

@ -11,23 +11,22 @@
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\SplFileInfo;
/**
* FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
*
* @extends MultiplePcreFilterIterator<string, \SplFileInfo>
* @extends MultiplePcreFilterIterator<string, SplFileInfo>
*/
class FilecontentFilterIterator extends MultiplePcreFilterIterator
{
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
if (!$this->matchRegexps && !$this->noMatchRegexps) {
return true;
@ -51,10 +50,8 @@ class FilecontentFilterIterator extends MultiplePcreFilterIterator
* Converts string to regexp if necessary.
*
* @param string $str Pattern: string or regexp
*
* @return string
*/
protected function toRegex(string $str)
protected function toRegex(string $str): string
{
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
}

View File

@ -24,11 +24,8 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
{
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
return $this->isAccepted($this->current()->getFilename());
}
@ -40,10 +37,8 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
* Glob strings are transformed with Glob::toRegex().
*
* @param string $str Pattern: glob or regexp
*
* @return string
*/
protected function toRegex(string $str)
protected function toRegex(string $str): string
{
return $this->isRegex($str) ? $str : Glob::toRegex($str);
}

View File

@ -18,11 +18,11 @@ namespace Symfony\Component\Finder\Iterator;
*/
class LazyIterator implements \IteratorAggregate
{
private $iteratorFactory;
private \Closure $iteratorFactory;
public function __construct(callable $iteratorFactory)
{
$this->iteratorFactory = $iteratorFactory;
$this->iteratorFactory = $iteratorFactory(...);
}
public function getIterator(): \Traversable

View File

@ -27,9 +27,9 @@ abstract class MultiplePcreFilterIterator extends \FilterIterator
protected $noMatchRegexps = [];
/**
* @param \Iterator $iterator The Iterator to filter
* @param string[] $matchPatterns An array of patterns that need to match
* @param string[] $noMatchPatterns An array of patterns that need to not match
* @param \Iterator<TKey, TValue> $iterator The Iterator to filter
* @param string[] $matchPatterns An array of patterns that need to match
* @param string[] $noMatchPatterns An array of patterns that need to not match
*/
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
{
@ -50,10 +50,8 @@ abstract class MultiplePcreFilterIterator extends \FilterIterator
* If there is no regexps defined in the class, this method will accept the string.
* Such case can be handled by child classes before calling the method if they want to
* apply a different behavior.
*
* @return bool
*/
protected function isAccepted(string $string)
protected function isAccepted(string $string): bool
{
// should at least not match one rule to exclude
foreach ($this->noMatchRegexps as $regex) {
@ -79,10 +77,8 @@ abstract class MultiplePcreFilterIterator extends \FilterIterator
/**
* Checks whether the string is a regex.
*
* @return bool
*/
protected function isRegex(string $str)
protected function isRegex(string $str): bool
{
$availableModifiers = 'imsxuADU';
@ -110,8 +106,6 @@ abstract class MultiplePcreFilterIterator extends \FilterIterator
/**
* Converts string into regexp.
*
* @return string
*/
abstract protected function toRegex(string $str);
abstract protected function toRegex(string $str): string;
}

View File

@ -11,23 +11,22 @@
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\SplFileInfo;
/**
* PathFilterIterator filters files by path patterns (e.g. some/special/dir).
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
*
* @extends MultiplePcreFilterIterator<string, \SplFileInfo>
* @extends MultiplePcreFilterIterator<string, SplFileInfo>
*/
class PathFilterIterator extends MultiplePcreFilterIterator
{
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
$filename = $this->current()->getRelativePathname();
@ -49,10 +48,8 @@ class PathFilterIterator extends MultiplePcreFilterIterator
* Use only / as directory separator (on Windows also).
*
* @param string $str Pattern: regexp or dirname
*
* @return string
*/
protected function toRegex(string $str)
protected function toRegex(string $str): string
{
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
}

View File

@ -18,23 +18,17 @@ use Symfony\Component\Finder\SplFileInfo;
* Extends the \RecursiveDirectoryIterator to support relative paths.
*
* @author Victor Berchet <victor@suumit.com>
* @extends \RecursiveDirectoryIterator<string, SplFileInfo>
*/
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
/**
* @var bool
*/
private $ignoreUnreadableDirs;
/**
* @var bool
*/
private $rewindable;
private bool $ignoreUnreadableDirs;
private ?bool $rewindable = null;
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
private $rootPath;
private $subPath;
private $directorySeparator = '/';
private string $rootPath;
private string $subPath;
private string $directorySeparator = '/';
/**
* @throws \RuntimeException
@ -55,17 +49,15 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
/**
* Return an instance of SplFileInfo with support for relative paths.
*
* @return SplFileInfo
*/
#[\ReturnTypeWillChange]
public function current()
public function current(): SplFileInfo
{
// the logic here avoids redoing the same work in all iterations
if (null === $subPathname = $this->subPath) {
$subPathname = $this->subPath = $this->getSubPath();
if (!isset($this->subPath)) {
$this->subPath = $this->getSubPath();
}
$subPathname = $this->subPath;
if ('' !== $subPathname) {
$subPathname .= $this->directorySeparator;
}
@ -78,13 +70,7 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
}
/**
* @param bool $allowLinks
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function hasChildren($allowLinks = false)
public function hasChildren(bool $allowLinks = false): bool
{
$hasChildren = parent::hasChildren($allowLinks);
@ -96,19 +82,16 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
parent::getChildren();
return true;
} catch (\UnexpectedValueException $e) {
} catch (\UnexpectedValueException) {
// If directory is unreadable and finder is set to ignore it, skip children
return false;
}
}
/**
* @return \RecursiveDirectoryIterator
*
* @throws AccessDeniedException
*/
#[\ReturnTypeWillChange]
public function getChildren()
public function getChildren(): \RecursiveDirectoryIterator
{
try {
$children = parent::getChildren();
@ -130,11 +113,8 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
/**
* Do nothing for non rewindable stream.
*
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
public function rewind(): void
{
if (false === $this->isRewindable()) {
return;
@ -145,10 +125,8 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
/**
* Checks if the stream is rewindable.
*
* @return bool
*/
public function isRewindable()
public function isRewindable(): bool
{
if (null !== $this->rewindable) {
return $this->rewindable;

View File

@ -22,7 +22,7 @@ use Symfony\Component\Finder\Comparator\NumberComparator;
*/
class SizeRangeFilterIterator extends \FilterIterator
{
private $comparators = [];
private array $comparators = [];
/**
* @param \Iterator<string, \SplFileInfo> $iterator
@ -37,11 +37,8 @@ class SizeRangeFilterIterator extends \FilterIterator
/**
* Filters the iterator values.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function accept()
public function accept(): bool
{
$fileinfo = $this->current();
if (!$fileinfo->isFile()) {

View File

@ -28,8 +28,9 @@ class SortableIterator implements \IteratorAggregate
public const SORT_BY_MODIFIED_TIME = 5;
public const SORT_BY_NAME_NATURAL = 6;
private $iterator;
private $sort;
/** @var \Traversable<string, \SplFileInfo> */
private \Traversable $iterator;
private \Closure|int $sort;
/**
* @param \Traversable<string, \SplFileInfo> $iterator
@ -37,7 +38,7 @@ class SortableIterator implements \IteratorAggregate
*
* @throws \InvalidArgumentException
*/
public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
public function __construct(\Traversable $iterator, int|callable $sort, bool $reverseOrder = false)
{
$this->iterator = $iterator;
$order = $reverseOrder ? -1 : 1;
@ -75,17 +76,13 @@ class SortableIterator implements \IteratorAggregate
} elseif (self::SORT_BY_NONE === $sort) {
$this->sort = $order;
} elseif (\is_callable($sort)) {
$this->sort = $reverseOrder ? static function (\SplFileInfo $a, \SplFileInfo $b) use ($sort) { return -$sort($a, $b); } : $sort;
$this->sort = $reverseOrder ? static function (\SplFileInfo $a, \SplFileInfo $b) use ($sort) { return -$sort($a, $b); } : $sort(...);
} else {
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
}
}
/**
* @return \Traversable<string, \SplFileInfo>
*/
#[\ReturnTypeWillChange]
public function getIterator()
public function getIterator(): \Traversable
{
if (1 === $this->sort) {
return $this->iterator;

View File

@ -13,6 +13,9 @@ namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Gitignore;
/**
* @extends \FilterIterator<string, \SplFileInfo>
*/
final class VcsIgnoredFilterIterator extends \FilterIterator
{
/**
@ -30,10 +33,20 @@ final class VcsIgnoredFilterIterator extends \FilterIterator
*/
private $ignoredPathsCache = [];
/**
* @param \Iterator<string, \SplFileInfo> $iterator
*/
public function __construct(\Iterator $iterator, string $baseDir)
{
$this->baseDir = $this->normalizePath($baseDir);
foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) {
if (@is_dir("{$parentDirectory}/.git")) {
$this->baseDir = $parentDirectory;
break;
}
}
parent::__construct($iterator);
}
@ -58,7 +71,7 @@ final class VcsIgnoredFilterIterator extends \FilterIterator
$ignored = false;
foreach ($this->parentsDirectoryDownward($fileRealPath) as $parentDirectory) {
foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) {
if ($this->isIgnored($parentDirectory)) {
// rules in ignored directories are ignored, no need to check further.
break;
@ -89,11 +102,11 @@ final class VcsIgnoredFilterIterator extends \FilterIterator
/**
* @return list<string>
*/
private function parentsDirectoryDownward(string $fileRealPath): array
private function parentDirectoriesUpwards(string $from): array
{
$parentDirectories = [];
$parentDirectory = $fileRealPath;
$parentDirectory = $from;
while (true) {
$newParentDirectory = \dirname($parentDirectory);
@ -103,16 +116,30 @@ final class VcsIgnoredFilterIterator extends \FilterIterator
break;
}
$parentDirectory = $newParentDirectory;
if (0 !== strpos($parentDirectory, $this->baseDir)) {
break;
}
$parentDirectories[] = $parentDirectory;
$parentDirectories[] = $parentDirectory = $newParentDirectory;
}
return array_reverse($parentDirectories);
return $parentDirectories;
}
private function parentDirectoriesUpTo(string $from, string $upTo): array
{
return array_filter(
$this->parentDirectoriesUpwards($from),
static function (string $directory) use ($upTo): bool {
return str_starts_with($directory, $upTo);
}
);
}
/**
* @return list<string>
*/
private function parentDirectoriesDownwards(string $fileRealPath): array
{
return array_reverse(
$this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)
);
}
/**

View File

@ -18,8 +18,8 @@ namespace Symfony\Component\Finder;
*/
class SplFileInfo extends \SplFileInfo
{
private $relativePath;
private $relativePathname;
private string $relativePath;
private string $relativePathname;
/**
* @param string $file The file name
@ -37,10 +37,8 @@ class SplFileInfo extends \SplFileInfo
* Returns the relative path.
*
* This path does not contain the file name.
*
* @return string
*/
public function getRelativePath()
public function getRelativePath(): string
{
return $this->relativePath;
}
@ -49,10 +47,8 @@ class SplFileInfo extends \SplFileInfo
* Returns the relative path name.
*
* This path contains the file name.
*
* @return string
*/
public function getRelativePathname()
public function getRelativePathname(): string
{
return $this->relativePathname;
}
@ -67,11 +63,9 @@ class SplFileInfo extends \SplFileInfo
/**
* Returns the contents of the file.
*
* @return string
*
* @throws \RuntimeException
*/
public function getContents()
public function getContents(): string
{
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
try {

View File

@ -16,9 +16,10 @@
}
],
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16"
"php": ">=8.1"
},
"require-dev": {
"symfony/filesystem": "^6.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Finder\\": "" },

View File

@ -1,19 +0,0 @@
Copyright (c) 2020 Fabien Potencier
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.

View File

@ -1,115 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php80;
/**
* @author Ion Bazan <ion.bazan@gmail.com>
* @author Nico Oelgart <nicoswd@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class Php80
{
public static function fdiv(float $dividend, float $divisor): float
{
return @($dividend / $divisor);
}
public static function get_debug_type($value): string
{
switch (true) {
case null === $value: return 'null';
case \is_bool($value): return 'bool';
case \is_string($value): return 'string';
case \is_array($value): return 'array';
case \is_int($value): return 'int';
case \is_float($value): return 'float';
case \is_object($value): break;
case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
default:
if (null === $type = @get_resource_type($value)) {
return 'unknown';
}
if ('Unknown' === $type) {
$type = 'closed';
}
return "resource ($type)";
}
$class = \get_class($value);
if (false === strpos($class, '@')) {
return $class;
}
return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
}
public static function get_resource_id($res): int
{
if (!\is_resource($res) && null === @get_resource_type($res)) {
throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
}
return (int) $res;
}
public static function preg_last_error_msg(): string
{
switch (preg_last_error()) {
case \PREG_INTERNAL_ERROR:
return 'Internal error';
case \PREG_BAD_UTF8_ERROR:
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
case \PREG_BAD_UTF8_OFFSET_ERROR:
return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
case \PREG_BACKTRACK_LIMIT_ERROR:
return 'Backtrack limit exhausted';
case \PREG_RECURSION_LIMIT_ERROR:
return 'Recursion limit exhausted';
case \PREG_JIT_STACKLIMIT_ERROR:
return 'JIT stack limit exhausted';
case \PREG_NO_ERROR:
return 'No error';
default:
return 'Unknown error';
}
}
public static function str_contains(string $haystack, string $needle): bool
{
return '' === $needle || false !== strpos($haystack, $needle);
}
public static function str_starts_with(string $haystack, string $needle): bool
{
return 0 === strncmp($haystack, $needle, \strlen($needle));
}
public static function str_ends_with(string $haystack, string $needle): bool
{
if ('' === $needle || $needle === $haystack) {
return true;
}
if ('' === $haystack) {
return false;
}
$needleLength = \strlen($needle);
return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
}
}

View File

@ -1,103 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php80;
/**
* @author Fedonyuk Anton <info@ensostudio.ru>
*
* @internal
*/
class PhpToken implements \Stringable
{
/**
* @var int
*/
public $id;
/**
* @var string
*/
public $text;
/**
* @var int
*/
public $line;
/**
* @var int
*/
public $pos;
public function __construct(int $id, string $text, int $line = -1, int $position = -1)
{
$this->id = $id;
$this->text = $text;
$this->line = $line;
$this->pos = $position;
}
public function getTokenName(): ?string
{
if ('UNKNOWN' === $name = token_name($this->id)) {
$name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
}
return $name;
}
/**
* @param int|string|array $kind
*/
public function is($kind): bool
{
foreach ((array) $kind as $value) {
if (\in_array($value, [$this->id, $this->text], true)) {
return true;
}
}
return false;
}
public function isIgnorable(): bool
{
return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
}
public function __toString(): string
{
return (string) $this->text;
}
/**
* @return static[]
*/
public static function tokenize(string $code, int $flags = 0): array
{
$line = 1;
$position = 0;
$tokens = token_get_all($code, $flags);
foreach ($tokens as $index => $token) {
if (\is_string($token)) {
$id = \ord($token);
$text = $token;
} else {
[$id, $text, $line] = $token;
}
$tokens[$index] = new static($id, $text, $line, $position);
$position += \strlen($text);
}
return $tokens;
}
}

View File

@ -1,25 +0,0 @@
Symfony Polyfill / Php80
========================
This component provides features added to PHP 8.0 core:
- [`Stringable`](https://php.net/stringable) interface
- [`fdiv`](https://php.net/fdiv)
- [`ValueError`](https://php.net/valueerror) class
- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
- `FILTER_VALIDATE_BOOL` constant
- [`get_debug_type`](https://php.net/get_debug_type)
- [`PhpToken`](https://php.net/phptoken) class
- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
- [`str_contains`](https://php.net/str_contains)
- [`str_starts_with`](https://php.net/str_starts_with)
- [`str_ends_with`](https://php.net/str_ends_with)
- [`get_resource_id`](https://php.net/get_resource_id)
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

View File

@ -1,22 +0,0 @@
<?php
#[Attribute(Attribute::TARGET_CLASS)]
final class Attribute
{
public const TARGET_CLASS = 1;
public const TARGET_FUNCTION = 2;
public const TARGET_METHOD = 4;
public const TARGET_PROPERTY = 8;
public const TARGET_CLASS_CONSTANT = 16;
public const TARGET_PARAMETER = 32;
public const TARGET_ALL = 63;
public const IS_REPEATABLE = 64;
/** @var int */
public $flags;
public function __construct(int $flags = self::TARGET_ALL)
{
$this->flags = $flags;
}
}

View File

@ -1,7 +0,0 @@
<?php
if (\PHP_VERSION_ID < 80000 && \extension_loaded('tokenizer')) {
class PhpToken extends Symfony\Polyfill\Php80\PhpToken
{
}
}

View File

@ -1,11 +0,0 @@
<?php
if (\PHP_VERSION_ID < 80000) {
interface Stringable
{
/**
* @return string
*/
public function __toString();
}
}

View File

@ -1,7 +0,0 @@
<?php
if (\PHP_VERSION_ID < 80000) {
class UnhandledMatchError extends Error
{
}
}

View File

@ -1,7 +0,0 @@
<?php
if (\PHP_VERSION_ID < 80000) {
class ValueError extends Error
{
}
}

View File

@ -1,42 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Php80 as p;
if (\PHP_VERSION_ID >= 80000) {
return;
}
if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
}
if (!function_exists('fdiv')) {
function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
}
if (!function_exists('preg_last_error_msg')) {
function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
}
if (!function_exists('str_contains')) {
function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_starts_with')) {
function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('str_ends_with')) {
function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
}
if (!function_exists('get_debug_type')) {
function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
}
if (!function_exists('get_resource_id')) {
function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
}

View File

@ -1,40 +0,0 @@
{
"name": "symfony/polyfill-php80",
"type": "library",
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"keywords": ["polyfill", "shim", "compatibility", "portable"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
"files": [ "bootstrap.php" ],
"classmap": [ "Resources/stubs" ]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

View File

@ -18,13 +18,9 @@ getAptPackage(){
# Update apt sources and install
export DEBIAN_FRONTEND=noninteractive
dpkg -s gnupg 2>/dev/null || (apt-get update && apt-get install -y gnupg)
echo "deb http://ppa.launchpad.net/stesie/libv8/ubuntu bionic main" | tee /etc/apt/sources.list.d/stesie-libv8.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1A10946ED858A0DF
echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu jammy main" | tee /etc/apt/sources.list.d/ondrej-php.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C
apt-get update --allow-unauthenticated
apt-get install -y --allow-unauthenticated -o Dpkg::Options::="--force-overwrite" libv8 php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd libseccomp-dev git vim ntp zip unzip curl wget libapache2-mod-xsendfile mysql-server php-pear cmake fp-compiler re2c libv8-7.5-dev libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk
# Install PHP extensions
git clone https://github.com/phpv8/v8js.git --depth=1 -b 2.1.2 /tmp/pear/download/v8js-master && cd /tmp/pear/download/v8js-master
phpize && ./configure --with-php-config=/usr/bin/php-config --with-v8js=/opt/libv8-7.5 && make install && cd -
apt-get install -y --allow-unauthenticated -o Dpkg::Options::="--force-overwrite" php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd libseccomp-dev git vim ntp zip unzip curl wget libapache2-mod-xsendfile mysql-server php-pear cmake fp-compiler re2c libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk
}
setLAMPConf(){
@ -53,7 +49,6 @@ UOJEOF
a2enmod rewrite headers && sed -i -e '172s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
#Create UOJ session save dir and make PHP extensions available
mkdir --mode=733 /var/lib/php/uoj_sessions && chmod +t /var/lib/php/uoj_sessions
sed -i -e '912a\extension=v8js.so\nextension=yaml.so' /etc/php/7.4/apache2/php.ini
sed -i 's|;sys_temp_dir = "/tmp"|sys_temp_dir = "/tmp"|g' /etc/php/7.4/apache2/php.ini
}