3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Validator
;
14 use Zend\Session\Container
as SessionContainer
;
15 use Zend\Stdlib\ArrayUtils
;
17 class Csrf
extends AbstractValidator
23 const NOT_SAME
= 'notSame';
29 protected $messageTemplates = array(
30 self
::NOT_SAME
=> "The form submitted did not originate from the expected site",
41 * Static cache of the session names to generated hashes
45 protected static $hashCache;
48 * Name of CSRF element (used to create non-colliding hashes)
52 protected $name = 'csrf';
58 protected $salt = 'salt';
61 * @var SessionContainer
69 protected $timeout = 300;
74 * @param array|Traversable $options
76 public function __construct($options = array())
78 parent
::__construct($options);
80 if ($options instanceof Traversable
) {
81 $options = ArrayUtils
::iteratorToArray($options);
84 if (!is_array($options)) {
85 $options = (array) $options;
88 foreach ($options as $key => $value) {
89 switch (strtolower($key)) {
91 $this->setName($value);
94 $this->setSalt($value);
97 $this->setSession($value);
100 $this->setTimeout($value);
103 // ignore unknown options
110 * Does the provided token match the one generated?
112 * @param string $value
113 * @param mixed $context
116 public function isValid($value, $context = null)
118 $this->setValue((string) $value);
120 $hash = $this->getValidationToken();
122 if ($value !== $hash) {
123 $this->error(self
::NOT_SAME
);
133 * @param string $name
136 public function setName($name)
138 $this->name
= (string) $name;
147 public function getName()
153 * Set session container
155 * @param SessionContainer $session
158 public function setSession(SessionContainer
$session)
160 $this->session
= $session;
162 $this->initCsrfToken();
168 * Get session container
170 * Instantiate session container if none currently exists
172 * @return SessionContainer
174 public function getSession()
176 if (null === $this->session
) {
177 // Using fully qualified name, to ensure polyfill class alias is used
178 $this->session
= new SessionContainer($this->getSessionName());
180 return $this->session
;
184 * Salt for CSRF token
186 * @param string $salt
189 public function setSalt($salt)
191 $this->salt
= (string) $salt;
196 * Retrieve salt for CSRF token
200 public function getSalt()
206 * Retrieve CSRF token
208 * If no CSRF token currently exists, or should be regenerated,
211 * @param bool $regenerate default false
214 public function getHash($regenerate = false)
216 if ((null === $this->hash
) ||
$regenerate) {
220 $this->hash
= $this->getValidationToken();
222 if (null === $this->hash
) {
223 $this->generateHash();
230 * Get session namespace for CSRF token
232 * Generates a session namespace based on salt, element name, and class.
236 public function getSessionName()
238 return str_replace('\\', '_', __CLASS__
) . '_'
239 . $this->getSalt() . '_'
240 . strtr($this->getName(), array('[' => '_', ']' => ''));
244 * Set timeout for CSRF session token
246 * @param int|null $ttl
249 public function setTimeout($ttl)
251 $this->timeout
= ($ttl !== null) ?
(int) $ttl : null;
256 * Get CSRF session token timeout
260 public function getTimeout()
262 return $this->timeout
;
266 * Initialize CSRF token in session
270 protected function initCsrfToken()
272 $session = $this->getSession();
273 //$session->setExpirationHops(1, null);
274 $timeout = $this->getTimeout();
275 if (null !== $timeout) {
276 $session->setExpirationSeconds($timeout);
278 $session->hash
= $this->getHash();
282 * Generate CSRF token
284 * Generates CSRF token and stores both in {@link $hash} and element
289 protected function generateHash()
291 if (isset(static::$hashCache[$this->getSessionName()])) {
292 $this->hash
= static::$hashCache[$this->getSessionName()];
294 $this->hash
= md5($this->getSalt() . Rand
::getBytes(32) . $this->getName());
295 static::$hashCache[$this->getSessionName()] = $this->hash
;
297 $this->setValue($this->hash
);
298 $this->initCsrfToken();
302 * Get validation token
304 * Retrieve token from session, if it exists.
306 * @return null|string
308 protected function getValidationToken()
310 $session = $this->getSession();
311 if (isset($session->hash
)) {
312 return $session->hash
;