*/ /** Allow to interract with controllers and models from the CLI */ class cli { /** Run in CLI mode with parameters Example of cli code : #!/usr/bin/php5 run(); */ private $EXPERT = false; public function __construct () { // Catch the trigger_errors and display them politely set_error_handler(array(&$this, "cliErrorHandler")); } /** The error handler for CLI : display error in STDERR */ public function cliErrorHandler ($errno, $errstr, $errfile, $errline) { if (!(error_reporting() & $errno)) { // This error code is not included in error_reporting return; } switch($errno) { case E_ERROR: $severity = "ERROR"; break; case E_WARNING: $severity = "WARNING"; break; case E_PARSE: $severity = "PARSE"; break; case E_NOTICE: $severity = "NOTICE"; break; case E_CORE_ERROR: $severity = "CORE_ERROR"; break; case E_CORE_WARNING: $severity = "CORE_WARNING"; break; case E_COMPILE_ERROR: $severity = "COMPILE_ERROR"; break; case E_COMPILE_WARNING: $severity = "COMPILE_WARNING"; break; case E_USER_ERROR: $severity = "USER_ERROR"; break; case E_USER_WARNING: $severity = "USER_WARNING"; break; case E_USER_NOTICE: $severity = "USER_NOTICE"; break; case E_STRICT: $severity = "STRICT"; break; case E_RECOVERABLE_ERROR: $severity = "RECOVERABLE_ERROR"; break; case E_DEPRECATED: $severity = "DEPRECATED"; break; case E_USER_DEPRECATED: $severity = "USER_DEPRECATED"; break; } file_put_contents ("php://stderr", sprintf ("%-17s", $severity)." ". "$errstr [".basename ($errfile) . ":$errline]\n"); if ($this->EXPERT) { $e = new Exception; file_put_contents ("php://stderr", print_r ($e->getTraceAsString(), TRUE)."\n"); } } public function run () { global $argv; $launcher = $argv[0]; chdir (dirname ($argv[0])."/.."); array_shift ($argv); if (isset ($argv[0]) && $argv[0] === "-h") { echo "Execute in CLI a controller or a model (in expert mode)\n"; echo " $launcher -h : display this help\n"; echo " $launcher -list : display controllers\n"; echo " $launcher -expert -list : display controllers and models\n"; echo " $launcher -listmethods : \n"; echo " display the methods available the controller class\n"; echo " $launcher -expert -listmethods :\n"; echo " display the methods available the model or controller class". "\n"; echo " $launcher -listmethodsdetails : \n"; echo " display the methods available the controller class\n"; echo " $launcher -expert -listmethodsdetails :\n"; echo " display the methods available the model or controller class". "\n"; echo " $launcher [args]\n"; echo " execute the method with the provided args\n"; echo " $launcher -expert [args]\n"; echo " execute the method with the provided args\n"; echo "You can replace ONE arg by a dash (-) to read from stdin\n"; echo "Arrays must be coded like key1=val1&key2=val2&key3=val3...\n"; exit; } $this->EXPERT = FALSE; if (isset ($argv[0]) && $argv[0] === "-expert") { $this->EXPERT = TRUE; array_shift ($argv); } // List the controllers and the models if the expert mode is activated $files = glob ("controllers/*.php"); if ($this->EXPERT) $files = array_merge ($files, glob ("models/*.php")); if (count ($files) === 0 && $this->EXPERT === FALSE) die ("No controllers available in ".getcwd()."\n"); if (count ($files) === 0 && $this->EXPERT === TRUE) die ("No controllers/models available in ".getcwd()."\n"); foreach ($files as $file) { if (strpos ($file, "_")) $classes[$file] = substr (strstr ($file, "_"), 1, -4); else $classes[$file] = str_replace ("/", "\\", substr ($file, 0, -4)); } if (isset ($argv[0]) && $argv[0] === "-listonly") { // Lists the classes available in controllers and models if expert mode // Don't do any presentation to be parseable (by bash completion by example) echo implode ("\n", $classes)."\n"; exit; } if (isset ($argv[0]) && $argv[0] === "-list") { // Lists the classes available in controllers and models if expert mode foreach ($classes as $key=>$class) $classes[$key] = str_replace ("\\", "\\\\", $class); echo "List of classes available :\n"; echo " ".implode ("\n ", $classes)."\n"; echo "Usage : ".$launcher; if ($this->EXPERT) echo " -expert"; echo " -listmethods \n"; exit; } if (isset ($argv[0]) && $argv[0] === "-listmethods" || isset ($argv[0]) && $argv[0] === "-listmethodsdetails" || isset ($argv[0]) && $argv[0] === "-listmethodsonly") { // Lists the methods of a class if (!isset ($argv[1])) die ("Missing parameter 'class'\n"); $class = $argv[1]; if (!in_array ($class, $classes)) die ("Unknown class '$class'\n"); $classesNames = array_keys ($classes, $class); $file = reset ($classesNames); require_once ($file); $refclass = new ReflectionClass ($class); // Look at constructor parameters // PARAMETERS MUST NOT BE OPTIONNAL $constParams = ""; try { $r = new ReflectionMethod ($class, "__construct"); $params = $r->getParameters(); foreach ($params as $param) { $constParams .= " "; $constParams .= " <"; $constParams .= $param->name; $constParams .= ">"; } } catch (Exception $e) { // No constructor } // Look at methods $methods = $refclass->getMethods(); if ($argv[0] !== "-listmethodsonly") echo "List of methods available in the class '$class' :\n"; foreach ($methods as $key=>$method) { if ($method->name === "__construct") continue; if ($key > 0 && $argv[0] !== "-listmethodsonly") echo "\n"; if ($argv[0] !== "-listmethodsonly") echo " "; echo $method->name.$constParams; if ($argv[0] !== "-listmethodsonly") { $r = new ReflectionMethod ($class, $method->name); $params = $r->getParameters(); foreach ($params as $param) { echo " "; if ($param->isOptional()) echo "["; else echo " <"; echo $param->name; if ($param->isOptional()) echo "]"; else echo ">"; } if ($argv[0] === "-listmethodsdetails") { echo "\n"; echo trim (substr ($method->getDocComment(), 3, -2)); } } echo "\n"; } exit; } // Execution of the class->method if (!isset ($argv[0])) die ("No class to execute provided\n"); $class = $argv[0]; if (!in_array ($class, $classes)) die ("Unknown class '$class'\n"); array_shift ($argv); $classesNames = array_keys ($classes, $class); $file = reset ($classesNames); require_once ($file); if (!isset ($argv[0])) die ("No method for class '$class' to execute\n"); $method = $argv[0]; array_shift ($argv); $refclass = new ReflectionClass ($class); $methods = $refclass->getMethods(); $found = FALSE; foreach ($methods as $meth) { if ($meth->name === $method) { $found = TRUE; break; } } if ($found === FALSE) die ("Method '$method' not available in class '$class'\n"); $min = 0; $max = 0; $paramsConst = array (); try { $r = new ReflectionMethod ($class, "__construct"); $paramsConst = $r->getParameters(); $min = $max = count ($paramsConst); } catch (Exception $e) { // No constructor available in class } $r = new ReflectionMethod ($class, $method); $params = $r->getParameters(); foreach ($params as $param) { if (!$param->isOptional()) $min++; $max++; } unset ($r); if (count ($argv) < $min) die ("Not enough parameters provided to method\n"); if (in_array ("-", $argv)) { $tab = array_keys ($argv, "-"); $keyStdIn = reset ($tab); $dataStdIn = file_get_contents ("php://stdin"); $argv[$keyStdIn] = $dataStdIn; } // Convert "toto=ror&ypyp=oo" arg to array("toto"=>"ror","ypyp"=>"oo") // (Array management in CLI) foreach ($argv as $key=>$arg) { // Don't modify the stdin if (isset ($keyStdIn) && $key === $keyStdIn) continue; $pairs = explode('&', $arg); foreach($pairs as $pair) { @list ($name, $value) = explode ('=', $pair, 2); if ($value === null) { $argv[$key] = $name; } else { if (! is_array ($argv[$key])) $argv[$key] = array (); $argv[$key][$name] = $value; } } } // Manage a parameter in the constructor of the class $paramConst = array (); if (count ($paramsConst) > 0) { $paramConst = array_slice ($argv, 0, count ($paramsConst)); $argv = array_slice ($argv, count ($paramsConst)); } try { $classReflection = new ReflectionClass($class); $r = $classReflection->newInstanceArgs($paramConst); $r->auth["email"] = "cli"; $s = call_user_func_array(array($r, $method), $argv); var_dump ($s); } catch (Exception $e) { file_put_contents("php://stderr", $e->getMessage()."\n"); if ($this->EXPERT) file_put_contents ("php://stderr", $e->getTraceAsString()."\n"); } exit; } }