xref: /dokuwiki/_test/core/TestRequest.php (revision 1ada9e0af1c0660c512bf5aa0e313746a5d95a26)
1<?php
2/**
3 * Simulates a full DokuWiki HTTP Request and allows
4 * runtime inspection.
5 */
6
7// output buffering
8$output_buffer = '';
9
10$currentTestRequest = null;
11
12function ob_start_callback($buffer) {
13    global $output_buffer;
14    $output_buffer .= $buffer;
15}
16
17/**
18 * Helper class to execute a fake request
19 */
20class TestRequest {
21
22    protected $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php');
23    protected $script;
24
25    protected $server = array();
26    protected $session = array();
27    protected $get = array();
28    protected $post = array();
29    protected $notifications = array();
30
31    /**
32     * Get a $_SERVER var
33     *
34     * @param string $key
35     * @return mixed
36     */
37    public function getServer($key) {
38        return $this->server[$key];
39    }
40
41    /**
42     * Get a $_SESSION var
43     *
44     * @param string $key
45     * @return mixed
46     */
47    public function getSession($key) {
48        return $this->session[$key];
49    }
50
51    /**
52     * Get a $_GET var
53     *
54     * @param string $key
55     * @return mixed
56     */
57    public function getGet($key) {
58        return $this->get[$key];
59    }
60
61    /**
62     * Get a $_POST var
63     *
64     * @param string $key
65     * @return mixed
66     */
67    public function getPost($key) {
68        return $this->post[$key];
69    }
70
71    /**
72     * Get the script that will execute the request
73     *
74     * @return string
75     */
76    public function getScript() {
77        return $this->script;
78    }
79
80    /**
81     * Set a $_SERVER var
82     *
83     * @param string $key
84     * @param mixed $value
85     */
86    public function setServer($key, $value) {
87        $this->server[$key] = $value;
88    }
89
90    /**
91     * Set a $_SESSION var
92     *
93     * @param string $key
94     * @param mixed $value
95     */
96    public function setSession($key, $value) {
97        $this->session[$key] = $value;
98    }
99
100    /**
101     * Set a $_GET var
102     *
103     * @param string $key
104     * @param mixed $value
105     */
106    public function setGet($key, $value) {
107        $this->get[$key] = $value;
108    }
109
110    /**
111     * Set a $_POST var
112     *
113     * @param string $key
114     * @param mixed $value
115     */
116    public function setPost($key, $value) {
117        $this->post[$key] = $value;
118    }
119
120    /**
121     * Executes the request
122     *
123     * @param string $uri end URL to simulate, needs to be one of the testable scripts
124     * @return TestResponse the resulting output of the request
125     */
126    public function execute($uri = '/doku.php') {
127        global $INPUT;
128        global $currentTestRequest;
129
130        $currentTestRequest = $this;
131
132        // save old environment
133        $server = $_SERVER;
134        $session = $_SESSION;
135        $get = $_GET;
136        $post = $_POST;
137        $request = $_REQUEST;
138        $input = $INPUT;
139
140        // prepare the right URI
141        $this->setUri($uri);
142
143        // import all defined globals into the function scope
144        foreach(array_keys($GLOBALS) as $glb) {
145            global $$glb;
146        }
147
148        // fake environment
149        global $default_server_vars;
150        $_SERVER = array_merge($default_server_vars, $this->server);
151        $_SESSION = $this->session;
152        $_GET = $this->get;
153        $_POST = $this->post;
154        $_REQUEST = array_merge($_GET, $_POST);
155
156        // reset output buffer
157        global $output_buffer;
158        $output_buffer = '';
159
160        // now execute dokuwiki and grep the output
161        header_remove();
162        ob_start('ob_start_callback');
163        $INPUT = new Input();
164        include(DOKU_INC . $this->script);
165        ob_end_flush();
166
167        // create the response object
168        $response = new TestResponse(
169            $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     * Add a notification to later store it in the test respone.
254     */
255    public function addNotification(array $new) {
256        $this->notifications[] = $new;
257    }
258}
259