diff options
author | Nala Ginrut <nalaginrut@gmail.com> | 2014-06-19 15:18:13 +0800 |
---|---|---|
committer | Nala Ginrut <nalaginrut@gmail.com> | 2014-06-19 15:18:13 +0800 |
commit | bfd1db41367f7931016931a94cf1b67396481c79 (patch) | |
tree | 2d696f2d8eca9ed2e4561c61c16584952d9f7b0b /app/Core | |
parent | d0944e682d5a3491f72c5b566248b87fbaff032a (diff) | |
parent | efdc959c555872677e599d2ff12e1263d719f3f2 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'app/Core')
-rw-r--r-- | app/Core/Event.php | 38 | ||||
-rw-r--r-- | app/Core/Request.php | 24 | ||||
-rw-r--r-- | app/Core/Response.php | 24 | ||||
-rw-r--r-- | app/Core/Security.php | 87 | ||||
-rw-r--r-- | app/Core/Session.php | 23 | ||||
-rw-r--r-- | app/Core/Translator.php | 10 |
6 files changed, 190 insertions, 16 deletions
diff --git a/app/Core/Event.php b/app/Core/Event.php index 2c029b49..0e6df5e8 100644 --- a/app/Core/Event.php +++ b/app/Core/Event.php @@ -67,13 +67,16 @@ class Event */ public function trigger($eventName, array $data) { - $this->lastEvent = $eventName; - $this->events[] = $eventName; + if (! $this->isEventTriggered($eventName)) { - if (isset($this->listeners[$eventName])) { - foreach ($this->listeners[$eventName] as $listener) { - if ($listener->execute($data)) { - $this->lastListener = get_class($listener); + $this->lastEvent = $eventName; + $this->events[] = $eventName; + + if (isset($this->listeners[$eventName])) { + foreach ($this->listeners[$eventName] as $listener) { + if ($listener->execute($data)) { + $this->lastListener = get_class($listener); + } } } } @@ -113,6 +116,29 @@ class Event } /** + * Check if an event have been triggered + * + * @access public + * @param string $eventName Event name + * @return bool + */ + public function isEventTriggered($eventName) + { + return in_array($eventName, $this->events); + } + + /** + * Flush the list of triggered events + * + * @access public + */ + public function clearTriggeredEvents() + { + $this->events = array(); + $this->lastEvent = ''; + } + + /** * Check if a listener bind to an event * * @access public diff --git a/app/Core/Request.php b/app/Core/Request.php index 7e9f24ac..6bc738be 100644 --- a/app/Core/Request.php +++ b/app/Core/Request.php @@ -2,6 +2,8 @@ namespace Core; +use Core\Security; + /** * Request class * @@ -58,7 +60,12 @@ class Request public function getValues() { if (! empty($_POST)) { - return $_POST; + + if (Security::validateCSRFFormToken($_POST)) { + return $_POST; + } + + return array(); } $result = json_decode($this->getBody(), true); @@ -116,6 +123,19 @@ class Request */ public function isAjax() { - return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; + return $this->getHeader('X-Requested-With') === 'XMLHttpRequest'; + } + + /** + * Return a HTTP header value + * + * @access public + * @param string $name Header name + * @return string + */ + public function getHeader($name) + { + $name = 'HTTP_'.str_replace('-', '_', strtoupper($name)); + return isset($_SERVER[$name]) ? $_SERVER[$name] : ''; } } diff --git a/app/Core/Response.php b/app/Core/Response.php index 87d2fa4a..aee029af 100644 --- a/app/Core/Response.php +++ b/app/Core/Response.php @@ -11,6 +11,20 @@ namespace Core; class Response { /** + * Send no cache headers + * + * @access public + */ + public function nocache() + { + header('Pragma: no-cache'); + header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); + + // Use no-store due to a Chrome bug: https://code.google.com/p/chromium/issues/detail?id=28035 + header('Cache-Control: no-store, must-revalidate'); + } + + /** * Send a custom Content-Type header * * @access public @@ -66,7 +80,7 @@ class Response public function json(array $data, $status_code = 200) { $this->status($status_code); - + $this->nocache(); header('Content-Type: application/json'); echo json_encode($data); @@ -83,7 +97,7 @@ class Response public function text($data, $status_code = 200) { $this->status($status_code); - + $this->nocache(); header('Content-Type: text/plain; charset=utf-8'); echo $data; @@ -100,7 +114,7 @@ class Response public function html($data, $status_code = 200) { $this->status($status_code); - + $this->nocache(); header('Content-Type: text/html; charset=utf-8'); echo $data; @@ -117,7 +131,7 @@ class Response public function xml($data, $status_code = 200) { $this->status($status_code); - + $this->nocache(); header('Content-Type: text/xml; charset=utf-8'); echo $data; @@ -151,7 +165,7 @@ class Response public function binary($data, $status_code = 200) { $this->status($status_code); - + $this->nocache(); header('Content-Transfer-Encoding: binary'); header('Content-Type: application/octet-stream'); echo $data; diff --git a/app/Core/Security.php b/app/Core/Security.php new file mode 100644 index 00000000..0bd7c991 --- /dev/null +++ b/app/Core/Security.php @@ -0,0 +1,87 @@ +<?php + +namespace Core; + +/** + * Security class + * + * @package core + * @author Frederic Guillot + */ +class Security +{ + /** + * Generate a random token with different methods: openssl or /dev/urandom or fallback to uniqid() + * + * @static + * @access public + * @return string Random token + */ + public static function generateToken() + { + if (function_exists('openssl_random_pseudo_bytes')) { + return bin2hex(\openssl_random_pseudo_bytes(30)); + } + else if (ini_get('open_basedir') === '' && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { + return hash('sha256', file_get_contents('/dev/urandom', false, null, 0, 30)); + } + + return hash('sha256', uniqid(mt_rand(), true)); + } + + /** + * Generate and store a CSRF token in the current session + * + * @static + * @access public + * @return string Random token + */ + public static function getCSRFToken() + { + $nonce = self::generateToken(); + + if (empty($_SESSION['csrf_tokens'])) { + $_SESSION['csrf_tokens'] = array(); + } + + $_SESSION['csrf_tokens'][$nonce] = true; + + return $nonce; + } + + /** + * Check if the token exists for the current session (a token can be used only one time) + * + * @static + * @access public + * @param string $token CSRF token + * @return bool + */ + public static function validateCSRFToken($token) + { + if (isset($_SESSION['csrf_tokens'][$token])) { + unset($_SESSION['csrf_tokens'][$token]); + return true; + } + + return false; + } + + /** + * Check if the token used in a form is correct and then remove the value + * + * @static + * @access public + * @param array $values Form values + * @return bool + */ + public static function validateCSRFFormToken(array &$values) + { + if (! empty($values['csrf_token']) && self::validateCSRFToken($values['csrf_token'])) { + unset($values['csrf_token']); + return true; + } + + return false; + } +} diff --git a/app/Core/Session.php b/app/Core/Session.php index 6ce1bd40..af7a9123 100644 --- a/app/Core/Session.php +++ b/app/Core/Session.php @@ -15,7 +15,7 @@ class Session * * @var integer */ - const SESSION_LIFETIME = 86400; // 1 day + const SESSION_LIFETIME = 7200; // 2 hours /** * Open a session @@ -35,7 +35,7 @@ class Session self::SESSION_LIFETIME, $base_path ?: '/', null, - isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', + ! empty($_SERVER['HTTPS']), true ); @@ -66,6 +66,25 @@ class Session */ public function close() { + // Flush all sessions variables + $_SESSION = array(); + + // Destroy the session cookie + if (ini_get('session.use_cookies')) { + $params = session_get_cookie_params(); + + setcookie( + session_name(), + '', + time() - 42000, + $params['path'], + $params['domain'], + $params['secure'], + $params['httponly'] + ); + } + + // Destroy session data session_destroy(); } diff --git a/app/Core/Translator.php b/app/Core/Translator.php index 015a76cb..d9386d3a 100644 --- a/app/Core/Translator.php +++ b/app/Core/Translator.php @@ -114,7 +114,15 @@ class Translator return ''; } - return strftime($this->get($format, $format), (int) $timestamp); + $format = $this->get($format, $format); + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $format = str_replace('%e', '%d', $format); + $format = str_replace('%G', '%Y', $format); + $format = str_replace('%k', '%H', $format); + } + + return strftime($format, (int) $timestamp); } /** |