Development

Changeset 3535

You must first sign up to be able to contribute.

Changeset 3535

Show
Ignore:
Timestamp:
02/22/07 15:28:26 (6 years ago)
Author:
francois
Message:

sfWebBrowserPlugin: 0.9.6 (beta) release (see changelog in README)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • plugins/sfWebBrowserPlugin/README

    r3528 r3535  
    7979Gzip and deflate content-encoded response bodies are also supported, provided that you have the [http://php.net/zlib zlib extention] enabled. 
    8080 
    81 The default page-fetching method uses [http://php.net/fopen fopen()]. However, you can use [http://php.net/curl Curl] if you prefer: 
    82  
    83 {{{ 
     81== Adapters == 
     82 
     83The browser can use various adapters to perform the requests: 
     84  
     85 * `sfFopenAdapter` (default): Uses [http://php.net/fopen `fopen()`] to fetch pages. `fopen()` can take an URL as a parameter provided that PHP is compiled with sockets support, and `allow_url_fopen` is defined to `true` in `php.ini`. This is the case in most PHP distributions, so the default adapter should work in almost every platform. On the other hand, the compatibility has a cost: this adapter is slow. 
     86  
     87 * `sfCurlAdapter`: Uses [http://php.net/curl Curl] to fetch pages. This adapter is a lot faster than `sfFopenAdapter`, however PHP must be compiled with the `with-curl` option, and the `curl` extension must be enabled in `php.ini` (which is rarely the case by default) for it to work.  
     88 
     89You can specify an adapter when you create a new browser object, as follows: 
     90 
     91{{{ 
     92// use default adapter, i.e. sfFopenAdapter 
     93$b = new sfWebBrowser(array()); 
     94// use sfCurlAdapter 
    8495$b = new sfWebBrowser(array(), 'sfCurlAdapter'); 
    85 // use $b in the same way as the examples above 
    86 }}} 
    87  
    88 To use Curl, make sure it is enabled in your php.ini file. 
     96}}} 
     97 
     98== Usage == 
     99 
     100`sfWebBrowser` distiguishes to types of error: adapter errors and response errors. Thus, `sfWebBrowser` calls should be run this way : 
     101 
     102{{{ 
     103$b = new sfWebBrowser(); 
     104try 
     105
     106  if (!$b->get($url)->responseIsError()) 
     107  { 
     108    // Successful response (eg. 200, 201, etc) 
     109  } 
     110  else 
     111  { 
     112    // Error response (eg. 404, 500, etc) 
     113  } 
     114
     115catch (Exception $e) 
     116
     117  // Adapter error (eg. Host not found) 
     118
     119}}} 
     120 
     121Besides, you should always remember that the response contents may contain incorrect code. Consider it as 'tainted', and therefore always use the [http://www.symfony-project.com/book/trunk/07-Inside-the-View-Layer#Output%20Escaping escaping] when outputting it to a template. 
     122 
     123{{{ 
     124// In the action 
     125$this->title = (string) $b->getResponseXml()->body->h1 
     126 
     127// In the template 
     128<?php echo $title // dangerous ?> 
     129<?php echo $sf_data->get('title') // correct ?> 
     130}}} 
    89131 
    90132== Installation == 
     
    102144== Known limitations == 
    103145 
    104 The web request is made via `fopen()`, so this will only work if PHP is compiled with sockets support and if `allow_url_fopen` is defined to `true` in the `php.ini`
     146If `allow_url_fopen` is not defined to `true` and if the curl extension cannot be activated in the `php.ini` file, the browser can't fetch pages. Workaround (todo): use a sockets adapter
    105147 
    106148Cookies are not handled yet. 
     
    110152== Changelog == 
    111153 
     154=== 2007-02-22 | 0.9.6 Beta === 
     155 
     156 * bmeynell, tristan: Allowed for requests with any method in `sfCurlAdapter` 
     157 * tristan: Added `sfWebBrowser::responseIsError()` 
     158 * tristan: Added `sfWebBrowser::getResponseMessage()` 
     159 * tristan: Refactored error management in `sfFopenAdapter` 
     160 
    112161=== 2007-02-21 | 0.9.5 Beta === 
    113162 
    114  * bmeynell: fixed bug with relative uri's attempting to use a port other than 80 (sfWebBrowser, 132 - 146) 
    115  * bmeynell: fixed small bug not printing hostname on exception (sfFopenAdapter, 61-62) 
    116  * bmeynell: created sfCurlAdapter and passes all unit tests 
    117  * bmeynell: removed '$changeStack = true' from call() prototype in sfCurlAdapter, sfFopenAdapter, and moved changestack check to sfWebBrowser 
    118  * bmeynell: added $askeet_url to sfWebBrowserTest 
    119  * bmeynell: added easy toggling between adapters in sfWebBrowserTest 
    120  * tristan: added put() and delete() public methods 
    121  * tristan: added unit tests to validate request HTTP method 
     163 * bmeynell: Fixed bug with relative uri's attempting to use a port other than 80 (sfWebBrowser, 132 - 146) 
     164 * bmeynell: Fixed small bug not printing hostname on exception (sfFopenAdapter, 61-62) 
     165 * bmeynell: Created sfCurlAdapter and passes all unit tests 
     166 * bmeynell: Removed '$changeStack = true' from call() prototype in sfCurlAdapter, sfFopenAdapter, and moved changestack check to sfWebBrowser 
     167 * bmeynell: Added $askeet_url to sfWebBrowserTest 
     168 * bmeynell: Added easy toggling between adapters in sfWebBrowserTest 
     169 * tristan: Added put() and delete() public methods 
     170 * tristan: Added unit tests to validate request HTTP method 
    122171 
    123172=== 2007-02-16 | 0.9.4 Beta === 
    124173 
    125  * francois: refactored the browser to make it multi-adapter 
     174 * francois: Refactored the browser to make it multi-adapter 
    126175 * francois: '''BC break''' constructor signature changed : `new sfWebBrowser(array $headers, string $adapter_class, array $adapter_options)`  
    127  * francois: fixed notice when trying to retrieve inexistent header 
    128  * francois: fixed header case normalization 
    129  * francois: transformed setResponseXXX() methods to public 
    130  * francois: fixed caps in `initializeRequestHeaders()` 
    131  * francois: fixed unit test #40 
     176 * francois: Fixed notice when trying to retrieve inexistent header 
     177 * francois: Fixed header case normalization 
     178 * francois: Transformed setResponseXXX() methods to public 
     179 * francois: Fixed caps in `initializeRequestHeaders()` 
     180 * francois: Fixed unit test #40 
    132181 
    133182=== 2007-02-16 | 0.9.3 Beta === 
  • plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php

    r3528 r3535  
    6969    curl_setopt($curl, CURLOPT_HEADERFUNCTION, array($this, 'read_header')); 
    7070 
    71     if ($method == 'POST') 
    72     { 
    73       curl_setopt($curl, CURLOPT_POST, 1); 
    74       curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($parameters)); 
     71    switch($method)  
     72    {  
     73      case 'POST':  
     74        curl_setopt($curl, CURLOPT_POST, 1);  
     75        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($parameters));  
     76        break; 
     77      default:  
     78        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($parameters));  
     79        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);  
     80        break;   
    7581    } 
    76  
     82     
    7783    $response = curl_exec($curl); 
    7884 
  • plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php

    r3528 r3535  
    2020{  
    2121  protected 
    22     $options = array(); 
     22    $options             = array(), 
     23    $adapterErrorMessage = null, 
     24    $browser             = null; 
    2325     
    2426  public function __construct($options = array()) 
     
    5153      array('header' => $request_headers) 
    5254    ))); 
     55 
     56    // Custom error handler 
     57    // -- browser instance must be accessible from handleRuntimeError() 
     58    $this->browser = $browser; 
     59    set_error_handler(array($this, 'handleRuntimeError'), E_WARNING); 
     60    if($handle = fopen($uri, 'r', false, $context)) 
     61    { 
     62      $response_headers = stream_get_meta_data($handle); 
     63      $browser->setResponseCode(array_shift($response_headers['wrapper_data'])); 
     64      $browser->setResponseHeaders($response_headers['wrapper_data']); 
     65      $browser->setResponseText(stream_get_contents($handle)); 
     66      fclose($handle); 
     67    } 
     68 
     69    restore_error_handler(); 
    5370     
    54     if(!$handle = @fopen($uri, 'r', false, $context)
     71    if ($this->adapterErrorMessage == true
    5572    { 
    56       $urlInfo = $browser->getUrlInfo(); 
    57       throw new Exception(sprintf('Host %s not found', $urlInfo['host']));  
     73      $msg = $this->adapterErrorMessage; 
     74      $this->adapterErrorMessage = null; 
     75      throw new Exception($msg); 
    5876    } 
    5977     
    60     $response_headers = stream_get_meta_data($handle); 
    61  
    62     $browser->setResponseCode(array_shift($response_headers['wrapper_data'])); 
    63     $browser->setResponseHeaders($response_headers['wrapper_data']); 
    64     $browser->setResponseText(stream_get_contents($handle)); 
    65     fclose($handle); 
    66  
    6778    return $browser; 
    6879  } 
    6980   
     81  /** 
     82   * Handles PHP runtime error. 
     83   *  
     84   * This handler is used to catch any warnigns sent by fopen($url) and reformat them to something 
     85   * usable. 
     86   * 
     87   * @see  http://php.net/set_error_handler 
     88   */ 
     89  function handleRuntimeError($errno, $errstr, $errfile = null, $errline = null, $errcontext = array() ) 
     90  { 
     91    $msg = sprintf('%s : "%s" occured in %s on line %d', 
     92                   $error_types[$errno], $errstr, $errfile, $errline); 
     93 
     94    $matches = array(); 
     95    if (preg_match('/HTTP\/\d\.\d (\d{3}) (.*)$/', $errstr, $matches)) 
     96    { 
     97      $this->browser->setResponseCode($matches[1]); 
     98      $this->browser->setResponseMessage($matches[2]); 
     99      $body = sprintf('The %s adapter cannot handle error responses body. Try using another adapter.', __CLASS__); 
     100      $this->browser->setResponseText($body); 
     101    } 
     102    else 
     103    { 
     104      $this->adapterErrorMessage = $msg; 
     105    } 
     106  } 
    70107} 
  • plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php

    r3528 r3535  
    2626    $responseHeaders         = array(), 
    2727    $responseCode            = '', 
     28    $responseMessage         = '', 
    2829    $responseText            = '', 
    2930    $responseDom             = null, 
     
    642643 
    643644  /** 
     645   * Returns true if server response is an error. 
     646   *  
     647   * @return   bool 
     648   */ 
     649  public function responseIsError() 
     650  { 
     651    return in_array((int)($this->getResponseCode() / 100), array(4, 5));  
     652  } 
     653 
     654  /** 
    644655   * Get the response headers 
    645656   * 
     
    696707  } 
    697708   
     709  /** 
     710   * Returns the response message (the 'Not Found' part in  'HTTP/1.1 404 Not Found') 
     711   *  
     712   * @return   string  
     713   */ 
     714  public function getResponseMessage() 
     715  { 
     716    return $this->responseMessage;     
     717  } 
     718   
     719  /** 
     720   * Sets response message. 
     721   *  
     722   * @param    string    $message 
     723   */ 
     724  public function setResponseMessage($msg) 
     725  { 
     726    $this->responseMessage = $msg; 
     727  } 
     728   
    698729  public function getUrlInfo() 
    699730  { 
  • plugins/sfWebBrowserPlugin/package.xml

    r3528 r3535  
    1111  <active>yes</active> 
    1212 </lead> 
    13  <date>2007-02-21</date> 
     13 <date>2007-02-22</date> 
    1414 <version> 
    15    <release>0.9.5</release> 
    16    <api>0.9.5</api> 
     15   <release>0.9.6</release> 
     16   <api>0.9.6</api> 
    1717 </version> 
    1818 <stability> 
  • plugins/sfWebBrowserPlugin/test/unit/sfWebBrowserTest.php

    r3528 r3535  
    2121require_once($sf_symfony_lib_dir.'/util/sfToolkit.class.php'); 
    2222 
    23 $t = new lime_test(51, new lime_output_color()); 
     23$t = new lime_test(54, new lime_output_color()); 
    2424 
    2525$t->diag('initialization'); 
     
    5252} 
    5353 
    54 try 
    55 { 
    56   $b->get('http://www.4Z5erg7fs.com'); 
    57   $t->fail('get() throws an exception when the host is not found'); 
    58 } 
    59 catch (Exception $e) 
    60 { 
    61   $t->pass('get() throws an exception when the host is not found'); 
    62 } 
    63  
    6454$t->diag('simple GET request'); 
    6555$t->like($b->get($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => GET/', 'get() performs a GET request'); 
     
    7969$t->diag('simple DELETE request'); 
    8070$t->like($b->delete($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => DELETE/', 'delete() performs a DELETE request'); 
     71 
     72$t->diag('arbitrary request'); 
     73$t->like($b->call($dump_headers_url, 'MICHEL')->getResponseText(), '/\[REQUEST_METHOD\] => MICHEL/', 'call() supports any HTTP methods'); 
     74 
    8175 
    8276$t->diag('Response formats methods'); 
     
    190184  $t->fail(sprintf('%s : skipping tests that need it', $e->getMessage()));   
    191185} 
     186 
     187$t->diag('Error management'); 
     188try 
     189{ 
     190  $b->get('http://nonexistent'); 
     191  $t->fail('an exception is thrown when an adapter error occurs'); 
     192} 
     193catch (Exception $e) 
     194{ 
     195  $t->pass('an exception is thrown when an adapter error occurs'); 
     196} 
     197 
     198$t->diag('responseIsError()'); 
     199$t->is($b->get($example_site_url . '/nonexistentpage.html')->responseIsError(), true, 'responseIsError() returns true when response is an error'); 
     200$t->is($b->get($example_site_url)->responseIsError(), false, 'responseIsError() returns false when response is not an error'); 
    192201 
    193202$t->diag('history methods');