1f8369d7dSTobias Sarnowski<?php 2f8369d7dSTobias Sarnowski/** 3f8369d7dSTobias Sarnowski * Simulates a full DokuWiki HTTP Request and allows 4f8369d7dSTobias Sarnowski * runtime inspection. 5f8369d7dSTobias Sarnowski */ 6f8369d7dSTobias Sarnowski 7f8369d7dSTobias Sarnowski/** 8f8369d7dSTobias Sarnowski * Helper class to execute a fake request 9f8369d7dSTobias Sarnowski */ 10f8369d7dSTobias Sarnowskiclass TestRequest { 11f8369d7dSTobias Sarnowski 121ada9e0aSAndreas Gohr protected $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php'); 131ada9e0aSAndreas Gohr protected $script; 149894e7afSChristopher Smith 151ada9e0aSAndreas Gohr protected $server = array(); 161ada9e0aSAndreas Gohr protected $session = array(); 171ada9e0aSAndreas Gohr protected $get = array(); 181ada9e0aSAndreas Gohr protected $post = array(); 19*27c0c399SAndreas Gohr protected $data = array(); 20f8369d7dSTobias Sarnowski 21444d58a8SAndreas Gohr /** @var string stores the output buffer, even when it's flushed */ 22444d58a8SAndreas Gohr protected $output_buffer = ''; 23444d58a8SAndreas Gohr 24444d58a8SAndreas Gohr /** @var null|TestRequest the currently running request */ 25444d58a8SAndreas Gohr static protected $running = null; 26444d58a8SAndreas Gohr 271ada9e0aSAndreas Gohr /** 281ada9e0aSAndreas Gohr * Get a $_SERVER var 291ada9e0aSAndreas Gohr * 301ada9e0aSAndreas Gohr * @param string $key 311ada9e0aSAndreas Gohr * @return mixed 321ada9e0aSAndreas Gohr */ 331ada9e0aSAndreas Gohr public function getServer($key) { 341ada9e0aSAndreas Gohr return $this->server[$key]; 351ada9e0aSAndreas Gohr } 36f8369d7dSTobias Sarnowski 371ada9e0aSAndreas Gohr /** 381ada9e0aSAndreas Gohr * Get a $_SESSION var 391ada9e0aSAndreas Gohr * 401ada9e0aSAndreas Gohr * @param string $key 411ada9e0aSAndreas Gohr * @return mixed 421ada9e0aSAndreas Gohr */ 431ada9e0aSAndreas Gohr public function getSession($key) { 441ada9e0aSAndreas Gohr return $this->session[$key]; 451ada9e0aSAndreas Gohr } 461ada9e0aSAndreas Gohr 471ada9e0aSAndreas Gohr /** 481ada9e0aSAndreas Gohr * Get a $_GET var 491ada9e0aSAndreas Gohr * 501ada9e0aSAndreas Gohr * @param string $key 511ada9e0aSAndreas Gohr * @return mixed 521ada9e0aSAndreas Gohr */ 531ada9e0aSAndreas Gohr public function getGet($key) { 541ada9e0aSAndreas Gohr return $this->get[$key]; 551ada9e0aSAndreas Gohr } 561ada9e0aSAndreas Gohr 571ada9e0aSAndreas Gohr /** 581ada9e0aSAndreas Gohr * Get a $_POST var 591ada9e0aSAndreas Gohr * 601ada9e0aSAndreas Gohr * @param string $key 611ada9e0aSAndreas Gohr * @return mixed 621ada9e0aSAndreas Gohr */ 631ada9e0aSAndreas Gohr public function getPost($key) { 641ada9e0aSAndreas Gohr return $this->post[$key]; 651ada9e0aSAndreas Gohr } 661ada9e0aSAndreas Gohr 671ada9e0aSAndreas Gohr /** 681ada9e0aSAndreas Gohr * Get the script that will execute the request 691ada9e0aSAndreas Gohr * 701ada9e0aSAndreas Gohr * @return string 711ada9e0aSAndreas Gohr */ 721ada9e0aSAndreas Gohr public function getScript() { 731ada9e0aSAndreas Gohr return $this->script; 741ada9e0aSAndreas Gohr } 751ada9e0aSAndreas Gohr 761ada9e0aSAndreas Gohr /** 771ada9e0aSAndreas Gohr * Set a $_SERVER var 781ada9e0aSAndreas Gohr * 791ada9e0aSAndreas Gohr * @param string $key 801ada9e0aSAndreas Gohr * @param mixed $value 811ada9e0aSAndreas Gohr */ 821ada9e0aSAndreas Gohr public function setServer($key, $value) { 831ada9e0aSAndreas Gohr $this->server[$key] = $value; 841ada9e0aSAndreas Gohr } 851ada9e0aSAndreas Gohr 861ada9e0aSAndreas Gohr /** 871ada9e0aSAndreas Gohr * Set a $_SESSION var 881ada9e0aSAndreas Gohr * 891ada9e0aSAndreas Gohr * @param string $key 901ada9e0aSAndreas Gohr * @param mixed $value 911ada9e0aSAndreas Gohr */ 921ada9e0aSAndreas Gohr public function setSession($key, $value) { 931ada9e0aSAndreas Gohr $this->session[$key] = $value; 941ada9e0aSAndreas Gohr } 951ada9e0aSAndreas Gohr 961ada9e0aSAndreas Gohr /** 971ada9e0aSAndreas Gohr * Set a $_GET var 981ada9e0aSAndreas Gohr * 991ada9e0aSAndreas Gohr * @param string $key 1001ada9e0aSAndreas Gohr * @param mixed $value 1011ada9e0aSAndreas Gohr */ 1021ada9e0aSAndreas Gohr public function setGet($key, $value) { 1031ada9e0aSAndreas Gohr $this->get[$key] = $value; 1041ada9e0aSAndreas Gohr } 1051ada9e0aSAndreas Gohr 1061ada9e0aSAndreas Gohr /** 1071ada9e0aSAndreas Gohr * Set a $_POST var 1081ada9e0aSAndreas Gohr * 1091ada9e0aSAndreas Gohr * @param string $key 1101ada9e0aSAndreas Gohr * @param mixed $value 1111ada9e0aSAndreas Gohr */ 1121ada9e0aSAndreas Gohr public function setPost($key, $value) { 1131ada9e0aSAndreas Gohr $this->post[$key] = $value; 1141ada9e0aSAndreas Gohr } 115f8369d7dSTobias Sarnowski 116f8369d7dSTobias Sarnowski /** 117f8369d7dSTobias Sarnowski * Executes the request 118f8369d7dSTobias Sarnowski * 1191ada9e0aSAndreas Gohr * @param string $uri end URL to simulate, needs to be one of the testable scripts 120f8369d7dSTobias Sarnowski * @return TestResponse the resulting output of the request 121f8369d7dSTobias Sarnowski */ 1224d053d04SAndreas Gohr public function execute($uri = '/doku.php') { 123fe717f57Slisps global $INPUT; 124fe717f57Slisps 125f8369d7dSTobias Sarnowski // save old environment 126f8369d7dSTobias Sarnowski $server = $_SERVER; 127f8369d7dSTobias Sarnowski $session = $_SESSION; 128f8369d7dSTobias Sarnowski $get = $_GET; 129f8369d7dSTobias Sarnowski $post = $_POST; 130f8369d7dSTobias Sarnowski $request = $_REQUEST; 131fe717f57Slisps $input = $INPUT; 132f8369d7dSTobias Sarnowski 1334d053d04SAndreas Gohr // prepare the right URI 1344d053d04SAndreas Gohr $this->setUri($uri); 1354d053d04SAndreas Gohr 1360189bd86SAndreas Gohr // import all defined globals into the function scope 1370189bd86SAndreas Gohr foreach(array_keys($GLOBALS) as $glb) { 1380189bd86SAndreas Gohr global $$glb; 1390189bd86SAndreas Gohr } 1400189bd86SAndreas Gohr 141f8369d7dSTobias Sarnowski // fake environment 142f8369d7dSTobias Sarnowski global $default_server_vars; 143f8369d7dSTobias Sarnowski $_SERVER = array_merge($default_server_vars, $this->server); 144f8369d7dSTobias Sarnowski $_SESSION = $this->session; 145f8369d7dSTobias Sarnowski $_GET = $this->get; 146f8369d7dSTobias Sarnowski $_POST = $this->post; 147f8369d7dSTobias Sarnowski $_REQUEST = array_merge($_GET, $_POST); 148f8369d7dSTobias Sarnowski 149f8369d7dSTobias Sarnowski // reset output buffer 150444d58a8SAndreas Gohr $this->output_buffer = ''; 151f8369d7dSTobias Sarnowski 152f8369d7dSTobias Sarnowski // now execute dokuwiki and grep the output 153444d58a8SAndreas Gohr self::$running = $this; 154f8369d7dSTobias Sarnowski header_remove(); 155444d58a8SAndreas Gohr ob_start(array($this, 'ob_start_callback')); 156fe717f57Slisps $INPUT = new Input(); 1579894e7afSChristopher Smith include(DOKU_INC . $this->script); 158f8369d7dSTobias Sarnowski ob_end_flush(); 159444d58a8SAndreas Gohr self::$running = null; 160f8369d7dSTobias Sarnowski 161f8369d7dSTobias Sarnowski // create the response object 162f8369d7dSTobias Sarnowski $response = new TestResponse( 163444d58a8SAndreas Gohr $this->output_buffer, 164*27c0c399SAndreas Gohr // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli 165*27c0c399SAndreas Gohr (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()), 166*27c0c399SAndreas Gohr $this->data 167f8369d7dSTobias Sarnowski ); 168f8369d7dSTobias Sarnowski 169f8369d7dSTobias Sarnowski // reset environment 170f8369d7dSTobias Sarnowski $_SERVER = $server; 171f8369d7dSTobias Sarnowski $_SESSION = $session; 172f8369d7dSTobias Sarnowski $_GET = $get; 173f8369d7dSTobias Sarnowski $_POST = $post; 174f8369d7dSTobias Sarnowski $_REQUEST = $request; 175fe717f57Slisps $INPUT = $input; 176f8369d7dSTobias Sarnowski 177f8369d7dSTobias Sarnowski return $response; 178f8369d7dSTobias Sarnowski } 1799e777ceeSAndreas Gohr 1809e777ceeSAndreas Gohr /** 1819e777ceeSAndreas Gohr * Set the virtual URI the request works against 1829e777ceeSAndreas Gohr * 1839e777ceeSAndreas Gohr * This parses the given URI and sets any contained GET variables 1849e777ceeSAndreas Gohr * but will not overwrite any previously set ones (eg. set via setGet()). 1859e777ceeSAndreas Gohr * 1869e777ceeSAndreas Gohr * It initializes the $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING'] 1879e777ceeSAndreas Gohr * with all set GET variables. 1889e777ceeSAndreas Gohr * 1891ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 1901ada9e0aSAndreas Gohr * @throws Exception when an invalid script is passed 1919e777ceeSAndreas Gohr */ 1924d053d04SAndreas Gohr protected function setUri($uri) { 1939894e7afSChristopher Smith if(!preg_match('#^(' . join('|', $this->valid_scripts) . ')#', $uri)) { 1949894e7afSChristopher Smith throw new Exception("$uri \n--- only " . join(', ', $this->valid_scripts) . " are supported currently"); 1959e777ceeSAndreas Gohr } 1969e777ceeSAndreas Gohr 1979e777ceeSAndreas Gohr $params = array(); 1989e777ceeSAndreas Gohr list($uri, $query) = explode('?', $uri, 2); 1999e777ceeSAndreas Gohr if($query) parse_str($query, $params); 2009e777ceeSAndreas Gohr 2019894e7afSChristopher Smith $this->script = substr($uri, 1); 2029e777ceeSAndreas Gohr $this->get = array_merge($params, $this->get); 2039e777ceeSAndreas Gohr if(count($this->get)) { 2049e777ceeSAndreas Gohr $query = '?' . http_build_query($this->get, '', '&'); 2059e777ceeSAndreas Gohr $query = str_replace( 2069e777ceeSAndreas Gohr array('%3A', '%5B', '%5D'), 2079e777ceeSAndreas Gohr array(':', '[', ']'), 2089e777ceeSAndreas Gohr $query 2099e777ceeSAndreas Gohr ); 2109e777ceeSAndreas Gohr $uri = $uri . $query; 2119e777ceeSAndreas Gohr } 2129e777ceeSAndreas Gohr 2139e777ceeSAndreas Gohr $this->setServer('QUERY_STRING', $query); 2149e777ceeSAndreas Gohr $this->setServer('REQUEST_URI', $uri); 2159e777ceeSAndreas Gohr } 2169e777ceeSAndreas Gohr 2179e777ceeSAndreas Gohr /** 2189e777ceeSAndreas Gohr * Simulate a POST request with the given variables 2199e777ceeSAndreas Gohr * 2209e777ceeSAndreas Gohr * @param array $post all the POST parameters to use 2211ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 2221ada9e0aSAndreas Gohr * @return TestResponse 2239e777ceeSAndreas Gohr */ 2249e777ceeSAndreas Gohr public function post($post = array(), $uri = '/doku.php') { 2259e777ceeSAndreas Gohr $this->post = array_merge($this->post, $post); 2269e777ceeSAndreas Gohr $this->setServer('REQUEST_METHOD', 'POST'); 2274d053d04SAndreas Gohr return $this->execute($uri); 2289e777ceeSAndreas Gohr } 2299e777ceeSAndreas Gohr 2309e777ceeSAndreas Gohr /** 2319e777ceeSAndreas Gohr * Simulate a GET request with the given variables 2329e777ceeSAndreas Gohr * 2331ada9e0aSAndreas Gohr * @param array $get all the GET parameters to use 2341ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 2351ada9e0aSAndreas Gohr * @return TestResponse 2369e777ceeSAndreas Gohr */ 2379e777ceeSAndreas Gohr public function get($get = array(), $uri = '/doku.php') { 2389e777ceeSAndreas Gohr $this->get = array_merge($this->get, $get); 2399e777ceeSAndreas Gohr $this->setServer('REQUEST_METHOD', 'GET'); 2404d053d04SAndreas Gohr return $this->execute($uri); 2419e777ceeSAndreas Gohr } 2429e777ceeSAndreas Gohr 243572dc222SLarsDW223 /** 244444d58a8SAndreas Gohr * Callback for ob_start 245444d58a8SAndreas Gohr * 246444d58a8SAndreas Gohr * This continues to fill our own buffer, even when some part 247444d58a8SAndreas Gohr * of the code askes for flushing the buffers 248444d58a8SAndreas Gohr * 249444d58a8SAndreas Gohr * @param string $buffer 250444d58a8SAndreas Gohr */ 251444d58a8SAndreas Gohr public function ob_start_callback($buffer) { 252444d58a8SAndreas Gohr $this->output_buffer .= $buffer; 253444d58a8SAndreas Gohr } 254444d58a8SAndreas Gohr 255444d58a8SAndreas Gohr /** 256*27c0c399SAndreas Gohr * Access the TestRequest from the executed code 257*27c0c399SAndreas Gohr * 258*27c0c399SAndreas Gohr * This allows certain functions to access the TestRequest that is accessing them 259*27c0c399SAndreas Gohr * to add additional info. 260*27c0c399SAndreas Gohr * 261*27c0c399SAndreas Gohr * @return null|TestRequest the currently executed request if any 262572dc222SLarsDW223 */ 263*27c0c399SAndreas Gohr public static function getRunning() { 264*27c0c399SAndreas Gohr return self::$running; 265*27c0c399SAndreas Gohr } 266*27c0c399SAndreas Gohr 267*27c0c399SAndreas Gohr /** 268*27c0c399SAndreas Gohr * Store data to be read in the response later 269*27c0c399SAndreas Gohr * 270*27c0c399SAndreas Gohr * When called multiple times with the same key, the data is appended to this 271*27c0c399SAndreas Gohr * key's array 272*27c0c399SAndreas Gohr * 273*27c0c399SAndreas Gohr * @param string $key the identifier for this information 274*27c0c399SAndreas Gohr * @param mixed $value arbitrary data to store 275*27c0c399SAndreas Gohr */ 276*27c0c399SAndreas Gohr public function addData($key, $value) { 277*27c0c399SAndreas Gohr if(!isset($this->data[$key])) $this->data[$key] = array(); 278*27c0c399SAndreas Gohr $this->data[$key][] = $value; 279572dc222SLarsDW223 } 280f8369d7dSTobias Sarnowski} 281