| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4 // +----------------------------------------------------------------------+ 5 // | Akelos Framework - http://www.akelos.org | 6 // +----------------------------------------------------------------------+ 7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez | 8 // | Released under the GNU Lesser General Public License, see LICENSE.txt| 9 // +----------------------------------------------------------------------+ 10 11 require_once(AK_VENDOR_DIR.DS.'pear'.DS.'PHP'.DS.'Compat'.DS.'Constant'.DS.'T.php'); 12 13 /** 14 * @todo Avoid the ussage of globals in the PHP parser 15 */ 16 17 /** 18 * This is a modified version of the pear/PHP_Shell package by Jan Kneschke 19 * and is used for validating PHP in the interactive shell 20 * before terminating execution with fatal errors. 21 * 22 * @package ActiveSupport 23 * @subpackage Console 24 * @author Jan Kneschke <jan@kneschke.de> 25 * @author Bermi Ferrer <bermi a.t akelos c.om> 26 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org 27 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> 28 */ 29 class AkPhpParser 30 { 31 var $errors = array(); 32 var $code = ''; 33 34 function AkPhpParser($code) 35 { 36 $this->code = trim($code); 37 } 38 /** 39 * parse the PHP code 40 * 41 * we parse before we eval() the code to 42 * - fetch fatal errors before they come up 43 * - know about where we have to wait for closing braces 44 * 45 * @return int 0 if a executable statement is in the code-buffer, non-zero otherwise 46 */ 47 function parse() 48 { 49 50 $this->code = trim($this->code); 51 if (empty($this->code)){ 52 return 1; 53 } 54 55 $t = token_get_all('<?php '.$this->code.' ?>'); 56 57 $need_semicolon = 1; /* do we need a semicolon to complete the statement ? */ 58 $need_return = 1; /* can we prepend a return to the eval-string ? */ 59 $eval = ''; /* code to be eval()'ed later */ 60 $braces = array(); /* to track if we need more closing braces */ 61 62 $methods = array(); /* to track duplicate methods in a class declaration */ 63 $ts = array(); /* tokens without whitespaces */ 64 65 foreach ($t as $ndx => $token) { 66 if (is_array($token)) { 67 $ignore = 0; 68 69 switch($token[0]) { 70 case T_WHITESPACE: 71 case T_OPEN_TAG: 72 case T_CLOSE_TAG: 73 $ignore = 1; 74 break; 75 case T_FOREACH: 76 case T_DO: 77 case T_WHILE: 78 case T_FOR: 79 80 case T_IF: 81 case T_RETURN: 82 83 case T_CLASS: 84 case T_FUNCTION: 85 case T_INTERFACE: 86 87 case T_PRINT: 88 case T_ECHO: 89 90 case T_COMMENT: 91 case T_UNSET: 92 93 case T_INCLUDE: 94 case T_REQUIRE: 95 case T_INCLUDE_ONCE: 96 case T_REQUIRE_ONCE: 97 case T_TRY: 98 $need_return = 0; 99 break; 100 case T_VARIABLE: 101 case T_STRING: 102 case T_NEW: 103 case T_EXTENDS: 104 case T_IMPLEMENTS: 105 case T_OBJECT_OPERATOR: 106 case T_DOUBLE_COLON: 107 case T_INSTANCEOF: 108 109 case T_CATCH: 110 111 case T_ELSE: 112 case T_AS: 113 case T_LNUMBER: 114 case T_DNUMBER: 115 case T_CONSTANT_ENCAPSED_STRING: 116 case T_ENCAPSED_AND_WHITESPACE: 117 case T_CHARACTER: 118 case T_ARRAY: 119 case T_DOUBLE_ARROW: 120 121 case T_CONST: 122 case T_PUBLIC: 123 case T_PROTECTED: 124 case T_PRIVATE: 125 case T_ABSTRACT: 126 case T_STATIC: 127 case T_VAR: 128 129 case T_INC: 130 case T_DEC: 131 case T_SL: 132 case T_SL_EQUAL: 133 case T_SR: 134 case T_SR_EQUAL: 135 136 case T_IS_EQUAL: 137 case T_IS_IDENTICAL: 138 case T_IS_GREATER_OR_EQUAL: 139 case T_IS_SMALLER_OR_EQUAL: 140 141 case T_BOOLEAN_OR: 142 case T_LOGICAL_OR: 143 case T_BOOLEAN_AND: 144 case T_LOGICAL_AND: 145 case T_LOGICAL_XOR: 146 case T_MINUS_EQUAL: 147 case T_PLUS_EQUAL: 148 case T_MUL_EQUAL: 149 case T_DIV_EQUAL: 150 case T_MOD_EQUAL: 151 case T_XOR_EQUAL: 152 case T_AND_EQUAL: 153 case T_OR_EQUAL: 154 155 case T_FUNC_C: 156 case T_CLASS_C: 157 case T_LINE: 158 case T_FILE: 159 160 /* just go on */ 161 break; 162 default: 163 /* debug unknown tags*/ 164 error_log(sprintf("unknown tag: %d (%s): %s".PHP_EOL, $token[0], token_name($token[0]), $token[1])); 165 166 break; 167 } 168 if (!$ignore) { 169 $eval .= $token[1]." "; 170 $ts[] = array("token" => $token[0], "value" => $token[1]); 171 } 172 } else { 173 $ts[] = array("token" => $token, "value" => ''); 174 175 $last = count($ts) - 1; 176 177 switch ($token) { 178 case '(': 179 /* walk backwards through the tokens */ 180 181 if ($last >= 3 && 182 $ts[$last - 1]['token'] == T_STRING && 183 $ts[$last - 2]['token'] == T_OBJECT_OPERATOR && 184 $ts[$last - 3]['token'] == T_VARIABLE ) { 185 186 /* $object->method( */ 187 188 /* $object has to exist and has to be a object */ 189 $objname = $ts[$last - 3]['value']; 190 191 if (!isset($GLOBALS[ltrim($objname, '$')])) { 192 $this->addError(sprintf('Variable \'%s\' is not set', $objname)); 193 } 194 195 $k = ltrim($objname, '$'); 196 197 if(isset($GLOBALS[$k])){ 198 $object = $GLOBALS[$k]; 199 200 if (!is_object($object)) { 201 $this->addError(sprintf('Variable \'%s\' is not a class', $objname)); 202 } 203 204 $method = $ts[$last - 1]['value']; 205 206 /* obj */ 207 208 if (!method_exists($object, $method)) { 209 $this->addError(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 210 $objname, get_class($object), $method)); 211 } 212 } 213 } else if ($last >= 3 && 214 $ts[$last - 1]['token'] == T_VARIABLE && 215 $ts[$last - 2]['token'] == T_OBJECT_OPERATOR && 216 $ts[$last - 3]['token'] == T_VARIABLE ) { 217 218 /* $object->$method( */ 219 220 /* $object has to exist and has to be a object */ 221 $objname = $ts[$last - 3]['value']; 222 223 if (!isset($GLOBALS[ltrim($objname, '$')])) { 224 $this->addError(sprintf('Variable \'%s\' is not set', $objname)); 225 } 226 $object = $GLOBALS[ltrim($objname, '$')]; 227 228 if (!is_object($object)) { 229 $this->addError(sprintf('Variable \'%s\' is not a class', $objname)); 230 } 231 232 $methodname = $ts[$last - 1]['value']; 233 234 if (!isset($GLOBALS[ltrim($methodname, '$')])) { 235 $this->addError(sprintf('Variable \'%s\' is not set', $methodname)); 236 } 237 $method = $GLOBALS[ltrim($methodname, '$')]; 238 239 /* obj */ 240 241 if (!method_exists($object, $method)) { 242 $this->addError(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 243 $objname, get_class($object), $method)); 244 } 245 246 } else if ($last >= 6 && 247 $ts[$last - 1]['token'] == T_STRING && 248 $ts[$last - 2]['token'] == T_OBJECT_OPERATOR && 249 $ts[$last - 3]['token'] == ']' && 250 /* might be anything as index */ 251 $ts[$last - 5]['token'] == '[' && 252 $ts[$last - 6]['token'] == T_VARIABLE ) { 253 254 /* $object[...]->method( */ 255 256 /* $object has to exist and has to be a object */ 257 $objname = $ts[$last - 6]['value']; 258 259 if (!isset($GLOBALS[ltrim($objname, '$')])) { 260 $this->addError(sprintf('Variable \'%s\' is not set', $objname)); 261 } 262 $array = $GLOBALS[ltrim($objname, '$')]; 263 264 if (!is_array($array)) { 265 $this->addError(sprintf('Variable \'%s\' is not a array', $objname)); 266 } 267 268 $andx = $ts[$last - 4]['value']; 269 270 if (!isset($array[$andx])) { 271 $this->addError(sprintf('%s[\'%s\'] is not set', $objname, $andx)); 272 } 273 274 $object = $array[$andx]; 275 276 if (!is_object($object)) { 277 $this->addError(sprintf('Variable \'%s\' is not a class', $objname)); 278 } 279 280 $method = $ts[$last - 1]['value']; 281 282 /* obj */ 283 284 if (!method_exists($object, $method)) { 285 $this->addError(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 286 $objname, get_class($object), $method)); 287 } 288 289 } else if ($last >= 3 && 290 $ts[$last - 1]['token'] == T_STRING && 291 $ts[$last - 2]['token'] == T_DOUBLE_COLON && 292 $ts[$last - 3]['token'] == T_STRING ) { 293 294 /* Class::method() */ 295 296 /* $object has to exist and has to be a object */ 297 $classname = $ts[$last - 3]['value']; 298 299 if (!class_exists($classname)) { 300 $this->addError(sprintf('Class \'%s\' doesn\'t exist', $classname)); 301 } 302 303 $method = $ts[$last - 1]['value']; 304 305 if (!empty($method) && !in_array($method, (array)get_class_methods($classname))) { 306 $this->addError(sprintf("Class '%s' doesn't have a method named '%s'", 307 $classname, $method)); 308 } 309 } else if ($last >= 3 && 310 $ts[$last - 1]['token'] == T_VARIABLE && 311 $ts[$last - 2]['token'] == T_DOUBLE_COLON && 312 $ts[$last - 3]['token'] == T_STRING ) { 313 314 /* Class::method() */ 315 316 /* $object has to exist and has to be a object */ 317 $classname = $ts[$last - 3]['value']; 318 319 if (!class_exists($classname)) { 320 $this->addError(sprintf('Class \'%s\' doesn\'t exist', $classname)); 321 } 322 323 $methodname = $ts[$last - 1]['value']; 324 325 if (!isset($GLOBALS[ltrim($methodname, '$')])) { 326 $this->addError(sprintf('Variable \'%s\' is not set', $methodname)); 327 } 328 $method = $GLOBALS[ltrim($methodname, '$')]; 329 330 if (!in_array($method, get_class_methods($classname))) { 331 $this->addError(sprintf("Class '%s' doesn't have a method named '%s'", 332 $classname, $method)); 333 } 334 335 } else if ($last >= 2 && 336 $ts[$last - 1]['token'] == T_STRING && 337 $ts[$last - 2]['token'] == T_NEW ) { 338 339 /* new Class() */ 340 341 $classname = $ts[$last - 1]['value']; 342 343 if (!class_exists($classname)) { 344 $this->addError(sprintf('Class \'%s\' doesn\'t exist', $classname)); 345 } 346 347 if(AK_PHP5){ 348 $r = new ReflectionClass($classname); 349 350 if ($r->isAbstract()) { 351 $this->addError(sprintf("Can't instantiate abstract Class '%s'", $classname)); 352 } 353 354 if (!$r->isInstantiable()) { 355 $this->addError(sprintf('Class \'%s\' can\'t be instantiated. Is the class abstract ?', $classname)); 356 } 357 } 358 359 } else if ($last >= 2 && 360 $ts[0]['token'] != T_CLASS && 361 $ts[$last - 1]['token'] == T_STRING && 362 $ts[$last - 2]['token'] == T_FUNCTION ) { 363 364 /* make sure we are not a in class definition */ 365 366 /* function a() */ 367 368 $func = $ts[$last - 1]['value']; 369 370 if (function_exists($func)) { 371 $this->addError(sprintf('Function \'%s\' is already defined', $func)); 372 } 373 } else if ($last >= 4 && 374 $ts[0]['token'] == T_CLASS && 375 $ts[1]['token'] == T_STRING && 376 $ts[$last - 1]['token'] == T_STRING && 377 $ts[$last - 2]['token'] == T_FUNCTION ) { 378 379 /* make sure we are not a in class definition */ 380 381 /* class a { .. function a() ... } */ 382 383 $func = $ts[$last - 1]['value']; 384 $classname = $ts[1]['value']; 385 386 if (isset($methods[$func])) { 387 $this->addError(sprintf("Can't redeclare method '%s' in Class '%s'", $func, $classname)); 388 } 389 390 $methods[$func] = 1; 391 392 } else if ($last >= 1 && 393 $ts[$last - 1]['token'] == T_STRING ) { 394 /* func() */ 395 $funcname = $ts[$last - 1]['value']; 396 397 if (!function_exists($funcname)) { 398 $this->addError(sprintf("Function %s() doesn't exist", $funcname)); 399 } 400 } else if ($last >= 1 && 401 $ts[$last - 1]['token'] == T_VARIABLE ) { 402 403 /* $object has to exist and has to be a object */ 404 $funcname = $ts[$last - 1]['value']; 405 406 if (!isset($GLOBALS[ltrim($funcname, '$')])) { 407 $this->addError(sprintf('Variable \'%s\' is not set', $funcname)); 408 } 409 $k = ltrim($funcname, '$'); 410 411 if(isset($GLOBALS[$k])){ 412 $func = $GLOBALS[$k]; 413 414 if (!function_exists($func)) { 415 $this->addError(sprintf("Function %s() doesn't exist", $func)); 416 } 417 } 418 419 } 420 421 array_push($braces, $token); 422 break; 423 case '{': 424 $need_return = 0; 425 426 if ($last >= 2 && 427 $ts[$last - 1]['token'] == T_STRING && 428 $ts[$last - 2]['token'] == T_CLASS ) { 429 430 /* class name { */ 431 432 $classname = $ts[$last - 1]['value']; 433 434 if (class_exists($classname)) { 435 $this->addError(sprintf("Class '%s' can't be redeclared", $classname)); 436 } 437 } else if ($last >= 4 && 438 $ts[$last - 1]['token'] == T_STRING && 439 $ts[$last - 2]['token'] == T_EXTENDS && 440 $ts[$last - 3]['token'] == T_STRING && 441 $ts[$last - 4]['token'] == T_CLASS ) { 442 443 /* class classname extends classname { */ 444 445 $classname = $ts[$last - 3]['value']; 446 $extendsname = $ts[$last - 1]['value']; 447 448 if (class_exists($classname, false)) { 449 $this->addError(sprintf("Class '%s' can't be redeclared", 450 $classname)); 451 } 452 if (!class_exists($extendsname, false)) { 453 $this->addError(sprintf("Can't extend '%s' from not existing Class '%s'", 454 $classname, $extendsname)); 455 } 456 } else if ($last >= 4 && 457 $ts[$last - 1]['token'] == T_STRING && 458 $ts[$last - 2]['token'] == T_IMPLEMENTS && 459 $ts[$last - 3]['token'] == T_STRING && 460 $ts[$last - 4]['token'] == T_CLASS ) { 461 462 /* class name implements interface { */ 463 464 $classname = $ts[$last - 3]['value']; 465 $implements = $ts[$last - 1]['value']; 466 467 if (class_exists($classname, false)) { 468 $this->addError(sprintf("Class '%s' can't be redeclared", 469 $classname)); 470 } 471 if (!interface_exists($implements, false)) { 472 $this->addError(sprintf("Can't implement not existing Interface '%s' for Class '%s'", 473 $implements, $classname)); 474 } 475 } 476 477 array_push($braces, $token); 478 break; 479 case '}': 480 $need_return = 0; 481 case ')': 482 array_pop($braces); 483 break; 484 } 485 486 $eval .= $token; 487 } 488 } 489 490 $last = count($ts) - 1; 491 if ($last >= 2 && 492 $ts[$last - 0]['token'] == T_STRING && 493 $ts[$last - 1]['token'] == T_DOUBLE_COLON && 494 $ts[$last - 2]['token'] == T_STRING ) { 495 496 /* Class::constant */ 497 498 /* $object has to exist and has to be a object */ 499 $classname = $ts[$last - 2]['value']; 500 501 if (!class_exists($classname)) { 502 $this->addError(sprintf('Class \'%s\' doesn\'t exist', $classname)); 503 } 504 505 $constname = $ts[$last - 0]['value']; 506 507 if(AK_PHP5){ 508 $c = new ReflectionClass($classname); 509 if (!$c->hasConstant($constname)) { 510 $this->addError(sprintf("Class '%s' doesn't have a constant named '%s'", 511 $classname, $constname)); 512 } 513 } 514 } else if ($last == 0 && 515 $ts[$last - 0]['token'] == T_VARIABLE ) { 516 517 /* $var */ 518 519 $varname = $ts[$last - 0]['value']; 520 521 if (!isset($GLOBALS[ltrim($varname, '$')])) { 522 $this->addError(sprintf('Variable \'%s\' is not set', $varname)); 523 } 524 } 525 526 527 $need_more = count($braces); 528 529 if ($need_more || ';' === $token) { 530 $need_semicolon = 0; 531 } 532 533 if ($need_return) { 534 $eval = "return ".$eval; 535 } 536 537 /* add a traling ; if necessary */ 538 if ($need_semicolon){ 539 $eval .= ';'; 540 } 541 542 if (!$need_more) { 543 $this->code = $eval; 544 } 545 546 return $need_more; 547 } 548 549 function addError($error) 550 { 551 $this->errors[$error] = ''; 552 } 553 554 function hasErrors() 555 { 556 return !empty($this->errors); 557 } 558 559 function getErrors() 560 { 561 return array_keys($this->errors); 562 } 563 564 } 565 566 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Oct 27 12:43:49 2008 | Cross-referenced by PHPXref 0.6 |