1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Controller 17 * @subpackage Zend_Controller_Action_Helper 18 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id$ 21 */ 22 23/** 24 * @see Zend_Controller_Action_Helper_Abstract 25 */ 26 27/** 28 * @category Zend 29 * @package Zend_Controller 30 * @subpackage Zend_Controller_Action_Helper 31 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 32 * @license http://framework.zend.com/license/new-bsd New BSD License 33 */ 34class Zend_Controller_Action_Helper_Redirector extends Zend_Controller_Action_Helper_Abstract 35{ 36 /** 37 * HTTP status code for redirects 38 * @var int 39 */ 40 protected $_code = 302; 41 42 /** 43 * Whether or not calls to _redirect() should exit script execution 44 * @var boolean 45 */ 46 protected $_exit = true; 47 48 /** 49 * Whether or not _redirect() should attempt to prepend the base URL to the 50 * passed URL (if it's a relative URL) 51 * @var boolean 52 */ 53 protected $_prependBase = true; 54 55 /** 56 * Url to which to redirect 57 * @var string 58 */ 59 protected $_redirectUrl = null; 60 61 /** 62 * Whether or not to use an absolute URI when redirecting 63 * @var boolean 64 */ 65 protected $_useAbsoluteUri = false; 66 67 /** 68 * Whether or not to close the session before exiting 69 * @var boolean 70 */ 71 protected $_closeSessionOnExit = true; 72 73 /** 74 * Retrieve HTTP status code to emit on {@link _redirect()} call 75 * 76 * @return int 77 */ 78 public function getCode() 79 { 80 return $this->_code; 81 } 82 83 /** 84 * Validate HTTP status redirect code 85 * 86 * @param int $code 87 * @throws Zend_Controller_Action_Exception on invalid HTTP status code 88 * @return true 89 */ 90 protected function _checkCode($code) 91 { 92 $code = (int)$code; 93 if ((300 > $code) || (307 < $code) || (304 == $code) || (306 == $code)) { 94 throw new Zend_Controller_Action_Exception('Invalid redirect HTTP status code (' . $code . ')'); 95 } 96 97 return true; 98 } 99 100 /** 101 * Set HTTP status code for {@link _redirect()} behaviour 102 * 103 * @param int $code 104 * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 105 */ 106 public function setCode($code) 107 { 108 $this->_checkCode($code); 109 $this->_code = $code; 110 return $this; 111 } 112 113 /** 114 * Retrieve flag for whether or not {@link _redirect()} will exit when finished. 115 * 116 * @return boolean 117 */ 118 public function getExit() 119 { 120 return $this->_exit; 121 } 122 123 /** 124 * Set exit flag for {@link _redirect()} behaviour 125 * 126 * @param boolean $flag 127 * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 128 */ 129 public function setExit($flag) 130 { 131 $this->_exit = ($flag) ? true : false; 132 return $this; 133 } 134 135 /** 136 * Retrieve flag for whether or not {@link _redirect()} will prepend the 137 * base URL on relative URLs 138 * 139 * @return boolean 140 */ 141 public function getPrependBase() 142 { 143 return $this->_prependBase; 144 } 145 146 /** 147 * Set 'prepend base' flag for {@link _redirect()} behaviour 148 * 149 * @param boolean $flag 150 * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 151 */ 152 public function setPrependBase($flag) 153 { 154 $this->_prependBase = ($flag) ? true : false; 155 return $this; 156 } 157 158 /** 159 * Retrieve flag for whether or not {@link redirectAndExit()} shall close the session before 160 * exiting. 161 * 162 * @return boolean 163 */ 164 public function getCloseSessionOnExit() 165 { 166 return $this->_closeSessionOnExit; 167 } 168 169 /** 170 * Set flag for whether or not {@link redirectAndExit()} shall close the session before exiting. 171 * 172 * @param boolean $flag 173 * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 174 */ 175 public function setCloseSessionOnExit($flag) 176 { 177 $this->_closeSessionOnExit = ($flag) ? true : false; 178 return $this; 179 } 180 181 /** 182 * Return use absolute URI flag 183 * 184 * @return boolean 185 */ 186 public function getUseAbsoluteUri() 187 { 188 return $this->_useAbsoluteUri; 189 } 190 191 /** 192 * Set use absolute URI flag 193 * 194 * @param boolean $flag 195 * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 196 */ 197 public function setUseAbsoluteUri($flag = true) 198 { 199 $this->_useAbsoluteUri = ($flag) ? true : false; 200 return $this; 201 } 202 203 /** 204 * Set redirect in response object 205 * 206 * @return void 207 */ 208 protected function _redirect($url) 209 { 210 if ($this->getUseAbsoluteUri() && !preg_match('#^(https?|ftp)://#', $url)) { 211 $host = (isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:''); 212 $proto = (isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=="off") ? 'https' : 'http'; 213 $port = (isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:80); 214 $uri = $proto . '://' . $host; 215 if ((('http' == $proto) && (80 != $port)) || (('https' == $proto) && (443 != $port))) { 216 // do not append if HTTP_HOST already contains port 217 if (strrchr($host, ':') === false) { 218 $uri .= ':' . $port; 219 } 220 } 221 $url = $uri . '/' . ltrim($url, '/'); 222 } 223 $this->_redirectUrl = $url; 224 $this->getResponse()->setRedirect($url, $this->getCode()); 225 } 226 227 /** 228 * Retrieve currently set URL for redirect 229 * 230 * @return string 231 */ 232 public function getRedirectUrl() 233 { 234 return $this->_redirectUrl; 235 } 236 237 /** 238 * Determine if the baseUrl should be prepended, and prepend if necessary 239 * 240 * @param string $url 241 * @return string 242 */ 243 protected function _prependBase($url) 244 { 245 if ($this->getPrependBase()) { 246 $request = $this->getRequest(); 247 if ($request instanceof Zend_Controller_Request_Http) { 248 $base = rtrim($request->getBaseUrl(), '/'); 249 if (!empty($base) && ('/' != $base)) { 250 $url = $base . '/' . ltrim($url, '/'); 251 } else { 252 $url = '/' . ltrim($url, '/'); 253 } 254 } 255 } 256 257 return $url; 258 } 259 260 /** 261 * Set a redirect URL of the form /module/controller/action/params 262 * 263 * @param string $action 264 * @param string $controller 265 * @param string $module 266 * @param array $params 267 * @return void 268 */ 269 public function setGotoSimple($action, $controller = null, $module = null, array $params = array()) 270 { 271 $dispatcher = $this->getFrontController()->getDispatcher(); 272 $request = $this->getRequest(); 273 $curModule = $request->getModuleName(); 274 $useDefaultController = false; 275 276 if (null === $controller && null !== $module) { 277 $useDefaultController = true; 278 } 279 280 if (null === $module) { 281 $module = $curModule; 282 } 283 284 if ($module == $dispatcher->getDefaultModule()) { 285 $module = ''; 286 } 287 288 if (null === $controller && !$useDefaultController) { 289 $controller = $request->getControllerName(); 290 if (empty($controller)) { 291 $controller = $dispatcher->getDefaultControllerName(); 292 } 293 } 294 295 $params[$request->getModuleKey()] = $module; 296 $params[$request->getControllerKey()] = $controller; 297 $params[$request->getActionKey()] = $action; 298 299 $router = $this->getFrontController()->getRouter(); 300 $url = $router->assemble($params, 'default', true); 301 302 $this->_redirect($url); 303 } 304 305 /** 306 * Build a URL based on a route 307 * 308 * @param array $urlOptions 309 * @param string $name Route name 310 * @param boolean $reset 311 * @param boolean $encode 312 * @return void 313 */ 314 public function setGotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) 315 { 316 $router = $this->getFrontController()->getRouter(); 317 $url = $router->assemble($urlOptions, $name, $reset, $encode); 318 319 $this->_redirect($url); 320 } 321 322 /** 323 * Set a redirect URL string 324 * 325 * By default, emits a 302 HTTP status header, prepends base URL as defined 326 * in request object if url is relative, and halts script execution by 327 * calling exit(). 328 * 329 * $options is an optional associative array that can be used to control 330 * redirect behaviour. The available option keys are: 331 * - exit: boolean flag indicating whether or not to halt script execution when done 332 * - prependBase: boolean flag indicating whether or not to prepend the base URL when a relative URL is provided 333 * - code: integer HTTP status code to use with redirect. Should be between 300 and 307. 334 * 335 * _redirect() sets the Location header in the response object. If you set 336 * the exit flag to false, you can override this header later in code 337 * execution. 338 * 339 * If the exit flag is true (true by default), _redirect() will write and 340 * close the current session, if any. 341 * 342 * @param string $url 343 * @param array $options 344 * @return void 345 */ 346 public function setGotoUrl($url, array $options = array()) 347 { 348 // prevent header injections 349 $url = str_replace(array("\n", "\r"), '', $url); 350 351 if (null !== $options) { 352 if (isset($options['exit'])) { 353 $this->setExit(($options['exit']) ? true : false); 354 } 355 if (isset($options['prependBase'])) { 356 $this->setPrependBase(($options['prependBase']) ? true : false); 357 } 358 if (isset($options['code'])) { 359 $this->setCode($options['code']); 360 } 361 } 362 363 // If relative URL, decide if we should prepend base URL 364 if (!preg_match('|^[a-z]+://|', $url)) { 365 $url = $this->_prependBase($url); 366 } 367 368 $this->_redirect($url); 369 } 370 371 /** 372 * Perform a redirect to an action/controller/module with params 373 * 374 * @param string $action 375 * @param string $controller 376 * @param string $module 377 * @param array $params 378 * @return void 379 */ 380 public function gotoSimple($action, $controller = null, $module = null, array $params = array()) 381 { 382 $this->setGotoSimple($action, $controller, $module, $params); 383 384 if ($this->getExit()) { 385 $this->redirectAndExit(); 386 } 387 } 388 389 /** 390 * Perform a redirect to an action/controller/module with params, forcing an immdiate exit 391 * 392 * @param mixed $action 393 * @param mixed $controller 394 * @param mixed $module 395 * @param array $params 396 * @return void 397 */ 398 public function gotoSimpleAndExit($action, $controller = null, $module = null, array $params = array()) 399 { 400 $this->setGotoSimple($action, $controller, $module, $params); 401 $this->redirectAndExit(); 402 } 403 404 /** 405 * Redirect to a route-based URL 406 * 407 * Uses route's assemble method to build the URL; route is specified by $name; 408 * default route is used if none provided. 409 * 410 * @param array $urlOptions Array of key/value pairs used to assemble URL 411 * @param string $name 412 * @param boolean $reset 413 * @param boolean $encode 414 * @return void 415 */ 416 public function gotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) 417 { 418 $this->setGotoRoute($urlOptions, $name, $reset, $encode); 419 420 if ($this->getExit()) { 421 $this->redirectAndExit(); 422 } 423 } 424 425 /** 426 * Redirect to a route-based URL, and immediately exit 427 * 428 * Uses route's assemble method to build the URL; route is specified by $name; 429 * default route is used if none provided. 430 * 431 * @param array $urlOptions Array of key/value pairs used to assemble URL 432 * @param string $name 433 * @param boolean $reset 434 * @return void 435 */ 436 public function gotoRouteAndExit(array $urlOptions = array(), $name = null, $reset = false) 437 { 438 $this->setGotoRoute($urlOptions, $name, $reset); 439 $this->redirectAndExit(); 440 } 441 442 /** 443 * Perform a redirect to a url 444 * 445 * @param string $url 446 * @param array $options 447 * @return void 448 */ 449 public function gotoUrl($url, array $options = array()) 450 { 451 $this->setGotoUrl($url, $options); 452 453 if ($this->getExit()) { 454 $this->redirectAndExit(); 455 } 456 } 457 458 /** 459 * Set a URL string for a redirect, perform redirect, and immediately exit 460 * 461 * @param string $url 462 * @param array $options 463 * @return void 464 */ 465 public function gotoUrlAndExit($url, array $options = array()) 466 { 467 $this->setGotoUrl($url, $options); 468 $this->redirectAndExit(); 469 } 470 471 /** 472 * exit(): Perform exit for redirector 473 * 474 * @return void 475 */ 476 public function redirectAndExit() 477 { 478 if ($this->getCloseSessionOnExit()) { 479 // Close session, if started 480 if (class_exists('Zend_Session', false) && Zend_Session::isStarted()) { 481 Zend_Session::writeClose(); 482 } elseif (isset($_SESSION)) { 483 session_write_close(); 484 } 485 } 486 487 $this->getResponse()->sendHeaders(); 488 exit(); 489 } 490 491 /** 492 * direct(): Perform helper when called as 493 * $this->_helper->redirector($action, $controller, $module, $params) 494 * 495 * @param string $action 496 * @param string $controller 497 * @param string $module 498 * @param array $params 499 * @return void 500 */ 501 public function direct($action, $controller = null, $module = null, array $params = array()) 502 { 503 $this->gotoSimple($action, $controller, $module, $params); 504 } 505 506 /** 507 * Overloading 508 * 509 * Overloading for old 'goto', 'setGoto', and 'gotoAndExit' methods 510 * 511 * @param string $method 512 * @param array $args 513 * @return mixed 514 * @throws Zend_Controller_Action_Exception for invalid methods 515 */ 516 public function __call($method, $args) 517 { 518 $method = strtolower($method); 519 if ('goto' == $method) { 520 return call_user_func_array(array($this, 'gotoSimple'), $args); 521 } 522 if ('setgoto' == $method) { 523 return call_user_func_array(array($this, 'setGotoSimple'), $args); 524 } 525 if ('gotoandexit' == $method) { 526 return call_user_func_array(array($this, 'gotoSimpleAndExit'), $args); 527 } 528 529 throw new Zend_Controller_Action_Exception(sprintf('Invalid method "%s" called on redirector', $method)); 530 } 531} 532