Adding tests for securing private variable inclussion on templates.
[akelos.git] / vendor / PHPCodeAnalyzer / PHPCodeAnalyzer.php
bloba0f518aeb98d5e10f860f32689b2ae8a786e9af5
1 <?php
2 /**
3 * A class for performing code analysis for php scripts
4 * It is designed to be the heart of a code limiting script
5 * to use with Savant {@link http://phpsavant.com}
7 * This code should be php4 compatiable but i've only run it in php5 and some of the Tokenizer constants have changed
9 * @author Joshua Eichorn <josh@bluga.net>
10 * @copyright Joshua Eichorn 2004
11 * @package PHPCodeAnalyzer
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of the
16 * License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * @license http://www.gnu.org/copyleft/lesser.html LGPL
26 /**#@+
27 * compat tokeniezer defines
29 if (! defined('T_OLD_FUNCTION')) {
30 define('T_OLD_FUNCTION', T_FUNCTION);
32 if (!defined('T_ML_COMMENT')) {
33 define('T_ML_COMMENT', T_COMMENT);
34 } else {
35 define('T_DOC_COMMENT', T_ML_COMMENT);
37 /**#@-*/
39 /**
40 * Code Analysis class
42 * Example Usage:
43 * <code>
44 * $analyzer = new PHPCodeAnalyzer();
45 * $analyzer->source = file_get_contents(__FILE__);
46 * $analyzer->analyze();
47 * print_r($analyzer->calledMethods);
48 * </code>
50 * @todo is it important to grab the details from creating new functions defines classes?
51 * @todo support php5 only stuff like interface
53 * @version 0.4
54 * @license http://www.gnu.org/copyleft/lesser.html LGPL
55 * @copyright Joshua Eichorn 2004
56 * @package PHPCodeAnalyzer
57 * @author Joshua Eichorn <josh@bluga.net>
59 class PHPCodeAnalyzer
61 /**
62 * Source code to analyze
64 var $source = "";
66 /**
67 * functions called
69 var $calledFunctions = array();
71 /**
72 * Called constructs
74 var $calledConstructs = array();
76 /**
77 * methods called
79 var $calledMethods = array();
81 /**
82 * static methods called
84 var $calledStaticMethods = array();
86 /**
87 * new classes instantiated
89 var $classesInstantiated = array();
91 /**
92 * variables used
94 var $usedVariables = array();
96 /**
97 * member variables used
99 var $usedMemberVariables = array();
102 * classes created
104 var $createdClasses = array();
107 * functions created
109 var $createdFunctions = array();
112 * Files includes or requried
114 var $filesIncluded = array();
116 // private variables
117 /**#@+
118 * @access private
120 var $currentString = null;
121 var $currentStrings = null;
122 var $currentVar = false;
123 var $staticClass = false;
124 var $inNew = false;
125 var $inInclude = false;
126 var $lineNumber = 1;
127 /**#@-*/
130 * parse source filling informational arrays
132 function analyze()
134 $tokens = token_get_all($this->source);
136 // mapping of token to method to call
137 $handleMap = array(
138 T_STRING => 'handleString',
139 T_CONSTANT_ENCAPSED_STRING => 'handleString',
140 T_ENCAPSED_AND_WHITESPACE => 'handleString',
141 T_CHARACTER => 'handleString',
142 T_NUM_STRING => 'handleString',
143 T_DNUMBER => 'handleString',
144 T_FUNC_C => 'handleString',
145 T_CLASS_C => 'handleString',
146 T_FILE => 'handleString',
147 T_LINE => 'handleString',
148 T_DOUBLE_ARROW => 'handleString',
150 T_ARRAY => 'handleClearStrings',
151 T_CONCAT_EQUAL => 'handleClearStrings',
153 T_DOUBLE_COLON => 'handleDoubleColon',
154 T_NEW => 'handleNew',
155 T_OBJECT_OPERATOR => 'handleObjectOperator',
156 T_VARIABLE => 'handleVariable',
157 T_FUNCTION => 'handleFunction',
158 T_OLD_FUNCTION => 'handleFunction',
159 T_CLASS => 'handleClass',
160 T_WHITESPACE => 'handleWhitespace',
161 T_INLINE_HTML => 'handleWhitespace',
162 T_OPEN_TAG => 'handleWhitespace',
163 T_CLOSE_TAG => 'handleWhitespace',
165 T_AS => 'handleAs',
167 T_ECHO => 'handleConstruct',
168 T_EVAL => 'handleConstruct',
169 T_UNSET => 'handleConstruct',
170 T_ISSET => 'handleConstruct',
171 T_PRINT => 'handleConstruct',
172 T_FOR => 'handleConstruct',
173 T_FOREACH=> 'handleConstruct',
174 T_EMPTY => 'handleConstruct',
175 T_EXIT => 'handleConstruct',
176 T_CASE => 'handleConstruct',
177 T_GLOBAL=> 'handleConstruct',
178 T_UNSET => 'handleConstruct',
179 T_WHILE => 'handleConstruct',
180 T_DO => 'handleConstruct',
181 T_IF => 'handleConstruct',
182 T_LIST => 'handleConstruct',
183 T_RETURN=> 'handleConstruct',
184 T_STATIC=> 'handleConstruct',
185 T_ENDFOR=> 'handleConstruct',
186 T_ENDFOREACH=> 'handleConstruct',
187 T_ENDIF=> 'handleConstruct',
188 T_ENDSWITCH=> 'handleConstruct',
189 T_ENDWHILE=> 'handleConstruct',
191 T_INCLUDE => 'handleInclude',
192 T_INCLUDE_ONCE => 'handleInclude',
193 T_REQUIRE => 'handleInclude',
194 T_REQUIRE_ONCE => 'handleInclude',
197 foreach($tokens as $token)
199 if (is_string($token))
201 // we have a simple 1-character token
202 $this->handleSimpleToken($token);
204 else
206 list($id, $text) = $token;
207 if (isset($handleMap[$id]))
209 $call = $handleMap[$id];
210 $this->$call($id,$text);
212 /*else * /
214 echo token_name($id).": $text<br>\n";
215 } /* */
221 * Handle a 1 char token
222 * @access private
224 function handleSimpleToken($token)
226 if ($token !== ";")
228 $this->currentStrings .= $token;
230 switch($token)
232 case "(":
233 // method is called
234 if ($this->staticClass !== false)
236 if (!isset($this->calledStaticMethods[$this->staticClass][$this->currentString]))
238 $this->calledStaticMethods[$this->staticClass][$this->currentString]
239 = array();
241 $this->calledStaticMethods[$this->staticClass][$this->currentString][]
242 = $this->lineNumber;
243 $this->staticClass = false;
245 else if ($this->currentVar !== false)
247 if (!isset($this->calledMethods[$this->currentVar][$this->currentString]))
249 $this->calledMethods[$this->currentVar][$this->currentString] = array();
251 $this->calledMethods[$this->currentVar][$this->currentString][] = $this->lineNumber;
252 $this->currentVar = false;
254 else if ($this->inNew !== false)
256 $this->classInstantiated();
258 else if ($this->currentString !== null)
260 $this->functionCalled();
262 //$this->currentString = null;
263 break;
264 case "=":
265 case ";":
266 if ($this->inNew !== false)
268 $this->classInstantiated();
270 else if ($this->inInclude !== false)
272 $this->fileIncluded();
274 else if ($this->currentVar !== false)
276 $this->useMemberVar();
278 $this->currentString = null;
279 $this->currentStrings = null;
280 break;
282 case ']':
283 $this->useMemberVar(false);
284 break;
289 * handle includes and requires
290 * @access private
292 function handleInclude($id,$text)
294 $this->inInclude = true;
295 $this->handleConstruct($id,$text);
299 * handle String tokens
300 * @access private
302 function handleString($id,$text)
304 $this->currentString = $text;
305 $this->currentStrings .= $text;
309 * handle String tokens
310 * @access private
312 function handleClearStrings($id,$text)
314 $this->currentString = '';
318 * handle variables
319 * @access private
321 function handleVariable($id,$text)
323 $this->currentString = $text;
324 $this->currentStrings .= $text;
325 $this->useVariable();
330 * handle Double Colon tokens
331 * @access private
333 function handleDoubleColon($id,$text)
335 $this->staticClass = $this->currentString;
336 $this->currentString = null;
340 * handle new keyword
341 * @access private
343 function handleNew($id,$text)
345 $this->inNew = true;
349 * handle function
350 * @access private
352 function handleFunction($id,$text)
354 $this->createdFunctions[] = $this->lineNumber;
358 * handle class
359 * @access private
361 function handleClass($id,$text)
363 $this->createdClasses[] = $this->lineNumber;
367 * Handle ->
368 * @access private
370 function handleObjectOperator($id,$text)
372 $this->currentVar = $this->currentString;
373 $this->currentString = null;
374 $this->currentStrings .= $text;
378 * handle whitespace to figure out line counts
379 * @access private
381 function handleWhitespace($id,$text)
383 $this->lineNumber+=substr_count($text,"\n");
384 if ($id == T_CLOSE_TAG)
386 $this->handleSimpleToken(";");
392 * as has been used we must have a var before it
394 * @access private
396 function handleAs($id,$text)
398 $this->handleSimpleToken(";");
402 * a language construct has been called record it
403 * @access private
405 function handleConstruct($id,$construct)
407 if (!isset($this->calledConstructs[$construct]))
409 $this->calledConstructs[$construct] = array();
411 $this->calledConstructs[$construct][] = $this->lineNumber;
412 $this->currentString = null;
416 * a class was Instantiated record it
417 * @access private
419 function classInstantiated()
421 if (!isset($this->classesInstantiated[$this->currentString]))
423 $this->classesInstantiated[$this->currentString] = array();
425 $this->classesInstantiated[$this->currentString][] = $this->lineNumber;
426 $this->inNew = false;
430 * a file was included record it
431 * @access private
433 function fileIncluded()
435 if (!isset($this->filesIncluded[$this->currentStrings]))
437 $this->filesIncluded[$this->currentStrings] = array();
439 $this->filesIncluded[$this->currentStrings][] = $this->lineNumber;
440 $this->inInclude = false;
441 $this->currentString = null;
442 $this->currentStrings = "";
446 * a function was called record it
447 * @access private
449 function functionCalled($id = false)
451 $function_name = trim(rtrim($this->currentStrings,'('));
452 if(empty($this->currentStrings) || substr($function_name,-1) != ']'){
453 $function_name = $this->currentString;
454 if(strstr('"\'',substr($function_name,-1))){
455 $this->currentString = null;
456 return ;
460 if (!isset($this->calledFunctions[$function_name]))
462 $this->calledFunctions[$function_name] = array();
465 $this->calledFunctions[$function_name][] = $this->lineNumber;
466 $this->currentString = null;
470 * we used a member variable record it
471 * @access private
473 function useMemberVar($reset = true)
475 if (!isset($this->usedMemberVariables[$this->currentVar][$this->currentString])){
476 $this->usedMemberVariables[$this->currentVar][$this->currentString] = array();
478 $this->usedMemberVariables[$this->currentVar][$this->currentString][] = $this->lineNumber;
479 if($reset){
480 $this->currentVar = false;
481 $this->currentString = null;
486 * we used a variable record it
487 * @access private
489 function useVariable()
491 if (!isset($this->usedVariables[$this->currentString]))
493 $this->usedVariables[$this->currentString] = array();
495 $this->usedVariables[$this->currentString][] = $this->lineNumber;