Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.42% covered (warning)
68.42%
26 / 38
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccessConditionExpression
68.42% covered (warning)
68.42%
26 / 38
50.00% covered (danger)
50.00%
1 / 2
13.15
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 evaluateCondition
62.50% covered (warning)
62.50%
20 / 32
0.00% covered (danger)
0.00%
0 / 1
13.27
1<?php
2
3/*******************
4
5DO NOT CHANGE!  This is a core UserFrosting file, and should not need to be changed by developers.
6
7********************/
8
9namespace UserFrosting;
10
11use PhpParser\Node;
12use PhpParser\ParserFactory;
13
14// Models the evaluation of an authorization condition expression, which is built as a boolean expression composed of AccessCondition method calls.
15class AccessConditionExpression {
16
17    protected $_app;        // The framework app to use (default Slim)
18    protected $_parser;
19    protected $_traverser;
20    protected $_prettyPrinter;
21    protected $_debug;
22
23    public function __construct($app, $debug = false){
24        // Use ParserFactory to create a parser instance
25        $parserFactory = new ParserFactory;
26        $this->_parser = $parserFactory->createForNewestSupportedVersion();
27        
28        $this->_traverser     = new \PhpParser\NodeTraverser;
29        $this->_prettyPrinter = new \PhpParser\PrettyPrinter\Standard;
30        $this->_debug = $debug;
31        $this->_app = $app;
32    }
33
34    // Evaluates a condition expression, based on the given parameters.  Returns true if the condition is passed for the given parameters, otherwise returns false.
35    public function evaluateCondition($condition, $params){
36        // Set the reserved `self` and `route` parameters.
37        // This replaces any values of `self` or `route` specified in the arguments, thus preventing them from being overridden in malicious user input.
38        $params['self'] = $this->_app->user->export();
39        
40        $route = $this->_app->router()->getCurrentRoute();
41        $params['route'] = $route->getParams();
42        
43        /* Traverse the parse tree, and execute all function calls as methods of class AccessCondition.
44           Replace the function node with the return value of the method.
45        */
46        $pv = new \ParserNodeFunctionEvaluator($params, $this->_debug);
47        $this->_traverser->addVisitor($pv);
48        
49        $code = "<?php $condition;";
50        
51        if ($this->_debug){
52            error_log("<pre>Evaluating access conditions:\n");
53            error_log($condition. "\n\n".
54            "on params: \n" .
55            print_r($params, true) . "\n" .
56            "</pre>");
57        }
58        
59        try {
60            
61            // parse
62            $stmts = $this->_parser->parse($code);    
63            
64            // traverse
65            $stmts = $this->_traverser->traverse($stmts);
66        
67            // Evaluate boolean statement.  It is safe to use eval() here, because our expression has been reduced entirely to a boolean expression.
68            // In PHP Parser 5.x, we need to extract the expression from the statement
69            $stmt = $stmts[0];
70            $expr = null;
71            
72            // Check if we have a Statement\Expression node and extract the expression
73            if ($stmt instanceof \PhpParser\Node\Stmt\Expression) {
74                $expr = $this->_prettyPrinter->prettyPrintExpr($stmt->expr);
75            } else {
76                // Fallback for other node types
77                $expr = $this->_prettyPrinter->prettyPrint([$stmt]);
78            }
79            
80            $expr_eval = "return " . $expr . ";\n";
81            $result = eval($expr_eval);
82            
83            if ($this->_debug){
84                error_log("<pre>\"$expr\" evaluates to " . ($result == true ? "true" : "false") . "</pre>");
85            }
86            
87            return $result;
88        } catch (\PhpParser\Error $e) {
89            if ($this->_debug){
90                error_log("Error parsing access condition \"$condition\": \n" . $e->getMessage());
91            }
92            return false;   // Access fails if the access condition can't be parsed.
93        } catch (\UserFrosting\AuthorizationException $e) {
94            if ($this->_debug){
95                error_log("Error parsing access condition \"$condition\": \n" . $e->getMessage());
96            }
97            return false;
98        }
99    }
100
101}