Author: Kris.Wallsmith
Date: 2010-05-26 13:01:16 +0200 (Wed, 26 May 2010)
New Revision: 29627

Modified:
   plugins/sfWebBrowserPlugin/trunk/lib/sfWebBrowser.class.php
Log:
[sfWebBrowserPlugin] made fixHeaders() protected rather than private

Modified: plugins/sfWebBrowserPlugin/trunk/lib/sfWebBrowser.class.php
===================================================================
--- plugins/sfWebBrowserPlugin/trunk/lib/sfWebBrowser.class.php 2010-05-25 
22:15:43 UTC (rev 29626)
+++ plugins/sfWebBrowserPlugin/trunk/lib/sfWebBrowser.class.php 2010-05-26 
11:01:16 UTC (rev 29627)
@@ -1,851 +1,851 @@
-<?php
-
-/*
- * This file is part of the sfWebBrowserPlugin package.
- * (c) 2004-2006 Francois Zaninotto <[email protected]>
- * (c) 2004-2006 Fabien Potencier <[email protected]> for 
the click-related functions
- * 
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * sfWebBrowser provides a basic HTTP client.
- *
- * @package    sfWebBrowserPlugin
- * @author     Francois Zaninotto <[email protected]>
- * @author     Tristan Rivoallan <[email protected]>
- * @version    0.9
- */
-class sfWebBrowser
-{
-  protected
-    $defaultHeaders          = array(),
-    $stack                   = array(),
-    $stackPosition           = -1,
-    $responseHeaders         = array(),
-    $responseCode            = '',
-    $responseMessage         = '',
-    $responseText            = '',
-    $responseDom             = null,
-    $responseDomCssSelector  = null,
-    $responseXml             = null,
-    $fields                  = array(),
-    $urlInfo                 = array();
-
-  public function __construct($defaultHeaders = array(), $adapterClass = null, 
$adapterOptions = array())
-  {
-    if(!$adapterClass)
-    {
-      if (function_exists('curl_init'))
-      {
-        $adapterClass = 'sfCurlAdapter';
-      }
-      else if(ini_get('allow_url_fopen') == 1)
-      {
-        $adapterClass = 'sfFopenAdapter';
-      }
-      else
-      {
-        $adapterClass = 'sfSocketsAdapter';
-      }
-    }
-    $this->defaultHeaders = $this->fixHeaders($defaultHeaders);
-    $this->adapter = new $adapterClass($adapterOptions);
-  }
-    
-  // Browser methods
-  
-  /**
-   * Restarts the browser
-   *
-   * @param array default browser options
-   *
-   * @return sfWebBrowser The current browser object
-   */    
-  public function restart($defaultHeaders = array())
-  {
-    $this->defaultHeaders = $this->fixHeaders($defaultHeaders);
-    $this->stack          = array();
-    $this->stackPosition  = -1;
-    $this->urlInfo        = array();
-    $this->initializeResponse();
-    
-    return $this;
-  }
-
-  /**
-   * Sets the browser user agent name
-   *
-   * @param string agent name
-   *
-   * @return sfWebBrowser The current browser object
-   */    
-  public function setUserAgent($agent)
-  {
-    $this->defaultHeaders['User-Agent'] = $agent;
-    
-    return $this;
-  }
-
-  /**
-   * Gets the browser user agent name
-   *
-   * @return string agent name
-   */    
-  public function getUserAgent()
-  {
-    return isset($this->defaultHeaders['User-Agent']) ? 
$this->defaultHeaders['User-Agent'] : '';
-  }
-
-  /**
-   * Submits a GET request
-   *
-   * @param string The request uri
-   * @param array  The request parameters (associative array)
-   * @param array  The request headers (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */
-  public function get($uri, $parameters = array(), $headers = array())
-  {
-    if ($parameters)
-    {
-      $uri .= ((false !== strpos($uri, '?')) ? '&' : '?') . 
http_build_query($parameters, '', '&');
-    }
-    return $this->call($uri, 'GET', array(), $headers);
-  }
-
-  public function head($uri, $parameters = array(), $headers = array())
-  {
-    if ($parameters)
-    {
-      $uri .= ((false !== strpos($uri, '?')) ? '&' : '?') . 
http_build_query($parameters, '', '&');
-    }
-    return $this->call($uri, 'HEAD', array(), $headers);
-  }
-
-  /**
-   * Submits a POST request
-   *
-   * @param string The request uri
-   * @param array  The request parameters (associative array)
-   * @param array  The request headers (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function post($uri, $parameters = array(), $headers = array())
-  {
-    return $this->call($uri, 'POST', $parameters, $headers);
-  }
-  
-  /**
-   * Submits a PUT request.
-   *
-   * @param string The request uri
-   * @param array  The request parameters (associative array)
-   * @param array  The request headers (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function put($uri, $parameters = array(), $headers = array())
-  {
-    return $this->call($uri, 'PUT', $parameters, $headers);
-  }
-
-  /**
-   * Submits a DELETE request.
-   *
-   * @param string The request uri
-   * @param array  The request parameters (associative array)
-   * @param array  The request headers (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function delete($uri, $parameters = array(), $headers = array())
-  {
-    return $this->call($uri, 'DELETE', $parameters, $headers);
-  }
-
-  /**
-   * Submits a request
-   *
-   * @param string  The request uri
-   * @param string  The request method
-   * @param array   The request parameters (associative array)
-   * @param array   The request headers (associative array)
-   * @param boolean To specify is the request changes the browser history
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function call($uri, $method = 'GET', $parameters = array(), $headers 
= array(), $changeStack = true)
-  {
-    $urlInfo = parse_url($uri);
-
-    // Check headers
-    $headers = $this->fixHeaders($headers);
-
-    // check port
-    if (isset($urlInfo['port']))
-    {
-      $this->urlInfo['port'] = $urlInfo['port'];
-    }
-    else if (!isset($this->urlInfo['port']))
-    {
-      $this->urlInfo['port'] = 80;
-    }
-
-    if(!isset($urlInfo['host']))
-    {
-      // relative link
-      $uri = 
$this->urlInfo['scheme'].'://'.$this->urlInfo['host'].':'.$this->urlInfo['port'].'/'.$uri;
-    }
-    else if($urlInfo['scheme'] != 'http' && $urlInfo['scheme'] != 'https')
-    {
-      throw new Exception('sfWebBrowser handles only http and https 
requests'); 
-    }
-
-    $this->urlInfo = parse_url($uri);
-
-    $this->initializeResponse();
-
-    if ($changeStack)
-    {
-      $this->addToStack($uri, $method, $parameters, $headers);
-    }
-
-    $browser = $this->adapter->call($this, $uri, $method, $parameters, 
$headers);
-
-    // redirect support
-    if ((in_array($browser->getResponseCode(), array(301, 307)) && 
in_array($method, array('GET', 'HEAD'))) || 
in_array($browser->getResponseCode(), array(302,303)))
-    {
-      $this->call($browser->getResponseHeader('Location'), 'GET', array(), 
$headers);
-    }
-
-    return $browser;
-  }
-
-  /**
-   * Gives a value to a form field in the response
-   *
-   * @param string field name
-   * @param string field value
-   *
-   * @return sfWebBrowser The current browser object
-   */ 
-  public function setField($name, $value)
-  {
-    // as we don't know yet the form, just store name/value pairs
-    $this->parseArgumentAsArray($name, $value, $this->fields);
-
-    return $this;
-  }
-  
-  /**
-   * Looks for a link or a button in the response and submits the related 
request
-   *
-   * @param string The link/button value/href/alt
-   * @param array request parameters (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */ 
-  public function click($name, $arguments = array())
-  {
-    if (!$dom = $this->getResponseDom())
-    {
-      throw new Exception('Cannot click because there is no current page in 
the browser');
-    }
-
-    $xpath = new DomXpath($dom);
-
-    // text link, the name being in an attribute
-    if ($link = $xpath->query(sprintf('//a...@*="%s"]', $name))->item(0))
-    {
-      return $this->get($link->getAttribute('href'));
-    }
-
-    // text link, the name being the text value
-    if ($links = $xpath->query('//a...@href]'))
-    {
-      foreach($links as $link)
-      {
-        if(preg_replace(array('/\s{2,}/', '/\\r\\n|\\n|\\r/'), array(' ', ''), 
$link->nodeValue) == $name)
-        {
-          return $this->get($link->getAttribute('href'));  
-        }
-      }
-    }
-    
-    // image link, the name being the alt attribute value
-    if ($link = $xpath->query(sprintf('//a/i...@alt="%s"]/ancestor::a', 
$name))->item(0))
-    {
-      return $this->get($link->getAttribute('href'));
-    }
-
-    // form, the name being the button or input value
-    if (!$form = $xpath->query(sprintf('//input[((@type="submit" or 
@type="button") and @value="%s") or (@type="image" and 
@alt="%s")]/ancestor::form', $name, $name))->item(0))
-    {
-      throw new Exception(sprintf('Cannot find the "%s" link or button.', 
$name));
-    }
-
-    // form attributes
-    $url = $form->getAttribute('action');
-    $method = $form->getAttribute('method') ? 
strtolower($form->getAttribute('method')) : 'get';
-
-    // merge form default values and arguments
-    $defaults = array();
-    foreach ($xpath->query('descendant::input | descendant::textarea | 
descendant::select', $form) as $element)
-    {
-      $elementName = $element->getAttribute('name');
-      $nodeName    = $element->nodeName;
-      $value       = null;
-      if ($nodeName == 'input' && ($element->getAttribute('type') == 
'checkbox' || $element->getAttribute('type') == 'radio'))
-      {
-        if ($element->getAttribute('checked'))
-        {
-          $value = $element->getAttribute('value');
-        }
-      }
-      else if (
-        $nodeName == 'input'
-        &&
-        (($element->getAttribute('type') != 'submit' && 
$element->getAttribute('type') != 'button') || $element->getAttribute('value') 
== $name)
-        &&
-        ($element->getAttribute('type') != 'image' || 
$element->getAttribute('alt') == $name)
-      )
-      {
-        $value = $element->getAttribute('value');
-      }
-      else if ($nodeName == 'textarea')
-      {
-        $value = '';
-        foreach ($element->childNodes as $el)
-        {
-          $value .= $dom->saveXML($el);
-        }
-      }
-      else if ($nodeName == 'select')
-      {
-        if ($multiple = $element->hasAttribute('multiple'))
-        {
-          $elementName = str_replace('[]', '', $elementName);
-          $value = array();
-        }
-        else
-        {
-          $value = null;
-        }
-
-        $found = false;
-        foreach ($xpath->query('descendant::option', $element) as $option)
-        {
-          if ($option->getAttribute('selected'))
-          {
-            $found = true;
-            if ($multiple)
-            {
-              $value[] = $option->getAttribute('value');
-            }
-            else
-            {
-              $value = $option->getAttribute('value');
-            }
-          }
-        }
-
-        // if no option is selected and if it is a simple select box, take the 
first option as the value
-        if (!$found && !$multiple)
-        {
-          $value = $xpath->query('descendant::option', 
$element)->item(0)->getAttribute('value');
-        }
-      }
-
-      if (null !== $value)
-      {
-        $this->parseArgumentAsArray($elementName, $value, $defaults);
-      }
-    }
-
-    // create request parameters
-    $arguments = sfToolkit::arrayDeepMerge($defaults, $this->fields, 
$arguments);
-    if ('post' == $method)
-    {
-      return $this->post($url, $arguments);
-    }
-    else
-    {
-      return $this->get($url, $arguments);
-    }
-  }
-
-  protected function parseArgumentAsArray($name, $value, &$vars)
-  {
-    if (false !== $pos = strpos($name, '['))
-    {
-      $var = &$vars;
-      $tmps = array_filter(preg_split('/(\[ | \[\] | \])/x', $name));
-      foreach ($tmps as $tmp)
-      {
-        $var = &$var[$tmp];
-      }
-      if ($var)
-      {
-        if (!is_array($var))
-        {
-          $var = array($var);
-        }
-        $var[] = $value;
-      }
-      else
-      {
-        $var = $value;
-      }
-    }
-    else
-    {
-      $vars[$name] = $value;
-    }
-  }
-
-  /**
-   * Adds the current request to the history stack
-   *
-   * @param string  The request uri
-   * @param string  The request method
-   * @param array   The request parameters (associative array)
-   * @param array   The request headers (associative array)
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function addToStack($uri, $method, $parameters, $headers)
-  {
-    $this->stack = array_slice($this->stack, 0, $this->stackPosition + 1);
-    $this->stack[] = array(
-      'uri'        => $uri,
-      'method'     => $method,
-      'parameters' => $parameters,
-      'headers'    => $headers
-    );
-    $this->stackPosition = count($this->stack) - 1;
-    
-    return $this;
-  }
-
-  /**
-   * Submits the previous request in history again
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function back()
-  {
-    if ($this->stackPosition < 1)
-    {
-      throw new Exception('You are already on the first page.');
-    }
-
-    --$this->stackPosition;
-    return $this->call($this->stack[$this->stackPosition]['uri'], 
-                       $this->stack[$this->stackPosition]['method'], 
-                       $this->stack[$this->stackPosition]['parameters'], 
-                       $this->stack[$this->stackPosition]['headers'],
-                       false);
-  }
-
-  /**
-   * Submits the next request in history again
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function forward()
-  {
-    if ($this->stackPosition > count($this->stack) - 2)
-    {
-      throw new Exception('You are already on the last page.');
-    }
-
-    ++$this->stackPosition;
-    return $this->call($this->stack[$this->stackPosition]['uri'], 
-                       $this->stack[$this->stackPosition]['method'], 
-                       $this->stack[$this->stackPosition]['parameters'], 
-                       $this->stack[$this->stackPosition]['headers'],
-                       false);
-  }
-
-  /**
-   * Submits the current request again
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function reload()
-  {
-    if (-1 == $this->stackPosition)
-    {
-      throw new Exception('No page to reload.');
-    }
-
-    return $this->call($this->stack[$this->stackPosition]['uri'], 
-                       $this->stack[$this->stackPosition]['method'], 
-                       $this->stack[$this->stackPosition]['parameters'], 
-                       $this->stack[$this->stackPosition]['headers'],
-                       false);
-  }
-  
-  /**
-   * Transforms an associative array of header names => header values to its 
HTTP equivalent.
-   * 
-   * @param    array     $headers
-   * @return   string
-   */
-  public function prepareHeaders($headers = array())
-  {
-    $prepared_headers = array();
-    foreach ($headers as $name => $value)
-    {
-      $prepared_headers[] = sprintf("%s: %s\r\n", ucfirst($name), $value);
-    }
-    
-    return implode('', $prepared_headers);
-  }
-  
-  // Response methods
-
-  /**
-   * Initializes the response and erases all content from prior requests
-   */  
-  public function initializeResponse()
-  {
-    $this->responseHeaders        = array();
-    $this->responseCode           = '';
-    $this->responseText           = '';
-    $this->responseDom            = null;
-    $this->responseDomCssSelector = null;
-    $this->responseXml            = null;
-    $this->fields                 = array();
-  }
-
-  /**
-   * Set the response headers
-   *
-   * @param array The response headers as an array of strings shaped like 
"key: value"
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function setResponseHeaders($headers = array())
-  {
-    $header_array = array();
-    foreach($headers as $header)
-    {
-      $arr = explode(': ', $header); 
-      if(isset($arr[1]))
-      {
-        $header_array[$this->normalizeHeaderName($arr[0])] = trim($arr[1]);
-      }
-    }
-    
-    $this->responseHeaders = $header_array;
-    
-    return $this;
-  }
-  
-  /**
-   * Set the response code
-   *
-   * @param string The first line of the response
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function setResponseCode($firstLine)
-  {
-    preg_match('/\d{3}/', $firstLine, $matches);
-    if(isset($matches[0]))
-    {
-      $this->responseCode = $matches[0];
-    }
-    else
-    {
-      $this->responseCode = '';
-    }
-    
-    return $this;
-  }  
-
-  /**
-   * Set the response contents
-   *
-   * @param string The response contents
-   *
-   * @return sfWebBrowser The current browser object
-   */  
-  public function setResponseText($res)
-  {
-    $this->responseText = $res;
-    
-    return $this;
-  }
-
-  /**
-   * Get a text version of the response
-   *
-   * @return string The response contents
-   */
-  public function getResponseText()
-  {
-    $text = $this->responseText;
-
-    // Decode any content-encoding (gzip or deflate) if needed
-    switch (strtolower($this->getResponseHeader('content-encoding'))) {
-
-        // Handle gzip encoding
-        case 'gzip':
-            $text = $this->decodeGzip($text);
-            break;
-
-        // Handle deflate encoding
-        case 'deflate':
-            $text = $this->decodeDeflate($text);
-            break;
-
-        default:
-            break;
-    }
-
-    return $text;
-  }
-
-  /**
-   * Get a text version of the body part of the response (without <body> and 
</body>)
-   *
-   * @return string The body part of the response contents
-   */
-  public function getResponseBody()
-  {
-    preg_match('/<body.*?>(.*)<\/body>/si', $this->getResponseText(), 
$matches);
-
-    return isset($matches[1]) ? $matches[1] : '';
-  }
-  
-  /**
-   * Get a DOMDocument version of the response 
-   *
-   * @return DOMDocument The reponse contents
-   */
-  public function getResponseDom()
-  {
-    if(!$this->responseDom)
-    {
-      // for HTML/XML content, create a DOM object for the response content
-      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
-      {
-        $this->responseDom = new DomDocument('1.0', 'utf8');
-        $this->responseDom->validateOnParse = true;
-        @$this->responseDom->loadHTML($this->getResponseText());
-      }
-    }
-
-    return $this->responseDom;
-  }
-
-  /**
-   * Get a sfDomCssSelector version of the response 
-   *
-   * @return sfDomCssSelector The response contents
-   */
-  public function getResponseDomCssSelector()
-  {
-    if(!$this->responseDomCssSelector)
-    {
-      // for HTML/XML content, create a DOM object for the response content
-      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
-      {
-        $this->responseDomCssSelector = new 
sfDomCssSelector($this->getResponseDom());
-      }
-    }
-
-    return $this->responseDomCssSelector;
-  }
-
-  /**
-   * Get a SimpleXML version of the response 
-   *
-   * @return  SimpleXMLElement                      The reponse contents
-   * @throws  sfWebBrowserInvalidResponseException  when response is not in a 
valid format 
-   */
-  public function getResponseXML()
-  {
-    if(!$this->responseXml)
-    {
-      // for HTML/XML content, create a DOM object for the response content
-      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
-      {
-        $this->responseXml = @simplexml_load_string($this->getResponseText());
-      }
-    }
-    
-    // Throw an exception if response is not valid XML
-    if (get_class($this->responseXml) != 'SimpleXMLElement')
-    {
-      $msg = sprintf("Response is not a valid XML string : \n%s", 
$this->getResponseText());
-      throw new sfWebBrowserInvalidResponseException($msg);
-    }
-    
-    return $this->responseXml;
-  }
-
-  /**
-   * Returns true if server response is an error.
-   * 
-   * @return   bool
-   */
-  public function responseIsError()
-  {
-    return in_array((int)($this->getResponseCode() / 100), array(4, 5)); 
-  }
-
-  /**
-   * Get the response headers
-   *
-   * @return array The response headers
-   */
-  public function getResponseHeaders()
-  {
-    return $this->responseHeaders;
-  }  
-
-  /**
-   * Get a response header
-   *
-   * @param string The response header name
-   *
-   * @return string The response header value
-   */
-  public function getResponseHeader($key)
-  {
-    $normalized_key = $this->normalizeHeaderName($key);
-    return (isset($this->responseHeaders[$normalized_key])) ? 
$this->responseHeaders[$normalized_key] : '';
-  }  
-  
-  /**
-   * Decodes gzip-encoded content ("content-encoding: gzip" response header).
-   * 
-   * @param       stream     $gzip_text
-   * @return      string     
-   */
-  protected function decodeGzip($gzip_text)
-  {
-    return gzinflate(substr($gzip_text, 10));
-  }
-
-  /**
-   * Decodes deflate-encoded content ("content-encoding: deflate" response 
header).
-   * 
-   * @param       stream     $deflate_text
-   * @return      string     
-   */  
-  protected function decodeDeflate($deflate_text)
-  {
-    return gzuncompress($deflate_text);
-  }
-  
-  /**
-   * Get the response code
-   *
-   * @return string The response code
-   */
-  public function getResponseCode()
-  {
-    return $this->responseCode; 
-  }
-  
-  /**
-   * Returns the response message (the 'Not Found' part in  'HTTP/1.1 404 Not 
Found')
-   * 
-   * @return   string 
-   */
-  public function getResponseMessage()
-  {
-    return $this->responseMessage;    
-  }
-  
-  /**
-   * Sets response message.
-   * 
-   * @param    string    $message
-   */
-  public function setResponseMessage($msg)
-  {
-    $this->responseMessage = $msg;
-  }
-  
-  public function getUrlInfo()
-  {
-    return $this->urlInfo; 
-  }
-  
-  public function getDefaultRequestHeaders()
-  {
-    return $this->defaultHeaders;
-  }
-  
-  /**
-   * Adds default headers to the supplied headers array.
-   * 
-   * @param       array    $headers
-   * @return      array
-   */
-  public function initializeRequestHeaders($headers = array())
-  {
-    // Supported encodings
-    $encodings = array();
-    if (isset($headers['Accept-Encoding']))
-    {
-      $encodings = explode(',', $headers['Accept-Encoding']);
-    }
-    if (function_exists('gzinflate') && !in_array('gzip', $encodings))
-    {
-      $encodings[] = 'gzip';
-    }
-    if (function_exists('gzuncompress') && !in_array('deflate', $encodings))
-    {
-      $encodings[] = 'deflate';
-    }
-    
-    $headers['Accept-Encoding'] = implode(',', array_unique($encodings));
-    
-    return $headers;
-  }
-  
-  /**
-   * Validates supplied headers and turns all names to lowercase.
-   * 
-   * @param     array     $headers
-   * @return    array
-   */
-  private function fixHeaders($headers)
-  {
-    $fixed_headers = array();
-    foreach ($headers as $name => $value)
-    {
-      if (!preg_match('/([a-z]*)(-[a-z]*)*/i', $name))
-      {
-        $msg = sprintf('Invalid header "%s"', $name);
-        throw new Exception($msg);
-      }
-      $fixed_headers[$this->normalizeHeaderName($name)] = trim($value);
-    }
-
-    return $fixed_headers;
-  }
-  
-  /**
-   * Retrieves a normalized Header.
-   *
-   * @param string Header name
-   *
-   * @return string Normalized header
-   */
-  protected function normalizeHeaderName($name)
-  {
-    return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", 
strtr(ucfirst($name), '_', '-'));
-  }
-
-}
+<?php
+
+/*
+ * This file is part of the sfWebBrowserPlugin package.
+ * (c) 2004-2006 Francois Zaninotto <[email protected]>
+ * (c) 2004-2006 Fabien Potencier <[email protected]> for 
the click-related functions
+ * 
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfWebBrowser provides a basic HTTP client.
+ *
+ * @package    sfWebBrowserPlugin
+ * @author     Francois Zaninotto <[email protected]>
+ * @author     Tristan Rivoallan <[email protected]>
+ * @version    0.9
+ */
+class sfWebBrowser
+{
+  protected
+    $defaultHeaders          = array(),
+    $stack                   = array(),
+    $stackPosition           = -1,
+    $responseHeaders         = array(),
+    $responseCode            = '',
+    $responseMessage         = '',
+    $responseText            = '',
+    $responseDom             = null,
+    $responseDomCssSelector  = null,
+    $responseXml             = null,
+    $fields                  = array(),
+    $urlInfo                 = array();
+
+  public function __construct($defaultHeaders = array(), $adapterClass = null, 
$adapterOptions = array())
+  {
+    if(!$adapterClass)
+    {
+      if (function_exists('curl_init'))
+      {
+        $adapterClass = 'sfCurlAdapter';
+      }
+      else if(ini_get('allow_url_fopen') == 1)
+      {
+        $adapterClass = 'sfFopenAdapter';
+      }
+      else
+      {
+        $adapterClass = 'sfSocketsAdapter';
+      }
+    }
+    $this->defaultHeaders = $this->fixHeaders($defaultHeaders);
+    $this->adapter = new $adapterClass($adapterOptions);
+  }
+    
+  // Browser methods
+  
+  /**
+   * Restarts the browser
+   *
+   * @param array default browser options
+   *
+   * @return sfWebBrowser The current browser object
+   */    
+  public function restart($defaultHeaders = array())
+  {
+    $this->defaultHeaders = $this->fixHeaders($defaultHeaders);
+    $this->stack          = array();
+    $this->stackPosition  = -1;
+    $this->urlInfo        = array();
+    $this->initializeResponse();
+    
+    return $this;
+  }
+
+  /**
+   * Sets the browser user agent name
+   *
+   * @param string agent name
+   *
+   * @return sfWebBrowser The current browser object
+   */    
+  public function setUserAgent($agent)
+  {
+    $this->defaultHeaders['User-Agent'] = $agent;
+    
+    return $this;
+  }
+
+  /**
+   * Gets the browser user agent name
+   *
+   * @return string agent name
+   */    
+  public function getUserAgent()
+  {
+    return isset($this->defaultHeaders['User-Agent']) ? 
$this->defaultHeaders['User-Agent'] : '';
+  }
+
+  /**
+   * Submits a GET request
+   *
+   * @param string The request uri
+   * @param array  The request parameters (associative array)
+   * @param array  The request headers (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */
+  public function get($uri, $parameters = array(), $headers = array())
+  {
+    if ($parameters)
+    {
+      $uri .= ((false !== strpos($uri, '?')) ? '&' : '?') . 
http_build_query($parameters, '', '&');
+    }
+    return $this->call($uri, 'GET', array(), $headers);
+  }
+
+  public function head($uri, $parameters = array(), $headers = array())
+  {
+    if ($parameters)
+    {
+      $uri .= ((false !== strpos($uri, '?')) ? '&' : '?') . 
http_build_query($parameters, '', '&');
+    }
+    return $this->call($uri, 'HEAD', array(), $headers);
+  }
+
+  /**
+   * Submits a POST request
+   *
+   * @param string The request uri
+   * @param array  The request parameters (associative array)
+   * @param array  The request headers (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function post($uri, $parameters = array(), $headers = array())
+  {
+    return $this->call($uri, 'POST', $parameters, $headers);
+  }
+  
+  /**
+   * Submits a PUT request.
+   *
+   * @param string The request uri
+   * @param array  The request parameters (associative array)
+   * @param array  The request headers (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function put($uri, $parameters = array(), $headers = array())
+  {
+    return $this->call($uri, 'PUT', $parameters, $headers);
+  }
+
+  /**
+   * Submits a DELETE request.
+   *
+   * @param string The request uri
+   * @param array  The request parameters (associative array)
+   * @param array  The request headers (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function delete($uri, $parameters = array(), $headers = array())
+  {
+    return $this->call($uri, 'DELETE', $parameters, $headers);
+  }
+
+  /**
+   * Submits a request
+   *
+   * @param string  The request uri
+   * @param string  The request method
+   * @param array   The request parameters (associative array)
+   * @param array   The request headers (associative array)
+   * @param boolean To specify is the request changes the browser history
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function call($uri, $method = 'GET', $parameters = array(), $headers 
= array(), $changeStack = true)
+  {
+    $urlInfo = parse_url($uri);
+
+    // Check headers
+    $headers = $this->fixHeaders($headers);
+
+    // check port
+    if (isset($urlInfo['port']))
+    {
+      $this->urlInfo['port'] = $urlInfo['port'];
+    }
+    else if (!isset($this->urlInfo['port']))
+    {
+      $this->urlInfo['port'] = 80;
+    }
+
+    if(!isset($urlInfo['host']))
+    {
+      // relative link
+      $uri = 
$this->urlInfo['scheme'].'://'.$this->urlInfo['host'].':'.$this->urlInfo['port'].'/'.$uri;
+    }
+    else if($urlInfo['scheme'] != 'http' && $urlInfo['scheme'] != 'https')
+    {
+      throw new Exception('sfWebBrowser handles only http and https 
requests'); 
+    }
+
+    $this->urlInfo = parse_url($uri);
+
+    $this->initializeResponse();
+
+    if ($changeStack)
+    {
+      $this->addToStack($uri, $method, $parameters, $headers);
+    }
+
+    $browser = $this->adapter->call($this, $uri, $method, $parameters, 
$headers);
+
+    // redirect support
+    if ((in_array($browser->getResponseCode(), array(301, 307)) && 
in_array($method, array('GET', 'HEAD'))) || 
in_array($browser->getResponseCode(), array(302,303)))
+    {
+      $this->call($browser->getResponseHeader('Location'), 'GET', array(), 
$headers);
+    }
+
+    return $browser;
+  }
+
+  /**
+   * Gives a value to a form field in the response
+   *
+   * @param string field name
+   * @param string field value
+   *
+   * @return sfWebBrowser The current browser object
+   */ 
+  public function setField($name, $value)
+  {
+    // as we don't know yet the form, just store name/value pairs
+    $this->parseArgumentAsArray($name, $value, $this->fields);
+
+    return $this;
+  }
+  
+  /**
+   * Looks for a link or a button in the response and submits the related 
request
+   *
+   * @param string The link/button value/href/alt
+   * @param array request parameters (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */ 
+  public function click($name, $arguments = array())
+  {
+    if (!$dom = $this->getResponseDom())
+    {
+      throw new Exception('Cannot click because there is no current page in 
the browser');
+    }
+
+    $xpath = new DomXpath($dom);
+
+    // text link, the name being in an attribute
+    if ($link = $xpath->query(sprintf('//a...@*="%s"]', $name))->item(0))
+    {
+      return $this->get($link->getAttribute('href'));
+    }
+
+    // text link, the name being the text value
+    if ($links = $xpath->query('//a...@href]'))
+    {
+      foreach($links as $link)
+      {
+        if(preg_replace(array('/\s{2,}/', '/\\r\\n|\\n|\\r/'), array(' ', ''), 
$link->nodeValue) == $name)
+        {
+          return $this->get($link->getAttribute('href'));  
+        }
+      }
+    }
+    
+    // image link, the name being the alt attribute value
+    if ($link = $xpath->query(sprintf('//a/i...@alt="%s"]/ancestor::a', 
$name))->item(0))
+    {
+      return $this->get($link->getAttribute('href'));
+    }
+
+    // form, the name being the button or input value
+    if (!$form = $xpath->query(sprintf('//input[((@type="submit" or 
@type="button") and @value="%s") or (@type="image" and 
@alt="%s")]/ancestor::form', $name, $name))->item(0))
+    {
+      throw new Exception(sprintf('Cannot find the "%s" link or button.', 
$name));
+    }
+
+    // form attributes
+    $url = $form->getAttribute('action');
+    $method = $form->getAttribute('method') ? 
strtolower($form->getAttribute('method')) : 'get';
+
+    // merge form default values and arguments
+    $defaults = array();
+    foreach ($xpath->query('descendant::input | descendant::textarea | 
descendant::select', $form) as $element)
+    {
+      $elementName = $element->getAttribute('name');
+      $nodeName    = $element->nodeName;
+      $value       = null;
+      if ($nodeName == 'input' && ($element->getAttribute('type') == 
'checkbox' || $element->getAttribute('type') == 'radio'))
+      {
+        if ($element->getAttribute('checked'))
+        {
+          $value = $element->getAttribute('value');
+        }
+      }
+      else if (
+        $nodeName == 'input'
+        &&
+        (($element->getAttribute('type') != 'submit' && 
$element->getAttribute('type') != 'button') || $element->getAttribute('value') 
== $name)
+        &&
+        ($element->getAttribute('type') != 'image' || 
$element->getAttribute('alt') == $name)
+      )
+      {
+        $value = $element->getAttribute('value');
+      }
+      else if ($nodeName == 'textarea')
+      {
+        $value = '';
+        foreach ($element->childNodes as $el)
+        {
+          $value .= $dom->saveXML($el);
+        }
+      }
+      else if ($nodeName == 'select')
+      {
+        if ($multiple = $element->hasAttribute('multiple'))
+        {
+          $elementName = str_replace('[]', '', $elementName);
+          $value = array();
+        }
+        else
+        {
+          $value = null;
+        }
+
+        $found = false;
+        foreach ($xpath->query('descendant::option', $element) as $option)
+        {
+          if ($option->getAttribute('selected'))
+          {
+            $found = true;
+            if ($multiple)
+            {
+              $value[] = $option->getAttribute('value');
+            }
+            else
+            {
+              $value = $option->getAttribute('value');
+            }
+          }
+        }
+
+        // if no option is selected and if it is a simple select box, take the 
first option as the value
+        if (!$found && !$multiple)
+        {
+          $value = $xpath->query('descendant::option', 
$element)->item(0)->getAttribute('value');
+        }
+      }
+
+      if (null !== $value)
+      {
+        $this->parseArgumentAsArray($elementName, $value, $defaults);
+      }
+    }
+
+    // create request parameters
+    $arguments = sfToolkit::arrayDeepMerge($defaults, $this->fields, 
$arguments);
+    if ('post' == $method)
+    {
+      return $this->post($url, $arguments);
+    }
+    else
+    {
+      return $this->get($url, $arguments);
+    }
+  }
+
+  protected function parseArgumentAsArray($name, $value, &$vars)
+  {
+    if (false !== $pos = strpos($name, '['))
+    {
+      $var = &$vars;
+      $tmps = array_filter(preg_split('/(\[ | \[\] | \])/x', $name));
+      foreach ($tmps as $tmp)
+      {
+        $var = &$var[$tmp];
+      }
+      if ($var)
+      {
+        if (!is_array($var))
+        {
+          $var = array($var);
+        }
+        $var[] = $value;
+      }
+      else
+      {
+        $var = $value;
+      }
+    }
+    else
+    {
+      $vars[$name] = $value;
+    }
+  }
+
+  /**
+   * Adds the current request to the history stack
+   *
+   * @param string  The request uri
+   * @param string  The request method
+   * @param array   The request parameters (associative array)
+   * @param array   The request headers (associative array)
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function addToStack($uri, $method, $parameters, $headers)
+  {
+    $this->stack = array_slice($this->stack, 0, $this->stackPosition + 1);
+    $this->stack[] = array(
+      'uri'        => $uri,
+      'method'     => $method,
+      'parameters' => $parameters,
+      'headers'    => $headers
+    );
+    $this->stackPosition = count($this->stack) - 1;
+    
+    return $this;
+  }
+
+  /**
+   * Submits the previous request in history again
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function back()
+  {
+    if ($this->stackPosition < 1)
+    {
+      throw new Exception('You are already on the first page.');
+    }
+
+    --$this->stackPosition;
+    return $this->call($this->stack[$this->stackPosition]['uri'], 
+                       $this->stack[$this->stackPosition]['method'], 
+                       $this->stack[$this->stackPosition]['parameters'], 
+                       $this->stack[$this->stackPosition]['headers'],
+                       false);
+  }
+
+  /**
+   * Submits the next request in history again
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function forward()
+  {
+    if ($this->stackPosition > count($this->stack) - 2)
+    {
+      throw new Exception('You are already on the last page.');
+    }
+
+    ++$this->stackPosition;
+    return $this->call($this->stack[$this->stackPosition]['uri'], 
+                       $this->stack[$this->stackPosition]['method'], 
+                       $this->stack[$this->stackPosition]['parameters'], 
+                       $this->stack[$this->stackPosition]['headers'],
+                       false);
+  }
+
+  /**
+   * Submits the current request again
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function reload()
+  {
+    if (-1 == $this->stackPosition)
+    {
+      throw new Exception('No page to reload.');
+    }
+
+    return $this->call($this->stack[$this->stackPosition]['uri'], 
+                       $this->stack[$this->stackPosition]['method'], 
+                       $this->stack[$this->stackPosition]['parameters'], 
+                       $this->stack[$this->stackPosition]['headers'],
+                       false);
+  }
+  
+  /**
+   * Transforms an associative array of header names => header values to its 
HTTP equivalent.
+   * 
+   * @param    array     $headers
+   * @return   string
+   */
+  public function prepareHeaders($headers = array())
+  {
+    $prepared_headers = array();
+    foreach ($headers as $name => $value)
+    {
+      $prepared_headers[] = sprintf("%s: %s\r\n", ucfirst($name), $value);
+    }
+    
+    return implode('', $prepared_headers);
+  }
+  
+  // Response methods
+
+  /**
+   * Initializes the response and erases all content from prior requests
+   */  
+  public function initializeResponse()
+  {
+    $this->responseHeaders        = array();
+    $this->responseCode           = '';
+    $this->responseText           = '';
+    $this->responseDom            = null;
+    $this->responseDomCssSelector = null;
+    $this->responseXml            = null;
+    $this->fields                 = array();
+  }
+
+  /**
+   * Set the response headers
+   *
+   * @param array The response headers as an array of strings shaped like 
"key: value"
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function setResponseHeaders($headers = array())
+  {
+    $header_array = array();
+    foreach($headers as $header)
+    {
+      $arr = explode(': ', $header); 
+      if(isset($arr[1]))
+      {
+        $header_array[$this->normalizeHeaderName($arr[0])] = trim($arr[1]);
+      }
+    }
+    
+    $this->responseHeaders = $header_array;
+    
+    return $this;
+  }
+  
+  /**
+   * Set the response code
+   *
+   * @param string The first line of the response
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function setResponseCode($firstLine)
+  {
+    preg_match('/\d{3}/', $firstLine, $matches);
+    if(isset($matches[0]))
+    {
+      $this->responseCode = $matches[0];
+    }
+    else
+    {
+      $this->responseCode = '';
+    }
+    
+    return $this;
+  }  
+
+  /**
+   * Set the response contents
+   *
+   * @param string The response contents
+   *
+   * @return sfWebBrowser The current browser object
+   */  
+  public function setResponseText($res)
+  {
+    $this->responseText = $res;
+    
+    return $this;
+  }
+
+  /**
+   * Get a text version of the response
+   *
+   * @return string The response contents
+   */
+  public function getResponseText()
+  {
+    $text = $this->responseText;
+
+    // Decode any content-encoding (gzip or deflate) if needed
+    switch (strtolower($this->getResponseHeader('content-encoding'))) {
+
+        // Handle gzip encoding
+        case 'gzip':
+            $text = $this->decodeGzip($text);
+            break;
+
+        // Handle deflate encoding
+        case 'deflate':
+            $text = $this->decodeDeflate($text);
+            break;
+
+        default:
+            break;
+    }
+
+    return $text;
+  }
+
+  /**
+   * Get a text version of the body part of the response (without <body> and 
</body>)
+   *
+   * @return string The body part of the response contents
+   */
+  public function getResponseBody()
+  {
+    preg_match('/<body.*?>(.*)<\/body>/si', $this->getResponseText(), 
$matches);
+
+    return isset($matches[1]) ? $matches[1] : '';
+  }
+  
+  /**
+   * Get a DOMDocument version of the response 
+   *
+   * @return DOMDocument The reponse contents
+   */
+  public function getResponseDom()
+  {
+    if(!$this->responseDom)
+    {
+      // for HTML/XML content, create a DOM object for the response content
+      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
+      {
+        $this->responseDom = new DomDocument('1.0', 'utf8');
+        $this->responseDom->validateOnParse = true;
+        @$this->responseDom->loadHTML($this->getResponseText());
+      }
+    }
+
+    return $this->responseDom;
+  }
+
+  /**
+   * Get a sfDomCssSelector version of the response 
+   *
+   * @return sfDomCssSelector The response contents
+   */
+  public function getResponseDomCssSelector()
+  {
+    if(!$this->responseDomCssSelector)
+    {
+      // for HTML/XML content, create a DOM object for the response content
+      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
+      {
+        $this->responseDomCssSelector = new 
sfDomCssSelector($this->getResponseDom());
+      }
+    }
+
+    return $this->responseDomCssSelector;
+  }
+
+  /**
+   * Get a SimpleXML version of the response 
+   *
+   * @return  SimpleXMLElement                      The reponse contents
+   * @throws  sfWebBrowserInvalidResponseException  when response is not in a 
valid format 
+   */
+  public function getResponseXML()
+  {
+    if(!$this->responseXml)
+    {
+      // for HTML/XML content, create a DOM object for the response content
+      if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type')))
+      {
+        $this->responseXml = @simplexml_load_string($this->getResponseText());
+      }
+    }
+    
+    // Throw an exception if response is not valid XML
+    if (get_class($this->responseXml) != 'SimpleXMLElement')
+    {
+      $msg = sprintf("Response is not a valid XML string : \n%s", 
$this->getResponseText());
+      throw new sfWebBrowserInvalidResponseException($msg);
+    }
+    
+    return $this->responseXml;
+  }
+
+  /**
+   * Returns true if server response is an error.
+   * 
+   * @return   bool
+   */
+  public function responseIsError()
+  {
+    return in_array((int)($this->getResponseCode() / 100), array(4, 5)); 
+  }
+
+  /**
+   * Get the response headers
+   *
+   * @return array The response headers
+   */
+  public function getResponseHeaders()
+  {
+    return $this->responseHeaders;
+  }  
+
+  /**
+   * Get a response header
+   *
+   * @param string The response header name
+   *
+   * @return string The response header value
+   */
+  public function getResponseHeader($key)
+  {
+    $normalized_key = $this->normalizeHeaderName($key);
+    return (isset($this->responseHeaders[$normalized_key])) ? 
$this->responseHeaders[$normalized_key] : '';
+  }  
+  
+  /**
+   * Decodes gzip-encoded content ("content-encoding: gzip" response header).
+   * 
+   * @param       stream     $gzip_text
+   * @return      string     
+   */
+  protected function decodeGzip($gzip_text)
+  {
+    return gzinflate(substr($gzip_text, 10));
+  }
+
+  /**
+   * Decodes deflate-encoded content ("content-encoding: deflate" response 
header).
+   * 
+   * @param       stream     $deflate_text
+   * @return      string     
+   */  
+  protected function decodeDeflate($deflate_text)
+  {
+    return gzuncompress($deflate_text);
+  }
+  
+  /**
+   * Get the response code
+   *
+   * @return string The response code
+   */
+  public function getResponseCode()
+  {
+    return $this->responseCode; 
+  }
+  
+  /**
+   * Returns the response message (the 'Not Found' part in  'HTTP/1.1 404 Not 
Found')
+   * 
+   * @return   string 
+   */
+  public function getResponseMessage()
+  {
+    return $this->responseMessage;    
+  }
+  
+  /**
+   * Sets response message.
+   * 
+   * @param    string    $message
+   */
+  public function setResponseMessage($msg)
+  {
+    $this->responseMessage = $msg;
+  }
+  
+  public function getUrlInfo()
+  {
+    return $this->urlInfo; 
+  }
+  
+  public function getDefaultRequestHeaders()
+  {
+    return $this->defaultHeaders;
+  }
+  
+  /**
+   * Adds default headers to the supplied headers array.
+   * 
+   * @param       array    $headers
+   * @return      array
+   */
+  public function initializeRequestHeaders($headers = array())
+  {
+    // Supported encodings
+    $encodings = array();
+    if (isset($headers['Accept-Encoding']))
+    {
+      $encodings = explode(',', $headers['Accept-Encoding']);
+    }
+    if (function_exists('gzinflate') && !in_array('gzip', $encodings))
+    {
+      $encodings[] = 'gzip';
+    }
+    if (function_exists('gzuncompress') && !in_array('deflate', $encodings))
+    {
+      $encodings[] = 'deflate';
+    }
+    
+    $headers['Accept-Encoding'] = implode(',', array_unique($encodings));
+    
+    return $headers;
+  }
+  
+  /**
+   * Validates supplied headers and turns all names to lowercase.
+   * 
+   * @param     array     $headers
+   * @return    array
+   */
+  protected function fixHeaders($headers)
+  {
+    $fixed_headers = array();
+    foreach ($headers as $name => $value)
+    {
+      if (!preg_match('/([a-z]*)(-[a-z]*)*/i', $name))
+      {
+        $msg = sprintf('Invalid header "%s"', $name);
+        throw new Exception($msg);
+      }
+      $fixed_headers[$this->normalizeHeaderName($name)] = trim($value);
+    }
+
+    return $fixed_headers;
+  }
+  
+  /**
+   * Retrieves a normalized Header.
+   *
+   * @param string Header name
+   *
+   * @return string Normalized header
+   */
+  protected function normalizeHeaderName($name)
+  {
+    return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", 
strtr(ucfirst($name), '_', '-'));
+  }
+
+}

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to