radarrplexorganizrnginxsonarrdashboardserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelandinghtpc
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							226 lines
						
					
					
						
							8.9 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							226 lines
						
					
					
						
							8.9 KiB
						
					
					
				| <?php | |
| 
 | |
| namespace PhpParser; | |
| 
 | |
| use PhpParser\Node\Expr; | |
| use PhpParser\Node\Scalar; | |
| 
 | |
| /** | |
|  * Evaluates constant expressions. | |
|  * | |
|  * This evaluator is able to evaluate all constant expressions (as defined by PHP), which can be | |
|  * evaluated without further context. If a subexpression is not of this type, a user-provided | |
|  * fallback evaluator is invoked. To support all constant expressions that are also supported by | |
|  * PHP (and not already handled by this class), the fallback evaluator must be able to handle the | |
|  * following node types: | |
|  * | |
|  *  * All Scalar\MagicConst\* nodes. | |
|  *  * Expr\ConstFetch nodes. Only null/false/true are already handled by this class. | |
|  *  * Expr\ClassConstFetch nodes. | |
|  * | |
|  * The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate. | |
|  * | |
|  * The evaluation is dependent on runtime configuration in two respects: Firstly, floating | |
|  * point to string conversions are affected by the precision ini setting. Secondly, they are also | |
|  * affected by the LC_NUMERIC locale. | |
|  */ | |
| class ConstExprEvaluator | |
| { | |
|     private $fallbackEvaluator; | |
| 
 | |
|     /** | |
|      * Create a constant expression evaluator. | |
|      * | |
|      * The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See | |
|      * class doc comment for more information. | |
|      * | |
|      * @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated | |
|      */ | |
|     public function __construct(callable $fallbackEvaluator = null) { | |
|         $this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) { | |
|             throw new ConstExprEvaluationException( | |
|                 "Expression of type {$expr->getType()} cannot be evaluated" | |
|             ); | |
|         }; | |
|     } | |
| 
 | |
|     /** | |
|      * Silently evaluates a constant expression into a PHP value. | |
|      * | |
|      * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException. | |
|      * The original source of the exception is available through getPrevious(). | |
|      * | |
|      * If some part of the expression cannot be evaluated, the fallback evaluator passed to the | |
|      * constructor will be invoked. By default, if no fallback is provided, an exception of type | |
|      * ConstExprEvaluationException is thrown. | |
|      * | |
|      * See class doc comment for caveats and limitations. | |
|      * | |
|      * @param Expr $expr Constant expression to evaluate | |
|      * @return mixed Result of evaluation | |
|      * | |
|      * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred | |
|      */ | |
|     public function evaluateSilently(Expr $expr) { | |
|         set_error_handler(function($num, $str, $file, $line) { | |
|             throw new \ErrorException($str, 0, $num, $file, $line); | |
|         }); | |
| 
 | |
|         try { | |
|             return $this->evaluate($expr); | |
|         } catch (\Throwable $e) { | |
|             if (!$e instanceof ConstExprEvaluationException) { | |
|                 $e = new ConstExprEvaluationException( | |
|                     "An error occurred during constant expression evaluation", 0, $e); | |
|             } | |
|             throw $e; | |
|         } finally { | |
|             restore_error_handler(); | |
|         } | |
|     } | |
| 
 | |
|     /** | |
|      * Directly evaluates a constant expression into a PHP value. | |
|      * | |
|      * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these | |
|      * into a ConstExprEvaluationException. | |
|      * | |
|      * If some part of the expression cannot be evaluated, the fallback evaluator passed to the | |
|      * constructor will be invoked. By default, if no fallback is provided, an exception of type | |
|      * ConstExprEvaluationException is thrown. | |
|      * | |
|      * See class doc comment for caveats and limitations. | |
|      * | |
|      * @param Expr $expr Constant expression to evaluate | |
|      * @return mixed Result of evaluation | |
|      * | |
|      * @throws ConstExprEvaluationException if the expression cannot be evaluated | |
|      */ | |
|     public function evaluateDirectly(Expr $expr) { | |
|         return $this->evaluate($expr); | |
|     } | |
| 
 | |
|     private function evaluate(Expr $expr) { | |
|         if ($expr instanceof Scalar\LNumber | |
|             || $expr instanceof Scalar\DNumber | |
|             || $expr instanceof Scalar\String_ | |
|         ) { | |
|             return $expr->value; | |
|         } | |
| 
 | |
|         if ($expr instanceof Expr\Array_) { | |
|             return $this->evaluateArray($expr); | |
|         } | |
| 
 | |
|         // Unary operators | |
|         if ($expr instanceof Expr\UnaryPlus) { | |
|             return +$this->evaluate($expr->expr); | |
|         } | |
|         if ($expr instanceof Expr\UnaryMinus) { | |
|             return -$this->evaluate($expr->expr); | |
|         } | |
|         if ($expr instanceof Expr\BooleanNot) { | |
|             return !$this->evaluate($expr->expr); | |
|         } | |
|         if ($expr instanceof Expr\BitwiseNot) { | |
|             return ~$this->evaluate($expr->expr); | |
|         } | |
| 
 | |
|         if ($expr instanceof Expr\BinaryOp) { | |
|             return $this->evaluateBinaryOp($expr); | |
|         } | |
| 
 | |
|         if ($expr instanceof Expr\Ternary) { | |
|             return $this->evaluateTernary($expr); | |
|         } | |
| 
 | |
|         if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) { | |
|             return $this->evaluate($expr->var)[$this->evaluate($expr->dim)]; | |
|         } | |
| 
 | |
|         if ($expr instanceof Expr\ConstFetch) { | |
|             return $this->evaluateConstFetch($expr); | |
|         } | |
| 
 | |
|         return ($this->fallbackEvaluator)($expr); | |
|     } | |
| 
 | |
|     private function evaluateArray(Expr\Array_ $expr) { | |
|         $array = []; | |
|         foreach ($expr->items as $item) { | |
|             if (null !== $item->key) { | |
|                 $array[$this->evaluate($item->key)] = $this->evaluate($item->value); | |
|             } else { | |
|                 $array[] = $this->evaluate($item->value); | |
|             } | |
|         } | |
|         return $array; | |
|     } | |
| 
 | |
|     private function evaluateTernary(Expr\Ternary $expr) { | |
|         if (null === $expr->if) { | |
|             return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else); | |
|         } | |
| 
 | |
|         return $this->evaluate($expr->cond) | |
|             ? $this->evaluate($expr->if) | |
|             : $this->evaluate($expr->else); | |
|     } | |
| 
 | |
|     private function evaluateBinaryOp(Expr\BinaryOp $expr) { | |
|         if ($expr instanceof Expr\BinaryOp\Coalesce | |
|             && $expr->left instanceof Expr\ArrayDimFetch | |
|         ) { | |
|             // This needs to be special cased to respect BP_VAR_IS fetch semantics | |
|             return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)] | |
|                 ?? $this->evaluate($expr->right); | |
|         } | |
| 
 | |
|         // The evaluate() calls are repeated in each branch, because some of the operators are | |
|         // short-circuiting and evaluating the RHS in advance may be illegal in that case | |
|         $l = $expr->left; | |
|         $r = $expr->right; | |
|         switch ($expr->getOperatorSigil()) { | |
|             case '&':   return $this->evaluate($l) &   $this->evaluate($r); | |
|             case '|':   return $this->evaluate($l) |   $this->evaluate($r); | |
|             case '^':   return $this->evaluate($l) ^   $this->evaluate($r); | |
|             case '&&':  return $this->evaluate($l) &&  $this->evaluate($r); | |
|             case '||':  return $this->evaluate($l) ||  $this->evaluate($r); | |
|             case '??':  return $this->evaluate($l) ??  $this->evaluate($r); | |
|             case '.':   return $this->evaluate($l) .   $this->evaluate($r); | |
|             case '/':   return $this->evaluate($l) /   $this->evaluate($r); | |
|             case '==':  return $this->evaluate($l) ==  $this->evaluate($r); | |
|             case '>':   return $this->evaluate($l) >   $this->evaluate($r); | |
|             case '>=':  return $this->evaluate($l) >=  $this->evaluate($r); | |
|             case '===': return $this->evaluate($l) === $this->evaluate($r); | |
|             case 'and': return $this->evaluate($l) and $this->evaluate($r); | |
|             case 'or':  return $this->evaluate($l) or  $this->evaluate($r); | |
|             case 'xor': return $this->evaluate($l) xor $this->evaluate($r); | |
|             case '-':   return $this->evaluate($l) -   $this->evaluate($r); | |
|             case '%':   return $this->evaluate($l) %   $this->evaluate($r); | |
|             case '*':   return $this->evaluate($l) *   $this->evaluate($r); | |
|             case '!=':  return $this->evaluate($l) !=  $this->evaluate($r); | |
|             case '!==': return $this->evaluate($l) !== $this->evaluate($r); | |
|             case '+':   return $this->evaluate($l) +   $this->evaluate($r); | |
|             case '**':  return $this->evaluate($l) **  $this->evaluate($r); | |
|             case '<<':  return $this->evaluate($l) <<  $this->evaluate($r); | |
|             case '>>':  return $this->evaluate($l) >>  $this->evaluate($r); | |
|             case '<':   return $this->evaluate($l) <   $this->evaluate($r); | |
|             case '<=':  return $this->evaluate($l) <=  $this->evaluate($r); | |
|             case '<=>': return $this->evaluate($l) <=> $this->evaluate($r); | |
|         } | |
| 
 | |
|         throw new \Exception('Should not happen'); | |
|     } | |
| 
 | |
|     private function evaluateConstFetch(Expr\ConstFetch $expr) { | |
|         $name = $expr->name->toLowerString(); | |
|         switch ($name) { | |
|             case 'null': return null; | |
|             case 'false': return false; | |
|             case 'true': return true; | |
|         } | |
| 
 | |
|         return ($this->fallbackEvaluator)($expr); | |
|     } | |
| }
 | |
| 
 |