App Engine Python SDK version 1.8.1
[gae.git] / python / demos / php / minishell / shell.php
blob4e3fedb6a2e7fe3328cbcc9c2aa0deb4c90daabc
1 <?php
2 /**
3 * Copyright 2007 Google Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 /**
18 * Handles the /shell.do url.
19 * It executes the received statement using the globals, constants and locals
20 * stored for this user. Statements declaring classes and functions are
21 * persisted and run every time.
24 class Session {
25 /**
26 * Stores a serialized version of both local and global variables.
29 private $globals = "";
30 private $locals = "";
31 private $statements = array();
32 private $use_statements = array();
33 private $constants = "";
35 function __construct() {
36 $this->locals = serialize(array());
37 $this->storeGlobals();
38 $this->functions = get_defined_functions();
39 $this->classes = get_declared_classes();
40 $this->storeConstants();
43 /** Stores a serialized version of the globals. */
44 function storeGlobals() {
45 $this->globals = serialize($GLOBALS);
48 /** Replace the globals with the serialized stored ones. */
49 function loadGlobals() {
50 $GLOBALS = unserialize($this->globals);
53 /** Stores a serialized version of the passed locals. */
54 function storeLocals($locals) {
55 foreach (array("_shell_statement",
56 "_shell_session") as $nonLocal) {
57 unset($locals[$nonLocal]);
59 $this->locals = serialize($locals);
62 /** Returns an array with the locals. */
63 function getLocals() {
64 return unserialize($this->locals);
67 /**
68 * Stores a statement if it declares a function, a class or if it is a
69 * use statment or a require/include statement.
71 function storeStatementIfNeeded($statement) {
72 $nonSerializableTokens = array(T_CLASS, T_FUNCTION,
73 T_REQUIRE, T_REQUIRE_ONCE,
74 T_INCLUDE, T_INCLUDE_ONCE);
75 foreach(token_get_all("<?php $statement ?>") as $token) {
76 if (in_array($token[0], $nonSerializableTokens)) {
77 array_push($this->statements, $statement);
78 } else if ($token[0] == T_USE) {
79 array_push($this->use_statements, $statement);
84 /** Stores a serialized version of the constants. */
85 function storeConstants() {
86 $this->constants = serialize(get_defined_constants());
89 /** Replace the constants with the serialized stored ones. */
90 function loadConstants() {
91 $constants = unserialize($this->constants);
92 foreach(array_diff($constants, get_defined_constants()) as $constant=>$value) {
93 define($constant, $value);
97 static function scrubOutput($output) {
98 return htmlentities($output);
101 /** Evaluate all saved statements.*/
102 function loadStatements() {
103 foreach ($this->statements as $statement) {
104 ob_start(['Session', 'scrubOutput']);
105 eval($statement);
106 ob_clean();
110 /** Prepend all the use statements to the given statement. */
111 function prependUseStatements($statement) {
112 return implode("\n", $this->use_statements) . "\n$statement";
115 /** Method to initialize user scope.*/
116 function start() {
117 // Must goes first, or otherwise the unserialized objects will be incomplete.
118 $this->loadStatements();
119 $this->loadGlobals();
120 $this->functions = get_defined_functions();
121 $this->classes = get_declared_classes();
122 $this->loadConstants();
125 /** Method to save user scope.*/
126 function end($statement, $locals) {
127 $this->storeGlobals();
128 $this->storeLocals($locals);
129 $this->storeStatementIfNeeded($statement);
130 $this->storeConstants();
135 * Handler to catch exceptions raised when evaluation the code.
136 * We just return the error and not the line, as they are not meaningful in this
137 * context.
139 function error_handler($errno, $errstr, $errfile, $errline) {
140 echo $errstr, "\n";
144 * Handler to catch fatal errors (like function not defined) and print them
145 * nicely.
147 function shutdown_handler() {
148 $error = error_get_last();
149 if($error !== NULL){
150 echo $error["message"], "\n";
155 * Executes a statement for the given session.
156 * All locals must be prefixed with _shell_, to avoid messing up with the user's
157 * local.
159 function shell($_shell_statement, $_shell_session) {
160 $_shell_session->start();
161 header("Content-Type: text/html; charset=utf-8");
162 extract($_shell_session->getLocals(), EXTR_SKIP);
163 // Disable all error reporting, otherwise it mess with the output.
164 error_reporting(0);
165 // Errors are handled with an error handler and a fatal error handler, because
166 // exceptions are not catchable when evaluating code.
167 register_shutdown_function('shutdown_handler');
168 set_error_handler('error_handler');
169 ob_start(['Session', 'scrubOutput']);
170 eval($_shell_session->prependUseStatements($_shell_statement));
171 ob_end_flush();
172 $_shell_session->end($_shell_statement, get_defined_vars());
175 session_start();
176 if (!isset($_SESSION["session"])) {
177 $_SESSION["session"] = new Session();
180 if (isset($_SESSION['token']) && ($_GET['token'] === $_SESSION['token'])) {
181 // Append a semi-colon just in case the statement doen't have one. An extra
182 // semi-colon makes no harm.
183 shell($_GET["statement"] . ";", $_SESSION["session"]);
184 } else if (!isset($_SESSION['token'])) {
185 syslog(LOG_ERR, 'Missing session token');
186 echo "Session token missing - Please reset your session.";
187 } else {
188 syslog(LOG_ERR, 'Mismatch session token.');
189 echo "Invalid session token - Please reset your session.";