1<?php 2/** 3 * Simulates a full DokuWiki HTTP Request and allows 4 * runtime inspection. 5 */ 6 7$currentTestRequest = null; 8 9 10/** 11 * Helper class to execute a fake request 12 */ 13class TestRequest { 14 15 protected $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php'); 16 protected $script; 17 18 protected $server = array(); 19 protected $session = array(); 20 protected $get = array(); 21 protected $post = array(); 22 protected $notifications = array(); 23 24 /** @var string stores the output buffer, even when it's flushed */ 25 protected $output_buffer = ''; 26 27 /** @var null|TestRequest the currently running request */ 28 static protected $running = null; 29 30 /** 31 * Get a $_SERVER var 32 * 33 * @param string $key 34 * @return mixed 35 */ 36 public function getServer($key) { 37 return $this->server[$key]; 38 } 39 40 /** 41 * Get a $_SESSION var 42 * 43 * @param string $key 44 * @return mixed 45 */ 46 public function getSession($key) { 47 return $this->session[$key]; 48 } 49 50 /** 51 * Get a $_GET var 52 * 53 * @param string $key 54 * @return mixed 55 */ 56 public function getGet($key) { 57 return $this->get[$key]; 58 } 59 60 /** 61 * Get a $_POST var 62 * 63 * @param string $key 64 * @return mixed 65 */ 66 public function getPost($key) { 67 return $this->post[$key]; 68 } 69 70 /** 71 * Get the script that will execute the request 72 * 73 * @return string 74 */ 75 public function getScript() { 76 return $this->script; 77 } 78 79 /** 80 * Set a $_SERVER var 81 * 82 * @param string $key 83 * @param mixed $value 84 */ 85 public function setServer($key, $value) { 86 $this->server[$key] = $value; 87 } 88 89 /** 90 * Set a $_SESSION var 91 * 92 * @param string $key 93 * @param mixed $value 94 */ 95 public function setSession($key, $value) { 96 $this->session[$key] = $value; 97 } 98 99 /** 100 * Set a $_GET var 101 * 102 * @param string $key 103 * @param mixed $value 104 */ 105 public function setGet($key, $value) { 106 $this->get[$key] = $value; 107 } 108 109 /** 110 * Set a $_POST var 111 * 112 * @param string $key 113 * @param mixed $value 114 */ 115 public function setPost($key, $value) { 116 $this->post[$key] = $value; 117 } 118 119 /** 120 * Executes the request 121 * 122 * @param string $uri end URL to simulate, needs to be one of the testable scripts 123 * @return TestResponse the resulting output of the request 124 */ 125 public function execute($uri = '/doku.php') { 126 global $INPUT; 127 global $currentTestRequest; 128 129 $currentTestRequest = $this; 130 131 // save old environment 132 $server = $_SERVER; 133 $session = $_SESSION; 134 $get = $_GET; 135 $post = $_POST; 136 $request = $_REQUEST; 137 $input = $INPUT; 138 139 // prepare the right URI 140 $this->setUri($uri); 141 142 // import all defined globals into the function scope 143 foreach(array_keys($GLOBALS) as $glb) { 144 global $$glb; 145 } 146 147 // fake environment 148 global $default_server_vars; 149 $_SERVER = array_merge($default_server_vars, $this->server); 150 $_SESSION = $this->session; 151 $_GET = $this->get; 152 $_POST = $this->post; 153 $_REQUEST = array_merge($_GET, $_POST); 154 155 // reset output buffer 156 $this->output_buffer = ''; 157 158 // now execute dokuwiki and grep the output 159 self::$running = $this; 160 header_remove(); 161 ob_start(array($this, 'ob_start_callback')); 162 $INPUT = new Input(); 163 include(DOKU_INC . $this->script); 164 ob_end_flush(); 165 self::$running = null; 166 167 // create the response object 168 $response = new TestResponse( 169 $this->output_buffer, 170 (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()) // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli 171 ); 172 if($this->notifications != null) { 173 $response->setNotifications($this->notifications); 174 } 175 176 // reset environment 177 $_SERVER = $server; 178 $_SESSION = $session; 179 $_GET = $get; 180 $_POST = $post; 181 $_REQUEST = $request; 182 $INPUT = $input; 183 184 $currentTestRequest = null; 185 186 return $response; 187 } 188 189 /** 190 * Set the virtual URI the request works against 191 * 192 * This parses the given URI and sets any contained GET variables 193 * but will not overwrite any previously set ones (eg. set via setGet()). 194 * 195 * It initializes the $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING'] 196 * with all set GET variables. 197 * 198 * @param string $uri end URL to simulate 199 * @throws Exception when an invalid script is passed 200 */ 201 protected function setUri($uri) { 202 if(!preg_match('#^(' . join('|', $this->valid_scripts) . ')#', $uri)) { 203 throw new Exception("$uri \n--- only " . join(', ', $this->valid_scripts) . " are supported currently"); 204 } 205 206 $params = array(); 207 list($uri, $query) = explode('?', $uri, 2); 208 if($query) parse_str($query, $params); 209 210 $this->script = substr($uri, 1); 211 $this->get = array_merge($params, $this->get); 212 if(count($this->get)) { 213 $query = '?' . http_build_query($this->get, '', '&'); 214 $query = str_replace( 215 array('%3A', '%5B', '%5D'), 216 array(':', '[', ']'), 217 $query 218 ); 219 $uri = $uri . $query; 220 } 221 222 $this->setServer('QUERY_STRING', $query); 223 $this->setServer('REQUEST_URI', $uri); 224 } 225 226 /** 227 * Simulate a POST request with the given variables 228 * 229 * @param array $post all the POST parameters to use 230 * @param string $uri end URL to simulate 231 * @return TestResponse 232 */ 233 public function post($post = array(), $uri = '/doku.php') { 234 $this->post = array_merge($this->post, $post); 235 $this->setServer('REQUEST_METHOD', 'POST'); 236 return $this->execute($uri); 237 } 238 239 /** 240 * Simulate a GET request with the given variables 241 * 242 * @param array $get all the GET parameters to use 243 * @param string $uri end URL to simulate 244 * @return TestResponse 245 */ 246 public function get($get = array(), $uri = '/doku.php') { 247 $this->get = array_merge($this->get, $get); 248 $this->setServer('REQUEST_METHOD', 'GET'); 249 return $this->execute($uri); 250 } 251 252 /** 253 * Callback for ob_start 254 * 255 * This continues to fill our own buffer, even when some part 256 * of the code askes for flushing the buffers 257 * 258 * @param string $buffer 259 */ 260 public function ob_start_callback($buffer) { 261 $this->output_buffer .= $buffer; 262 } 263 264 /** 265 * Add a notification to later store it in the test respone. 266 */ 267 public function addNotification(array $new) { 268 $this->notifications[] = $new; 269 } 270} 271