First version, support for sending mail not yet implemented.
This commit is contained in:
commit
0222265abc
76 changed files with 4858 additions and 0 deletions
5
composer.json
Normal file
5
composer.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"gregwar/captcha": "^1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
120
composer.lock
generated
Normal file
120
composer.lock
generated
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "4389e3003e6957af2cf9f87bf65335cc",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "gregwar/captcha",
|
||||||
|
"version": "v1.1.8",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Gregwar/Captcha.git",
|
||||||
|
"reference": "6088ad3db59bc226423ad1476a9f0424b19b1866"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6088ad3db59bc226423ad1476a9f0424b19b1866",
|
||||||
|
"reference": "6088ad3db59bc226423ad1476a9f0424b19b1866",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=5.3.0",
|
||||||
|
"symfony/finder": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.4"
|
||||||
|
},
|
||||||
|
"type": "captcha",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gregwar\\": "src/Gregwar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Grégoire Passault",
|
||||||
|
"email": "g.passault@gmail.com",
|
||||||
|
"homepage": "http://www.gregwar.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jeremy Livingston",
|
||||||
|
"email": "jeremy.j.livingston@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Captcha generator",
|
||||||
|
"homepage": "https://github.com/Gregwar/Captcha",
|
||||||
|
"keywords": [
|
||||||
|
"bot",
|
||||||
|
"captcha",
|
||||||
|
"spam"
|
||||||
|
],
|
||||||
|
"time": "2020-01-22T14:54:02+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/finder",
|
||||||
|
"version": "v5.0.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/finder.git",
|
||||||
|
"reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/finder/zipball/4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
|
||||||
|
"reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Finder\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Finder Component",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"time": "2020-01-04T14:08:26+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": []
|
||||||
|
}
|
||||||
240
module.php
Executable file
240
module.php
Executable file
|
|
@ -0,0 +1,240 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
use Lewp\Resolve;
|
||||||
|
|
||||||
|
return new class extends Lewp\Module
|
||||||
|
{
|
||||||
|
|
||||||
|
const KEY_CSRF_TOKEN = 'csrf_token';
|
||||||
|
const KEY_CAPTCHA_PHRASE = 'captcha_phrase';
|
||||||
|
|
||||||
|
private function createForm()
|
||||||
|
{
|
||||||
|
$form = $this->createAndSetupElement(
|
||||||
|
'form',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'method' => 'post',
|
||||||
|
'action' => '',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
// LABEL NAME
|
||||||
|
$label_name = $this->createAndSetupElement(
|
||||||
|
'label',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'name'
|
||||||
|
])),
|
||||||
|
[
|
||||||
|
'for' => 'name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($label_name);
|
||||||
|
// NAME INPUT
|
||||||
|
$name = $this->createAndSetupElement(
|
||||||
|
'input',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'id' => 'name',
|
||||||
|
'name' => 'name',
|
||||||
|
'type' => 'text',
|
||||||
|
'value' => $_POST['name'] ?? '',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($name);
|
||||||
|
// LABEL Email
|
||||||
|
$label_email = $this->createAndSetupElement(
|
||||||
|
'label',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'email'
|
||||||
|
])),
|
||||||
|
[
|
||||||
|
'for' => 'email'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($label_email);
|
||||||
|
// EMAIL INPUT
|
||||||
|
$email = $this->createAndSetupElement(
|
||||||
|
'input',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'id' => 'email',
|
||||||
|
'name' => 'email',
|
||||||
|
'type' => 'email',
|
||||||
|
'value' => $_POST['email'] ?? '',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($email);
|
||||||
|
// LABEL Message
|
||||||
|
$label_message = $this->createAndSetupElement(
|
||||||
|
'label',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'message'
|
||||||
|
])),
|
||||||
|
[
|
||||||
|
'for' => 'message'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($label_message);
|
||||||
|
// MESSAGE INPUT
|
||||||
|
$message = $this->createAndSetupElement(
|
||||||
|
'textarea',
|
||||||
|
$_POST['message'] ?? '',
|
||||||
|
[
|
||||||
|
'id' => 'message',
|
||||||
|
'name' => 'message',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($message);
|
||||||
|
// LABEL Captcha
|
||||||
|
$label_captcha = $this->createAndSetupElement(
|
||||||
|
'label',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'for' => self::KEY_CAPTCHA_PHRASE
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$label_captcha->appendChild($this->generateCaptcha());
|
||||||
|
$form->appendChild($label_captcha);
|
||||||
|
// CAPTCHA INPUT
|
||||||
|
$captcha = $this->createAndSetupElement(
|
||||||
|
'input',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'id' => 'captchainput',
|
||||||
|
'name' => self::KEY_CAPTCHA_PHRASE,
|
||||||
|
'type' => 'text',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($captcha);
|
||||||
|
// SUBMIT BUTTON
|
||||||
|
$submit = $this->createAndSetupElement(
|
||||||
|
'button',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'submit'
|
||||||
|
])),
|
||||||
|
[
|
||||||
|
'id' => 'submit',
|
||||||
|
'type' => 'submit',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$form->appendChild($submit);
|
||||||
|
// ADD CSRF CHECK
|
||||||
|
$form->appendChild($this->generateCsrfInput());
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateCsrfInput()
|
||||||
|
{
|
||||||
|
// create token and save to session
|
||||||
|
$token = bin2hex(random_bytes(6));
|
||||||
|
$this->getSession()->set(self::KEY_CSRF_TOKEN, $token);
|
||||||
|
return $this->createAndSetupElement(
|
||||||
|
'input',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'type' => 'hidden',
|
||||||
|
'name' => self::KEY_CSRF_TOKEN,
|
||||||
|
'value' => $token,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateCsrfInput() : bool
|
||||||
|
{
|
||||||
|
if (!$this->formSubmitted()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->getSession()->get(self::KEY_CSRF_TOKEN);
|
||||||
|
if (
|
||||||
|
is_null($_POST[self::KEY_CSRF_TOKEN])
|
||||||
|
|| $_POST[self::KEY_CSRF_TOKEN] !== $token
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateCaptcha()
|
||||||
|
{
|
||||||
|
$builder = new CaptchaBuilder();
|
||||||
|
$builder->build();
|
||||||
|
$this->getSession()->set(self::KEY_CAPTCHA_PHRASE, $builder->getPhrase());
|
||||||
|
$img_captcha = $this->createAndSetupElement(
|
||||||
|
'img',
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
'id' => 'captcha',
|
||||||
|
'src' => $builder->inline(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $img_captcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateCaptcha() : bool
|
||||||
|
{
|
||||||
|
if (!$this->formSubmitted()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_phrase = $this->getSession()->get(self::KEY_CAPTCHA_PHRASE);
|
||||||
|
if (
|
||||||
|
is_null($_POST[self::KEY_CAPTCHA_PHRASE])
|
||||||
|
|| $_POST[self::KEY_CAPTCHA_PHRASE] !== $valid_phrase
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formSubmitted()
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
!is_null($_POST['name'])
|
||||||
|
|| !is_null($_POST['email'])
|
||||||
|
|| !is_null($_POST['message'])
|
||||||
|
) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(array $options = []) : bool
|
||||||
|
{
|
||||||
|
if (!$this->validateCsrfInput()) {
|
||||||
|
$this->getSession()->getFlashBag()->add(
|
||||||
|
'error',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'flashmessages',
|
||||||
|
'error',
|
||||||
|
'csrf-failed'
|
||||||
|
]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!$this->validateCaptcha()) {
|
||||||
|
$this->getSession()->getFlashBag()->add(
|
||||||
|
'error',
|
||||||
|
$this->loadTextFile(Resolve::arrayToId([
|
||||||
|
$this->getLanguage(),
|
||||||
|
'flashmessages',
|
||||||
|
'error',
|
||||||
|
'captcha-failed'
|
||||||
|
]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$form = $this->createForm();
|
||||||
|
$this->appendChild($form);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onWebsocketRequest(
|
||||||
|
\Lewp\Websocket\Message $message
|
||||||
|
) : \Lewp\Websocket\Message {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
1
resources/text/de/email.txt
Normal file
1
resources/text/de/email.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Email:
|
||||||
1
resources/text/de/flashmessages/error/captcha-failed.txt
Normal file
1
resources/text/de/flashmessages/error/captcha-failed.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Captcha überprüfung fehlgeschlagen. Bitte versuchen Sie es erneut!
|
||||||
1
resources/text/de/flashmessages/error/csrf-failed.txt
Normal file
1
resources/text/de/flashmessages/error/csrf-failed.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
CSRF überprüfung fehlgeschlagen. Bitte versuchen Sie es erneut.
|
||||||
1
resources/text/de/message.txt
Normal file
1
resources/text/de/message.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Deine Nachricht:
|
||||||
1
resources/text/de/name.txt
Normal file
1
resources/text/de/name.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Name:
|
||||||
1
resources/text/de/submit.txt
Normal file
1
resources/text/de/submit.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Absenden
|
||||||
1
resources/text/en/email.txt
Normal file
1
resources/text/en/email.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Email:
|
||||||
1
resources/text/en/flashmessages/error/captcha-failed.txt
Normal file
1
resources/text/en/flashmessages/error/captcha-failed.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Captcha input check failed. Please try again!
|
||||||
1
resources/text/en/flashmessages/error/csrf-failed.txt
Normal file
1
resources/text/en/flashmessages/error/csrf-failed.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
CSRF check failed! Please try again!
|
||||||
1
resources/text/en/message.txt
Normal file
1
resources/text/en/message.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Your message:
|
||||||
1
resources/text/en/name.txt
Normal file
1
resources/text/en/name.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Name:
|
||||||
1
resources/text/en/submit.txt
Normal file
1
resources/text/en/submit.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Submit
|
||||||
7
vendor/autoload.php
vendored
Normal file
7
vendor/autoload.php
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInitee6682223d81df2e680b8ac7236187b7::getLoader();
|
||||||
445
vendor/composer/ClassLoader.php
vendored
Normal file
445
vendor/composer/ClassLoader.php
vendored
Normal file
|
|
@ -0,0 +1,445 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see http://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see http://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
// PSR-4
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
private $useIncludePath = false;
|
||||||
|
private $classMap = array();
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
private $missingClasses = array();
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $classMap Class to filename map
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 base directories
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return bool|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*/
|
||||||
|
function includeFile($file)
|
||||||
|
{
|
||||||
|
include $file;
|
||||||
|
}
|
||||||
56
vendor/composer/LICENSE
vendored
Normal file
56
vendor/composer/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: Composer
|
||||||
|
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
Source: https://github.com/composer/composer
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||||
|
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: src/Composer/Util/TlsHelper.php
|
||||||
|
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||||
|
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
2013, Evan Coury <me@evancoury.com>
|
||||||
|
License: Expat and BSD-2-Clause
|
||||||
|
|
||||||
|
License: BSD-2-Clause
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
.
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
.
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
License: Expat
|
||||||
|
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.
|
||||||
9
vendor/composer/autoload_classmap.php
vendored
Normal file
9
vendor/composer/autoload_classmap.php
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
11
vendor/composer/autoload_psr4.php
vendored
Normal file
11
vendor/composer/autoload_psr4.php
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
|
||||||
|
'Gregwar\\' => array($vendorDir . '/gregwar/captcha/src/Gregwar'),
|
||||||
|
);
|
||||||
52
vendor/composer/autoload_real.php
vendored
Normal file
52
vendor/composer/autoload_real.php
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInitee6682223d81df2e680b8ac7236187b7
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInitee6682223d81df2e680b8ac7236187b7', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInitee6682223d81df2e680b8ac7236187b7', 'loadClassLoader'));
|
||||||
|
|
||||||
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
require_once __DIR__ . '/autoload_static.php';
|
||||||
|
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInitee6682223d81df2e680b8ac7236187b7::getInitializer($loader));
|
||||||
|
} else {
|
||||||
|
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->set($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = require __DIR__ . '/autoload_psr4.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->setPsr4($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||||
|
if ($classMap) {
|
||||||
|
$loader->addClassMap($classMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
vendor/composer/autoload_static.php
vendored
Normal file
39
vendor/composer/autoload_static.php
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInitee6682223d81df2e680b8ac7236187b7
|
||||||
|
{
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Symfony\\Component\\Finder\\' => 25,
|
||||||
|
),
|
||||||
|
'G' =>
|
||||||
|
array (
|
||||||
|
'Gregwar\\' => 8,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Symfony\\Component\\Finder\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/finder',
|
||||||
|
),
|
||||||
|
'Gregwar\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/gregwar/captcha/src/Gregwar',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInitee6682223d81df2e680b8ac7236187b7::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInitee6682223d81df2e680b8ac7236187b7::$prefixDirsPsr4;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
108
vendor/composer/installed.json
vendored
Normal file
108
vendor/composer/installed.json
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "gregwar/captcha",
|
||||||
|
"version": "v1.1.8",
|
||||||
|
"version_normalized": "1.1.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Gregwar/Captcha.git",
|
||||||
|
"reference": "6088ad3db59bc226423ad1476a9f0424b19b1866"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6088ad3db59bc226423ad1476a9f0424b19b1866",
|
||||||
|
"reference": "6088ad3db59bc226423ad1476a9f0424b19b1866",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=5.3.0",
|
||||||
|
"symfony/finder": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.4"
|
||||||
|
},
|
||||||
|
"time": "2020-01-22T14:54:02+00:00",
|
||||||
|
"type": "captcha",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gregwar\\": "src/Gregwar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Grégoire Passault",
|
||||||
|
"email": "g.passault@gmail.com",
|
||||||
|
"homepage": "http://www.gregwar.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jeremy Livingston",
|
||||||
|
"email": "jeremy.j.livingston@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Captcha generator",
|
||||||
|
"homepage": "https://github.com/Gregwar/Captcha",
|
||||||
|
"keywords": [
|
||||||
|
"bot",
|
||||||
|
"captcha",
|
||||||
|
"spam"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/finder",
|
||||||
|
"version": "v5.0.3",
|
||||||
|
"version_normalized": "5.0.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/finder.git",
|
||||||
|
"reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/finder/zipball/4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
|
||||||
|
"reference": "4176e7cb846fe08f32518b7e0ed8462e2db8d9bb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5"
|
||||||
|
},
|
||||||
|
"time": "2020-01-04T14:08:26+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Finder\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Finder Component",
|
||||||
|
"homepage": "https://symfony.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
4
vendor/gregwar/captcha/.gitignore
vendored
Normal file
4
vendor/gregwar/captcha/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
demo/*.jpg
|
||||||
|
demo/*.pgm
|
||||||
|
demo/temp/
|
||||||
|
vendor/
|
||||||
16
vendor/gregwar/captcha/.travis.yml
vendored
Normal file
16
vendor/gregwar/captcha/.travis.yml
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3.3
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- 7.1
|
||||||
|
- 7.2
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
script:
|
||||||
|
- composer install
|
||||||
|
- phpunit
|
||||||
19
vendor/gregwar/captcha/LICENSE
vendored
Normal file
19
vendor/gregwar/captcha/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) <2012-2017> Grégoire Passault
|
||||||
|
|
||||||
|
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.
|
||||||
146
vendor/gregwar/captcha/README.md
vendored
Normal file
146
vendor/gregwar/captcha/README.md
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
Captcha
|
||||||
|
=======
|
||||||
|
|
||||||
|

|
||||||
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YUXRLWHQSWS6L)
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
With composer :
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"require": {
|
||||||
|
"gregwar/captcha": "1.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
You can create a captcha with the `CaptchaBuilder` :
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
$builder = new CaptchaBuilder;
|
||||||
|
$builder->build();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then save it to a file :
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$builder->save('out.jpg');
|
||||||
|
```
|
||||||
|
|
||||||
|
Or output it directly :
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
header('Content-type: image/jpeg');
|
||||||
|
$builder->output();
|
||||||
|
```
|
||||||
|
|
||||||
|
Or inline it directly in the HTML page:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<img src="<?php echo $builder->inline(); ?>" />
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll be able to get the code and compare it with a user input :
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Example: storing the phrase in the session to test for the user
|
||||||
|
// input later
|
||||||
|
$_SESSION['phrase'] = $builder->getPhrase();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can compare the phrase with user input:
|
||||||
|
```php
|
||||||
|
if($builder->testPhrase($userInput)) {
|
||||||
|
// instructions if user phrase is good
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// user phrase is wrong
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
API
|
||||||
|
===
|
||||||
|
|
||||||
|
You can use theses functions :
|
||||||
|
|
||||||
|
* **__construct($phrase = null)**, constructs the builder with the given phrase, if the phrase is null, a random one will be generated
|
||||||
|
* **getPhrase()**, allow you to get the phrase contents
|
||||||
|
* **setDistortion($distortion)**, enable or disable the distortion, call it before `build()`
|
||||||
|
* **isOCRReadable()**, returns `true` if the OCR can be read using the `ocrad` software, you'll need to have shell_exec enabled, imagemagick and ocrad installed
|
||||||
|
* **buildAgainstOCR($width = 150, $height = 40, $font = null)**, builds a code until it is not readable by `ocrad`
|
||||||
|
* **build($width = 150, $height = 40, $font = null)**, builds a code with the given $width, $height and $font. By default, a random font will be used from the library
|
||||||
|
* **save($filename, $quality = 80)**, saves the captcha into a jpeg in the $filename, with the given quality
|
||||||
|
* **get($quality = 80)**, returns the jpeg data
|
||||||
|
* **output($quality = 80)**, directly outputs the jpeg code to a browser
|
||||||
|
* **setBackgroundColor($r, $g, $b)**, sets the background color to force it (this will disable many effects and is not recommended)
|
||||||
|
* **setBackgroundImages(array($imagepath1, $imagePath2))**, Sets custom background images to be used as captcha background. It is recommended to disable image effects when passing custom images for background (ignore_all_effects). A random image is selected from the list passed, the full paths to the image files must be passed.
|
||||||
|
* **setInterpolation($interpolate)**, enable or disable the interpolation (enabled by default), disabling it will be quicker but the images will look uglier
|
||||||
|
* **setIgnoreAllEffects($ignoreAllEffects)**, disable all effects on the captcha image. Recommended to use when passing custom background images for the captcha.
|
||||||
|
* **testPhrase($phrase)**, returns true if the given phrase is good
|
||||||
|
* **setMaxBehindLines($lines)**, sets the maximum number of lines behind the code
|
||||||
|
* **setMaxFrontLines($lines)**, sets the maximum number of lines on the front of the code
|
||||||
|
|
||||||
|
If you want to change the number of character, you can call the phrase builder directly using
|
||||||
|
extra parameters:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
use Gregwar\Captcha\PhraseBuilder;
|
||||||
|
|
||||||
|
// Will build phrases of 3 characters
|
||||||
|
$phraseBuilder = new PhraseBuilder(4)
|
||||||
|
|
||||||
|
// Will build phrases of 5 characters, only digits
|
||||||
|
$phraseBuilder = new PhraseBuilder(5, '0123456789');
|
||||||
|
|
||||||
|
// Pass it as first argument of CaptchaBuilder, passing it the phrase
|
||||||
|
// builder
|
||||||
|
$captcha = new CaptchaBuilder(null, $phraseBuilder);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also pass directly the wanted phrase to the builder:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Building a Captcha with the "hello" phrase
|
||||||
|
$captcha = new CaptchaBuilder('hello');
|
||||||
|
```
|
||||||
|
|
||||||
|
Complete example
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to see an example you can have a look at he ``demo/form.php``, which uses ``demo/session.php`` to
|
||||||
|
render a captcha and check it after the submission
|
||||||
|
|
||||||
|
Symfony Bundle
|
||||||
|
================
|
||||||
|
|
||||||
|
You can have a look at the following repository to enjoy the Symfony 2 bundle packaging this captcha generator :
|
||||||
|
https://github.com/Gregwar/CaptchaBundle
|
||||||
|
|
||||||
|
Yii2 Extension
|
||||||
|
===============
|
||||||
|
|
||||||
|
You can use the following extension for integrating with Yii2 Framework :
|
||||||
|
https://github.com/juliardi/yii2-captcha
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
This library is under MIT license, have a look to the `LICENSE` file
|
||||||
33
vendor/gregwar/captcha/composer.json
vendored
Normal file
33
vendor/gregwar/captcha/composer.json
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "gregwar/captcha",
|
||||||
|
"type": "captcha",
|
||||||
|
"description": "Captcha generator",
|
||||||
|
"keywords": ["captcha", "spam", "bot"],
|
||||||
|
"homepage": "https://github.com/Gregwar/Captcha",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Grégoire Passault",
|
||||||
|
"email": "g.passault@gmail.com",
|
||||||
|
"homepage": "http://www.gregwar.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jeremy Livingston",
|
||||||
|
"email": "jeremy.j.livingston@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"symfony/finder": "*"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gregwar\\": "src/Gregwar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
vendor/gregwar/captcha/demo/demo.php
vendored
Normal file
11
vendor/gregwar/captcha/demo/demo.php
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
$captcha = new CaptchaBuilder;
|
||||||
|
$captcha
|
||||||
|
->build()
|
||||||
|
->save('out.jpg')
|
||||||
|
;
|
||||||
12
vendor/gregwar/captcha/demo/fingerprint.php
vendored
Normal file
12
vendor/gregwar/captcha/demo/fingerprint.php
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
echo count(CaptchaBuilder::create()
|
||||||
|
->build()
|
||||||
|
->getFingerprint()
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "\n";
|
||||||
32
vendor/gregwar/captcha/demo/form.php
vendored
Normal file
32
vendor/gregwar/captcha/demo/form.php
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
use Gregwar\Captcha\PhraseBuilder;
|
||||||
|
|
||||||
|
// We need the session to check the phrase after submitting
|
||||||
|
session_start();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<?php
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
// Checking that the posted phrase match the phrase stored in the session
|
||||||
|
if (isset($_SESSION['phrase']) && PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['phrase'])) {
|
||||||
|
echo "<h1>Captcha is valid !</h1>";
|
||||||
|
} else {
|
||||||
|
echo "<h1>Captcha is not valid!</h1>";
|
||||||
|
}
|
||||||
|
// The phrase can't be used twice
|
||||||
|
unset($_SESSION['phrase']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<form method="post">
|
||||||
|
Copy the CAPTCHA:
|
||||||
|
<?php
|
||||||
|
// See session.php, where the captcha is actually rendered and the session phrase
|
||||||
|
// is set accordingly to the image displayed
|
||||||
|
?>
|
||||||
|
<img src="session.php" />
|
||||||
|
<input type="text" name="phrase" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
</html>
|
||||||
15
vendor/gregwar/captcha/demo/index.php
vendored
Normal file
15
vendor/gregwar/captcha/demo/index.php
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<body>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</html>
|
||||||
|
<body>
|
||||||
|
<h1>Captchas gallery</h1>
|
||||||
|
<?php for ($x=0; $x<8; $x++) { ?>
|
||||||
|
<?php for ($y=0; $y<5; $y++) { ?>
|
||||||
|
<img src="output.php?n=<?php echo 5*$x+$y; ?>" />
|
||||||
|
<?php } ?>
|
||||||
|
<br />
|
||||||
|
<?php } ?>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
22
vendor/gregwar/captcha/demo/inline.php
vendored
Normal file
22
vendor/gregwar/captcha/demo/inline.php
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
$captcha = new CaptchaBuilder();
|
||||||
|
$captcha->build();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<body>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</html>
|
||||||
|
<body>
|
||||||
|
<h1>Inline Captcha</h1>
|
||||||
|
|
||||||
|
<img src="<?php echo $captcha->inline(); ?>"/><br/>
|
||||||
|
Phrase: <?php echo $captcha->getPhrase(); ?>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
39
vendor/gregwar/captcha/demo/ocr.php
vendored
Normal file
39
vendor/gregwar/captcha/demo/ocr.php
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates 1000 captchas and try to read their code with the
|
||||||
|
* ocrad OCR
|
||||||
|
*/
|
||||||
|
|
||||||
|
$tests = 10000;
|
||||||
|
$passed = 0;
|
||||||
|
|
||||||
|
shell_exec('rm passed*.jpg');
|
||||||
|
|
||||||
|
for ($i=0; $i<$tests; $i++) {
|
||||||
|
echo "Captcha $i/$tests... ";
|
||||||
|
|
||||||
|
$captcha = new CaptchaBuilder;
|
||||||
|
|
||||||
|
$captcha
|
||||||
|
->setDistortion(false)
|
||||||
|
->build()
|
||||||
|
;
|
||||||
|
|
||||||
|
if ($captcha->isOCRReadable()) {
|
||||||
|
$passed++;
|
||||||
|
$captcha->save("passed$passed.jpg");
|
||||||
|
echo "passed at ocr... ";
|
||||||
|
} else {
|
||||||
|
echo "failed... ";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "pass rate: ".round(100*$passed/($i+1),2)."%\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n";
|
||||||
|
echo "Over, $passed/$tests readed with OCR\n";
|
||||||
12
vendor/gregwar/captcha/demo/output.php
vendored
Normal file
12
vendor/gregwar/captcha/demo/output.php
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
header('Content-type: image/jpeg');
|
||||||
|
|
||||||
|
CaptchaBuilder::create()
|
||||||
|
->build()
|
||||||
|
->output()
|
||||||
|
;
|
||||||
22
vendor/gregwar/captcha/demo/session.php
vendored
Normal file
22
vendor/gregwar/captcha/demo/session.php
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
// We need the session to store the correct phrase for later check
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// Including the autoload (you need to composer install in the main directory)
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
|
||||||
|
// Creating the captcha instance and setting the phrase in the session to store
|
||||||
|
// it for check when the form is submitted
|
||||||
|
$captcha = new CaptchaBuilder;
|
||||||
|
$_SESSION['phrase'] = $captcha->getPhrase();
|
||||||
|
|
||||||
|
// Setting the header to image jpeg because we here render an image
|
||||||
|
header('Content-Type: image/jpeg');
|
||||||
|
|
||||||
|
// Running the actual rendering of the captcha image
|
||||||
|
$captcha
|
||||||
|
->build()
|
||||||
|
->output()
|
||||||
|
;
|
||||||
15
vendor/gregwar/captcha/phpunit.xml.dist
vendored
Normal file
15
vendor/gregwar/captcha/phpunit.xml.dist
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<phpunit colors="true" bootstrap="vendor/autoload.php">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="KnpMenu Test Suite">
|
||||||
|
<directory suffix="Test.php">./tests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory>./src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
||||||
717
vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilder.php
vendored
Normal file
717
vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilder.php
vendored
Normal file
|
|
@ -0,0 +1,717 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gregwar\Captcha;
|
||||||
|
|
||||||
|
use \Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a new captcha image
|
||||||
|
* Uses the fingerprint parameter, if one is passed, to generate the same image
|
||||||
|
*
|
||||||
|
* @author Gregwar <g.passault@gmail.com>
|
||||||
|
* @author Jeremy Livingston <jeremy.j.livingston@gmail.com>
|
||||||
|
*/
|
||||||
|
class CaptchaBuilder implements CaptchaBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fingerprint = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $useFingerprint = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $textColor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $backgroundColor = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $backgroundImages = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $contents = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $phrase = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PhraseBuilderInterface
|
||||||
|
*/
|
||||||
|
protected $builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $distortion = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of lines to draw in front of
|
||||||
|
* the image. null - use default algorithm
|
||||||
|
*/
|
||||||
|
protected $maxFrontLines = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of lines to draw behind
|
||||||
|
* the image. null - use default algorithm
|
||||||
|
*/
|
||||||
|
protected $maxBehindLines = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum angle of char
|
||||||
|
*/
|
||||||
|
protected $maxAngle = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum offset of char
|
||||||
|
*/
|
||||||
|
protected $maxOffset = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the interpolation enabled ?
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $interpolation = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore all effects
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $ignoreAllEffects = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed image types for the background images
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $allowedBackgroundImageTypes = array('image/png', 'image/jpeg', 'image/gif');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The image contents
|
||||||
|
*/
|
||||||
|
public function getContents()
|
||||||
|
{
|
||||||
|
return $this->contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disables the interpolation
|
||||||
|
*
|
||||||
|
* @param $interpolate bool True to enable, false to disable
|
||||||
|
*
|
||||||
|
* @return CaptchaBuilder
|
||||||
|
*/
|
||||||
|
public function setInterpolation($interpolate = true)
|
||||||
|
{
|
||||||
|
$this->interpolation = $interpolate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary dir, for OCR check
|
||||||
|
*/
|
||||||
|
public $tempDir = 'temp/';
|
||||||
|
|
||||||
|
public function __construct($phrase = null, PhraseBuilderInterface $builder = null)
|
||||||
|
{
|
||||||
|
if ($builder === null) {
|
||||||
|
$this->builder = new PhraseBuilder;
|
||||||
|
} else {
|
||||||
|
$this->builder = $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->phrase = is_string($phrase) ? $phrase : $this->builder->build($phrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting the phrase
|
||||||
|
*/
|
||||||
|
public function setPhrase($phrase)
|
||||||
|
{
|
||||||
|
$this->phrase = (string) $phrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables/disable distortion
|
||||||
|
*/
|
||||||
|
public function setDistortion($distortion)
|
||||||
|
{
|
||||||
|
$this->distortion = (bool) $distortion;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMaxBehindLines($maxBehindLines)
|
||||||
|
{
|
||||||
|
$this->maxBehindLines = $maxBehindLines;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMaxFrontLines($maxFrontLines)
|
||||||
|
{
|
||||||
|
$this->maxFrontLines = $maxFrontLines;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMaxAngle($maxAngle)
|
||||||
|
{
|
||||||
|
$this->maxAngle = $maxAngle;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMaxOffset($maxOffset)
|
||||||
|
{
|
||||||
|
$this->maxOffset = $maxOffset;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the captcha phrase
|
||||||
|
*/
|
||||||
|
public function getPhrase()
|
||||||
|
{
|
||||||
|
return $this->phrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given phrase is good
|
||||||
|
*/
|
||||||
|
public function testPhrase($phrase)
|
||||||
|
{
|
||||||
|
return ($this->builder->niceize($phrase) == $this->builder->niceize($this->getPhrase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiation
|
||||||
|
*/
|
||||||
|
public static function create($phrase = null)
|
||||||
|
{
|
||||||
|
return new self($phrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text color to use
|
||||||
|
*/
|
||||||
|
public function setTextColor($r, $g, $b)
|
||||||
|
{
|
||||||
|
$this->textColor = array($r, $g, $b);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the background color to use
|
||||||
|
*/
|
||||||
|
public function setBackgroundColor($r, $g, $b)
|
||||||
|
{
|
||||||
|
$this->backgroundColor = array($r, $g, $b);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ignoreAllEffects value
|
||||||
|
*
|
||||||
|
* @param bool $ignoreAllEffects
|
||||||
|
* @return CaptchaBuilder
|
||||||
|
*/
|
||||||
|
public function setIgnoreAllEffects($ignoreAllEffects)
|
||||||
|
{
|
||||||
|
$this->ignoreAllEffects = $ignoreAllEffects;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list of background images to use (one image is randomly selected)
|
||||||
|
*/
|
||||||
|
public function setBackgroundImages(array $backgroundImages)
|
||||||
|
{
|
||||||
|
$this->backgroundImages = $backgroundImages;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw lines over the image
|
||||||
|
*/
|
||||||
|
protected function drawLine($image, $width, $height, $tcol = null)
|
||||||
|
{
|
||||||
|
if ($tcol === null) {
|
||||||
|
$tcol = imagecolorallocate($image, $this->rand(100, 255), $this->rand(100, 255), $this->rand(100, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->rand(0, 1)) { // Horizontal
|
||||||
|
$Xa = $this->rand(0, $width/2);
|
||||||
|
$Ya = $this->rand(0, $height);
|
||||||
|
$Xb = $this->rand($width/2, $width);
|
||||||
|
$Yb = $this->rand(0, $height);
|
||||||
|
} else { // Vertical
|
||||||
|
$Xa = $this->rand(0, $width);
|
||||||
|
$Ya = $this->rand(0, $height/2);
|
||||||
|
$Xb = $this->rand(0, $width);
|
||||||
|
$Yb = $this->rand($height/2, $height);
|
||||||
|
}
|
||||||
|
imagesetthickness($image, $this->rand(1, 3));
|
||||||
|
imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply some post effects
|
||||||
|
*/
|
||||||
|
protected function postEffect($image)
|
||||||
|
{
|
||||||
|
if (!function_exists('imagefilter')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->backgroundColor != null || $this->textColor != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negate ?
|
||||||
|
if ($this->rand(0, 1) == 0) {
|
||||||
|
imagefilter($image, IMG_FILTER_NEGATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edge ?
|
||||||
|
if ($this->rand(0, 10) == 0) {
|
||||||
|
imagefilter($image, IMG_FILTER_EDGEDETECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contrast
|
||||||
|
imagefilter($image, IMG_FILTER_CONTRAST, $this->rand(-50, 10));
|
||||||
|
|
||||||
|
// Colorize
|
||||||
|
if ($this->rand(0, 5) == 0) {
|
||||||
|
imagefilter($image, IMG_FILTER_COLORIZE, $this->rand(-80, 50), $this->rand(-80, 50), $this->rand(-80, 50));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the phrase on the image
|
||||||
|
*/
|
||||||
|
protected function writePhrase($image, $phrase, $font, $width, $height)
|
||||||
|
{
|
||||||
|
$length = mb_strlen($phrase);
|
||||||
|
if ($length === 0) {
|
||||||
|
return \imagecolorallocate($image, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the text size and start position
|
||||||
|
$size = $width / $length - $this->rand(0, 3) - 1;
|
||||||
|
$box = \imagettfbbox($size, 0, $font, $phrase);
|
||||||
|
$textWidth = $box[2] - $box[0];
|
||||||
|
$textHeight = $box[1] - $box[7];
|
||||||
|
$x = ($width - $textWidth) / 2;
|
||||||
|
$y = ($height - $textHeight) / 2 + $size;
|
||||||
|
|
||||||
|
if (!$this->textColor) {
|
||||||
|
$textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150));
|
||||||
|
} else {
|
||||||
|
$textColor = $this->textColor;
|
||||||
|
}
|
||||||
|
$col = \imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
|
||||||
|
|
||||||
|
// Write the letters one by one, with random angle
|
||||||
|
for ($i=0; $i<$length; $i++) {
|
||||||
|
$symbol = mb_substr($phrase, $i, 1);
|
||||||
|
$box = \imagettfbbox($size, 0, $font, $symbol);
|
||||||
|
$w = $box[2] - $box[0];
|
||||||
|
$angle = $this->rand(-$this->maxAngle, $this->maxAngle);
|
||||||
|
$offset = $this->rand(-$this->maxOffset, $this->maxOffset);
|
||||||
|
\imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $symbol);
|
||||||
|
$x += $w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $col;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to read the code against an OCR
|
||||||
|
*/
|
||||||
|
public function isOCRReadable()
|
||||||
|
{
|
||||||
|
if (!is_dir($this->tempDir)) {
|
||||||
|
@mkdir($this->tempDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tempj = $this->tempDir . uniqid('captcha', true) . '.jpg';
|
||||||
|
$tempp = $this->tempDir . uniqid('captcha', true) . '.pgm';
|
||||||
|
|
||||||
|
$this->save($tempj);
|
||||||
|
shell_exec("convert $tempj $tempp");
|
||||||
|
$value = trim(strtolower(shell_exec("ocrad $tempp")));
|
||||||
|
|
||||||
|
@unlink($tempj);
|
||||||
|
@unlink($tempp);
|
||||||
|
|
||||||
|
return $this->testPhrase($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds while the code is readable against an OCR
|
||||||
|
*/
|
||||||
|
public function buildAgainstOCR($width = 150, $height = 40, $font = null, $fingerprint = null)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
$this->build($width, $height, $font, $fingerprint);
|
||||||
|
} while ($this->isOCRReadable());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the image
|
||||||
|
*/
|
||||||
|
public function build($width = 150, $height = 40, $font = null, $fingerprint = null)
|
||||||
|
{
|
||||||
|
if (null !== $fingerprint) {
|
||||||
|
$this->fingerprint = $fingerprint;
|
||||||
|
$this->useFingerprint = true;
|
||||||
|
} else {
|
||||||
|
$this->fingerprint = array();
|
||||||
|
$this->useFingerprint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($font === null) {
|
||||||
|
$font = __DIR__ . '/Font/captcha'.$this->rand(0, 5).'.ttf';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->backgroundImages)) {
|
||||||
|
// if background images list is not set, use a color fill as a background
|
||||||
|
$image = imagecreatetruecolor($width, $height);
|
||||||
|
if ($this->backgroundColor == null) {
|
||||||
|
$bg = imagecolorallocate($image, $this->rand(200, 255), $this->rand(200, 255), $this->rand(200, 255));
|
||||||
|
} else {
|
||||||
|
$color = $this->backgroundColor;
|
||||||
|
$bg = imagecolorallocate($image, $color[0], $color[1], $color[2]);
|
||||||
|
}
|
||||||
|
$this->background = $bg;
|
||||||
|
imagefill($image, 0, 0, $bg);
|
||||||
|
} else {
|
||||||
|
// use a random background image
|
||||||
|
$randomBackgroundImage = $this->backgroundImages[rand(0, count($this->backgroundImages)-1)];
|
||||||
|
|
||||||
|
$imageType = $this->validateBackgroundImage($randomBackgroundImage);
|
||||||
|
|
||||||
|
$image = $this->createBackgroundImageFromType($randomBackgroundImage, $imageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply effects
|
||||||
|
if (!$this->ignoreAllEffects) {
|
||||||
|
$square = $width * $height;
|
||||||
|
$effects = $this->rand($square/3000, $square/2000);
|
||||||
|
|
||||||
|
// set the maximum number of lines to draw in front of the text
|
||||||
|
if ($this->maxBehindLines != null && $this->maxBehindLines > 0) {
|
||||||
|
$effects = min($this->maxBehindLines, $effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->maxBehindLines !== 0) {
|
||||||
|
for ($e = 0; $e < $effects; $e++) {
|
||||||
|
$this->drawLine($image, $width, $height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write CAPTCHA text
|
||||||
|
$color = $this->writePhrase($image, $this->phrase, $font, $width, $height);
|
||||||
|
|
||||||
|
// Apply effects
|
||||||
|
if (!$this->ignoreAllEffects) {
|
||||||
|
$square = $width * $height;
|
||||||
|
$effects = $this->rand($square/3000, $square/2000);
|
||||||
|
|
||||||
|
// set the maximum number of lines to draw in front of the text
|
||||||
|
if ($this->maxFrontLines != null && $this->maxFrontLines > 0) {
|
||||||
|
$effects = min($this->maxFrontLines, $effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->maxFrontLines !== 0) {
|
||||||
|
for ($e = 0; $e < $effects; $e++) {
|
||||||
|
$this->drawLine($image, $width, $height, $color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distort the image
|
||||||
|
if ($this->distortion && !$this->ignoreAllEffects) {
|
||||||
|
$image = $this->distort($image, $width, $height, $bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post effects
|
||||||
|
if (!$this->ignoreAllEffects) {
|
||||||
|
$this->postEffect($image);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->contents = $image;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distorts the image
|
||||||
|
*/
|
||||||
|
public function distort($image, $width, $height, $bg)
|
||||||
|
{
|
||||||
|
$contents = imagecreatetruecolor($width, $height);
|
||||||
|
$X = $this->rand(0, $width);
|
||||||
|
$Y = $this->rand(0, $height);
|
||||||
|
$phase = $this->rand(0, 10);
|
||||||
|
$scale = 1.1 + $this->rand(0, 10000) / 30000;
|
||||||
|
for ($x = 0; $x < $width; $x++) {
|
||||||
|
for ($y = 0; $y < $height; $y++) {
|
||||||
|
$Vx = $x - $X;
|
||||||
|
$Vy = $y - $Y;
|
||||||
|
$Vn = sqrt($Vx * $Vx + $Vy * $Vy);
|
||||||
|
|
||||||
|
if ($Vn != 0) {
|
||||||
|
$Vn2 = $Vn + 4 * sin($Vn / 30);
|
||||||
|
$nX = $X + ($Vx * $Vn2 / $Vn);
|
||||||
|
$nY = $Y + ($Vy * $Vn2 / $Vn);
|
||||||
|
} else {
|
||||||
|
$nX = $X;
|
||||||
|
$nY = $Y;
|
||||||
|
}
|
||||||
|
$nY = $nY + $scale * sin($phase + $nX * 0.2);
|
||||||
|
|
||||||
|
if ($this->interpolation) {
|
||||||
|
$p = $this->interpolate(
|
||||||
|
$nX - floor($nX),
|
||||||
|
$nY - floor($nY),
|
||||||
|
$this->getCol($image, floor($nX), floor($nY), $bg),
|
||||||
|
$this->getCol($image, ceil($nX), floor($nY), $bg),
|
||||||
|
$this->getCol($image, floor($nX), ceil($nY), $bg),
|
||||||
|
$this->getCol($image, ceil($nX), ceil($nY), $bg)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$p = $this->getCol($image, round($nX), round($nY), $bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($p == 0) {
|
||||||
|
$p = $bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
imagesetpixel($contents, $x, $y, $p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the Captcha to a jpeg file
|
||||||
|
*/
|
||||||
|
public function save($filename, $quality = 90)
|
||||||
|
{
|
||||||
|
imagejpeg($this->contents, $filename, $quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the image GD
|
||||||
|
*/
|
||||||
|
public function getGd()
|
||||||
|
{
|
||||||
|
return $this->contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the image contents
|
||||||
|
*/
|
||||||
|
public function get($quality = 90)
|
||||||
|
{
|
||||||
|
ob_start();
|
||||||
|
$this->output($quality);
|
||||||
|
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the HTML inline base64
|
||||||
|
*/
|
||||||
|
public function inline($quality = 90)
|
||||||
|
{
|
||||||
|
return 'data:image/jpeg;base64,' . base64_encode($this->get($quality));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the image
|
||||||
|
*/
|
||||||
|
public function output($quality = 90)
|
||||||
|
{
|
||||||
|
imagejpeg($this->contents, null, $quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFingerprint()
|
||||||
|
{
|
||||||
|
return $this->fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random number or the next number in the
|
||||||
|
* fingerprint
|
||||||
|
*/
|
||||||
|
protected function rand($min, $max)
|
||||||
|
{
|
||||||
|
if (!is_array($this->fingerprint)) {
|
||||||
|
$this->fingerprint = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->useFingerprint) {
|
||||||
|
$value = current($this->fingerprint);
|
||||||
|
next($this->fingerprint);
|
||||||
|
} else {
|
||||||
|
$value = mt_rand($min, $max);
|
||||||
|
$this->fingerprint[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $x
|
||||||
|
* @param $y
|
||||||
|
* @param $nw
|
||||||
|
* @param $ne
|
||||||
|
* @param $sw
|
||||||
|
* @param $se
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function interpolate($x, $y, $nw, $ne, $sw, $se)
|
||||||
|
{
|
||||||
|
list($r0, $g0, $b0) = $this->getRGB($nw);
|
||||||
|
list($r1, $g1, $b1) = $this->getRGB($ne);
|
||||||
|
list($r2, $g2, $b2) = $this->getRGB($sw);
|
||||||
|
list($r3, $g3, $b3) = $this->getRGB($se);
|
||||||
|
|
||||||
|
$cx = 1.0 - $x;
|
||||||
|
$cy = 1.0 - $y;
|
||||||
|
|
||||||
|
$m0 = $cx * $r0 + $x * $r1;
|
||||||
|
$m1 = $cx * $r2 + $x * $r3;
|
||||||
|
$r = (int) ($cy * $m0 + $y * $m1);
|
||||||
|
|
||||||
|
$m0 = $cx * $g0 + $x * $g1;
|
||||||
|
$m1 = $cx * $g2 + $x * $g3;
|
||||||
|
$g = (int) ($cy * $m0 + $y * $m1);
|
||||||
|
|
||||||
|
$m0 = $cx * $b0 + $x * $b1;
|
||||||
|
$m1 = $cx * $b2 + $x * $b3;
|
||||||
|
$b = (int) ($cy * $m0 + $y * $m1);
|
||||||
|
|
||||||
|
return ($r << 16) | ($g << 8) | $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $image
|
||||||
|
* @param $x
|
||||||
|
* @param $y
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function getCol($image, $x, $y, $background)
|
||||||
|
{
|
||||||
|
$L = imagesx($image);
|
||||||
|
$H = imagesy($image);
|
||||||
|
if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) {
|
||||||
|
return $background;
|
||||||
|
}
|
||||||
|
|
||||||
|
return imagecolorat($image, $x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $col
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getRGB($col)
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
(int) ($col >> 16) & 0xff,
|
||||||
|
(int) ($col >> 8) & 0xff,
|
||||||
|
(int) ($col) & 0xff,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the background image path. Return the image type if valid
|
||||||
|
*
|
||||||
|
* @param string $backgroundImage
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function validateBackgroundImage($backgroundImage)
|
||||||
|
{
|
||||||
|
// check if file exists
|
||||||
|
if (!file_exists($backgroundImage)) {
|
||||||
|
$backgroundImageExploded = explode('/', $backgroundImage);
|
||||||
|
$imageFileName = count($backgroundImageExploded) > 1? $backgroundImageExploded[count($backgroundImageExploded)-1] : $backgroundImage;
|
||||||
|
|
||||||
|
throw new Exception('Invalid background image: ' . $imageFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check image type
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
|
||||||
|
$imageType = finfo_file($finfo, $backgroundImage);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
if (!in_array($imageType, $this->allowedBackgroundImageTypes)) {
|
||||||
|
throw new Exception('Invalid background image type! Allowed types are: ' . join(', ', $this->allowedBackgroundImageTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $imageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create background image from type
|
||||||
|
*
|
||||||
|
* @param string $backgroundImage
|
||||||
|
* @param string $imageType
|
||||||
|
* @return resource
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function createBackgroundImageFromType($backgroundImage, $imageType)
|
||||||
|
{
|
||||||
|
switch ($imageType) {
|
||||||
|
case 'image/jpeg':
|
||||||
|
$image = imagecreatefromjpeg($backgroundImage);
|
||||||
|
break;
|
||||||
|
case 'image/png':
|
||||||
|
$image = imagecreatefrompng($backgroundImage);
|
||||||
|
break;
|
||||||
|
case 'image/gif':
|
||||||
|
$image = imagecreatefromgif($backgroundImage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception('Not supported file type for background image!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilderInterface.php
vendored
Normal file
29
vendor/gregwar/captcha/src/Gregwar/Captcha/CaptchaBuilderInterface.php
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gregwar\Captcha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Captcha builder
|
||||||
|
*/
|
||||||
|
interface CaptchaBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Builds the code
|
||||||
|
*/
|
||||||
|
public function build($width, $height, $font, $fingerprint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the code to a file
|
||||||
|
*/
|
||||||
|
public function save($filename, $quality);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the image contents
|
||||||
|
*/
|
||||||
|
public function get($quality);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the image
|
||||||
|
*/
|
||||||
|
public function output($quality);
|
||||||
|
}
|
||||||
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha0.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha0.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha1.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha1.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha2.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha2.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha3.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha3.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha4.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha4.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha5.ttf
vendored
Normal file
BIN
vendor/gregwar/captcha/src/Gregwar/Captcha/Font/captcha5.ttf
vendored
Normal file
Binary file not shown.
105
vendor/gregwar/captcha/src/Gregwar/Captcha/ImageFileHandler.php
vendored
Normal file
105
vendor/gregwar/captcha/src/Gregwar/Captcha/ImageFileHandler.php
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gregwar\Captcha;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles actions related to captcha image files including saving and garbage collection
|
||||||
|
*
|
||||||
|
* @author Gregwar <g.passault@gmail.com>
|
||||||
|
* @author Jeremy Livingston <jeremy@quizzle.com>
|
||||||
|
*/
|
||||||
|
class ImageFileHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name of folder for captcha images
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $imageFolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Absolute path to public web folder
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $webPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frequency of garbage collection in fractions of 1
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $gcFreq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum age of images in minutes
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $expiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $imageFolder
|
||||||
|
* @param $webPath
|
||||||
|
* @param $gcFreq
|
||||||
|
* @param $expiration
|
||||||
|
*/
|
||||||
|
public function __construct($imageFolder, $webPath, $gcFreq, $expiration)
|
||||||
|
{
|
||||||
|
$this->imageFolder = $imageFolder;
|
||||||
|
$this->webPath = $webPath;
|
||||||
|
$this->gcFreq = $gcFreq;
|
||||||
|
$this->expiration = $expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the provided image content as a file
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function saveAsFile($contents)
|
||||||
|
{
|
||||||
|
$this->createFolderIfMissing();
|
||||||
|
|
||||||
|
$filename = md5(uniqid()) . '.jpg';
|
||||||
|
$filePath = $this->webPath . '/' . $this->imageFolder . '/' . $filename;
|
||||||
|
imagejpeg($contents, $filePath, 15);
|
||||||
|
|
||||||
|
return '/' . $this->imageFolder . '/' . $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomly runs garbage collection on the image directory
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectGarbage()
|
||||||
|
{
|
||||||
|
if (!mt_rand(1, $this->gcFreq) == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->createFolderIfMissing();
|
||||||
|
|
||||||
|
$finder = new Finder();
|
||||||
|
$criteria = sprintf('<= now - %s minutes', $this->expiration);
|
||||||
|
$finder->in($this->webPath . '/' . $this->imageFolder)
|
||||||
|
->date($criteria);
|
||||||
|
|
||||||
|
foreach ($finder->files() as $file) {
|
||||||
|
unlink($file->getPathname());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the folder if it doesn't exist
|
||||||
|
*/
|
||||||
|
protected function createFolderIfMissing()
|
||||||
|
{
|
||||||
|
if (!file_exists($this->webPath . '/' . $this->imageFolder)) {
|
||||||
|
mkdir($this->webPath . '/' . $this->imageFolder, 0755);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilder.php
vendored
Normal file
75
vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilder.php
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gregwar\Captcha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random phrase
|
||||||
|
*
|
||||||
|
* @author Gregwar <g.passault@gmail.com>
|
||||||
|
*/
|
||||||
|
class PhraseBuilder implements PhraseBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $charset;
|
||||||
|
/**
|
||||||
|
* Constructs a PhraseBuilder with given parameters
|
||||||
|
*/
|
||||||
|
public function __construct($length = 5, $charset = 'abcdefghijklmnpqrstuvwxyz123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||||
|
{
|
||||||
|
$this->length = $length;
|
||||||
|
$this->charset = $charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random phrase of given length with given charset
|
||||||
|
*/
|
||||||
|
public function build($length = null, $charset = null)
|
||||||
|
{
|
||||||
|
if ($length !== null) {
|
||||||
|
$this->length = $length;
|
||||||
|
}
|
||||||
|
if ($charset !== null) {
|
||||||
|
$this->charset = $charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
$phrase = '';
|
||||||
|
$chars = str_split($this->charset);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $this->length; $i++) {
|
||||||
|
$phrase .= $chars[array_rand($chars)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $phrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Niceize" a code
|
||||||
|
*/
|
||||||
|
public function niceize($str)
|
||||||
|
{
|
||||||
|
return self::doNiceize($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static helper to niceize
|
||||||
|
*/
|
||||||
|
public static function doNiceize($str)
|
||||||
|
{
|
||||||
|
return strtr(strtolower($str), '01', 'ol');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static helper to compare
|
||||||
|
*/
|
||||||
|
public static function comparePhrases($str1, $str2)
|
||||||
|
{
|
||||||
|
return self::doNiceize($str1) === self::doNiceize($str2);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilderInterface.php
vendored
Normal file
21
vendor/gregwar/captcha/src/Gregwar/Captcha/PhraseBuilderInterface.php
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Gregwar\Captcha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the PhraseBuilder
|
||||||
|
*
|
||||||
|
* @author Gregwar <g.passault@gmail.com>
|
||||||
|
*/
|
||||||
|
interface PhraseBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates random phrase of given length with given charset
|
||||||
|
*/
|
||||||
|
public function build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Niceize" a code
|
||||||
|
*/
|
||||||
|
public function niceize($str);
|
||||||
|
}
|
||||||
30
vendor/gregwar/captcha/tests/CaptchaBuilderTest.php
vendored
Normal file
30
vendor/gregwar/captcha/tests/CaptchaBuilderTest.php
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Test;
|
||||||
|
|
||||||
|
use Gregwar\Captcha\CaptchaBuilder;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class CaptchaBuilderTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testDemo()
|
||||||
|
{
|
||||||
|
$captcha = new CaptchaBuilder();
|
||||||
|
$captcha
|
||||||
|
->build()
|
||||||
|
->save('out.jpg')
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->assertTrue(file_exists(__DIR__.'/../out.jpg'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFingerPrint()
|
||||||
|
{
|
||||||
|
$int = count(CaptchaBuilder::create()
|
||||||
|
->build()
|
||||||
|
->getFingerprint()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue(is_int($int));
|
||||||
|
}
|
||||||
|
}
|
||||||
3
vendor/symfony/finder/.gitattributes
vendored
Normal file
3
vendor/symfony/finder/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
/Tests export-ignore
|
||||||
|
/phpunit.xml.dist export-ignore
|
||||||
|
/.gitignore export-ignore
|
||||||
79
vendor/symfony/finder/CHANGELOG.md
vendored
Normal file
79
vendor/symfony/finder/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
|
||||||
|
5.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added `$useNaturalSort` argument to `Finder::sortByName()`
|
||||||
|
|
||||||
|
4.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added Finder::ignoreVCSIgnored() to ignore files based on rules listed in .gitignore
|
||||||
|
|
||||||
|
4.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added $useNaturalSort option to Finder::sortByName() method
|
||||||
|
* the `Finder::sortByName()` method will have a new `$useNaturalSort`
|
||||||
|
argument in version 5.0, not defining it is deprecated
|
||||||
|
* added `Finder::reverseSorting()` to reverse the sorting
|
||||||
|
|
||||||
|
4.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* removed `ExceptionInterface`
|
||||||
|
* removed `Symfony\Component\Finder\Iterator\FilterIterator`
|
||||||
|
|
||||||
|
3.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* deprecated `Symfony\Component\Finder\Iterator\FilterIterator`
|
||||||
|
* added Finder::hasResults() method to check if any results were found
|
||||||
|
|
||||||
|
3.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added double-star matching to Glob::toRegex()
|
||||||
|
|
||||||
|
3.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* removed deprecated classes
|
||||||
|
|
||||||
|
2.8.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* deprecated adapters and related classes
|
||||||
|
|
||||||
|
2.5.0
|
||||||
|
-----
|
||||||
|
* added support for GLOB_BRACE in the paths passed to Finder::in()
|
||||||
|
|
||||||
|
2.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
|
||||||
|
* unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception
|
||||||
|
|
||||||
|
2.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added Finder::path() and Finder::notPath() methods
|
||||||
|
* added finder adapters to improve performance on specific platforms
|
||||||
|
* added support for wildcard characters (glob patterns) in the paths passed
|
||||||
|
to Finder::in()
|
||||||
|
|
||||||
|
2.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
|
||||||
|
Finder::sortByModifiedTime()
|
||||||
|
* added Countable to Finder
|
||||||
|
* added support for an array of directories as an argument to
|
||||||
|
Finder::exclude()
|
||||||
|
* added searching based on the file content via Finder::contains() and
|
||||||
|
Finder::notContains()
|
||||||
|
* added support for the != operator in the Comparator
|
||||||
|
* [BC BREAK] filter expressions (used for file name and content) are no more
|
||||||
|
considered as regexps but glob patterns when they are enclosed in '*' or '?'
|
||||||
91
vendor/symfony/finder/Comparator/Comparator.php
vendored
Normal file
91
vendor/symfony/finder/Comparator/Comparator.php
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?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\Component\Finder\Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparator.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class Comparator
|
||||||
|
{
|
||||||
|
private $target;
|
||||||
|
private $operator = '==';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the target value.
|
||||||
|
*
|
||||||
|
* @return string The target value
|
||||||
|
*/
|
||||||
|
public function getTarget()
|
||||||
|
{
|
||||||
|
return $this->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTarget(string $target)
|
||||||
|
{
|
||||||
|
$this->target = $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the comparison operator.
|
||||||
|
*
|
||||||
|
* @return string The operator
|
||||||
|
*/
|
||||||
|
public function getOperator()
|
||||||
|
{
|
||||||
|
return $this->operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the comparison operator.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setOperator(string $operator)
|
||||||
|
{
|
||||||
|
if ('' === $operator) {
|
||||||
|
$operator = '==';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->operator = $operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests against the target.
|
||||||
|
*
|
||||||
|
* @param mixed $test A test value
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function test($test)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
vendor/symfony/finder/Comparator/DateComparator.php
vendored
Normal file
51
vendor/symfony/finder/Comparator/DateComparator.php
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?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\Component\Finder\Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateCompare compiles date comparisons.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class DateComparator extends Comparator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $test A comparison string
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the test is not understood
|
||||||
|
*/
|
||||||
|
public function __construct(string $test)
|
||||||
|
{
|
||||||
|
if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$date = new \DateTime($matches[2]);
|
||||||
|
$target = $date->format('U');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$operator = isset($matches[1]) ? $matches[1] : '==';
|
||||||
|
if ('since' === $operator || 'after' === $operator) {
|
||||||
|
$operator = '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('until' === $operator || 'before' === $operator) {
|
||||||
|
$operator = '<';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setOperator($operator);
|
||||||
|
$this->setTarget($target);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
vendor/symfony/finder/Comparator/NumberComparator.php
vendored
Normal file
79
vendor/symfony/finder/Comparator/NumberComparator.php
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?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\Component\Finder\Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NumberComparator compiles a simple comparison to an anonymous
|
||||||
|
* subroutine, which you can call with a value to be tested again.
|
||||||
|
*
|
||||||
|
* Now this would be very pointless, if NumberCompare didn't understand
|
||||||
|
* magnitudes.
|
||||||
|
*
|
||||||
|
* The target value may use magnitudes of kilobytes (k, ki),
|
||||||
|
* megabytes (m, mi), or gigabytes (g, gi). Those suffixed
|
||||||
|
* with an i use the appropriate 2**n version in accordance with the
|
||||||
|
* IEC standard: http://physics.nist.gov/cuu/Units/binary.html
|
||||||
|
*
|
||||||
|
* Based on the Perl Number::Compare module.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com> PHP port
|
||||||
|
* @author Richard Clamp <richardc@unixbeard.net> Perl version
|
||||||
|
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
|
||||||
|
*
|
||||||
|
* @see http://physics.nist.gov/cuu/Units/binary.html
|
||||||
|
*/
|
||||||
|
class NumberComparator extends Comparator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string|int $test A comparison string or an integer
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If the test is not understood
|
||||||
|
*/
|
||||||
|
public function __construct(?string $test)
|
||||||
|
{
|
||||||
|
if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = $matches[2];
|
||||||
|
if (!is_numeric($target)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
|
||||||
|
}
|
||||||
|
if (isset($matches[3])) {
|
||||||
|
// magnitude
|
||||||
|
switch (strtolower($matches[3])) {
|
||||||
|
case 'k':
|
||||||
|
$target *= 1000;
|
||||||
|
break;
|
||||||
|
case 'ki':
|
||||||
|
$target *= 1024;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
$target *= 1000000;
|
||||||
|
break;
|
||||||
|
case 'mi':
|
||||||
|
$target *= 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
$target *= 1000000000;
|
||||||
|
break;
|
||||||
|
case 'gi':
|
||||||
|
$target *= 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setTarget($target);
|
||||||
|
$this->setOperator(isset($matches[1]) ? $matches[1] : '==');
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/symfony/finder/Exception/AccessDeniedException.php
vendored
Normal file
19
vendor/symfony/finder/Exception/AccessDeniedException.php
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?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\Component\Finder\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||||
|
*/
|
||||||
|
class AccessDeniedException extends \UnexpectedValueException
|
||||||
|
{
|
||||||
|
}
|
||||||
19
vendor/symfony/finder/Exception/DirectoryNotFoundException.php
vendored
Normal file
19
vendor/symfony/finder/Exception/DirectoryNotFoundException.php
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?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\Component\Finder\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Erhard <andreas.erhard@i-med.ac.at>
|
||||||
|
*/
|
||||||
|
class DirectoryNotFoundException extends \InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
||||||
793
vendor/symfony/finder/Finder.php
vendored
Normal file
793
vendor/symfony/finder/Finder.php
vendored
Normal file
|
|
@ -0,0 +1,793 @@
|
||||||
|
<?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\Component\Finder;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Comparator\DateComparator;
|
||||||
|
use Symfony\Component\Finder\Comparator\NumberComparator;
|
||||||
|
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
|
||||||
|
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
|
||||||
|
use Symfony\Component\Finder\Iterator\SortableIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finder allows to build rules to find files and directories.
|
||||||
|
*
|
||||||
|
* It is a thin wrapper around several specialized iterator classes.
|
||||||
|
*
|
||||||
|
* All rules may be invoked several times.
|
||||||
|
*
|
||||||
|
* All methods return the current Finder object to allow chaining:
|
||||||
|
*
|
||||||
|
* $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class Finder implements \IteratorAggregate, \Countable
|
||||||
|
{
|
||||||
|
const IGNORE_VCS_FILES = 1;
|
||||||
|
const IGNORE_DOT_FILES = 2;
|
||||||
|
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 static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Finder.
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
public static function create()
|
||||||
|
{
|
||||||
|
return new static();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restricts the matching to directories only.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function directories()
|
||||||
|
{
|
||||||
|
$this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restricts the matching to files only.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function files()
|
||||||
|
{
|
||||||
|
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tests for the directory depth.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* $finder->depth('> 1') // the Finder will start matching at level 1.
|
||||||
|
* $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
|
||||||
|
* $finder->depth(['>= 1', '< 3'])
|
||||||
|
*
|
||||||
|
* @param string|int|string[]|int[] $levels The depth level expression or an array of depth levels
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see DepthRangeFilterIterator
|
||||||
|
* @see NumberComparator
|
||||||
|
*/
|
||||||
|
public function depth($levels)
|
||||||
|
{
|
||||||
|
foreach ((array) $levels as $level) {
|
||||||
|
$this->depths[] = new Comparator\NumberComparator($level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tests for file dates (last modified).
|
||||||
|
*
|
||||||
|
* The date must be something that strtotime() is able to parse:
|
||||||
|
*
|
||||||
|
* $finder->date('since yesterday');
|
||||||
|
* $finder->date('until 2 days ago');
|
||||||
|
* $finder->date('> now - 2 hours');
|
||||||
|
* $finder->date('>= 2005-10-15');
|
||||||
|
* $finder->date(['>= 2005-10-15', '<= 2006-05-27']);
|
||||||
|
*
|
||||||
|
* @param string|string[] $dates A date range string or an array of date ranges
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see strtotime
|
||||||
|
* @see DateRangeFilterIterator
|
||||||
|
* @see DateComparator
|
||||||
|
*/
|
||||||
|
public function date($dates)
|
||||||
|
{
|
||||||
|
foreach ((array) $dates as $date) {
|
||||||
|
$this->dates[] = new Comparator\DateComparator($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rules that files must match.
|
||||||
|
*
|
||||||
|
* You can use patterns (delimited with / sign), globs or simple strings.
|
||||||
|
*
|
||||||
|
* $finder->name('*.php')
|
||||||
|
* $finder->name('/\.php$/') // same as above
|
||||||
|
* $finder->name('test.php')
|
||||||
|
* $finder->name(['test.py', 'test.php'])
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilenameFilterIterator
|
||||||
|
*/
|
||||||
|
public function name($patterns)
|
||||||
|
{
|
||||||
|
$this->names = array_merge($this->names, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rules that files must not match.
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilenameFilterIterator
|
||||||
|
*/
|
||||||
|
public function notName($patterns)
|
||||||
|
{
|
||||||
|
$this->notNames = array_merge($this->notNames, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tests that file contents must match.
|
||||||
|
*
|
||||||
|
* Strings or PCRE patterns can be used:
|
||||||
|
*
|
||||||
|
* $finder->contains('Lorem ipsum')
|
||||||
|
* $finder->contains('/Lorem ipsum/i')
|
||||||
|
* $finder->contains(['dolor', '/ipsum/i'])
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (string or regexp) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilecontentFilterIterator
|
||||||
|
*/
|
||||||
|
public function contains($patterns)
|
||||||
|
{
|
||||||
|
$this->contains = array_merge($this->contains, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tests that file contents must not match.
|
||||||
|
*
|
||||||
|
* Strings or PCRE patterns can be used:
|
||||||
|
*
|
||||||
|
* $finder->notContains('Lorem ipsum')
|
||||||
|
* $finder->notContains('/Lorem ipsum/i')
|
||||||
|
* $finder->notContains(['lorem', '/dolor/i'])
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (string or regexp) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilecontentFilterIterator
|
||||||
|
*/
|
||||||
|
public function notContains($patterns)
|
||||||
|
{
|
||||||
|
$this->notContains = array_merge($this->notContains, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rules that filenames must match.
|
||||||
|
*
|
||||||
|
* You can use patterns (delimited with / sign) or simple strings.
|
||||||
|
*
|
||||||
|
* $finder->path('some/special/dir')
|
||||||
|
* $finder->path('/some\/special\/dir/') // same as above
|
||||||
|
* $finder->path(['some dir', 'another/dir'])
|
||||||
|
*
|
||||||
|
* Use only / as dirname separator.
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilenameFilterIterator
|
||||||
|
*/
|
||||||
|
public function path($patterns)
|
||||||
|
{
|
||||||
|
$this->paths = array_merge($this->paths, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rules that filenames must not match.
|
||||||
|
*
|
||||||
|
* You can use patterns (delimited with / sign) or simple strings.
|
||||||
|
*
|
||||||
|
* $finder->notPath('some/special/dir')
|
||||||
|
* $finder->notPath('/some\/special\/dir/') // same as above
|
||||||
|
* $finder->notPath(['some/file.txt', 'another/file.log'])
|
||||||
|
*
|
||||||
|
* Use only / as dirname separator.
|
||||||
|
*
|
||||||
|
* @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see FilenameFilterIterator
|
||||||
|
*/
|
||||||
|
public function notPath($patterns)
|
||||||
|
{
|
||||||
|
$this->notPaths = array_merge($this->notPaths, (array) $patterns);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tests for file sizes.
|
||||||
|
*
|
||||||
|
* $finder->size('> 10K');
|
||||||
|
* $finder->size('<= 1Ki');
|
||||||
|
* $finder->size(4);
|
||||||
|
* $finder->size(['> 10K', '< 20K'])
|
||||||
|
*
|
||||||
|
* @param string|int|string[]|int[] $sizes A size range string or an integer or an array of size ranges
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SizeRangeFilterIterator
|
||||||
|
* @see NumberComparator
|
||||||
|
*/
|
||||||
|
public function size($sizes)
|
||||||
|
{
|
||||||
|
foreach ((array) $sizes as $size) {
|
||||||
|
$this->sizes[] = new Comparator\NumberComparator($size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excludes directories.
|
||||||
|
*
|
||||||
|
* Directories passed as argument must be relative to the ones defined with the `in()` method. For example:
|
||||||
|
*
|
||||||
|
* $finder->in(__DIR__)->exclude('ruby');
|
||||||
|
*
|
||||||
|
* @param string|array $dirs A directory path or an array of directories
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see ExcludeDirectoryFilterIterator
|
||||||
|
*/
|
||||||
|
public function exclude($dirs)
|
||||||
|
{
|
||||||
|
$this->exclude = array_merge($this->exclude, (array) $dirs);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excludes "hidden" directories and files (starting with a dot).
|
||||||
|
*
|
||||||
|
* This option is enabled by default.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see ExcludeDirectoryFilterIterator
|
||||||
|
*/
|
||||||
|
public function ignoreDotFiles(bool $ignoreDotFiles)
|
||||||
|
{
|
||||||
|
if ($ignoreDotFiles) {
|
||||||
|
$this->ignore |= static::IGNORE_DOT_FILES;
|
||||||
|
} else {
|
||||||
|
$this->ignore &= ~static::IGNORE_DOT_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces the finder to ignore version control directories.
|
||||||
|
*
|
||||||
|
* This option is enabled by default.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see ExcludeDirectoryFilterIterator
|
||||||
|
*/
|
||||||
|
public function ignoreVCS(bool $ignoreVCS)
|
||||||
|
{
|
||||||
|
if ($ignoreVCS) {
|
||||||
|
$this->ignore |= static::IGNORE_VCS_FILES;
|
||||||
|
} else {
|
||||||
|
$this->ignore &= ~static::IGNORE_VCS_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces Finder to obey .gitignore and ignore files based on rules listed there.
|
||||||
|
*
|
||||||
|
* This option is disabled by default.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function ignoreVCSIgnored(bool $ignoreVCSIgnored)
|
||||||
|
{
|
||||||
|
if ($ignoreVCSIgnored) {
|
||||||
|
$this->ignore |= static::IGNORE_VCS_IGNORED_FILES;
|
||||||
|
} else {
|
||||||
|
$this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds VCS patterns.
|
||||||
|
*
|
||||||
|
* @see ignoreVCS()
|
||||||
|
*
|
||||||
|
* @param string|string[] $pattern VCS patterns to ignore
|
||||||
|
*/
|
||||||
|
public static function addVCSPattern($pattern)
|
||||||
|
{
|
||||||
|
foreach ((array) $pattern as $p) {
|
||||||
|
self::$vcsPatterns[] = $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$vcsPatterns = array_unique(self::$vcsPatterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by an anonymous function.
|
||||||
|
*
|
||||||
|
* The anonymous function receives two \SplFileInfo instances to compare.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sort(\Closure $closure)
|
||||||
|
{
|
||||||
|
$this->sort = $closure;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by name.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sortByName(bool $useNaturalSort = false)
|
||||||
|
{
|
||||||
|
$this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by type (directories before files), then by name.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sortByType()
|
||||||
|
{
|
||||||
|
$this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by the last accessed time.
|
||||||
|
*
|
||||||
|
* This is the time that the file was last accessed, read or written to.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sortByAccessedTime()
|
||||||
|
{
|
||||||
|
$this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverses the sorting.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function reverseSorting()
|
||||||
|
{
|
||||||
|
$this->reverseSorting = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by the last inode changed time.
|
||||||
|
*
|
||||||
|
* This is the time that the inode information was last modified (permissions, owner, group or other metadata).
|
||||||
|
*
|
||||||
|
* On Windows, since inode is not available, changed time is actually the file creation time.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sortByChangedTime()
|
||||||
|
{
|
||||||
|
$this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts files and directories by the last modified time.
|
||||||
|
*
|
||||||
|
* This is the last time the actual contents of the file were last modified.
|
||||||
|
*
|
||||||
|
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see SortableIterator
|
||||||
|
*/
|
||||||
|
public function sortByModifiedTime()
|
||||||
|
{
|
||||||
|
$this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator with an anonymous function.
|
||||||
|
*
|
||||||
|
* The anonymous function receives a \SplFileInfo and must return false
|
||||||
|
* to remove files.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @see CustomFilterIterator
|
||||||
|
*/
|
||||||
|
public function filter(\Closure $closure)
|
||||||
|
{
|
||||||
|
$this->filters[] = $closure;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces the following of symlinks.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function followLinks()
|
||||||
|
{
|
||||||
|
$this->followLinks = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells finder to ignore unreadable directories.
|
||||||
|
*
|
||||||
|
* By default, scanning unreadable directories content throws an AccessDeniedException.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function ignoreUnreadableDirs(bool $ignore = true)
|
||||||
|
{
|
||||||
|
$this->ignoreUnreadableDirs = $ignore;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches files and directories which match defined rules.
|
||||||
|
*
|
||||||
|
* @param string|string[] $dirs A directory path or an array of directories
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws DirectoryNotFoundException if one of the directories does not exist
|
||||||
|
*/
|
||||||
|
public function in($dirs)
|
||||||
|
{
|
||||||
|
$resolvedDirs = [];
|
||||||
|
|
||||||
|
foreach ((array) $dirs as $dir) {
|
||||||
|
if (is_dir($dir)) {
|
||||||
|
$resolvedDirs[] = $this->normalizeDir($dir);
|
||||||
|
} elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR | GLOB_NOSORT)) {
|
||||||
|
sort($glob);
|
||||||
|
$resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob));
|
||||||
|
} else {
|
||||||
|
throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dirs = array_merge($this->dirs, $resolvedDirs);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Iterator for the current Finder configuration.
|
||||||
|
*
|
||||||
|
* This method implements the IteratorAggregate interface.
|
||||||
|
*
|
||||||
|
* @return \Iterator|SplFileInfo[] An iterator
|
||||||
|
*
|
||||||
|
* @throws \LogicException if the in() method has not been called
|
||||||
|
*/
|
||||||
|
public function getIterator()
|
||||||
|
{
|
||||||
|
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.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
|
||||||
|
return $this->searchInDirectory($this->dirs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new \AppendIterator();
|
||||||
|
foreach ($this->dirs as $dir) {
|
||||||
|
$iterator->append($this->searchInDirectory($dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->iterators as $it) {
|
||||||
|
$iterator->append($it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an existing set of files/directories to the finder.
|
||||||
|
*
|
||||||
|
* The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException when the given argument is not iterable
|
||||||
|
*/
|
||||||
|
public function append(iterable $iterator)
|
||||||
|
{
|
||||||
|
if ($iterator instanceof \IteratorAggregate) {
|
||||||
|
$this->iterators[] = $iterator->getIterator();
|
||||||
|
} elseif ($iterator instanceof \Iterator) {
|
||||||
|
$this->iterators[] = $iterator;
|
||||||
|
} elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
|
||||||
|
$it = new \ArrayIterator();
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
$it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
|
||||||
|
}
|
||||||
|
$this->iterators[] = $it;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the any results were found.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasResults()
|
||||||
|
{
|
||||||
|
foreach ($this->getIterator() as $_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts all the results collected by the iterators.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return iterator_count($this->getIterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function searchInDirectory(string $dir): \Iterator
|
||||||
|
{
|
||||||
|
$exclude = $this->exclude;
|
||||||
|
$notPaths = $this->notPaths;
|
||||||
|
|
||||||
|
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
|
||||||
|
$exclude = array_merge($exclude, self::$vcsPatterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
|
||||||
|
$notPaths[] = '#(^|/)\..+(/|$)#';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) {
|
||||||
|
$gitignoreFilePath = sprintf('%s/.gitignore', $dir);
|
||||||
|
if (!is_readable($gitignoreFilePath)) {
|
||||||
|
throw new \RuntimeException(sprintf('The "ignoreVCSIgnored" option cannot be used by the Finder as the "%s" file is not readable.', $gitignoreFilePath));
|
||||||
|
}
|
||||||
|
$notPaths = array_merge($notPaths, [Gitignore::toRegex(file_get_contents($gitignoreFilePath))]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$minDepth = 0;
|
||||||
|
$maxDepth = PHP_INT_MAX;
|
||||||
|
|
||||||
|
foreach ($this->depths as $comparator) {
|
||||||
|
switch ($comparator->getOperator()) {
|
||||||
|
case '>':
|
||||||
|
$minDepth = $comparator->getTarget() + 1;
|
||||||
|
break;
|
||||||
|
case '>=':
|
||||||
|
$minDepth = $comparator->getTarget();
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
$maxDepth = $comparator->getTarget() - 1;
|
||||||
|
break;
|
||||||
|
case '<=':
|
||||||
|
$maxDepth = $comparator->getTarget();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$minDepth = $maxDepth = $comparator->getTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
||||||
|
|
||||||
|
if ($this->followLinks) {
|
||||||
|
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
|
||||||
|
|
||||||
|
if ($exclude) {
|
||||||
|
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
|
||||||
|
|
||||||
|
if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
|
||||||
|
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->mode) {
|
||||||
|
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->names || $this->notNames) {
|
||||||
|
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->contains || $this->notContains) {
|
||||||
|
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->sizes) {
|
||||||
|
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dates) {
|
||||||
|
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->filters) {
|
||||||
|
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->paths || $notPaths) {
|
||||||
|
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->sort || $this->reverseSorting) {
|
||||||
|
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting);
|
||||||
|
$iterator = $iteratorAggregate->getIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes given directory names by removing trailing slashes.
|
||||||
|
*
|
||||||
|
* Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper
|
||||||
|
*/
|
||||||
|
private function normalizeDir(string $dir): string
|
||||||
|
{
|
||||||
|
$dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
|
if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
|
||||||
|
$dir .= '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
vendor/symfony/finder/Gitignore.php
vendored
Normal file
105
vendor/symfony/finder/Gitignore.php
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?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\Component\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gitignore matches against text.
|
||||||
|
*
|
||||||
|
* @author Ahmed Abdou <mail@ahmd.io>
|
||||||
|
*/
|
||||||
|
class Gitignore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns a regexp which is the equivalent of the gitignore pattern.
|
||||||
|
*
|
||||||
|
* @return string The regexp
|
||||||
|
*/
|
||||||
|
public static function toRegex(string $gitignoreFileContent): string
|
||||||
|
{
|
||||||
|
$gitignoreFileContent = preg_replace('/^[^\\\r\n]*#.*/m', '', $gitignoreFileContent);
|
||||||
|
$gitignoreLines = preg_split('/\r\n|\r|\n/', $gitignoreFileContent);
|
||||||
|
$gitignoreLines = array_map('trim', $gitignoreLines);
|
||||||
|
$gitignoreLines = array_filter($gitignoreLines);
|
||||||
|
|
||||||
|
$ignoreLinesPositive = array_filter($gitignoreLines, function (string $line) {
|
||||||
|
return !preg_match('/^!/', $line);
|
||||||
|
});
|
||||||
|
|
||||||
|
$ignoreLinesNegative = array_filter($gitignoreLines, function (string $line) {
|
||||||
|
return preg_match('/^!/', $line);
|
||||||
|
});
|
||||||
|
|
||||||
|
$ignoreLinesNegative = array_map(function (string $line) {
|
||||||
|
return preg_replace('/^!(.*)/', '${1}', $line);
|
||||||
|
}, $ignoreLinesNegative);
|
||||||
|
$ignoreLinesNegative = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesNegative);
|
||||||
|
|
||||||
|
$ignoreLinesPositive = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesPositive);
|
||||||
|
if (empty($ignoreLinesPositive)) {
|
||||||
|
return '/^$/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($ignoreLinesNegative)) {
|
||||||
|
return sprintf('/%s/', implode('|', $ignoreLinesPositive));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('/(?=^(?:(?!(%s)).)*$)(%s)/', implode('|', $ignoreLinesNegative), implode('|', $ignoreLinesPositive));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getRegexFromGitignore(string $gitignorePattern): string
|
||||||
|
{
|
||||||
|
$regex = '(';
|
||||||
|
if (0 === strpos($gitignorePattern, '/')) {
|
||||||
|
$gitignorePattern = substr($gitignorePattern, 1);
|
||||||
|
$regex .= '^';
|
||||||
|
} else {
|
||||||
|
$regex .= '(^|\/)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('/' === $gitignorePattern[\strlen($gitignorePattern) - 1]) {
|
||||||
|
$gitignorePattern = substr($gitignorePattern, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iMax = \strlen($gitignorePattern);
|
||||||
|
for ($i = 0; $i < $iMax; ++$i) {
|
||||||
|
$doubleChars = substr($gitignorePattern, $i, 2);
|
||||||
|
if ('**' === $doubleChars) {
|
||||||
|
$regex .= '.+';
|
||||||
|
++$i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$c = $gitignorePattern[$i];
|
||||||
|
switch ($c) {
|
||||||
|
case '*':
|
||||||
|
$regex .= '[^\/]+';
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
case '.':
|
||||||
|
case ':':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
$regex .= '\\'.$c;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$regex .= $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex .= '($|\/)';
|
||||||
|
$regex .= ')';
|
||||||
|
|
||||||
|
return $regex;
|
||||||
|
}
|
||||||
|
}
|
||||||
111
vendor/symfony/finder/Glob.php
vendored
Normal file
111
vendor/symfony/finder/Glob.php
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?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\Component\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Glob matches globbing patterns against text.
|
||||||
|
*
|
||||||
|
* if match_glob("foo.*", "foo.bar") echo "matched\n";
|
||||||
|
*
|
||||||
|
* // prints foo.bar and foo.baz
|
||||||
|
* $regex = glob_to_regex("foo.*");
|
||||||
|
* for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t)
|
||||||
|
* {
|
||||||
|
* if (/$regex/) echo "matched: $car\n";
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Glob implements glob(3) style matching that can be used to match
|
||||||
|
* against text, rather than fetching names from a filesystem.
|
||||||
|
*
|
||||||
|
* Based on the Perl Text::Glob module.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com> PHP port
|
||||||
|
* @author Richard Clamp <richardc@unixbeard.net> Perl version
|
||||||
|
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
|
||||||
|
*/
|
||||||
|
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 = '#')
|
||||||
|
{
|
||||||
|
$firstByte = true;
|
||||||
|
$escaping = false;
|
||||||
|
$inCurlies = 0;
|
||||||
|
$regex = '';
|
||||||
|
$sizeGlob = \strlen($glob);
|
||||||
|
for ($i = 0; $i < $sizeGlob; ++$i) {
|
||||||
|
$car = $glob[$i];
|
||||||
|
if ($firstByte && $strictLeadingDot && '.' !== $car) {
|
||||||
|
$regex .= '(?=[^\.])';
|
||||||
|
}
|
||||||
|
|
||||||
|
$firstByte = '/' === $car;
|
||||||
|
|
||||||
|
if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {
|
||||||
|
$car = '[^/]++/';
|
||||||
|
if (!isset($glob[$i + 3])) {
|
||||||
|
$car .= '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($strictLeadingDot) {
|
||||||
|
$car = '(?=[^\.])'.$car;
|
||||||
|
}
|
||||||
|
|
||||||
|
$car = '/(?:'.$car.')*';
|
||||||
|
$i += 2 + isset($glob[$i + 3]);
|
||||||
|
|
||||||
|
if ('/' === $delimiter) {
|
||||||
|
$car = str_replace('/', '\\/', $car);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
|
||||||
|
$regex .= "\\$car";
|
||||||
|
} elseif ('*' === $car) {
|
||||||
|
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
|
||||||
|
} elseif ('?' === $car) {
|
||||||
|
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
|
||||||
|
} elseif ('{' === $car) {
|
||||||
|
$regex .= $escaping ? '\\{' : '(';
|
||||||
|
if (!$escaping) {
|
||||||
|
++$inCurlies;
|
||||||
|
}
|
||||||
|
} elseif ('}' === $car && $inCurlies) {
|
||||||
|
$regex .= $escaping ? '}' : ')';
|
||||||
|
if (!$escaping) {
|
||||||
|
--$inCurlies;
|
||||||
|
}
|
||||||
|
} elseif (',' === $car && $inCurlies) {
|
||||||
|
$regex .= $escaping ? ',' : '|';
|
||||||
|
} elseif ('\\' === $car) {
|
||||||
|
if ($escaping) {
|
||||||
|
$regex .= '\\\\';
|
||||||
|
$escaping = false;
|
||||||
|
} else {
|
||||||
|
$escaping = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$regex .= $car;
|
||||||
|
}
|
||||||
|
$escaping = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $delimiter.'^'.$regex.'$'.$delimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
vendor/symfony/finder/Iterator/CustomFilterIterator.php
vendored
Normal file
61
vendor/symfony/finder/Iterator/CustomFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFilterIterator filters files by applying anonymous functions.
|
||||||
|
*
|
||||||
|
* The anonymous function receives a \SplFileInfo and must return false
|
||||||
|
* to remove files.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class CustomFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
private $filters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
|
* @param callable[] $filters An array of PHP callbacks
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, array $filters)
|
||||||
|
{
|
||||||
|
foreach ($filters as $filter) {
|
||||||
|
if (!\is_callable($filter)) {
|
||||||
|
throw new \InvalidArgumentException('Invalid PHP callback.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->filters = $filters;
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
$fileinfo = $this->current();
|
||||||
|
|
||||||
|
foreach ($this->filters as $filter) {
|
||||||
|
if (false === $filter($fileinfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
vendor/symfony/finder/Iterator/DateRangeFilterIterator.php
vendored
Normal file
58
vendor/symfony/finder/Iterator/DateRangeFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Comparator\DateComparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class DateRangeFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
private $comparators = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
|
* @param DateComparator[] $comparators An array of DateComparator instances
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, array $comparators)
|
||||||
|
{
|
||||||
|
$this->comparators = $comparators;
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
$fileinfo = $this->current();
|
||||||
|
|
||||||
|
if (!file_exists($fileinfo->getPathname())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filedate = $fileinfo->getMTime();
|
||||||
|
foreach ($this->comparators as $compare) {
|
||||||
|
if (!$compare->test($filedate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php
vendored
Normal file
45
vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DepthRangeFilterIterator limits the directory depth.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class DepthRangeFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
private $minDepth = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \RecursiveIteratorIterator $iterator The Iterator to filter
|
||||||
|
* @param int $minDepth The min depth
|
||||||
|
* @param int $maxDepth The max depth
|
||||||
|
*/
|
||||||
|
public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = PHP_INT_MAX)
|
||||||
|
{
|
||||||
|
$this->minDepth = $minDepth;
|
||||||
|
$iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php
vendored
Normal file
87
vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExcludeDirectoryFilterIterator filters out directories.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
|
||||||
|
{
|
||||||
|
private $iterator;
|
||||||
|
private $isRecursive;
|
||||||
|
private $excludedDirs = [];
|
||||||
|
private $excludedPattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
|
* @param string[] $directories An array of directories to exclude
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, array $directories)
|
||||||
|
{
|
||||||
|
$this->iterator = $iterator;
|
||||||
|
$this->isRecursive = $iterator instanceof \RecursiveIterator;
|
||||||
|
$patterns = [];
|
||||||
|
foreach ($directories as $directory) {
|
||||||
|
$directory = rtrim($directory, '/');
|
||||||
|
if (!$this->isRecursive || false !== strpos($directory, '/')) {
|
||||||
|
$patterns[] = preg_quote($directory, '#');
|
||||||
|
} else {
|
||||||
|
$this->excludedDirs[$directory] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($patterns) {
|
||||||
|
$this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool True if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->excludedPattern) {
|
||||||
|
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
|
||||||
|
$path = str_replace('\\', '/', $path);
|
||||||
|
|
||||||
|
return !preg_match($this->excludedPattern, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasChildren()
|
||||||
|
{
|
||||||
|
return $this->isRecursive && $this->iterator->hasChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
$children = new self($this->iterator->getChildren(), []);
|
||||||
|
$children->excludedDirs = $this->excludedDirs;
|
||||||
|
$children->excludedPattern = $this->excludedPattern;
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
vendor/symfony/finder/Iterator/FileTypeFilterIterator.php
vendored
Normal file
53
vendor/symfony/finder/Iterator/FileTypeFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileTypeFilterIterator only keeps files, directories, or both.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class FileTypeFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
const ONLY_FILES = 1;
|
||||||
|
const ONLY_DIRECTORIES = 2;
|
||||||
|
|
||||||
|
private $mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
|
* @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, int $mode)
|
||||||
|
{
|
||||||
|
$this->mode = $mode;
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
$fileinfo = $this->current();
|
||||||
|
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
|
||||||
|
return false;
|
||||||
|
} elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
vendor/symfony/finder/Iterator/FilecontentFilterIterator.php
vendored
Normal file
58
vendor/symfony/finder/Iterator/FilecontentFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
||||||
|
*/
|
||||||
|
class FilecontentFilterIterator extends MultiplePcreFilterIterator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
if (!$this->matchRegexps && !$this->noMatchRegexps) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileinfo = $this->current();
|
||||||
|
|
||||||
|
if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $fileinfo->getContents();
|
||||||
|
if (!$content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->isAccepted($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts string to regexp if necessary.
|
||||||
|
*
|
||||||
|
* @param string $str Pattern: string or regexp
|
||||||
|
*
|
||||||
|
* @return string regexp corresponding to a given string or regexp
|
||||||
|
*/
|
||||||
|
protected function toRegex(string $str)
|
||||||
|
{
|
||||||
|
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
||||||
|
}
|
||||||
|
}
|
||||||
47
vendor/symfony/finder/Iterator/FilenameFilterIterator.php
vendored
Normal file
47
vendor/symfony/finder/Iterator/FilenameFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Glob;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class FilenameFilterIterator extends MultiplePcreFilterIterator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
return $this->isAccepted($this->current()->getFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts glob to regexp.
|
||||||
|
*
|
||||||
|
* PCRE patterns are left unchanged.
|
||||||
|
* Glob strings are transformed with Glob::toRegex().
|
||||||
|
*
|
||||||
|
* @param string $str Pattern: glob or regexp
|
||||||
|
*
|
||||||
|
* @return string regexp corresponding to a given glob or regexp
|
||||||
|
*/
|
||||||
|
protected function toRegex(string $str)
|
||||||
|
{
|
||||||
|
return $this->isRegex($str) ? $str : Glob::toRegex($str);
|
||||||
|
}
|
||||||
|
}
|
||||||
106
vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php
vendored
Normal file
106
vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
abstract class MultiplePcreFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
protected $matchRegexps = [];
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
|
||||||
|
{
|
||||||
|
foreach ($matchPatterns as $pattern) {
|
||||||
|
$this->matchRegexps[] = $this->toRegex($pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($noMatchPatterns as $pattern) {
|
||||||
|
$this->noMatchRegexps[] = $this->toRegex($pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the string is accepted by the regex filters.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
// should at least not match one rule to exclude
|
||||||
|
foreach ($this->noMatchRegexps as $regex) {
|
||||||
|
if (preg_match($regex, $string)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// should at least match one rule
|
||||||
|
if ($this->matchRegexps) {
|
||||||
|
foreach ($this->matchRegexps as $regex) {
|
||||||
|
if (preg_match($regex, $string)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no match rules, the file is accepted
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the string is a regex.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isRegex(string $str)
|
||||||
|
{
|
||||||
|
if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
|
||||||
|
$start = substr($m[1], 0, 1);
|
||||||
|
$end = substr($m[1], -1);
|
||||||
|
|
||||||
|
if ($start === $end) {
|
||||||
|
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
|
||||||
|
if ($start === $delimiters[0] && $end === $delimiters[1]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts string into regexp.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract protected function toRegex(string $str);
|
||||||
|
}
|
||||||
56
vendor/symfony/finder/Iterator/PathFilterIterator.php
vendored
Normal file
56
vendor/symfony/finder/Iterator/PathFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PathFilterIterator filters files by path patterns (e.g. some/special/dir).
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
||||||
|
*/
|
||||||
|
class PathFilterIterator extends MultiplePcreFilterIterator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
$filename = $this->current()->getRelativePathname();
|
||||||
|
|
||||||
|
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||||
|
$filename = str_replace('\\', '/', $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->isAccepted($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts strings to regexp.
|
||||||
|
*
|
||||||
|
* PCRE patterns are left unchanged.
|
||||||
|
*
|
||||||
|
* Default conversion:
|
||||||
|
* 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
|
||||||
|
*
|
||||||
|
* Use only / as directory separator (on Windows also).
|
||||||
|
*
|
||||||
|
* @param string $str Pattern: regexp or dirname
|
||||||
|
*
|
||||||
|
* @return string regexp corresponding to a given string or regexp
|
||||||
|
*/
|
||||||
|
protected function toRegex(string $str)
|
||||||
|
{
|
||||||
|
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
||||||
|
}
|
||||||
|
}
|
||||||
140
vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php
vendored
Normal file
140
vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
||||||
|
use Symfony\Component\Finder\SplFileInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the \RecursiveDirectoryIterator to support relative paths.
|
||||||
|
*
|
||||||
|
* @author Victor Berchet <victor@suumit.com>
|
||||||
|
*/
|
||||||
|
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $ignoreUnreadableDirs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $rewindable;
|
||||||
|
|
||||||
|
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
|
||||||
|
private $rootPath;
|
||||||
|
private $subPath;
|
||||||
|
private $directorySeparator = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
|
||||||
|
{
|
||||||
|
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
|
||||||
|
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($path, $flags);
|
||||||
|
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
||||||
|
$this->rootPath = $path;
|
||||||
|
if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
|
||||||
|
$this->directorySeparator = \DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance of SplFileInfo with support for relative paths.
|
||||||
|
*
|
||||||
|
* @return SplFileInfo File information
|
||||||
|
*/
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
// the logic here avoids redoing the same work in all iterations
|
||||||
|
|
||||||
|
if (null === $subPathname = $this->subPath) {
|
||||||
|
$subPathname = $this->subPath = (string) $this->getSubPath();
|
||||||
|
}
|
||||||
|
if ('' !== $subPathname) {
|
||||||
|
$subPathname .= $this->directorySeparator;
|
||||||
|
}
|
||||||
|
$subPathname .= $this->getFilename();
|
||||||
|
|
||||||
|
return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \RecursiveIterator
|
||||||
|
*
|
||||||
|
* @throws AccessDeniedException
|
||||||
|
*/
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$children = parent::getChildren();
|
||||||
|
|
||||||
|
if ($children instanceof self) {
|
||||||
|
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
|
||||||
|
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
|
||||||
|
|
||||||
|
// performance optimization to avoid redoing the same work in all children
|
||||||
|
$children->rewindable = &$this->rewindable;
|
||||||
|
$children->rootPath = $this->rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
} catch (\UnexpectedValueException $e) {
|
||||||
|
if ($this->ignoreUnreadableDirs) {
|
||||||
|
// If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
|
||||||
|
return new \RecursiveArrayIterator([]);
|
||||||
|
} else {
|
||||||
|
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do nothing for non rewindable stream.
|
||||||
|
*/
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
if (false === $this->isRewindable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the stream is rewindable.
|
||||||
|
*
|
||||||
|
* @return bool true when the stream is rewindable, false otherwise
|
||||||
|
*/
|
||||||
|
public function isRewindable()
|
||||||
|
{
|
||||||
|
if (null !== $this->rewindable) {
|
||||||
|
return $this->rewindable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $stream = @opendir($this->getPath())) {
|
||||||
|
$infos = stream_get_meta_data($stream);
|
||||||
|
closedir($stream);
|
||||||
|
|
||||||
|
if ($infos['seekable']) {
|
||||||
|
return $this->rewindable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rewindable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php
vendored
Normal file
57
vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Comparator\NumberComparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SizeRangeFilterIterator filters out files that are not in the given size range.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class SizeRangeFilterIterator extends \FilterIterator
|
||||||
|
{
|
||||||
|
private $comparators = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
|
* @param NumberComparator[] $comparators An array of NumberComparator instances
|
||||||
|
*/
|
||||||
|
public function __construct(\Iterator $iterator, array $comparators)
|
||||||
|
{
|
||||||
|
$this->comparators = $comparators;
|
||||||
|
|
||||||
|
parent::__construct($iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the iterator values.
|
||||||
|
*
|
||||||
|
* @return bool true if the value should be kept, false otherwise
|
||||||
|
*/
|
||||||
|
public function accept()
|
||||||
|
{
|
||||||
|
$fileinfo = $this->current();
|
||||||
|
if (!$fileinfo->isFile()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filesize = $fileinfo->getSize();
|
||||||
|
foreach ($this->comparators as $compare) {
|
||||||
|
if (!$compare->test($filesize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
101
vendor/symfony/finder/Iterator/SortableIterator.php
vendored
Normal file
101
vendor/symfony/finder/Iterator/SortableIterator.php
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?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\Component\Finder\Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SortableIterator applies a sort on a given Iterator.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class SortableIterator implements \IteratorAggregate
|
||||||
|
{
|
||||||
|
const SORT_BY_NONE = 0;
|
||||||
|
const SORT_BY_NAME = 1;
|
||||||
|
const SORT_BY_TYPE = 2;
|
||||||
|
const SORT_BY_ACCESSED_TIME = 3;
|
||||||
|
const SORT_BY_CHANGED_TIME = 4;
|
||||||
|
const SORT_BY_MODIFIED_TIME = 5;
|
||||||
|
const SORT_BY_NAME_NATURAL = 6;
|
||||||
|
|
||||||
|
private $iterator;
|
||||||
|
private $sort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Traversable $iterator The Iterator to filter
|
||||||
|
* @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
|
||||||
|
{
|
||||||
|
$this->iterator = $iterator;
|
||||||
|
$order = $reverseOrder ? -1 : 1;
|
||||||
|
|
||||||
|
if (self::SORT_BY_NAME === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||||
|
};
|
||||||
|
} elseif (self::SORT_BY_NAME_NATURAL === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
return $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||||
|
};
|
||||||
|
} elseif (self::SORT_BY_TYPE === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
if ($a->isDir() && $b->isFile()) {
|
||||||
|
return -$order;
|
||||||
|
} elseif ($a->isFile() && $b->isDir()) {
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
|
||||||
|
};
|
||||||
|
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
return $order * ($a->getATime() - $b->getATime());
|
||||||
|
};
|
||||||
|
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
return $order * ($a->getCTime() - $b->getCTime());
|
||||||
|
};
|
||||||
|
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
||||||
|
$this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
|
||||||
|
return $order * ($a->getMTime() - $b->getMTime());
|
||||||
|
};
|
||||||
|
} 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;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Traversable
|
||||||
|
*/
|
||||||
|
public function getIterator()
|
||||||
|
{
|
||||||
|
if (1 === $this->sort) {
|
||||||
|
return $this->iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
$array = iterator_to_array($this->iterator, true);
|
||||||
|
|
||||||
|
if (-1 === $this->sort) {
|
||||||
|
$array = array_reverse($array);
|
||||||
|
} else {
|
||||||
|
uasort($array, $this->sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new \ArrayIterator($array);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/symfony/finder/LICENSE
vendored
Normal file
19
vendor/symfony/finder/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2004-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.
|
||||||
14
vendor/symfony/finder/README.md
vendored
Normal file
14
vendor/symfony/finder/README.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
Finder Component
|
||||||
|
================
|
||||||
|
|
||||||
|
The Finder component finds files and directories via an intuitive fluent
|
||||||
|
interface.
|
||||||
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
|
||||||
|
* [Documentation](https://symfony.com/doc/current/components/finder.html)
|
||||||
|
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||||
|
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||||
|
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||||
|
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||||
85
vendor/symfony/finder/SplFileInfo.php
vendored
Normal file
85
vendor/symfony/finder/SplFileInfo.php
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?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\Component\Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends \SplFileInfo to support relative paths.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class SplFileInfo extends \SplFileInfo
|
||||||
|
{
|
||||||
|
private $relativePath;
|
||||||
|
private $relativePathname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file The file name
|
||||||
|
* @param string $relativePath The relative path
|
||||||
|
* @param string $relativePathname The relative path name
|
||||||
|
*/
|
||||||
|
public function __construct(string $file, string $relativePath, string $relativePathname)
|
||||||
|
{
|
||||||
|
parent::__construct($file);
|
||||||
|
$this->relativePath = $relativePath;
|
||||||
|
$this->relativePathname = $relativePathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the relative path.
|
||||||
|
*
|
||||||
|
* This path does not contain the file name.
|
||||||
|
*
|
||||||
|
* @return string the relative path
|
||||||
|
*/
|
||||||
|
public function getRelativePath()
|
||||||
|
{
|
||||||
|
return $this->relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the relative path name.
|
||||||
|
*
|
||||||
|
* This path contains the file name.
|
||||||
|
*
|
||||||
|
* @return string the relative path name
|
||||||
|
*/
|
||||||
|
public function getRelativePathname()
|
||||||
|
{
|
||||||
|
return $this->relativePathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilenameWithoutExtension(): string
|
||||||
|
{
|
||||||
|
$filename = $this->getFilename();
|
||||||
|
|
||||||
|
return pathinfo($filename, PATHINFO_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of the file.
|
||||||
|
*
|
||||||
|
* @return string the contents of the file
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
public function getContents()
|
||||||
|
{
|
||||||
|
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||||
|
$content = file_get_contents($this->getPathname());
|
||||||
|
restore_error_handler();
|
||||||
|
if (false === $content) {
|
||||||
|
throw new \RuntimeException($error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
vendor/symfony/finder/composer.json
vendored
Normal file
33
vendor/symfony/finder/composer.json
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "symfony/finder",
|
||||||
|
"type": "library",
|
||||||
|
"description": "Symfony Finder Component",
|
||||||
|
"keywords": [],
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": { "Symfony\\Component\\Finder\\": "" },
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.0-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue