Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\BrowserKit;
|
Chris@0
|
13
|
Chris@0
|
14 use Symfony\Component\DomCrawler\Crawler;
|
Chris@0
|
15 use Symfony\Component\DomCrawler\Link;
|
Chris@0
|
16 use Symfony\Component\DomCrawler\Form;
|
Chris@0
|
17 use Symfony\Component\Process\PhpProcess;
|
Chris@0
|
18
|
Chris@0
|
19 /**
|
Chris@0
|
20 * Client simulates a browser.
|
Chris@0
|
21 *
|
Chris@0
|
22 * To make the actual request, you need to implement the doRequest() method.
|
Chris@0
|
23 *
|
Chris@0
|
24 * If you want to be able to run requests in their own process (insulated flag),
|
Chris@0
|
25 * you need to also implement the getScript() method.
|
Chris@0
|
26 *
|
Chris@0
|
27 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
28 */
|
Chris@0
|
29 abstract class Client
|
Chris@0
|
30 {
|
Chris@0
|
31 protected $history;
|
Chris@0
|
32 protected $cookieJar;
|
Chris@0
|
33 protected $server = array();
|
Chris@0
|
34 protected $internalRequest;
|
Chris@0
|
35 protected $request;
|
Chris@0
|
36 protected $internalResponse;
|
Chris@0
|
37 protected $response;
|
Chris@0
|
38 protected $crawler;
|
Chris@0
|
39 protected $insulated = false;
|
Chris@0
|
40 protected $redirect;
|
Chris@0
|
41 protected $followRedirects = true;
|
Chris@0
|
42
|
Chris@0
|
43 private $maxRedirects = -1;
|
Chris@0
|
44 private $redirectCount = 0;
|
Chris@0
|
45 private $isMainRequest = true;
|
Chris@0
|
46
|
Chris@0
|
47 /**
|
Chris@0
|
48 * Constructor.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @param array $server The server parameters (equivalent of $_SERVER)
|
Chris@0
|
51 * @param History $history A History instance to store the browser history
|
Chris@0
|
52 * @param CookieJar $cookieJar A CookieJar instance to store the cookies
|
Chris@0
|
53 */
|
Chris@0
|
54 public function __construct(array $server = array(), History $history = null, CookieJar $cookieJar = null)
|
Chris@0
|
55 {
|
Chris@0
|
56 $this->setServerParameters($server);
|
Chris@0
|
57 $this->history = $history ?: new History();
|
Chris@0
|
58 $this->cookieJar = $cookieJar ?: new CookieJar();
|
Chris@0
|
59 }
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * Sets whether to automatically follow redirects or not.
|
Chris@0
|
63 *
|
Chris@0
|
64 * @param bool $followRedirect Whether to follow redirects
|
Chris@0
|
65 */
|
Chris@0
|
66 public function followRedirects($followRedirect = true)
|
Chris@0
|
67 {
|
Chris@0
|
68 $this->followRedirects = (bool) $followRedirect;
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 /**
|
Chris@0
|
72 * Returns whether client automatically follows redirects or not.
|
Chris@0
|
73 *
|
Chris@0
|
74 * @return bool
|
Chris@0
|
75 */
|
Chris@0
|
76 public function isFollowingRedirects()
|
Chris@0
|
77 {
|
Chris@0
|
78 return $this->followRedirects;
|
Chris@0
|
79 }
|
Chris@0
|
80
|
Chris@0
|
81 /**
|
Chris@0
|
82 * Sets the maximum number of requests that crawler can follow.
|
Chris@0
|
83 *
|
Chris@0
|
84 * @param int $maxRedirects
|
Chris@0
|
85 */
|
Chris@0
|
86 public function setMaxRedirects($maxRedirects)
|
Chris@0
|
87 {
|
Chris@0
|
88 $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
|
Chris@0
|
89 $this->followRedirects = -1 != $this->maxRedirects;
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 /**
|
Chris@0
|
93 * Returns the maximum number of requests that crawler can follow.
|
Chris@0
|
94 *
|
Chris@0
|
95 * @return int
|
Chris@0
|
96 */
|
Chris@0
|
97 public function getMaxRedirects()
|
Chris@0
|
98 {
|
Chris@0
|
99 return $this->maxRedirects;
|
Chris@0
|
100 }
|
Chris@0
|
101
|
Chris@0
|
102 /**
|
Chris@0
|
103 * Sets the insulated flag.
|
Chris@0
|
104 *
|
Chris@0
|
105 * @param bool $insulated Whether to insulate the requests or not
|
Chris@0
|
106 *
|
Chris@0
|
107 * @throws \RuntimeException When Symfony Process Component is not installed
|
Chris@0
|
108 */
|
Chris@0
|
109 public function insulate($insulated = true)
|
Chris@0
|
110 {
|
Chris@0
|
111 if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) {
|
Chris@0
|
112 throw new \RuntimeException('Unable to isolate requests as the Symfony Process Component is not installed.');
|
Chris@0
|
113 }
|
Chris@0
|
114
|
Chris@0
|
115 $this->insulated = (bool) $insulated;
|
Chris@0
|
116 }
|
Chris@0
|
117
|
Chris@0
|
118 /**
|
Chris@0
|
119 * Sets server parameters.
|
Chris@0
|
120 *
|
Chris@0
|
121 * @param array $server An array of server parameters
|
Chris@0
|
122 */
|
Chris@0
|
123 public function setServerParameters(array $server)
|
Chris@0
|
124 {
|
Chris@0
|
125 $this->server = array_merge(array(
|
Chris@0
|
126 'HTTP_USER_AGENT' => 'Symfony BrowserKit',
|
Chris@0
|
127 ), $server);
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 /**
|
Chris@0
|
131 * Sets single server parameter.
|
Chris@0
|
132 *
|
Chris@0
|
133 * @param string $key A key of the parameter
|
Chris@0
|
134 * @param string $value A value of the parameter
|
Chris@0
|
135 */
|
Chris@0
|
136 public function setServerParameter($key, $value)
|
Chris@0
|
137 {
|
Chris@0
|
138 $this->server[$key] = $value;
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 /**
|
Chris@0
|
142 * Gets single server parameter for specified key.
|
Chris@0
|
143 *
|
Chris@0
|
144 * @param string $key A key of the parameter to get
|
Chris@0
|
145 * @param string $default A default value when key is undefined
|
Chris@0
|
146 *
|
Chris@0
|
147 * @return string A value of the parameter
|
Chris@0
|
148 */
|
Chris@0
|
149 public function getServerParameter($key, $default = '')
|
Chris@0
|
150 {
|
Chris@0
|
151 return isset($this->server[$key]) ? $this->server[$key] : $default;
|
Chris@0
|
152 }
|
Chris@0
|
153
|
Chris@0
|
154 /**
|
Chris@0
|
155 * Returns the History instance.
|
Chris@0
|
156 *
|
Chris@0
|
157 * @return History A History instance
|
Chris@0
|
158 */
|
Chris@0
|
159 public function getHistory()
|
Chris@0
|
160 {
|
Chris@0
|
161 return $this->history;
|
Chris@0
|
162 }
|
Chris@0
|
163
|
Chris@0
|
164 /**
|
Chris@0
|
165 * Returns the CookieJar instance.
|
Chris@0
|
166 *
|
Chris@0
|
167 * @return CookieJar A CookieJar instance
|
Chris@0
|
168 */
|
Chris@0
|
169 public function getCookieJar()
|
Chris@0
|
170 {
|
Chris@0
|
171 return $this->cookieJar;
|
Chris@0
|
172 }
|
Chris@0
|
173
|
Chris@0
|
174 /**
|
Chris@0
|
175 * Returns the current Crawler instance.
|
Chris@0
|
176 *
|
Chris@0
|
177 * @return Crawler|null A Crawler instance
|
Chris@0
|
178 */
|
Chris@0
|
179 public function getCrawler()
|
Chris@0
|
180 {
|
Chris@0
|
181 return $this->crawler;
|
Chris@0
|
182 }
|
Chris@0
|
183
|
Chris@0
|
184 /**
|
Chris@0
|
185 * Returns the current BrowserKit Response instance.
|
Chris@0
|
186 *
|
Chris@0
|
187 * @return Response|null A BrowserKit Response instance
|
Chris@0
|
188 */
|
Chris@0
|
189 public function getInternalResponse()
|
Chris@0
|
190 {
|
Chris@0
|
191 return $this->internalResponse;
|
Chris@0
|
192 }
|
Chris@0
|
193
|
Chris@0
|
194 /**
|
Chris@0
|
195 * Returns the current origin response instance.
|
Chris@0
|
196 *
|
Chris@0
|
197 * The origin response is the response instance that is returned
|
Chris@0
|
198 * by the code that handles requests.
|
Chris@0
|
199 *
|
Chris@0
|
200 * @return object|null A response instance
|
Chris@0
|
201 *
|
Chris@0
|
202 * @see doRequest()
|
Chris@0
|
203 */
|
Chris@0
|
204 public function getResponse()
|
Chris@0
|
205 {
|
Chris@0
|
206 return $this->response;
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 /**
|
Chris@0
|
210 * Returns the current BrowserKit Request instance.
|
Chris@0
|
211 *
|
Chris@0
|
212 * @return Request|null A BrowserKit Request instance
|
Chris@0
|
213 */
|
Chris@0
|
214 public function getInternalRequest()
|
Chris@0
|
215 {
|
Chris@0
|
216 return $this->internalRequest;
|
Chris@0
|
217 }
|
Chris@0
|
218
|
Chris@0
|
219 /**
|
Chris@0
|
220 * Returns the current origin Request instance.
|
Chris@0
|
221 *
|
Chris@0
|
222 * The origin request is the request instance that is sent
|
Chris@0
|
223 * to the code that handles requests.
|
Chris@0
|
224 *
|
Chris@0
|
225 * @return object|null A Request instance
|
Chris@0
|
226 *
|
Chris@0
|
227 * @see doRequest()
|
Chris@0
|
228 */
|
Chris@0
|
229 public function getRequest()
|
Chris@0
|
230 {
|
Chris@0
|
231 return $this->request;
|
Chris@0
|
232 }
|
Chris@0
|
233
|
Chris@0
|
234 /**
|
Chris@0
|
235 * Clicks on a given link.
|
Chris@0
|
236 *
|
Chris@0
|
237 * @param Link $link A Link instance
|
Chris@0
|
238 *
|
Chris@0
|
239 * @return Crawler
|
Chris@0
|
240 */
|
Chris@0
|
241 public function click(Link $link)
|
Chris@0
|
242 {
|
Chris@0
|
243 if ($link instanceof Form) {
|
Chris@0
|
244 return $this->submit($link);
|
Chris@0
|
245 }
|
Chris@0
|
246
|
Chris@0
|
247 return $this->request($link->getMethod(), $link->getUri());
|
Chris@0
|
248 }
|
Chris@0
|
249
|
Chris@0
|
250 /**
|
Chris@0
|
251 * Submits a form.
|
Chris@0
|
252 *
|
Chris@0
|
253 * @param Form $form A Form instance
|
Chris@0
|
254 * @param array $values An array of form field values
|
Chris@0
|
255 *
|
Chris@0
|
256 * @return Crawler
|
Chris@0
|
257 */
|
Chris@0
|
258 public function submit(Form $form, array $values = array())
|
Chris@0
|
259 {
|
Chris@0
|
260 $form->setValues($values);
|
Chris@0
|
261
|
Chris@0
|
262 return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles());
|
Chris@0
|
263 }
|
Chris@0
|
264
|
Chris@0
|
265 /**
|
Chris@0
|
266 * Calls a URI.
|
Chris@0
|
267 *
|
Chris@0
|
268 * @param string $method The request method
|
Chris@0
|
269 * @param string $uri The URI to fetch
|
Chris@0
|
270 * @param array $parameters The Request parameters
|
Chris@0
|
271 * @param array $files The files
|
Chris@0
|
272 * @param array $server The server parameters (HTTP headers are referenced with a HTTP_ prefix as PHP does)
|
Chris@0
|
273 * @param string $content The raw body data
|
Chris@0
|
274 * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
|
Chris@0
|
275 *
|
Chris@0
|
276 * @return Crawler
|
Chris@0
|
277 */
|
Chris@0
|
278 public function request($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = true)
|
Chris@0
|
279 {
|
Chris@0
|
280 if ($this->isMainRequest) {
|
Chris@0
|
281 $this->redirectCount = 0;
|
Chris@0
|
282 } else {
|
Chris@0
|
283 ++$this->redirectCount;
|
Chris@0
|
284 }
|
Chris@0
|
285
|
Chris@0
|
286 $uri = $this->getAbsoluteUri($uri);
|
Chris@0
|
287
|
Chris@0
|
288 $server = array_merge($this->server, $server);
|
Chris@0
|
289
|
Chris@0
|
290 if (isset($server['HTTPS'])) {
|
Chris@0
|
291 $uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
|
Chris@0
|
292 }
|
Chris@0
|
293
|
Chris@0
|
294 if (!$this->history->isEmpty()) {
|
Chris@0
|
295 $server['HTTP_REFERER'] = $this->history->current()->getUri();
|
Chris@0
|
296 }
|
Chris@0
|
297
|
Chris@0
|
298 if (empty($server['HTTP_HOST'])) {
|
Chris@0
|
299 $server['HTTP_HOST'] = $this->extractHost($uri);
|
Chris@0
|
300 }
|
Chris@0
|
301
|
Chris@0
|
302 $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME);
|
Chris@0
|
303
|
Chris@0
|
304 $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);
|
Chris@0
|
305
|
Chris@0
|
306 $this->request = $this->filterRequest($this->internalRequest);
|
Chris@0
|
307
|
Chris@0
|
308 if (true === $changeHistory) {
|
Chris@0
|
309 $this->history->add($this->internalRequest);
|
Chris@0
|
310 }
|
Chris@0
|
311
|
Chris@0
|
312 if ($this->insulated) {
|
Chris@0
|
313 $this->response = $this->doRequestInProcess($this->request);
|
Chris@0
|
314 } else {
|
Chris@0
|
315 $this->response = $this->doRequest($this->request);
|
Chris@0
|
316 }
|
Chris@0
|
317
|
Chris@0
|
318 $this->internalResponse = $this->filterResponse($this->response);
|
Chris@0
|
319
|
Chris@0
|
320 $this->cookieJar->updateFromResponse($this->internalResponse, $uri);
|
Chris@0
|
321
|
Chris@0
|
322 $status = $this->internalResponse->getStatus();
|
Chris@0
|
323
|
Chris@0
|
324 if ($status >= 300 && $status < 400) {
|
Chris@0
|
325 $this->redirect = $this->internalResponse->getHeader('Location');
|
Chris@0
|
326 } else {
|
Chris@0
|
327 $this->redirect = null;
|
Chris@0
|
328 }
|
Chris@0
|
329
|
Chris@0
|
330 if ($this->followRedirects && $this->redirect) {
|
Chris@0
|
331 return $this->crawler = $this->followRedirect();
|
Chris@0
|
332 }
|
Chris@0
|
333
|
Chris@0
|
334 return $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));
|
Chris@0
|
335 }
|
Chris@0
|
336
|
Chris@0
|
337 /**
|
Chris@0
|
338 * Makes a request in another process.
|
Chris@0
|
339 *
|
Chris@0
|
340 * @param object $request An origin request instance
|
Chris@0
|
341 *
|
Chris@0
|
342 * @return object An origin response instance
|
Chris@0
|
343 *
|
Chris@0
|
344 * @throws \RuntimeException When processing returns exit code
|
Chris@0
|
345 */
|
Chris@0
|
346 protected function doRequestInProcess($request)
|
Chris@0
|
347 {
|
Chris@0
|
348 $process = new PhpProcess($this->getScript($request), null, null);
|
Chris@0
|
349 $process->run();
|
Chris@0
|
350
|
Chris@0
|
351 if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) {
|
Chris@0
|
352 throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput()));
|
Chris@0
|
353 }
|
Chris@0
|
354
|
Chris@0
|
355 return unserialize($process->getOutput());
|
Chris@0
|
356 }
|
Chris@0
|
357
|
Chris@0
|
358 /**
|
Chris@0
|
359 * Makes a request.
|
Chris@0
|
360 *
|
Chris@0
|
361 * @param object $request An origin request instance
|
Chris@0
|
362 *
|
Chris@0
|
363 * @return object An origin response instance
|
Chris@0
|
364 */
|
Chris@0
|
365 abstract protected function doRequest($request);
|
Chris@0
|
366
|
Chris@0
|
367 /**
|
Chris@0
|
368 * Returns the script to execute when the request must be insulated.
|
Chris@0
|
369 *
|
Chris@0
|
370 * @param object $request An origin request instance
|
Chris@0
|
371 *
|
Chris@0
|
372 * @throws \LogicException When this abstract class is not implemented
|
Chris@0
|
373 */
|
Chris@0
|
374 protected function getScript($request)
|
Chris@0
|
375 {
|
Chris@0
|
376 throw new \LogicException('To insulate requests, you need to override the getScript() method.');
|
Chris@0
|
377 }
|
Chris@0
|
378
|
Chris@0
|
379 /**
|
Chris@0
|
380 * Filters the BrowserKit request to the origin one.
|
Chris@0
|
381 *
|
Chris@0
|
382 * @param Request $request The BrowserKit Request to filter
|
Chris@0
|
383 *
|
Chris@0
|
384 * @return object An origin request instance
|
Chris@0
|
385 */
|
Chris@0
|
386 protected function filterRequest(Request $request)
|
Chris@0
|
387 {
|
Chris@0
|
388 return $request;
|
Chris@0
|
389 }
|
Chris@0
|
390
|
Chris@0
|
391 /**
|
Chris@0
|
392 * Filters the origin response to the BrowserKit one.
|
Chris@0
|
393 *
|
Chris@0
|
394 * @param object $response The origin response to filter
|
Chris@0
|
395 *
|
Chris@0
|
396 * @return Response An BrowserKit Response instance
|
Chris@0
|
397 */
|
Chris@0
|
398 protected function filterResponse($response)
|
Chris@0
|
399 {
|
Chris@0
|
400 return $response;
|
Chris@0
|
401 }
|
Chris@0
|
402
|
Chris@0
|
403 /**
|
Chris@0
|
404 * Creates a crawler.
|
Chris@0
|
405 *
|
Chris@0
|
406 * This method returns null if the DomCrawler component is not available.
|
Chris@0
|
407 *
|
Chris@0
|
408 * @param string $uri A URI
|
Chris@0
|
409 * @param string $content Content for the crawler to use
|
Chris@0
|
410 * @param string $type Content type
|
Chris@0
|
411 *
|
Chris@0
|
412 * @return Crawler|null
|
Chris@0
|
413 */
|
Chris@0
|
414 protected function createCrawlerFromContent($uri, $content, $type)
|
Chris@0
|
415 {
|
Chris@0
|
416 if (!class_exists('Symfony\Component\DomCrawler\Crawler')) {
|
Chris@0
|
417 return;
|
Chris@0
|
418 }
|
Chris@0
|
419
|
Chris@0
|
420 $crawler = new Crawler(null, $uri);
|
Chris@0
|
421 $crawler->addContent($content, $type);
|
Chris@0
|
422
|
Chris@0
|
423 return $crawler;
|
Chris@0
|
424 }
|
Chris@0
|
425
|
Chris@0
|
426 /**
|
Chris@0
|
427 * Goes back in the browser history.
|
Chris@0
|
428 *
|
Chris@0
|
429 * @return Crawler
|
Chris@0
|
430 */
|
Chris@0
|
431 public function back()
|
Chris@0
|
432 {
|
Chris@0
|
433 return $this->requestFromRequest($this->history->back(), false);
|
Chris@0
|
434 }
|
Chris@0
|
435
|
Chris@0
|
436 /**
|
Chris@0
|
437 * Goes forward in the browser history.
|
Chris@0
|
438 *
|
Chris@0
|
439 * @return Crawler
|
Chris@0
|
440 */
|
Chris@0
|
441 public function forward()
|
Chris@0
|
442 {
|
Chris@0
|
443 return $this->requestFromRequest($this->history->forward(), false);
|
Chris@0
|
444 }
|
Chris@0
|
445
|
Chris@0
|
446 /**
|
Chris@0
|
447 * Reloads the current browser.
|
Chris@0
|
448 *
|
Chris@0
|
449 * @return Crawler
|
Chris@0
|
450 */
|
Chris@0
|
451 public function reload()
|
Chris@0
|
452 {
|
Chris@0
|
453 return $this->requestFromRequest($this->history->current(), false);
|
Chris@0
|
454 }
|
Chris@0
|
455
|
Chris@0
|
456 /**
|
Chris@0
|
457 * Follow redirects?
|
Chris@0
|
458 *
|
Chris@0
|
459 * @return Crawler
|
Chris@0
|
460 *
|
Chris@0
|
461 * @throws \LogicException If request was not a redirect
|
Chris@0
|
462 */
|
Chris@0
|
463 public function followRedirect()
|
Chris@0
|
464 {
|
Chris@0
|
465 if (empty($this->redirect)) {
|
Chris@0
|
466 throw new \LogicException('The request was not redirected.');
|
Chris@0
|
467 }
|
Chris@0
|
468
|
Chris@0
|
469 if (-1 !== $this->maxRedirects) {
|
Chris@0
|
470 if ($this->redirectCount > $this->maxRedirects) {
|
Chris@0
|
471 throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
|
Chris@0
|
472 }
|
Chris@0
|
473 }
|
Chris@0
|
474
|
Chris@0
|
475 $request = $this->internalRequest;
|
Chris@0
|
476
|
Chris@0
|
477 if (in_array($this->internalResponse->getStatus(), array(302, 303))) {
|
Chris@0
|
478 $method = 'GET';
|
Chris@0
|
479 $files = array();
|
Chris@0
|
480 $content = null;
|
Chris@0
|
481 } else {
|
Chris@0
|
482 $method = $request->getMethod();
|
Chris@0
|
483 $files = $request->getFiles();
|
Chris@0
|
484 $content = $request->getContent();
|
Chris@0
|
485 }
|
Chris@0
|
486
|
Chris@0
|
487 if ('GET' === strtoupper($method)) {
|
Chris@0
|
488 // Don't forward parameters for GET request as it should reach the redirection URI
|
Chris@0
|
489 $parameters = array();
|
Chris@0
|
490 } else {
|
Chris@0
|
491 $parameters = $request->getParameters();
|
Chris@0
|
492 }
|
Chris@0
|
493
|
Chris@0
|
494 $server = $request->getServer();
|
Chris@0
|
495 $server = $this->updateServerFromUri($server, $this->redirect);
|
Chris@0
|
496
|
Chris@0
|
497 $this->isMainRequest = false;
|
Chris@0
|
498
|
Chris@0
|
499 $response = $this->request($method, $this->redirect, $parameters, $files, $server, $content);
|
Chris@0
|
500
|
Chris@0
|
501 $this->isMainRequest = true;
|
Chris@0
|
502
|
Chris@0
|
503 return $response;
|
Chris@0
|
504 }
|
Chris@0
|
505
|
Chris@0
|
506 /**
|
Chris@0
|
507 * Restarts the client.
|
Chris@0
|
508 *
|
Chris@0
|
509 * It flushes history and all cookies.
|
Chris@0
|
510 */
|
Chris@0
|
511 public function restart()
|
Chris@0
|
512 {
|
Chris@0
|
513 $this->cookieJar->clear();
|
Chris@0
|
514 $this->history->clear();
|
Chris@0
|
515 }
|
Chris@0
|
516
|
Chris@0
|
517 /**
|
Chris@0
|
518 * Takes a URI and converts it to absolute if it is not already absolute.
|
Chris@0
|
519 *
|
Chris@0
|
520 * @param string $uri A URI
|
Chris@0
|
521 *
|
Chris@0
|
522 * @return string An absolute URI
|
Chris@0
|
523 */
|
Chris@0
|
524 protected function getAbsoluteUri($uri)
|
Chris@0
|
525 {
|
Chris@0
|
526 // already absolute?
|
Chris@0
|
527 if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) {
|
Chris@0
|
528 return $uri;
|
Chris@0
|
529 }
|
Chris@0
|
530
|
Chris@0
|
531 if (!$this->history->isEmpty()) {
|
Chris@0
|
532 $currentUri = $this->history->current()->getUri();
|
Chris@0
|
533 } else {
|
Chris@0
|
534 $currentUri = sprintf('http%s://%s/',
|
Chris@0
|
535 isset($this->server['HTTPS']) ? 's' : '',
|
Chris@0
|
536 isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost'
|
Chris@0
|
537 );
|
Chris@0
|
538 }
|
Chris@0
|
539
|
Chris@0
|
540 // protocol relative URL
|
Chris@0
|
541 if (0 === strpos($uri, '//')) {
|
Chris@0
|
542 return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri;
|
Chris@0
|
543 }
|
Chris@0
|
544
|
Chris@0
|
545 // anchor or query string parameters?
|
Chris@0
|
546 if (!$uri || '#' == $uri[0] || '?' == $uri[0]) {
|
Chris@0
|
547 return preg_replace('/[#?].*?$/', '', $currentUri).$uri;
|
Chris@0
|
548 }
|
Chris@0
|
549
|
Chris@0
|
550 if ('/' !== $uri[0]) {
|
Chris@0
|
551 $path = parse_url($currentUri, PHP_URL_PATH);
|
Chris@0
|
552
|
Chris@0
|
553 if ('/' !== substr($path, -1)) {
|
Chris@0
|
554 $path = substr($path, 0, strrpos($path, '/') + 1);
|
Chris@0
|
555 }
|
Chris@0
|
556
|
Chris@0
|
557 $uri = $path.$uri;
|
Chris@0
|
558 }
|
Chris@0
|
559
|
Chris@0
|
560 return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri;
|
Chris@0
|
561 }
|
Chris@0
|
562
|
Chris@0
|
563 /**
|
Chris@0
|
564 * Makes a request from a Request object directly.
|
Chris@0
|
565 *
|
Chris@0
|
566 * @param Request $request A Request instance
|
Chris@0
|
567 * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
|
Chris@0
|
568 *
|
Chris@0
|
569 * @return Crawler
|
Chris@0
|
570 */
|
Chris@0
|
571 protected function requestFromRequest(Request $request, $changeHistory = true)
|
Chris@0
|
572 {
|
Chris@0
|
573 return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory);
|
Chris@0
|
574 }
|
Chris@0
|
575
|
Chris@0
|
576 private function updateServerFromUri($server, $uri)
|
Chris@0
|
577 {
|
Chris@0
|
578 $server['HTTP_HOST'] = $this->extractHost($uri);
|
Chris@0
|
579 $scheme = parse_url($uri, PHP_URL_SCHEME);
|
Chris@0
|
580 $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme;
|
Chris@0
|
581 unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']);
|
Chris@0
|
582
|
Chris@0
|
583 return $server;
|
Chris@0
|
584 }
|
Chris@0
|
585
|
Chris@0
|
586 private function extractHost($uri)
|
Chris@0
|
587 {
|
Chris@0
|
588 $host = parse_url($uri, PHP_URL_HOST);
|
Chris@0
|
589
|
Chris@0
|
590 if ($port = parse_url($uri, PHP_URL_PORT)) {
|
Chris@0
|
591 return $host.':'.$port;
|
Chris@0
|
592 }
|
Chris@0
|
593
|
Chris@0
|
594 return $host;
|
Chris@0
|
595 }
|
Chris@0
|
596 }
|