[ Index ]
 

Code source de PHPonTrax 2.6.6-svn

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/vendor/trax/php_shell/ -> shell.php (source)

   1  <?php
   2  /**
   3   *  (PHP 5)
   4   *
   5   *  @package PHPonTrax
   6   *  @version $Id:$
   7   *  @copyright (c) 2005 John Peterson
   8   *
   9   *  Permission is hereby granted, free of charge, to any person obtaining
  10   *  a copy of this software and associated documentation files (the
  11   *  "Software"), to deal in the Software without restriction, including
  12   *  without limitation the rights to use, copy, modify, merge, publish,
  13   *  distribute, sublicense, and/or sell copies of the Software, and to
  14   *  permit persons to whom the Software is furnished to do so, subject to
  15   *  the following conditions:
  16   *
  17   *  The above copyright notice and this permission notice shall be
  18   *  included in all copies or substantial portions of the Software.
  19   *
  20   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21   *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22   *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23   *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24   *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25   *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26   *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27   */
  28   
  29  /*
  30  vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
  31  (c) 2006 Jan Kneschke <jan@kneschke.de>
  32  
  33  Permission is hereby granted, free of charge, to any person obtaining a copy of
  34  this software and associated documentation files (the "Software"), to deal in
  35  the Software without restriction, including without limitation the rights to
  36  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  37  of the Software, and to permit persons to whom the Software is furnished to do
  38  so, subject to the following conditions:
  39  
  40  The above copyright notice and this permission notice shall be included in all
  41  copies or substantial portions of the Software.
  42  
  43  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  44  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  45  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  46  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  47  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  48  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  49  SOFTWARE.
  50  */
  51  
  52  /**
  53  * A interactive PHP Shell
  54  * 
  55  * The more I work with other languages like python and ruby I like their way how they
  56  * work on problems. While PHP is very forgiving on errors, it is weak on the debugging
  57  * side. It was missing a simple to use interactive shell for years. Python and Ruby have
  58  * their ipython and iruby shell which give you a direct way to interact with the objects.
  59  * No need to write a script and execute it afterwards.
  60  * 
  61  * ChangeLog
  62  * 
  63  * 
  64  * Starting the Shell:
  65  * 
  66  * If you have a php-cli at hand you can open the shell by defining 'SHELL' 
  67  * and opening the PHP_Shell class file. 
  68  * 
  69  * <code>
  70  * $ php -v
  71  * PHP 5.1.4 (cli) (built: May  7 2006 20:52:45)
  72  * Copyright (c) 1997-2006 The PHP Group
  73  * Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies
  74  * 
  75  * $ php -r "define('SHELL', 1); require 'PHP/Shell.php';" 
  76  * </code>
  77  * If you only have php-cgi write a php-script:
  78  * 
  79  * <code>
  80  *     error_reporting(E_ALL);
  81  * 
  82  *     define("SHELL", 1);
  83  *     ## in case your terminal support colours:
  84  *     define("SHELL_HAS_COLOUR", 1);
  85  * 
  86  *     require "PHP/Shell.php";
  87  * </code>
  88  * 
  89  * and execute it with:
  90  * 
  91  * <pre>
  92  * $ php -q php-shell.php
  93  * </pre>
  94  * 
  95  * Inline Help
  96  *
  97  * <pre>
  98  * PHP-Shell - Version 0.2.0, with readline() support
  99  * (c) 2006, Jan Kneschke <jan@kneschke.de>
 100  * released under the terms of the PHP License 2.0
 101  * 
 102  * >> use '?' to open the inline help
 103  * 
 104  * >> ?
 105  * "inline help for the PHP-shell
 106  * 
 107  *   >> ?
 108  *     print this help
 109  *   >> ? <topic>
 110  *     get the doccomment for a class, method, property or function
 111  *   >> p <var>
 112  *     execute a verbose print (if implemented)
 113  *   >> quit
 114  *     leave shell
 115  * "
 116  * >> ? PHP_Shell
 117  * </pre>
 118  * Alternatives
 119  * 
 120  * - http://david.acz.org/phpa/
 121  * - http://www.hping.org/phpinteractive/
 122  * - the embedded interactive php-shell: $ php -a 
 123  * 
 124  * @package PHP
 125  */
 126  
 127  /**
 128  * PHP_Shell
 129  *
 130  * a interactive PHP Shell with tab-completion and history
 131  * it can catch FATAL errors before executing the code
 132  *
 133  * to customize the operation of the shell you can either 
 134  * extend the PHP_Shell class or declare a external autoload 
 135  * or error-handler. If you want to use your own print-out
 136  * functions declare __shell_print_vars(). 
 137  *
 138  * - __shell_error_handler() 
 139  * - __autoload()
 140  * - __shell_print_vars()
 141  *
 142  * To keep the namespace clashing between shell and your program 
 143  * as small as possible all public variables and functions from
 144  * the shell are prefixed with __shell:
 145  * 
 146  * - $__shell is the object of the shell
 147  *   can be read, this is the shell object itself, don't touch it
 148  * - $__shell_retval is the return value of the eval() before 
 149  *   it is printed
 150  *   can't be read, but overwrites existing vars with this name
 151  * - $__shell_exception is the catched Exception on Warnings, Notices, ..
 152  *   can't be read, but overwrites existing vars with this name
 153  * 
 154  * @package PHP
 155  */
 156  
 157  require_once("php_shell/shell_prototypes.php");
 158  
 159  class PHP_Shell {
 160      /** 
 161      * current code-buffer
 162      * @var string
 163      */
 164      protected $code; 
 165  
 166      /** 
 167      * set if 'p ...' is executed 
 168      * @var bool
 169      */
 170      protected $verbose; 
 171  
 172      /** 
 173      * set if readline support is enabled 
 174      * @var bool
 175      */
 176      protected $have_readline; 
 177  
 178      /** 
 179      * current version of the class 
 180      * @var string
 181      */
 182      protected $version = '0.2.7';
 183  
 184      /**
 185      * registered commands
 186      *
 187      * @var array
 188      * @see registerCommand
 189      */
 190      protected $commands;
 191  
 192      /**
 193      * does the use want to use the internal autoload ? 
 194      *
 195      * @var bool
 196      */
 197      protected $autoload = false;
 198      
 199  
 200      /**
 201      * shell colours
 202      *
 203      * @var array
 204      * @see setColourScheme
 205      */
 206      protected $colours;
 207  
 208      /**
 209      * shell colour schemes
 210      *
 211      * @var array
 212      * @see registerColourScheme
 213      */
 214      protected $colour_scheme;
 215  
 216      # shell colours
 217      const C_RESET = "\033[0m";
 218  
 219      const C_BLACK = "\033[0;30m";
 220      const C_RED = "\033[0;31m";
 221      const C_GREEN = "\033[0;32m";
 222      const C_BROWN = "\033[0;33m";
 223      const C_BLUE = "\033[0;34m";
 224      const C_PURPLE = "\033[0;35m";
 225      const C_CYAN = "\033[0;36m";
 226      const C_LIGHT_GRAY = "\033[0;37m";
 227  
 228      const C_GRAY = "\033[1;30m";
 229      const C_LIGHT_RED = "\033[1;31m";
 230      const C_LIGHT_GREEN = "\033[1;32m";
 231      const C_YELLOW = "\033[1;33m";
 232      const C_LIGHT_BLUE = "\033[1;34m";
 233      const C_LIGHT_PURPLE = "\033[1;35m";
 234      const C_LIGHT_CYAN = "\033[1;36m";
 235      const C_WHITE = "\033[1;37m";
 236  
 237      /**
 238      * init the shell and change if readline support is available
 239      */ 
 240      public function __construct() {
 241          $this->code = '';
 242          $this->vars = array();
 243  
 244          $this->stdin = null;
 245  
 246          $this->have_readline = function_exists('readline');
 247  
 248          if ($this->have_readline) {
 249              readline_completion_function('__shell_readline_complete');
 250          }
 251  
 252          $this->use_readline = true;
 253  
 254          $this->commands = array();
 255  
 256          $this->registerCommand('#^quit$#', 'cmdQuit', 'quit', 'leaves the shell');
 257          $this->registerCommand('#^\?$#', 'cmdHelp', '?', 'show this help');
 258          $this->registerCommand('#^\? #', 'cmdHelp', '? <var>', 'show the DocComment a Class, Method or Function'.PHP_EOL.'    e.g.: ? fopen(), ? PHP_Shell, ? $__shell');
 259          $this->registerCommand('#^p #', 'cmdPrint', 'p <var>', 'print the variable verbosly');
 260          $this->registerCommand('#^:set #', 'cmdSet', ':set <var>', 'set a shell variable');
 261  
 262          $this->registerColourScheme(
 263              "plain", array( 
 264                  "default"   => "", "value"     => "",
 265                  "exception" => "", "reset"     => ""));
 266  
 267          $this->registerColourScheme(
 268              "dark", array( 
 269                  "default"   => PHP_SHELL::C_YELLOW, 
 270                  "value"     => PHP_SHELL::C_WHITE,
 271                  "exception" => PHP_SHELL::C_PURPLE));
 272  
 273          $this->registerColourScheme(
 274              "light", array( 
 275                  "default"   => PHP_SHELL::C_BLACK, 
 276                  "value"     => PHP_SHELL::C_BLUE,
 277                  "exception" => PHP_SHELL::C_RED));
 278  
 279      }
 280  
 281      /**
 282      * register your own command for the shell
 283      *
 284      * @param string $regex a regex to match against the input line
 285      * @param string $callback a method in this class to call of the regex matches
 286      * @param string $cmd the command string for the help
 287      * @param string $help the full help description for this command
 288      */
 289      public function registerCommand($regex, $callback, $cmd, $help) {
 290          $this->commands[] = array(
 291              'regex' => $regex,
 292              'method' => $callback,
 293              'command' => $cmd,
 294              'description' => $help
 295          );
 296      }
 297      
 298      /**
 299      * parse the PHP code
 300      *
 301      * we parse before we eval() the code to
 302      * - fetch fatal errors before they come up
 303      * - know about where we have to wait for closing braces
 304      *
 305      * @return int 0 if a executable statement is in the code-buffer, non-zero otherwise
 306      */
 307      public function parse() {
 308          ## remove empty lines
 309          $this->code = trim($this->code);
 310          if ($this->code == '') return 1;
 311  
 312          $t = token_get_all('<?php '.$this->code.' ?>');
 313    
 314          $need_semicolon = 1; /* do we need a semicolon to complete the statement ? */
 315          $need_return = 1;    /* can we prepend a return to the eval-string ? */
 316          $eval = '';          /* code to be eval()'ed later */
 317          $braces = array();   /* to track if we need more closing braces */
 318  
 319          $methods = array();  /* to track duplicate methods in a class declaration */
 320          $ts = array();       /* tokens without whitespaces */
 321          
 322          foreach ($t as $ndx => $token) {
 323              if (is_array($token)) {
 324                  $ignore = 0;
 325        
 326                  switch($token[0]) {
 327                  case T_WHITESPACE:
 328                  case T_OPEN_TAG:
 329                  case T_CLOSE_TAG:
 330                      $ignore = 1;
 331                      break;
 332                  case T_FOREACH:
 333                  case T_DO:
 334                  case T_WHILE:
 335                  case T_FOR:
 336  
 337                  case T_IF:
 338                  case T_RETURN:
 339                      
 340                  case T_CLASS:
 341                  case T_FUNCTION:
 342                  case T_INTERFACE:
 343  
 344                  case T_PRINT:
 345                  case T_ECHO:
 346  
 347                  case T_COMMENT:
 348                  case T_UNSET:
 349  
 350                  case T_INCLUDE:
 351                  case T_REQUIRE:
 352                  case T_INCLUDE_ONCE:
 353                  case T_REQUIRE_ONCE:
 354                  case T_TRY:
 355                      $need_return = 0;
 356                      break;
 357                  case T_VARIABLE:
 358                  case T_STRING:
 359                  case T_NEW:
 360                  case T_EXTENDS:
 361                  case T_IMPLEMENTS:
 362                  case T_OBJECT_OPERATOR:
 363                  case T_DOUBLE_COLON:
 364                  case T_INSTANCEOF:
 365  
 366                  case T_CATCH:
 367  
 368                  case T_ELSE:
 369                  case T_AS:
 370                  case T_LNUMBER:
 371                  case T_DNUMBER:
 372                  case T_CONSTANT_ENCAPSED_STRING:
 373                  case T_ENCAPSED_AND_WHITESPACE:
 374                  case T_CHARACTER:
 375                  case T_ARRAY:
 376                  case T_DOUBLE_ARROW:
 377  
 378                  case T_CONST:
 379                  case T_PUBLIC:
 380                  case T_PROTECTED:
 381                  case T_PRIVATE:
 382                  case T_ABSTRACT:
 383                  case T_STATIC:
 384                  case T_VAR:
 385  
 386                  case T_INC:
 387                  case T_DEC:
 388                  case T_SL:
 389                  case T_SL_EQUAL:
 390                  case T_SR:
 391                  case T_SR_EQUAL:
 392  
 393                  case T_IS_EQUAL:
 394                  case T_IS_IDENTICAL:
 395                  case T_IS_GREATER_OR_EQUAL:
 396                  case T_IS_SMALLER_OR_EQUAL:
 397                      
 398                  case T_BOOLEAN_OR:
 399                  case T_LOGICAL_OR:
 400                  case T_BOOLEAN_AND:
 401                  case T_LOGICAL_AND:
 402                  case T_LOGICAL_XOR:
 403                  case T_MINUS_EQUAL:
 404                  case T_PLUS_EQUAL:
 405                  case T_MUL_EQUAL:
 406                  case T_DIV_EQUAL:
 407                  case T_MOD_EQUAL:
 408                  case T_XOR_EQUAL:
 409                  case T_AND_EQUAL:
 410                  case T_OR_EQUAL:
 411  
 412                  case T_FUNC_C:
 413                  case T_CLASS_C:
 414                  case T_LINE:
 415                  case T_FILE:
 416  
 417                      /* just go on */
 418                      break;
 419                  default:
 420                      /* debug unknown tags*/
 421                      error_log(sprintf("unknown tag: %d (%s): %s".PHP_EOL, $token[0], token_name($token[0]), $token[1]));
 422                      
 423                      break;
 424                  }
 425                  if (!$ignore) {
 426                      $eval .= $token[1]." ";
 427                      $ts[] = array("token" => $token[0], "value" => $token[1]);
 428                  }
 429              } else {
 430                  $ts[] = array("token" => $token, "value" => '');
 431  
 432                  $last = count($ts) - 1;
 433  
 434                  switch ($token) {
 435                  case '(':
 436                      /* walk backwards through the tokens */
 437  
 438                      if ($last >= 3 &&
 439                          $ts[$last - 1]['token'] == T_STRING &&
 440                          $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
 441                          $ts[$last - 3]['token'] == T_VARIABLE ) {
 442  
 443                          /* $object->method( */
 444  
 445                          /* $object has to exist and has to be a object */
 446                          $objname = $ts[$last - 3]['value'];
 447                         
 448                          if (!isset($GLOBALS[ltrim($objname, '$')])) {
 449                              throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
 450                          }
 451                          $object = $GLOBALS[ltrim($objname, '$')];
 452  
 453                          if (!is_object($object)) {
 454                              throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
 455                          }
 456                          
 457                          $method = $ts[$last - 1]['value'];
 458  
 459                          /* obj */
 460                          
 461                          if (!method_exists($object, $method)) {
 462                              throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 
 463                                  $objname, get_class($object), $method));
 464                          }
 465                      } else if ($last >= 3 &&
 466                          $ts[$last - 1]['token'] == T_VARIABLE &&
 467                          $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
 468                          $ts[$last - 3]['token'] == T_VARIABLE ) {
 469  
 470                          /* $object->$method( */
 471  
 472                          /* $object has to exist and has to be a object */
 473                          $objname = $ts[$last - 3]['value'];
 474                         
 475                          if (!isset($GLOBALS[ltrim($objname, '$')])) {
 476                              throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
 477                          }
 478                          $object = $GLOBALS[ltrim($objname, '$')];
 479  
 480                          if (!is_object($object)) {
 481                              throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
 482                          }
 483                          
 484                          $methodname = $ts[$last - 1]['value'];
 485  
 486                          if (!isset($GLOBALS[ltrim($methodname, '$')])) {
 487                              throw new Exception(sprintf('Variable \'%s\' is not set', $methodname));
 488                          }
 489                          $method = $GLOBALS[ltrim($methodname, '$')];
 490  
 491                          /* obj */
 492                          
 493                          if (!method_exists($object, $method)) {
 494                              throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 
 495                                  $objname, get_class($object), $method));
 496                          }
 497  
 498                      } else if ($last >= 6 &&
 499                          $ts[$last - 1]['token'] == T_STRING &&
 500                          $ts[$last - 2]['token'] == T_OBJECT_OPERATOR &&
 501                          $ts[$last - 3]['token'] == ']' &&
 502                              /* might be anything as index */
 503                          $ts[$last - 5]['token'] == '[' &&
 504                          $ts[$last - 6]['token'] == T_VARIABLE ) {
 505  
 506                          /* $object[...]->method( */
 507  
 508                          /* $object has to exist and has to be a object */
 509                          $objname = $ts[$last - 6]['value'];
 510                         
 511                          if (!isset($GLOBALS[ltrim($objname, '$')])) {
 512                              throw new Exception(sprintf('Variable \'%s\' is not set', $objname));
 513                          }
 514                          $array = $GLOBALS[ltrim($objname, '$')];
 515  
 516                          if (!is_array($array)) {
 517                              throw new Exception(sprintf('Variable \'%s\' is not a array', $objname));
 518                          }
 519  
 520                          $andx = $ts[$last - 4]['value'];
 521  
 522                          if (!isset($array[$andx])) {
 523                              throw new Exception(sprintf('%s[\'%s\'] is not set', $objname, $andx));
 524                          }
 525  
 526                          $object = $array[$andx];
 527  
 528                          if (!is_object($object)) {
 529                              throw new Exception(sprintf('Variable \'%s\' is not a class', $objname));
 530                          }
 531                          
 532                          $method = $ts[$last - 1]['value'];
 533  
 534                          /* obj */
 535                          
 536                          if (!method_exists($object, $method)) {
 537                              throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'", 
 538                                  $objname, get_class($object), $method));
 539                          }
 540  
 541                      } else if ($last >= 3 &&
 542                          $ts[$last - 1]['token'] == T_STRING &&
 543                          $ts[$last - 2]['token'] == T_DOUBLE_COLON &&
 544                          $ts[$last - 3]['token'] == T_STRING ) {
 545  
 546                          /* Class::method() */
 547  
 548                          /* $object has to exist and has to be a object */
 549                          $classname = $ts[$last - 3]['value'];
 550                         
 551                          if (!class_exists($classname)) {
 552                              throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
 553                          }
 554                          
 555                          $method = $ts[$last - 1]['value'];
 556  
 557                          if (!in_array($method, get_class_methods($classname))) {
 558                              throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'", 
 559                                  $classname, $method));
 560                          }
 561                      } else if ($last >= 3 &&
 562                          $ts[$last - 1]['token'] == T_VARIABLE &&
 563                          $ts[$last - 2]['token'] == T_DOUBLE_COLON &&
 564                          $ts[$last - 3]['token'] == T_STRING ) {
 565  
 566                          /* Class::method() */
 567  
 568                          /* $object has to exist and has to be a object */
 569                          $classname = $ts[$last - 3]['value'];
 570                         
 571                          if (!class_exists($classname)) {
 572                              throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
 573                          }
 574                          
 575                          $methodname = $ts[$last - 1]['value'];
 576  
 577                          if (!isset($GLOBALS[ltrim($methodname, '$')])) {
 578                              throw new Exception(sprintf('Variable \'%s\' is not set', $methodname));
 579                          }
 580                          $method = $GLOBALS[ltrim($methodname, '$')];
 581  
 582                          if (!in_array($method, get_class_methods($classname))) {
 583                              throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'", 
 584                                  $classname, $method));
 585                          }
 586  
 587                      } else if ($last >= 2 &&
 588                          $ts[$last - 1]['token'] == T_STRING &&
 589                          $ts[$last - 2]['token'] == T_NEW ) {
 590  
 591                          /* new Class() */
 592  
 593                          $classname = $ts[$last - 1]['value'];
 594  
 595                          if (!class_exists($classname)) {
 596                              throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
 597                          }
 598  
 599                          $r = new ReflectionClass($classname);
 600  
 601                          if ($r->isAbstract()) {
 602                              throw new Exception(sprintf("Can't instantiate abstract Class '%s'", $classname));
 603                          }
 604  
 605                          if (!$r->isInstantiable()) {
 606                              throw new Exception(sprintf('Class \'%s\' can\'t be instantiated. Is the class abstract ?', $classname));
 607                          }
 608  
 609                      } else if ($last >= 2 &&
 610                          $ts[0]['token'] != T_CLASS &&
 611                          $ts[$last - 1]['token'] == T_STRING &&
 612                          $ts[$last - 2]['token'] == T_FUNCTION ) {
 613  
 614                          /* make sure we are not a in class definition */
 615  
 616                          /* function a() */
 617  
 618                          $func = $ts[$last - 1]['value'];
 619  
 620                          if (function_exists($func)) {
 621                              throw new Exception(sprintf('Function \'%s\' is already defined', $func));
 622                          }
 623                      } else if ($last >= 4 &&
 624                          $ts[0]['token'] == T_CLASS &&
 625                          $ts[1]['token'] == T_STRING &&
 626                          $ts[$last - 1]['token'] == T_STRING &&
 627                          $ts[$last - 2]['token'] == T_FUNCTION ) {
 628  
 629                          /* make sure we are not a in class definition */
 630  
 631                          /* class a { .. function a() ... } */
 632  
 633                          $func = $ts[$last - 1]['value'];
 634                          $classname = $ts[1]['value'];
 635  
 636                          if (isset($methods[$func])) {
 637                              throw new Exception(sprintf("Can't redeclare method '%s' in Class '%s'", $func, $classname));
 638                          }
 639  
 640                          $methods[$func] = 1;
 641  
 642                      } else if ($last >= 1 &&
 643                          $ts[$last - 1]['token'] == T_STRING ) {
 644                          /* func() */
 645                          $funcname = $ts[$last - 1]['value'];
 646                          
 647                          if (!function_exists($funcname)) {
 648                              throw new Exception(sprintf("Function %s() doesn't exist", $funcname));
 649                          }
 650                      } else if ($last >= 1 &&
 651                          $ts[$last - 1]['token'] == T_VARIABLE ) {
 652      
 653                          /* $object has to exist and has to be a object */
 654                          $funcname = $ts[$last - 1]['value'];
 655                         
 656                          if (!isset($GLOBALS[ltrim($funcname, '$')])) {
 657                              throw new Exception(sprintf('Variable \'%s\' is not set', $funcname));
 658                          }
 659                          $func = $GLOBALS[ltrim($funcname, '$')];
 660  
 661                          if (!function_exists($func)) {
 662                              throw new Exception(sprintf("Function %s() doesn't exist", $func));
 663                          }
 664  
 665                      }
 666                      
 667                      array_push($braces, $token);
 668                      break;
 669                  case '{':
 670                      $need_return = 0;
 671  
 672                      if ($last >= 2 &&
 673                          $ts[$last - 1]['token'] == T_STRING &&
 674                          $ts[$last - 2]['token'] == T_CLASS ) {
 675  
 676                          /* class name { */
 677  
 678                          $classname = $ts[$last - 1]['value'];
 679  
 680                          if (class_exists($classname, false)) {
 681                              throw new Exception(sprintf("Class '%s' can't be redeclared", $classname));
 682                          }
 683                      } else if ($last >= 4 &&
 684                          $ts[$last - 1]['token'] == T_STRING &&
 685                          $ts[$last - 2]['token'] == T_EXTENDS &&
 686                          $ts[$last - 3]['token'] == T_STRING &&
 687                          $ts[$last - 4]['token'] == T_CLASS ) {
 688  
 689                          /* class classname extends classname { */
 690  
 691                          $classname = $ts[$last - 3]['value'];
 692                          $extendsname = $ts[$last - 1]['value'];
 693  
 694                          if (class_exists($classname, false)) {
 695                              throw new Exception(sprintf("Class '%s' can't be redeclared", 
 696                                  $classname));
 697                          }
 698                          if (!class_exists($extendsname, false)) {
 699                              throw new Exception(sprintf("Can't extend '%s' from not existing Class '%s'", 
 700                                  $classname, $extendsname));
 701                          }
 702                      } else if ($last >= 4 &&
 703                          $ts[$last - 1]['token'] == T_STRING &&
 704                          $ts[$last - 2]['token'] == T_IMPLEMENTS &&
 705                          $ts[$last - 3]['token'] == T_STRING &&
 706                          $ts[$last - 4]['token'] == T_CLASS ) {
 707  
 708                          /* class name implements interface { */
 709  
 710                          $classname = $ts[$last - 3]['value'];
 711                          $implements = $ts[$last - 1]['value'];
 712  
 713                          if (class_exists($classname, false)) {
 714                              throw new Exception(sprintf("Class '%s' can't be redeclared", 
 715                                  $classname));
 716                          }
 717                          if (!interface_exists($implements, false)) {
 718                              throw new Exception(sprintf("Can't implement not existing Interface '%s' for Class '%s'", 
 719                                  $implements, $classname));
 720                          }
 721                      }
 722  
 723                      array_push($braces, $token);
 724                      break;
 725                  case '}':
 726                      $need_return = 0;
 727                  case ')':
 728                      array_pop($braces);
 729                      break;
 730                  }
 731                    
 732                  $eval .= $token;
 733              }    
 734          }
 735  
 736          $last = count($ts) - 1;
 737          if ($last >= 2 &&
 738              $ts[$last - 0]['token'] == T_STRING &&
 739              $ts[$last - 1]['token'] == T_DOUBLE_COLON &&
 740              $ts[$last - 2]['token'] == T_STRING ) {
 741  
 742              /* Class::constant */
 743  
 744              /* $object has to exist and has to be a object */
 745              $classname = $ts[$last - 2]['value'];
 746             
 747              if (!class_exists($classname)) {
 748                  throw new Exception(sprintf('Class \'%s\' doesn\'t exist', $classname));
 749              }
 750              
 751              $constname = $ts[$last - 0]['value'];
 752  
 753              $c = new ReflectionClass($classname);
 754              if (!$c->hasConstant($constname)) {
 755                  throw new Exception(sprintf("Class '%s' doesn't have a constant named '%s'", 
 756                      $classname, $constname));
 757              }
 758          } else if ($last == 0 &&
 759              $ts[$last - 0]['token'] == T_VARIABLE ) {
 760  
 761              /* $var */
 762  
 763              $varname = $ts[$last - 0]['value'];
 764             
 765              if (!isset($GLOBALS[ltrim($varname, '$')])) {
 766                  throw new Exception(sprintf('Variable \'%s\' is not set', $varname));
 767              }
 768          }
 769  
 770  
 771          $need_more = count($braces);
 772          
 773          if ($need_more || ';' === $token) {
 774              $need_semicolon = 0;
 775          }  
 776    
 777          if ($need_return) {
 778              $eval = "return ".$eval;
 779          }
 780   
 781          /* add a traling ; if necessary */ 
 782          if ($need_semicolon) $eval .= ';';
 783          
 784          if (!$need_more) {
 785              $this->code = $eval;
 786          }
 787                  
 788          return $need_more;
 789      }
 790      
 791      /**
 792      * show the prompt and fetch a single line
 793      * 
 794      * uses readline() if avaialbe
 795      * 
 796      * @return string a input-line
 797      */
 798      public function readline() {
 799          if (empty($this->code)) print PHP_EOL;
 800  
 801          $prompt = (empty($this->code)) ? '>> ' : '.. ';
 802  
 803          if ($this->have_readline) {
 804              $l = readline($prompt);
 805  
 806              readline_add_history($l);
 807          } else {
 808              print $prompt;
 809  
 810              if (is_null($this->stdin)) {
 811                  if (false === ($this->stdin = fopen("php://stdin", "r"))) {
 812                      return false;
 813                  }
 814              }
 815              $l = fgets($this->stdin);
 816          }
 817          return $l;
 818      }
 819  
 820      /**
 821      * get the inline help
 822      *
 823      * @return string the inline help as string 
 824      */
 825      public function getHelp() {
 826          $o = 'Inline Help:'.PHP_EOL;
 827  
 828          foreach ($this->commands as $cmd) {
 829              $o .= sprintf('  >> %s'.PHP_EOL.'    %s'.PHP_EOL,
 830                  $cmd['command'],
 831                  $cmd['description']
 832              );
 833          }
 834  
 835          return $o;
 836      }
 837  
 838      /**
 839      * handle the 'quit' command
 840      *
 841      * @return bool false to leave the input() call
 842      * @see input
 843      */
 844      protected function cmdQuit($l) {
 845          return false;
 846      }
 847  
 848      /**
 849      * handle the 'p ' command
 850      *
 851      * set the verbose flag
 852      *
 853      * @return string the pure command-string without the 'p ' command
 854      */
 855      protected function cmdPrint($l) {
 856          $this->verbose = 1;
 857          $cmd = substr($l, 2);
 858  
 859          return $cmd;
 860      }
 861  
 862      /**
 863      * handle the '?' commands
 864      *
 865      * With the help of the Reflection Class we extract the DocComments and display them
 866      * For internal Functions we extract the prototype from the php source.
 867      *
 868      * ? Class::method()
 869      * ? $obj->method()
 870      * ? Class::property
 871      * ? $obj::property
 872      * ? Class
 873      * ? $obj
 874      * ? function()
 875      *
 876      * The license of the PHP_Shell class
 877      * ? license
 878      *
 879      * @return string the help text
 880      */
 881      protected function cmdHelp($l) {
 882          if ("? " == substr($l, 0, strlen("? "))) {
 883              $str = substr($l, 2);
 884  
 885              $cmd = '';
 886              
 887              if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\(\s*\)\s*#', $str, $a)) {
 888                  /* ? Class::method() */
 889  
 890                  $class = $a[1];
 891                  $method = $a[2];
 892  
 893                  if (false !== ($proto = PHP_ShellPrototypes::getInstance()->get($class.'::'.$method))) {
 894  
 895                      $cmd = sprintf("/**\n* %s\n\n* @params %s\n* @return %s\n*/\n",
 896                          $proto['description'],
 897                          $proto['params'],
 898                          $proto['return']
 899                      );
 900                  } else if (class_exists($class, false)) {
 901                      $c = new ReflectionClass($class);
 902  
 903                      if ($c->hasMethod($method)) {
 904                          $cmd = $c->getMethod($method)->getDocComment();
 905                      }
 906                  }
 907              } else if (preg_match('#^\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\(\s*\)\s*#', $str, $a)) {
 908                  /* ? $obj->method() */
 909                  if (isset($GLOBALS[$a[1]]) && is_object($GLOBALS[$a[1]])) {
 910                      $class = get_class($GLOBALS[$a[1]]);
 911                      $method = $a[2];
 912                      
 913                      $c = new ReflectionClass($class);
 914      
 915                      if ($c->hasMethod($method)) {
 916                          $cmd = $c->getMethod($method)->getDocComment();
 917                      }
 918                  }
 919              } else if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\s*$#', $str, $a)) { 
 920                  /* ? Class::property */
 921                  $class = $a[1];
 922                  $property = $a[2];
 923                  if (class_exists($class, false)) {
 924                      $c = new ReflectionClass($class);
 925  
 926                      if ($c->hasProperty($property)) {
 927                          $cmd = $c->getProperty($property)->getDocComment();
 928                      }
 929                  }
 930              } else if (preg_match('#^\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\s*$#', $str, $a)) { 
 931                  /* ? $obj->property */
 932                  if (isset($GLOBALS[$a[1]]) && is_object($GLOBALS[$a[1]])) {
 933                      $class = get_class($GLOBALS[$a[1]]);
 934                      $method = $a[2];
 935                      
 936                      $c = new ReflectionClass($class);
 937  
 938                      if ($c->hasProperty($property)) {
 939                          $cmd = $c->getProperty($property)->getDocComment();
 940                      }
 941  
 942                  }
 943              } else if (preg_match('#^([A-Za-z0-9_]+)$#', $str, $a)) {
 944                  /* ? Class */
 945                  if (class_exists($a[1], false)) {
 946                      $c = new ReflectionClass($a[1]);
 947                      $cmd = $c->getDocComment();
 948                  } else if ($a[1] == 'license') {
 949                      $cmd = <<<EOF
 950  (c) 2006 Jan Kneschke <jan@kneschke.de>
 951  
 952  Permission is hereby granted, free of charge, to any person obtaining a copy of
 953  this software and associated documentation files (the "Software"), to deal in
 954  the Software without restriction, including without limitation the rights to
 955  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 956  of the Software, and to permit persons to whom the Software is furnished to do
 957  so, subject to the following conditions:
 958  
 959  The above copyright notice and this permission notice shall be included in all
 960  copies or substantial portions of the Software.
 961  
 962  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 963  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 964  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 965  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 966  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 967  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 968  SOFTWARE.
 969  
 970  EOF;
 971                  }
 972              } else if (preg_match('#^\$([A-Za-z0-9_]+)$#', $str, $a)) {
 973                  /* ? $object */
 974                  $obj = $a[1];
 975                  if (isset($GLOBALS[$obj]) && is_object($GLOBALS[$obj])) {
 976                      $class = get_class($GLOBALS[$obj]);
 977  
 978                      $c = new ReflectionClass($class);
 979                      $cmd = $c->getDocComment();
 980                  }
 981  
 982              } else if (preg_match('#^([A-Za-z0-9_]+)\(\s*\)$#', $str, $a)) {
 983                  /* ? function() */
 984                  $func = $a[1];
 985  
 986                  if (false !== ($proto = PHP_ShellPrototypes::getInstance()->get($func))) {
 987                      $cmd = sprintf("/**\n* %s\n*\n* @params %s\n* @return %s\n*/\n",
 988                          $proto['description'],
 989                          $proto['params'],
 990                          $proto['return']
 991                      );
 992                  } else if (function_exists($func)) {
 993                      $c = new ReflectionFunction($func);
 994                      $cmd = $c->getDocComment();
 995                  }
 996              }
 997  
 998              if ($cmd == '') {
 999                  $cmd = var_export(sprintf('no help found for \'%s\'', $str), 1);
1000              } else {
1001                  $cmd = var_export($cmd, 1);
1002              }
1003          } else if ("?" == $l) {
1004              $cmd = $this->getHelp();
1005              $cmd = var_export($cmd, 1);
1006          }
1007  
1008          return $cmd;
1009      }
1010  
1011      /**
1012      * set a shell-var
1013      *
1014      * :set al to enable autoload
1015      * :set bg=dark to enable highlighting with a dark backgroud
1016      */
1017      public function cmdSet($l) {
1018          if (!preg_match('#:set\s+([a-z]+)\s*(?:=\s*([a-z0-9]+)\s*)?$#i', $l, $a)) {
1019              print('unknown :set syntax');
1020              return;
1021          }
1022  
1023          $key = $a[1];
1024  
1025          switch ($key) {
1026          case 'bg':
1027          case 'background':
1028              if (!isset($a[2])) {
1029                  print(':set '.$key.' failed: a value is required, example: :set '.$key.'=dark');
1030                  return;
1031              }
1032              if (false == $this->applyColourScheme($a[2])) {
1033                  print('setting colourscheme failed: colourscheme '.$a[2].' is unknown');
1034                  return;
1035              }
1036              break;
1037          case 'al':
1038          case 'autoload':
1039              if (function_exists('__autoload')) {
1040                  print('can\'t enabled autoload as a external __autoload() function is already defined');
1041                  return;
1042              }
1043  
1044              if ($this->autoload) {
1045                  print('autload is already enabled');
1046                  return;
1047              }
1048  
1049              $this->autoload = true;
1050              break;
1051          default:
1052              print (':set '.$key.' failed: unknown key');
1053              return;
1054          }
1055      }
1056      
1057      /**
1058      * handle the input line
1059      *
1060      * read the input and handle the commands of the shell
1061      *
1062      * @return bool false on 'quit' or EOF, true otherwise
1063      */
1064      public function input() {
1065          $l = $this->readline();
1066  
1067          /* got EOF ? */
1068          if (false === $l) return false;
1069  
1070          $l = trim($l);
1071          
1072          if (empty($this->code)) {
1073              $this->verbose = 0;
1074  
1075              foreach ($this->commands as $cmd) {
1076                  if (preg_match($cmd['regex'], $l)) {
1077                      $func = $cmd['method'];
1078  
1079                      if (false === ($l = $this->$func($l))) {
1080                          ## quit
1081                          return false;
1082                      }
1083                      break;
1084                  }
1085              }
1086          }
1087         
1088          $this->appendCode($l); 
1089  
1090          return true;
1091      }
1092  
1093      public function isAutoloadEnabled() {
1094          return $this->autoload;
1095      }
1096      
1097      /**
1098      * get the code-buffer
1099      * 
1100      * @return string the code-buffer
1101      */
1102      public function getCode() {
1103          return $this->code;
1104      }
1105      
1106      /**
1107      * reset the code-buffer
1108      */
1109      public function resetCode() {
1110          $this->code = '';
1111      }
1112   
1113      /**
1114      * append code to the code-buffer
1115      *
1116      * @param string $code input buffer
1117      */
1118      public function appendCode($code) {
1119          $this->code .= $code;
1120      }
1121     
1122      /**
1123      * check if we have a verbose print-out
1124      *
1125      * @return bool 1 if verbose, 0 otherwise
1126      */
1127      public function getVerbose() {
1128          return $this->verbose;
1129      }
1130  
1131      /**
1132      * check if readline support is enabled
1133      *
1134      * @return bool true if enabled, false otherwise
1135      */
1136      public function hasReadline() {
1137          return $this->have_readline;
1138      }
1139  
1140      /**
1141      * get version of the class
1142      *
1143      * @return string version-string
1144      */
1145      public function getVersion() {
1146          return $this->version;
1147      }
1148  
1149      /**
1150      * get a colour for the shell
1151      *
1152      * @param string $type one of (value|exception|reset|default)
1153      * @return string a colour string or a empty string
1154      */
1155      public function getColour($type) {
1156          return isset($this->colour[$type]) ? $this->colour[$type] : '';
1157      }
1158  
1159      /**
1160      * apply a colour scheme to the current shell
1161      *
1162      * @param string $scheme name of the scheme
1163      * @return false if colourscheme is not known, otherwise true
1164      */
1165      public function applyColourScheme($scheme) {
1166          if (!isset($this->colour_scheme[$scheme])) return false;
1167  
1168          $this->colour = $this->colour_scheme[$scheme];
1169  
1170          return true;
1171      }
1172  
1173      /**
1174      * registers a colour scheme
1175      *
1176      * @param string $scheme name of the colour scheme
1177      * @param array a array of colours
1178      */
1179      public function registerColourScheme($scheme, $colours) {
1180          if (!is_array($colours)) return;
1181  
1182          /* set a reset colour if it is not supplied from the outside */
1183          if (!isset($colours["reset"])) $colours["reset"] = PHP_SHELL::C_RESET;
1184  
1185          $this->colour_scheme[$scheme] = $colours;
1186      }
1187  }
1188  
1189  /**
1190  * a readline completion callback
1191  *
1192  * @param string $str linebuffer
1193  * @param integer $pos position in linebuffer
1194  * @return array list of possible matches
1195  */
1196  function __shell_readline_complete($str, $pos) {
1197      $in = readline_info('line_buffer');
1198  
1199      /**
1200      * parse the line-buffer backwards to see if we have a 
1201      * - constant
1202      * - function 
1203      * - variable
1204      */
1205  
1206      $m = array();
1207  
1208      if (preg_match('#\$([A-Za-z0-9_]+)->#', $in, $a)) {
1209          /* check for $o->... */
1210          $name = $a[1];
1211  
1212          if (isset($GLOBALS[$name]) && is_object($GLOBALS[$name])) {
1213              $c = get_class_methods($GLOBALS[$name]);
1214  
1215              foreach ($c as $v) {
1216                  $m[] = $v.'(';
1217              }
1218              $c = get_class_vars(get_class($GLOBALS[$name]));
1219  
1220              foreach ($c as $k => $v) {
1221                  $m[] = $k;
1222              }
1223  
1224              return $m;
1225          }
1226      } else if (preg_match('#\$([A-Za-z0-9_]+)\[([^\]]+)\]->#', $in, $a)) {
1227          /* check for $o[...]->... */
1228          $name = $a[1];
1229  
1230          if (isset($GLOBALS[$name]) && 
1231              is_array($GLOBALS[$name]) &&
1232              isset($GLOBALS[$name][$a[2]])) {
1233  
1234              $c = get_class_methods($GLOBALS[$name][$a[2]]);
1235  
1236              foreach ($c as $v) {
1237                  $m[] = $v.'(';
1238              }
1239              $c = get_class_vars(get_class($GLOBALS[$name][$a[2]]));
1240  
1241              foreach ($c as $k => $v) {
1242                  $m[] = $k;
1243              }
1244              return $m;
1245          }
1246  
1247      } else if (preg_match('#([A-Za-z0-9_]+)::#', $in, $a)) {
1248          /* check for Class:: */
1249          $name = $a[1];
1250  
1251          if (class_exists($name, false)) {
1252              $c = get_class_methods($name);
1253  
1254              foreach ($c as $v) {
1255                  $m[] = sprintf('%s::%s(', $name, $v);
1256              }
1257  
1258              $cl = new ReflectionClass($name);
1259              $c = $cl->getConstants();
1260  
1261              foreach ($c as $k => $v) {
1262                  $m[] = sprintf('%s::%s', $name, $k);
1263              }
1264  
1265              return $m;
1266          }
1267      } else if (preg_match('#\$([a-zA-Z]?[a-zA-Z0-9_]*)$#', $in)) {
1268          $m = array_keys($GLOBALS);
1269  
1270          return $m;
1271      } else if (preg_match('#new #', $in)) {
1272          $c = get_declared_classes();
1273      
1274          foreach ($c as $v) {
1275              $m[] = $v.'(';
1276          }
1277  
1278          return $m;
1279      } else if (preg_match('#^:set #', $in)) {
1280          $m[] = 'autoload';
1281          $m[] = 'background=';
1282  
1283          return $m;
1284      }
1285  
1286      $f = get_defined_functions();
1287  
1288      foreach ($f['internal'] as $v) {
1289          $m[] = $v.'(';
1290      }
1291  
1292      foreach ($f['user'] as $v) {
1293          $m[] = $v.'(';
1294      }
1295      
1296      $c = get_declared_classes();
1297  
1298      foreach ($c as $v) {
1299          $m[] = $v.'::';
1300      }
1301  
1302      $c = get_defined_constants();
1303  
1304      foreach ($c as $k => $v) {
1305          $m[] = $k;
1306      }
1307  
1308      $m[] = 'foreach (';
1309      $m[] = 'require';
1310  
1311      # printf("%s ... %s\n", $str, $pos);
1312      return $m;
1313  }
1314  
1315  


Généré le : Sun Feb 25 20:04:38 2007 par Balluche grâce à PHPXref 0.7