installed plugin Infinite Uploads
version 2.0.8
This commit is contained in:
43
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/AstRuntime.php
vendored
Normal file
43
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/AstRuntime.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Uses an external tree visitor to interpret an AST.
|
||||
*/
|
||||
class AstRuntime
|
||||
{
|
||||
private $parser;
|
||||
private $interpreter;
|
||||
private $cache = [];
|
||||
private $cachedCount = 0;
|
||||
public function __construct(\UglyRobot\Infinite_Uploads\JmesPath\Parser $parser = null, callable $fnDispatcher = null)
|
||||
{
|
||||
$fnDispatcher = $fnDispatcher ?: \UglyRobot\Infinite_Uploads\JmesPath\FnDispatcher::getInstance();
|
||||
$this->interpreter = new \UglyRobot\Infinite_Uploads\JmesPath\TreeInterpreter($fnDispatcher);
|
||||
$this->parser = $parser ?: new \UglyRobot\Infinite_Uploads\JmesPath\Parser();
|
||||
}
|
||||
/**
|
||||
* Returns data from the provided input that matches a given JMESPath
|
||||
* expression.
|
||||
*
|
||||
* @param string $expression JMESPath expression to evaluate
|
||||
* @param mixed $data Data to search. This data should be data that
|
||||
* is similar to data returned from json_decode
|
||||
* using associative arrays rather than objects.
|
||||
*
|
||||
* @return mixed Returns the matching data or null
|
||||
*/
|
||||
public function __invoke($expression, $data)
|
||||
{
|
||||
if (!isset($this->cache[$expression])) {
|
||||
// Clear the AST cache when it hits 1024 entries
|
||||
if (++$this->cachedCount > 1024) {
|
||||
$this->cache = [];
|
||||
$this->cachedCount = 0;
|
||||
}
|
||||
$this->cache[$expression] = $this->parser->parse($expression);
|
||||
}
|
||||
return $this->interpreter->visit($this->cache[$expression], $data);
|
||||
}
|
||||
}
|
68
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/CompilerRuntime.php
vendored
Normal file
68
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/CompilerRuntime.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Compiles JMESPath expressions to PHP source code and executes it.
|
||||
*
|
||||
* JMESPath file names are stored in the cache directory using the following
|
||||
* logic to determine the filename:
|
||||
*
|
||||
* 1. Start with the string "jmespath_"
|
||||
* 2. Append the MD5 checksum of the expression.
|
||||
* 3. Append ".php"
|
||||
*/
|
||||
class CompilerRuntime
|
||||
{
|
||||
private $parser;
|
||||
private $compiler;
|
||||
private $cacheDir;
|
||||
private $interpreter;
|
||||
/**
|
||||
* @param string|null $dir Directory used to store compiled PHP files.
|
||||
* @param Parser|null $parser JMESPath parser to utilize
|
||||
* @throws \RuntimeException if the cache directory cannot be created
|
||||
*/
|
||||
public function __construct($dir = null, \UglyRobot\Infinite_Uploads\JmesPath\Parser $parser = null)
|
||||
{
|
||||
$this->parser = $parser ?: new \UglyRobot\Infinite_Uploads\JmesPath\Parser();
|
||||
$this->compiler = new \UglyRobot\Infinite_Uploads\JmesPath\TreeCompiler();
|
||||
$dir = $dir ?: sys_get_temp_dir();
|
||||
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
|
||||
throw new \RuntimeException("Unable to create cache directory: {$dir}");
|
||||
}
|
||||
$this->cacheDir = realpath($dir);
|
||||
$this->interpreter = new \UglyRobot\Infinite_Uploads\JmesPath\TreeInterpreter();
|
||||
}
|
||||
/**
|
||||
* Returns data from the provided input that matches a given JMESPath
|
||||
* expression.
|
||||
*
|
||||
* @param string $expression JMESPath expression to evaluate
|
||||
* @param mixed $data Data to search. This data should be data that
|
||||
* is similar to data returned from json_decode
|
||||
* using associative arrays rather than objects.
|
||||
*
|
||||
* @return mixed Returns the matching data or null
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __invoke($expression, $data)
|
||||
{
|
||||
$functionName = 'jmespath_' . md5($expression);
|
||||
if (!function_exists($functionName)) {
|
||||
$filename = "{$this->cacheDir}/{$functionName}.php";
|
||||
if (!file_exists($filename)) {
|
||||
$this->compile($filename, $expression, $functionName);
|
||||
}
|
||||
require $filename;
|
||||
}
|
||||
return $functionName($this->interpreter, $data);
|
||||
}
|
||||
private function compile($filename, $expression, $functionName)
|
||||
{
|
||||
$code = $this->compiler->visit($this->parser->parse($expression), $functionName, $expression);
|
||||
if (!file_put_contents($filename, $code)) {
|
||||
throw new \RuntimeException(sprintf('Unable to write the compiled PHP code to: %s (%s)', $filename, var_export(error_get_last(), true)));
|
||||
}
|
||||
}
|
||||
}
|
85
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/DebugRuntime.php
vendored
Normal file
85
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/DebugRuntime.php
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Provides CLI debugging information for the AST and Compiler runtimes.
|
||||
*/
|
||||
class DebugRuntime
|
||||
{
|
||||
private $runtime;
|
||||
private $out;
|
||||
private $lexer;
|
||||
private $parser;
|
||||
public function __construct(callable $runtime, $output = null)
|
||||
{
|
||||
$this->runtime = $runtime;
|
||||
$this->out = $output ?: STDOUT;
|
||||
$this->lexer = new \UglyRobot\Infinite_Uploads\JmesPath\Lexer();
|
||||
$this->parser = new \UglyRobot\Infinite_Uploads\JmesPath\Parser($this->lexer);
|
||||
}
|
||||
public function __invoke($expression, $data)
|
||||
{
|
||||
if ($this->runtime instanceof CompilerRuntime) {
|
||||
return $this->debugCompiled($expression, $data);
|
||||
}
|
||||
return $this->debugInterpreted($expression, $data);
|
||||
}
|
||||
private function debugInterpreted($expression, $data)
|
||||
{
|
||||
return $this->debugCallback(function () use($expression, $data) {
|
||||
$runtime = $this->runtime;
|
||||
return $runtime($expression, $data);
|
||||
}, $expression, $data);
|
||||
}
|
||||
private function debugCompiled($expression, $data)
|
||||
{
|
||||
$result = $this->debugCallback(function () use($expression, $data) {
|
||||
$runtime = $this->runtime;
|
||||
return $runtime($expression, $data);
|
||||
}, $expression, $data);
|
||||
$this->dumpCompiledCode($expression);
|
||||
return $result;
|
||||
}
|
||||
private function dumpTokens($expression)
|
||||
{
|
||||
$lexer = new \UglyRobot\Infinite_Uploads\JmesPath\Lexer();
|
||||
fwrite($this->out, "Tokens\n======\n\n");
|
||||
$tokens = $lexer->tokenize($expression);
|
||||
foreach ($tokens as $t) {
|
||||
fprintf($this->out, "%3d %-13s %s\n", $t['pos'], $t['type'], json_encode($t['value']));
|
||||
}
|
||||
fwrite($this->out, "\n");
|
||||
}
|
||||
private function dumpAst($expression)
|
||||
{
|
||||
$parser = new \UglyRobot\Infinite_Uploads\JmesPath\Parser();
|
||||
$ast = $parser->parse($expression);
|
||||
fwrite($this->out, "AST\n========\n\n");
|
||||
fwrite($this->out, json_encode($ast, JSON_PRETTY_PRINT) . "\n");
|
||||
}
|
||||
private function dumpCompiledCode($expression)
|
||||
{
|
||||
fwrite($this->out, "Code\n========\n\n");
|
||||
$dir = sys_get_temp_dir();
|
||||
$hash = md5($expression);
|
||||
$functionName = "jmespath_{$hash}";
|
||||
$filename = "{$dir}/{$functionName}.php";
|
||||
fwrite($this->out, "File: {$filename}\n\n");
|
||||
fprintf($this->out, file_get_contents($filename));
|
||||
}
|
||||
private function debugCallback(callable $debugFn, $expression, $data)
|
||||
{
|
||||
fprintf($this->out, "Expression\n==========\n\n%s\n\n", $expression);
|
||||
$this->dumpTokens($expression);
|
||||
$this->dumpAst($expression);
|
||||
fprintf($this->out, "\nData\n====\n\n%s\n\n", json_encode($data, JSON_PRETTY_PRINT));
|
||||
$startTime = microtime(true);
|
||||
$result = $debugFn();
|
||||
$total = microtime(true) - $startTime;
|
||||
fprintf($this->out, "\nResult\n======\n\n%s\n\n", json_encode($result, JSON_PRETTY_PRINT));
|
||||
fwrite($this->out, "Time\n====\n\n");
|
||||
fprintf($this->out, "Total time: %f ms\n\n", $total);
|
||||
return $result;
|
||||
}
|
||||
}
|
84
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Env.php
vendored
Normal file
84
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Env.php
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Provides a simple environment based search.
|
||||
*
|
||||
* The runtime utilized by the Env class can be customized via environment
|
||||
* variables. If the JP_PHP_COMPILE environment variable is specified, then the
|
||||
* CompilerRuntime will be utilized. If set to "on", JMESPath expressions will
|
||||
* be cached to the system's temp directory. Set the environment variable to
|
||||
* a string to cache expressions to a specific directory.
|
||||
*/
|
||||
final class Env
|
||||
{
|
||||
const COMPILE_DIR = 'JP_PHP_COMPILE';
|
||||
/**
|
||||
* Returns data from the input array that matches a JMESPath expression.
|
||||
*
|
||||
* @param string $expression JMESPath expression to evaluate
|
||||
* @param mixed $data JSON-like data to search
|
||||
*
|
||||
* @return mixed Returns the matching data or null
|
||||
*/
|
||||
public static function search($expression, $data)
|
||||
{
|
||||
static $runtime;
|
||||
if (!$runtime) {
|
||||
$runtime = \UglyRobot\Infinite_Uploads\JmesPath\Env::createRuntime();
|
||||
}
|
||||
return $runtime($expression, $data);
|
||||
}
|
||||
/**
|
||||
* Creates a JMESPath runtime based on environment variables and extensions
|
||||
* available on a system.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public static function createRuntime()
|
||||
{
|
||||
switch ($compileDir = self::getEnvVariable(self::COMPILE_DIR)) {
|
||||
case false:
|
||||
return new \UglyRobot\Infinite_Uploads\JmesPath\AstRuntime();
|
||||
case 'on':
|
||||
return new \UglyRobot\Infinite_Uploads\JmesPath\CompilerRuntime();
|
||||
default:
|
||||
return new \UglyRobot\Infinite_Uploads\JmesPath\CompilerRuntime($compileDir);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Delete all previously compiled JMESPath files from the JP_COMPILE_DIR
|
||||
* directory or sys_get_temp_dir().
|
||||
*
|
||||
* @return int Returns the number of deleted files.
|
||||
*/
|
||||
public static function cleanCompileDir()
|
||||
{
|
||||
$total = 0;
|
||||
$compileDir = self::getEnvVariable(self::COMPILE_DIR) ?: sys_get_temp_dir();
|
||||
foreach (glob("{$compileDir}/jmespath_*.php") as $file) {
|
||||
$total++;
|
||||
unlink($file);
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
/**
|
||||
* Reads an environment variable from $_SERVER, $_ENV or via getenv().
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private static function getEnvVariable($name)
|
||||
{
|
||||
if (array_key_exists($name, $_SERVER)) {
|
||||
return $_SERVER[$name];
|
||||
}
|
||||
if (array_key_exists($name, $_ENV)) {
|
||||
return $_ENV[$name];
|
||||
}
|
||||
$value = getenv($name);
|
||||
return $value === false ? null : $value;
|
||||
}
|
||||
}
|
341
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/FnDispatcher.php
vendored
Normal file
341
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/FnDispatcher.php
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Dispatches to named JMESPath functions using a single function that has the
|
||||
* following signature:
|
||||
*
|
||||
* mixed $result = fn(string $function_name, array $args)
|
||||
*/
|
||||
class FnDispatcher
|
||||
{
|
||||
/**
|
||||
* Gets a cached instance of the default function implementations.
|
||||
*
|
||||
* @return FnDispatcher
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
static $instance = null;
|
||||
if (!$instance) {
|
||||
$instance = new self();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
/**
|
||||
* @param string $fn Function name.
|
||||
* @param array $args Function arguments.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke($fn, array $args)
|
||||
{
|
||||
return $this->{'fn_' . $fn}($args);
|
||||
}
|
||||
private function fn_abs(array $args)
|
||||
{
|
||||
$this->validate('abs', $args, [['number']]);
|
||||
return abs($args[0]);
|
||||
}
|
||||
private function fn_avg(array $args)
|
||||
{
|
||||
$this->validate('avg', $args, [['array']]);
|
||||
$sum = $this->reduce('avg:0', $args[0], ['number'], function ($a, $b) {
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::add($a, $b);
|
||||
});
|
||||
return $args[0] ? $sum / count($args[0]) : null;
|
||||
}
|
||||
private function fn_ceil(array $args)
|
||||
{
|
||||
$this->validate('ceil', $args, [['number']]);
|
||||
return ceil($args[0]);
|
||||
}
|
||||
private function fn_contains(array $args)
|
||||
{
|
||||
$this->validate('contains', $args, [['string', 'array'], ['any']]);
|
||||
if (is_array($args[0])) {
|
||||
return in_array($args[1], $args[0]);
|
||||
} elseif (is_string($args[1])) {
|
||||
return mb_strpos($args[0], $args[1], 0, 'UTF-8') !== false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private function fn_ends_with(array $args)
|
||||
{
|
||||
$this->validate('ends_with', $args, [['string'], ['string']]);
|
||||
list($search, $suffix) = $args;
|
||||
return $suffix === '' || mb_substr($search, -mb_strlen($suffix, 'UTF-8'), null, 'UTF-8') === $suffix;
|
||||
}
|
||||
private function fn_floor(array $args)
|
||||
{
|
||||
$this->validate('floor', $args, [['number']]);
|
||||
return floor($args[0]);
|
||||
}
|
||||
private function fn_not_null(array $args)
|
||||
{
|
||||
if (!$args) {
|
||||
throw new \RuntimeException("not_null() expects 1 or more arguments, 0 were provided");
|
||||
}
|
||||
return array_reduce($args, function ($carry, $item) {
|
||||
return $carry !== null ? $carry : $item;
|
||||
});
|
||||
}
|
||||
private function fn_join(array $args)
|
||||
{
|
||||
$this->validate('join', $args, [['string'], ['array']]);
|
||||
$fn = function ($a, $b, $i) use($args) {
|
||||
return $i ? $a . $args[0] . $b : $b;
|
||||
};
|
||||
return $this->reduce('join:0', $args[1], ['string'], $fn);
|
||||
}
|
||||
private function fn_keys(array $args)
|
||||
{
|
||||
$this->validate('keys', $args, [['object']]);
|
||||
return array_keys((array) $args[0]);
|
||||
}
|
||||
private function fn_length(array $args)
|
||||
{
|
||||
$this->validate('length', $args, [['string', 'array', 'object']]);
|
||||
return is_string($args[0]) ? mb_strlen($args[0], 'UTF-8') : count((array) $args[0]);
|
||||
}
|
||||
private function fn_max(array $args)
|
||||
{
|
||||
$this->validate('max', $args, [['array']]);
|
||||
$fn = function ($a, $b) {
|
||||
return $a >= $b ? $a : $b;
|
||||
};
|
||||
return $this->reduce('max:0', $args[0], ['number', 'string'], $fn);
|
||||
}
|
||||
private function fn_max_by(array $args)
|
||||
{
|
||||
$this->validate('max_by', $args, [['array'], ['expression']]);
|
||||
$expr = $this->wrapExpression('max_by:1', $args[1], ['number', 'string']);
|
||||
$fn = function ($carry, $item, $index) use($expr) {
|
||||
return $index ? $expr($carry) >= $expr($item) ? $carry : $item : $item;
|
||||
};
|
||||
return $this->reduce('max_by:1', $args[0], ['any'], $fn);
|
||||
}
|
||||
private function fn_min(array $args)
|
||||
{
|
||||
$this->validate('min', $args, [['array']]);
|
||||
$fn = function ($a, $b, $i) {
|
||||
return $i && $a <= $b ? $a : $b;
|
||||
};
|
||||
return $this->reduce('min:0', $args[0], ['number', 'string'], $fn);
|
||||
}
|
||||
private function fn_min_by(array $args)
|
||||
{
|
||||
$this->validate('min_by', $args, [['array'], ['expression']]);
|
||||
$expr = $this->wrapExpression('min_by:1', $args[1], ['number', 'string']);
|
||||
$i = -1;
|
||||
$fn = function ($a, $b) use($expr, &$i) {
|
||||
return ++$i ? $expr($a) <= $expr($b) ? $a : $b : $b;
|
||||
};
|
||||
return $this->reduce('min_by:1', $args[0], ['any'], $fn);
|
||||
}
|
||||
private function fn_reverse(array $args)
|
||||
{
|
||||
$this->validate('reverse', $args, [['array', 'string']]);
|
||||
if (is_array($args[0])) {
|
||||
return array_reverse($args[0]);
|
||||
} elseif (is_string($args[0])) {
|
||||
return strrev($args[0]);
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot reverse provided argument');
|
||||
}
|
||||
}
|
||||
private function fn_sum(array $args)
|
||||
{
|
||||
$this->validate('sum', $args, [['array']]);
|
||||
$fn = function ($a, $b) {
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::add($a, $b);
|
||||
};
|
||||
return $this->reduce('sum:0', $args[0], ['number'], $fn);
|
||||
}
|
||||
private function fn_sort(array $args)
|
||||
{
|
||||
$this->validate('sort', $args, [['array']]);
|
||||
$valid = ['string', 'number'];
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::stableSort($args[0], function ($a, $b) use($valid) {
|
||||
$this->validateSeq('sort:0', $valid, $a, $b);
|
||||
return strnatcmp($a, $b);
|
||||
});
|
||||
}
|
||||
private function fn_sort_by(array $args)
|
||||
{
|
||||
$this->validate('sort_by', $args, [['array'], ['expression']]);
|
||||
$expr = $args[1];
|
||||
$valid = ['string', 'number'];
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::stableSort($args[0], function ($a, $b) use($expr, $valid) {
|
||||
$va = $expr($a);
|
||||
$vb = $expr($b);
|
||||
$this->validateSeq('sort_by:0', $valid, $va, $vb);
|
||||
return strnatcmp($va, $vb);
|
||||
});
|
||||
}
|
||||
private function fn_starts_with(array $args)
|
||||
{
|
||||
$this->validate('starts_with', $args, [['string'], ['string']]);
|
||||
list($search, $prefix) = $args;
|
||||
return $prefix === '' || mb_strpos($search, $prefix, 0, 'UTF-8') === 0;
|
||||
}
|
||||
private function fn_type(array $args)
|
||||
{
|
||||
$this->validateArity('type', count($args), 1);
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::type($args[0]);
|
||||
}
|
||||
private function fn_to_string(array $args)
|
||||
{
|
||||
$this->validateArity('to_string', count($args), 1);
|
||||
$v = $args[0];
|
||||
if (is_string($v)) {
|
||||
return $v;
|
||||
} elseif (is_object($v) && !$v instanceof \JsonSerializable && method_exists($v, '__toString')) {
|
||||
return (string) $v;
|
||||
}
|
||||
return json_encode($v);
|
||||
}
|
||||
private function fn_to_number(array $args)
|
||||
{
|
||||
$this->validateArity('to_number', count($args), 1);
|
||||
$value = $args[0];
|
||||
$type = \UglyRobot\Infinite_Uploads\JmesPath\Utils::type($value);
|
||||
if ($type == 'number') {
|
||||
return $value;
|
||||
} elseif ($type == 'string' && is_numeric($value)) {
|
||||
return mb_strpos($value, '.', 0, 'UTF-8') ? (double) $value : (int) $value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private function fn_values(array $args)
|
||||
{
|
||||
$this->validate('values', $args, [['array', 'object']]);
|
||||
return array_values((array) $args[0]);
|
||||
}
|
||||
private function fn_merge(array $args)
|
||||
{
|
||||
if (!$args) {
|
||||
throw new \RuntimeException("merge() expects 1 or more arguments, 0 were provided");
|
||||
}
|
||||
return call_user_func_array('array_replace', $args);
|
||||
}
|
||||
private function fn_to_array(array $args)
|
||||
{
|
||||
$this->validate('to_array', $args, [['any']]);
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::isArray($args[0]) ? $args[0] : [$args[0]];
|
||||
}
|
||||
private function fn_map(array $args)
|
||||
{
|
||||
$this->validate('map', $args, [['expression'], ['any']]);
|
||||
$result = [];
|
||||
foreach ($args[1] as $a) {
|
||||
$result[] = $args[0]($a);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private function typeError($from, $msg)
|
||||
{
|
||||
if (mb_strpos($from, ':', 0, 'UTF-8')) {
|
||||
list($fn, $pos) = explode(':', $from);
|
||||
throw new \RuntimeException(sprintf('Argument %d of %s %s', $pos, $fn, $msg));
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Type error: %s %s', $from, $msg));
|
||||
}
|
||||
}
|
||||
private function validateArity($from, $given, $expected)
|
||||
{
|
||||
if ($given != $expected) {
|
||||
$err = "%s() expects {$expected} arguments, {$given} were provided";
|
||||
throw new \RuntimeException(sprintf($err, $from));
|
||||
}
|
||||
}
|
||||
private function validate($from, $args, $types = [])
|
||||
{
|
||||
$this->validateArity($from, count($args), count($types));
|
||||
foreach ($args as $index => $value) {
|
||||
if (!isset($types[$index]) || !$types[$index]) {
|
||||
continue;
|
||||
}
|
||||
$this->validateType("{$from}:{$index}", $value, $types[$index]);
|
||||
}
|
||||
}
|
||||
private function validateType($from, $value, array $types)
|
||||
{
|
||||
if ($types[0] == 'any' || in_array(\UglyRobot\Infinite_Uploads\JmesPath\Utils::type($value), $types) || $value === [] && in_array('object', $types)) {
|
||||
return;
|
||||
}
|
||||
$msg = 'must be one of the following types: ' . implode(', ', $types) . '. ' . \UglyRobot\Infinite_Uploads\JmesPath\Utils::type($value) . ' found';
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
/**
|
||||
* Validates value A and B, ensures they both are correctly typed, and of
|
||||
* the same type.
|
||||
*
|
||||
* @param string $from String of function:argument_position
|
||||
* @param array $types Array of valid value types.
|
||||
* @param mixed $a Value A
|
||||
* @param mixed $b Value B
|
||||
*/
|
||||
private function validateSeq($from, array $types, $a, $b)
|
||||
{
|
||||
$ta = \UglyRobot\Infinite_Uploads\JmesPath\Utils::type($a);
|
||||
$tb = \UglyRobot\Infinite_Uploads\JmesPath\Utils::type($b);
|
||||
if ($ta !== $tb) {
|
||||
$msg = "encountered a type mismatch in sequence: {$ta}, {$tb}";
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
$typeMatch = $types && $types[0] == 'any' || in_array($ta, $types);
|
||||
if (!$typeMatch) {
|
||||
$msg = 'encountered a type error in sequence. The argument must be ' . 'an array of ' . implode('|', $types) . ' types. ' . "Found {$ta}, {$tb}.";
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reduces and validates an array of values to a single value using a fn.
|
||||
*
|
||||
* @param string $from String of function:argument_position
|
||||
* @param array $values Values to reduce.
|
||||
* @param array $types Array of valid value types.
|
||||
* @param callable $reduce Reduce function that accepts ($carry, $item).
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function reduce($from, array $values, array $types, callable $reduce)
|
||||
{
|
||||
$i = -1;
|
||||
return array_reduce($values, function ($carry, $item) use($from, $types, $reduce, &$i) {
|
||||
if (++$i > 0) {
|
||||
$this->validateSeq($from, $types, $carry, $item);
|
||||
}
|
||||
return $reduce($carry, $item, $i);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Validates the return values of expressions as they are applied.
|
||||
*
|
||||
* @param string $from Function name : position
|
||||
* @param callable $expr Expression function to validate.
|
||||
* @param array $types Array of acceptable return type values.
|
||||
*
|
||||
* @return callable Returns a wrapped function
|
||||
*/
|
||||
private function wrapExpression($from, callable $expr, array $types)
|
||||
{
|
||||
list($fn, $pos) = explode(':', $from);
|
||||
$from = "The expression return value of argument {$pos} of {$fn}";
|
||||
return function ($value) use($from, $expr, $types) {
|
||||
$value = $expr($value);
|
||||
$this->validateType($from, $value, $types);
|
||||
return $value;
|
||||
};
|
||||
}
|
||||
/** @internal Pass function name validation off to runtime */
|
||||
public function __call($name, $args)
|
||||
{
|
||||
$name = str_replace('fn_', '', $name);
|
||||
throw new \RuntimeException("Call to undefined function {$name}");
|
||||
}
|
||||
}
|
18
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/JmesPath.php
vendored
Normal file
18
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/JmesPath.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Returns data from the input array that matches a JMESPath expression.
|
||||
*
|
||||
* @param string $expression Expression to search.
|
||||
* @param mixed $data Data to search.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
if (!function_exists(__NAMESPACE__ . '\\search')) {
|
||||
function search($expression, $data)
|
||||
{
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Env::search($expression, $data);
|
||||
}
|
||||
}
|
235
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Lexer.php
vendored
Normal file
235
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Lexer.php
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Tokenizes JMESPath expressions
|
||||
*/
|
||||
class Lexer
|
||||
{
|
||||
const T_DOT = 'dot';
|
||||
const T_STAR = 'star';
|
||||
const T_COMMA = 'comma';
|
||||
const T_COLON = 'colon';
|
||||
const T_CURRENT = 'current';
|
||||
const T_EXPREF = 'expref';
|
||||
const T_LPAREN = 'lparen';
|
||||
const T_RPAREN = 'rparen';
|
||||
const T_LBRACE = 'lbrace';
|
||||
const T_RBRACE = 'rbrace';
|
||||
const T_LBRACKET = 'lbracket';
|
||||
const T_RBRACKET = 'rbracket';
|
||||
const T_FLATTEN = 'flatten';
|
||||
const T_IDENTIFIER = 'identifier';
|
||||
const T_NUMBER = 'number';
|
||||
const T_QUOTED_IDENTIFIER = 'quoted_identifier';
|
||||
const T_UNKNOWN = 'unknown';
|
||||
const T_PIPE = 'pipe';
|
||||
const T_OR = 'or';
|
||||
const T_AND = 'and';
|
||||
const T_NOT = 'not';
|
||||
const T_FILTER = 'filter';
|
||||
const T_LITERAL = 'literal';
|
||||
const T_EOF = 'eof';
|
||||
const T_COMPARATOR = 'comparator';
|
||||
const STATE_IDENTIFIER = 0;
|
||||
const STATE_NUMBER = 1;
|
||||
const STATE_SINGLE_CHAR = 2;
|
||||
const STATE_WHITESPACE = 3;
|
||||
const STATE_STRING_LITERAL = 4;
|
||||
const STATE_QUOTED_STRING = 5;
|
||||
const STATE_JSON_LITERAL = 6;
|
||||
const STATE_LBRACKET = 7;
|
||||
const STATE_PIPE = 8;
|
||||
const STATE_LT = 9;
|
||||
const STATE_GT = 10;
|
||||
const STATE_EQ = 11;
|
||||
const STATE_NOT = 12;
|
||||
const STATE_AND = 13;
|
||||
/** @var array We know what token we are consuming based on each char */
|
||||
private static $transitionTable = ['<' => self::STATE_LT, '>' => self::STATE_GT, '=' => self::STATE_EQ, '!' => self::STATE_NOT, '[' => self::STATE_LBRACKET, '|' => self::STATE_PIPE, '&' => self::STATE_AND, '`' => self::STATE_JSON_LITERAL, '"' => self::STATE_QUOTED_STRING, "'" => self::STATE_STRING_LITERAL, '-' => self::STATE_NUMBER, '0' => self::STATE_NUMBER, '1' => self::STATE_NUMBER, '2' => self::STATE_NUMBER, '3' => self::STATE_NUMBER, '4' => self::STATE_NUMBER, '5' => self::STATE_NUMBER, '6' => self::STATE_NUMBER, '7' => self::STATE_NUMBER, '8' => self::STATE_NUMBER, '9' => self::STATE_NUMBER, ' ' => self::STATE_WHITESPACE, "\t" => self::STATE_WHITESPACE, "\n" => self::STATE_WHITESPACE, "\r" => self::STATE_WHITESPACE, '.' => self::STATE_SINGLE_CHAR, '*' => self::STATE_SINGLE_CHAR, ']' => self::STATE_SINGLE_CHAR, ',' => self::STATE_SINGLE_CHAR, ':' => self::STATE_SINGLE_CHAR, '@' => self::STATE_SINGLE_CHAR, '(' => self::STATE_SINGLE_CHAR, ')' => self::STATE_SINGLE_CHAR, '{' => self::STATE_SINGLE_CHAR, '}' => self::STATE_SINGLE_CHAR, '_' => self::STATE_IDENTIFIER, 'A' => self::STATE_IDENTIFIER, 'B' => self::STATE_IDENTIFIER, 'C' => self::STATE_IDENTIFIER, 'D' => self::STATE_IDENTIFIER, 'E' => self::STATE_IDENTIFIER, 'F' => self::STATE_IDENTIFIER, 'G' => self::STATE_IDENTIFIER, 'H' => self::STATE_IDENTIFIER, 'I' => self::STATE_IDENTIFIER, 'J' => self::STATE_IDENTIFIER, 'K' => self::STATE_IDENTIFIER, 'L' => self::STATE_IDENTIFIER, 'M' => self::STATE_IDENTIFIER, 'N' => self::STATE_IDENTIFIER, 'O' => self::STATE_IDENTIFIER, 'P' => self::STATE_IDENTIFIER, 'Q' => self::STATE_IDENTIFIER, 'R' => self::STATE_IDENTIFIER, 'S' => self::STATE_IDENTIFIER, 'T' => self::STATE_IDENTIFIER, 'U' => self::STATE_IDENTIFIER, 'V' => self::STATE_IDENTIFIER, 'W' => self::STATE_IDENTIFIER, 'X' => self::STATE_IDENTIFIER, 'Y' => self::STATE_IDENTIFIER, 'Z' => self::STATE_IDENTIFIER, 'a' => self::STATE_IDENTIFIER, 'b' => self::STATE_IDENTIFIER, 'c' => self::STATE_IDENTIFIER, 'd' => self::STATE_IDENTIFIER, 'e' => self::STATE_IDENTIFIER, 'f' => self::STATE_IDENTIFIER, 'g' => self::STATE_IDENTIFIER, 'h' => self::STATE_IDENTIFIER, 'i' => self::STATE_IDENTIFIER, 'j' => self::STATE_IDENTIFIER, 'k' => self::STATE_IDENTIFIER, 'l' => self::STATE_IDENTIFIER, 'm' => self::STATE_IDENTIFIER, 'n' => self::STATE_IDENTIFIER, 'o' => self::STATE_IDENTIFIER, 'p' => self::STATE_IDENTIFIER, 'q' => self::STATE_IDENTIFIER, 'r' => self::STATE_IDENTIFIER, 's' => self::STATE_IDENTIFIER, 't' => self::STATE_IDENTIFIER, 'u' => self::STATE_IDENTIFIER, 'v' => self::STATE_IDENTIFIER, 'w' => self::STATE_IDENTIFIER, 'x' => self::STATE_IDENTIFIER, 'y' => self::STATE_IDENTIFIER, 'z' => self::STATE_IDENTIFIER];
|
||||
/** @var array Valid identifier characters after first character */
|
||||
private $validIdentifier = ['A' => true, 'B' => true, 'C' => true, 'D' => true, 'E' => true, 'F' => true, 'G' => true, 'H' => true, 'I' => true, 'J' => true, 'K' => true, 'L' => true, 'M' => true, 'N' => true, 'O' => true, 'P' => true, 'Q' => true, 'R' => true, 'S' => true, 'T' => true, 'U' => true, 'V' => true, 'W' => true, 'X' => true, 'Y' => true, 'Z' => true, 'a' => true, 'b' => true, 'c' => true, 'd' => true, 'e' => true, 'f' => true, 'g' => true, 'h' => true, 'i' => true, 'j' => true, 'k' => true, 'l' => true, 'm' => true, 'n' => true, 'o' => true, 'p' => true, 'q' => true, 'r' => true, 's' => true, 't' => true, 'u' => true, 'v' => true, 'w' => true, 'x' => true, 'y' => true, 'z' => true, '_' => true, '0' => true, '1' => true, '2' => true, '3' => true, '4' => true, '5' => true, '6' => true, '7' => true, '8' => true, '9' => true];
|
||||
/** @var array Valid number characters after the first character */
|
||||
private $numbers = ['0' => true, '1' => true, '2' => true, '3' => true, '4' => true, '5' => true, '6' => true, '7' => true, '8' => true, '9' => true];
|
||||
/** @var array Map of simple single character tokens */
|
||||
private $simpleTokens = ['.' => self::T_DOT, '*' => self::T_STAR, ']' => self::T_RBRACKET, ',' => self::T_COMMA, ':' => self::T_COLON, '@' => self::T_CURRENT, '(' => self::T_LPAREN, ')' => self::T_RPAREN, '{' => self::T_LBRACE, '}' => self::T_RBRACE];
|
||||
/**
|
||||
* Tokenize the JMESPath expression into an array of tokens hashes that
|
||||
* contain a 'type', 'value', and 'key'.
|
||||
*
|
||||
* @param string $input JMESPath input
|
||||
*
|
||||
* @return array
|
||||
* @throws SyntaxErrorException
|
||||
*/
|
||||
public function tokenize($input)
|
||||
{
|
||||
$tokens = [];
|
||||
if ($input === '') {
|
||||
goto eof;
|
||||
}
|
||||
$chars = str_split($input);
|
||||
while (false !== ($current = current($chars))) {
|
||||
// Every character must be in the transition character table.
|
||||
if (!isset(self::$transitionTable[$current])) {
|
||||
$tokens[] = ['type' => self::T_UNKNOWN, 'pos' => key($chars), 'value' => $current];
|
||||
next($chars);
|
||||
continue;
|
||||
}
|
||||
$state = self::$transitionTable[$current];
|
||||
if ($state === self::STATE_SINGLE_CHAR) {
|
||||
// Consume simple tokens like ".", ",", "@", etc.
|
||||
$tokens[] = ['type' => $this->simpleTokens[$current], 'pos' => key($chars), 'value' => $current];
|
||||
next($chars);
|
||||
} elseif ($state === self::STATE_IDENTIFIER) {
|
||||
// Consume identifiers
|
||||
$start = key($chars);
|
||||
$buffer = '';
|
||||
do {
|
||||
$buffer .= $current;
|
||||
$current = next($chars);
|
||||
} while ($current !== false && isset($this->validIdentifier[$current]));
|
||||
$tokens[] = ['type' => self::T_IDENTIFIER, 'value' => $buffer, 'pos' => $start];
|
||||
} elseif ($state === self::STATE_WHITESPACE) {
|
||||
// Skip whitespace
|
||||
next($chars);
|
||||
} elseif ($state === self::STATE_LBRACKET) {
|
||||
// Consume "[", "[?", and "[]"
|
||||
$position = key($chars);
|
||||
$actual = next($chars);
|
||||
if ($actual === ']') {
|
||||
next($chars);
|
||||
$tokens[] = ['type' => self::T_FLATTEN, 'pos' => $position, 'value' => '[]'];
|
||||
} elseif ($actual === '?') {
|
||||
next($chars);
|
||||
$tokens[] = ['type' => self::T_FILTER, 'pos' => $position, 'value' => '[?'];
|
||||
} else {
|
||||
$tokens[] = ['type' => self::T_LBRACKET, 'pos' => $position, 'value' => '['];
|
||||
}
|
||||
} elseif ($state === self::STATE_STRING_LITERAL) {
|
||||
// Consume raw string literals
|
||||
$t = $this->inside($chars, "'", self::T_LITERAL);
|
||||
$t['value'] = str_replace("\\'", "'", $t['value']);
|
||||
$tokens[] = $t;
|
||||
} elseif ($state === self::STATE_PIPE) {
|
||||
// Consume pipe and OR
|
||||
$tokens[] = $this->matchOr($chars, '|', '|', self::T_OR, self::T_PIPE);
|
||||
} elseif ($state == self::STATE_JSON_LITERAL) {
|
||||
// Consume JSON literals
|
||||
$token = $this->inside($chars, '`', self::T_LITERAL);
|
||||
if ($token['type'] === self::T_LITERAL) {
|
||||
$token['value'] = str_replace('\\`', '`', $token['value']);
|
||||
$token = $this->parseJson($token);
|
||||
}
|
||||
$tokens[] = $token;
|
||||
} elseif ($state == self::STATE_NUMBER) {
|
||||
// Consume numbers
|
||||
$start = key($chars);
|
||||
$buffer = '';
|
||||
do {
|
||||
$buffer .= $current;
|
||||
$current = next($chars);
|
||||
} while ($current !== false && isset($this->numbers[$current]));
|
||||
$tokens[] = ['type' => self::T_NUMBER, 'value' => (int) $buffer, 'pos' => $start];
|
||||
} elseif ($state === self::STATE_QUOTED_STRING) {
|
||||
// Consume quoted identifiers
|
||||
$token = $this->inside($chars, '"', self::T_QUOTED_IDENTIFIER);
|
||||
if ($token['type'] === self::T_QUOTED_IDENTIFIER) {
|
||||
$token['value'] = '"' . $token['value'] . '"';
|
||||
$token = $this->parseJson($token);
|
||||
}
|
||||
$tokens[] = $token;
|
||||
} elseif ($state === self::STATE_EQ) {
|
||||
// Consume equals
|
||||
$tokens[] = $this->matchOr($chars, '=', '=', self::T_COMPARATOR, self::T_UNKNOWN);
|
||||
} elseif ($state == self::STATE_AND) {
|
||||
$tokens[] = $this->matchOr($chars, '&', '&', self::T_AND, self::T_EXPREF);
|
||||
} elseif ($state === self::STATE_NOT) {
|
||||
// Consume not equal
|
||||
$tokens[] = $this->matchOr($chars, '!', '=', self::T_COMPARATOR, self::T_NOT);
|
||||
} else {
|
||||
// either '<' or '>'
|
||||
// Consume less than and greater than
|
||||
$tokens[] = $this->matchOr($chars, $current, '=', self::T_COMPARATOR, self::T_COMPARATOR);
|
||||
}
|
||||
}
|
||||
eof:
|
||||
$tokens[] = ['type' => self::T_EOF, 'pos' => mb_strlen($input, 'UTF-8'), 'value' => null];
|
||||
return $tokens;
|
||||
}
|
||||
/**
|
||||
* Returns a token based on whether or not the next token matches the
|
||||
* expected value. If it does, a token of "$type" is returned. Otherwise,
|
||||
* a token of "$orElse" type is returned.
|
||||
*
|
||||
* @param array $chars Array of characters by reference.
|
||||
* @param string $current The current character.
|
||||
* @param string $expected Expected character.
|
||||
* @param string $type Expected result type.
|
||||
* @param string $orElse Otherwise return a token of this type.
|
||||
*
|
||||
* @return array Returns a conditional token.
|
||||
*/
|
||||
private function matchOr(array &$chars, $current, $expected, $type, $orElse)
|
||||
{
|
||||
if (next($chars) === $expected) {
|
||||
next($chars);
|
||||
return ['type' => $type, 'pos' => key($chars) - 1, 'value' => $current . $expected];
|
||||
}
|
||||
return ['type' => $orElse, 'pos' => key($chars) - 1, 'value' => $current];
|
||||
}
|
||||
/**
|
||||
* Returns a token the is the result of consuming inside of delimiter
|
||||
* characters. Escaped delimiters will be adjusted before returning a
|
||||
* value. If the token is not closed, "unknown" is returned.
|
||||
*
|
||||
* @param array $chars Array of characters by reference.
|
||||
* @param string $delim The delimiter character.
|
||||
* @param string $type Token type.
|
||||
*
|
||||
* @return array Returns the consumed token.
|
||||
*/
|
||||
private function inside(array &$chars, $delim, $type)
|
||||
{
|
||||
$position = key($chars);
|
||||
$current = next($chars);
|
||||
$buffer = '';
|
||||
while ($current !== $delim) {
|
||||
if ($current === '\\') {
|
||||
$buffer .= '\\';
|
||||
$current = next($chars);
|
||||
}
|
||||
if ($current === false) {
|
||||
// Unclosed delimiter
|
||||
return ['type' => self::T_UNKNOWN, 'value' => $buffer, 'pos' => $position];
|
||||
}
|
||||
$buffer .= $current;
|
||||
$current = next($chars);
|
||||
}
|
||||
next($chars);
|
||||
return ['type' => $type, 'value' => $buffer, 'pos' => $position];
|
||||
}
|
||||
/**
|
||||
* Parses a JSON token or sets the token type to "unknown" on error.
|
||||
*
|
||||
* @param array $token Token that needs parsing.
|
||||
*
|
||||
* @return array Returns a token with a parsed value.
|
||||
*/
|
||||
private function parseJson(array $token)
|
||||
{
|
||||
$value = json_decode($token['value'], true);
|
||||
if ($error = json_last_error()) {
|
||||
// Legacy support for elided quotes. Try to parse again by adding
|
||||
// quotes around the bad input value.
|
||||
$value = json_decode('"' . $token['value'] . '"', true);
|
||||
if ($error = json_last_error()) {
|
||||
$token['type'] = self::T_UNKNOWN;
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
$token['value'] = $value;
|
||||
return $token;
|
||||
}
|
||||
}
|
356
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Parser.php
vendored
Normal file
356
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Parser.php
vendored
Normal file
@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
use UglyRobot\Infinite_Uploads\JmesPath\Lexer as T;
|
||||
/**
|
||||
* JMESPath Pratt parser
|
||||
* @link http://hall.org.ua/halls/wizzard/pdf/Vaughan.Pratt.TDOP.pdf
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
/** @var Lexer */
|
||||
private $lexer;
|
||||
private $tokens;
|
||||
private $token;
|
||||
private $tpos;
|
||||
private $expression;
|
||||
private static $nullToken = ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EOF];
|
||||
private static $currentNode = ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_CURRENT];
|
||||
private static $bp = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EOF => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_QUOTED_IDENTIFIER => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_IDENTIFIER => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RPAREN => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMMA => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACE => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_CURRENT => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EXPREF => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON => 0, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_PIPE => 1, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_OR => 2, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_AND => 3, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMPARATOR => 5, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FLATTEN => 9, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR => 20, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FILTER => 21, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_DOT => 40, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NOT => 45, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACE => 50, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACKET => 55, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LPAREN => 60];
|
||||
/** @var array Acceptable tokens after a dot token */
|
||||
private static $afterDot = [
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_IDENTIFIER => true,
|
||||
// foo.bar
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_QUOTED_IDENTIFIER => true,
|
||||
// foo."bar"
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR => true,
|
||||
// foo.*
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACE => true,
|
||||
// foo[1]
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACKET => true,
|
||||
// foo{a: 0}
|
||||
\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FILTER => true,
|
||||
];
|
||||
/**
|
||||
* @param Lexer|null $lexer Lexer used to tokenize expressions
|
||||
*/
|
||||
public function __construct(\UglyRobot\Infinite_Uploads\JmesPath\Lexer $lexer = null)
|
||||
{
|
||||
$this->lexer = $lexer ?: new \UglyRobot\Infinite_Uploads\JmesPath\Lexer();
|
||||
}
|
||||
/**
|
||||
* Parses a JMESPath expression into an AST
|
||||
*
|
||||
* @param string $expression JMESPath expression to compile
|
||||
*
|
||||
* @return array Returns an array based AST
|
||||
* @throws SyntaxErrorException
|
||||
*/
|
||||
public function parse($expression)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->tokens = $this->lexer->tokenize($expression);
|
||||
$this->tpos = -1;
|
||||
$this->next();
|
||||
$result = $this->expr();
|
||||
if ($this->token['type'] === \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EOF) {
|
||||
return $result;
|
||||
}
|
||||
throw $this->syntax('Did not reach the end of the token stream');
|
||||
}
|
||||
/**
|
||||
* Parses an expression while rbp < lbp.
|
||||
*
|
||||
* @param int $rbp Right bound precedence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function expr($rbp = 0)
|
||||
{
|
||||
$left = $this->{"nud_{$this->token['type']}"}();
|
||||
while ($rbp < self::$bp[$this->token['type']]) {
|
||||
$left = $this->{"led_{$this->token['type']}"}($left);
|
||||
}
|
||||
return $left;
|
||||
}
|
||||
private function nud_identifier()
|
||||
{
|
||||
$token = $this->token;
|
||||
$this->next();
|
||||
return ['type' => 'field', 'value' => $token['value']];
|
||||
}
|
||||
private function nud_quoted_identifier()
|
||||
{
|
||||
$token = $this->token;
|
||||
$this->next();
|
||||
$this->assertNotToken(\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LPAREN);
|
||||
return ['type' => 'field', 'value' => $token['value']];
|
||||
}
|
||||
private function nud_current()
|
||||
{
|
||||
$this->next();
|
||||
return self::$currentNode;
|
||||
}
|
||||
private function nud_literal()
|
||||
{
|
||||
$token = $this->token;
|
||||
$this->next();
|
||||
return ['type' => 'literal', 'value' => $token['value']];
|
||||
}
|
||||
private function nud_expref()
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EXPREF, 'children' => [$this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EXPREF])]];
|
||||
}
|
||||
private function nud_not()
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NOT, 'children' => [$this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NOT])]];
|
||||
}
|
||||
private function nud_lparen()
|
||||
{
|
||||
$this->next();
|
||||
$result = $this->expr(0);
|
||||
if ($this->token['type'] !== \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RPAREN) {
|
||||
throw $this->syntax('Unclosed `(`');
|
||||
}
|
||||
$this->next();
|
||||
return $result;
|
||||
}
|
||||
private function nud_lbrace()
|
||||
{
|
||||
static $validKeys = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_QUOTED_IDENTIFIER => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_IDENTIFIER => true];
|
||||
$this->next($validKeys);
|
||||
$pairs = [];
|
||||
do {
|
||||
$pairs[] = $this->parseKeyValuePair();
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMMA) {
|
||||
$this->next($validKeys);
|
||||
}
|
||||
} while ($this->token['type'] !== \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACE);
|
||||
$this->next();
|
||||
return ['type' => 'multi_select_hash', 'children' => $pairs];
|
||||
}
|
||||
private function nud_flatten()
|
||||
{
|
||||
return $this->led_flatten(self::$currentNode);
|
||||
}
|
||||
private function nud_filter()
|
||||
{
|
||||
return $this->led_filter(self::$currentNode);
|
||||
}
|
||||
private function nud_star()
|
||||
{
|
||||
return $this->parseWildcardObject(self::$currentNode);
|
||||
}
|
||||
private function nud_lbracket()
|
||||
{
|
||||
$this->next();
|
||||
$type = $this->token['type'];
|
||||
if ($type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER || $type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON) {
|
||||
return $this->parseArrayIndexExpression();
|
||||
} elseif ($type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR && $this->lookahead() == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET) {
|
||||
return $this->parseWildcardArray();
|
||||
} else {
|
||||
return $this->parseMultiSelectList();
|
||||
}
|
||||
}
|
||||
private function led_lbracket(array $left)
|
||||
{
|
||||
static $nextTypes = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR => true];
|
||||
$this->next($nextTypes);
|
||||
switch ($this->token['type']) {
|
||||
case \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER:
|
||||
case \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON:
|
||||
return ['type' => 'subexpression', 'children' => [$left, $this->parseArrayIndexExpression()]];
|
||||
default:
|
||||
return $this->parseWildcardArray($left);
|
||||
}
|
||||
}
|
||||
private function led_flatten(array $left)
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => 'projection', 'from' => 'array', 'children' => [['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FLATTEN, 'children' => [$left]], $this->parseProjection(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FLATTEN])]];
|
||||
}
|
||||
private function led_dot(array $left)
|
||||
{
|
||||
$this->next(self::$afterDot);
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR) {
|
||||
return $this->parseWildcardObject($left);
|
||||
}
|
||||
return ['type' => 'subexpression', 'children' => [$left, $this->parseDot(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_DOT])]];
|
||||
}
|
||||
private function led_or(array $left)
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_OR, 'children' => [$left, $this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_OR])]];
|
||||
}
|
||||
private function led_and(array $left)
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_AND, 'children' => [$left, $this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_AND])]];
|
||||
}
|
||||
private function led_pipe(array $left)
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_PIPE, 'children' => [$left, $this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_PIPE])]];
|
||||
}
|
||||
private function led_lparen(array $left)
|
||||
{
|
||||
$args = [];
|
||||
$this->next();
|
||||
while ($this->token['type'] != \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RPAREN) {
|
||||
$args[] = $this->expr(0);
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMMA) {
|
||||
$this->next();
|
||||
}
|
||||
}
|
||||
$this->next();
|
||||
return ['type' => 'function', 'value' => $left['value'], 'children' => $args];
|
||||
}
|
||||
private function led_filter(array $left)
|
||||
{
|
||||
$this->next();
|
||||
$expression = $this->expr();
|
||||
if ($this->token['type'] != \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET) {
|
||||
throw $this->syntax('Expected a closing rbracket for the filter');
|
||||
}
|
||||
$this->next();
|
||||
$rhs = $this->parseProjection(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FILTER]);
|
||||
return ['type' => 'projection', 'from' => 'array', 'children' => [$left ?: self::$currentNode, ['type' => 'condition', 'children' => [$expression, $rhs]]]];
|
||||
}
|
||||
private function led_comparator(array $left)
|
||||
{
|
||||
$token = $this->token;
|
||||
$this->next();
|
||||
return ['type' => \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMPARATOR, 'value' => $token['value'], 'children' => [$left, $this->expr(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMPARATOR])]];
|
||||
}
|
||||
private function parseProjection($bp)
|
||||
{
|
||||
$type = $this->token['type'];
|
||||
if (self::$bp[$type] < 10) {
|
||||
return self::$currentNode;
|
||||
} elseif ($type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_DOT) {
|
||||
$this->next(self::$afterDot);
|
||||
return $this->parseDot($bp);
|
||||
} elseif ($type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACKET || $type == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_FILTER) {
|
||||
return $this->expr($bp);
|
||||
}
|
||||
throw $this->syntax('Syntax error after projection');
|
||||
}
|
||||
private function parseDot($bp)
|
||||
{
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_LBRACKET) {
|
||||
$this->next();
|
||||
return $this->parseMultiSelectList();
|
||||
}
|
||||
return $this->expr($bp);
|
||||
}
|
||||
private function parseKeyValuePair()
|
||||
{
|
||||
static $validColon = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON => true];
|
||||
$key = $this->token['value'];
|
||||
$this->next($validColon);
|
||||
$this->next();
|
||||
return ['type' => 'key_val_pair', 'value' => $key, 'children' => [$this->expr()]];
|
||||
}
|
||||
private function parseWildcardObject(array $left = null)
|
||||
{
|
||||
$this->next();
|
||||
return ['type' => 'projection', 'from' => 'object', 'children' => [$left ?: self::$currentNode, $this->parseProjection(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR])]];
|
||||
}
|
||||
private function parseWildcardArray(array $left = null)
|
||||
{
|
||||
static $getRbracket = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET => true];
|
||||
$this->next($getRbracket);
|
||||
$this->next();
|
||||
return ['type' => 'projection', 'from' => 'array', 'children' => [$left ?: self::$currentNode, $this->parseProjection(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR])]];
|
||||
}
|
||||
/**
|
||||
* Parses an array index expression (e.g., [0], [1:2:3]
|
||||
*/
|
||||
private function parseArrayIndexExpression()
|
||||
{
|
||||
static $matchNext = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET => true];
|
||||
$pos = 0;
|
||||
$parts = [null, null, null];
|
||||
$expected = $matchNext;
|
||||
do {
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON) {
|
||||
$pos++;
|
||||
$expected = $matchNext;
|
||||
} elseif ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_NUMBER) {
|
||||
$parts[$pos] = $this->token['value'];
|
||||
$expected = [\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COLON => true, \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET => true];
|
||||
}
|
||||
$this->next($expected);
|
||||
} while ($this->token['type'] != \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET);
|
||||
// Consume the closing bracket
|
||||
$this->next();
|
||||
if ($pos === 0) {
|
||||
// No colons were found so this is a simple index extraction
|
||||
return ['type' => 'index', 'value' => $parts[0]];
|
||||
}
|
||||
if ($pos > 2) {
|
||||
throw $this->syntax('Invalid array slice syntax: too many colons');
|
||||
}
|
||||
// Sliced array from start (e.g., [2:])
|
||||
return ['type' => 'projection', 'from' => 'array', 'children' => [['type' => 'slice', 'value' => $parts], $this->parseProjection(self::$bp[\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_STAR])]];
|
||||
}
|
||||
private function parseMultiSelectList()
|
||||
{
|
||||
$nodes = [];
|
||||
do {
|
||||
$nodes[] = $this->expr();
|
||||
if ($this->token['type'] == \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_COMMA) {
|
||||
$this->next();
|
||||
$this->assertNotToken(\UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET);
|
||||
}
|
||||
} while ($this->token['type'] !== \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_RBRACKET);
|
||||
$this->next();
|
||||
return ['type' => 'multi_select_list', 'children' => $nodes];
|
||||
}
|
||||
private function syntax($msg)
|
||||
{
|
||||
return new \UglyRobot\Infinite_Uploads\JmesPath\SyntaxErrorException($msg, $this->token, $this->expression);
|
||||
}
|
||||
private function lookahead()
|
||||
{
|
||||
return !isset($this->tokens[$this->tpos + 1]) ? \UglyRobot\Infinite_Uploads\JmesPath\Lexer::T_EOF : $this->tokens[$this->tpos + 1]['type'];
|
||||
}
|
||||
private function next(array $match = null)
|
||||
{
|
||||
if (!isset($this->tokens[$this->tpos + 1])) {
|
||||
$this->token = self::$nullToken;
|
||||
} else {
|
||||
$this->token = $this->tokens[++$this->tpos];
|
||||
}
|
||||
if ($match && !isset($match[$this->token['type']])) {
|
||||
throw $this->syntax($match);
|
||||
}
|
||||
}
|
||||
private function assertNotToken($type)
|
||||
{
|
||||
if ($this->token['type'] == $type) {
|
||||
throw $this->syntax("Token {$this->tpos} not allowed to be {$type}");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal Handles undefined tokens without paying the cost of validation
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$prefix = substr($method, 0, 4);
|
||||
if ($prefix == 'nud_' || $prefix == 'led_') {
|
||||
$token = substr($method, 4);
|
||||
$message = "Unexpected \"{$token}\" token ({$method}). Expected one of" . " the following tokens: " . implode(', ', array_map(function ($i) {
|
||||
return '"' . substr($i, 4) . '"';
|
||||
}, array_filter(get_class_methods($this), function ($i) use($prefix) {
|
||||
return strpos($i, $prefix) === 0;
|
||||
})));
|
||||
throw $this->syntax($message);
|
||||
}
|
||||
throw new \BadMethodCallException("Call to undefined method {$method}");
|
||||
}
|
||||
}
|
25
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/SyntaxErrorException.php
vendored
Normal file
25
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/SyntaxErrorException.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Syntax errors raise this exception that gives context
|
||||
*/
|
||||
class SyntaxErrorException extends \InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* @param string $expectedTypesOrMessage Expected array of tokens or message
|
||||
* @param array $token Current token
|
||||
* @param string $expression Expression input
|
||||
*/
|
||||
public function __construct($expectedTypesOrMessage, array $token, $expression)
|
||||
{
|
||||
$message = "Syntax error at character {$token['pos']}\n" . $expression . "\n" . str_repeat(' ', $token['pos']) . "^\n";
|
||||
$message .= !is_array($expectedTypesOrMessage) ? $expectedTypesOrMessage : $this->createTokenMessage($token, $expectedTypesOrMessage);
|
||||
parent::__construct($message);
|
||||
}
|
||||
private function createTokenMessage(array $token, array $valid)
|
||||
{
|
||||
return sprintf('Expected one of the following: %s; found %s "%s"', implode(', ', array_keys($valid)), $token['type'], $token['value']);
|
||||
}
|
||||
}
|
225
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/TreeCompiler.php
vendored
Normal file
225
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/TreeCompiler.php
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Tree visitor used to compile JMESPath expressions into native PHP code.
|
||||
*/
|
||||
class TreeCompiler
|
||||
{
|
||||
private $indentation;
|
||||
private $source;
|
||||
private $vars;
|
||||
/**
|
||||
* @param array $ast AST to compile.
|
||||
* @param string $fnName The name of the function to generate.
|
||||
* @param string $expr Expression being compiled.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function visit(array $ast, $fnName, $expr)
|
||||
{
|
||||
$this->vars = [];
|
||||
$this->source = $this->indentation = '';
|
||||
$this->write("<?php\n")->write('use JmesPath\\TreeInterpreter as Ti;')->write('use JmesPath\\FnDispatcher as Fd;')->write('use JmesPath\\Utils;')->write('')->write('function %s(Ti $interpreter, $value) {', $fnName)->indent()->dispatch($ast)->write('')->write('return $value;')->outdent()->write('}');
|
||||
return $this->source;
|
||||
}
|
||||
/**
|
||||
* @param array $node
|
||||
* @return mixed
|
||||
*/
|
||||
private function dispatch(array $node)
|
||||
{
|
||||
return $this->{"visit_{$node['type']}"}($node);
|
||||
}
|
||||
/**
|
||||
* Creates a monotonically incrementing unique variable name by prefix.
|
||||
*
|
||||
* @param string $prefix Variable name prefix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function makeVar($prefix)
|
||||
{
|
||||
if (!isset($this->vars[$prefix])) {
|
||||
$this->vars[$prefix] = 0;
|
||||
return '$' . $prefix;
|
||||
}
|
||||
return '$' . $prefix . ++$this->vars[$prefix];
|
||||
}
|
||||
/**
|
||||
* Writes the given line of source code. Pass positional arguments to write
|
||||
* that match the format of sprintf.
|
||||
*
|
||||
* @param string $str String to write
|
||||
* @return $this
|
||||
*/
|
||||
private function write($str)
|
||||
{
|
||||
$this->source .= $this->indentation;
|
||||
if (func_num_args() == 1) {
|
||||
$this->source .= $str . "\n";
|
||||
return $this;
|
||||
}
|
||||
$this->source .= vsprintf($str, array_slice(func_get_args(), 1)) . "\n";
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Decreases the indentation level of code being written
|
||||
* @return $this
|
||||
*/
|
||||
private function outdent()
|
||||
{
|
||||
$this->indentation = substr($this->indentation, 0, -4);
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Increases the indentation level of code being written
|
||||
* @return $this
|
||||
*/
|
||||
private function indent()
|
||||
{
|
||||
$this->indentation .= ' ';
|
||||
return $this;
|
||||
}
|
||||
private function visit_or(array $node)
|
||||
{
|
||||
$a = $this->makeVar('beforeOr');
|
||||
return $this->write('%s = $value;', $a)->dispatch($node['children'][0])->write('if (!$value && $value !== "0" && $value !== 0) {')->indent()->write('$value = %s;', $a)->dispatch($node['children'][1])->outdent()->write('}');
|
||||
}
|
||||
private function visit_and(array $node)
|
||||
{
|
||||
$a = $this->makeVar('beforeAnd');
|
||||
return $this->write('%s = $value;', $a)->dispatch($node['children'][0])->write('if ($value || $value === "0" || $value === 0) {')->indent()->write('$value = %s;', $a)->dispatch($node['children'][1])->outdent()->write('}');
|
||||
}
|
||||
private function visit_not(array $node)
|
||||
{
|
||||
return $this->write('// Visiting not node')->dispatch($node['children'][0])->write('// Applying boolean not to result of not node')->write('$value = !Utils::isTruthy($value);');
|
||||
}
|
||||
private function visit_subexpression(array $node)
|
||||
{
|
||||
return $this->dispatch($node['children'][0])->write('if ($value !== null) {')->indent()->dispatch($node['children'][1])->outdent()->write('}');
|
||||
}
|
||||
private function visit_field(array $node)
|
||||
{
|
||||
$arr = '$value[' . var_export($node['value'], true) . ']';
|
||||
$obj = '$value->{' . var_export($node['value'], true) . '}';
|
||||
$this->write('if (is_array($value) || $value instanceof \\ArrayAccess) {')->indent()->write('$value = isset(%s) ? %s : null;', $arr, $arr)->outdent()->write('} elseif ($value instanceof \\stdClass) {')->indent()->write('$value = isset(%s) ? %s : null;', $obj, $obj)->outdent()->write("} else {")->indent()->write('$value = null;')->outdent()->write("}");
|
||||
return $this;
|
||||
}
|
||||
private function visit_index(array $node)
|
||||
{
|
||||
if ($node['value'] >= 0) {
|
||||
$check = '$value[' . $node['value'] . ']';
|
||||
return $this->write('$value = (is_array($value) || $value instanceof \\ArrayAccess)' . ' && isset(%s) ? %s : null;', $check, $check);
|
||||
}
|
||||
$a = $this->makeVar('count');
|
||||
return $this->write('if (is_array($value) || ($value instanceof \\ArrayAccess && $value instanceof \\Countable)) {')->indent()->write('%s = count($value) + %s;', $a, $node['value'])->write('$value = isset($value[%s]) ? $value[%s] : null;', $a, $a)->outdent()->write('} else {')->indent()->write('$value = null;')->outdent()->write('}');
|
||||
}
|
||||
private function visit_literal(array $node)
|
||||
{
|
||||
return $this->write('$value = %s;', var_export($node['value'], true));
|
||||
}
|
||||
private function visit_pipe(array $node)
|
||||
{
|
||||
return $this->dispatch($node['children'][0])->dispatch($node['children'][1]);
|
||||
}
|
||||
private function visit_multi_select_list(array $node)
|
||||
{
|
||||
return $this->visit_multi_select_hash($node);
|
||||
}
|
||||
private function visit_multi_select_hash(array $node)
|
||||
{
|
||||
$listVal = $this->makeVar('list');
|
||||
$value = $this->makeVar('prev');
|
||||
$this->write('if ($value !== null) {')->indent()->write('%s = [];', $listVal)->write('%s = $value;', $value);
|
||||
$first = true;
|
||||
foreach ($node['children'] as $child) {
|
||||
if (!$first) {
|
||||
$this->write('$value = %s;', $value);
|
||||
}
|
||||
$first = false;
|
||||
if ($node['type'] == 'multi_select_hash') {
|
||||
$this->dispatch($child['children'][0]);
|
||||
$key = var_export($child['value'], true);
|
||||
$this->write('%s[%s] = $value;', $listVal, $key);
|
||||
} else {
|
||||
$this->dispatch($child);
|
||||
$this->write('%s[] = $value;', $listVal);
|
||||
}
|
||||
}
|
||||
return $this->write('$value = %s;', $listVal)->outdent()->write('}');
|
||||
}
|
||||
private function visit_function(array $node)
|
||||
{
|
||||
$value = $this->makeVar('val');
|
||||
$args = $this->makeVar('args');
|
||||
$this->write('%s = $value;', $value)->write('%s = [];', $args);
|
||||
foreach ($node['children'] as $arg) {
|
||||
$this->dispatch($arg);
|
||||
$this->write('%s[] = $value;', $args)->write('$value = %s;', $value);
|
||||
}
|
||||
return $this->write('$value = Fd::getInstance()->__invoke("%s", %s);', $node['value'], $args);
|
||||
}
|
||||
private function visit_slice(array $node)
|
||||
{
|
||||
return $this->write('$value = !is_string($value) && !Utils::isArray($value)')->write(' ? null : Utils::slice($value, %s, %s, %s);', var_export($node['value'][0], true), var_export($node['value'][1], true), var_export($node['value'][2], true));
|
||||
}
|
||||
private function visit_current(array $node)
|
||||
{
|
||||
return $this->write('// Visiting current node (no-op)');
|
||||
}
|
||||
private function visit_expref(array $node)
|
||||
{
|
||||
$child = var_export($node['children'][0], true);
|
||||
return $this->write('$value = function ($value) use ($interpreter) {')->indent()->write('return $interpreter->visit(%s, $value);', $child)->outdent()->write('};');
|
||||
}
|
||||
private function visit_flatten(array $node)
|
||||
{
|
||||
$this->dispatch($node['children'][0]);
|
||||
$merged = $this->makeVar('merged');
|
||||
$val = $this->makeVar('val');
|
||||
$this->write('// Visiting merge node')->write('if (!Utils::isArray($value)) {')->indent()->write('$value = null;')->outdent()->write('} else {')->indent()->write('%s = [];', $merged)->write('foreach ($value as %s) {', $val)->indent()->write('if (is_array(%s) && isset(%s[0])) {', $val, $val)->indent()->write('%s = array_merge(%s, %s);', $merged, $merged, $val)->outdent()->write('} elseif (%s !== []) {', $val)->indent()->write('%s[] = %s;', $merged, $val)->outdent()->write('}')->outdent()->write('}')->write('$value = %s;', $merged)->outdent()->write('}');
|
||||
return $this;
|
||||
}
|
||||
private function visit_projection(array $node)
|
||||
{
|
||||
$val = $this->makeVar('val');
|
||||
$collected = $this->makeVar('collected');
|
||||
$this->write('// Visiting projection node')->dispatch($node['children'][0])->write('');
|
||||
if (!isset($node['from'])) {
|
||||
$this->write('if (!is_array($value) || !($value instanceof \\stdClass)) { $value = null; }');
|
||||
} elseif ($node['from'] == 'object') {
|
||||
$this->write('if (!Utils::isObject($value)) { $value = null; }');
|
||||
} elseif ($node['from'] == 'array') {
|
||||
$this->write('if (!Utils::isArray($value)) { $value = null; }');
|
||||
}
|
||||
$this->write('if ($value !== null) {')->indent()->write('%s = [];', $collected)->write('foreach ((array) $value as %s) {', $val)->indent()->write('$value = %s;', $val)->dispatch($node['children'][1])->write('if ($value !== null) {')->indent()->write('%s[] = $value;', $collected)->outdent()->write('}')->outdent()->write('}')->write('$value = %s;', $collected)->outdent()->write('}');
|
||||
return $this;
|
||||
}
|
||||
private function visit_condition(array $node)
|
||||
{
|
||||
$value = $this->makeVar('beforeCondition');
|
||||
return $this->write('%s = $value;', $value)->write('// Visiting condition node')->dispatch($node['children'][0])->write('// Checking result of condition node')->write('if (Utils::isTruthy($value)) {')->indent()->write('$value = %s;', $value)->dispatch($node['children'][1])->outdent()->write('} else {')->indent()->write('$value = null;')->outdent()->write('}');
|
||||
}
|
||||
private function visit_comparator(array $node)
|
||||
{
|
||||
$value = $this->makeVar('val');
|
||||
$a = $this->makeVar('left');
|
||||
$b = $this->makeVar('right');
|
||||
$this->write('// Visiting comparator node')->write('%s = $value;', $value)->dispatch($node['children'][0])->write('%s = $value;', $a)->write('$value = %s;', $value)->dispatch($node['children'][1])->write('%s = $value;', $b);
|
||||
if ($node['value'] == '==') {
|
||||
$this->write('$value = Utils::isEqual(%s, %s);', $a, $b);
|
||||
} elseif ($node['value'] == '!=') {
|
||||
$this->write('$value = !Utils::isEqual(%s, %s);', $a, $b);
|
||||
} else {
|
||||
$this->write('$value = (is_int(%s) || is_float(%s)) && (is_int(%s) || is_float(%s)) && %s %s %s;', $a, $a, $b, $b, $a, $node['value'], $b);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/** @internal */
|
||||
public function __call($method, $args)
|
||||
{
|
||||
throw new \RuntimeException(sprintf('Invalid node encountered: %s', json_encode($args[0])));
|
||||
}
|
||||
}
|
182
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/TreeInterpreter.php
vendored
Normal file
182
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/TreeInterpreter.php
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
/**
|
||||
* Tree visitor used to evaluates JMESPath AST expressions.
|
||||
*/
|
||||
class TreeInterpreter
|
||||
{
|
||||
/** @var callable */
|
||||
private $fnDispatcher;
|
||||
/**
|
||||
* @param callable|null $fnDispatcher Function dispatching function that accepts
|
||||
* a function name argument and an array of
|
||||
* function arguments and returns the result.
|
||||
*/
|
||||
public function __construct(callable $fnDispatcher = null)
|
||||
{
|
||||
$this->fnDispatcher = $fnDispatcher ?: \UglyRobot\Infinite_Uploads\JmesPath\FnDispatcher::getInstance();
|
||||
}
|
||||
/**
|
||||
* Visits each node in a JMESPath AST and returns the evaluated result.
|
||||
*
|
||||
* @param array $node JMESPath AST node
|
||||
* @param mixed $data Data to evaluate
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function visit(array $node, $data)
|
||||
{
|
||||
return $this->dispatch($node, $data);
|
||||
}
|
||||
/**
|
||||
* Recursively traverses an AST using depth-first, pre-order traversal.
|
||||
* The evaluation logic for each node type is embedded into a large switch
|
||||
* statement to avoid the cost of "double dispatch".
|
||||
* @return mixed
|
||||
*/
|
||||
private function dispatch(array $node, $value)
|
||||
{
|
||||
$dispatcher = $this->fnDispatcher;
|
||||
switch ($node['type']) {
|
||||
case 'field':
|
||||
if (is_array($value) || $value instanceof \ArrayAccess) {
|
||||
return isset($value[$node['value']]) ? $value[$node['value']] : null;
|
||||
} elseif ($value instanceof \stdClass) {
|
||||
return isset($value->{$node['value']}) ? $value->{$node['value']} : null;
|
||||
}
|
||||
return null;
|
||||
case 'subexpression':
|
||||
return $this->dispatch($node['children'][1], $this->dispatch($node['children'][0], $value));
|
||||
case 'index':
|
||||
if (!\UglyRobot\Infinite_Uploads\JmesPath\Utils::isArray($value)) {
|
||||
return null;
|
||||
}
|
||||
$idx = $node['value'] >= 0 ? $node['value'] : $node['value'] + count($value);
|
||||
return isset($value[$idx]) ? $value[$idx] : null;
|
||||
case 'projection':
|
||||
$left = $this->dispatch($node['children'][0], $value);
|
||||
switch ($node['from']) {
|
||||
case 'object':
|
||||
if (!\UglyRobot\Infinite_Uploads\JmesPath\Utils::isObject($left)) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case 'array':
|
||||
if (!\UglyRobot\Infinite_Uploads\JmesPath\Utils::isArray($left)) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!is_array($left) || !$left instanceof \stdClass) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$collected = [];
|
||||
foreach ((array) $left as $val) {
|
||||
$result = $this->dispatch($node['children'][1], $val);
|
||||
if ($result !== null) {
|
||||
$collected[] = $result;
|
||||
}
|
||||
}
|
||||
return $collected;
|
||||
case 'flatten':
|
||||
static $skipElement = [];
|
||||
$value = $this->dispatch($node['children'][0], $value);
|
||||
if (!\UglyRobot\Infinite_Uploads\JmesPath\Utils::isArray($value)) {
|
||||
return null;
|
||||
}
|
||||
$merged = [];
|
||||
foreach ($value as $values) {
|
||||
// Only merge up arrays lists and not hashes
|
||||
if (is_array($values) && isset($values[0])) {
|
||||
$merged = array_merge($merged, $values);
|
||||
} elseif ($values !== $skipElement) {
|
||||
$merged[] = $values;
|
||||
}
|
||||
}
|
||||
return $merged;
|
||||
case 'literal':
|
||||
return $node['value'];
|
||||
case 'current':
|
||||
return $value;
|
||||
case 'or':
|
||||
$result = $this->dispatch($node['children'][0], $value);
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::isTruthy($result) ? $result : $this->dispatch($node['children'][1], $value);
|
||||
case 'and':
|
||||
$result = $this->dispatch($node['children'][0], $value);
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::isTruthy($result) ? $this->dispatch($node['children'][1], $value) : $result;
|
||||
case 'not':
|
||||
return !\UglyRobot\Infinite_Uploads\JmesPath\Utils::isTruthy($this->dispatch($node['children'][0], $value));
|
||||
case 'pipe':
|
||||
return $this->dispatch($node['children'][1], $this->dispatch($node['children'][0], $value));
|
||||
case 'multi_select_list':
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
$collected = [];
|
||||
foreach ($node['children'] as $node) {
|
||||
$collected[] = $this->dispatch($node, $value);
|
||||
}
|
||||
return $collected;
|
||||
case 'multi_select_hash':
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
$collected = [];
|
||||
foreach ($node['children'] as $node) {
|
||||
$collected[$node['value']] = $this->dispatch($node['children'][0], $value);
|
||||
}
|
||||
return $collected;
|
||||
case 'comparator':
|
||||
$left = $this->dispatch($node['children'][0], $value);
|
||||
$right = $this->dispatch($node['children'][1], $value);
|
||||
if ($node['value'] == '==') {
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::isEqual($left, $right);
|
||||
} elseif ($node['value'] == '!=') {
|
||||
return !\UglyRobot\Infinite_Uploads\JmesPath\Utils::isEqual($left, $right);
|
||||
} else {
|
||||
return self::relativeCmp($left, $right, $node['value']);
|
||||
}
|
||||
case 'condition':
|
||||
return \UglyRobot\Infinite_Uploads\JmesPath\Utils::isTruthy($this->dispatch($node['children'][0], $value)) ? $this->dispatch($node['children'][1], $value) : null;
|
||||
case 'function':
|
||||
$args = [];
|
||||
foreach ($node['children'] as $arg) {
|
||||
$args[] = $this->dispatch($arg, $value);
|
||||
}
|
||||
return $dispatcher($node['value'], $args);
|
||||
case 'slice':
|
||||
return is_string($value) || \UglyRobot\Infinite_Uploads\JmesPath\Utils::isArray($value) ? \UglyRobot\Infinite_Uploads\JmesPath\Utils::slice($value, $node['value'][0], $node['value'][1], $node['value'][2]) : null;
|
||||
case 'expref':
|
||||
$apply = $node['children'][0];
|
||||
return function ($value) use($apply) {
|
||||
return $this->visit($apply, $value);
|
||||
};
|
||||
default:
|
||||
throw new \RuntimeException("Unknown node type: {$node['type']}");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private static function relativeCmp($left, $right, $cmp)
|
||||
{
|
||||
if (!(is_int($left) || is_float($left)) || !(is_int($right) || is_float($right))) {
|
||||
return false;
|
||||
}
|
||||
switch ($cmp) {
|
||||
case '>':
|
||||
return $left > $right;
|
||||
case '>=':
|
||||
return $left >= $right;
|
||||
case '<':
|
||||
return $left < $right;
|
||||
case '<=':
|
||||
return $left <= $right;
|
||||
default:
|
||||
throw new \RuntimeException("Invalid comparison: {$cmp}");
|
||||
}
|
||||
}
|
||||
}
|
220
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Utils.php
vendored
Normal file
220
wp-content/plugins/infinite-uploads/vendor/Aws3/JmesPath/Utils.php
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace UglyRobot\Infinite_Uploads\JmesPath;
|
||||
|
||||
class Utils
|
||||
{
|
||||
public static $typeMap = ['boolean' => 'boolean', 'string' => 'string', 'NULL' => 'null', 'double' => 'number', 'float' => 'number', 'integer' => 'number'];
|
||||
/**
|
||||
* Returns true if the value is truthy
|
||||
*
|
||||
* @param mixed $value Value to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTruthy($value)
|
||||
{
|
||||
if (!$value) {
|
||||
return $value === 0 || $value === '0';
|
||||
} elseif ($value instanceof \stdClass) {
|
||||
return (bool) get_object_vars($value);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the JMESPath type equivalent of a PHP variable.
|
||||
*
|
||||
* @param mixed $arg PHP variable
|
||||
* @return string Returns the JSON data type
|
||||
* @throws \InvalidArgumentException when an unknown type is given.
|
||||
*/
|
||||
public static function type($arg)
|
||||
{
|
||||
$type = gettype($arg);
|
||||
if (isset(self::$typeMap[$type])) {
|
||||
return self::$typeMap[$type];
|
||||
} elseif ($type === 'array') {
|
||||
if (empty($arg)) {
|
||||
return 'array';
|
||||
}
|
||||
reset($arg);
|
||||
return key($arg) === 0 ? 'array' : 'object';
|
||||
} elseif ($arg instanceof \stdClass) {
|
||||
return 'object';
|
||||
} elseif ($arg instanceof \Closure) {
|
||||
return 'expression';
|
||||
} elseif ($arg instanceof \ArrayAccess && $arg instanceof \Countable) {
|
||||
return count($arg) == 0 || $arg->offsetExists(0) ? 'array' : 'object';
|
||||
} elseif (method_exists($arg, '__toString')) {
|
||||
return 'string';
|
||||
}
|
||||
throw new \InvalidArgumentException('Unable to determine JMESPath type from ' . get_class($arg));
|
||||
}
|
||||
/**
|
||||
* Determine if the provided value is a JMESPath compatible object.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isObject($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return !$value || array_keys($value)[0] !== 0;
|
||||
}
|
||||
// Handle array-like values. Must be empty or offset 0 does not exist
|
||||
return $value instanceof \Countable && $value instanceof \ArrayAccess ? count($value) == 0 || !$value->offsetExists(0) : $value instanceof \stdClass;
|
||||
}
|
||||
/**
|
||||
* Determine if the provided value is a JMESPath compatible array.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isArray($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return !$value || array_keys($value)[0] === 0;
|
||||
}
|
||||
// Handle array-like values. Must be empty or offset 0 exists.
|
||||
return $value instanceof \Countable && $value instanceof \ArrayAccess ? count($value) == 0 || $value->offsetExists(0) : false;
|
||||
}
|
||||
/**
|
||||
* JSON aware value comparison function.
|
||||
*
|
||||
* @param mixed $a First value to compare
|
||||
* @param mixed $b Second value to compare
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEqual($a, $b)
|
||||
{
|
||||
if ($a === $b) {
|
||||
return true;
|
||||
} elseif ($a instanceof \stdClass) {
|
||||
return self::isEqual((array) $a, $b);
|
||||
} elseif ($b instanceof \stdClass) {
|
||||
return self::isEqual($a, (array) $b);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Safely add together two values.
|
||||
*
|
||||
* @param mixed $a First value to add
|
||||
* @param mixed $b Second value to add
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public static function add($a, $b)
|
||||
{
|
||||
if (is_numeric($a)) {
|
||||
if (is_numeric($b)) {
|
||||
return $a + $b;
|
||||
} else {
|
||||
return $a;
|
||||
}
|
||||
} else {
|
||||
if (is_numeric($b)) {
|
||||
return $b;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* JMESPath requires a stable sorting algorithm, so here we'll implement
|
||||
* a simple Schwartzian transform that uses array index positions as tie
|
||||
* breakers.
|
||||
*
|
||||
* @param array $data List or map of data to sort
|
||||
* @param callable $sortFn Callable used to sort values
|
||||
*
|
||||
* @return array Returns the sorted array
|
||||
* @link http://en.wikipedia.org/wiki/Schwartzian_transform
|
||||
*/
|
||||
public static function stableSort(array $data, callable $sortFn)
|
||||
{
|
||||
// Decorate each item by creating an array of [value, index]
|
||||
array_walk($data, function (&$v, $k) {
|
||||
$v = [$v, $k];
|
||||
});
|
||||
// Sort by the sort function and use the index as a tie-breaker
|
||||
uasort($data, function ($a, $b) use($sortFn) {
|
||||
return $sortFn($a[0], $b[0]) ?: ($a[1] < $b[1] ? -1 : 1);
|
||||
});
|
||||
// Undecorate each item and return the resulting sorted array
|
||||
return array_map(function ($v) {
|
||||
return $v[0];
|
||||
}, array_values($data));
|
||||
}
|
||||
/**
|
||||
* Creates a Python-style slice of a string or array.
|
||||
*
|
||||
* @param array|string $value Value to slice
|
||||
* @param int|null $start Starting position
|
||||
* @param int|null $stop Stop position
|
||||
* @param int $step Step (1, 2, -1, -2, etc.)
|
||||
*
|
||||
* @return array|string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function slice($value, $start = null, $stop = null, $step = 1)
|
||||
{
|
||||
if (!is_array($value) && !is_string($value)) {
|
||||
throw new \InvalidArgumentException('Expects string or array');
|
||||
}
|
||||
return self::sliceIndices($value, $start, $stop, $step);
|
||||
}
|
||||
private static function adjustEndpoint($length, $endpoint, $step)
|
||||
{
|
||||
if ($endpoint < 0) {
|
||||
$endpoint += $length;
|
||||
if ($endpoint < 0) {
|
||||
$endpoint = $step < 0 ? -1 : 0;
|
||||
}
|
||||
} elseif ($endpoint >= $length) {
|
||||
$endpoint = $step < 0 ? $length - 1 : $length;
|
||||
}
|
||||
return $endpoint;
|
||||
}
|
||||
private static function adjustSlice($length, $start, $stop, $step)
|
||||
{
|
||||
if ($step === null) {
|
||||
$step = 1;
|
||||
} elseif ($step === 0) {
|
||||
throw new \RuntimeException('step cannot be 0');
|
||||
}
|
||||
if ($start === null) {
|
||||
$start = $step < 0 ? $length - 1 : 0;
|
||||
} else {
|
||||
$start = self::adjustEndpoint($length, $start, $step);
|
||||
}
|
||||
if ($stop === null) {
|
||||
$stop = $step < 0 ? -1 : $length;
|
||||
} else {
|
||||
$stop = self::adjustEndpoint($length, $stop, $step);
|
||||
}
|
||||
return [$start, $stop, $step];
|
||||
}
|
||||
private static function sliceIndices($subject, $start, $stop, $step)
|
||||
{
|
||||
$type = gettype($subject);
|
||||
$len = $type == 'string' ? mb_strlen($subject, 'UTF-8') : count($subject);
|
||||
list($start, $stop, $step) = self::adjustSlice($len, $start, $stop, $step);
|
||||
$result = [];
|
||||
if ($step > 0) {
|
||||
for ($i = $start; $i < $stop; $i += $step) {
|
||||
$result[] = $subject[$i];
|
||||
}
|
||||
} else {
|
||||
for ($i = $start; $i > $stop; $i += $step) {
|
||||
$result[] = $subject[$i];
|
||||
}
|
||||
}
|
||||
return $type == 'string' ? implode('', $result) : $result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user