6130 lines
181 KiB
Plaintext
6130 lines
181 KiB
Plaintext
|
#!/usr/bin/env php
|
|||
|
<?php
|
|||
|
|
|||
|
$web = 'index.php';
|
|||
|
|
|||
|
if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
|
|||
|
Phar::interceptFileFuncs();
|
|||
|
set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
|
|||
|
Phar::webPhar(null, $web);
|
|||
|
include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
|
|||
|
Extract_Phar::go(true);
|
|||
|
$mimes = array(
|
|||
|
'phps' => 2,
|
|||
|
'c' => 'text/plain',
|
|||
|
'cc' => 'text/plain',
|
|||
|
'cpp' => 'text/plain',
|
|||
|
'c++' => 'text/plain',
|
|||
|
'dtd' => 'text/plain',
|
|||
|
'h' => 'text/plain',
|
|||
|
'log' => 'text/plain',
|
|||
|
'rng' => 'text/plain',
|
|||
|
'txt' => 'text/plain',
|
|||
|
'xsd' => 'text/plain',
|
|||
|
'php' => 1,
|
|||
|
'inc' => 1,
|
|||
|
'avi' => 'video/avi',
|
|||
|
'bmp' => 'image/bmp',
|
|||
|
'css' => 'text/css',
|
|||
|
'gif' => 'image/gif',
|
|||
|
'htm' => 'text/html',
|
|||
|
'html' => 'text/html',
|
|||
|
'htmls' => 'text/html',
|
|||
|
'ico' => 'image/x-ico',
|
|||
|
'jpe' => 'image/jpeg',
|
|||
|
'jpg' => 'image/jpeg',
|
|||
|
'jpeg' => 'image/jpeg',
|
|||
|
'js' => 'application/x-javascript',
|
|||
|
'midi' => 'audio/midi',
|
|||
|
'mid' => 'audio/midi',
|
|||
|
'mod' => 'audio/mod',
|
|||
|
'mov' => 'movie/quicktime',
|
|||
|
'mp3' => 'audio/mp3',
|
|||
|
'mpg' => 'video/mpeg',
|
|||
|
'mpeg' => 'video/mpeg',
|
|||
|
'pdf' => 'application/pdf',
|
|||
|
'png' => 'image/png',
|
|||
|
'swf' => 'application/shockwave-flash',
|
|||
|
'tif' => 'image/tiff',
|
|||
|
'tiff' => 'image/tiff',
|
|||
|
'wav' => 'audio/wav',
|
|||
|
'xbm' => 'image/xbm',
|
|||
|
'xml' => 'text/xml',
|
|||
|
);
|
|||
|
|
|||
|
header("Cache-Control: no-cache, must-revalidate");
|
|||
|
header("Pragma: no-cache");
|
|||
|
|
|||
|
$basename = basename(__FILE__);
|
|||
|
if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
|
|||
|
chdir(Extract_Phar::$temp);
|
|||
|
include $web;
|
|||
|
return;
|
|||
|
}
|
|||
|
$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
|
|||
|
if (!$pt || $pt == '/') {
|
|||
|
$pt = $web;
|
|||
|
header('HTTP/1.1 301 Moved Permanently');
|
|||
|
header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
|
|||
|
exit;
|
|||
|
}
|
|||
|
$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
|
|||
|
if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
|
|||
|
header('HTTP/1.0 404 Not Found');
|
|||
|
echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File Not Found</h1>\n </body>\n</html>";
|
|||
|
exit;
|
|||
|
}
|
|||
|
$b = pathinfo($a);
|
|||
|
if (!isset($b['extension'])) {
|
|||
|
header('Content-Type: text/plain');
|
|||
|
header('Content-Length: ' . filesize($a));
|
|||
|
readfile($a);
|
|||
|
exit;
|
|||
|
}
|
|||
|
if (isset($mimes[$b['extension']])) {
|
|||
|
if ($mimes[$b['extension']] === 1) {
|
|||
|
include $a;
|
|||
|
exit;
|
|||
|
}
|
|||
|
if ($mimes[$b['extension']] === 2) {
|
|||
|
highlight_file($a);
|
|||
|
exit;
|
|||
|
}
|
|||
|
header('Content-Type: ' .$mimes[$b['extension']]);
|
|||
|
header('Content-Length: ' . filesize($a));
|
|||
|
readfile($a);
|
|||
|
exit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class Extract_Phar
|
|||
|
{
|
|||
|
static $temp;
|
|||
|
static $origdir;
|
|||
|
const GZ = 0x1000;
|
|||
|
const BZ2 = 0x2000;
|
|||
|
const MASK = 0x3000;
|
|||
|
const START = 'bootstrap.php';
|
|||
|
const LEN = 6647;
|
|||
|
|
|||
|
static function go($return = false)
|
|||
|
{
|
|||
|
$fp = fopen(__FILE__, 'rb');
|
|||
|
fseek($fp, self::LEN);
|
|||
|
$L = unpack('V', $a = fread($fp, 4));
|
|||
|
$m = '';
|
|||
|
|
|||
|
do {
|
|||
|
$read = 8192;
|
|||
|
if ($L[1] - strlen($m) < 8192) {
|
|||
|
$read = $L[1] - strlen($m);
|
|||
|
}
|
|||
|
$last = fread($fp, $read);
|
|||
|
$m .= $last;
|
|||
|
} while (strlen($last) && strlen($m) < $L[1]);
|
|||
|
|
|||
|
if (strlen($m) < $L[1]) {
|
|||
|
die('ERROR: manifest length read was "' .
|
|||
|
strlen($m) .'" should be "' .
|
|||
|
$L[1] . '"');
|
|||
|
}
|
|||
|
|
|||
|
$info = self::_unpack($m);
|
|||
|
$f = $info['c'];
|
|||
|
|
|||
|
if ($f & self::GZ) {
|
|||
|
if (!function_exists('gzinflate')) {
|
|||
|
die('Error: zlib extension is not enabled -' .
|
|||
|
' gzinflate() function needed for zlib-compressed .phars');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ($f & self::BZ2) {
|
|||
|
if (!function_exists('bzdecompress')) {
|
|||
|
die('Error: bzip2 extension is not enabled -' .
|
|||
|
' bzdecompress() function needed for bz2-compressed .phars');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$temp = self::tmpdir();
|
|||
|
|
|||
|
if (!$temp || !is_writable($temp)) {
|
|||
|
$sessionpath = session_save_path();
|
|||
|
if (strpos ($sessionpath, ";") !== false)
|
|||
|
$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
|
|||
|
if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
|
|||
|
die('Could not locate temporary directory to extract phar');
|
|||
|
}
|
|||
|
$temp = $sessionpath;
|
|||
|
}
|
|||
|
|
|||
|
$temp .= '/pharextract/'.basename(__FILE__, '.phar');
|
|||
|
self::$temp = $temp;
|
|||
|
self::$origdir = getcwd();
|
|||
|
@mkdir($temp, 0777, true);
|
|||
|
$temp = realpath($temp);
|
|||
|
|
|||
|
if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
|
|||
|
self::_removeTmpFiles($temp, getcwd());
|
|||
|
@mkdir($temp, 0777, true);
|
|||
|
@file_put_contents($temp . '/' . md5_file(__FILE__), '');
|
|||
|
|
|||
|
foreach ($info['m'] as $path => $file) {
|
|||
|
$a = !file_exists(dirname($temp . '/' . $path));
|
|||
|
@mkdir(dirname($temp . '/' . $path), 0777, true);
|
|||
|
clearstatcache();
|
|||
|
|
|||
|
if ($path[strlen($path) - 1] == '/') {
|
|||
|
@mkdir($temp . '/' . $path, 0777);
|
|||
|
} else {
|
|||
|
file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
|
|||
|
@chmod($temp . '/' . $path, 0666);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
chdir($temp);
|
|||
|
|
|||
|
if (!$return) {
|
|||
|
include self::START;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static function tmpdir()
|
|||
|
{
|
|||
|
if (strpos(PHP_OS, 'WIN') !== false) {
|
|||
|
if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
|
|||
|
return $var;
|
|||
|
}
|
|||
|
if (is_dir('/temp') || mkdir('/temp')) {
|
|||
|
return realpath('/temp');
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
if ($var = getenv('TMPDIR')) {
|
|||
|
return $var;
|
|||
|
}
|
|||
|
return realpath('/tmp');
|
|||
|
}
|
|||
|
|
|||
|
static function _unpack($m)
|
|||
|
{
|
|||
|
$info = unpack('V', substr($m, 0, 4));
|
|||
|
$l = unpack('V', substr($m, 10, 4));
|
|||
|
$m = substr($m, 14 + $l[1]);
|
|||
|
$s = unpack('V', substr($m, 0, 4));
|
|||
|
$o = 0;
|
|||
|
$start = 4 + $s[1];
|
|||
|
$ret['c'] = 0;
|
|||
|
|
|||
|
for ($i = 0; $i < $info[1]; $i++) {
|
|||
|
$len = unpack('V', substr($m, $start, 4));
|
|||
|
$start += 4;
|
|||
|
$savepath = substr($m, $start, $len[1]);
|
|||
|
$start += $len[1];
|
|||
|
$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
|
|||
|
$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
|
|||
|
& 0xffffffff);
|
|||
|
$ret['m'][$savepath][7] = $o;
|
|||
|
$o += $ret['m'][$savepath][2];
|
|||
|
$start += 24 + $ret['m'][$savepath][5];
|
|||
|
$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
|
|||
|
}
|
|||
|
return $ret;
|
|||
|
}
|
|||
|
|
|||
|
static function extractFile($path, $entry, $fp)
|
|||
|
{
|
|||
|
$data = '';
|
|||
|
$c = $entry[2];
|
|||
|
|
|||
|
while ($c) {
|
|||
|
if ($c < 8192) {
|
|||
|
$data .= @fread($fp, $c);
|
|||
|
$c = 0;
|
|||
|
} else {
|
|||
|
$c -= 8192;
|
|||
|
$data .= @fread($fp, 8192);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ($entry[4] & self::GZ) {
|
|||
|
$data = gzinflate($data);
|
|||
|
} elseif ($entry[4] & self::BZ2) {
|
|||
|
$data = bzdecompress($data);
|
|||
|
}
|
|||
|
|
|||
|
if (strlen($data) != $entry[0]) {
|
|||
|
die("Invalid internal .phar file (size error " . strlen($data) . " != " .
|
|||
|
$stat[7] . ")");
|
|||
|
}
|
|||
|
|
|||
|
if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
|
|||
|
die("Invalid internal .phar file (checksum error)");
|
|||
|
}
|
|||
|
|
|||
|
return $data;
|
|||
|
}
|
|||
|
|
|||
|
static function _removeTmpFiles($temp, $origdir)
|
|||
|
{
|
|||
|
chdir($temp);
|
|||
|
|
|||
|
foreach (glob('*') as $f) {
|
|||
|
if (file_exists($f)) {
|
|||
|
is_dir($f) ? @rmdir($f) : @unlink($f);
|
|||
|
if (file_exists($f) && is_dir($f)) {
|
|||
|
self::_removeTmpFiles($f, getcwd());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@rmdir($temp);
|
|||
|
clearstatcache();
|
|||
|
chdir($origdir);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Extract_Phar::go();
|
|||
|
__HALT_COMPILER(); ?>
|
|||
|
<EFBFBD>I<00>a:4:{s:14:"phar.generator";s:26:"PharLite/0.1.x (PHP/8.0.8)";s:9:"phar.type";s:3:"app";s:12:"package.name";s:18:"noccylabs/pharlite";s:15:"package.version";N;}!vendor/composer/autoload_real.php<68>BF<42>a<EFBFBD><00>N V<>'vendor/composer/autoload_namespaces.php<68>BF<42>a<EFBFBD>t<>!פ!vendor/composer/autoload_psr4.php
|
|||
|
BF<42>a
|
|||
|
I<>Ѥ#vendor/composer/autoload_static.php BF<42>a <00><><07>vendor/composer/installed.jsonBF<42>a/<2F> k<>vendor/composer/LICENSE.BF<42>a. <20><03>%vendor/composer/autoload_classmap.php<68>BF<42>a<EFBFBD><00><>b<07>vendor/composer/ClassLoader.php<68>4BF<42>a<EFBFBD>4Q<><51><EFBFBD><EFBFBD>*vendor/symfony/finder/Tests/FinderTest.php<68>fBF<42>a<EFBFBD>f<00><07>q<EFBFBD>=vendor/symfony/finder/Tests/Iterator/SortableIteratorTest.phpsBF<42>as<14>.¤8vendor/symfony/finder/Tests/Iterator/MockSplFileInfo.php<68>BF<42>a<EFBFBD>t(<28><1F>Dvendor/symfony/finder/Tests/Iterator/SizeRangeFilterIteratorTest.phpBF<42>ag<><67><EFBFBD>=vendor/symfony/finder/Tests/Iterator/RealIteratorTestCase.php<68>BF<42>a<EFBFBD><00>y^ <09>=vendor/symfony/finder/Tests/Iterator/MockFileListIterator.php(BF<42>a(<00>[+<2B>Kvendor/symfony/finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php<68>BF<42>a<EFBFBD>3<><33><01>Cvendor/symfony/finder/Tests/Iterator/FilenameFilterIteratorTest.php<68>BF<42>a<EFBFBD><00><>7<EFBFBD><37>Gvendor/symfony/finder/Tests/Iterator/RecursiveDirectoryIteratorTest.phpBF<42>a-<2D><>u<EFBFBD>?vendor/symfony/finder/Tests/Iterator/PathFilterIteratorTest.php<68>BF<42>a<EFBFBD><00><>Vk<56>Gvendor/symfony/finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php BF<42>a C+m<><6D>Fvendor/symfony/finder/Tests/Iterator/FilecontentFilterIteratorTest.phpr
|
|||
|
BF<42>ar
|
|||
|
<00><>v<EFBFBD><76>9vendor/symfony/finder/Tests/Iterator/IteratorTestCase.phpt
BF<42>at
~"/<2F>Avendor/symfony/finder/Tests/Iterator/CustomFilterIteratorTest.php<68>BF<42>a<EFBFBD><00><>j7<6A>Evendor/symfony/finder/Tests/Iterator/DepthRangeFilterIteratorTest.phpsBF<42>as<12><>]<5D>1vendor/symfony/finder/Tests/Iterator/Iterator.phpBF<42>a<00>S䞤Cvendor/symfony/finder/Tests/Iterator/FileTypeFilterIteratorTest.phpgBF<42>ag<00><><EFBFBD><EFBFBD><EFBFBD>Dvendor/symfony/finder/Tests/Iterator/DateRangeFilterIteratorTest.phpnBF<42>an<00>'<27>c<EFBFBD>2vendor/symfony/finder/Tests/Fixtures/A/B/C/abc.datBF<42>a<00>/vendor/symfony/finder/Tests/Fixtures/A/B/ab.datBF<42>a<00>,vendor/symfony/finder/Tests/Fixtures/A/a.datBF<42>a<00>.vendor/symfony/finder/Tests/Fixtures/ipsum.txt)BF<42>a)'<27><><EFBFBD><EFBFBD>1vendor/symfony/finder/Tests/Fixtures/one/b/c.neonBF<42>a<00>1vendor/symfony/finder/Tests/Fixtures/one/b/d.neonBF<42>a<00>*vendor/symfony/finder/Tests/Fixtures/one/aBF<42>a<00>@vendor/symfony/finder/Tests/Fixtures/r+e.gex[c]a(r)s/dir/bar.datBF<42>a<00>.vendor/symfony/finder/Tests/Fixtures/dolor.txtBF<42>ao<>5|<7C>.vendor/symfony/finder/Tests/Fixtures/lorem.txt5BF<42>a5<16><><EFBFBD><EFBFBD>6vendor/symfony/finder/Tests/Fixtures/copy/A/a.dat.copyBF<42>a<00><vendor/symfony/finder/Tests/Fixtures/copy/A/B/C/abc.dat.copyBF<42>a<00>9vendor/symfony/finder/Tests/Fixtures/copy/A/B/ab.dat.copyBF<42>a<00>7vendor/symfony/finder/Tests/Fixtures/with space/foo.txtBF<42>a<00>=vendor/symfony/finder/Tests/Comparator/DateComparatorTest.php<68> BF<42>a<EFBFBD> P<1F><><EFBFBD>9vendor/symfony/finder/Tests/Comparator/ComparatorTest.php<68>BF<42>a<EFBFBD>Ͽ_<CFBF><5F>?vendor/symfony/finder/Tests/Comparator/NumberComparatorTest.phpUBF<42>aU<00>tUy<55>(vendor/symfony/finder/Tests/GlobTest.php<BF<42>a<<00><11>/<2F>vendor/symfony/finder/Glob.php<68>BF<42>a<EFBFBD>J<>@<40>;vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php<68>BF<42>a<EFBFBD><05>h<EFBFBD><68><vendor/symfony/finder/Iterator/FilecontentFilterIterator.php<68>BF<42>a<EFBFBD>r<>~<7E>9vendor/symfony/finder/Iterator/FileTypeFilterIterator.phpCBF<42>aCQN<51><4E><EFBFBD>3vendor/symfony/finder/Iterator/SortableIterator.php
|
|||
|
BF<42>a
|
|||
|
!ư<>:vendor/symfony/finder/Iterator/DateRangeFilterIterator.php<68>BF<42>a<EFBFBD><00>0<EFBFBD>[<5B>9vendor/symfony/finder/Iterator/FilenameFilterIterator.php<68>BF<42>a<EFBFBD><0C>p<EFBFBD><70>5vendor/symfony/finder/Iterator/PathFilterIterator.php<68>BF<42>a<EFBFBD><00><><EFBFBD><EFBFBD><EFBFBD>:vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php<68>BF<42>a<EFBFBD>
CT<16>Avendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php<68> BF<42>a<EFBFBD> U<><05>7vendor/symfony/finder/Iterator/CustomFilterIterator.php<68>BF<42>a<EFBFBD>x<>s<10>=vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php<68>BF<42>a<EFBFBD>jk<6A><6B>=vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.phpBF<42>a7űx<C5B1>&vendor/symfony/finder/phpunit.xml.distABF<42>aAf"%`<60>vendor/symfony/finder/README.md<6D>BF<42>a<EFBFBD>#L<><4C><EFBFBD>#vendor/symfony/finder/composer.json<6F>BF<42>a<EFBFBD>He<48>w<EFBFBD>"vendor/symfony/finder/CHANGELOG.md<6D>BF<42>a<EFBFBD>)<29>Pݤ vendor/symfony/finder/Finder.php<68>KBF<42>a<EFBFBD>K#%<25><>vendor/symfony/finder/LICENSE)BF<42>a)NUN<55><4E>5vendor/symfony/finder/Comparator/NumberComparator.php
|
|||
|
BF<42>a
|
|||
|
<0F><><EFBFBD>/vendor/symfony/finder/Comparator/Comparator.phpBF<42>a<00><><03><>3vendor/symfony/finder/Comparator/DateComparator.php<68>BF<42>a<EFBFBD><00>is<69>%vendor/symfony/finder/SplFileInfo.phpoBF<42>ao<12>)<29>9vendor/symfony/finder/Exception/AccessDeniedException.php<68>BF<42>a<EFBFBD><00>cWޤvendor/autoload.php<68>BF<42>a<EFBFBD>zg<7A><67><EFBFBD>src/Builder.phpi.BF<42>ai.2<>a<14>src/Manifest.phpOBF<42>aO<05><><EFBFBD><EFBFBD>src/ManifestObject.php0BF<42>a0<00>`<60><11>
bootstrap.phpWBF<42>aW<00><>N<><?php
|
|||
|
|
|||
|
// autoload_real.php @generated by Composer
|
|||
|
|
|||
|
class ComposerAutoloaderInitf90ebbc9abf27126721bf097052ab924
|
|||
|
{
|
|||
|
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('ComposerAutoloaderInitf90ebbc9abf27126721bf097052ab924', 'loadClassLoader'), true, true);
|
|||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
|||
|
spl_autoload_unregister(array('ComposerAutoloaderInitf90ebbc9abf27126721bf097052ab924', '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\ComposerStaticInitf90ebbc9abf27126721bf097052ab924::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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?php
|
|||
|
|
|||
|
// autoload_namespaces.php @generated by Composer
|
|||
|
|
|||
|
$vendorDir = dirname(dirname(__FILE__));
|
|||
|
$baseDir = dirname($vendorDir);
|
|||
|
|
|||
|
return array(
|
|||
|
);
|
|||
|
<?php
|
|||
|
|
|||
|
// autoload_psr4.php @generated by Composer
|
|||
|
|
|||
|
$vendorDir = dirname(dirname(__FILE__));
|
|||
|
$baseDir = dirname($vendorDir);
|
|||
|
|
|||
|
return array(
|
|||
|
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
|
|||
|
'PharLite\\' => array($baseDir . '/src'),
|
|||
|
);
|
|||
|
<?php
|
|||
|
|
|||
|
// autoload_static.php @generated by Composer
|
|||
|
|
|||
|
namespace Composer\Autoload;
|
|||
|
|
|||
|
class ComposerStaticInitf90ebbc9abf27126721bf097052ab924
|
|||
|
{
|
|||
|
public static $prefixLengthsPsr4 = array (
|
|||
|
'S' =>
|
|||
|
array (
|
|||
|
'Symfony\\Component\\Finder\\' => 25,
|
|||
|
),
|
|||
|
'P' =>
|
|||
|
array (
|
|||
|
'PharLite\\' => 9,
|
|||
|
),
|
|||
|
);
|
|||
|
|
|||
|
public static $prefixDirsPsr4 = array (
|
|||
|
'Symfony\\Component\\Finder\\' =>
|
|||
|
array (
|
|||
|
0 => __DIR__ . '/..' . '/symfony/finder',
|
|||
|
),
|
|||
|
'PharLite\\' =>
|
|||
|
array (
|
|||
|
0 => __DIR__ . '/../..' . '/src',
|
|||
|
),
|
|||
|
);
|
|||
|
|
|||
|
public static function getInitializer(ClassLoader $loader)
|
|||
|
{
|
|||
|
return \Closure::bind(function () use ($loader) {
|
|||
|
$loader->prefixLengthsPsr4 = ComposerStaticInitf90ebbc9abf27126721bf097052ab924::$prefixLengthsPsr4;
|
|||
|
$loader->prefixDirsPsr4 = ComposerStaticInitf90ebbc9abf27126721bf097052ab924::$prefixDirsPsr4;
|
|||
|
|
|||
|
}, null, ClassLoader::class);
|
|||
|
}
|
|||
|
}
|
|||
|
[
|
|||
|
{
|
|||
|
"name": "symfony/finder",
|
|||
|
"version": "v4.0.6",
|
|||
|
"version_normalized": "4.0.6.0",
|
|||
|
"source": {
|
|||
|
"type": "git",
|
|||
|
"url": "https://github.com/symfony/finder.git",
|
|||
|
"reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f"
|
|||
|
},
|
|||
|
"dist": {
|
|||
|
"type": "zip",
|
|||
|
"url": "https://api.github.com/repos/symfony/finder/zipball/44a796d2ecc2a16a5fc8f2956a34ee617934d55f",
|
|||
|
"reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f",
|
|||
|
"shasum": ""
|
|||
|
},
|
|||
|
"require": {
|
|||
|
"php": "^7.1.3"
|
|||
|
},
|
|||
|
"time": "2018-03-05T18:28:26+00:00",
|
|||
|
"type": "library",
|
|||
|
"extra": {
|
|||
|
"branch-alias": {
|
|||
|
"dev-master": "4.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"
|
|||
|
}
|
|||
|
]
|
|||
|
|
|||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
|||
|
|
|||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
|
of this software and associated documentation files (the "Software"), to deal
|
|||
|
in the Software without restriction, including without limitation the rights
|
|||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
|||
|
to do so, subject to the following conditions:
|
|||
|
|
|||
|
The above copyright notice and this permission notice shall be included in all
|
|||
|
copies or substantial portions of the Software.
|
|||
|
|
|||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
|
THE SOFTWARE.
|
|||
|
|
|||
|
<?php
|
|||
|
|
|||
|
// autoload_classmap.php @generated by Composer
|
|||
|
|
|||
|
$vendorDir = dirname(dirname(__FILE__));
|
|||
|
$baseDir = dirname($vendorDir);
|
|||
|
|
|||
|
return array(
|
|||
|
);
|
|||
|
<?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') && ini_get('apc.enabled') ? $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])) {
|
|||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
|||
|
$length = $this->prefixLengthsPsr4[$first][$search];
|
|||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
|||
|
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;
|
|||
|
}
|
|||
|
<?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\Tests;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Finder;
|
|||
|
|
|||
|
class FinderTest extends Iterator\RealIteratorTestCase
|
|||
|
{
|
|||
|
public function testCreate()
|
|||
|
{
|
|||
|
$this->assertInstanceOf('Symfony\Component\Finder\Finder', Finder::create());
|
|||
|
}
|
|||
|
|
|||
|
public function testDirectories()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->directories());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->directories();
|
|||
|
$finder->files();
|
|||
|
$finder->directories();
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testFiles()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->files());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->files();
|
|||
|
$finder->directories();
|
|||
|
$finder->files();
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testDepth()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->depth('< 1'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->depth('<= 0'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->depth('>= 1'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->depth('< 1')->depth('>= 1');
|
|||
|
$this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testName()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->name('*.php'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('test.ph*');
|
|||
|
$finder->name('test.py');
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('~^test~i');
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('~\\.php$~i');
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('test.p{hp,y}');
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testNotName()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->notName('*.php'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->notName('*.php');
|
|||
|
$finder->notName('*.py');
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('test.ph*');
|
|||
|
$finder->name('test.py');
|
|||
|
$finder->notName('*.php');
|
|||
|
$finder->notName('*.py');
|
|||
|
$this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name('test.ph*');
|
|||
|
$finder->name('test.py');
|
|||
|
$finder->notName('*.p{hp,y}');
|
|||
|
$this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getRegexNameTestData
|
|||
|
*/
|
|||
|
public function testRegexName($regex)
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->name($regex);
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.py', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSize()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testDate()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->files()->date('until last month'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testExclude()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->exclude('foo'));
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testIgnoreVCS()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
|
|||
|
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
|
|||
|
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testIgnoreDotFiles()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
|
|||
|
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
|
|||
|
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSortByName()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sortByName());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSortByType()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sortByType());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSortByAccessedTime()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sortByAccessedTime());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSortByChangedTime()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sortByChangedTime());
|
|||
|
$this->assertIterator($this->toAbsolute(array('toto', 'test.py', 'test.php', 'foo/bar.tmp', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSortByModifiedTime()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sortByModifiedTime());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testSort()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }));
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testFilter()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return false !== strpos($f, 'test'); }));
|
|||
|
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testFollowLinks()
|
|||
|
{
|
|||
|
if ('\\' == DIRECTORY_SEPARATOR) {
|
|||
|
$this->markTestSkipped('symlinks are not supported on Windows');
|
|||
|
}
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertSame($finder, $finder->followLinks());
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testIn()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator();
|
|||
|
|
|||
|
$expected = array(
|
|||
|
self::$tmpDir.DIRECTORY_SEPARATOR.'test.php',
|
|||
|
__DIR__.DIRECTORY_SEPARATOR.'FinderTest.php',
|
|||
|
__DIR__.DIRECTORY_SEPARATOR.'GlobTest.php',
|
|||
|
);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @expectedException \InvalidArgumentException
|
|||
|
*/
|
|||
|
public function testInWithNonExistentDirectory()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->in('foobar');
|
|||
|
}
|
|||
|
|
|||
|
public function testInWithGlob()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(array(__DIR__.'/Fixtures/*/B/C', __DIR__.'/Fixtures/*/*/B/C'))->getIterator();
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @expectedException \InvalidArgumentException
|
|||
|
*/
|
|||
|
public function testInWithNonDirectoryGlob()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->in(__DIR__.'/Fixtures/A/a*');
|
|||
|
}
|
|||
|
|
|||
|
public function testInWithGlobBrace()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(array(__DIR__.'/Fixtures/{A,copy/A}/B/C'))->getIterator();
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @expectedException \LogicException
|
|||
|
*/
|
|||
|
public function testGetIteratorWithoutIn()
|
|||
|
{
|
|||
|
$finder = Finder::create();
|
|||
|
$finder->getIterator();
|
|||
|
}
|
|||
|
|
|||
|
public function testGetIterator()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$dirs = array();
|
|||
|
foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
|
|||
|
$dirs[] = (string) $dir;
|
|||
|
}
|
|||
|
|
|||
|
$expected = $this->toAbsolute(array('foo', 'toto'));
|
|||
|
|
|||
|
sort($dirs);
|
|||
|
sort($expected);
|
|||
|
|
|||
|
$this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$a = iterator_to_array($finder->directories()->in(self::$tmpDir));
|
|||
|
$a = array_values(array_map('strval', $a));
|
|||
|
sort($a);
|
|||
|
$this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
|
|||
|
}
|
|||
|
|
|||
|
public function testRelativePath()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder()->in(self::$tmpDir);
|
|||
|
|
|||
|
$paths = array();
|
|||
|
|
|||
|
foreach ($finder as $file) {
|
|||
|
$paths[] = $file->getRelativePath();
|
|||
|
}
|
|||
|
|
|||
|
$ref = array('', '', '', '', 'foo', '');
|
|||
|
|
|||
|
sort($ref);
|
|||
|
sort($paths);
|
|||
|
|
|||
|
$this->assertEquals($ref, $paths);
|
|||
|
}
|
|||
|
|
|||
|
public function testRelativePathname()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder()->in(self::$tmpDir)->sortByName();
|
|||
|
|
|||
|
$paths = array();
|
|||
|
|
|||
|
foreach ($finder as $file) {
|
|||
|
$paths[] = $file->getRelativePathname();
|
|||
|
}
|
|||
|
|
|||
|
$ref = array('test.php', 'toto', 'test.py', 'foo', 'foo'.DIRECTORY_SEPARATOR.'bar.tmp', 'foo bar');
|
|||
|
|
|||
|
sort($paths);
|
|||
|
sort($ref);
|
|||
|
|
|||
|
$this->assertEquals($ref, $paths);
|
|||
|
}
|
|||
|
|
|||
|
public function testAppendWithAFinder()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
|
|||
|
|
|||
|
$finder1 = $this->buildFinder();
|
|||
|
$finder1->directories()->in(self::$tmpDir);
|
|||
|
|
|||
|
$finder = $finder->append($finder1);
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testAppendWithAnArray()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
|
|||
|
|
|||
|
$finder->append($this->toAbsolute(array('foo', 'toto')));
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testAppendReturnsAFinder()
|
|||
|
{
|
|||
|
$this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', Finder::create()->append(array()));
|
|||
|
}
|
|||
|
|
|||
|
public function testAppendDoesNotRequireIn()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
|
|||
|
|
|||
|
$finder1 = Finder::create()->append($finder);
|
|||
|
|
|||
|
$this->assertIterator(iterator_to_array($finder->getIterator()), $finder1->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
public function testCountDirectories()
|
|||
|
{
|
|||
|
$directory = Finder::create()->directories()->in(self::$tmpDir);
|
|||
|
$i = 0;
|
|||
|
|
|||
|
foreach ($directory as $dir) {
|
|||
|
++$i;
|
|||
|
}
|
|||
|
|
|||
|
$this->assertCount($i, $directory);
|
|||
|
}
|
|||
|
|
|||
|
public function testCountFiles()
|
|||
|
{
|
|||
|
$files = Finder::create()->files()->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
|
|||
|
$i = 0;
|
|||
|
|
|||
|
foreach ($files as $file) {
|
|||
|
++$i;
|
|||
|
}
|
|||
|
|
|||
|
$this->assertCount($i, $files);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @expectedException \LogicException
|
|||
|
*/
|
|||
|
public function testCountWithoutIn()
|
|||
|
{
|
|||
|
$finder = Finder::create()->files();
|
|||
|
count($finder);
|
|||
|
}
|
|||
|
|
|||
|
public function testHasResults()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__);
|
|||
|
$this->assertTrue($finder->hasResults());
|
|||
|
}
|
|||
|
|
|||
|
public function testNoResults()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__)->name('DoesNotExist');
|
|||
|
$this->assertFalse($finder->hasResults());
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getContainsTestData
|
|||
|
*/
|
|||
|
public function testContains($matchPatterns, $noMatchPatterns, $expected)
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
|
|||
|
->name('*.txt')->sortByName()
|
|||
|
->contains($matchPatterns)
|
|||
|
->notContains($noMatchPatterns);
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
|
|||
|
}
|
|||
|
|
|||
|
public function testContainsOnDirectory()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__)
|
|||
|
->directories()
|
|||
|
->name('Fixtures')
|
|||
|
->contains('abc');
|
|||
|
$this->assertIterator(array(), $finder);
|
|||
|
}
|
|||
|
|
|||
|
public function testNotContainsOnDirectory()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__)
|
|||
|
->directories()
|
|||
|
->name('Fixtures')
|
|||
|
->notContains('abc');
|
|||
|
$this->assertIterator(array(), $finder);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
|
|||
|
* with inner FilesystemIterator in an invalid state.
|
|||
|
*
|
|||
|
* @see https://bugs.php.net/68557
|
|||
|
*/
|
|||
|
public function testMultipleLocations()
|
|||
|
{
|
|||
|
$locations = array(
|
|||
|
self::$tmpDir.'/',
|
|||
|
self::$tmpDir.'/toto/',
|
|||
|
);
|
|||
|
|
|||
|
// it is expected that there are test.py test.php in the tmpDir
|
|||
|
$finder = new Finder();
|
|||
|
$finder->in($locations)
|
|||
|
// the default flag IGNORE_DOT_FILES fixes the problem indirectly
|
|||
|
// so we set it to false for better isolation
|
|||
|
->ignoreDotFiles(false)
|
|||
|
->depth('< 1')->name('test.php');
|
|||
|
|
|||
|
$this->assertCount(1, $finder);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Searching in multiple locations with sub directories involves
|
|||
|
* AppendIterator which does an unnecessary rewind which leaves
|
|||
|
* FilterIterator with inner FilesystemIterator in an invalid state.
|
|||
|
*
|
|||
|
* @see https://bugs.php.net/68557
|
|||
|
*/
|
|||
|
public function testMultipleLocationsWithSubDirectories()
|
|||
|
{
|
|||
|
$locations = array(
|
|||
|
__DIR__.'/Fixtures/one',
|
|||
|
self::$tmpDir.DIRECTORY_SEPARATOR.'toto',
|
|||
|
);
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in($locations)->depth('< 10')->name('*.neon');
|
|||
|
|
|||
|
$expected = array(
|
|||
|
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'c.neon',
|
|||
|
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'d.neon',
|
|||
|
);
|
|||
|
|
|||
|
$this->assertIterator($expected, $finder);
|
|||
|
$this->assertIteratorInForeach($expected, $finder);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Iterator keys must be the file pathname.
|
|||
|
*/
|
|||
|
public function testIteratorKeys()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder()->in(self::$tmpDir);
|
|||
|
foreach ($finder as $key => $file) {
|
|||
|
$this->assertEquals($file->getPathname(), $key);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag()
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
|
|||
|
->path('/^dir/');
|
|||
|
|
|||
|
$expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir', 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat');
|
|||
|
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
|
|||
|
}
|
|||
|
|
|||
|
public function getContainsTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('', '', array()),
|
|||
|
array('foo', 'bar', array()),
|
|||
|
array('', 'foobar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
|
|||
|
array('lorem ipsum dolor sit amet', 'foobar', array('lorem.txt')),
|
|||
|
array('sit', 'bar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
|
|||
|
array('dolor sit amet', '@^L@m', array('dolor.txt', 'ipsum.txt')),
|
|||
|
array('/^lorem ipsum dolor sit amet$/m', 'foobar', array('lorem.txt')),
|
|||
|
array('lorem', 'foobar', array('lorem.txt')),
|
|||
|
array('', 'lorem', array('dolor.txt', 'ipsum.txt')),
|
|||
|
array('ipsum dolor sit amet', '/^IPSUM/m', array('lorem.txt')),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
public function getRegexNameTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('~.+\\.p.+~i'),
|
|||
|
array('~t.*s~i'),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getTestPathData
|
|||
|
*/
|
|||
|
public function testPath($matchPatterns, $noMatchPatterns, array $expected)
|
|||
|
{
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
|
|||
|
->path($matchPatterns)
|
|||
|
->notPath($noMatchPatterns);
|
|||
|
|
|||
|
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
|
|||
|
}
|
|||
|
|
|||
|
public function getTestPathData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('', '', array()),
|
|||
|
array('/^A\/B\/C/', '/C$/',
|
|||
|
array('A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat'),
|
|||
|
),
|
|||
|
array('/^A\/B/', 'foobar',
|
|||
|
array(
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
|
|||
|
),
|
|||
|
),
|
|||
|
array('A/B/C', 'foobar',
|
|||
|
array(
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
|
|||
|
),
|
|||
|
),
|
|||
|
array('A/B', 'foobar',
|
|||
|
array(
|
|||
|
//dirs
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
|
|||
|
//files
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
|
|||
|
'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat.copy',
|
|||
|
'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
|
|||
|
),
|
|||
|
),
|
|||
|
array('/^with space\//', 'foobar',
|
|||
|
array(
|
|||
|
'with space'.DIRECTORY_SEPARATOR.'foo.txt',
|
|||
|
),
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
public function testAccessDeniedException()
|
|||
|
{
|
|||
|
if ('\\' === DIRECTORY_SEPARATOR) {
|
|||
|
$this->markTestSkipped('chmod is not supported on Windows');
|
|||
|
}
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->files()->in(self::$tmpDir);
|
|||
|
|
|||
|
// make 'foo' directory non-readable
|
|||
|
$testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
|
|||
|
chmod($testDir, 0333);
|
|||
|
|
|||
|
if (false === $couldRead = is_readable($testDir)) {
|
|||
|
try {
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
|
|||
|
$this->fail('Finder should throw an exception when opening a non-readable directory.');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException';
|
|||
|
if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
|
|||
|
$this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit_Framework_ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
|
|||
|
}
|
|||
|
|
|||
|
if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) {
|
|||
|
$this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, '\PHPUnit\Framework\ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
|
|||
|
}
|
|||
|
|
|||
|
$this->assertInstanceOf($expectedExceptionClass, $e);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// restore original permissions
|
|||
|
chmod($testDir, 0777);
|
|||
|
clearstatcache($testDir);
|
|||
|
|
|||
|
if ($couldRead) {
|
|||
|
$this->markTestSkipped('could read test files while test requires unreadable');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function testIgnoredAccessDeniedException()
|
|||
|
{
|
|||
|
if ('\\' === DIRECTORY_SEPARATOR) {
|
|||
|
$this->markTestSkipped('chmod is not supported on Windows');
|
|||
|
}
|
|||
|
|
|||
|
$finder = $this->buildFinder();
|
|||
|
$finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
|
|||
|
|
|||
|
// make 'foo' directory non-readable
|
|||
|
$testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
|
|||
|
chmod($testDir, 0333);
|
|||
|
|
|||
|
if (false === ($couldRead = is_readable($testDir))) {
|
|||
|
$this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
|
|||
|
}
|
|||
|
|
|||
|
// restore original permissions
|
|||
|
chmod($testDir, 0777);
|
|||
|
clearstatcache($testDir);
|
|||
|
|
|||
|
if ($couldRead) {
|
|||
|
$this->markTestSkipped('could read test files while test requires unreadable');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected function buildFinder()
|
|||
|
{
|
|||
|
return Finder::create();
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\SortableIterator;
|
|||
|
|
|||
|
class SortableIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
public function testConstructor()
|
|||
|
{
|
|||
|
try {
|
|||
|
new SortableIterator(new Iterator(array()), 'foobar');
|
|||
|
$this->fail('__construct() throws an \InvalidArgumentException exception if the mode is not valid');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException exception if the mode is not valid');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($mode, $expected)
|
|||
|
{
|
|||
|
if (!is_callable($mode)) {
|
|||
|
switch ($mode) {
|
|||
|
case SortableIterator::SORT_BY_ACCESSED_TIME:
|
|||
|
if ('\\' === DIRECTORY_SEPARATOR) {
|
|||
|
touch(self::toAbsolute('.git'));
|
|||
|
} else {
|
|||
|
file_get_contents(self::toAbsolute('.git'));
|
|||
|
}
|
|||
|
sleep(1);
|
|||
|
file_get_contents(self::toAbsolute('.bar'));
|
|||
|
break;
|
|||
|
case SortableIterator::SORT_BY_CHANGED_TIME:
|
|||
|
file_put_contents(self::toAbsolute('test.php'), 'foo');
|
|||
|
sleep(1);
|
|||
|
file_put_contents(self::toAbsolute('test.py'), 'foo');
|
|||
|
break;
|
|||
|
case SortableIterator::SORT_BY_MODIFIED_TIME:
|
|||
|
file_put_contents(self::toAbsolute('test.php'), 'foo');
|
|||
|
sleep(1);
|
|||
|
file_put_contents(self::toAbsolute('test.py'), 'foo');
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$inner = new Iterator(self::$files);
|
|||
|
|
|||
|
$iterator = new SortableIterator($inner, $mode);
|
|||
|
|
|||
|
if (SortableIterator::SORT_BY_ACCESSED_TIME === $mode
|
|||
|
|| SortableIterator::SORT_BY_CHANGED_TIME === $mode
|
|||
|
|| SortableIterator::SORT_BY_MODIFIED_TIME === $mode
|
|||
|
) {
|
|||
|
if ('\\' === DIRECTORY_SEPARATOR && SortableIterator::SORT_BY_MODIFIED_TIME !== $mode) {
|
|||
|
$this->markTestSkipped('Sorting by atime or ctime is not supported on Windows');
|
|||
|
}
|
|||
|
$this->assertOrderedIteratorForGroups($expected, $iterator);
|
|||
|
} else {
|
|||
|
$this->assertOrderedIterator($expected, $iterator);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$sortByName = array(
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.git',
|
|||
|
'foo',
|
|||
|
'foo bar',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'test.py',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
);
|
|||
|
|
|||
|
$sortByType = array(
|
|||
|
'.foo',
|
|||
|
'.git',
|
|||
|
'foo',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'.bar',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'foo bar',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'test.py',
|
|||
|
);
|
|||
|
|
|||
|
$customComparison = array(
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.git',
|
|||
|
'foo',
|
|||
|
'foo bar',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'test.py',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
);
|
|||
|
|
|||
|
$sortByAccessedTime = array(
|
|||
|
// For these two files the access time was set to 2005-10-15
|
|||
|
array('foo/bar.tmp', 'test.php'),
|
|||
|
// These files were created more or less at the same time
|
|||
|
array(
|
|||
|
'.git',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'foo bar',
|
|||
|
),
|
|||
|
// This file was accessed after sleeping for 1 sec
|
|||
|
array('.bar'),
|
|||
|
);
|
|||
|
|
|||
|
$sortByChangedTime = array(
|
|||
|
array(
|
|||
|
'.git',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.bar',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'foo bar',
|
|||
|
),
|
|||
|
array('test.php'),
|
|||
|
array('test.py'),
|
|||
|
);
|
|||
|
|
|||
|
$sortByModifiedTime = array(
|
|||
|
array(
|
|||
|
'.git',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.bar',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'foo bar',
|
|||
|
),
|
|||
|
array('test.php'),
|
|||
|
array('test.py'),
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(SortableIterator::SORT_BY_NAME, $this->toAbsolute($sortByName)),
|
|||
|
array(SortableIterator::SORT_BY_TYPE, $this->toAbsolute($sortByType)),
|
|||
|
array(SortableIterator::SORT_BY_ACCESSED_TIME, $this->toAbsolute($sortByAccessedTime)),
|
|||
|
array(SortableIterator::SORT_BY_CHANGED_TIME, $this->toAbsolute($sortByChangedTime)),
|
|||
|
array(SortableIterator::SORT_BY_MODIFIED_TIME, $this->toAbsolute($sortByModifiedTime)),
|
|||
|
array(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }, $this->toAbsolute($customComparison)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
class MockSplFileInfo extends \SplFileInfo
|
|||
|
{
|
|||
|
const TYPE_DIRECTORY = 1;
|
|||
|
const TYPE_FILE = 2;
|
|||
|
const TYPE_UNKNOWN = 3;
|
|||
|
|
|||
|
private $contents = null;
|
|||
|
private $mode = null;
|
|||
|
private $type = null;
|
|||
|
private $relativePath = null;
|
|||
|
private $relativePathname = null;
|
|||
|
|
|||
|
public function __construct($param)
|
|||
|
{
|
|||
|
if (is_string($param)) {
|
|||
|
parent::__construct($param);
|
|||
|
} elseif (is_array($param)) {
|
|||
|
$defaults = array(
|
|||
|
'name' => 'file.txt',
|
|||
|
'contents' => null,
|
|||
|
'mode' => null,
|
|||
|
'type' => null,
|
|||
|
'relativePath' => null,
|
|||
|
'relativePathname' => null,
|
|||
|
);
|
|||
|
$defaults = array_merge($defaults, $param);
|
|||
|
parent::__construct($defaults['name']);
|
|||
|
$this->setContents($defaults['contents']);
|
|||
|
$this->setMode($defaults['mode']);
|
|||
|
$this->setType($defaults['type']);
|
|||
|
$this->setRelativePath($defaults['relativePath']);
|
|||
|
$this->setRelativePathname($defaults['relativePathname']);
|
|||
|
} else {
|
|||
|
throw new \RuntimeException(sprintf('Incorrect parameter "%s"', $param));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function isFile()
|
|||
|
{
|
|||
|
if (null === $this->type) {
|
|||
|
return false !== strpos($this->getFilename(), 'file');
|
|||
|
}
|
|||
|
|
|||
|
return self::TYPE_FILE === $this->type;
|
|||
|
}
|
|||
|
|
|||
|
public function isDir()
|
|||
|
{
|
|||
|
if (null === $this->type) {
|
|||
|
return false !== strpos($this->getFilename(), 'directory');
|
|||
|
}
|
|||
|
|
|||
|
return self::TYPE_DIRECTORY === $this->type;
|
|||
|
}
|
|||
|
|
|||
|
public function isReadable()
|
|||
|
{
|
|||
|
if (null === $this->mode) {
|
|||
|
return preg_match('/r\+/', $this->getFilename());
|
|||
|
}
|
|||
|
|
|||
|
return preg_match('/r\+/', $this->mode);
|
|||
|
}
|
|||
|
|
|||
|
public function getContents()
|
|||
|
{
|
|||
|
return $this->contents;
|
|||
|
}
|
|||
|
|
|||
|
public function setContents($contents)
|
|||
|
{
|
|||
|
$this->contents = $contents;
|
|||
|
}
|
|||
|
|
|||
|
public function setMode($mode)
|
|||
|
{
|
|||
|
$this->mode = $mode;
|
|||
|
}
|
|||
|
|
|||
|
public function setType($type)
|
|||
|
{
|
|||
|
if (is_string($type)) {
|
|||
|
switch ($type) {
|
|||
|
case 'directory':
|
|||
|
case 'd':
|
|||
|
$this->type = self::TYPE_DIRECTORY;
|
|||
|
break;
|
|||
|
case 'file':
|
|||
|
case 'f':
|
|||
|
$this->type = self::TYPE_FILE;
|
|||
|
break;
|
|||
|
default:
|
|||
|
$this->type = self::TYPE_UNKNOWN;
|
|||
|
}
|
|||
|
} else {
|
|||
|
$this->type = $type;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function setRelativePath($relativePath)
|
|||
|
{
|
|||
|
$this->relativePath = $relativePath;
|
|||
|
}
|
|||
|
|
|||
|
public function setRelativePathname($relativePathname)
|
|||
|
{
|
|||
|
$this->relativePathname = $relativePathname;
|
|||
|
}
|
|||
|
|
|||
|
public function getRelativePath()
|
|||
|
{
|
|||
|
return $this->relativePath;
|
|||
|
}
|
|||
|
|
|||
|
public function getRelativePathname()
|
|||
|
{
|
|||
|
return $this->relativePathname;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
|
|||
|
use Symfony\Component\Finder\Comparator\NumberComparator;
|
|||
|
|
|||
|
class SizeRangeFilterIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($size, $expected)
|
|||
|
{
|
|||
|
$inner = new InnerSizeIterator(self::$files);
|
|||
|
|
|||
|
$iterator = new SizeRangeFilterIterator($inner, $size);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$lessThan1KGreaterThan05K = array(
|
|||
|
'.foo',
|
|||
|
'.git',
|
|||
|
'foo',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(array(new NumberComparator('< 1K'), new NumberComparator('> 0.5K')), $this->toAbsolute($lessThan1KGreaterThan05K)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class InnerSizeIterator extends \ArrayIterator
|
|||
|
{
|
|||
|
public function current()
|
|||
|
{
|
|||
|
return new \SplFileInfo(parent::current());
|
|||
|
}
|
|||
|
|
|||
|
public function getFilename()
|
|||
|
{
|
|||
|
return parent::current();
|
|||
|
}
|
|||
|
|
|||
|
public function isFile()
|
|||
|
{
|
|||
|
return $this->current()->isFile();
|
|||
|
}
|
|||
|
|
|||
|
public function getSize()
|
|||
|
{
|
|||
|
return $this->current()->getSize();
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
abstract class RealIteratorTestCase extends IteratorTestCase
|
|||
|
{
|
|||
|
protected static $tmpDir;
|
|||
|
protected static $files;
|
|||
|
|
|||
|
public static function setUpBeforeClass()
|
|||
|
{
|
|||
|
self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
|
|||
|
|
|||
|
self::$files = array(
|
|||
|
'.git/',
|
|||
|
'.foo/',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.bar',
|
|||
|
'test.py',
|
|||
|
'foo/',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'toto/',
|
|||
|
'toto/.git/',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
self::$files = self::toAbsolute(self::$files);
|
|||
|
|
|||
|
if (is_dir(self::$tmpDir)) {
|
|||
|
self::tearDownAfterClass();
|
|||
|
} else {
|
|||
|
mkdir(self::$tmpDir);
|
|||
|
}
|
|||
|
|
|||
|
foreach (self::$files as $file) {
|
|||
|
if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
|
|||
|
mkdir($file);
|
|||
|
} else {
|
|||
|
touch($file);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
file_put_contents(self::toAbsolute('test.php'), str_repeat(' ', 800));
|
|||
|
file_put_contents(self::toAbsolute('test.py'), str_repeat(' ', 2000));
|
|||
|
|
|||
|
touch(self::toAbsolute('foo/bar.tmp'), strtotime('2005-10-15'));
|
|||
|
touch(self::toAbsolute('test.php'), strtotime('2005-10-15'));
|
|||
|
}
|
|||
|
|
|||
|
public static function tearDownAfterClass()
|
|||
|
{
|
|||
|
foreach (array_reverse(self::$files) as $file) {
|
|||
|
if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
|
|||
|
@rmdir($file);
|
|||
|
} else {
|
|||
|
@unlink($file);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected static function toAbsolute($files = null)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Without the call to setUpBeforeClass() property can be null.
|
|||
|
*/
|
|||
|
if (!self::$tmpDir) {
|
|||
|
self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
|
|||
|
}
|
|||
|
|
|||
|
if (is_array($files)) {
|
|||
|
$f = array();
|
|||
|
foreach ($files as $file) {
|
|||
|
if (is_array($file)) {
|
|||
|
$f[] = self::toAbsolute($file);
|
|||
|
} else {
|
|||
|
$f[] = self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $file);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $f;
|
|||
|
}
|
|||
|
|
|||
|
if (is_string($files)) {
|
|||
|
return self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $files);
|
|||
|
}
|
|||
|
|
|||
|
return self::$tmpDir;
|
|||
|
}
|
|||
|
|
|||
|
protected static function toAbsoluteFixtures($files)
|
|||
|
{
|
|||
|
$f = array();
|
|||
|
foreach ($files as $file) {
|
|||
|
$f[] = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$file);
|
|||
|
}
|
|||
|
|
|||
|
return $f;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
class MockFileListIterator extends \ArrayIterator
|
|||
|
{
|
|||
|
public function __construct(array $filesArray = array())
|
|||
|
{
|
|||
|
$files = array_map(function ($file) { return new MockSplFileInfo($file); }, $filesArray);
|
|||
|
parent::__construct($files);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
|
|||
|
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
|
|||
|
|
|||
|
class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($directories, $expected)
|
|||
|
{
|
|||
|
$inner = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
|
|||
|
|
|||
|
$iterator = new ExcludeDirectoryFilterIterator($inner, $directories);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$foo = array(
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
$fo = array(
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
$toto = array(
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(array('foo'), $this->toAbsolute($foo)),
|
|||
|
array(array('fo'), $this->toAbsolute($fo)),
|
|||
|
array(array('toto/'), $this->toAbsolute($toto)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
|
|||
|
|
|||
|
class FilenameFilterIteratorTest extends IteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($matchPatterns, $noMatchPatterns, $expected)
|
|||
|
{
|
|||
|
$inner = new InnerNameIterator(array('test.php', 'test.py', 'foo.php'));
|
|||
|
|
|||
|
$iterator = new FilenameFilterIterator($inner, $matchPatterns, $noMatchPatterns);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array(array('test.*'), array(), array('test.php', 'test.py')),
|
|||
|
array(array(), array('test.*'), array('foo.php')),
|
|||
|
array(array('*.php'), array('test.*'), array('foo.php')),
|
|||
|
array(array('*.php', '*.py'), array('foo.*'), array('test.php', 'test.py')),
|
|||
|
array(array('/\.php$/'), array(), array('test.php', 'foo.php')),
|
|||
|
array(array(), array('/\.php$/'), array('test.py')),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class InnerNameIterator extends \ArrayIterator
|
|||
|
{
|
|||
|
public function current()
|
|||
|
{
|
|||
|
return new \SplFileInfo(parent::current());
|
|||
|
}
|
|||
|
|
|||
|
public function getFilename()
|
|||
|
{
|
|||
|
return parent::current();
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
|
|||
|
|
|||
|
class RecursiveDirectoryIteratorTest extends IteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @group network
|
|||
|
*/
|
|||
|
public function testRewindOnFtp()
|
|||
|
{
|
|||
|
try {
|
|||
|
$i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
|
|||
|
} catch (\UnexpectedValueException $e) {
|
|||
|
$this->markTestSkipped('Unsupported stream "ftp".');
|
|||
|
}
|
|||
|
|
|||
|
$i->rewind();
|
|||
|
|
|||
|
$this->assertTrue(true);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @group network
|
|||
|
*/
|
|||
|
public function testSeekOnFtp()
|
|||
|
{
|
|||
|
try {
|
|||
|
$i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
|
|||
|
} catch (\UnexpectedValueException $e) {
|
|||
|
$this->markTestSkipped('Unsupported stream "ftp".');
|
|||
|
}
|
|||
|
|
|||
|
$contains = array(
|
|||
|
'ftp://speedtest.tele2.net'.DIRECTORY_SEPARATOR.'1000GB.zip',
|
|||
|
'ftp://speedtest.tele2.net'.DIRECTORY_SEPARATOR.'100GB.zip',
|
|||
|
);
|
|||
|
$actual = array();
|
|||
|
|
|||
|
$i->seek(0);
|
|||
|
$actual[] = $i->getPathname();
|
|||
|
|
|||
|
$i->seek(1);
|
|||
|
$actual[] = $i->getPathname();
|
|||
|
|
|||
|
$this->assertEquals($contains, $actual);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\PathFilterIterator;
|
|||
|
|
|||
|
class PathFilterIteratorTest extends IteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getTestFilterData
|
|||
|
*/
|
|||
|
public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
|
|||
|
{
|
|||
|
$iterator = new PathFilterIterator($inner, $matchPatterns, $noMatchPatterns);
|
|||
|
$this->assertIterator($resultArray, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getTestFilterData()
|
|||
|
{
|
|||
|
$inner = new MockFileListIterator();
|
|||
|
|
|||
|
//PATH: A/B/C/abc.dat
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'abc.dat',
|
|||
|
'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
|
|||
|
));
|
|||
|
|
|||
|
//PATH: A/B/ab.dat
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'ab.dat',
|
|||
|
'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
|
|||
|
));
|
|||
|
|
|||
|
//PATH: A/a.dat
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'a.dat',
|
|||
|
'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'a.dat',
|
|||
|
));
|
|||
|
|
|||
|
//PATH: copy/A/B/C/abc.dat.copy
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'abc.dat.copy',
|
|||
|
'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
|
|||
|
));
|
|||
|
|
|||
|
//PATH: copy/A/B/ab.dat.copy
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'ab.dat.copy',
|
|||
|
'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
|
|||
|
));
|
|||
|
|
|||
|
//PATH: copy/A/a.dat.copy
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'a.dat.copy',
|
|||
|
'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'a.dat',
|
|||
|
));
|
|||
|
|
|||
|
return array(
|
|||
|
array($inner, array('/^A/'), array(), array('abc.dat', 'ab.dat', 'a.dat')),
|
|||
|
array($inner, array('/^A\/B/'), array(), array('abc.dat', 'ab.dat')),
|
|||
|
array($inner, array('/^A\/B\/C/'), array(), array('abc.dat')),
|
|||
|
array($inner, array('/A\/B\/C/'), array(), array('abc.dat', 'abc.dat.copy')),
|
|||
|
|
|||
|
array($inner, array('A'), array(), array('abc.dat', 'ab.dat', 'a.dat', 'abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
|
|||
|
array($inner, array('A/B'), array(), array('abc.dat', 'ab.dat', 'abc.dat.copy', 'ab.dat.copy')),
|
|||
|
array($inner, array('A/B/C'), array(), array('abc.dat', 'abc.dat.copy')),
|
|||
|
|
|||
|
array($inner, array('copy/A'), array(), array('abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
|
|||
|
array($inner, array('copy/A/B'), array(), array('abc.dat.copy', 'ab.dat.copy')),
|
|||
|
array($inner, array('copy/A/B/C'), array(), array('abc.dat.copy')),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
use Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator;
|
|||
|
|
|||
|
class MultiplePcreFilterIteratorTest extends TestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getIsRegexFixtures
|
|||
|
*/
|
|||
|
public function testIsRegex($string, $isRegex, $message)
|
|||
|
{
|
|||
|
$testIterator = new TestMultiplePcreFilterIterator();
|
|||
|
$this->assertEquals($isRegex, $testIterator->isRegex($string), $message);
|
|||
|
}
|
|||
|
|
|||
|
public function getIsRegexFixtures()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('foo', false, 'string'),
|
|||
|
array(' foo ', false, '" " is not a valid delimiter'),
|
|||
|
array('\\foo\\', false, '"\\" is not a valid delimiter'),
|
|||
|
array('afooa', false, '"a" is not a valid delimiter'),
|
|||
|
array('//', false, 'the pattern should contain at least 1 character'),
|
|||
|
array('/a/', true, 'valid regex'),
|
|||
|
array('/foo/', true, 'valid regex'),
|
|||
|
array('/foo/i', true, 'valid regex with a single modifier'),
|
|||
|
array('/foo/imsxu', true, 'valid regex with multiple modifiers'),
|
|||
|
array('#foo#', true, '"#" is a valid delimiter'),
|
|||
|
array('{foo}', true, '"{,}" is a valid delimiter pair'),
|
|||
|
array('[foo]', true, '"[,]" is a valid delimiter pair'),
|
|||
|
array('(foo)', true, '"(,)" is a valid delimiter pair'),
|
|||
|
array('<foo>', true, '"<,>" is a valid delimiter pair'),
|
|||
|
array('*foo.*', false, '"*" is not considered as a valid delimiter'),
|
|||
|
array('?foo.?', false, '"?" is not considered as a valid delimiter'),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class TestMultiplePcreFilterIterator extends MultiplePcreFilterIterator
|
|||
|
{
|
|||
|
public function __construct()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
public function accept()
|
|||
|
{
|
|||
|
throw new \BadFunctionCallException('Not implemented');
|
|||
|
}
|
|||
|
|
|||
|
public function isRegex($str)
|
|||
|
{
|
|||
|
return parent::isRegex($str);
|
|||
|
}
|
|||
|
|
|||
|
public function toRegex($str)
|
|||
|
{
|
|||
|
throw new \BadFunctionCallException('Not implemented');
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
|
|||
|
|
|||
|
class FilecontentFilterIteratorTest extends IteratorTestCase
|
|||
|
{
|
|||
|
public function testAccept()
|
|||
|
{
|
|||
|
$inner = new MockFileListIterator(array('test.txt'));
|
|||
|
$iterator = new FilecontentFilterIterator($inner, array(), array());
|
|||
|
$this->assertIterator(array('test.txt'), $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function testDirectory()
|
|||
|
{
|
|||
|
$inner = new MockFileListIterator(array('directory'));
|
|||
|
$iterator = new FilecontentFilterIterator($inner, array('directory'), array());
|
|||
|
$this->assertIterator(array(), $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function testUnreadableFile()
|
|||
|
{
|
|||
|
$inner = new MockFileListIterator(array('file r-'));
|
|||
|
$iterator = new FilecontentFilterIterator($inner, array('file r-'), array());
|
|||
|
$this->assertIterator(array(), $iterator);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getTestFilterData
|
|||
|
*/
|
|||
|
public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
|
|||
|
{
|
|||
|
$iterator = new FilecontentFilterIterator($inner, $matchPatterns, $noMatchPatterns);
|
|||
|
$this->assertIterator($resultArray, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getTestFilterData()
|
|||
|
{
|
|||
|
$inner = new MockFileListIterator();
|
|||
|
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'a.txt',
|
|||
|
'contents' => 'Lorem ipsum...',
|
|||
|
'type' => 'file',
|
|||
|
'mode' => 'r+', )
|
|||
|
);
|
|||
|
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'b.yml',
|
|||
|
'contents' => 'dolor sit...',
|
|||
|
'type' => 'file',
|
|||
|
'mode' => 'r+', )
|
|||
|
);
|
|||
|
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'some/other/dir/third.php',
|
|||
|
'contents' => 'amet...',
|
|||
|
'type' => 'file',
|
|||
|
'mode' => 'r+', )
|
|||
|
);
|
|||
|
|
|||
|
$inner[] = new MockSplFileInfo(array(
|
|||
|
'name' => 'unreadable-file.txt',
|
|||
|
'contents' => false,
|
|||
|
'type' => 'file',
|
|||
|
'mode' => 'r+', )
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array($inner, array('.'), array(), array('a.txt', 'b.yml', 'some/other/dir/third.php')),
|
|||
|
array($inner, array('ipsum'), array(), array('a.txt')),
|
|||
|
array($inner, array('i', 'amet'), array('Lorem', 'amet'), array('b.yml')),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
|
|||
|
abstract class IteratorTestCase extends TestCase
|
|||
|
{
|
|||
|
protected function assertIterator($expected, \Traversable $iterator)
|
|||
|
{
|
|||
|
// set iterator_to_array $use_key to false to avoid values merge
|
|||
|
// this made FinderTest::testAppendWithAnArray() fail with GnuFinderAdapter
|
|||
|
$values = array_map(function (\SplFileInfo $fileinfo) { return str_replace('/', DIRECTORY_SEPARATOR, $fileinfo->getPathname()); }, iterator_to_array($iterator, false));
|
|||
|
|
|||
|
$expected = array_map(function ($path) { return str_replace('/', DIRECTORY_SEPARATOR, $path); }, $expected);
|
|||
|
|
|||
|
sort($values);
|
|||
|
sort($expected);
|
|||
|
|
|||
|
$this->assertEquals($expected, array_values($values));
|
|||
|
}
|
|||
|
|
|||
|
protected function assertOrderedIterator($expected, \Traversable $iterator)
|
|||
|
{
|
|||
|
$values = array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator));
|
|||
|
|
|||
|
$this->assertEquals($expected, array_values($values));
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Same as assertOrderedIterator, but checks the order of groups of
|
|||
|
* array elements.
|
|||
|
*
|
|||
|
* @param array $expected - an array of arrays. For any two subarrays
|
|||
|
* $a and $b such that $a goes before $b in $expected, the method
|
|||
|
* asserts that any element of $a goes before any element of $b
|
|||
|
* in the sequence generated by $iterator
|
|||
|
* @param \Traversable $iterator
|
|||
|
*/
|
|||
|
protected function assertOrderedIteratorForGroups($expected, \Traversable $iterator)
|
|||
|
{
|
|||
|
$values = array_values(array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator)));
|
|||
|
|
|||
|
foreach ($expected as $subarray) {
|
|||
|
$temp = array();
|
|||
|
while (count($values) && count($temp) < count($subarray)) {
|
|||
|
$temp[] = array_shift($values);
|
|||
|
}
|
|||
|
sort($temp);
|
|||
|
sort($subarray);
|
|||
|
$this->assertEquals($subarray, $temp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Same as IteratorTestCase::assertIterator with foreach usage.
|
|||
|
*
|
|||
|
* @param array $expected
|
|||
|
* @param \Traversable $iterator
|
|||
|
*/
|
|||
|
protected function assertIteratorInForeach($expected, \Traversable $iterator)
|
|||
|
{
|
|||
|
$values = array();
|
|||
|
foreach ($iterator as $file) {
|
|||
|
$this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
|
|||
|
$values[] = $file->getPathname();
|
|||
|
}
|
|||
|
|
|||
|
sort($values);
|
|||
|
sort($expected);
|
|||
|
|
|||
|
$this->assertEquals($expected, array_values($values));
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Same as IteratorTestCase::assertOrderedIterator with foreach usage.
|
|||
|
*
|
|||
|
* @param array $expected
|
|||
|
* @param \Traversable $iterator
|
|||
|
*/
|
|||
|
protected function assertOrderedIteratorInForeach($expected, \Traversable $iterator)
|
|||
|
{
|
|||
|
$values = array();
|
|||
|
foreach ($iterator as $file) {
|
|||
|
$this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
|
|||
|
$values[] = $file->getPathname();
|
|||
|
}
|
|||
|
|
|||
|
$this->assertEquals($expected, array_values($values));
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
|
|||
|
|
|||
|
class CustomFilterIteratorTest extends IteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @expectedException \InvalidArgumentException
|
|||
|
*/
|
|||
|
public function testWithInvalidFilter()
|
|||
|
{
|
|||
|
new CustomFilterIterator(new Iterator(), array('foo'));
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($filters, $expected)
|
|||
|
{
|
|||
|
$inner = new Iterator(array('test.php', 'test.py', 'foo.php'));
|
|||
|
|
|||
|
$iterator = new CustomFilterIterator($inner, $filters);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array(array(function (\SplFileInfo $fileinfo) { return false; }), array()),
|
|||
|
array(array(function (\SplFileInfo $fileinfo) { return 0 === strpos($fileinfo, 'test'); }), array('test.php', 'test.py')),
|
|||
|
array(array('is_dir'), array()),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
|
|||
|
|
|||
|
class DepthRangeFilterIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($minDepth, $maxDepth, $expected)
|
|||
|
{
|
|||
|
$inner = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
|
|||
|
|
|||
|
$iterator = new DepthRangeFilterIterator($inner, $minDepth, $maxDepth);
|
|||
|
|
|||
|
$actual = array_keys(iterator_to_array($iterator));
|
|||
|
sort($expected);
|
|||
|
sort($actual);
|
|||
|
$this->assertEquals($expected, $actual);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$lessThan1 = array(
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'.foo',
|
|||
|
'.bar',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
$lessThanOrEqualTo1 = array(
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'.bar',
|
|||
|
'foo bar',
|
|||
|
'.foo/bar',
|
|||
|
);
|
|||
|
|
|||
|
$graterThanOrEqualTo1 = array(
|
|||
|
'toto/.git',
|
|||
|
'foo/bar.tmp',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
);
|
|||
|
|
|||
|
$equalTo1 = array(
|
|||
|
'toto/.git',
|
|||
|
'foo/bar.tmp',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(0, 0, $this->toAbsolute($lessThan1)),
|
|||
|
array(0, 1, $this->toAbsolute($lessThanOrEqualTo1)),
|
|||
|
array(2, PHP_INT_MAX, array()),
|
|||
|
array(1, PHP_INT_MAX, $this->toAbsolute($graterThanOrEqualTo1)),
|
|||
|
array(1, 1, $this->toAbsolute($equalTo1)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
class Iterator implements \Iterator
|
|||
|
{
|
|||
|
protected $values = array();
|
|||
|
|
|||
|
public function __construct(array $values = array())
|
|||
|
{
|
|||
|
foreach ($values as $value) {
|
|||
|
$this->attach(new \SplFileInfo($value));
|
|||
|
}
|
|||
|
$this->rewind();
|
|||
|
}
|
|||
|
|
|||
|
public function attach(\SplFileInfo $fileinfo)
|
|||
|
{
|
|||
|
$this->values[] = $fileinfo;
|
|||
|
}
|
|||
|
|
|||
|
public function rewind()
|
|||
|
{
|
|||
|
reset($this->values);
|
|||
|
}
|
|||
|
|
|||
|
public function valid()
|
|||
|
{
|
|||
|
return false !== $this->current();
|
|||
|
}
|
|||
|
|
|||
|
public function next()
|
|||
|
{
|
|||
|
next($this->values);
|
|||
|
}
|
|||
|
|
|||
|
public function current()
|
|||
|
{
|
|||
|
return current($this->values);
|
|||
|
}
|
|||
|
|
|||
|
public function key()
|
|||
|
{
|
|||
|
return key($this->values);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\FileTypeFilterIterator;
|
|||
|
|
|||
|
class FileTypeFilterIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($mode, $expected)
|
|||
|
{
|
|||
|
$inner = new InnerTypeIterator(self::$files);
|
|||
|
|
|||
|
$iterator = new FileTypeFilterIterator($inner, $mode);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$onlyFiles = array(
|
|||
|
'test.py',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'.bar',
|
|||
|
'.foo/.bar',
|
|||
|
'.foo/bar',
|
|||
|
'foo bar',
|
|||
|
);
|
|||
|
|
|||
|
$onlyDirectories = array(
|
|||
|
'.git',
|
|||
|
'foo',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'.foo',
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(FileTypeFilterIterator::ONLY_FILES, $this->toAbsolute($onlyFiles)),
|
|||
|
array(FileTypeFilterIterator::ONLY_DIRECTORIES, $this->toAbsolute($onlyDirectories)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class InnerTypeIterator extends \ArrayIterator
|
|||
|
{
|
|||
|
public function current()
|
|||
|
{
|
|||
|
return new \SplFileInfo(parent::current());
|
|||
|
}
|
|||
|
|
|||
|
public function isFile()
|
|||
|
{
|
|||
|
return $this->current()->isFile();
|
|||
|
}
|
|||
|
|
|||
|
public function isDir()
|
|||
|
{
|
|||
|
return $this->current()->isDir();
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Iterator;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
|
|||
|
use Symfony\Component\Finder\Comparator\DateComparator;
|
|||
|
|
|||
|
class DateRangeFilterIteratorTest extends RealIteratorTestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getAcceptData
|
|||
|
*/
|
|||
|
public function testAccept($size, $expected)
|
|||
|
{
|
|||
|
$files = self::$files;
|
|||
|
$files[] = self::toAbsolute('doesnotexist');
|
|||
|
$inner = new Iterator($files);
|
|||
|
|
|||
|
$iterator = new DateRangeFilterIterator($inner, $size);
|
|||
|
|
|||
|
$this->assertIterator($expected, $iterator);
|
|||
|
}
|
|||
|
|
|||
|
public function getAcceptData()
|
|||
|
{
|
|||
|
$since20YearsAgo = array(
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'foo bar',
|
|||
|
'.foo/bar',
|
|||
|
);
|
|||
|
|
|||
|
$since2MonthsAgo = array(
|
|||
|
'.git',
|
|||
|
'test.py',
|
|||
|
'foo',
|
|||
|
'toto',
|
|||
|
'toto/.git',
|
|||
|
'.bar',
|
|||
|
'.foo',
|
|||
|
'.foo/.bar',
|
|||
|
'foo bar',
|
|||
|
'.foo/bar',
|
|||
|
);
|
|||
|
|
|||
|
$untilLastMonth = array(
|
|||
|
'foo/bar.tmp',
|
|||
|
'test.php',
|
|||
|
);
|
|||
|
|
|||
|
return array(
|
|||
|
array(array(new DateComparator('since 20 years ago')), $this->toAbsolute($since20YearsAgo)),
|
|||
|
array(array(new DateComparator('since 2 months ago')), $this->toAbsolute($since2MonthsAgo)),
|
|||
|
array(array(new DateComparator('until last month')), $this->toAbsolute($untilLastMonth)),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
ipsum dolor sit amet
|
|||
|
IPSUM DOLOR SIT AMETdolor sit amet
|
|||
|
DOLOR SIT AMETlorem ipsum dolor sit amet
|
|||
|
LOREM IPSUM DOLOR SIT AMET<?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\Tests\Comparator;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
use Symfony\Component\Finder\Comparator\DateComparator;
|
|||
|
|
|||
|
class DateComparatorTest extends TestCase
|
|||
|
{
|
|||
|
public function testConstructor()
|
|||
|
{
|
|||
|
try {
|
|||
|
new DateComparator('foobar');
|
|||
|
$this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
new DateComparator('');
|
|||
|
$this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getTestData
|
|||
|
*/
|
|||
|
public function testTest($test, $match, $noMatch)
|
|||
|
{
|
|||
|
$c = new DateComparator($test);
|
|||
|
|
|||
|
foreach ($match as $m) {
|
|||
|
$this->assertTrue($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
|
|||
|
foreach ($noMatch as $m) {
|
|||
|
$this->assertFalse($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function getTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('< 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
|
|||
|
array('until 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
|
|||
|
array('before 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
|
|||
|
array('> 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
|
|||
|
array('after 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
|
|||
|
array('since 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
|
|||
|
array('!= 2005-10-10', array(strtotime('2005-10-11')), array(strtotime('2005-10-10'))),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Comparator;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
use Symfony\Component\Finder\Comparator\Comparator;
|
|||
|
|
|||
|
class ComparatorTest extends TestCase
|
|||
|
{
|
|||
|
public function testGetSetOperator()
|
|||
|
{
|
|||
|
$comparator = new Comparator();
|
|||
|
try {
|
|||
|
$comparator->setOperator('foo');
|
|||
|
$this->fail('->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->assertInstanceOf('InvalidArgumentException', $e, '->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
|
|||
|
}
|
|||
|
|
|||
|
$comparator = new Comparator();
|
|||
|
$comparator->setOperator('>');
|
|||
|
$this->assertEquals('>', $comparator->getOperator(), '->getOperator() returns the current operator');
|
|||
|
}
|
|||
|
|
|||
|
public function testGetSetTarget()
|
|||
|
{
|
|||
|
$comparator = new Comparator();
|
|||
|
$comparator->setTarget(8);
|
|||
|
$this->assertEquals(8, $comparator->getTarget(), '->getTarget() returns the target');
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getTestData
|
|||
|
*/
|
|||
|
public function testTest($operator, $target, $match, $noMatch)
|
|||
|
{
|
|||
|
$c = new Comparator();
|
|||
|
$c->setOperator($operator);
|
|||
|
$c->setTarget($target);
|
|||
|
|
|||
|
foreach ($match as $m) {
|
|||
|
$this->assertTrue($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
|
|||
|
foreach ($noMatch as $m) {
|
|||
|
$this->assertFalse($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function getTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('<', '1000', array('500', '999'), array('1000', '1500')),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests\Comparator;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
use Symfony\Component\Finder\Comparator\NumberComparator;
|
|||
|
|
|||
|
class NumberComparatorTest extends TestCase
|
|||
|
{
|
|||
|
/**
|
|||
|
* @dataProvider getConstructorTestData
|
|||
|
*/
|
|||
|
public function testConstructor($successes, $failures)
|
|||
|
{
|
|||
|
foreach ($successes as $s) {
|
|||
|
new NumberComparator($s);
|
|||
|
}
|
|||
|
|
|||
|
foreach ($failures as $f) {
|
|||
|
try {
|
|||
|
new NumberComparator($f);
|
|||
|
$this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @dataProvider getTestData
|
|||
|
*/
|
|||
|
public function testTest($test, $match, $noMatch)
|
|||
|
{
|
|||
|
$c = new NumberComparator($test);
|
|||
|
|
|||
|
foreach ($match as $m) {
|
|||
|
$this->assertTrue($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
|
|||
|
foreach ($noMatch as $m) {
|
|||
|
$this->assertFalse($c->test($m), '->test() tests a string against the expression');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function getTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array('< 1000', array('500', '999'), array('1000', '1500')),
|
|||
|
|
|||
|
array('< 1K', array('500', '999'), array('1000', '1500')),
|
|||
|
array('<1k', array('500', '999'), array('1000', '1500')),
|
|||
|
array(' < 1 K ', array('500', '999'), array('1000', '1500')),
|
|||
|
array('<= 1K', array('1000'), array('1001')),
|
|||
|
array('> 1K', array('1001'), array('1000')),
|
|||
|
array('>= 1K', array('1000'), array('999')),
|
|||
|
|
|||
|
array('< 1KI', array('500', '1023'), array('1024', '1500')),
|
|||
|
array('<= 1KI', array('1024'), array('1025')),
|
|||
|
array('> 1KI', array('1025'), array('1024')),
|
|||
|
array('>= 1KI', array('1024'), array('1023')),
|
|||
|
|
|||
|
array('1KI', array('1024'), array('1023', '1025')),
|
|||
|
array('==1KI', array('1024'), array('1023', '1025')),
|
|||
|
|
|||
|
array('==1m', array('1000000'), array('999999', '1000001')),
|
|||
|
array('==1mi', array(1024 * 1024), array(1024 * 1024 - 1, 1024 * 1024 + 1)),
|
|||
|
|
|||
|
array('==1g', array('1000000000'), array('999999999', '1000000001')),
|
|||
|
array('==1gi', array(1024 * 1024 * 1024), array(1024 * 1024 * 1024 - 1, 1024 * 1024 * 1024 + 1)),
|
|||
|
|
|||
|
array('!= 1000', array('500', '999'), array('1000')),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
public function getConstructorTestData()
|
|||
|
{
|
|||
|
return array(
|
|||
|
array(
|
|||
|
array(
|
|||
|
'1', '0',
|
|||
|
'3.5', '33.55', '123.456', '123456.78',
|
|||
|
'.1', '.123',
|
|||
|
'.0', '0.0',
|
|||
|
'1.', '0.', '123.',
|
|||
|
'==1', '!=1', '<1', '>1', '<=1', '>=1',
|
|||
|
'==1k', '==1ki', '==1m', '==1mi', '==1g', '==1gi',
|
|||
|
'1k', '1ki', '1m', '1mi', '1g', '1gi',
|
|||
|
),
|
|||
|
array(
|
|||
|
false, null, '',
|
|||
|
' ', 'foobar',
|
|||
|
'=1', '===1',
|
|||
|
'0 . 1', '123 .45', '234. 567',
|
|||
|
'..', '.0.', '0.1.2',
|
|||
|
),
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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\Tests;
|
|||
|
|
|||
|
use PHPUnit\Framework\TestCase;
|
|||
|
use Symfony\Component\Finder\Finder;
|
|||
|
use Symfony\Component\Finder\Glob;
|
|||
|
|
|||
|
class GlobTest extends TestCase
|
|||
|
{
|
|||
|
public function testGlobToRegexDelimiters()
|
|||
|
{
|
|||
|
$this->assertEquals('#^(?=[^\.])\#$#', Glob::toRegex('#'));
|
|||
|
$this->assertEquals('#^\.[^/]*$#', Glob::toRegex('.*'));
|
|||
|
$this->assertEquals('^\.[^/]*$', Glob::toRegex('.*', true, true, ''));
|
|||
|
$this->assertEquals('/^\.[^/]*$/', Glob::toRegex('.*', true, true, '/'));
|
|||
|
}
|
|||
|
|
|||
|
public function testGlobToRegexDoubleStarStrictDots()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->ignoreDotFiles(false);
|
|||
|
$regex = Glob::toRegex('/**/*.neon');
|
|||
|
|
|||
|
foreach ($finder->in(__DIR__) as $k => $v) {
|
|||
|
$k = str_replace(DIRECTORY_SEPARATOR, '/', $k);
|
|||
|
if (preg_match($regex, substr($k, strlen(__DIR__)))) {
|
|||
|
$match[] = substr($k, 10 + strlen(__DIR__));
|
|||
|
}
|
|||
|
}
|
|||
|
sort($match);
|
|||
|
|
|||
|
$this->assertSame(array('one/b/c.neon', 'one/b/d.neon'), $match);
|
|||
|
}
|
|||
|
|
|||
|
public function testGlobToRegexDoubleStarNonStrictDots()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->ignoreDotFiles(false);
|
|||
|
$regex = Glob::toRegex('/**/*.neon', false);
|
|||
|
|
|||
|
foreach ($finder->in(__DIR__) as $k => $v) {
|
|||
|
$k = str_replace(DIRECTORY_SEPARATOR, '/', $k);
|
|||
|
if (preg_match($regex, substr($k, strlen(__DIR__)))) {
|
|||
|
$match[] = substr($k, 10 + strlen(__DIR__));
|
|||
|
}
|
|||
|
}
|
|||
|
sort($match);
|
|||
|
|
|||
|
$this->assertSame(array('.dot/b/c.neon', '.dot/b/d.neon', 'one/b/c.neon', 'one/b/d.neon'), $match);
|
|||
|
}
|
|||
|
|
|||
|
public function testGlobToRegexDoubleStarWithoutLeadingSlash()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->ignoreDotFiles(false);
|
|||
|
$regex = Glob::toRegex('/Fixtures/one/**');
|
|||
|
|
|||
|
foreach ($finder->in(__DIR__) as $k => $v) {
|
|||
|
$k = str_replace(DIRECTORY_SEPARATOR, '/', $k);
|
|||
|
if (preg_match($regex, substr($k, strlen(__DIR__)))) {
|
|||
|
$match[] = substr($k, 10 + strlen(__DIR__));
|
|||
|
}
|
|||
|
}
|
|||
|
sort($match);
|
|||
|
|
|||
|
$this->assertSame(array('one/a', 'one/b', 'one/b/c.neon', 'one/b/d.neon'), $match);
|
|||
|
}
|
|||
|
|
|||
|
public function testGlobToRegexDoubleStarWithoutLeadingSlashNotStrictLeadingDot()
|
|||
|
{
|
|||
|
$finder = new Finder();
|
|||
|
$finder->ignoreDotFiles(false);
|
|||
|
$regex = Glob::toRegex('/Fixtures/one/**', false);
|
|||
|
|
|||
|
foreach ($finder->in(__DIR__) as $k => $v) {
|
|||
|
$k = str_replace(DIRECTORY_SEPARATOR, '/', $k);
|
|||
|
if (preg_match($regex, substr($k, strlen(__DIR__)))) {
|
|||
|
$match[] = substr($k, 10 + strlen(__DIR__));
|
|||
|
}
|
|||
|
}
|
|||
|
sort($match);
|
|||
|
|
|||
|
$this->assertSame(array('one/.dot', 'one/a', 'one/b', 'one/b/c.neon', 'one/b/d.neon'), $match);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 (array('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.
|
|||
|
*
|
|||
|
* @param string $glob The glob pattern
|
|||
|
* @param bool $strictLeadingDot
|
|||
|
* @param bool $strictWildcardSlash
|
|||
|
* @param string $delimiter Optional delimiter
|
|||
|
*
|
|||
|
* @return string regex The regexp
|
|||
|
*/
|
|||
|
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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($str)
|
|||
|
{
|
|||
|
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
|||
|
}
|
|||
|
}
|
|||
|
<?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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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_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;
|
|||
|
|
|||
|
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)
|
|||
|
{
|
|||
|
$this->iterator = $iterator;
|
|||
|
|
|||
|
if (self::SORT_BY_NAME === $sort) {
|
|||
|
$this->sort = function ($a, $b) {
|
|||
|
return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
|
|||
|
};
|
|||
|
} elseif (self::SORT_BY_TYPE === $sort) {
|
|||
|
$this->sort = function ($a, $b) {
|
|||
|
if ($a->isDir() && $b->isFile()) {
|
|||
|
return -1;
|
|||
|
} elseif ($a->isFile() && $b->isDir()) {
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
|
|||
|
};
|
|||
|
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
|||
|
$this->sort = function ($a, $b) {
|
|||
|
return $a->getATime() - $b->getATime();
|
|||
|
};
|
|||
|
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
|||
|
$this->sort = function ($a, $b) {
|
|||
|
return $a->getCTime() - $b->getCTime();
|
|||
|
};
|
|||
|
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
|||
|
$this->sort = function ($a, $b) {
|
|||
|
return $a->getMTime() - $b->getMTime();
|
|||
|
};
|
|||
|
} elseif (is_callable($sort)) {
|
|||
|
$this->sort = $sort;
|
|||
|
} else {
|
|||
|
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function getIterator()
|
|||
|
{
|
|||
|
$array = iterator_to_array($this->iterator, true);
|
|||
|
uasort($array, $this->sort);
|
|||
|
|
|||
|
return new \ArrayIterator($array);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 = array();
|
|||
|
|
|||
|
/**
|
|||
|
* @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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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($str)
|
|||
|
{
|
|||
|
return $this->isRegex($str) ? $str : Glob::toRegex($str);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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($str)
|
|||
|
{
|
|||
|
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 = array();
|
|||
|
|
|||
|
/**
|
|||
|
* @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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 = array();
|
|||
|
private $excludedPattern;
|
|||
|
|
|||
|
/**
|
|||
|
* @param \Iterator $iterator The Iterator to filter
|
|||
|
* @param array $directories An array of directories to exclude
|
|||
|
*/
|
|||
|
public function __construct(\Iterator $iterator, array $directories)
|
|||
|
{
|
|||
|
$this->iterator = $iterator;
|
|||
|
$this->isRecursive = $iterator instanceof \RecursiveIterator;
|
|||
|
$patterns = array();
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
public function hasChildren()
|
|||
|
{
|
|||
|
return $this->isRecursive && $this->iterator->hasChildren();
|
|||
|
}
|
|||
|
|
|||
|
public function getChildren()
|
|||
|
{
|
|||
|
$children = new self($this->iterator->getChildren(), array());
|
|||
|
$children->excludedDirs = $this->excludedDirs;
|
|||
|
$children->excludedPattern = $this->excludedPattern;
|
|||
|
|
|||
|
return $children;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 = array();
|
|||
|
|
|||
|
/**
|
|||
|
* @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 === call_user_func($filter, $fileinfo)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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 = array();
|
|||
|
protected $noMatchRegexps = array();
|
|||
|
|
|||
|
/**
|
|||
|
* @param \Iterator $iterator The Iterator to filter
|
|||
|
* @param array $matchPatterns An array of patterns that need to match
|
|||
|
* @param array $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.
|
|||
|
*
|
|||
|
* @param string $string The string to be matched against filters
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function isAccepted($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.
|
|||
|
*
|
|||
|
* @param string $str
|
|||
|
*
|
|||
|
* @return bool Whether the given string is a regex
|
|||
|
*/
|
|||
|
protected function isRegex($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 (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
|
|||
|
if ($start === $delimiters[0] && $end === $delimiters[1]) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Converts string into regexp.
|
|||
|
*
|
|||
|
* @param string $str Pattern
|
|||
|
*
|
|||
|
* @return string regexp corresponding to a given string
|
|||
|
*/
|
|||
|
abstract protected function toRegex($str);
|
|||
|
}
|
|||
|
<?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(array());
|
|||
|
} 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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?xml version="1.0" encoding="UTF-8"?>
|
|||
|
|
|||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|||
|
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
|||
|
backupGlobals="false"
|
|||
|
colors="true"
|
|||
|
bootstrap="vendor/autoload.php"
|
|||
|
failOnRisky="true"
|
|||
|
failOnWarning="true"
|
|||
|
>
|
|||
|
<php>
|
|||
|
<ini name="error_reporting" value="-1" />
|
|||
|
</php>
|
|||
|
|
|||
|
<testsuites>
|
|||
|
<testsuite name="Symfony Finder Component Test Suite">
|
|||
|
<directory>./Tests/</directory>
|
|||
|
</testsuite>
|
|||
|
</testsuites>
|
|||
|
|
|||
|
<filter>
|
|||
|
<whitelist>
|
|||
|
<directory>./</directory>
|
|||
|
<exclude>
|
|||
|
<directory>./Tests</directory>
|
|||
|
<directory>./vendor</directory>
|
|||
|
</exclude>
|
|||
|
</whitelist>
|
|||
|
</filter>
|
|||
|
</phpunit>
|
|||
|
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)
|
|||
|
{
|
|||
|
"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.1.3"
|
|||
|
},
|
|||
|
"autoload": {
|
|||
|
"psr-4": { "Symfony\\Component\\Finder\\": "" },
|
|||
|
"exclude-from-classmap": [
|
|||
|
"/Tests/"
|
|||
|
]
|
|||
|
},
|
|||
|
"minimum-stability": "dev",
|
|||
|
"extra": {
|
|||
|
"branch-alias": {
|
|||
|
"dev-master": "4.0-dev"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
CHANGELOG
|
|||
|
=========
|
|||
|
|
|||
|
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 '?'
|
|||
|
<?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\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 easy 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;
|
|||
|
|
|||
|
private $mode = 0;
|
|||
|
private $names = array();
|
|||
|
private $notNames = array();
|
|||
|
private $exclude = array();
|
|||
|
private $filters = array();
|
|||
|
private $depths = array();
|
|||
|
private $sizes = array();
|
|||
|
private $followLinks = false;
|
|||
|
private $sort = false;
|
|||
|
private $ignore = 0;
|
|||
|
private $dirs = array();
|
|||
|
private $dates = array();
|
|||
|
private $iterators = array();
|
|||
|
private $contains = array();
|
|||
|
private $notContains = array();
|
|||
|
private $paths = array();
|
|||
|
private $notPaths = array();
|
|||
|
private $ignoreUnreadableDirs = false;
|
|||
|
|
|||
|
private static $vcsPatterns = array('.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.
|
|||
|
*
|
|||
|
* @param string|int $level The depth level expression
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see DepthRangeFilterIterator
|
|||
|
* @see NumberComparator
|
|||
|
*/
|
|||
|
public function depth($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');
|
|||
|
*
|
|||
|
* @param string $date A date range string
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see strtotime
|
|||
|
* @see DateRangeFilterIterator
|
|||
|
* @see DateComparator
|
|||
|
*/
|
|||
|
public function date($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')
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (a regexp, a glob, or a string)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilenameFilterIterator
|
|||
|
*/
|
|||
|
public function name($pattern)
|
|||
|
{
|
|||
|
$this->names[] = $pattern;
|
|||
|
|
|||
|
return $this;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds rules that files must not match.
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (a regexp, a glob, or a string)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilenameFilterIterator
|
|||
|
*/
|
|||
|
public function notName($pattern)
|
|||
|
{
|
|||
|
$this->notNames[] = $pattern;
|
|||
|
|
|||
|
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')
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (string or regexp)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilecontentFilterIterator
|
|||
|
*/
|
|||
|
public function contains($pattern)
|
|||
|
{
|
|||
|
$this->contains[] = $pattern;
|
|||
|
|
|||
|
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')
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (string or regexp)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilecontentFilterIterator
|
|||
|
*/
|
|||
|
public function notContains($pattern)
|
|||
|
{
|
|||
|
$this->notContains[] = $pattern;
|
|||
|
|
|||
|
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
|
|||
|
*
|
|||
|
* Use only / as dirname separator.
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (a regexp or a string)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilenameFilterIterator
|
|||
|
*/
|
|||
|
public function path($pattern)
|
|||
|
{
|
|||
|
$this->paths[] = $pattern;
|
|||
|
|
|||
|
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
|
|||
|
*
|
|||
|
* Use only / as dirname separator.
|
|||
|
*
|
|||
|
* @param string $pattern A pattern (a regexp or a string)
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see FilenameFilterIterator
|
|||
|
*/
|
|||
|
public function notPath($pattern)
|
|||
|
{
|
|||
|
$this->notPaths[] = $pattern;
|
|||
|
|
|||
|
return $this;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds tests for file sizes.
|
|||
|
*
|
|||
|
* $finder->size('> 10K');
|
|||
|
* $finder->size('<= 1Ki');
|
|||
|
* $finder->size(4);
|
|||
|
*
|
|||
|
* @param string|int $size A size range string or an integer
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see SizeRangeFilterIterator
|
|||
|
* @see NumberComparator
|
|||
|
*/
|
|||
|
public function size($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.
|
|||
|
*
|
|||
|
* @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see ExcludeDirectoryFilterIterator
|
|||
|
*/
|
|||
|
public function ignoreDotFiles($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.
|
|||
|
*
|
|||
|
* @param bool $ignoreVCS Whether to exclude VCS files or not
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @see ExcludeDirectoryFilterIterator
|
|||
|
*/
|
|||
|
public function ignoreVCS($ignoreVCS)
|
|||
|
{
|
|||
|
if ($ignoreVCS) {
|
|||
|
$this->ignore |= static::IGNORE_VCS_FILES;
|
|||
|
} else {
|
|||
|
$this->ignore &= ~static::IGNORE_VCS_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()
|
|||
|
{
|
|||
|
$this->sort = 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;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 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.
|
|||
|
*
|
|||
|
* @param bool $ignore
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*/
|
|||
|
public function ignoreUnreadableDirs($ignore = true)
|
|||
|
{
|
|||
|
$this->ignoreUnreadableDirs = (bool) $ignore;
|
|||
|
|
|||
|
return $this;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Searches files and directories which match defined rules.
|
|||
|
*
|
|||
|
* @param string|array $dirs A directory path or an array of directories
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @throws \InvalidArgumentException if one of the directories does not exist
|
|||
|
*/
|
|||
|
public function in($dirs)
|
|||
|
{
|
|||
|
$resolvedDirs = array();
|
|||
|
|
|||
|
foreach ((array) $dirs as $dir) {
|
|||
|
if (is_dir($dir)) {
|
|||
|
$resolvedDirs[] = $dir;
|
|||
|
} elseif ($glob = glob($dir, (defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
|
|||
|
$resolvedDirs = array_merge($resolvedDirs, $glob);
|
|||
|
} else {
|
|||
|
throw new \InvalidArgumentException(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.
|
|||
|
*
|
|||
|
* @param mixed $iterator
|
|||
|
*
|
|||
|
* @return $this
|
|||
|
*
|
|||
|
* @throws \InvalidArgumentException when the given argument is not iterable
|
|||
|
*/
|
|||
|
public function append($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
|
|||
|
{
|
|||
|
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
|
|||
|
$this->exclude = array_merge($this->exclude, self::$vcsPatterns);
|
|||
|
}
|
|||
|
|
|||
|
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
|
|||
|
$this->notPaths[] = '#(^|/)\..+(/|$)#';
|
|||
|
}
|
|||
|
|
|||
|
$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 ($this->exclude) {
|
|||
|
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->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 || $this->notPaths) {
|
|||
|
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
|
|||
|
}
|
|||
|
|
|||
|
if ($this->sort) {
|
|||
|
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
|
|||
|
$iterator = $iteratorAggregate->getIterator();
|
|||
|
}
|
|||
|
|
|||
|
return $iterator;
|
|||
|
}
|
|||
|
}
|
|||
|
Copyright (c) 2004-2018 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.
|
|||
|
<?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] : '==');
|
|||
|
}
|
|||
|
}
|
|||
|
<?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;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Sets the target value.
|
|||
|
*
|
|||
|
* @param string $target The target value
|
|||
|
*/
|
|||
|
public function setTarget($target)
|
|||
|
{
|
|||
|
$this->target = $target;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Gets the comparison operator.
|
|||
|
*
|
|||
|
* @return string The operator
|
|||
|
*/
|
|||
|
public function getOperator()
|
|||
|
{
|
|||
|
return $this->operator;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Sets the comparison operator.
|
|||
|
*
|
|||
|
* @param string $operator A valid operator
|
|||
|
*
|
|||
|
* @throws \InvalidArgumentException
|
|||
|
*/
|
|||
|
public function setOperator($operator)
|
|||
|
{
|
|||
|
if (!$operator) {
|
|||
|
$operator = '==';
|
|||
|
}
|
|||
|
|
|||
|
if (!in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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);
|
|||
|
}
|
|||
|
}
|
|||
|
<?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;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the contents of the file.
|
|||
|
*
|
|||
|
* @return string the contents of the file
|
|||
|
*
|
|||
|
* @throws \RuntimeException
|
|||
|
*/
|
|||
|
public function getContents()
|
|||
|
{
|
|||
|
$level = error_reporting(0);
|
|||
|
$content = file_get_contents($this->getPathname());
|
|||
|
error_reporting($level);
|
|||
|
if (false === $content) {
|
|||
|
$error = error_get_last();
|
|||
|
throw new \RuntimeException($error['message']);
|
|||
|
}
|
|||
|
|
|||
|
return $content;
|
|||
|
}
|
|||
|
}
|
|||
|
<?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
|
|||
|
{
|
|||
|
}
|
|||
|
<?php
|
|||
|
|
|||
|
// autoload.php @generated by Composer
|
|||
|
|
|||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
|||
|
|
|||
|
return ComposerAutoloaderInitf90ebbc9abf27126721bf097052ab924::getLoader();
|
|||
|
<?php
|
|||
|
|
|||
|
namespace PharLite;
|
|||
|
|
|||
|
class Builder
|
|||
|
{
|
|||
|
|
|||
|
const PHAR_TYPE_APP = "app";
|
|||
|
const PHAR_TYPE_WEB = "web";
|
|||
|
const PHAR_TYPE_LIB = "lib";
|
|||
|
|
|||
|
/** @var string */
|
|||
|
protected $path;
|
|||
|
|
|||
|
protected $manifest;
|
|||
|
|
|||
|
protected $composer;
|
|||
|
|
|||
|
protected $output;
|
|||
|
|
|||
|
protected $pharType = self::PHAR_TYPE_LIB;
|
|||
|
|
|||
|
protected $pharOpts = [];
|
|||
|
|
|||
|
protected $index;
|
|||
|
|
|||
|
protected $bins;
|
|||
|
|
|||
|
protected $dependencies = [];
|
|||
|
|
|||
|
private static $default_options = [
|
|||
|
'install' => false,
|
|||
|
];
|
|||
|
|
|||
|
public function __construct($path=null, array $opts=[])
|
|||
|
{
|
|||
|
if (!$path) {
|
|||
|
$path = getcwd();
|
|||
|
}
|
|||
|
|
|||
|
if (!file_exists($path."/composer.json")) {
|
|||
|
throw new \RuntimeException("Could not find a composer.json in {$path}");
|
|||
|
}
|
|||
|
|
|||
|
$this->opts = array_merge(
|
|||
|
self::$default_options,
|
|||
|
$opts
|
|||
|
);
|
|||
|
$this->path = $path;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private function readComposer()
|
|||
|
{
|
|||
|
print_info("Parsing composer.json...");
|
|||
|
|
|||
|
$json = file_get_contents($this->path."/composer.json");
|
|||
|
|
|||
|
$composer = json_decode($json);
|
|||
|
|
|||
|
if (isset($composer->require)) {
|
|||
|
foreach ($composer->require as $package=>$constraint) {
|
|||
|
if ($package == "php") {
|
|||
|
$this->dependencies[$package] = $constraint;
|
|||
|
print_info(" ! require php: %s", $constraint);
|
|||
|
} elseif (strpos($package, "ext-") === 0) {
|
|||
|
$this->dependencies[$package] = $constraint;
|
|||
|
print_info(" ! require ext: %s %s", $package, $constraint);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!isset($composer->bin) || !is_array($composer->bin)) {
|
|||
|
print_warn("No executable defined, building a library phar...");
|
|||
|
} elseif (count($composer->bin)>1) {
|
|||
|
print_notice("More than one executable defined, using the first one as default");
|
|||
|
print_info(" → Using default executable %s", $composer->bin[0]);
|
|||
|
for ($n = 1; $n < count($composer->bin); $n++) {
|
|||
|
print_info(" → Adding alternate executable %s", $composer->bin[$n]);
|
|||
|
}
|
|||
|
$this->bins = $composer->bin;
|
|||
|
} else {
|
|||
|
print_info(" → Using executable %s", $composer->bin[0]);
|
|||
|
$this->bins = $composer->bin;
|
|||
|
}
|
|||
|
|
|||
|
if ($this->index) {
|
|||
|
$this->pharType = self::PHAR_TYPE_WEB;
|
|||
|
$this->output = basename($this->index,".php").".phar";
|
|||
|
} else {
|
|||
|
if (isset($composer->bin) && is_array($composer->bin)) {
|
|||
|
$this->pharType = self::PHAR_TYPE_APP;
|
|||
|
}
|
|||
|
$this->output = "output.phar";
|
|||
|
}
|
|||
|
|
|||
|
if (isset($composer->extra)) {
|
|||
|
if (isset($composer->extra->phar)) {
|
|||
|
print_info(" → Found extra phar configuration");
|
|||
|
$this->pharOpts = (array)$composer->extra->phar;
|
|||
|
}
|
|||
|
if (array_key_exists('output', $this->pharOpts)) {
|
|||
|
$this->output = $this->pharOpts['output'];
|
|||
|
}
|
|||
|
if (array_key_exists('stub', $this->pharOpts)) {
|
|||
|
// set a custom stub
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
print_info("Generating output %s", $this->output);
|
|||
|
|
|||
|
$this->composer = $composer;
|
|||
|
}
|
|||
|
|
|||
|
private function installComposer()
|
|||
|
{
|
|||
|
print_info("Installing dependencies...");
|
|||
|
passthru("composer install --no-interaction --optimize-autoloader");
|
|||
|
}
|
|||
|
|
|||
|
private function buildManifest()
|
|||
|
{
|
|||
|
print_info("Creating manifest...");
|
|||
|
|
|||
|
$excluded = (array)(
|
|||
|
array_key_exists('exclude',$this->pharOpts)
|
|||
|
?$this->pharOpts['exclude']
|
|||
|
:[]
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
$manifest = new Manifest($this->path);
|
|||
|
|
|||
|
$manifest->setExcluded($excluded);
|
|||
|
|
|||
|
// Always include the vendor directory
|
|||
|
print_info(" ← vendor/");
|
|||
|
$manifest->addDirectory("vendor");
|
|||
|
// Include everything from the autoload
|
|||
|
if (isset($this->composer->autoload)) {
|
|||
|
foreach ((array)$this->composer->autoload as $type=>$autoloaders) {
|
|||
|
if ($type == "files") {
|
|||
|
foreach ($autoloaders as $file) {
|
|||
|
print_info(" ← %s", $file);
|
|||
|
$manifest->addFile($file);
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
foreach ($autoloaders as $prefix=>$path) {
|
|||
|
print_info(" ← %s", $path);
|
|||
|
$manifest->addDirectory($path);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (array_key_exists('include', $this->pharOpts)) {
|
|||
|
foreach ((array)$this->pharOpts['include'] as $path) {
|
|||
|
print_info(" ← %s", $path);
|
|||
|
if (substr($path,-1,1)==DIRECTORY_SEPARATOR) {
|
|||
|
$manifest->addDirectory($path);
|
|||
|
} else {
|
|||
|
$manifest->addFile($path);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$this->manifest = $manifest;
|
|||
|
}
|
|||
|
|
|||
|
private function generateBootstrap(\Phar $phar, $type, $index=null, ?array $bins=null)
|
|||
|
{
|
|||
|
print_info("Generating bootstrap stub...");
|
|||
|
|
|||
|
$bins = (array)$bins;
|
|||
|
|
|||
|
$indexFile = "<?php\n";
|
|||
|
|
|||
|
$depcheck = null;
|
|||
|
foreach ($this->dependencies as $dep=>$constraint) {
|
|||
|
if ($dep == "php") {
|
|||
|
|
|||
|
} elseif (strpos($dep, "ext-") === 0) {
|
|||
|
$ext = substr($dep, 4);
|
|||
|
$depcheck.= 'if (!extension_loaded("' . $ext . '")) { @fwrite(STDERR, "Fatal: Missing required extension ' . $ext . '.\n"); exit(2); }' . PHP_EOL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$indexFile.= "define('WD',getcwd()); ";
|
|||
|
|
|||
|
if (!$index && count($bins)==0) {
|
|||
|
$indexFile.= 'require_once __DIR__."/vendor/autoload.php";';
|
|||
|
} elseif (count($bins)>1) {
|
|||
|
$indexFile.= '$bin=getenv("PHAR_ENTRY")?:basename($argv[0],".phar"); switch($bin) {';
|
|||
|
for ($n = 1; $n<count($bins); $n++) {
|
|||
|
$indexFile.= 'case '.var_export(basename($bins[$n]),true).': require_once __DIR__."/".'.var_export($bins[$n],true).'; break;';
|
|||
|
}
|
|||
|
$indexFile.= 'case '.var_export(basename($bins[0]),true).': default: require_once __DIR__."/".'.var_export($bins[0],true).'; break;';
|
|||
|
$indexFile.= '}';
|
|||
|
$index = "bootstrap.php";
|
|||
|
foreach ($bins as $bin) {
|
|||
|
$str = file_get_contents($bin);
|
|||
|
$str = $this->stripShebang($str);
|
|||
|
$phar->addFromString($bin, $str);
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (count($bins)) {
|
|||
|
$index = array_shift($bins);
|
|||
|
}
|
|||
|
$indexFile = file_get_contents($index);
|
|||
|
$indexFile = $this->stripShebang($indexFile);
|
|||
|
$index = "bootstrap.php";
|
|||
|
}
|
|||
|
|
|||
|
$indexFile = str_replace("<?php", "<?php ".$depcheck, $indexFile);
|
|||
|
|
|||
|
$stub = "#!/usr/bin/env php\n".$phar->createDefaultStub($index);
|
|||
|
$phar->setStub($stub);
|
|||
|
|
|||
|
if ($index) {
|
|||
|
$phar->addFromString($index, $indexFile);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private function stripShebang($str)
|
|||
|
{
|
|||
|
if (strpos($str, '#!') === 0) {
|
|||
|
if (strpos($str, '#!/usr/bin/env php') === 0) {
|
|||
|
$str = substr($str,strpos($str, "<?"));
|
|||
|
}
|
|||
|
}
|
|||
|
return $str;
|
|||
|
}
|
|||
|
|
|||
|
private function writeMetadata(\Phar $phar, array $metadata=[])
|
|||
|
{
|
|||
|
$metadata = array_merge([
|
|||
|
'phar.generator' => "PharLite/".PHARLITE_VERSION." (PHP/".PHP_VERSION.")",
|
|||
|
'phar.type' => $this->pharType,
|
|||
|
'package.name' => isset($this->composer->name)?$this->composer->name:null,
|
|||
|
'package.version' => isset($this->composer->version)?$this->composer->version:null,
|
|||
|
], $metadata);
|
|||
|
|
|||
|
print_info("Writing metadata:\n%s", json_encode($metadata, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT));
|
|||
|
|
|||
|
$phar->setMetadata($metadata);
|
|||
|
}
|
|||
|
|
|||
|
public function build()
|
|||
|
{
|
|||
|
$this->readComposer();
|
|||
|
|
|||
|
if ($this->opts['install']) {
|
|||
|
$this->installComposer();
|
|||
|
}
|
|||
|
|
|||
|
$this->buildManifest();
|
|||
|
|
|||
|
print_info("Adding files...");
|
|||
|
|
|||
|
$tempName = uniqid("phar").".phar";
|
|||
|
$phar = new \Phar($tempName);
|
|||
|
|
|||
|
$total = count($this->manifest);
|
|||
|
$pcf = 100 / $total;
|
|||
|
$bw = 40;
|
|||
|
$tw = intval(exec("tput cols"));
|
|||
|
$pbf = $tw / $total;
|
|||
|
$index = 0;
|
|||
|
$spinner = [ "/", "-", "\\", "|" ];
|
|||
|
$s = 0; $t = microtime(true);
|
|||
|
$totalBytes = 0;
|
|||
|
foreach ($this->manifest as $object) {
|
|||
|
// printf(" %s: %s\n", $object->getFilename(), $object->getLocalName());
|
|||
|
$object->addToPhar($phar);
|
|||
|
$index++;
|
|||
|
$totalBytes += $object->getFilesize();
|
|||
|
if (posix_isatty(STDOUT) && (microtime(true)>$t+.2)) {
|
|||
|
$t = microtime(true);
|
|||
|
$pc = $pcf * $index;
|
|||
|
$pb = round($pbf * $index);
|
|||
|
$bar = str_pad(sprintf(" %4.1f%% %d files, %.1fKiB %s ", $pc, $index, $totalBytes/1024, dirname($object->getFilename())), $tw);
|
|||
|
echo "\r\e[30;42m".substr($bar, 0, $pb)."\e[0m".substr($bar, $pb);
|
|||
|
//printf("\r%4.1f%% [%s%s%s] %d files, %.1fKiB", $pc, str_repeat("=",$pb), $spinner[$s=(($s+1)%4)], str_repeat(" ",$bw-$pb), $index, $totalBytes/1024);
|
|||
|
}
|
|||
|
}
|
|||
|
if (posix_isatty(STDOUT)) {
|
|||
|
printf("\r\e[2K");
|
|||
|
}
|
|||
|
|
|||
|
print_info("Added %d files!", $index);
|
|||
|
|
|||
|
$this->generateBootstrap($phar, $this->pharType, $this->index, $this->bins);
|
|||
|
$this->writeMetadata($phar, (array)(array_key_exists('metadata',$this->pharOpts)?$this->pharOpts['metadata']:[]));
|
|||
|
|
|||
|
if (file_exists($this->output)) {
|
|||
|
unlink($this->output);
|
|||
|
}
|
|||
|
rename($tempName, $this->output);
|
|||
|
chmod($this->output, 0777);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public function initConfig()
|
|||
|
{
|
|||
|
print_info("Configuring pharlite");
|
|||
|
|
|||
|
$askString = function($prompt, $default=null) {
|
|||
|
return readline($prompt." [".$default."]? ")?:null;
|
|||
|
};
|
|||
|
|
|||
|
$composer = json_decode(file_get_contents($this->path."/composer.json"));
|
|||
|
|
|||
|
if (!isset($composer->extra)) {
|
|||
|
$composer->extra = (object)[];
|
|||
|
}
|
|||
|
if (!isset($composer->extra->phar)) {
|
|||
|
$composer->extra->phar = (object)[];
|
|||
|
}
|
|||
|
|
|||
|
if ($output = $askString('Output filename', @$composer->extra->phar->output)) {
|
|||
|
$composer->extra->phar->output = $output;
|
|||
|
}
|
|||
|
if ($index = $askString('Index file (for web phar)', @$composer->extra->phar->index)) {
|
|||
|
$composer->extra->phar->index = $index;
|
|||
|
}
|
|||
|
if ($stub = $askString('Loader stub', @$composer->extra->phar->stub)) {
|
|||
|
$composer->extra->phar->stub = $stub;
|
|||
|
}
|
|||
|
|
|||
|
if (empty($composer->bin)) {
|
|||
|
print_warn("You have no bins defined in your composer.json. Specify at least one bin to create an application phar.");
|
|||
|
}
|
|||
|
|
|||
|
if (file_exists($this->path."/composer.bak")) {
|
|||
|
unlink($this->path."/composer.bak");
|
|||
|
}
|
|||
|
rename($this->path."/composer.json", $this->path."/composer.bak");
|
|||
|
file_put_contents($this->path."/composer.json", json_encode($composer, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)."\n");
|
|||
|
|
|||
|
exec("composer validate --no-check-lock -q", $output, $retval);
|
|||
|
if ($retval == 0) {
|
|||
|
print_info("Updated composer.json");
|
|||
|
unlink($this->path."/composer.bak");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
print_error("The composer.json file isn't valid after being modified. Reverting...");
|
|||
|
unlink($this->path."/composer.json");
|
|||
|
rename($this->path."/composer.bak", $this->path."/composer.json");
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
<?php
|
|||
|
|
|||
|
namespace PharLite;
|
|||
|
|
|||
|
use Symfony\Component\Finder\Finder;
|
|||
|
|
|||
|
|
|||
|
class Manifest implements \IteratorAggregate, \Countable
|
|||
|
{
|
|||
|
/** @var string Root directory of the project being built */
|
|||
|
protected $root;
|
|||
|
/** @var ManifestObject[] The included objects */
|
|||
|
protected $objects = [];
|
|||
|
|
|||
|
protected $excluded = [];
|
|||
|
|
|||
|
public function __construct($root)
|
|||
|
{
|
|||
|
$this->root = $root;
|
|||
|
}
|
|||
|
|
|||
|
public function setExcluded(array $patterns=[])
|
|||
|
{
|
|||
|
$this->excluded = $patterns;
|
|||
|
}
|
|||
|
|
|||
|
public function addDirectory($path, callable $filter=null)
|
|||
|
{
|
|||
|
$path = rtrim($path, DIRECTORY_SEPARATOR);
|
|||
|
$obj = (new Finder)->files()->in($path);
|
|||
|
foreach ($obj as $o) {
|
|||
|
if (is_callable($filter) && (false === $filter($o))) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
$path = $o->getPathname();
|
|||
|
$this->addFile($path);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function addFile($file)
|
|||
|
{
|
|||
|
// Don't add the file if it matches an excluded pattern
|
|||
|
if ($this->excluded) foreach ($this->excluded as $p) {
|
|||
|
if (fnmatch($p, $file)) return;
|
|||
|
}
|
|||
|
|
|||
|
// Figure out local path name
|
|||
|
if (strpos($file, $this->root) === 0) {
|
|||
|
$local = substr($file, 0, strlen($this->root));
|
|||
|
} else {
|
|||
|
$local = $file;
|
|||
|
}
|
|||
|
|
|||
|
// Add object to manifest
|
|||
|
$this->objects[] = new ManifestObject($file, $local);
|
|||
|
}
|
|||
|
|
|||
|
public function getIterator()
|
|||
|
{
|
|||
|
return new \ArrayIterator($this->objects);
|
|||
|
}
|
|||
|
|
|||
|
public function count()
|
|||
|
{
|
|||
|
return count($this->objects);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
<?php
|
|||
|
|
|||
|
namespace PharLite;
|
|||
|
|
|||
|
/**
|
|||
|
* Class representing a single object to be added to a phar
|
|||
|
*
|
|||
|
*
|
|||
|
*/
|
|||
|
class ManifestObject
|
|||
|
{
|
|||
|
protected $filename;
|
|||
|
|
|||
|
protected $localname;
|
|||
|
|
|||
|
protected $stripped = false;
|
|||
|
|
|||
|
public function __construct($filename, $localname=null)
|
|||
|
{
|
|||
|
$this->filename = $filename;
|
|||
|
$this->localname = $localname;
|
|||
|
}
|
|||
|
|
|||
|
public function setStripped(bool $stripped)
|
|||
|
{
|
|||
|
$this->stripped = $stripped;
|
|||
|
}
|
|||
|
|
|||
|
public function getStripped():bool
|
|||
|
{
|
|||
|
return $this->stripped;
|
|||
|
}
|
|||
|
|
|||
|
public function getFilename():string
|
|||
|
{
|
|||
|
return $this->filename;
|
|||
|
}
|
|||
|
|
|||
|
public function getLocalName():string
|
|||
|
{
|
|||
|
return $this->localname;
|
|||
|
}
|
|||
|
|
|||
|
public function addToPhar(\Phar $phar)
|
|||
|
{
|
|||
|
if ($this->stripped) {
|
|||
|
// strip and add
|
|||
|
} else {
|
|||
|
$phar->addFile(
|
|||
|
$this->getFilename(),
|
|||
|
$this->getLocalName()
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public function addFiltered(\Phar $phar, callable $filter)
|
|||
|
{
|
|||
|
$body = file_get_contents(realpath($this->filename));
|
|||
|
$body = call_user_func($filter, $body);
|
|||
|
$phar->addFromString($this->getLocalName(), $body);
|
|||
|
}
|
|||
|
|
|||
|
public function getFilesize()
|
|||
|
{
|
|||
|
return filesize(realpath($this->filename));
|
|||
|
}
|
|||
|
}
|
|||
|
<?php
|
|||
|
|
|||
|
if (is_dir(__DIR__."/../vendor"))
|
|||
|
require_once __DIR__."/../vendor/autoload.php";
|
|||
|
elseif (file_exists(__DIR__."/../../../autoload.php"))
|
|||
|
require_once __DIR__."/../../../autoload.php";
|
|||
|
else
|
|||
|
die("Could not locate composer vendor/autoload.php");
|
|||
|
|
|||
|
define("PHARLITE_VERSION", "0.1.x");
|
|||
|
|
|||
|
if (posix_isatty(STDOUT)) {
|
|||
|
define("FMT_ERR", "\e[31;1m");
|
|||
|
define("FMT_WARN", "\e[33;1m");
|
|||
|
define("FMT_INFO", "\e[32m");
|
|||
|
define("FMT_NOTICE", "\e[33m");
|
|||
|
define("FMT_AFTER", "\e[0m");
|
|||
|
} else {
|
|||
|
define("FMT_ERR", "");
|
|||
|
define("FMT_WARN", "");
|
|||
|
define("FMT_INFO", "");
|
|||
|
define("FMT_AFTER", "");
|
|||
|
define("FMT_NOTICE", "");
|
|||
|
}
|
|||
|
|
|||
|
function print_error($fmt, ...$arg) {
|
|||
|
fprintf(STDOUT, FMT_ERR.$fmt."ERROR: ".FMT_AFTER.PHP_EOL, ...$arg);
|
|||
|
}
|
|||
|
|
|||
|
function print_warn($fmt, ...$arg) {
|
|||
|
fprintf(STDOUT, FMT_WARN.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
|||
|
}
|
|||
|
|
|||
|
function print_info($fmt, ...$arg) {
|
|||
|
fprintf(STDOUT, FMT_INFO.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
|||
|
}
|
|||
|
|
|||
|
function print_notice($fmt, ...$arg) {
|
|||
|
fprintf(STDOUT, FMT_NOTICE.$fmt.FMT_AFTER.PHP_EOL, ...$arg);
|
|||
|
}
|
|||
|
|
|||
|
function show_app_usage() {
|
|||
|
printf("options:\n");
|
|||
|
printf(" -I,--init Initialize a new configuration\n");
|
|||
|
}
|
|||
|
|
|||
|
function parse_opts() {
|
|||
|
|
|||
|
$opts = getopt(
|
|||
|
"ho:d:iI",
|
|||
|
[
|
|||
|
"help",
|
|||
|
"directory:",
|
|||
|
"dir:",
|
|||
|
"output:",
|
|||
|
"install",
|
|||
|
"init"
|
|||
|
]
|
|||
|
);
|
|||
|
|
|||
|
$parsed = [
|
|||
|
'install' => false,
|
|||
|
'init' => false
|
|||
|
];
|
|||
|
|
|||
|
foreach ($opts as $option=>$value) {
|
|||
|
switch ($option) {
|
|||
|
case 'h':
|
|||
|
case 'help':
|
|||
|
show_app_usage();
|
|||
|
return false;
|
|||
|
case 'd':
|
|||
|
case 'dir':
|
|||
|
case 'directory':
|
|||
|
$parsed['dir'] = $value;
|
|||
|
break;
|
|||
|
case 'o':
|
|||
|
case 'output':
|
|||
|
$parsed['output'] = $value;
|
|||
|
break;
|
|||
|
case 'i':
|
|||
|
case 'install':
|
|||
|
$parsed['install'] = true;
|
|||
|
break;
|
|||
|
case 'I':
|
|||
|
case 'init':
|
|||
|
$parsed['init'] = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $parsed;
|
|||
|
}
|
|||
|
|
|||
|
$opts = parse_opts();
|
|||
|
if (false === $opts) {
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
|
|||
|
$path = getcwd();
|
|||
|
|
|||
|
$builder = new PharLite\Builder($path, $opts);
|
|||
|
if ($opts['init']) {
|
|||
|
$builder->initConfig();
|
|||
|
} else {
|
|||
|
$builder->build();
|
|||
|
}
|
|||
|
><3E><><EFBFBD><<3C>R<EFBFBD><52><EFBFBD>6<EFBFBD>j<EFBFBD><6A>Z<EFBFBD>>GBMB
|