Changeset 3535
- Timestamp:
- 02/22/07 15:28:26 (6 years ago)
- Files:
-
- plugins/sfWebBrowserPlugin/README (modified) (3 diffs)
- plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php (modified) (1 diff)
- plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php (modified) (2 diffs)
- plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php (modified) (3 diffs)
- plugins/sfWebBrowserPlugin/package.xml (modified) (1 diff)
- plugins/sfWebBrowserPlugin/test/unit/sfWebBrowserTest.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/sfWebBrowserPlugin/README
r3528 r3535 79 79 Gzip and deflate content-encoded response bodies are also supported, provided that you have the [http://php.net/zlib zlib extention] enabled. 80 80 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 83 The 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 89 You 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 84 95 $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(); 104 try 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 } 115 catch (Exception $e) 116 { 117 // Adapter error (eg. Host not found) 118 } 119 }}} 120 121 Besides, 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 }}} 89 131 90 132 == Installation == … … 102 144 == Known limitations == 103 145 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`.146 If `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. 105 147 106 148 Cookies are not handled yet. … … 110 152 == Changelog == 111 153 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 112 161 === 2007-02-21 | 0.9.5 Beta === 113 162 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 tests117 * bmeynell: removed '$changeStack = true' from call() prototype in sfCurlAdapter, sfFopenAdapter, and moved changestack check to sfWebBrowser118 * bmeynell: added $askeet_url to sfWebBrowserTest119 * bmeynell: added easy toggling between adapters in sfWebBrowserTest120 * tristan: added put() and delete() public methods121 * tristan: added unit tests to validate request HTTP method163 * 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 122 171 123 172 === 2007-02-16 | 0.9.4 Beta === 124 173 125 * francois: refactored the browser to make it multi-adapter174 * francois: Refactored the browser to make it multi-adapter 126 175 * 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 header128 * francois: fixed header case normalization129 * francois: transformed setResponseXXX() methods to public130 * francois: fixed caps in `initializeRequestHeaders()`131 * francois: fixed unit test #40176 * 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 132 181 133 182 === 2007-02-16 | 0.9.3 Beta === plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php
r3528 r3535 69 69 curl_setopt($curl, CURLOPT_HEADERFUNCTION, array($this, 'read_header')); 70 70 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; 75 81 } 76 82 77 83 $response = curl_exec($curl); 78 84 plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php
r3528 r3535 20 20 { 21 21 protected 22 $options = array(); 22 $options = array(), 23 $adapterErrorMessage = null, 24 $browser = null; 23 25 24 26 public function __construct($options = array()) … … 51 53 array('header' => $request_headers) 52 54 ))); 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(); 53 70 54 if (!$handle = @fopen($uri, 'r', false, $context))71 if ($this->adapterErrorMessage == true) 55 72 { 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); 58 76 } 59 77 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 67 78 return $browser; 68 79 } 69 80 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 } 70 107 } plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php
r3528 r3535 26 26 $responseHeaders = array(), 27 27 $responseCode = '', 28 $responseMessage = '', 28 29 $responseText = '', 29 30 $responseDom = null, … … 642 643 643 644 /** 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 /** 644 655 * Get the response headers 645 656 * … … 696 707 } 697 708 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 698 729 public function getUrlInfo() 699 730 { plugins/sfWebBrowserPlugin/package.xml
r3528 r3535 11 11 <active>yes</active> 12 12 </lead> 13 <date>2007-02-2 1</date>13 <date>2007-02-22</date> 14 14 <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> 17 17 </version> 18 18 <stability> plugins/sfWebBrowserPlugin/test/unit/sfWebBrowserTest.php
r3528 r3535 21 21 require_once($sf_symfony_lib_dir.'/util/sfToolkit.class.php'); 22 22 23 $t = new lime_test(5 1, new lime_output_color());23 $t = new lime_test(54, new lime_output_color()); 24 24 25 25 $t->diag('initialization'); … … 52 52 } 53 53 54 try55 {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 64 54 $t->diag('simple GET request'); 65 55 $t->like($b->get($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => GET/', 'get() performs a GET request'); … … 79 69 $t->diag('simple DELETE request'); 80 70 $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 81 75 82 76 $t->diag('Response formats methods'); … … 190 184 $t->fail(sprintf('%s : skipping tests that need it', $e->getMessage())); 191 185 } 186 187 $t->diag('Error management'); 188 try 189 { 190 $b->get('http://nonexistent'); 191 $t->fail('an exception is thrown when an adapter error occurs'); 192 } 193 catch (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'); 192 201 193 202 $t->diag('history methods');