xref: /dokuwiki/_test/core/TestRequest.php (revision 9f236ef28b069f14b4bd71cac7b91de7296dcf18)
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/**
19 * Helper class to execute a fake request
20 */
21class TestRequest {
22
23    private $valid_scripts = array('/doku.php', '/lib/exe/fetch.php', '/lib/exe/detail.php', '/lib/exe/ajax.php');
24    private $script;
25
26    private $server = array();
27    private $session = array();
28    private $get = array();
29    private $post = array();
30    private $notifications = array();
31
32    public function getServer($key) { return $this->server[$key]; }
33    public function getSession($key) { return $this->session[$key]; }
34    public function getGet($key) { return $this->get[$key]; }
35    public function getPost($key) { return $this->post[$key]; }
36    public function getScript() { return $this->script; }
37
38    public function setServer($key, $value) { $this->server[$key] = $value; }
39    public function setSession($key, $value) { $this->session[$key] = $value; }
40    public function setGet($key, $value) { $this->get[$key] = $value; }
41    public function setPost($key, $value) { $this->post[$key] = $value; }
42
43    /**
44     * Executes the request
45     *
46     * @param string $url  end URL to simulate, needs to start with /doku.php currently
47     * @return TestResponse the resulting output of the request
48     */
49    public function execute($uri='/doku.php') {
50        global $INPUT;
51        global $currentTestRequest;
52
53        $currentTestRequest = $this;
54
55        // save old environment
56        $server = $_SERVER;
57        $session = $_SESSION;
58        $get = $_GET;
59        $post = $_POST;
60        $request = $_REQUEST;
61        $input = $INPUT;
62
63        // prepare the right URI
64        $this->setUri($uri);
65
66        // import all defined globals into the function scope
67        foreach(array_keys($GLOBALS) as $glb){
68            global $$glb;
69        }
70
71        // fake environment
72        global $default_server_vars;
73        $_SERVER = array_merge($default_server_vars, $this->server);
74        $_SESSION = $this->session;
75        $_GET = $this->get;
76        $_POST = $this->post;
77        $_REQUEST = array_merge($_GET, $_POST);
78
79        // reset output buffer
80        global $output_buffer;
81        $output_buffer = '';
82
83        // now execute dokuwiki and grep the output
84        header_remove();
85        ob_start('ob_start_callback');
86        $INPUT = new Input();
87        include(DOKU_INC.$this->script);
88        ob_end_flush();
89
90        // create the response object
91        $response = new TestResponse(
92            $output_buffer,
93            (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list())   // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli
94        );
95        if ($this->notifications != null) {
96            $response->setNotifications($this->notifications);
97        }
98
99        // reset environment
100        $_SERVER = $server;
101        $_SESSION = $session;
102        $_GET = $get;
103        $_POST = $post;
104        $_REQUEST = $request;
105        $INPUT = $input;
106
107        $currentTestRequest = null;
108
109        return $response;
110    }
111
112    /**
113     * Set the virtual URI the request works against
114     *
115     * This parses the given URI and sets any contained GET variables
116     * but will not overwrite any previously set ones (eg. set via setGet()).
117     *
118     * It initializes the $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING']
119     * with all set GET variables.
120     *
121     * @param string $url  end URL to simulate, needs to start with /doku.php currently
122     * @todo make this work with other end points
123     */
124    protected function setUri($uri){
125        if(!preg_match('#^('.join('|',$this->valid_scripts).')#',$uri)){
126            throw new Exception("$uri \n--- only ".join(', ',$this->valid_scripts)." are supported currently");
127        }
128
129        $params = array();
130        list($uri, $query) = explode('?',$uri,2);
131        if($query) parse_str($query, $params);
132
133        $this->script = substr($uri,1);
134        $this->get  = array_merge($params, $this->get);
135        if(count($this->get)){
136            $query = '?'.http_build_query($this->get, '', '&');
137            $query = str_replace(
138                array('%3A', '%5B', '%5D'),
139                array(':', '[', ']'),
140                $query
141            );
142            $uri = $uri.$query;
143        }
144
145        $this->setServer('QUERY_STRING', $query);
146        $this->setServer('REQUEST_URI', $uri);
147    }
148
149    /**
150     * Simulate a POST request with the given variables
151     *
152     * @param array $post  all the POST parameters to use
153     * @param string $url  end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently
154     * @param return TestResponse
155     */
156    public function post($post=array(), $uri='/doku.php') {
157        $this->post = array_merge($this->post, $post);
158        $this->setServer('REQUEST_METHOD', 'POST');
159        return $this->execute($uri);
160    }
161
162    /**
163     * Simulate a GET request with the given variables
164     *
165     * @param array $GET   all the GET parameters to use
166     * @param string $url  end URL to simulate, needs to start with /doku.php, /lib/exe/fetch.php or /lib/exe/detail.php currently
167     * @param return TestResponse
168     */
169    public function get($get=array(), $uri='/doku.php') {
170        $this->get  = array_merge($this->get, $get);
171        $this->setServer('REQUEST_METHOD', 'GET');
172        return $this->execute($uri);
173    }
174
175    /**
176     * Add a notification to later store it in the test respone.
177     */
178    public function addNotification(array $new) {
179        $this->notifications[] = $new;
180    }
181}
182