* @version 3.0 */ class CustomizedValidatorVisitor extends NodeVisitorAbstract { /** The PHPSandbox instance to check against * @var PHPSandbox */ protected CustomizedSandbox $sandbox; /** ValidatorVisitor class constructor * * This constructor takes a passed PHPSandbox instance to check against for validating sandboxed code. * * @param CustomizedSandbox $sandbox The PHPSandbox instance to check against */ public function __construct(CustomizedSandbox $sandbox){ $this->sandbox = $sandbox; } /** Examine the current PhpParser_Node node against the PHPSandbox configuration for validating sandboxed code * * @param Node $node The sandboxed $node to validate * * @throws Throwable Throws an exception if validation fails * * @return Node|bool|null Return rewritten node, false if node must be removed, or null if no changes to the node are made */ public function leaveNode(Node $node){ if($node instanceof Node\Arg && $this->sandbox->sandbox_strings){ return new Node\Expr\FuncCall(new Node\Name\FullyQualified(($node->value instanceof Node\Expr\Variable) ? 'PHPSandbox\\wrapByRef' : 'PHPSandbox\\wrap'), [$node, new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox')], $node->getAttributes()); } else if($node instanceof Node\Stmt\InlineHTML){ if(!$this->sandbox->allow_escaping){ $this->sandbox->validationError("Sandboxed code attempted to escape to HTML!", Error::ESCAPE_ERROR, $node); } }else if($node instanceof Node\Expr\Cast){ if(!$this->sandbox->allow_casting){ $this->sandbox->validationError("Sandboxed code attempted to cast!", Error::CAST_ERROR, $node); } if($node instanceof Node\Expr\Cast\Int_){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_intval', [new Node\Arg($node->expr)], $node->getAttributes()); } else if($node instanceof Node\Expr\Cast\Double){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_floatval', [new Node\Arg($node->expr)], $node->getAttributes()); } else if($node instanceof Node\Expr\Cast\Bool_){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_boolval', [new Node\Arg($node->expr)], $node->getAttributes()); } else if($node instanceof Node\Expr\Cast\Array_){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_arrayval', [new Node\Arg($node->expr)], $node->getAttributes()); } else if($node instanceof Node\Expr\Cast\Object_){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_objectval', [new Node\Arg($node->expr)], $node->getAttributes()); } } else if($node instanceof Node\Expr\FuncCall){ if($node->name instanceof Node\Name){ $name = strtolower($node->name->toString()); if(!$this->sandbox->checkFunc($name)){ $this->sandbox->validationError('Function failed custom validation!', Error::VALID_FUNC_ERROR, $node); } if($this->sandbox->isDefinedFunc($name)){ $args = $node->args; array_unshift($args, new Node\Arg(new Node\Scalar\String_($name))); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); } if($this->sandbox->overwrite_defined_funcs && in_array($name, CustomizedSandbox::$defined_funcs)){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name([$name])))], $node->getAttributes()); } if($this->sandbox->overwrite_sandboxed_string_funcs && in_array($name, CustomizedSandbox::$sandboxed_string_funcs)){ $args = $node->args; return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, $args, $node->getAttributes()); } if($this->sandbox->overwrite_func_get_args && in_array($name, CustomizedSandbox::$arg_funcs)){ if($name === 'func_get_arg'){ $index = new Node\Arg(new Node\Scalar\LNumber(0)); if(isset($node->args[0]) && $node->args[0] instanceof Node\Arg){ $index = $node->args[0]; } return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args']))), $index], $node->getAttributes()); } return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args'])))], $node->getAttributes()); } } else { return new Node\Expr\Ternary( new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'checkFunc', [new Node\Arg($node->name)], $node->getAttributes()), $node, new Node\Expr\ConstFetch(new Node\Name('null')) ); } } else if($node instanceof Node\Stmt\Function_){ if(!$this->sandbox->allow_functions){ $this->sandbox->validationError('Sandboxed code attempted to define function!', Error::DEFINE_FUNC_ERROR, $node); } if(!$this->sandbox->checkKeyword('function')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'function'); } if(!$node->name){ $this->sandbox->validationError('Sandboxed code attempted to define unnamed function!', Error::DEFINE_FUNC_ERROR, $node, ''); } if($this->sandbox->isDefinedFunc($node->name)){ $this->sandbox->validationError('Sandboxed code attempted to redefine function!', Error::DEFINE_FUNC_ERROR, $node, $node->name); } if($node->byRef && !$this->sandbox->allow_references){ $this->sandbox->validationError('Sandboxed code attempted to define function return by reference!', Error::BYREF_ERROR, $node); } } else if($node instanceof Node\Expr\Closure){ if(!$this->sandbox->allow_closures){ $this->sandbox->validationError('Sandboxed code attempted to create a closure!', Error::CLOSURE_ERROR, $node); } } else if($node instanceof Node\Stmt\Class_){ if(!$this->sandbox->allow_classes){ $this->sandbox->validationError('Sandboxed code attempted to define class!', Error::DEFINE_CLASS_ERROR, $node); } if(!$this->sandbox->checkKeyword('class')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'class'); } if(!$node->name){ $this->sandbox->validationError('Sandboxed code attempted to define unnamed class!', Error::DEFINE_CLASS_ERROR, $node, ''); } if(!$this->sandbox->checkClass($node->name)){ $this->sandbox->validationError('Class failed custom validation!', Error::VALID_CLASS_ERROR, $node, $node->name); } if($node->extends instanceof Node\Name){ if(!$this->sandbox->checkKeyword('extends')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'extends'); } if(!$node->extends->toString()){ $this->sandbox->validationError('Sandboxed code attempted to extend unnamed class!', Error::DEFINE_CLASS_ERROR, $node, ''); } if(!$this->sandbox->checkClass($node->extends->toString(), true)){ $this->sandbox->validationError('Class extension failed custom validation!', Error::VALID_CLASS_ERROR, $node, $node->extends->toString()); } } if(is_array($node->implements)){ if(!$this->sandbox->checkKeyword('implements')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'implements'); } foreach($node->implements as $implement){ /** * @var Node\Name $implement */ if(!$implement->toString()){ $this->sandbox->validationError('Sandboxed code attempted to implement unnamed interface!', Error::DEFINE_INTERFACE_ERROR, $node, ''); } if(!$this->sandbox->checkInterface($implement->toString())){ $this->sandbox->validationError('Interface failed custom validation!', Error::VALID_INTERFACE_ERROR, $node, $implement->toString()); } } } } else if($node instanceof Node\Stmt\Interface_){ if(!$this->sandbox->allow_interfaces){ $this->sandbox->validationError('Sandboxed code attempted to define interface!', Error::DEFINE_INTERFACE_ERROR, $node); } if(!$this->sandbox->checkKeyword('interface')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'interface'); } if(!$node->name){ $this->sandbox->validationError('Sandboxed code attempted to define unnamed interface!', Error::DEFINE_INTERFACE_ERROR, $node, ''); } if(!$this->sandbox->checkInterface($node->name)){ $this->sandbox->validationError('Interface failed custom validation!', Error::VALID_INTERFACE_ERROR, $node, $node->name); } } else if($node instanceof Node\Stmt\Trait_){ if(!$this->sandbox->allow_traits){ $this->sandbox->validationError('Sandboxed code attempted to define trait!', Error::DEFINE_TRAIT_ERROR, $node); } if(!$this->sandbox->checkKeyword('trait')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'trait'); } if(!$node->name){ $this->sandbox->validationError('Sandboxed code attempted to define unnamed trait!', Error::DEFINE_TRAIT_ERROR, $node, ''); } if(!$this->sandbox->checkTrait($node->name)){ $this->sandbox->validationError('Trait failed custom validation!', Error::VALID_TRAIT_ERROR, $node, $node->name); } } else if($node instanceof Node\Stmt\TraitUse){ if(!$this->sandbox->checkKeyword('use')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'use'); } if(is_array($node->traits)){ foreach($node->traits as $trait){ /** * @var Node\Name $trait */ if(!$trait->toString()){ $this->sandbox->validationError('Sandboxed code attempted to use unnamed trait!', Error::DEFINE_TRAIT_ERROR, $node, ''); } if(!$this->sandbox->checkTrait($trait->toString())){ $this->sandbox->validationError('Trait failed custom validation!', Error::VALID_TRAIT_ERROR, $node, $trait->toString()); } } } } else if($node instanceof Node\Expr\Yield_){ if(!$this->sandbox->allow_generators){ $this->sandbox->validationError('Sandboxed code attempted to create a generator!', Error::GENERATOR_ERROR, $node); } if(!$this->sandbox->checkKeyword('yield')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'yield'); } } else if($node instanceof Node\Stmt\Global_){ if(!$this->sandbox->allow_globals){ $this->sandbox->validationError('Sandboxed code attempted to use global keyword!', Error::GLOBALS_ERROR, $node); } if(!$this->sandbox->checkKeyword('global')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'global'); } foreach($node->vars as $var){ /** * @var Node\Expr\Variable $var */ if($var instanceof Node\Expr\Variable){ if(!$this->sandbox->checkGlobal($var->name)){ $this->sandbox->validationError('Global failed custom validation!', Error::VALID_GLOBAL_ERROR, $node, $var->name); } } else { $this->sandbox->validationError('Sandboxed code attempted to pass non-variable to global keyword!', Error::DEFINE_GLOBAL_ERROR, $node); } } } else if($node instanceof Node\Expr\Variable){ if(!is_string($node->name)){ $this->sandbox->validationError('Sandboxed code attempted dynamically-named variable call!', Error::DYNAMIC_VAR_ERROR, $node); } if($node->name == $this->sandbox->name){ $this->sandbox->validationError('Sandboxed code attempted to access the PHPSandbox instance!', Error::SANDBOX_ACCESS_ERROR, $node); } if(in_array($node->name, CustomizedSandbox::$superglobals)){ if(!$this->sandbox->checkSuperglobal($node->name)){ $this->sandbox->validationError('Superglobal failed custom validation!', Error::VALID_SUPERGLOBAL_ERROR, $node, $node->name); } if($this->sandbox->overwrite_superglobals){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_get_superglobal', [new Node\Arg(new Node\Scalar\String_($node->name))], $node->getAttributes()); } } else { if(!$this->sandbox->checkVar($node->name)){ $this->sandbox->validationError('Variable failed custom validation!', Error::VALID_VAR_ERROR, $node, $node->name); } } } else if($node instanceof Node\Stmt\StaticVar){ if(!$this->sandbox->allow_static_variables){ $this->sandbox->validationError('Sandboxed code attempted to create static variable!', Error::STATIC_VAR_ERROR, $node); } if(!is_string($node->var->name)){ $this->sandbox->validationError('Sandboxed code attempted dynamically-named static variable call!', Error::DYNAMIC_STATIC_VAR_ERROR, $node); } if(!$this->sandbox->checkVar($node->var->name)){ $this->sandbox->validationError('Variable failed custom validation!', Error::VALID_VAR_ERROR, $node, $node->var->name); } if($node->default instanceof Node\Expr\New_){ $node->default = $node->default->args[0]; } } else if($node instanceof Node\Stmt\Const_){ $this->sandbox->validationError('Sandboxed code cannot use const keyword in the global scope!', Error::GLOBAL_CONST_ERROR, $node); } else if($node instanceof Node\Expr\ConstFetch){ if(!$node->name instanceof Node\Name){ $this->sandbox->validationError('Sandboxed code attempted dynamically-named constant call!', Error::DYNAMIC_CONST_ERROR, $node); } if(!$this->sandbox->checkConst($node->name->toString())){ $this->sandbox->validationError('Constant failed custom validation!', Error::VALID_CONST_ERROR, $node, $node->name->toString()); } } else if($node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\StaticPropertyFetch){ $class = $node->class; if(!$class instanceof Node\Name){ $this->sandbox->validationError('Sandboxed code attempted dynamically-named class call!', Error::DYNAMIC_CLASS_ERROR, $node); } if($this->sandbox->isDefinedClass($class)){ $node->class = new Node\Name($this->sandbox->getDefinedClass($class)); } /** * @var Node\Name $class */ if(!$this->sandbox->checkClass($class->toString())){ $this->sandbox->validationError('Class constant failed custom validation!', Error::VALID_CLASS_ERROR, $node, $class->toString()); } return $node; } else if($node instanceof Node\Param && $node->type instanceof Node\Name){ $class = $node->type->toString(); if($this->sandbox->isDefinedClass($class)){ $node->type = new Node\Name($this->sandbox->getDefinedClass($class)); } return $node; } else if($node instanceof Node\Expr\New_){ if(!$this->sandbox->allow_objects){ $this->sandbox->validationError('Sandboxed code attempted to create object!', Error::CREATE_OBJECT_ERROR, $node); } if(!$this->sandbox->checkKeyword('new')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'new'); } if(!$node->class instanceof Node\Name){ $this->sandbox->validationError('Sandboxed code attempted dynamically-named class call!', Error::DYNAMIC_CLASS_ERROR, $node); } $class = $node->class->toString(); if($this->sandbox->isDefinedClass($class)){ $node->class = new Node\Name($this->sandbox->getDefinedClass($class)); } $this->sandbox->checkType($class); return $node; } else if($node instanceof Node\Expr\ErrorSuppress){ if(!$this->sandbox->allow_error_suppressing){ $this->sandbox->validationError('Sandboxed code attempted to suppress error!', Error::ERROR_SUPPRESS_ERROR, $node); } } else if($node instanceof Node\Expr\AssignRef){ if(!$this->sandbox->allow_references){ $this->sandbox->validationError('Sandboxed code attempted to assign by reference!', Error::BYREF_ERROR, $node); } } else if($node instanceof Node\Stmt\HaltCompiler){ if(!$this->sandbox->allow_halting){ $this->sandbox->validationError('Sandboxed code attempted to halt compiler!', Error::HALT_ERROR, $node); } if(!$this->sandbox->checkKeyword('halt')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'halt'); } } else if($node instanceof Node\Stmt\Namespace_){ if(!$this->sandbox->allow_namespaces){ $this->sandbox->validationError('Sandboxed code attempted to define namespace!', Error::DEFINE_NAMESPACE_ERROR, $node); } if(!$this->sandbox->checkKeyword('namespace')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'namespace'); } if($node->name instanceof Node\Name){ $namespace = $node->name->toString(); $this->sandbox->checkNamespace($namespace); if(!$this->sandbox->isDefinedNamespace($namespace)){ $this->sandbox->defineNamespace($namespace); } } else { $this->sandbox->validationError('Sandboxed code attempted use invalid namespace!', Error::DEFINE_NAMESPACE_ERROR, $node); } return $node->stmts; } else if($node instanceof Node\Stmt\Use_){ if(!$this->sandbox->allow_aliases){ $this->sandbox->validationError('Sandboxed code attempted to use namespace and/or alias!', Error::DEFINE_ALIAS_ERROR, $node); } if(!$this->sandbox->checkKeyword('use')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'use'); } foreach($node->uses as $use){ /** * @var Node\Stmt\UseUse $use */ if($use instanceof Node\Stmt\UseUse && $use->name instanceof Node\Name && (is_string($use->alias) || $use->alias instanceof Node\Identifier || is_null($use->alias))){ $this->sandbox->checkAlias($use->name->toString()); if($use->alias){ if(!$this->sandbox->checkKeyword('as')){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'as'); } } $this->sandbox->whitelistClass($use->getAlias()); $this->sandbox->whitelistType($use->getAlias()); $this->sandbox->defineAlias($use->name->toString(), $use->getAlias()); } else { $this->sandbox->validationError('Sandboxed code attempted use invalid namespace or alias!', Error::DEFINE_ALIAS_ERROR, $node); } } return NodeTraverser::REMOVE_NODE; } else if($node instanceof Node\Expr\ShellExec){ if($this->sandbox->isDefinedFunc('shell_exec')){ $args = [ new Node\Arg(new Node\Scalar\String_('shell_exec')), new Node\Arg(new Node\Scalar\String_(implode('', $node->parts))) ]; return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); } if($this->sandbox->hasWhitelistedFuncs()){ if(!$this->sandbox->isWhitelistedFunc('shell_exec')){ $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks when the shell_exec function is not whitelisted!', Error::BACKTICKS_ERROR, $node); } } else if($this->sandbox->hasBlacklistedFuncs() && $this->sandbox->isBlacklistedFunc('shell_exec')){ $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks when the shell_exec function is blacklisted!', Error::BACKTICKS_ERROR, $node); } if(!$this->sandbox->allow_backticks){ $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks!', Error::BACKTICKS_ERROR, $node); } } else if($name = $this->isMagicConst($node)){ if(!$this->sandbox->checkMagicConst($name)){ $this->sandbox->validationError('Magic constant failed custom validation!', Error::VALID_MAGIC_CONST_ERROR, $node, $name); } if($this->sandbox->isDefinedMagicConst($name)){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_get_magic_const', [new Node\Arg(new Node\Scalar\String_($name))], $node->getAttributes()); } else if(($filepath = $this->sandbox->getExecutingFile()) && in_array($name, ['__DIR__', '__FILE__'], true)){ return new Node\Scalar\String_($name === '__DIR__' ? dirname($filepath) : $filepath); } } else if($name = $this->isKeyword($node)){ if(!$this->sandbox->checkKeyword($name)){ $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, $name); } if($node instanceof Node\Expr\Include_ && !$this->sandbox->allow_includes){ $this->sandbox->validationError('Sandboxed code attempted to include files!', Error::INCLUDE_ERROR, $node, $name); } else if($node instanceof Node\Expr\Include_ && ( ($node->type == Node\Expr\Include_::TYPE_INCLUDE && $this->sandbox->isDefinedFunc('include')) || ($node->type == Node\Expr\Include_::TYPE_INCLUDE_ONCE && $this->sandbox->isDefinedFunc('include_once')) || ($node->type == Node\Expr\Include_::TYPE_REQUIRE && $this->sandbox->isDefinedFunc('require')) || ($node->type == Node\Expr\Include_::TYPE_REQUIRE_ONCE && $this->sandbox->isDefinedFunc('require_once')) ) ){ return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', [new Node\Arg(new Node\Scalar\String_($name)), new Node\Arg($node->expr)], $node->getAttributes()); } else if($node instanceof Node\Expr\Include_ && $this->sandbox->sandbox_includes){ switch($node->type){ case Node\Expr\Include_::TYPE_INCLUDE_ONCE: return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_include_once', [new Node\Arg($node->expr)], $node->getAttributes()); case Node\Expr\Include_::TYPE_REQUIRE: return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_require', [new Node\Arg($node->expr)], $node->getAttributes()); case Node\Expr\Include_::TYPE_REQUIRE_ONCE: return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_require_once', [new Node\Arg($node->expr)], $node->getAttributes()); case Node\Expr\Include_::TYPE_INCLUDE: default: return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_include', [new Node\Arg($node->expr)], $node->getAttributes()); } } } else if($name = $this->isOperator($node)){ if(!$this->sandbox->checkOperator($name)){ $this->sandbox->validationError('Operator failed custom validation!', Error::VALID_OPERATOR_ERROR, $node, $name); } } else if($name = $this->isPrimitive($node)){ if(!$this->sandbox->checkPrimitive($name)){ $this->sandbox->validationError('Primitive failed custom validation!', Error::VALID_PRIMITIVE_ERROR, $node, $name); } } return null; } /** Test the current PhpParser_Node node to see if it is a magic constant, and return the name if it is and null if it is not * * @param Node $node The sandboxed $node to test * * @return string|null Return string name of node, or null if it is not a magic constant */ protected function isMagicConst(Node $node) : ?string { return ($node instanceof Node\Scalar\MagicConst) ? $node->getName() : null; } /** Test the current PhpParser_Node node to see if it is a keyword, and return the name if it is and null if it is not * * @param Node $node The sandboxed $node to test * * @return string|null Return string name of node, or null if it is not a keyword */ protected function isKeyword(Node $node) : ?string { switch($node->getType()){ case 'Expr_Eval': return 'eval'; case 'Expr_Exit': return 'exit'; case 'Expr_Include': return 'include'; case 'Stmt_Echo': case 'Expr_Print': //for our purposes print is treated as functionally equivalent to echo return 'echo'; case 'Expr_Clone': return 'clone'; case 'Expr_Empty': return 'empty'; case 'Expr_Yield': return 'yield'; case 'Stmt_Goto': case 'Stmt_Label': //no point in using labels without goto return 'goto'; case 'Stmt_If': case 'Stmt_Else': //no point in using ifs without else case 'Stmt_ElseIf': //no point in using ifs without elseif return 'if'; case 'Stmt_Break': return 'break'; case 'Stmt_Switch': case 'Stmt_Case': //no point in using cases without switch return 'switch'; case 'Stmt_Try': case 'Stmt_Catch': //no point in using catch without try case 'Stmt_TryCatch': //no point in using try, catch or finally without try return 'try'; case 'Stmt_Throw': return 'throw'; case 'Stmt_Unset': return 'unset'; case 'Stmt_Return': return 'return'; case 'Stmt_Static': return 'static'; case 'Stmt_While': case 'Stmt_Do': //no point in using do without while return 'while'; case 'Stmt_Declare': case 'Stmt_DeclareDeclare': //no point in using declare key=>value without declare return 'declare'; case 'Stmt_For': case 'Stmt_Foreach': //no point in using foreach without for return 'for'; case 'Expr_Instanceof': return 'instanceof'; case 'Expr_Isset': return 'isset'; case 'Expr_List': return 'list'; } return null; } /** Test the current PhpParser_Node node to see if it is an operator, and return the name if it is and null if it is not * * @param Node $node The sandboxed $node to test * * @return string|null Return string name of node, or null if it is not an operator */ protected function isOperator(Node $node) : ?string { switch($node->getType()){ case 'Expr_Assign': return '='; case 'Expr_AssignBitwiseAnd': return '&='; case 'Expr_AssignBitwiseOr': return '|='; case 'Expr_AssignBitwiseXor': return '^='; case 'Expr_AssignConcat': return '.='; case 'Expr_AssignDiv': return '/='; case 'Expr_AssignMinus': return '-='; case 'Expr_AssignMod': return '%='; case 'Expr_AssignMul': return '*='; case 'Expr_AssignPlus': return '+='; case 'Expr_AssignRef': return '=&'; case 'Expr_AssignShiftLeft': return '<<='; case 'Expr_AssignShiftRight': return '>>='; case 'Expr_BitwiseAnd': return '&'; case 'Expr_BitwiseNot': return '~'; case 'Expr_BitwiseOr': return '|'; case 'Expr_BitwiseXor': return '^'; case 'Expr_BooleanAnd': return '&&'; case 'Expr_BooleanNot': return '!'; case 'Expr_BooleanOr': return '||'; case 'Expr_Concat': return '.'; case 'Expr_Div': return '/'; case 'Expr_Equal': return '=='; case 'Expr_Greater': return '>'; case 'Expr_GreaterOrEqual': return '>='; case 'Expr_Identical': return '==='; case 'Expr_LogicalAnd': return 'and'; case 'Expr_LogicalOr': return 'or'; case 'Expr_LogicalXor': return 'xor'; case 'Expr_Minus': return '-'; case 'Expr_Mod': return '%'; case 'Expr_Mul': return '*'; case 'Expr_NotEqual': return '!='; case 'Expr_NotIdentical': return '!=='; case 'Expr_Plus': return '+'; case 'Expr_PostDec': return 'n--'; case 'Expr_PostInc': return 'n++'; case 'Expr_PreDec': return '--n'; case 'Expr_PreInc': return '++n'; case 'Expr_ShiftLeft': return '<<'; case 'Expr_ShiftRight': return '>>'; case 'Expr_Smaller': return '<'; case 'Expr_SmallerOrEqual': return '<='; case 'Expr_Ternary': return '?'; case 'Expr_UnaryMinus': return '-n'; case 'Expr_UnaryPlus': return '+n'; } return null; } /** Test the current PhpParser_Node node to see if it is a primitive, and return the name if it is and null if it is not * * @param Node $node The sandboxed $node to test * * @return string|null Return string name of node, or null if it is not a primitive */ protected function isPrimitive(Node $node) : ?string { switch($node->getType()){ case 'Expr_Cast_Array': case 'Expr_Array': return 'array'; case 'Expr_Cast_Bool': //booleans are treated as constants otherwise. . . return 'bool'; case 'Expr_Cast_String': case 'Scalar_String': case 'Scalar_Encapsed': return 'string'; case 'Expr_Cast_Double': case 'Scalar_DNumber': return 'float'; case 'Expr_Cast_Int': case 'Scalar_LNumber': return 'int'; case 'Expr_Cast_Object': return 'object'; } return null; } }