1f8369d7dSTobias Sarnowski<?php 2f8369d7dSTobias Sarnowski/** 3f8369d7dSTobias Sarnowski * Simulates a full DokuWiki HTTP Request and allows 4f8369d7dSTobias Sarnowski * runtime inspection. 5f8369d7dSTobias Sarnowski */ 6f8369d7dSTobias Sarnowski 7*ccc4c71cSAndreas Gohruse dokuwiki\Input\Input; 8*ccc4c71cSAndreas Gohr 9f8369d7dSTobias Sarnowski/** 10f8369d7dSTobias Sarnowski * Helper class to execute a fake request 11f8369d7dSTobias Sarnowski */ 12f8369d7dSTobias Sarnowskiclass TestRequest { 13f8369d7dSTobias Sarnowski 141ada9e0aSAndreas Gohr protected $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php'); 151ada9e0aSAndreas Gohr protected $script; 169894e7afSChristopher Smith 171ada9e0aSAndreas Gohr protected $server = array(); 181ada9e0aSAndreas Gohr protected $session = array(); 191ada9e0aSAndreas Gohr protected $get = array(); 201ada9e0aSAndreas Gohr protected $post = array(); 2127c0c399SAndreas Gohr protected $data = array(); 22f8369d7dSTobias Sarnowski 23444d58a8SAndreas Gohr /** @var string stores the output buffer, even when it's flushed */ 24444d58a8SAndreas Gohr protected $output_buffer = ''; 25444d58a8SAndreas Gohr 26444d58a8SAndreas Gohr /** @var null|TestRequest the currently running request */ 27444d58a8SAndreas Gohr static protected $running = null; 28444d58a8SAndreas Gohr 291ada9e0aSAndreas Gohr /** 301ada9e0aSAndreas Gohr * Get a $_SERVER var 311ada9e0aSAndreas Gohr * 321ada9e0aSAndreas Gohr * @param string $key 331ada9e0aSAndreas Gohr * @return mixed 341ada9e0aSAndreas Gohr */ 351ada9e0aSAndreas Gohr public function getServer($key) { 361ada9e0aSAndreas Gohr return $this->server[$key]; 371ada9e0aSAndreas Gohr } 38f8369d7dSTobias Sarnowski 391ada9e0aSAndreas Gohr /** 401ada9e0aSAndreas Gohr * Get a $_SESSION var 411ada9e0aSAndreas Gohr * 421ada9e0aSAndreas Gohr * @param string $key 431ada9e0aSAndreas Gohr * @return mixed 441ada9e0aSAndreas Gohr */ 451ada9e0aSAndreas Gohr public function getSession($key) { 461ada9e0aSAndreas Gohr return $this->session[$key]; 471ada9e0aSAndreas Gohr } 481ada9e0aSAndreas Gohr 491ada9e0aSAndreas Gohr /** 501ada9e0aSAndreas Gohr * Get a $_GET var 511ada9e0aSAndreas Gohr * 521ada9e0aSAndreas Gohr * @param string $key 531ada9e0aSAndreas Gohr * @return mixed 541ada9e0aSAndreas Gohr */ 551ada9e0aSAndreas Gohr public function getGet($key) { 561ada9e0aSAndreas Gohr return $this->get[$key]; 571ada9e0aSAndreas Gohr } 581ada9e0aSAndreas Gohr 591ada9e0aSAndreas Gohr /** 601ada9e0aSAndreas Gohr * Get a $_POST var 611ada9e0aSAndreas Gohr * 621ada9e0aSAndreas Gohr * @param string $key 631ada9e0aSAndreas Gohr * @return mixed 641ada9e0aSAndreas Gohr */ 651ada9e0aSAndreas Gohr public function getPost($key) { 661ada9e0aSAndreas Gohr return $this->post[$key]; 671ada9e0aSAndreas Gohr } 681ada9e0aSAndreas Gohr 691ada9e0aSAndreas Gohr /** 701ada9e0aSAndreas Gohr * Get the script that will execute the request 711ada9e0aSAndreas Gohr * 721ada9e0aSAndreas Gohr * @return string 731ada9e0aSAndreas Gohr */ 741ada9e0aSAndreas Gohr public function getScript() { 751ada9e0aSAndreas Gohr return $this->script; 761ada9e0aSAndreas Gohr } 771ada9e0aSAndreas Gohr 781ada9e0aSAndreas Gohr /** 791ada9e0aSAndreas Gohr * Set a $_SERVER var 801ada9e0aSAndreas Gohr * 811ada9e0aSAndreas Gohr * @param string $key 821ada9e0aSAndreas Gohr * @param mixed $value 831ada9e0aSAndreas Gohr */ 841ada9e0aSAndreas Gohr public function setServer($key, $value) { 851ada9e0aSAndreas Gohr $this->server[$key] = $value; 861ada9e0aSAndreas Gohr } 871ada9e0aSAndreas Gohr 881ada9e0aSAndreas Gohr /** 891ada9e0aSAndreas Gohr * Set a $_SESSION var 901ada9e0aSAndreas Gohr * 911ada9e0aSAndreas Gohr * @param string $key 921ada9e0aSAndreas Gohr * @param mixed $value 931ada9e0aSAndreas Gohr */ 941ada9e0aSAndreas Gohr public function setSession($key, $value) { 951ada9e0aSAndreas Gohr $this->session[$key] = $value; 961ada9e0aSAndreas Gohr } 971ada9e0aSAndreas Gohr 981ada9e0aSAndreas Gohr /** 991ada9e0aSAndreas Gohr * Set a $_GET var 1001ada9e0aSAndreas Gohr * 1011ada9e0aSAndreas Gohr * @param string $key 1021ada9e0aSAndreas Gohr * @param mixed $value 1031ada9e0aSAndreas Gohr */ 1041ada9e0aSAndreas Gohr public function setGet($key, $value) { 1051ada9e0aSAndreas Gohr $this->get[$key] = $value; 1061ada9e0aSAndreas Gohr } 1071ada9e0aSAndreas Gohr 1081ada9e0aSAndreas Gohr /** 1091ada9e0aSAndreas Gohr * Set a $_POST var 1101ada9e0aSAndreas Gohr * 1111ada9e0aSAndreas Gohr * @param string $key 1121ada9e0aSAndreas Gohr * @param mixed $value 1131ada9e0aSAndreas Gohr */ 1141ada9e0aSAndreas Gohr public function setPost($key, $value) { 1151ada9e0aSAndreas Gohr $this->post[$key] = $value; 1161ada9e0aSAndreas Gohr } 117f8369d7dSTobias Sarnowski 118f8369d7dSTobias Sarnowski /** 119f8369d7dSTobias Sarnowski * Executes the request 120f8369d7dSTobias Sarnowski * 1211ada9e0aSAndreas Gohr * @param string $uri end URL to simulate, needs to be one of the testable scripts 122f8369d7dSTobias Sarnowski * @return TestResponse the resulting output of the request 123f8369d7dSTobias Sarnowski */ 1244d053d04SAndreas Gohr public function execute($uri = '/doku.php') { 125fe717f57Slisps global $INPUT; 126fe717f57Slisps 127f8369d7dSTobias Sarnowski // save old environment 128f8369d7dSTobias Sarnowski $server = $_SERVER; 129f8369d7dSTobias Sarnowski $session = $_SESSION; 130f8369d7dSTobias Sarnowski $get = $_GET; 131f8369d7dSTobias Sarnowski $post = $_POST; 132f8369d7dSTobias Sarnowski $request = $_REQUEST; 133fe717f57Slisps $input = $INPUT; 134f8369d7dSTobias Sarnowski 1354d053d04SAndreas Gohr // prepare the right URI 1364d053d04SAndreas Gohr $this->setUri($uri); 1374d053d04SAndreas Gohr 1380189bd86SAndreas Gohr // import all defined globals into the function scope 1390189bd86SAndreas Gohr foreach(array_keys($GLOBALS) as $glb) { 1400189bd86SAndreas Gohr global $$glb; 1410189bd86SAndreas Gohr } 1420189bd86SAndreas Gohr 143f8369d7dSTobias Sarnowski // fake environment 144f8369d7dSTobias Sarnowski global $default_server_vars; 145f8369d7dSTobias Sarnowski $_SERVER = array_merge($default_server_vars, $this->server); 146f8369d7dSTobias Sarnowski $_SESSION = $this->session; 147f8369d7dSTobias Sarnowski $_GET = $this->get; 148f8369d7dSTobias Sarnowski $_POST = $this->post; 149f8369d7dSTobias Sarnowski $_REQUEST = array_merge($_GET, $_POST); 150f8369d7dSTobias Sarnowski 151f8369d7dSTobias Sarnowski // reset output buffer 152444d58a8SAndreas Gohr $this->output_buffer = ''; 153f8369d7dSTobias Sarnowski 154f8369d7dSTobias Sarnowski // now execute dokuwiki and grep the output 155444d58a8SAndreas Gohr self::$running = $this; 156f8369d7dSTobias Sarnowski header_remove(); 157444d58a8SAndreas Gohr ob_start(array($this, 'ob_start_callback')); 158fe717f57Slisps $INPUT = new Input(); 1599894e7afSChristopher Smith include(DOKU_INC . $this->script); 160f8369d7dSTobias Sarnowski ob_end_flush(); 161444d58a8SAndreas Gohr self::$running = null; 162f8369d7dSTobias Sarnowski 163f8369d7dSTobias Sarnowski // create the response object 164f8369d7dSTobias Sarnowski $response = new TestResponse( 165444d58a8SAndreas Gohr $this->output_buffer, 16627c0c399SAndreas Gohr // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli 16727c0c399SAndreas Gohr (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()), 16827c0c399SAndreas Gohr $this->data 169f8369d7dSTobias Sarnowski ); 170f8369d7dSTobias Sarnowski 171f8369d7dSTobias Sarnowski // reset environment 172f8369d7dSTobias Sarnowski $_SERVER = $server; 173f8369d7dSTobias Sarnowski $_SESSION = $session; 174f8369d7dSTobias Sarnowski $_GET = $get; 175f8369d7dSTobias Sarnowski $_POST = $post; 176f8369d7dSTobias Sarnowski $_REQUEST = $request; 177fe717f57Slisps $INPUT = $input; 178f8369d7dSTobias Sarnowski 179f8369d7dSTobias Sarnowski return $response; 180f8369d7dSTobias Sarnowski } 1819e777ceeSAndreas Gohr 1829e777ceeSAndreas Gohr /** 1839e777ceeSAndreas Gohr * Set the virtual URI the request works against 1849e777ceeSAndreas Gohr * 1859e777ceeSAndreas Gohr * This parses the given URI and sets any contained GET variables 1869e777ceeSAndreas Gohr * but will not overwrite any previously set ones (eg. set via setGet()). 1879e777ceeSAndreas Gohr * 1889e777ceeSAndreas Gohr * It initializes the $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING'] 1899e777ceeSAndreas Gohr * with all set GET variables. 1909e777ceeSAndreas Gohr * 1911ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 1921ada9e0aSAndreas Gohr * @throws Exception when an invalid script is passed 1939e777ceeSAndreas Gohr */ 1944d053d04SAndreas Gohr protected function setUri($uri) { 1959894e7afSChristopher Smith if(!preg_match('#^(' . join('|', $this->valid_scripts) . ')#', $uri)) { 1969894e7afSChristopher Smith throw new Exception("$uri \n--- only " . join(', ', $this->valid_scripts) . " are supported currently"); 1979e777ceeSAndreas Gohr } 1989e777ceeSAndreas Gohr 1999e777ceeSAndreas Gohr $params = array(); 2009e777ceeSAndreas Gohr list($uri, $query) = explode('?', $uri, 2); 2019e777ceeSAndreas Gohr if($query) parse_str($query, $params); 2029e777ceeSAndreas Gohr 2039894e7afSChristopher Smith $this->script = substr($uri, 1); 2049e777ceeSAndreas Gohr $this->get = array_merge($params, $this->get); 2059e777ceeSAndreas Gohr if(count($this->get)) { 2069e777ceeSAndreas Gohr $query = '?' . http_build_query($this->get, '', '&'); 2079e777ceeSAndreas Gohr $query = str_replace( 2089e777ceeSAndreas Gohr array('%3A', '%5B', '%5D'), 2099e777ceeSAndreas Gohr array(':', '[', ']'), 2109e777ceeSAndreas Gohr $query 2119e777ceeSAndreas Gohr ); 2129e777ceeSAndreas Gohr $uri = $uri . $query; 2139e777ceeSAndreas Gohr } 2149e777ceeSAndreas Gohr 2159e777ceeSAndreas Gohr $this->setServer('QUERY_STRING', $query); 2169e777ceeSAndreas Gohr $this->setServer('REQUEST_URI', $uri); 2179e777ceeSAndreas Gohr } 2189e777ceeSAndreas Gohr 2199e777ceeSAndreas Gohr /** 2209e777ceeSAndreas Gohr * Simulate a POST request with the given variables 2219e777ceeSAndreas Gohr * 2229e777ceeSAndreas Gohr * @param array $post all the POST parameters to use 2231ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 2241ada9e0aSAndreas Gohr * @return TestResponse 2259e777ceeSAndreas Gohr */ 2269e777ceeSAndreas Gohr public function post($post = array(), $uri = '/doku.php') { 2279e777ceeSAndreas Gohr $this->post = array_merge($this->post, $post); 2289e777ceeSAndreas Gohr $this->setServer('REQUEST_METHOD', 'POST'); 2294d053d04SAndreas Gohr return $this->execute($uri); 2309e777ceeSAndreas Gohr } 2319e777ceeSAndreas Gohr 2329e777ceeSAndreas Gohr /** 2339e777ceeSAndreas Gohr * Simulate a GET request with the given variables 2349e777ceeSAndreas Gohr * 2351ada9e0aSAndreas Gohr * @param array $get all the GET parameters to use 2361ada9e0aSAndreas Gohr * @param string $uri end URL to simulate 2371ada9e0aSAndreas Gohr * @return TestResponse 2389e777ceeSAndreas Gohr */ 2399e777ceeSAndreas Gohr public function get($get = array(), $uri = '/doku.php') { 2409e777ceeSAndreas Gohr $this->get = array_merge($this->get, $get); 2419e777ceeSAndreas Gohr $this->setServer('REQUEST_METHOD', 'GET'); 2424d053d04SAndreas Gohr return $this->execute($uri); 2439e777ceeSAndreas Gohr } 2449e777ceeSAndreas Gohr 245572dc222SLarsDW223 /** 246444d58a8SAndreas Gohr * Callback for ob_start 247444d58a8SAndreas Gohr * 248444d58a8SAndreas Gohr * This continues to fill our own buffer, even when some part 249444d58a8SAndreas Gohr * of the code askes for flushing the buffers 250444d58a8SAndreas Gohr * 251444d58a8SAndreas Gohr * @param string $buffer 252444d58a8SAndreas Gohr */ 253444d58a8SAndreas Gohr public function ob_start_callback($buffer) { 254444d58a8SAndreas Gohr $this->output_buffer .= $buffer; 255444d58a8SAndreas Gohr } 256444d58a8SAndreas Gohr 257444d58a8SAndreas Gohr /** 25827c0c399SAndreas Gohr * Access the TestRequest from the executed code 25927c0c399SAndreas Gohr * 26027c0c399SAndreas Gohr * This allows certain functions to access the TestRequest that is accessing them 26127c0c399SAndreas Gohr * to add additional info. 26227c0c399SAndreas Gohr * 26327c0c399SAndreas Gohr * @return null|TestRequest the currently executed request if any 264572dc222SLarsDW223 */ 26527c0c399SAndreas Gohr public static function getRunning() { 26627c0c399SAndreas Gohr return self::$running; 26727c0c399SAndreas Gohr } 26827c0c399SAndreas Gohr 26927c0c399SAndreas Gohr /** 27027c0c399SAndreas Gohr * Store data to be read in the response later 27127c0c399SAndreas Gohr * 27227c0c399SAndreas Gohr * When called multiple times with the same key, the data is appended to this 27327c0c399SAndreas Gohr * key's array 27427c0c399SAndreas Gohr * 27527c0c399SAndreas Gohr * @param string $key the identifier for this information 27627c0c399SAndreas Gohr * @param mixed $value arbitrary data to store 27727c0c399SAndreas Gohr */ 27827c0c399SAndreas Gohr public function addData($key, $value) { 27927c0c399SAndreas Gohr if(!isset($this->data[$key])) $this->data[$key] = array(); 28027c0c399SAndreas Gohr $this->data[$key][] = $value; 281572dc222SLarsDW223 } 282f8369d7dSTobias Sarnowski} 283