Development

/branches/1.2/lib/util/sfBrowserBase.class.php

You must first sign up to be able to contribute.

root/branches/1.2/lib/util/sfBrowserBase.class.php

Revision 27616, 24.2 kB (checked in by FabianLange, 4 years ago)

[1.2, 1.3, 1.4] passed the changeStack option in ->get() and ->post() calls of sfBrowserBase to the delegated ->call() (fixes #4271)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * sfBrowserBase is the base class for sfBrowser.
13  *
14  * It implements features that is independent from the symfony controllers.
15  *
16  * @package    symfony
17  * @subpackage util
18  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
19  * @version    SVN: $Id$
20  */
21 abstract class sfBrowserBase
22 {
23   protected
24     $hostname           = null,
25     $remote             = null,
26     $dom                = null,
27     $stack              = array(),
28     $stackPosition      = -1,
29     $cookieJar          = array(),
30     $fields             = array(),
31     $files              = array(),
32     $vars               = array(),
33     $defaultServerArray = array(),
34     $headers            = array(),
35     $currentException   = null;
36
37   /**
38    * Class constructor.
39    *
40    * @param string $hostname  Hostname to browse
41    * @param string $remote    Remote address to spook
42    * @param array  $options   Options for sfBrowser
43    *
44    * @return void
45    */
46   public function __construct($hostname = null, $remote = null, $options = array())
47   {
48     $this->initialize($hostname, $remote, $options);
49   }
50
51   /**
52    * Initializes sfBrowser - sets up environment
53    *
54    * @param string $hostname  Hostname to browse
55    * @param string $remote    Remote address to spook
56    * @param array  $options   Options for sfBrowser
57    *
58    * @return void
59    */
60   public function initialize($hostname = null, $remote = null, $options = array())
61   {
62     unset($_SERVER['argv']);
63     unset($_SERVER['argc']);
64
65     // setup our fake environment
66     $this->hostname = is_null($hostname) ? 'localhost' : $hostname;
67     $this->remote   = is_null($remote) ? '127.0.0.1' : $remote;
68
69     // we set a session id (fake cookie / persistence)
70     $this->newSession();
71
72     // store default global $_SERVER array
73     $this->defaultServerArray = $_SERVER;
74
75     // register our shutdown function
76     register_shutdown_function(array($this, 'shutdown'));
77   }
78
79   /**
80    * Sets variable name
81    *
82    * @param string $name   The variable name
83    * @param mixed  $value  The value
84    *
85    * @return sfBrowserBase
86    */
87   public function setVar($name, $value)
88   {
89     $this->vars[$name] = $value;
90
91     return $this;
92   }
93
94   /**
95    * Sets a HTTP header for the very next request.
96    *
97    * @param string $header  The header name
98    * @param string $value   The header value
99    */
100   public function setHttpHeader($header, $value)
101   {
102     $this->headers[$header] = $value;
103
104     return $this;
105   }
106
107   /**
108    * Sets a cookie.
109    *
110    * @param  string  $name     The cookie name
111    * @param  string  $value    Value for the cookie
112    * @param  string  $expire   Cookie expiration period
113    * @param  string  $path     Path
114    * @param  string  $domain   Domain name
115    * @param  bool    $secure   If secure
116    * @param  bool    $httpOnly If uses only HTTP
117    *
118    * @return sfBrowserBase     This sfBrowserBase instance
119    */
120   public function setCookie($name, $value, $expire = null, $path = '/', $domain = '', $secure = false, $httpOnly = false)
121   {
122     $this->cookieJar[$name] = array(
123       'name'     => $name,
124       'value'    => $value,
125       'expire'   => $expire,
126       'path'     => $path,
127       'domain'   => $domain,
128       'secure'   => (Boolean) $secure,
129       'httpOnly' => $httpOnly,
130     );
131
132     return $this;
133   }
134
135   /**
136    * Removes a cookie by name.
137    *
138    * @param string $name   The cookie name
139    *
140    * @return sfBrowserBase This sfBrowserBase instance
141    */
142   public function removeCookie($name)
143   {
144     unset($this->cookieJar[$name]);
145
146     return $this;
147   }
148
149   /**
150    * Clears all cookies.
151    *
152    * @return sfBrowserBase This sfBrowserBase instance
153    */
154   public function clearCookies()
155   {
156     $this->cookieJar = array();
157
158     return $this;
159   }
160
161   /**
162    * Sets username and password for simulating http authentication.
163    *
164    * @param string $username  The username
165    * @param string $password  The password
166    *
167    * @return sfBrowserBase
168    */
169   public function setAuth($username, $password)
170   {
171     $this->vars['PHP_AUTH_USER'] = $username;
172     $this->vars['PHP_AUTH_PW']   = $password;
173
174     return $this;
175   }
176
177   /**
178    * Gets a uri.
179    *
180    * @param string $uri         The URI to fetch
181    * @param array  $parameters  The Request parameters
182    * @param bool   $changeStack  Change the browser history stack?
183    *
184    * @return sfBrowserBase
185    */
186   public function get($uri, $parameters = array(), $changeStack = true)
187   {
188     return $this->call($uri, 'get', $parameters, $changeStack);
189   }
190
191   /**
192    * Posts a uri.
193    *
194    * @param string $uri         The URI to fetch
195    * @param array  $parameters  The Request parameters
196    * @param bool   $changeStack  Change the browser history stack?
197    *
198    * @return sfBrowserBase
199    */
200   public function post($uri, $parameters = array(), $changeStack = true)
201   {
202     return $this->call($uri, 'post', $parameters, $changeStack);
203   }
204
205   /**
206    * Calls a request to a uri.
207    *
208    * @param string $uri          The URI to fetch
209    * @param string $method       The request method
210    * @param array  $parameters   The Request parameters
211    * @param bool   $changeStack  Change the browser history stack?
212    *
213    * @return sfBrowserBase
214    */
215   public function call($uri, $method = 'get', $parameters = array(), $changeStack = true)
216   {
217     // check that the previous call() hasn't returned an uncatched exception
218     $this->checkCurrentExceptionIsEmpty();
219
220     $uri = $this->fixUri($uri);
221
222     // add uri to the stack
223     if ($changeStack)
224     {
225       $this->stack = array_slice($this->stack, 0, $this->stackPosition + 1);
226       $this->stack[] = array(
227         'uri'        => $uri,
228         'method'     => $method,
229         'parameters' => $parameters,
230       );
231       $this->stackPosition = count($this->stack) - 1;
232     }
233
234     list($path, $queryString) = false !== ($pos = strpos($uri, '?')) ? array(substr($uri, 0, $pos), substr($uri, $pos + 1)) : array($uri, '');
235     $queryString = html_entity_decode($queryString);
236
237     // remove anchor
238     $path = preg_replace('/#.*/', '', $path);
239
240     // removes all fields from previous request
241     $this->fields = array();
242
243     // prepare the request object
244     $_SERVER = $this->defaultServerArray;
245     $_SERVER['HTTP_HOST']       = $this->hostname;
246     $_SERVER['SERVER_NAME']     = $_SERVER['HTTP_HOST'];
247     $_SERVER['SERVER_PORT']     = 80;
248     $_SERVER['HTTP_USER_AGENT'] = 'PHP5/CLI';
249     $_SERVER['REMOTE_ADDR']     = $this->remote;
250     $_SERVER['REQUEST_METHOD']  = strtoupper($method);
251     $_SERVER['PATH_INFO']       = $path;
252     $_SERVER['REQUEST_URI']     = '/index.php'.$uri;
253     $_SERVER['SCRIPT_NAME']     = '/index.php';
254     $_SERVER['SCRIPT_FILENAME'] = '/index.php';
255     $_SERVER['QUERY_STRING']    = $queryString;
256
257     if ($this->stackPosition >= 1)
258     {
259       $_SERVER['HTTP_REFERER'] = sprintf('http%s://%s%s', isset($this->defaultServerArray['HTTPS']) ? 's' : '', $this->hostname, $this->stack[$this->stackPosition - 1]['uri']);
260     }
261
262     foreach ($this->vars as $key => $value)
263     {
264       $_SERVER[strtoupper($key)] = $value;
265     }
266
267     foreach ($this->headers as $header => $value)
268     {
269       $_SERVER['HTTP_'.strtoupper(str_replace('-', '_', $header))] = $value;
270     }
271     $this->headers = array();
272
273     // request parameters
274     $_GET = $_POST = array();
275     if (in_array(strtoupper($method), array('POST', 'DELETE', 'PUT')))
276     {
277       if (isset($parameters['_with_csrf']) && $parameters['_with_csrf'])
278       {
279         unset($parameters['_with_csrf']);
280         $form = new sfForm();
281         $parameters[$form->getCSRFFieldName()] = $form->getCSRFToken();
282       }
283
284       $_POST = $parameters;
285     }
286     if (strtoupper($method) == 'GET')
287     {
288       $_GET = $parameters;
289     }
290
291     // handle input type="file" fields
292     $_FILES = array();
293     if (count($this->files))
294     {
295       $_FILES = $this->files;
296     }
297     $this->files = array();
298
299     parse_str($queryString, $qs);
300     if (is_array($qs))
301     {
302       $_GET = array_merge($qs, $_GET);
303     }
304
305     // expire cookies
306     $cookies = $this->cookieJar;
307     foreach ($cookies as $name => $cookie)
308     {
309       if ($cookie['expire'] && $cookie['expire'] < time())
310       {
311         unset($this->cookieJar[$name]);
312       }
313     }
314
315     // restore cookies
316     $_COOKIE = array();
317     foreach ($this->cookieJar as $name => $cookie)
318     {
319       $_COOKIE[$name] = $cookie['value'];
320     }
321
322     $this->doCall();
323
324     $response = $this->getResponse();
325
326     // save cookies
327     foreach ($response->getCookies() as $name => $cookie)
328     {
329       // FIXME: deal with path, secure, ...
330       $this->cookieJar[$name] = $cookie;
331     }
332
333     // support for the ETag header
334     if ($etag = $response->getHttpHeader('Etag'))
335     {
336       $this->vars['HTTP_IF_NONE_MATCH'] = $etag;
337     }
338     else
339     {
340       unset($this->vars['HTTP_IF_NONE_MATCH']);
341     }
342
343     // support for the last modified header
344     if ($lastModified = $response->getHttpHeader('Last-Modified'))
345     {
346       $this->vars['HTTP_IF_MODIFIED_SINCE'] = $lastModified;
347     }
348     else
349     {
350       unset($this->vars['HTTP_IF_MODIFIED_SINCE']);
351     }
352
353     // for HTML/XML content, create a DOM and sfDomCssSelector objects for the response content
354     $this->dom = null;
355     $this->domCssSelector = null;
356     if (preg_match('/(x|ht)ml/i', $response->getContentType(), $matches))
357     {
358       $this->dom = new DomDocument('1.0', $response->getCharset());
359       $this->dom->validateOnParse = true;
360       if ('x' == $matches[1])
361       {
362         @$this->dom->loadXML($response->getContent());
363       }
364       else
365       {
366         @$this->dom->loadHTML($response->getContent());
367       }
368       $this->domCssSelector = new sfDomCssSelector($this->dom);
369     }
370
371     return $this;
372   }
373
374   /**
375    * Calls a request to a uri.
376    */
377   abstract protected function doCall();
378
379   /**
380    * Go back in the browser history stack.
381    *
382    * @return sfBrowserBase
383    */
384   public function back()
385   {
386     if ($this->stackPosition < 1)
387     {
388       throw new LogicException('You are already on the first page.');
389     }
390
391     --$this->stackPosition;
392     return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false);
393   }
394
395   /**
396    * Go forward in the browser history stack.
397    *
398    * @return sfBrowserBase
399    */
400   public function forward()
401   {
402     if ($this->stackPosition > count($this->stack) - 2)
403     {
404       throw new LogicException('You are already on the last page.');
405     }
406
407     ++$this->stackPosition;
408     return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false);
409   }
410
411   /**
412    * Reload the current browser.
413    *
414    * @return sfBrowserBase
415    */
416   public function reload()
417   {
418     if (-1 == $this->stackPosition)
419     {
420       throw new LogicException('No page to reload.');
421     }
422
423     return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false);
424   }
425
426   /**
427    * Get response dom css selector.
428    *
429    * @return sfDomCssSelector
430    */
431   public function getResponseDomCssSelector()
432   {
433     if (is_null($this->dom))
434     {
435       throw new LogicException('The DOM is not accessible because the browser response content type is not HTML.');
436     }
437
438     return $this->domCssSelector;
439   }
440
441   /**
442    * Get response dom.
443    *
444    * @return sfDomCssSelector
445    */
446   public function getResponseDom()
447   {
448     if (is_null($this->dom))
449     {
450       throw new LogicException('The DOM is not accessible because the browser response content type is not HTML.');
451     }
452
453     return $this->dom;
454   }
455
456   /**
457    * Gets response.
458    *
459    * @return sfWebResponse
460    */
461   abstract public function getResponse();
462
463   /**
464    * Gets request.
465    *
466    * @return sfWebRequest
467    */
468   abstract public function getRequest();
469
470   /**
471    * Gets user.
472    *
473    * @return sfUser
474    */
475   abstract public function getUser();
476
477   /**
478    * Gets the current exception.
479    *
480    * @return Exception
481    */
482   public function getCurrentException()
483   {
484     return $this->currentException;
485   }
486
487   /**
488    * Sets the current exception.
489    *
490    * @param Exception $exception An Exception instance
491    */
492   public function setCurrentException(Exception $exception)
493   {
494     $this->currentException = $exception;
495   }
496
497   /**
498    * Resets the current exception.
499    */
500   public function resetCurrentException()
501   {
502     $this->currentException = null;
503   }
504
505   /**
506    * Test for an uncaught exception.
507    *
508    * @return  boolean
509    */
510   public function checkCurrentExceptionIsEmpty()
511   {
512     return is_null($this->getCurrentException()) || $this->getCurrentException() instanceof sfError404Exception;
513   }
514
515   /**
516    * Follow redirects?
517    *
518    * @throws sfException If request was not a redirect
519    *
520    * @return sfBrowserBase
521    */
522   public function followRedirect()
523   {
524     if (null === $this->getResponse()->getHttpHeader('Location'))
525     {
526       throw new LogicException('The request was not redirected.');
527     }
528
529     return $this->get($this->getResponse()->getHttpHeader('Location'));
530   }
531
532   /**
533    * Sets a form field in the browser.
534    *
535    * @param string $name   The field name
536    * @param string $value  The field value
537    *
538    * @return sfBrowserBase
539    */
540   public function setField($name, $value)
541   {
542     // as we don't know yet the form, just store name/value pairs
543     $this->parseArgumentAsArray($name, $value, $this->fields);
544
545     return $this;
546   }
547
548   /**
549    * Simulates deselecting a checkbox or radiobutton.
550    *
551    * @param string  $name       The checkbox or radiobutton id, name or text
552    *
553    * @return sfBrowserBase
554    *
555    * @see    doSelect()
556    */
557   public function deselect($name)
558   {
559     $this->doSelect($name, false);
560
561     return $this;
562   }
563
564   /**
565    * Simulates selecting a checkbox or radiobutton.
566    *
567    * @param string  $name       The checkbox or radiobutton id, name or text
568    *
569    * @return sfBrowserBase
570    *
571    * @see    doSelect()
572    */
573   public function select($name)
574   {
575     $this->doSelect($name, true);
576
577     return $this;
578   }
579
580   /**
581    * Simulates selecting a checkbox or radiobutton.
582    *
583    * This method is called internally by the select() and deselect() methods.
584    *
585    * @param string  $name       The checkbox or radiobutton id, name or text
586    * @param boolean $selected   If true the item will be selected
587    *
588    */
589   public function doSelect($name, $selected)
590   {
591     $position = 0;
592     $dom = $this->getResponseDom();
593
594     if (!$dom)
595     {
596       throw new LogicException('Cannot select because there is no current page in the browser.');
597     }
598
599     $xpath = new DomXpath($dom);
600
601     if ($element = $xpath->query(sprintf('//input[(@type="radio" or @type="checkbox") and (.="%s" or @id="%s" or @name="%s")]', $name, $name, $name))->item($position))
602     {
603       if ($selected)
604       {
605         if ($element->getAttribute('type') == 'radio')
606         {
607           //we need to deselect all other radio buttons with the same name
608           foreach ($xpath->query(sprintf('//input[@type="radio" and @name="%s"]', $element->getAttribute('name'))) as $radio)
609           {
610             $radio->removeAttribute('checked');
611           }
612         }
613         $element->setAttribute('checked', 'checked');
614       }
615       else
616       {
617         if ($element->getAttribute('type') == 'radio')
618         {
619           throw new InvalidArgumentException('Radiobutton cannot be deselected - Select another radiobutton to deselect the current.');
620         }
621         $element->removeAttribute('checked');
622       }
623     }
624     else
625     {
626       throw new InvalidArgumentException(sprintf('Cannot find the "%s" checkbox or radiobutton.', $name));
627     }
628   }
629
630   /**
631    * Simulates a click on a link or button.
632    *
633    * @param string  $name       The link or button text
634    * @param array   $arguments  The arguments to pass to the link
635    * @param array   $options    An array of options
636    *
637    * @return sfBrowserBase
638    *
639    * @see    doClick()
640    */
641   public function click($name, $arguments = array(), $options = array())
642   {
643     list($uri, $method, $parameters) = $this->doClick($name, $arguments, $options);
644
645     return $this->call($uri, $method, $parameters);
646   }
647
648   /**
649    * Simulates a click on a link or button.
650    *
651    * This method is called internally by the click() method.
652    *
653    * Available options:
654    *
655    *  * position: The position of the linked to link if several ones have the same name
656    *              (the first one is 1, not 0)
657    *  * method:   The method to used instead of the form ones
658    *              (useful when you need to click on a link that is converted to a form with JavaScript code)
659    *
660    * @param string  $name       The link or button text
661    * @param array   $arguments  The arguments to pass to the link
662    * @param array   $options    An array of options
663    *
664    * @return array An array composed of the URI, the method and the arguments to pass to the call() call
665    */
666   public function doClick($name, $arguments = array(), $options = array())
667   {
668     $position = isset($options['position']) ? $options['position'] - 1 : 0;
669
670     $dom = $this->getResponseDom();
671
672     if (!$dom)
673     {
674       throw new LogicException('Cannot click because there is no current page in the browser.');
675     }
676
677     $xpath = new DomXpath($dom);
678
679     $method = strtolower(isset($options['method']) ? $options['method'] : 'get');
680
681     $query  = sprintf('//a[.="%s"]', $name);
682     $query .= sprintf('|//a/img[@alt="%s"]/ancestor::a', $name);
683     $query .= sprintf('|//input[((@type="submit" or @type="button") and @value="%s") or (@type="image" and @alt="%s")]/ancestor::form', $name, $name);
684     $query .= sprintf('|//button[.="%s" or @id="%s" or @name="%s"]/ancestor::form', $name, $name, $name);
685     $list = $xpath->query($query);
686
687     if (!$item = $list->item($position))
688     {
689       throw new InvalidArgumentException(sprintf('Cannot find the "%s" link or button.', $name));
690     }
691
692     if ('a' == $item->nodeName)
693     {
694       if (in_array($method, array('post', 'put', 'delete')))
695       {
696         if (isset($options['_with_csrf']) && $options['_with_csrf'])
697         {
698           $arguments['_with_csrf'] = true;
699         }
700
701         return array($item->getAttribute('href'), $method, $arguments);
702       }
703       else
704       {
705         return array($item->getAttribute('href'), 'get', $arguments);
706       }
707     }
708
709     // form attributes
710     $url = $item->getAttribute('action');
711     if (!$url || '#' == $url)
712     {
713       $url = $this->stack[$this->stackPosition]['uri'];
714     }
715     $method = strtolower(isset($options['method']) ? $options['method'] : ($item->getAttribute('method') ? $item->getAttribute('method') : 'get'));
716
717     // merge form default values and arguments
718     $defaults = array();
719     $arguments = sfToolkit::arrayDeepMerge($this->fields, $arguments);
720
721     foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $item) as $element)
722     {
723       $elementName = $element->getAttribute('name');
724       $nodeName    = $element->nodeName;
725       $value       = null;
726
727       if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio'))
728       {
729         if ($element->getAttribute('checked'))
730         {
731           $value = $element->hasAttribute('value') ? $element->getAttribute('value') : '1';
732         }
733       }
734       else if ($nodeName == 'input' && $element->getAttribute('type') == 'file')
735       {
736         $filename = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');
737
738         if (is_readable($filename))
739         {
740           $fileError = UPLOAD_ERR_OK;
741           $fileSize = filesize($filename);
742         }
743         else
744         {
745           $fileError = UPLOAD_ERR_NO_FILE;
746           $fileSize = 0;
747         }
748
749         unset($arguments[$elementName]);
750
751         $this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => '', 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
752       }
753       else if (
754         $nodeName == 'input'
755         &&
756         (($element->getAttribute('type') != 'submit' && $element->getAttribute('type') != 'button') || $element->getAttribute('value') == $name)
757         &&
758         ($element->getAttribute('type') != 'image' || $element->getAttribute('alt') == $name)
759       )
760       {
761         $value = $element->getAttribute('value');
762       }
763       else if ($nodeName == 'textarea')
764       {
765         $value = '';
766         foreach ($element->childNodes as $el)
767         {
768           $value .= $dom->saveXML($el);
769         }
770       }
771       else if ($nodeName == 'select')
772       {
773         if ($multiple = $element->hasAttribute('multiple'))
774         {
775           $elementName = str_replace('[]', '', $elementName);
776           $value = array();
777         }
778         else
779         {
780           $value = null;
781         }
782
783         $found = false;
784         foreach ($xpath->query('descendant::option', $element) as $option)
785         {
786           if ($option->getAttribute('selected'))
787           {
788             $found = true;
789             if ($multiple)
790             {
791               $value[] = $option->getAttribute('value');
792             }
793             else
794             {
795               $value = $option->getAttribute('value');
796             }
797           }
798         }
799
800         // if no option is selected and if it is a simple select box, take the first option as the value
801         $option = $xpath->query('descendant::option', $element)->item(0);
802         if (!$found && !$multiple && $option instanceof DOMElement)
803         {
804           $value = $option->getAttribute('value');
805         }
806       }
807
808       if (null !== $value)
809       {
810         $this->parseArgumentAsArray($elementName, $value, $defaults);
811       }
812     }
813
814     // create request parameters
815     $arguments = sfToolkit::arrayDeepMerge($defaults, $arguments);
816     if (in_array($method, array('post', 'put', 'delete')))
817     {
818       return array($url, $method, $arguments);
819     }
820     else
821     {
822       $queryString = http_build_query($arguments, null, '&');
823       $sep = false === strpos($url, '?') ? '?' : '&';
824
825       return array($url.($queryString ? $sep.$queryString : ''), 'get', array());
826     }
827   }
828
829   /**
830    * Parses arguments as array
831    *
832    * @param string $name   The argument name
833    * @param string $value  The argument value
834    * @param array  $vars
835    */
836   protected function parseArgumentAsArray($name, $value, &$vars)
837   {
838     if (false !== $pos = strpos($name, '['))
839     {
840       $var = &$vars;
841       $tmps = array_filter(preg_split('/(\[ | \[\] | \])/x', $name), create_function('$s', 'return $s !== "";'));
842       foreach ($tmps as $tmp)
843       {
844         $var = &$var[$tmp];
845       }
846       if ($var)
847       {
848         if (!is_array($var))
849         {
850           $var = array($var);
851         }
852         $var[] = $value;
853       }
854       else
855       {
856         $var = $value;
857       }
858     }
859     else
860     {
861       $vars[$name] = $value;
862     }
863   }
864
865   /**
866    * Reset browser to original state
867    *
868    * @return sfBrowserBase
869    */
870   public function restart()
871   {
872     $this->newSession();
873     $this->cookieJar     = array();
874     $this->stack         = array();
875     $this->fields        = array();
876     $this->vars          = array();
877     $this->dom           = null;
878     $this->stackPosition = -1;
879
880     return $this;
881   }
882
883   /**
884    * Shutdown function to clean up and remove sessions
885    *
886    * @return void
887    */
888   public function shutdown()
889   {
890     $this->checkCurrentExceptionIsEmpty();
891   }
892
893   /**
894    * Fixes uri removing # declarations and front controller.
895    *
896    * @param  string $uri  The URI to fix
897    * @return string The fixed uri
898    */
899   public function fixUri($uri)
900   {
901     // remove absolute information if needed (to be able to do follow redirects, click on links, ...)
902     if (0 === strpos($uri, 'http'))
903     {
904       // detect secure request
905       if (0 === strpos($uri, 'https'))
906       {
907         $this->defaultServerArray['HTTPS'] = 'on';
908       }
909       else
910       {
911         unset($this->defaultServerArray['HTTPS']);
912       }
913
914       $uri = preg_replace('#^https?\://[^/]+/#', '/', $uri);
915     }
916     $uri = str_replace('/index.php', '', $uri);
917
918     // # as a uri
919     if ($uri && '#' == $uri[0])
920     {
921       $uri = $this->stack[$this->stackPosition]['uri'].$uri;
922     }
923
924     return $uri;
925   }
926
927   /**
928    * Creates a new session in the browser.
929    *
930    * @return void
931    */
932   protected function newSession()
933   {
934     $this->defaultServerArray['session_id'] = $_SERVER['session_id'] = md5(uniqid(rand(), true));
935   }
936 }
937
Note: See TracBrowser for help on using the browser.