Development

/branches/1.4/lib/controller/sfWebController.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/controller/sfWebController.class.php

Revision 30563, 5.4 kB (checked in by fabien, 4 years ago)

[1.3, 1.4] fixed sfWebController::redirect method does not respect HTTP specification (closes #8952, patch from rande)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
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  * (c) 2004-2006 Sean Kerr <sean@code-box.org>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * sfWebController provides web specific methods to sfController such as, url redirection.
14  *
15  * @package    symfony
16  * @subpackage controller
17  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
18  * @author     Sean Kerr <sean@code-box.org>
19  * @version    SVN: $Id$
20  */
21 abstract class sfWebController extends sfController
22 {
23   /**
24    * Generates an URL from an array of parameters.
25    *
26    * @param mixed   $parameters An associative array of URL parameters or an internal URI as a string.
27    * @param boolean $absolute   Whether to generate an absolute URL
28    *
29    * @return string A URL to a symfony resource
30    */
31   public function genUrl($parameters = array(), $absolute = false)
32   {
33     $route = '';
34     $fragment = '';
35
36     if (is_string($parameters))
37     {
38       // absolute URL or symfony URL?
39       if (preg_match('#^[a-z][a-z0-9\+.\-]*\://#i', $parameters))
40       {
41         return $parameters;
42       }
43
44       // relative URL?
45       if (0 === strpos($parameters, '/'))
46       {
47         return $parameters;
48       }
49
50       if ($parameters == '#')
51       {
52         return $parameters;
53       }
54  
55       // strip fragment
56       if (false !== ($pos = strpos($parameters, '#')))
57       {
58         $fragment = substr($parameters, $pos + 1);
59         $parameters = substr($parameters, 0, $pos);
60       }
61
62       list($route, $parameters) = $this->convertUrlStringToParameters($parameters);
63     }
64     else if (is_array($parameters))
65     {
66       if (isset($parameters['sf_route']))
67       {
68         $route = $parameters['sf_route'];
69         unset($parameters['sf_route']);
70       }
71     }
72
73     // routing to generate path
74     $url = $this->context->getRouting()->generate($route, $parameters, $absolute);
75
76     if ($fragment)
77     {
78       $url .= '#'.$fragment;
79     }
80
81     return $url;
82   }
83
84   /**
85    * Converts an internal URI string to an array of parameters.
86    *
87    * @param string $url An internal URI
88    *
89    * @return array An array of parameters
90    */
91   public function convertUrlStringToParameters($url)
92   {
93     $givenUrl = $url;
94
95     $params = array();
96     $queryString = '';
97     $route = '';
98
99     // empty url?
100     if (!$url)
101     {
102       $url = '/';
103     }
104
105     // we get the query string out of the url
106     if ($pos = strpos($url, '?'))
107     {
108       $queryString = substr($url, $pos + 1);
109       $url = substr($url, 0, $pos);
110     }
111
112     // 2 url forms
113     // @routeName?key1=value1&key2=value2...
114     // module/action?key1=value1&key2=value2...
115
116     // first slash optional
117     if ($url[0] == '/')
118     {
119       $url = substr($url, 1);
120     }
121
122     // routeName?
123     if ($url[0] == '@')
124     {
125       $route = substr($url, 1);
126     }
127     else if (false !== strpos($url, '/'))
128     {
129       list($params['module'], $params['action']) = explode('/', $url);
130     }
131     else if (!$queryString)
132     {
133       $route = $givenUrl;
134     }
135     else
136     {
137       throw new InvalidArgumentException(sprintf('An internal URI must contain a module and an action (module/action) ("%s" given).', $givenUrl));
138     }
139
140     // split the query string
141     if ($queryString)
142     {
143       $matched = preg_match_all('/
144         ([^&=]+)            # key
145         =                   # =
146         (.*?)               # value
147         (?:
148           (?=&[^&=]+=) | $  # followed by another key= or the end of the string
149         )
150       /x', $queryString, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
151       foreach ($matches as $match)
152       {
153         $params[urldecode($match[1][0])] = urldecode($match[2][0]);
154       }
155
156       // check that all string is matched
157       if (!$matched)
158       {
159         throw new sfParseException(sprintf('Unable to parse query string "%s".', $queryString));
160       }
161     }
162
163     return array($route, $params);
164   }
165
166   /**
167    * Redirects the request to another URL.
168    *
169    * @param string $url        An associative array of URL parameters or an internal URI as a string
170    * @param int    $delay      A delay in seconds before redirecting. This is only needed on
171    *                           browsers that do not support HTTP headers
172    * @param int    $statusCode The status code
173    *
174    * @throws InvalidArgumentException If the url argument is null or an empty string
175    */
176   public function redirect($url, $delay = 0, $statusCode = 302)
177   {
178     if (empty($url))
179     {
180       throw new InvalidArgumentException('Cannot redirect to an empty URL.');
181     }
182
183     $url = $this->genUrl($url, true);
184     // see #8083
185     $url = str_replace('&amp;', '&', $url);
186
187     if (sfConfig::get('sf_logging_enabled'))
188     {
189       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Redirect to "%s"', $url))));
190     }
191
192     // redirect
193     $response = $this->context->getResponse();
194     $response->clearHttpHeaders();
195     $response->setStatusCode($statusCode);
196
197     // The Location header should only be used for status codes 201 and 3..
198     // For other code, only the refresh meta tag is used
199     if ($statusCode == 201 || ($statusCode >= 300 && $statusCode < 400))
200     {
201       $response->setHttpHeader('Location', $url);
202     }
203
204     $response->setContent(sprintf('<html><head><meta http-equiv="refresh" content="%d;url=%s"/></head></html>', $delay, htmlspecialchars($url, ENT_QUOTES, sfConfig::get('sf_charset'))));
205     $response->send();
206   }
207 }
208
Note: See TracBrowser for help on using the browser.