| [ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 3 /* 4 * This file is part of the symfony package. 5 * (c) 2004-2006 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 * sfBrowser simulates a fake browser which can surf a symfony application. 13 * 14 * @package symfony 15 * @subpackage util 16 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 17 * @version SVN: $Id: sfBrowser.class.php 3334 2007-01-23 15:46:08Z fabien $ 18 */ 19 class sfBrowser 20 { 21 protected 22 $context = null, 23 $hostname = null, 24 $remote = null, 25 $dom = null, 26 $stack = array(), 27 $stackPosition = -1, 28 $cookieJar = array(), 29 $fields = array(), 30 $vars = array(), 31 $defaultServerArray = array(), 32 $currentException = null; 33 34 public function initialize($hostname = null, $remote = null, $options = array()) 35 { 36 unset($_SERVER['argv']); 37 unset($_SERVER['argc']); 38 39 // setup our fake environment 40 $this->hostname = $hostname; 41 $this->remote = $remote; 42 43 sfConfig::set('sf_path_info_array', 'SERVER'); 44 sfConfig::set('sf_test', true); 45 46 // we set a session id (fake cookie / persistence) 47 $this->newSession(); 48 49 // store default global $_SERVER array 50 $this->defaultServerArray = $_SERVER; 51 52 // register our shutdown function 53 register_shutdown_function(array($this, 'shutdown')); 54 } 55 56 public function setVar($name, $value) 57 { 58 $this->vars[$name] = $value; 59 60 return $this; 61 } 62 63 public function setAuth($login, $password) 64 { 65 $this->vars['PHP_AUTH_USER'] = $login; 66 $this->vars['PHP_AUTH_PW'] = $password; 67 68 return $this; 69 } 70 71 public function get($uri, $parameters = array()) 72 { 73 return $this->call($uri, 'get', $parameters); 74 } 75 76 public function post($uri, $parameters = array()) 77 { 78 return $this->call($uri, 'post', $parameters); 79 } 80 81 public function call($uri, $method = 'get', $parameters = array(), $changeStack = true) 82 { 83 $uri = $this->fixUri($uri); 84 85 // add uri to the stack 86 if ($changeStack) 87 { 88 $this->stack = array_slice($this->stack, 0, $this->stackPosition + 1); 89 $this->stack[] = array( 90 'uri' => $uri, 91 'method' => $method, 92 'parameters' => $parameters, 93 ); 94 $this->stackPosition = count($this->stack) - 1; 95 } 96 97 list($path, $query_string) = false !== ($pos = strpos($uri, '?')) ? array(substr($uri, 0, $pos), substr($uri, $pos + 1)) : array($uri, ''); 98 $query_string = html_entity_decode($query_string); 99 100 // remove anchor 101 $path = preg_replace('/#.*/', '', $path); 102 103 // removes all fields from previous request 104 $this->fields = array(); 105 106 // prepare the request object 107 $_SERVER = $this->defaultServerArray; 108 $_SERVER['HTTP_HOST'] = $this->hostname ? $this->hostname : sfConfig::get('sf_app').'-'.sfConfig::get('sf_environment'); 109 $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST']; 110 $_SERVER['SERVER_PORT'] = 80; 111 $_SERVER['HTTP_USER_AGENT'] = 'PHP5/CLI'; 112 $_SERVER['REMOTE_ADDR'] = $this->remote ? $this->remote : '127.0.0.1'; 113 $_SERVER['REQUEST_METHOD'] = strtoupper($method); 114 $_SERVER['PATH_INFO'] = $path; 115 $_SERVER['REQUEST_URI'] = '/index.php'.$uri; 116 $_SERVER['SCRIPT_NAME'] = '/index.php'; 117 $_SERVER['SCRIPT_FILENAME'] = '/index.php'; 118 $_SERVER['QUERY_STRING'] = $query_string; 119 foreach ($this->vars as $key => $value) 120 { 121 $_SERVER[strtoupper($key)] = $value; 122 } 123 124 // request parameters 125 $_GET = $_POST = array(); 126 if (strtoupper($method) == 'POST') 127 { 128 $_POST = $parameters; 129 } 130 if (strtoupper($method) == 'GET') 131 { 132 $_GET = $parameters; 133 } 134 parse_str($query_string, $qs); 135 if (is_array($qs)) 136 { 137 $_GET = array_merge($qs, $_GET); 138 } 139 140 // restore cookies 141 $_COOKIE = array(); 142 foreach ($this->cookieJar as $name => $cookie) 143 { 144 $_COOKIE[$name] = $cookie['value']; 145 } 146 147 // recycle our context object 148 sfContext::removeInstance(); 149 $this->context = sfContext::getInstance(); 150 151 // launch request via controller 152 $controller = $this->context->getController(); 153 $request = $this->context->getRequest(); 154 $response = $this->context->getResponse(); 155 156 // we register a fake rendering filter 157 sfConfig::set('sf_rendering_filter', array('sfFakeRenderingFilter', null)); 158 159 $this->currentException = null; 160 161 // dispatch our request 162 ob_start(); 163 try 164 { 165 $controller->dispatch(); 166 } 167 catch (sfException $e) 168 { 169 $this->currentException = $e; 170 171 $e->printStackTrace(); 172 } 173 catch (Exception $e) 174 { 175 $this->currentException = $e; 176 177 $sfException = new sfException(); 178 $sfException->printStackTrace($e); 179 } 180 $retval = ob_get_clean(); 181 182 if ($this->currentException instanceof sfStopException) 183 { 184 $this->currentException = null; 185 } 186 187 // append retval to the response content 188 $response->setContent($retval); 189 190 // manually shutdown user to save current session data 191 $this->context->getUser()->shutdown(); 192 $this->context->getStorage()->shutdown(); 193 194 // save cookies 195 $this->cookieJar = array(); 196 foreach ($response->getCookies() as $name => $cookie) 197 { 198 // FIXME: deal with expire, path, secure, ... 199 $this->cookieJar[$name] = $cookie; 200 } 201 202 // for HTML/XML content, create a DOM and sfDomCssSelector objects for the response content 203 if (preg_match('/(x|ht)ml/i', $response->getContentType())) 204 { 205 $this->dom = new DomDocument('1.0', sfConfig::get('sf_charset')); 206 $this->dom->validateOnParse = true; 207 @$this->dom->loadHTML($response->getContent()); 208 $this->domCssSelector = new sfDomCssSelector($this->dom); 209 } 210 211 return $this; 212 } 213 214 public function back() 215 { 216 if ($this->stackPosition < 1) 217 { 218 throw new sfException('You are already on the first page.'); 219 } 220 221 --$this->stackPosition; 222 return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false); 223 } 224 225 public function forward() 226 { 227 if ($this->stackPosition > count($this->stack) - 2) 228 { 229 throw new sfException('You are already on the last page.'); 230 } 231 232 ++$this->stackPosition; 233 return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false); 234 } 235 236 public function reload() 237 { 238 if (-1 == $this->stackPosition) 239 { 240 throw new sfException('No page to reload.'); 241 } 242 243 return $this->call($this->stack[$this->stackPosition]['uri'], $this->stack[$this->stackPosition]['method'], $this->stack[$this->stackPosition]['parameters'], false); 244 } 245 246 public function getResponseDomCssSelector() 247 { 248 return $this->domCssSelector; 249 } 250 251 public function getResponseDom() 252 { 253 return $this->dom; 254 } 255 256 public function getContext() 257 { 258 return $this->context; 259 } 260 261 public function getResponse() 262 { 263 return $this->context->getResponse(); 264 } 265 266 public function getRequest() 267 { 268 return $this->context->getRequest(); 269 } 270 271 public function getCurrentException() 272 { 273 return $this->currentException; 274 } 275 276 public function followRedirect() 277 { 278 if (null === $this->getContext()->getResponse()->getHttpHeader('Location')) 279 { 280 throw new sfException('The request was not redirected'); 281 } 282 283 return $this->get($this->getContext()->getResponse()->getHttpHeader('Location')); 284 } 285 286 public function setField($name, $value) 287 { 288 // as we don't know yet the form, just store name/value pairs 289 $this->parseArgumentAsArray($name, $value, $this->fields); 290 291 return $this; 292 } 293 294 // link or button 295 public function click($name, $arguments = array()) 296 { 297 if (!$this->dom) 298 { 299 throw new sfException('Cannot click because there is no current page in the browser'); 300 } 301 302 $xpath = new DomXpath($this->dom); 303 $dom = $this->dom; 304 305 // text link 306 if ($link = $xpath->query(sprintf('//a[.="%s"]', $name))->item(0)) 307 { 308 return $this->get($link->getAttribute('href')); 309 } 310 311 // image link 312 if ($link = $xpath->query(sprintf('//a/img[@alt="%s"]/ancestor::a', $name))->item(0)) 313 { 314 return $this->get($link->getAttribute('href')); 315 } 316 317 // form 318 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)) 319 { 320 throw new sfException(sprintf('Cannot find the "%s" link or button.', $name)); 321 } 322 323 // form attributes 324 $url = $form->getAttribute('action'); 325 $method = $form->getAttribute('method') ? strtolower($form->getAttribute('method')) : 'get'; 326 327 // merge form default values and arguments 328 $defaults = array(); 329 foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $form) as $element) 330 { 331 $elementName = $element->getAttribute('name'); 332 $nodeName = $element->nodeName; 333 $value = null; 334 if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio')) 335 { 336 if ($element->getAttribute('checked')) 337 { 338 $value = $element->getAttribute('value'); 339 } 340 } 341 else if ( 342 $nodeName == 'input' 343 && 344 (($element->getAttribute('type') != 'submit' && $element->getAttribute('type') != 'button') || $element->getAttribute('value') == $name) 345 && 346 ($element->getAttribute('type') != 'image' || $element->getAttribute('alt') == $name) 347 ) 348 { 349 $value = $element->getAttribute('value'); 350 } 351 else if ($nodeName == 'textarea') 352 { 353 $value = ''; 354 foreach ($element->childNodes as $el) 355 { 356 $value .= $dom->saveXML($el); 357 } 358 } 359 else if ($nodeName == 'select') 360 { 361 if ($multiple = $element->hasAttribute('multiple')) 362 { 363 $elementName = str_replace('[]', '', $elementName); 364 $value = array(); 365 } 366 else 367 { 368 $value = null; 369 } 370 371 $found = false; 372 foreach ($xpath->query('descendant::option', $element) as $option) 373 { 374 if ($option->getAttribute('selected')) 375 { 376 $found = true; 377 if ($multiple) 378 { 379 $value[] = $option->getAttribute('value'); 380 } 381 else 382 { 383 $value = $option->getAttribute('value'); 384 } 385 } 386 } 387 388 // if no option is selected and if it is a simple select box, take the first option as the value 389 if (!$found && !$multiple) 390 { 391 $value = $xpath->query('descendant::option', $element)->item(0)->getAttribute('value'); 392 } 393 } 394 395 if (null !== $value) 396 { 397 $this->parseArgumentAsArray($elementName, $value, $defaults); 398 } 399 } 400 401 // create request parameters 402 $arguments = sfToolkit::arrayDeepMerge($defaults, $this->fields, $arguments); 403 if ('post' == $method) 404 { 405 return $this->post($url, $arguments); 406 } 407 else 408 { 409 $query_string = http_build_query($arguments); 410 $sep = false === strpos($url, '?') ? '?' : '&'; 411 412 return $this->get($url.($query_string ? $sep.$query_string : '')); 413 } 414 } 415 416 protected function parseArgumentAsArray($name, $value, &$vars) 417 { 418 if (false !== $pos = strpos($name, '[')) 419 { 420 $var = &$vars; 421 $tmps = array_filter(preg_split('/(\[ | \[\] | \])/x', $name)); 422 foreach ($tmps as $tmp) 423 { 424 $var = &$var[$tmp]; 425 } 426 if ($var) 427 { 428 if (!is_array($var)) 429 { 430 $var = array($var); 431 } 432 $var[] = $value; 433 } 434 else 435 { 436 $var = $value; 437 } 438 } 439 else 440 { 441 $vars[$name] = $value; 442 } 443 } 444 445 public function restart() 446 { 447 $this->newSession(); 448 $this->cookieJar = array(); 449 $this->stack = array(); 450 $this->fields = array(); 451 $this->vars = array(); 452 $this->dom = null; 453 $this->stackPosition = -1; 454 455 return $this; 456 } 457 458 public function shutdown() 459 { 460 // we remove all session data 461 sfToolkit::clearDirectory(sfConfig::get('sf_test_cache_dir').'/sessions'); 462 } 463 464 protected function fixUri($uri) 465 { 466 // remove absolute information if needed (to be able to do follow redirects, click on links, ...) 467 if (0 === strpos($uri, 'http')) 468 { 469 // detect secure request 470 if (0 === strpos($uri, 'https')) 471 { 472 $this->defaultServerArray['HTTPS'] = 'on'; 473 } 474 else 475 { 476 unset($this->defaultServerArray['HTTPS']); 477 } 478 479 $uri = substr($uri, strpos($uri, 'index.php') + strlen('index.php')); 480 } 481 $uri = str_replace('/index.php', '', $uri); 482 483 // # as a uri 484 if ($uri && '#' == $uri[0]) 485 { 486 $uri = $this->stack[$this->stackPosition]['uri'].$uri; 487 } 488 489 return $uri; 490 } 491 492 protected function newSession() 493 { 494 $_SERVER['session_id'] = md5(uniqid(rand(), true)); 495 } 496 } 497 498 class sfFakeRenderingFilter extends sfFilter 499 { 500 public function execute($filterChain) 501 { 502 $filterChain->execute(); 503 504 $this->getContext()->getResponse()->sendContent(); 505 } 506 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |