Upgrade CakePHP from 2.2.5 to 2.9.5

This commit is contained in:
Brm Ko 2017-02-26 15:29:44 +01:00
parent 5a580df460
commit 235a541597
793 changed files with 60746 additions and 23753 deletions

View file

@ -4,19 +4,18 @@
*
* Controller used by ErrorHandler to render error views.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AppController', 'Controller');
@ -30,13 +29,6 @@ App::uses('AppController', 'Controller');
*/
class CakeErrorController extends AppController {
/**
* Controller name
*
* @var string
*/
public $name = 'CakeError';
/**
* Uses Property
*
@ -45,10 +37,10 @@ class CakeErrorController extends AppController {
public $uses = array();
/**
* __construct
* Constructor
*
* @param CakeRequest $request
* @param CakeResponse $response
* @param CakeRequest $request Request instance.
* @param CakeResponse $response Response instance.
*/
public function __construct($request = null, $response = null) {
parent::__construct($request, $response);
@ -67,18 +59,4 @@ class CakeErrorController extends AppController {
$this->_set(array('cacheAction' => false, 'viewPath' => 'Errors'));
}
/**
* Escapes the viewVars.
*
* @return void
*/
public function beforeRender() {
parent::beforeRender();
foreach ($this->viewVars as $key => $value) {
if (!is_object($value)) {
$this->viewVars[$key] = h($value);
}
}
}
}

View file

@ -1,31 +1,30 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller
* @since CakePHP(tm) v 1.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('ComponentCollection', 'Controller');
/**
* Base class for an individual Component. Components provide reusable bits of
* controller logic that can be composed into a controller. Components also
* Base class for an individual Component. Components provide reusable bits of
* controller logic that can be composed into a controller. Components also
* provide request life-cycle callbacks for injecting logic at specific points.
*
* ## Life cycle callbacks
*
* Components can provide several callbacks that are fired at various stages of the request
* cycle. The available callbacks are:
* cycle. The available callbacks are:
*
* - `initialize()` - Fired before the controller's beforeFilter method.
* - `startup()` - Fired after the controller's beforeFilter method.
@ -38,7 +37,7 @@ App::uses('ComponentCollection', 'Controller');
* @link http://book.cakephp.org/2.0/en/controllers/components.html
* @see Controller::$components
*/
class Component extends Object {
class Component extends CakeObject {
/**
* Component collection class used to lazy load components.
@ -91,7 +90,7 @@ class Component extends Object {
*/
public function __get($name) {
if (isset($this->_componentMap[$name]) && !isset($this->{$name})) {
$settings = array_merge((array)$this->_componentMap[$name]['settings'], array('enabled' => false));
$settings = (array)$this->_componentMap[$name]['settings'] + array('enabled' => false);
$this->{$name} = $this->_Collection->load($this->_componentMap[$name]['class'], $settings);
}
if (isset($this->{$name})) {
@ -135,29 +134,29 @@ class Component extends Object {
*
* @param Controller $controller Controller with components to shutdown
* @return void
* @link @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::shutdown
* @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::shutdown
*/
public function shutdown(Controller $controller) {
}
/**
* Called before Controller::redirect(). Allows you to replace the url that will
* be redirected to with a new url. The return of this method can either be an array or a string.
* Called before Controller::redirect(). Allows you to replace the URL that will
* be redirected to with a new URL. The return of this method can either be an array or a string.
*
* If the return is an array and contains a 'url' key. You may also supply the following:
* If the return is an array and contains a 'url' key. You may also supply the following:
*
* - `status` The status code for the redirect
* - `exit` Whether or not the redirect should exit.
*
* If your response is a string or an array that does not contain a 'url' key it will
* be used as the new url to redirect to.
* be used as the new URL to redirect to.
*
* @param Controller $controller Controller with components to beforeRedirect
* @param string|array $url Either the string or url array that is being redirected to.
* @param integer $status The status code of the redirect
* @param boolean $exit Will the script exit.
* @param string|array $url Either the string or URL array that is being redirected to.
* @param int $status The status code of the redirect
* @param bool $exit Will the script exit.
* @return array|null Either an array or null.
* @link @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::beforeRedirect
* @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::beforeRedirect
*/
public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
}

View file

@ -1,16 +1,17 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component.Acl
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
@ -27,6 +28,7 @@ interface AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return bool Success
*/
public function check($aro, $aco, $action = "*");
@ -36,7 +38,7 @@ interface AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function allow($aro, $aco, $action = "*");
@ -46,7 +48,7 @@ interface AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function deny($aro, $aco, $action = "*");
@ -56,14 +58,15 @@ interface AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function inherit($aro, $aco, $action = "*");
/**
* Initialization method for the Acl implementation
*
* @param AclComponent $component
* @param Component $component The AclComponent instance.
* @return void
*/
public function initialize(Component $component);

View file

@ -1,23 +1,26 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component.Acl
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AclInterface', 'Controller/Component/Acl');
App::uses('Hash', 'Utility');
App::uses('ClassRegistry', 'Utility');
/**
* DbAcl implements an ACL control system in the database. ARO's and ACO's are
* structured into trees and a linking table is used to define permissions. You
* DbAcl implements an ACL control system in the database. ARO's and ACO's are
* structured into trees and a linking table is used to define permissions. You
* can install the schema for DbAcl with the Schema Shell.
*
* `$aco` and `$aro` parameters can be slash delimited paths to tree nodes.
@ -26,19 +29,18 @@ App::uses('Hash', 'Utility');
*
* Would point to a tree structure like
*
* {{{
* ```
* controllers
* Users
* edit
* }}}
* ```
*
* @package Cake.Controller.Component.Acl
*/
class DbAcl extends Object implements AclInterface {
class DbAcl extends CakeObject implements AclInterface {
/**
* Constructor
*
*/
public function __construct() {
parent::__construct();
@ -50,7 +52,7 @@ class DbAcl extends Object implements AclInterface {
/**
* Initializes the containing component and sets the Aro/Aco objects to it.
*
* @param AclComponent $component
* @param AclComponent $component The AclComponent instance.
* @return void
*/
public function initialize(Component $component) {
@ -64,7 +66,7 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success (true if ARO has access to action in ACO, false otherwise)
* @return bool Success (true if ARO has access to action in ACO, false otherwise)
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
*/
public function check($aro, $aco, $action = "*") {
@ -77,8 +79,8 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $actions Action (defaults to *)
* @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
* @return boolean Success
* @param int $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
* @return bool Success
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
*/
public function allow($aro, $aco, $actions = "*", $value = 1) {
@ -91,7 +93,7 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
*/
public function deny($aro, $aco, $action = "*") {
@ -104,7 +106,7 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function inherit($aro, $aco, $action = "*") {
return $this->allow($aro, $aco, $action, 0);
@ -116,7 +118,7 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
* @see allow()
*/
public function grant($aro, $aco, $action = "*") {
@ -129,7 +131,7 @@ class DbAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
* @see deny()
*/
public function revoke($aro, $aco, $action = "*") {

View file

@ -1,26 +1,28 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component.Acl
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AclInterface', 'Controller/Component/Acl');
/**
* IniAcl implements an access control system using an INI file. An example
* IniAcl implements an access control system using an INI file. An example
* of the ini file used can be found in /config/acl.ini.php.
*
* @package Cake.Controller.Component.Acl
*/
class IniAcl extends Object implements AclInterface {
class IniAcl extends CakeObject implements AclInterface {
/**
* Array with configuration, parsed from ini file
@ -31,7 +33,7 @@ class IniAcl extends Object implements AclInterface {
/**
* The Hash::extract() path to the user/aro identifier in the
* acl.ini file. This path will be used to extract the string
* acl.ini file. This path will be used to extract the string
* representation of a user used in the ini file.
*
* @var string
@ -41,7 +43,7 @@ class IniAcl extends Object implements AclInterface {
/**
* Initialize method
*
* @param AclBase $component
* @param Component $component The AclComponent instance.
* @return void
*/
public function initialize(Component $component) {
@ -53,7 +55,7 @@ class IniAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function allow($aro, $aco, $action = "*") {
}
@ -64,7 +66,7 @@ class IniAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function deny($aro, $aco, $action = "*") {
}
@ -75,7 +77,7 @@ class IniAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function inherit($aro, $aco, $action = "*") {
}
@ -88,10 +90,10 @@ class IniAcl extends Object implements AclInterface {
* @param string $aro ARO
* @param string $aco ACO
* @param string $action Action
* @return boolean Success
* @return bool Success
*/
public function check($aro, $aco, $action = null) {
if ($this->config == null) {
if (!$this->config) {
$this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
}
$aclConfig = $this->config;

View file

@ -2,19 +2,18 @@
/**
* PHP configuration based AclInterface implementation
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component.Acl
* @since CakePHP(tm) v 2.1
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
@ -23,9 +22,20 @@
*
* @package Cake.Controller.Component.Acl
*/
class PhpAcl extends Object implements AclInterface {
class PhpAcl extends CakeObject implements AclInterface {
/**
* Constant for deny
*
* @var bool
*/
const DENY = false;
/**
* Constant for allow
*
* @var bool
*/
const ALLOW = true;
/**
@ -58,7 +68,7 @@ class PhpAcl extends Object implements AclInterface {
*/
public function __construct() {
$this->options = array(
'policy' => self::DENY,
'policy' => static::DENY,
'config' => APP . 'Config' . DS . 'acl.php',
);
}
@ -71,7 +81,7 @@ class PhpAcl extends Object implements AclInterface {
*/
public function initialize(Component $Component) {
if (!empty($Component->settings['adapter'])) {
$this->options = array_merge($this->options, $Component->settings['adapter']);
$this->options = $Component->settings['adapter'] + $this->options;
}
App::uses('PhpReader', 'Configure');
@ -91,11 +101,11 @@ class PhpAcl extends Object implements AclInterface {
*/
public function build(array $config) {
if (empty($config['roles'])) {
throw new AclException(__d('cake_dev','"roles" section not found in configuration.'));
throw new AclException(__d('cake_dev', '"roles" section not found in configuration.'));
}
if (empty($config['rules']['allow']) && empty($config['rules']['deny'])) {
throw new AclException(__d('cake_dev','Neither "allow" nor "deny" rules were provided in configuration.'));
throw new AclException(__d('cake_dev', 'Neither "allow" nor "deny" rules were provided in configuration.'));
}
$rules['allow'] = !empty($config['rules']['allow']) ? $config['rules']['allow'] : array();
@ -114,7 +124,7 @@ class PhpAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function allow($aro, $aco, $action = "*") {
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'allow');
@ -126,7 +136,7 @@ class PhpAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function deny($aro, $aco, $action = "*") {
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'deny');
@ -138,7 +148,7 @@ class PhpAcl extends Object implements AclInterface {
* @param string $aro ARO The requesting object identifier.
* @param string $aco ACO The controlled object identifier.
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function inherit($aro, $aco, $action = "*") {
return false;
@ -151,13 +161,13 @@ class PhpAcl extends Object implements AclInterface {
* @param string $aro ARO
* @param string $aco ACO
* @param string $action Action
* @return boolean true if access is granted, false otherwise
* @return bool true if access is granted, false otherwise
*/
public function check($aro, $aco, $action = "*") {
$allow = $this->options['policy'];
$prioritizedAros = $this->Aro->roles($aro);
if ($action && $action != "*") {
if ($action && $action !== "*") {
$aco .= '/' . $action;
}
@ -167,14 +177,14 @@ class PhpAcl extends Object implements AclInterface {
return $allow;
}
foreach ($path as $depth => $node) {
foreach ($path as $node) {
foreach ($prioritizedAros as $aros) {
if (!empty($node['allow'])) {
$allow = $allow || count(array_intersect($node['allow'], $aros)) > 0;
$allow = $allow || count(array_intersect($node['allow'], $aros));
}
if (!empty($node['deny'])) {
$allow = $allow && count(array_intersect($node['deny'], $aros)) == 0;
$allow = $allow && !count(array_intersect($node['deny'], $aros));
}
}
}
@ -186,7 +196,6 @@ class PhpAcl extends Object implements AclInterface {
/**
* Access Control Object
*
*/
class PhpAco {
@ -206,6 +215,11 @@ class PhpAco {
'*' => '.*',
);
/**
* Constructor
*
* @param array $rules Rules array
*/
public function __construct(array $rules = array()) {
foreach (array('allow', 'deny') as $type) {
if (empty($rules[$type])) {
@ -219,6 +233,7 @@ class PhpAco {
/**
* return path to the requested ACO with allow and deny rules attached on each level
*
* @param string $aco ACO string
* @return array
*/
public function path($aco) {
@ -236,7 +251,7 @@ class PhpAco {
}
foreach ($root as $node => $elements) {
$pattern = '/^' . str_replace(array_keys(self::$modifiers), array_values(self::$modifiers), $node) . '$/';
$pattern = '/^' . str_replace(array_keys(static::$modifiers), array_values(static::$modifiers), $node) . '$/';
if ($node == $aco[$level] || preg_match($pattern, $aco[$level])) {
// merge allow/denies with $path of current level
@ -263,6 +278,10 @@ class PhpAco {
/**
* allow/deny ARO access to ARO
*
* @param string $aro ARO string
* @param string $aco ACO string
* @param string $action Action string
* @param string $type access type
* @return void
*/
public function access($aro, $aco, $action, $type = 'deny') {
@ -273,7 +292,7 @@ class PhpAco {
foreach ($aco as $i => $node) {
if (!isset($tree[$node])) {
$tree[$node] = array(
$tree[$node] = array(
'children' => array(),
);
}
@ -303,7 +322,7 @@ class PhpAco {
return array_map('strtolower', $aco);
}
// strip multiple occurences of '/'
// strip multiple occurrences of '/'
$aco = preg_replace('#/+#', '/', $aco);
// make case insensitive
$aco = ltrim(strtolower($aco), '/');
@ -319,7 +338,6 @@ class PhpAco {
*/
public function build(array $allow, array $deny = array()) {
$this->_tree = array();
$tree = array();
foreach ($allow as $dotPath => $aros) {
if (is_string($aros)) {
@ -342,7 +360,6 @@ class PhpAco {
/**
* Access Request Object
*
*/
class PhpAro {
@ -385,6 +402,13 @@ class PhpAro {
*/
protected $_tree = array();
/**
* Constructor
*
* @param array $aro The aro data
* @param array $map The identifier mappings
* @param array $aliases The aliases to map.
*/
public function __construct(array $aro = array(), array $map = array(), array $aliases = array()) {
if (!empty($map)) {
$this->map = $map;
@ -436,7 +460,7 @@ class PhpAro {
$mapped = '';
if (is_array($aro)) {
if (isset($aro['model']) && isset($aro['foreign_key']) && $aro['model'] == $aroGroup) {
if (isset($aro['model']) && isset($aro['foreign_key']) && $aro['model'] === $aroGroup) {
$mapped = $aroGroup . '/' . $aro['foreign_key'];
} elseif (isset($aro[$model][$field])) {
$mapped = $aroGroup . '/' . $aro[$model][$field];
@ -453,7 +477,7 @@ class PhpAro {
$aroModel = Inflector::camelize($aroModel);
if ($aroModel == $model || $aroModel == $aroGroup) {
if ($aroModel === $model || $aroModel === $aroGroup) {
$mapped = $aroGroup . '/' . $aroValue;
}
}
@ -468,7 +492,7 @@ class PhpAro {
return $this->aliases[$mapped];
}
}
return self::DEFAULT_ROLE;
return static::DEFAULT_ROLE;
}
/**
@ -519,8 +543,8 @@ class PhpAro {
* @param array $alias alias from => to (e.g. Role/13 -> Role/editor)
* @return void
*/
public function addAlias(array $alias) {
$this->aliases = array_merge($this->aliases, $alias);
public function addAlias(array $alias) {
$this->aliases = $alias + $this->aliases;
}
/**

View file

@ -1,17 +1,19 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
App::uses('AclInterface', 'Controller/Component/Acl');
@ -19,8 +21,8 @@ App::uses('AclInterface', 'Controller/Component/Acl');
* Access Control List factory class.
*
* Uses a strategy pattern to allow custom ACL implementations to be used with the same component interface.
* You can define by changing `Configure::write('Acl.classname', 'DbAcl');` in your core.php. Concrete ACL
* implementations should extend `AclBase` and implement the methods it defines.
* You can define by changing `Configure::write('Acl.classname', 'DbAcl');` in your core.php. The adapter
* you specify must implement `AclInterface`
*
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html
@ -51,8 +53,8 @@ class AclComponent extends Component {
/**
* Constructor. Will return an instance of the correct ACL class as defined in `Configure::read('Acl.classname')`
*
* @param ComponentCollection $collection
* @param array $settings
* @param ComponentCollection $collection Collection instance.
* @param array $settings Settings list.
* @throws CakeException when Acl.classname could not be loaded.
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
@ -77,7 +79,7 @@ class AclComponent extends Component {
* Will call the initialize method on the adapter if setting a new one.
*
* @param AclInterface|string $adapter Instance of AclInterface or a string name of the class to use. (optional)
* @return AclInterface|void either null, or the adapter implementation.
* @return AclInterface|null Either null, or the adapter implementation.
* @throws CakeException when the given class is not an instance of AclInterface
*/
public function adapter($adapter = null) {
@ -90,19 +92,19 @@ class AclComponent extends Component {
}
$this->_Instance = $adapter;
$this->_Instance->initialize($this);
return;
return null;
}
return $this->_Instance;
}
/**
* Pass-thru function for ACL check instance. Check methods
* Pass-thru function for ACL check instance. Check methods
* are used to check whether or not an ARO can access an ACO
*
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function check($aro, $aco, $action = "*") {
return $this->_Instance->check($aro, $aco, $action);
@ -115,7 +117,7 @@ class AclComponent extends Component {
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function allow($aro, $aco, $action = "*") {
return $this->_Instance->allow($aro, $aco, $action);
@ -128,7 +130,7 @@ class AclComponent extends Component {
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function deny($aro, $aco, $action = "*") {
return $this->_Instance->deny($aro, $aco, $action);
@ -141,7 +143,7 @@ class AclComponent extends Component {
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @return bool Success
*/
public function inherit($aro, $aco, $action = "*") {
return $this->_Instance->inherit($aro, $aco, $action);
@ -153,11 +155,11 @@ class AclComponent extends Component {
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @deprecated
* @return bool Success
* @deprecated 3.0.0 Will be removed in 3.0.
*/
public function grant($aro, $aco, $action = "*") {
trigger_error(__d('cake_dev', 'AclComponent::grant() is deprecated, use allow() instead'), E_USER_WARNING);
trigger_error(__d('cake_dev', '%s is deprecated, use %s instead', 'AclComponent::grant()', 'allow()'), E_USER_WARNING);
return $this->_Instance->allow($aro, $aco, $action);
}
@ -167,11 +169,11 @@ class AclComponent extends Component {
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
* @param string $action Action (defaults to *)
* @return boolean Success
* @deprecated
* @return bool Success
* @deprecated 3.0.0 Will be removed in 3.0.
*/
public function revoke($aro, $aco, $action = "*") {
trigger_error(__d('cake_dev', 'AclComponent::revoke() is deprecated, use deny() instead'), E_USER_WARNING);
trigger_error(__d('cake_dev', '%s is deprecated, use %s instead', 'AclComponent::revoke()', 'deny()'), E_USER_WARNING);
return $this->_Instance->deny($aro, $aco, $action);
}

View file

@ -0,0 +1,72 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.4.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Abstract password hashing class
*
* @package Cake.Controller.Component.Auth
*/
abstract class AbstractPasswordHasher {
/**
* Configurations for this object. Settings passed from authenticator class to
* the constructor are merged with this property.
*
* @var array
*/
protected $_config = array();
/**
* Constructor
*
* @param array $config Array of config.
*/
public function __construct($config = array()) {
$this->config($config);
}
/**
* Get/Set the config
*
* @param array $config Sets config, if null returns existing config
* @return array Returns configs
*/
public function config($config = null) {
if (is_array($config)) {
$this->_config = array_merge($this->_config, $config);
}
return $this->_config;
}
/**
* Generates password hash.
*
* @param string|array $password Plain text password to hash or array of data
* required to generate password hash.
* @return string Password hash
*/
abstract public function hash($password);
/**
* Check hash. Generate hash from user provided password string or data array
* and check against existing hash.
*
* @param string|array $password Plain text password to hash or data array.
* @param string $hashedPassword Existing hashed password.
* @return bool True if hashes match else false.
*/
abstract public function check($password, $hashedPassword);
}

View file

@ -1,22 +1,21 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthorize', 'Controller/Component/Auth');
/**
* An authorization adapter for AuthComponent. Provides the ability to authorize using the AclComponent,
* An authorization adapter for AuthComponent. Provides the ability to authorize using the AclComponent,
* If AclComponent is not already loaded it will be loaded using the Controller's ComponentCollection.
*
* @package Cake.Controller.Component.Auth
@ -31,7 +30,7 @@ class ActionsAuthorize extends BaseAuthorize {
*
* @param array $user The user to authorize
* @param CakeRequest $request The request needing authorization.
* @return boolean
* @return bool
*/
public function authorize($user, CakeRequest $request) {
$Acl = $this->_Collection->load('Acl');

View file

@ -1,36 +1,41 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Security', 'Utility');
App::uses('Hash', 'Utility');
App::uses('CakeEventListener', 'Event');
/**
* Base Authentication class with common methods and properties.
*
* @package Cake.Controller.Component.Auth
*/
abstract class BaseAuthenticate {
abstract class BaseAuthenticate implements CakeEventListener {
/**
* Settings for this object.
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `userFields` Array of fields to retrieve from User model, null to retrieve all. Defaults to null.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
* - `contain` Extra models to contain and store in session.
* - `passwordHasher` Password hasher class. Can be a string specifying class name
* or an array containing `className` key, any other keys will be passed as
* settings to the class. Defaults to 'Simple'.
*
* @var array
*/
@ -40,9 +45,11 @@ abstract class BaseAuthenticate {
'password' => 'password'
),
'userModel' => 'User',
'userFields' => null,
'scope' => array(),
'recursive' => 0,
'contain' => null,
'passwordHasher' => 'Simple'
);
/**
@ -52,6 +59,22 @@ abstract class BaseAuthenticate {
*/
protected $_Collection;
/**
* Password hasher instance.
*
* @var AbstractPasswordHasher
*/
protected $_passwordHasher;
/**
* Implemented events
*
* @return array of events => callbacks.
*/
public function implementedEvents() {
return array();
}
/**
* Constructor
*
@ -66,42 +89,102 @@ abstract class BaseAuthenticate {
/**
* Find a user record using the standard options.
*
* @param string $username The username/identifier.
* @param string $password The unhashed password.
* @return Mixed Either false on failure, or an array of user data.
* The $username parameter can be a (string)username or an array containing
* conditions for Model::find('first'). If the $password param is not provided
* the password field will be present in returned array.
*
* Input passwords will be hashed even when a user doesn't exist. This
* helps mitigate timing attacks that are attempting to find valid usernames.
*
* @param string|array $username The username/identifier, or an array of find conditions.
* @param string $password The password, only used if $username param is string.
* @return bool|array Either false on failure, or an array of user data.
*/
protected function _findUser($username, $password) {
protected function _findUser($username, $password = null) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
list(, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
$conditions = array(
$model . '.' . $fields['username'] => $username,
$model . '.' . $fields['password'] => $this->_password($password),
);
if (is_array($username)) {
$conditions = $username;
} else {
$conditions = array(
$model . '.' . $fields['username'] => $username
);
}
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
$userFields = $this->settings['userFields'];
if ($password !== null && $userFields !== null) {
$userFields[] = $model . '.' . $fields['password'];
}
$result = ClassRegistry::init($userModel)->find('first', array(
'conditions' => $conditions,
'recursive' => $this->settings['recursive'],
'fields' => $userFields,
'contain' => $this->settings['contain'],
));
if (empty($result) || empty($result[$model])) {
if (empty($result[$model])) {
$this->passwordHasher()->hash($password);
return false;
}
$user = $result[$model];
unset($user[$fields['password']]);
if ($password !== null) {
if (!$this->passwordHasher()->check($password, $user[$fields['password']])) {
return false;
}
unset($user[$fields['password']]);
}
unset($result[$model]);
return array_merge($user, $result);
}
/**
* Return password hasher object
*
* @return AbstractPasswordHasher Password hasher instance
* @throws CakeException If password hasher class not found or
* it does not extend AbstractPasswordHasher
*/
public function passwordHasher() {
if ($this->_passwordHasher) {
return $this->_passwordHasher;
}
$config = array();
if (is_string($this->settings['passwordHasher'])) {
$class = $this->settings['passwordHasher'];
} else {
$class = $this->settings['passwordHasher']['className'];
$config = $this->settings['passwordHasher'];
unset($config['className']);
}
list($plugin, $class) = pluginSplit($class, true);
$className = $class . 'PasswordHasher';
App::uses($className, $plugin . 'Controller/Component/Auth');
if (!class_exists($className)) {
throw new CakeException(__d('cake_dev', 'Password hasher class "%s" was not found.', $class));
}
if (!is_subclass_of($className, 'AbstractPasswordHasher')) {
throw new CakeException(__d('cake_dev', 'Password hasher must extend AbstractPasswordHasher class.'));
}
$this->_passwordHasher = new $className($config);
return $this->_passwordHasher;
}
/**
* Hash the plain text password so that it matches the hashed/encrypted password
* in the datasource.
*
* @param string $password The plain text password.
* @return string The hashed form of the password.
* @deprecated 3.0.0 Since 2.4. Use a PasswordHasher class instead.
*/
protected function _password($password) {
return Security::hash($password, null, true);
@ -130,14 +213,25 @@ abstract class BaseAuthenticate {
}
/**
* Get a user based on information in the request. Primarily used by stateless authentication
* Get a user based on information in the request. Primarily used by stateless authentication
* systems like basic and digest auth.
*
* @param CakeRequest $request Request object.
* @return mixed Either false or an array of user information
*/
public function getUser($request) {
public function getUser(CakeRequest $request) {
return false;
}
/**
* Handle unauthenticated access attempt.
*
* @param CakeRequest $request A request object.
* @param CakeResponse $response A response object.
* @return mixed Either true to indicate the unauthenticated request has been
* dealt with and no more action is required by AuthComponent or void (default).
*/
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
}
}

View file

@ -1,17 +1,17 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Hash', 'Utility');
/**
@ -40,10 +40,10 @@ abstract class BaseAuthorize {
/**
* Settings for authorize objects.
*
* - `actionPath` - The path to ACO nodes that contains the nodes for controllers. Used as a prefix
* - `actionPath` - The path to ACO nodes that contains the nodes for controllers. Used as a prefix
* when calling $this->action();
* - `actionMap` - Action -> crud mappings. Used by authorization objects that want to map actions to CRUD roles.
* - `userModel` - Model name that ARO records can be found under. Defaults to 'User'.
* - `userModel` - Model name that ARO records can be found under. Defaults to 'User'.
*
* @var array
*/
@ -64,7 +64,7 @@ abstract class BaseAuthorize {
* Constructor
*
* @param ComponentCollection $collection The controller for this request.
* @param string $settings An array of settings. This class does not use any settings.
* @param string $settings An array of settings. This class does not use any settings.
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
$this->_Collection = $collection;
@ -77,8 +77,8 @@ abstract class BaseAuthorize {
* Checks user authorization.
*
* @param array $user Active user data
* @param CakeRequest $request
* @return boolean
* @param CakeRequest $request Request instance.
* @return bool
*/
abstract public function authorize($user, CakeRequest $request);
@ -101,14 +101,14 @@ abstract class BaseAuthorize {
}
/**
* Get the action path for a given request. Primarily used by authorize objects
* Get the action path for a given request. Primarily used by authorize objects
* that need to get information about the plugin, controller, and action being invoked.
*
* @param CakeRequest $request The request a path is needed for.
* @param string $path
* @param string $path Path format.
* @return string the action path for the given request.
*/
public function action($request, $path = '/:plugin/:controller/:action') {
public function action(CakeRequest $request, $path = '/:plugin/:controller/:action') {
$plugin = empty($request['plugin']) ? null : Inflector::camelize($request['plugin']) . '/';
$path = str_replace(
array(':controller', ':action', ':plugin/'),
@ -120,24 +120,31 @@ abstract class BaseAuthorize {
}
/**
* Maps crud actions to actual action names. Used to modify or get the current mapped actions.
* Maps crud actions to actual action names. Used to modify or get the current mapped actions.
*
* Create additional mappings for a standard CRUD operation:
*
* {{{
* ```
* $this->Auth->mapActions(array('create' => array('add', 'register'));
* }}}
* ```
*
* Or equivalently:
*
* ```
* $this->Auth->mapActions(array('register' => 'create', 'add' => 'create'));
* ```
*
* Create mappings for custom CRUD operations:
*
* {{{
* $this->Auth->mapActions(array('my_action' => 'admin'));
* }}}
* ```
* $this->Auth->mapActions(array('range' => 'search'));
* ```
*
* You can use the custom CRUD operations to create additional generic permissions
* that behave like CRUD operations. Doing this will require additional columns on the
* permissions lookup. When using with DbAcl, you'll have to add additional _admin type columns
* to the `aros_acos` table.
* that behave like CRUD operations. Doing this will require additional columns on the
* permissions lookup. For example if one wanted an additional search CRUD operation
* one would create and additional column '_search' in the aros_acos table. One could
* create a custom admin CRUD operation for administration functions similarly if needed.
*
* @param array $map Either an array of mappings, or undefined to get current values.
* @return mixed Either the current mappings or null when setting.
@ -147,9 +154,8 @@ abstract class BaseAuthorize {
if (empty($map)) {
return $this->settings['actionMap'];
}
$crud = array('create', 'read', 'update', 'delete');
foreach ($map as $action => $type) {
if (in_array($action, $crud) && is_array($type)) {
if (is_array($type)) {
foreach ($type as $typedAction) {
$this->settings['actionMap'][$typedAction] = $action;
}

View file

@ -1,16 +1,15 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
@ -18,55 +17,39 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
/**
* Basic Authentication adapter for AuthComponent.
*
* Provides Basic HTTP authentication support for AuthComponent. Basic Auth will authenticate users
* against the configured userModel and verify the username and passwords match. Clients using Basic Authentication
* must support cookies. Since AuthComponent identifies users based on Session contents, clients using Basic
* Auth must support cookies.
* Provides Basic HTTP authentication support for AuthComponent. Basic Auth will
* authenticate users against the configured userModel and verify the username
* and passwords match.
*
* ### Using Basic auth
*
* In your controller's components array, add auth + the required settings.
* {{{
* ```
* public $components = array(
* 'Auth' => array(
* 'authenticate' => array('Basic')
* )
* );
* }}}
* ```
*
* In your login function just call `$this->Auth->login()` without any checks for POST data. This
* will send the authentication headers, and trigger the login dialog in the browser/client.
* You should also set `AuthComponent::$sessionKey = false;` in your AppController's
* beforeFilter() to prevent CakePHP from sending a session cookie to the client.
*
* Since HTTP Basic Authentication is stateless you don't need a login() action
* in your controller. The user credentials will be checked on each request. If
* valid credentials are not provided, required authentication headers will be sent
* by this authentication provider which triggers the login dialog in the browser/client.
*
* You may also want to use `$this->Auth->unauthorizedRedirect = false;`.
* By default, unauthorized users are redirected to the referrer URL,
* `AuthComponent::$loginAction`, or '/'. If unauthorizedRedirect is set to
* false, a ForbiddenException exception is thrown instead of redirecting.
*
* @package Cake.Controller.Component.Auth
* @since 2.0
*/
class BasicAuthenticate extends BaseAuthenticate {
/**
* Settings for this object.
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
* - `contain` Extra models to contain and store in session.
* - `realm` The realm authentication is for. Defaults the server name.
*
* @var array
*/
public $settings = array(
'fields' => array(
'username' => 'username',
'password' => 'password'
),
'userModel' => 'User',
'scope' => array(),
'recursive' => 0,
'contain' => null,
'realm' => '',
);
/**
* Constructor, completes configuration for basic authentication.
*
@ -81,41 +64,47 @@ class BasicAuthenticate extends BaseAuthenticate {
}
/**
* Authenticate a user using basic HTTP auth. Will use the configured User model and attempt a
* login using basic HTTP auth.
* Authenticate a user using HTTP auth. Will use the configured User model and attempt a
* login using HTTP auth.
*
* @param CakeRequest $request The request to authenticate with.
* @param CakeResponse $response The response to add headers to.
* @return mixed Either false on failure, or an array of user data on success.
*/
public function authenticate(CakeRequest $request, CakeResponse $response) {
$result = $this->getUser($request);
if (empty($result)) {
$response->header($this->loginHeaders());
$response->statusCode(401);
$response->send();
return false;
}
return $result;
return $this->getUser($request);
}
/**
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
*
* @param CakeRequest $request Request object.
* @return mixed Either false or an array of user information
*/
public function getUser($request) {
public function getUser(CakeRequest $request) {
$username = env('PHP_AUTH_USER');
$pass = env('PHP_AUTH_PW');
if (empty($username) || empty($pass)) {
if (!is_string($username) || $username === '' || !is_string($pass) || $pass === '') {
return false;
}
return $this->_findUser($username, $pass);
}
/**
* Handles an unauthenticated access attempt by sending appropriate login headers
*
* @param CakeRequest $request A request object.
* @param CakeResponse $response A response object.
* @return void
* @throws UnauthorizedException
*/
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
$Exception = new UnauthorizedException();
$Exception->responseHeader(array($this->loginHeaders()));
throw $Exception;
}
/**
* Generate the login headers
*

View file

@ -0,0 +1,53 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of the files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('FormAuthenticate', 'Controller/Component/Auth');
/**
* An authentication adapter for AuthComponent. Provides the ability to authenticate using POST data using Blowfish
* hashing. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
*
* ```
* $this->Auth->authenticate = array(
* 'Blowfish' => array(
* 'scope' => array('User.active' => 1)
* )
* )
* ```
*
* When configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions
* are used. See FormAuthenticate::$settings for more information.
*
* For initial password hashing/creation see Security::hash(). Other than how the password is initially hashed,
* BlowfishAuthenticate works exactly the same way as FormAuthenticate.
*
* @package Cake.Controller.Component.Auth
* @since CakePHP(tm) v 2.3
* @see AuthComponent::$authenticate
* @deprecated 3.0.0 Since 2.4. Just use FormAuthenticate with 'passwordHasher' setting set to 'Blowfish'
*/
class BlowfishAuthenticate extends FormAuthenticate {
/**
* Constructor. Sets default passwordHasher to Blowfish
*
* @param ComponentCollection $collection The Component collection used on this request.
* @param array $settings Array of settings to use.
*/
public function __construct(ComponentCollection $collection, $settings) {
$this->settings['passwordHasher'] = 'Blowfish';
parent::__construct($collection, $settings);
}
}

View file

@ -0,0 +1,48 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.4.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
App::uses('Security', 'Utility');
/**
* Blowfish password hashing class.
*
* @package Cake.Controller.Component.Auth
*/
class BlowfishPasswordHasher extends AbstractPasswordHasher {
/**
* Generates password hash.
*
* @param string $password Plain text password to hash.
* @return string Password hash
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#using-bcrypt-for-passwords
*/
public function hash($password) {
return Security::hash($password, 'blowfish', false);
}
/**
* Check hash. Generate hash for user provided password and check against existing hash.
*
* @param string $password Plain text password to hash.
* @param string $hashedPassword Existing hashed password.
* @return bool True if hashes match else false.
*/
public function check($password, $hashedPassword) {
return $hashedPassword === Security::hash($password, 'blowfish', $hashedPassword);
}
}

View file

@ -1,32 +1,31 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthorize', 'Controller/Component/Auth');
/**
* An authorization adapter for AuthComponent. Provides the ability to authorize using a controller callback.
* An authorization adapter for AuthComponent. Provides the ability to authorize using a controller callback.
* Your controller's isAuthorized() method should return a boolean to indicate whether or not the user is authorized.
*
* {{{
* ```
* public function isAuthorized($user) {
* if (!empty($this->request->params['admin'])) {
* return $user['role'] == 'admin';
* return $user['role'] === 'admin';
* }
* return !empty($user);
* }
* }}}
* ```
*
* the above is simple implementation that would only authorize users of the 'admin' role to access
* admin routing.
@ -38,7 +37,7 @@ App::uses('BaseAuthorize', 'Controller/Component/Auth');
class ControllerAuthorize extends BaseAuthorize {
/**
* Get/set the controller this authorize object will be working with. Also checks that isAuthorized is implemented.
* Get/set the controller this authorize object will be working with. Also checks that isAuthorized is implemented.
*
* @param Controller $controller null to get, a controller to set.
* @return mixed
@ -47,7 +46,7 @@ class ControllerAuthorize extends BaseAuthorize {
public function controller(Controller $controller = null) {
if ($controller) {
if (!method_exists($controller, 'isAuthorized')) {
throw new CakeException(__d('cake_dev', '$controller does not implement an isAuthorized() method.'));
throw new CakeException(__d('cake_dev', '$controller does not implement an %s method.', 'isAuthorized()'));
}
}
return parent::controller($controller);
@ -57,8 +56,8 @@ class ControllerAuthorize extends BaseAuthorize {
* Checks user authorization using a controller callback.
*
* @param array $user Active user data
* @param CakeRequest $request
* @return boolean
* @param CakeRequest $request Request instance.
* @return bool
*/
public function authorize($user, CakeRequest $request) {
return (bool)$this->_Controller->isAuthorized($user);

View file

@ -1,28 +1,27 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthorize', 'Controller/Component/Auth');
App::uses('Router', 'Routing');
/**
* An authorization adapter for AuthComponent. Provides the ability to authorize using CRUD mappings.
* An authorization adapter for AuthComponent. Provides the ability to authorize using CRUD mappings.
* CRUD mappings allow you to translate controller actions into *C*reate *R*ead *U*pdate *D*elete actions.
* This is then checked in the AclComponent as specific permissions.
*
* For example, taking `/posts/index` as the current request. The default mapping for `index`, is a `read` permission
* check. The Acl check would then be for the `posts` controller with the `read` permission. This allows you
* For example, taking `/posts/index` as the current request. The default mapping for `index`, is a `read` permission
* check. The Acl check would then be for the `posts` controller with the `read` permission. This allows you
* to create permission systems that focus more on what is being done to resources, rather than the specific actions
* being visited.
*
@ -37,7 +36,7 @@ class CrudAuthorize extends BaseAuthorize {
* Sets up additional actionMap values that match the configured `Routing.prefixes`.
*
* @param ComponentCollection $collection The component collection from the controller.
* @param string $settings An array of settings. This class does not use any settings.
* @param string $settings An array of settings. This class does not use any settings.
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
parent::__construct($collection, $settings);
@ -77,7 +76,7 @@ class CrudAuthorize extends BaseAuthorize {
*
* @param array $user The user to authorize
* @param CakeRequest $request The request needing authorization.
* @return boolean
* @return bool
*/
public function authorize($user, CakeRequest $request) {
if (!isset($this->settings['actionMap'][$request->params['action']])) {

View file

@ -1,72 +1,72 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
App::uses('BasicAuthenticate', 'Controller/Component/Auth');
/**
* Digest Authentication adapter for AuthComponent.
*
* Provides Digest HTTP authentication support for AuthComponent. Unlike most AuthComponent adapters,
* DigestAuthenticate requires a special password hash that conforms to RFC2617. You can create this
* password using `DigestAuthenticate::password()`. If you wish to use digest authentication alongside other
* Provides Digest HTTP authentication support for AuthComponent. Unlike most AuthComponent adapters,
* DigestAuthenticate requires a special password hash that conforms to RFC2617. You can create this
* password using `DigestAuthenticate::password()`. If you wish to use digest authentication alongside other
* authentication methods, its recommended that you store the digest authentication separately.
*
* Clients using Digest Authentication must support cookies. Since AuthComponent identifies users based
* Clients using Digest Authentication must support cookies. Since AuthComponent identifies users based
* on Session contents, clients without support for cookies will not function properly.
*
* ### Using Digest auth
*
* In your controller's components array, add auth + the required settings.
* {{{
* ```
* public $components = array(
* 'Auth' => array(
* 'authenticate' => array('Digest')
* )
* );
* }}}
* ```
*
* In your login function just call `$this->Auth->login()` without any checks for POST data. This
* In your login function just call `$this->Auth->login()` without any checks for POST data. This
* will send the authentication headers, and trigger the login dialog in the browser/client.
*
* ### Generating passwords compatible with Digest authentication.
*
* Due to the Digest authentication specification, digest auth requires a special password value. You
* Due to the Digest authentication specification, digest auth requires a special password value. You
* can generate this password using `DigestAuthenticate::password()`
*
* `$digestPass = DigestAuthenticate::password($username, env('SERVER_NAME'), $password);`
*
* Its recommended that you store this digest auth only password separate from password hashes used for other
* login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would
* login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would
* store the password hash for use with other methods like Basic or Form.
*
* @package Cake.Controller.Component.Auth
* @since 2.0
*/
class DigestAuthenticate extends BaseAuthenticate {
class DigestAuthenticate extends BasicAuthenticate {
/**
* Settings for this object.
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `userFields` Array of fields to retrieve from User model, null to retrieve all. Defaults to null.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
* - `contain` Extra models to contain and store in session.
* - `realm` The realm authentication is for, Defaults to the servername.
* - `nonce` A nonce used for authentication. Defaults to `uniqid()`.
* - `nonce` A nonce used for authentication. Defaults to `uniqid()`.
* - `qop` Defaults to auth, no other values are supported at this time.
* - `opaque` A string that must be returned unchanged by clients.
* Defaults to `md5($settings['realm'])`
@ -79,13 +79,15 @@ class DigestAuthenticate extends BaseAuthenticate {
'password' => 'password'
),
'userModel' => 'User',
'userFields' => null,
'scope' => array(),
'recursive' => 0,
'contain' => null,
'realm' => '',
'qop' => 'auth',
'nonce' => '',
'opaque' => ''
'opaque' => '',
'passwordHasher' => 'Simple',
);
/**
@ -96,9 +98,6 @@ class DigestAuthenticate extends BaseAuthenticate {
*/
public function __construct(ComponentCollection $collection, $settings) {
parent::__construct($collection, $settings);
if (empty($this->settings['realm'])) {
$this->settings['realm'] = env('SERVER_NAME');
}
if (empty($this->settings['nonce'])) {
$this->settings['nonce'] = uniqid('');
}
@ -108,37 +107,21 @@ class DigestAuthenticate extends BaseAuthenticate {
}
/**
* Authenticate a user using Digest HTTP auth. Will use the configured User model and attempt a
* login using Digest HTTP auth.
*
* @param CakeRequest $request The request to authenticate with.
* @param CakeResponse $response The response to add headers to.
* @return mixed Either false on failure, or an array of user data on success.
*/
public function authenticate(CakeRequest $request, CakeResponse $response) {
$user = $this->getUser($request);
if (empty($user)) {
$response->header($this->loginHeaders());
$response->statusCode(401);
$response->send();
return false;
}
return $user;
}
/**
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
*
* @param CakeRequest $request Request object.
* @return mixed Either false or an array of user information
*/
public function getUser($request) {
public function getUser(CakeRequest $request) {
$digest = $this->_getDigest();
if (empty($digest)) {
return false;
}
$user = $this->_findUser($digest['username'], null);
list(, $model) = pluginSplit($this->settings['userModel']);
$user = $this->_findUser(array(
$model . '.' . $this->settings['fields']['username'] => $digest['username']
));
if (empty($user)) {
return false;
}
@ -150,34 +133,6 @@ class DigestAuthenticate extends BaseAuthenticate {
return false;
}
/**
* Find a user record using the standard options.
*
* @param string $username The username/identifier.
* @param string $password Unused password, digest doesn't require passwords.
* @return Mixed Either false on failure, or an array of user data.
*/
protected function _findUser($username, $password) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
$conditions = array(
$model . '.' . $fields['username'] => $username,
);
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
$result = ClassRegistry::init($userModel)->find('first', array(
'conditions' => $conditions,
'recursive' => $this->settings['recursive']
));
if (empty($result) || empty($result[$model])) {
return false;
}
return $result[$model];
}
/**
* Gets the digest headers from the request/environment.
*
@ -187,7 +142,7 @@ class DigestAuthenticate extends BaseAuthenticate {
$digest = env('PHP_AUTH_DIGEST');
if (empty($digest) && function_exists('apache_request_headers')) {
$headers = apache_request_headers();
if (!empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') {
if (!empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) === 'Digest ') {
$digest = substr($headers['Authorization'], 7);
}
}
@ -201,15 +156,15 @@ class DigestAuthenticate extends BaseAuthenticate {
* Parse the digest authentication headers and split them up.
*
* @param string $digest The raw digest authentication headers.
* @return array An array of digest authentication headers
* @return array|null An array of digest authentication headers
*/
public function parseAuthData($digest) {
if (substr($digest, 0, 7) == 'Digest ') {
if (substr($digest, 0, 7) === 'Digest ') {
$digest = substr($digest, 7);
}
$keys = $match = array();
$req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1);
preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER);
preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9\:\#\%\?\&@=\.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER);
foreach ($match as $i) {
$keys[$i[1]] = $i[3];

View file

@ -1,31 +1,30 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
/**
* An authentication adapter for AuthComponent. Provides the ability to authenticate using POST
* data. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
* An authentication adapter for AuthComponent. Provides the ability to authenticate using POST
* data. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
*
* {{{
* ```
* $this->Auth->authenticate = array(
* 'Form' => array(
* 'scope' => array('User.active' => 1)
* )
* )
* }}}
* ```
*
* When configuring FormAuthenticate you can pass in settings to which fields, model and additional conditions
* are used. See FormAuthenticate::$settings for more information.
@ -37,26 +36,41 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
class FormAuthenticate extends BaseAuthenticate {
/**
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
* to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
* there is no post data, either username or password is missing, of if the scope conditions have not been met.
* Checks the fields to ensure they are supplied.
*
* @param CakeRequest $request The request that contains login information.
* @param CakeResponse $response Unused response object.
* @return mixed. False on login failure. An array of User data on success.
* @param string $model The model used for login verification.
* @param array $fields The fields to be checked.
* @return bool False if the fields have not been supplied. True if they exist.
*/
public function authenticate(CakeRequest $request, CakeResponse $response) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
protected function _checkFields(CakeRequest $request, $model, $fields) {
if (empty($request->data[$model])) {
return false;
}
if (
empty($request->data[$model][$fields['username']]) ||
empty($request->data[$model][$fields['password']])
) {
foreach (array($fields['username'], $fields['password']) as $field) {
$value = $request->data($model . '.' . $field);
if (empty($value) && $value !== '0' || !is_string($value)) {
return false;
}
}
return true;
}
/**
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
* to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
* there is no post data, either username or password is missing, or if the scope conditions have not been met.
*
* @param CakeRequest $request The request that contains login information.
* @param CakeResponse $response Unused response object.
* @return mixed False on login failure. An array of User data on success.
*/
public function authenticate(CakeRequest $request, CakeResponse $response) {
$userModel = $this->settings['userModel'];
list(, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
return $this->_findUser(

View file

@ -0,0 +1,55 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.4.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
App::uses('Security', 'Utility');
/**
* Simple password hashing class.
*
* @package Cake.Controller.Component.Auth
*/
class SimplePasswordHasher extends AbstractPasswordHasher {
/**
* Config for this object.
*
* @var array
*/
protected $_config = array('hashType' => null);
/**
* Generates password hash.
*
* @param string $password Plain text password to hash.
* @return string Password hash
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#hashing-passwords
*/
public function hash($password) {
return Security::hash($password, $this->_config['hashType'], true);
}
/**
* Check hash. Generate hash for user provided password and check against existing hash.
*
* @param string $password Plain text password to hash.
* @param string $hashedPassword Existing hashed password.
* @return bool True if hashes match else false.
*/
public function check($password, $hashedPassword) {
return $hashedPassword === $this->hash($password);
}
}

View file

@ -4,19 +4,18 @@
*
* Manages user logins and permissions.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
@ -27,6 +26,7 @@ App::uses('Hash', 'Utility');
App::uses('CakeSession', 'Model/Datasource');
App::uses('BaseAuthorize', 'Controller/Component/Auth');
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
App::uses('CakeEvent', 'Event');
/**
* Authentication control component class
@ -38,6 +38,11 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
*/
class AuthComponent extends Component {
/**
* Constant for 'all'
*
* @var string
*/
const ALL = 'all';
/**
@ -45,25 +50,25 @@ class AuthComponent extends Component {
*
* @var array
*/
public $components = array('Session', 'RequestHandler');
public $components = array('Session', 'Flash', 'RequestHandler');
/**
* An array of authentication objects to use for authenticating users. You can configure
* An array of authentication objects to use for authenticating users. You can configure
* multiple adapters and they will be checked sequentially when users are identified.
*
* {{{
* ```
* $this->Auth->authenticate = array(
* 'Form' => array(
* 'userModel' => 'Users.User'
* )
* );
* }}}
* ```
*
* Using the class name without 'Authenticate' as the key, you can pass in an array of settings for each
* authentication object. Additionally you can define settings that should be set to all authentications objects
* authentication object. Additionally you can define settings that should be set to all authentications objects
* using the 'all' key:
*
* {{{
* ```
* $this->Auth->authenticate = array(
* 'all' => array(
* 'userModel' => 'Users.User',
@ -72,7 +77,7 @@ class AuthComponent extends Component {
* 'Form',
* 'Basic'
* );
* }}}
* ```
*
* You can also use AuthComponent::ALL instead of the string 'all'.
*
@ -84,27 +89,27 @@ class AuthComponent extends Component {
/**
* Objects that will be used for authentication checks.
*
* @var array
* @var BaseAuthenticate[]
*/
protected $_authenticateObjects = array();
/**
* An array of authorization objects to use for authorizing users. You can configure
* An array of authorization objects to use for authorizing users. You can configure
* multiple adapters and they will be checked sequentially when authorization checks are done.
*
* {{{
* ```
* $this->Auth->authorize = array(
* 'Crud' => array(
* 'actionPath' => 'controllers/'
* )
* );
* }}}
* ```
*
* Using the class name without 'Authorize' as the key, you can pass in an array of settings for each
* authorization object. Additionally you can define settings that should be set to all authorization objects
* authorization object. Additionally you can define settings that should be set to all authorization objects
* using the 'all' key:
*
* {{{
* ```
* $this->Auth->authorize = array(
* 'all' => array(
* 'actionPath' => 'controllers/'
@ -112,7 +117,7 @@ class AuthComponent extends Component {
* 'Crud',
* 'CustomAuth'
* );
* }}}
* ```
*
* You can also use AuthComponent::ALL instead of the string 'all'
*
@ -124,7 +129,7 @@ class AuthComponent extends Component {
/**
* Objects that will be used for authorization checks.
*
* @var array
* @var BaseAuthorize[]
*/
protected $_authorizeObjects = array();
@ -153,8 +158,9 @@ class AuthComponent extends Component {
);
/**
* The session key name where the record of the current user is stored. If
* unspecified, it will be "Auth.User".
* The session key name where the record of the current user is stored. Default
* key is "Auth.User". If you are using only stateless authenticators set this
* to false to ensure session is not started.
*
* @var string
*/
@ -170,7 +176,7 @@ class AuthComponent extends Component {
/**
* A URL (defined as a string or array) to the controller action that handles
* logins. Defaults to `/users/login`
* logins. Defaults to `/users/login`.
*
* @var mixed
*/
@ -183,8 +189,8 @@ class AuthComponent extends Component {
/**
* Normally, if a user is redirected to the $loginAction page, the location they
* were redirected from will be stored in the session so that they can be
* redirected back after a successful login. If this session value is not
* set, the user will be redirected to the page specified in $loginRedirect.
* redirected back after a successful login. If this session value is not
* set, redirectUrl() method will return the URL specified in $loginRedirect.
*
* @var mixed
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$loginRedirect
@ -192,7 +198,7 @@ class AuthComponent extends Component {
public $loginRedirect = null;
/**
* The default action to redirect to after the user is logged out. While AuthComponent does
* The default action to redirect to after the user is logged out. While AuthComponent does
* not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
* Defaults to AuthComponent::$loginAction.
*
@ -206,11 +212,22 @@ class AuthComponent extends Component {
* Error to display when user attempts to access an object or action to which they do not have
* access.
*
* @var string
* @var string|bool
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$authError
*/
public $authError = null;
/**
* Controls handling of unauthorized access.
* - For default value `true` unauthorized user is redirected to the referrer URL
* or AuthComponent::$loginRedirect or '/'.
* - If set to a string or array the value is used as a URL to redirect to.
* - If set to false a ForbiddenException exception is thrown instead of redirecting.
*
* @var mixed
*/
public $unauthorizedRedirect = true;
/**
* Controller actions for which user validation is not required.
*
@ -234,14 +251,14 @@ class AuthComponent extends Component {
public $response;
/**
* Method list for bound controller
* Method list for bound controller.
*
* @var array
*/
protected $_methods = array();
/**
* Initializes AuthComponent for use in the controller
* Initializes AuthComponent for use in the controller.
*
* @param Controller $controller A reference to the instantiating controller object
* @return void
@ -257,11 +274,11 @@ class AuthComponent extends Component {
}
/**
* Main execution method. Handles redirecting of invalid users, and processing
* Main execution method. Handles redirecting of invalid users, and processing
* of login form data.
*
* @param Controller $controller A reference to the instantiating controller object
* @return boolean
* @return bool
*/
public function startup(Controller $controller) {
$methods = array_flip(array_map('strtolower', $controller->methods));
@ -279,67 +296,137 @@ class AuthComponent extends Component {
if (!$this->_setDefaults()) {
return false;
}
$request = $controller->request;
$url = '';
if (isset($request->url)) {
$url = $request->url;
}
$url = Router::normalize($url);
$loginAction = Router::normalize($this->loginAction);
$allowedActions = $this->allowedActions;
$isAllowed = (
$this->allowedActions == array('*') ||
in_array($action, array_map('strtolower', $allowedActions))
);
if ($loginAction != $url && $isAllowed) {
if ($this->_isAllowed($controller)) {
return true;
}
if ($loginAction == $url) {
if (empty($request->data)) {
if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
if (!$this->_getUser()) {
return $this->_unauthenticated($controller);
}
if ($this->_isLoginAction($controller) ||
empty($this->authorize) ||
$this->isAuthorized($this->user())
) {
return true;
}
return $this->_unauthorized($controller);
}
/**
* Checks whether current action is accessible without authentication.
*
* @param Controller $controller A reference to the instantiating controller object
* @return bool True if action is accessible without authentication else false
*/
protected function _isAllowed(Controller $controller) {
$action = strtolower($controller->request->params['action']);
if (in_array($action, array_map('strtolower', $this->allowedActions))) {
return true;
}
return false;
}
/**
* Handles unauthenticated access attempt. First the `unathenticated()` method
* of the last authenticator in the chain will be called. The authenticator can
* handle sending response or redirection as appropriate and return `true` to
* indicate no furthur action is necessary. If authenticator returns null this
* method redirects user to login action. If it's an ajax request and
* $ajaxLogin is specified that element is rendered else a 403 http status code
* is returned.
*
* @param Controller $controller A reference to the controller object.
* @return bool True if current action is login action else false.
*/
protected function _unauthenticated(Controller $controller) {
if (empty($this->_authenticateObjects)) {
$this->constructAuthenticate();
}
$auth = $this->_authenticateObjects[count($this->_authenticateObjects) - 1];
if ($auth->unauthenticated($this->request, $this->response)) {
return false;
}
if ($this->_isLoginAction($controller)) {
if (empty($controller->request->data)) {
if (!$this->Session->check('Auth.redirect') && env('HTTP_REFERER')) {
$this->Session->write('Auth.redirect', $controller->referer(null, true));
}
}
return true;
} else {
if (!$this->_getUser()) {
if (!$request->is('ajax')) {
$this->flash($this->authError);
$this->Session->write('Auth.redirect', $request->here());
$controller->redirect($loginAction);
return false;
} elseif (!empty($this->ajaxLogin)) {
$controller->viewPath = 'Elements';
echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
$this->_stop();
return false;
} else {
$controller->redirect(null, 403);
}
}
}
if (empty($this->authorize) || $this->isAuthorized($this->user())) {
return true;
if (!$controller->request->is('ajax') && !$controller->request->is('json')) {
$this->flash($this->authError);
$this->Session->write('Auth.redirect', $controller->request->here(false));
$controller->redirect($this->loginAction);
return false;
}
if (!empty($this->ajaxLogin)) {
$controller->response->statusCode(403);
$controller->viewPath = 'Elements';
$response = $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
$response->send();
$this->_stop();
return false;
}
$controller->response->statusCode(403);
$controller->response->send();
$this->_stop();
return false;
}
/**
* Normalizes $loginAction and checks if current request URL is same as login action.
*
* @param Controller $controller A reference to the controller object.
* @return bool True if current action is login action else false.
*/
protected function _isLoginAction(Controller $controller) {
$url = '';
if (isset($controller->request->url)) {
$url = $controller->request->url;
}
$url = Router::normalize($url);
$loginAction = Router::normalize($this->loginAction);
return $loginAction === $url;
}
/**
* Handle unauthorized access attempt
*
* @param Controller $controller A reference to the controller object
* @return bool Returns false
* @throws ForbiddenException
* @see AuthComponent::$unauthorizedRedirect
*/
protected function _unauthorized(Controller $controller) {
if ($this->unauthorizedRedirect === false) {
throw new ForbiddenException($this->authError);
}
$this->flash($this->authError);
$default = '/';
if (!empty($this->loginRedirect)) {
$default = $this->loginRedirect;
if ($this->unauthorizedRedirect === true) {
$default = '/';
if (!empty($this->loginRedirect)) {
$default = $this->loginRedirect;
}
$url = $controller->referer($default, true);
} else {
$url = $this->unauthorizedRedirect;
}
$controller->redirect($controller->referer($default, true), null, true);
$controller->redirect($url);
return false;
}
/**
* Attempts to introspect the correct values for object properties.
*
* @return boolean
* @return bool True
*/
protected function _setDefaults() {
$defaults = array(
@ -347,7 +434,7 @@ class AuthComponent extends Component {
'authError' => __d('cake', 'You are not authorized to access that location.')
);
foreach ($defaults as $key => $value) {
if (empty($this->{$key})) {
if (!isset($this->{$key}) || $this->{$key} === true) {
$this->{$key} = $value;
}
}
@ -355,18 +442,21 @@ class AuthComponent extends Component {
}
/**
* Check if the provided user is authorized for the request.
*
* Uses the configured Authorization adapters to check whether or not a user is authorized.
* Each adapter will be checked in sequence, if any of them return true, then the user will
* be authorized for the request.
*
* @param array $user The user to check the authorization of. If empty the user in the session will be used.
* @param CakeRequest $request The request to authenticate for. If empty, the current request will be used.
* @return boolean True if $user is authorized, otherwise false
* @param array|null $user The user to check the authorization of. If empty the user in the session will be used.
* @param CakeRequest|null $request The request to authenticate for. If empty, the current request will be used.
* @return bool True if $user is authorized, otherwise false
*/
public function isAuthorized($user = null, $request = null) {
public function isAuthorized($user = null, CakeRequest $request = null) {
if (empty($user) && !$this->user()) {
return false;
} elseif (empty($user)) {
}
if (empty($user)) {
$user = $this->user();
}
if (empty($request)) {
@ -391,7 +481,7 @@ class AuthComponent extends Component {
*/
public function constructAuthorize() {
if (empty($this->authorize)) {
return;
return null;
}
$this->_authorizeObjects = array();
$config = Hash::normalize((array)$this->authorize);
@ -408,7 +498,7 @@ class AuthComponent extends Component {
throw new CakeException(__d('cake_dev', 'Authorization adapter "%s" was not found.', $class));
}
if (!method_exists($className, 'authorize')) {
throw new CakeException(__d('cake_dev', 'Authorization objects must implement an authorize method.'));
throw new CakeException(__d('cake_dev', 'Authorization objects must implement an %s method.', 'authorize()'));
}
$settings = array_merge($global, (array)$settings);
$this->_authorizeObjects[] = new $className($this->_Collection, $settings);
@ -426,7 +516,7 @@ class AuthComponent extends Component {
* `$this->Auth->allow('edit', 'add');` or
* `$this->Auth->allow();` to allow all actions
*
* @param string|array $action,... Controller action name or array of actions
* @param string|array|null $action Controller action name or array of actions
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-public
*/
@ -434,12 +524,12 @@ class AuthComponent extends Component {
$args = func_get_args();
if (empty($args) || $action === null) {
$this->allowedActions = $this->_methods;
} else {
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
$this->allowedActions = array_merge($this->allowedActions, $args);
return;
}
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
$this->allowedActions = array_merge($this->allowedActions, $args);
}
/**
@ -451,7 +541,7 @@ class AuthComponent extends Component {
* `$this->Auth->deny('edit', 'add');` or
* `$this->Auth->deny();` to remove all items from the allowed list
*
* @param string|array $action,... Controller action name or array of actions
* @param string|array|null $action Controller action name or array of actions
* @return void
* @see AuthComponent::allow()
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-require-authorization
@ -460,47 +550,58 @@ class AuthComponent extends Component {
$args = func_get_args();
if (empty($args) || $action === null) {
$this->allowedActions = array();
} else {
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
foreach ($args as $arg) {
$i = array_search($arg, $this->allowedActions);
if (is_int($i)) {
unset($this->allowedActions[$i]);
}
}
$this->allowedActions = array_values($this->allowedActions);
return;
}
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
foreach ($args as $arg) {
$i = array_search($arg, $this->allowedActions);
if (is_int($i)) {
unset($this->allowedActions[$i]);
}
}
$this->allowedActions = array_values($this->allowedActions);
}
/**
* Maps action names to CRUD operations. Used for controller-based authentication. Make sure
* Maps action names to CRUD operations.
*
* Used for controller-based authentication. Make sure
* to configure the authorize property before calling this method. As it delegates $map to all the
* attached authorize objects.
*
* @param array $map Actions to map
* @return void
* @return array
* @see BaseAuthorize::mapActions()
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#mapping-actions-when-using-crudauthorize
* @deprecated 3.0.0 Map actions using `actionMap` config key on authorize objects instead
*/
public function mapActions($map = array()) {
if (empty($this->_authorizeObjects)) {
$this->constructAuthorize();
}
$mappedActions = array();
foreach ($this->_authorizeObjects as $auth) {
$auth->mapActions($map);
$mappedActions = Hash::merge($mappedActions, $auth->mapActions($map));
}
if (empty($map)) {
return $mappedActions;
}
return array();
}
/**
* Log a user in. If a $user is provided that data will be stored as the logged in user. If `$user` is empty or not
* Log a user in.
*
* If a $user is provided that data will be stored as the logged in user. If `$user` is empty or not
* specified, the request will be used to identify a user. If the identification was successful,
* the user record is written to the session key specified in AuthComponent::$sessionKey. Logging in
* will also change the session id in order to help mitigate session replays.
*
* @param array $user Either an array of user data, or null to identify a user using the current request.
* @return boolean True on login success, false on failure
* @param array|null $user Either an array of user data, or null to identify a user using the current request.
* @return bool True on login success, false on failure
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#identifying-users-and-logging-them-in
*/
public function login($user = null) {
@ -510,18 +611,26 @@ class AuthComponent extends Component {
$user = $this->identify($this->request, $this->response);
}
if ($user) {
$this->Session->renew();
$this->Session->write(self::$sessionKey, $user);
if (static::$sessionKey) {
$this->Session->renew();
$this->Session->write(static::$sessionKey, $user);
} else {
static::$_user = $user;
}
$event = new CakeEvent('Auth.afterIdentify', $this, array('user' => $user));
$this->_Collection->getController()->getEventManager()->dispatch($event);
}
return $this->loggedIn();
return (bool)$this->user();
}
/**
* Logs a user out, and returns the login action to redirect to.
* Triggers the logout() method of all the authenticate objects, so they can perform
* custom logout logic. AuthComponent will remove the session data, so
* there is no need to do that in an authentication object. Logging out
* will also renew the session id. This helps mitigate issues with session replays.
* Log a user out.
*
* Returns the logout action to redirect to. Triggers the logout() method of
* all the authenticate objects, so they can perform custom logout logic.
* AuthComponent will remove the session data, so there is no need to do that
* in an authentication object. Logging out will also renew the session id.
* This helps mitigate issues with session replays.
*
* @return string AuthComponent::$logoutRedirect
* @see AuthComponent::$logoutRedirect
@ -536,7 +645,7 @@ class AuthComponent extends Component {
foreach ($this->_authenticateObjects as $auth) {
$auth->logout($user);
}
$this->Session->delete(self::$sessionKey);
$this->Session->delete(static::$sessionKey);
$this->Session->delete('Auth.redirect');
$this->Session->renew();
return Router::normalize($this->logoutRedirect);
@ -545,22 +654,21 @@ class AuthComponent extends Component {
/**
* Get the current user.
*
* Will prefer the static user cache over sessions. The static user
* cache is primarily used for stateless authentication. For stateful authentication,
* Will prefer the static user cache over sessions. The static user
* cache is primarily used for stateless authentication. For stateful authentication,
* cookies + sessions will be used.
*
* @param string $key field to retrieve. Leave null to get entire User record
* @return mixed User record. or null if no user is logged in.
* @param string|null $key field to retrieve. Leave null to get entire User record
* @return mixed|null User record. or null if no user is logged in.
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
*/
public static function user($key = null) {
if (empty(self::$_user) && !CakeSession::check(self::$sessionKey)) {
return null;
}
if (!empty(self::$_user)) {
$user = self::$_user;
if (!empty(static::$_user)) {
$user = static::$_user;
} elseif (static::$sessionKey && CakeSession::check(static::$sessionKey)) {
$user = CakeSession::read(static::$sessionKey);
} else {
$user = CakeSession::read(self::$sessionKey);
return null;
}
if ($key === null) {
return $user;
@ -570,51 +678,80 @@ class AuthComponent extends Component {
/**
* Similar to AuthComponent::user() except if the session user cannot be found, connected authentication
* objects will have their getUser() methods called. This lets stateless authentication methods function correctly.
* objects will have their getUser() methods called. This lets stateless authentication methods function correctly.
*
* @return boolean true if a user can be found, false if one cannot.
* @return bool True if a user can be found, false if one cannot.
*/
protected function _getUser() {
$user = $this->user();
if ($user) {
$this->Session->delete('Auth.redirect');
return true;
}
if (empty($this->_authenticateObjects)) {
$this->constructAuthenticate();
}
foreach ($this->_authenticateObjects as $auth) {
$result = $auth->getUser($this->request);
if (!empty($result) && is_array($result)) {
self::$_user = $result;
static::$_user = $result;
return true;
}
}
return false;
}
/**
* If no parameter is passed, gets the authentication redirect URL. Pass a url in to
* set the destination a user should be redirected to upon logging in. Will fallback to
* AuthComponent::$loginRedirect if there is no stored redirect value.
* Backwards compatible alias for AuthComponent::redirectUrl().
*
* @param string|array $url Optional URL to write as the login redirect URL.
* @param string|array|null $url Optional URL to write as the login redirect URL.
* @return string Redirect URL
* @deprecated 3.0.0 Since 2.3.0, use AuthComponent::redirectUrl() instead
*/
public function redirect($url = null) {
if (!is_null($url)) {
return $this->redirectUrl($url);
}
/**
* Get the URL a user should be redirected to upon login.
*
* Pass a URL in to set the destination a user should be redirected to upon
* logging in.
*
* If no parameter is passed, gets the authentication redirect URL. The URL
* returned is as per following rules:
*
* - Returns the normalized URL from session Auth.redirect value if it is
* present and for the same domain the current app is running on.
* - If there is no session value and there is a $loginRedirect, the $loginRedirect
* value is returned.
* - If there is no session and no $loginRedirect, / is returned.
*
* @param string|array|null $url Optional URL to write as the login redirect URL.
* @return string Redirect URL
*/
public function redirectUrl($url = null) {
if ($url !== null) {
$redir = $url;
$this->Session->write('Auth.redirect', $redir);
} elseif ($this->Session->check('Auth.redirect')) {
$redir = $this->Session->read('Auth.redirect');
$this->Session->delete('Auth.redirect');
if (Router::normalize($redir) == Router::normalize($this->loginAction)) {
$redir = $this->loginRedirect;
if (Router::normalize($redir) === Router::normalize($this->loginAction)) {
$redir = $this->loginRedirect ?: '/';
}
} else {
} elseif ($this->loginRedirect) {
$redir = $this->loginRedirect;
} else {
$redir = '/';
}
return Router::normalize($redir);
if (is_array($redir)) {
return Router::url($redir + array('base' => false));
}
return $redir;
}
/**
@ -639,14 +776,14 @@ class AuthComponent extends Component {
}
/**
* loads the configured authentication objects.
* Loads the configured authentication objects.
*
* @return mixed either null on empty authenticate value, or an array of loaded objects.
* @return mixed Either null on empty authenticate value, or an array of loaded objects.
* @throws CakeException
*/
public function constructAuthenticate() {
if (empty($this->authenticate)) {
return;
return null;
}
$this->_authenticateObjects = array();
$config = Hash::normalize((array)$this->authenticate);
@ -656,6 +793,10 @@ class AuthComponent extends Component {
unset($config[AuthComponent::ALL]);
}
foreach ($config as $class => $settings) {
if (!empty($settings['className'])) {
$class = $settings['className'];
unset($settings['className']);
}
list($plugin, $class) = pluginSplit($class, true);
$className = $class . 'Authenticate';
App::uses($className, $plugin . 'Controller/Component/Auth');
@ -663,10 +804,12 @@ class AuthComponent extends Component {
throw new CakeException(__d('cake_dev', 'Authentication adapter "%s" was not found.', $class));
}
if (!method_exists($className, 'authenticate')) {
throw new CakeException(__d('cake_dev', 'Authentication objects must implement an authenticate method.'));
throw new CakeException(__d('cake_dev', 'Authentication objects must implement an %s method.', 'authenticate()'));
}
$settings = array_merge($global, (array)$settings);
$this->_authenticateObjects[] = new $className($this->_Collection, $settings);
$auth = new $className($this->_Collection, $settings);
$this->_Collection->getController()->getEventManager()->attach($auth);
$this->_authenticateObjects[] = $auth;
}
return $this->_authenticateObjects;
}
@ -674,46 +817,38 @@ class AuthComponent extends Component {
/**
* Hash a password with the application's salt value (as defined with Configure::write('Security.salt');
*
* This method is intended as a convenience wrapper for Security::hash(). If you want to use
* This method is intended as a convenience wrapper for Security::hash(). If you want to use
* a hashing/encryption system not supported by that method, do not use this method.
*
* @param string $password Password to hash
* @return string Hashed password
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#hashing-passwords
* @deprecated 3.0.0 Since 2.4. Use Security::hash() directly or a password hasher object.
*/
public static function password($password) {
return Security::hash($password, null, true);
}
/**
* Component shutdown. If user is logged in, wipe out redirect.
*
* @param Controller $controller Instantiating controller
* @return void
*/
public function shutdown(Controller $controller) {
if ($this->loggedIn()) {
$this->Session->delete('Auth.redirect');
}
}
/**
* Check whether or not the current user has data in the session, and is considered logged in.
*
* @return boolean true if the user is logged in, false otherwise
* @return bool true if the user is logged in, false otherwise
* @deprecated 3.0.0 Since 2.5. Use AuthComponent::user() directly.
*/
public function loggedIn() {
return $this->user() != array();
return (bool)$this->user();
}
/**
* Set a flash message. Uses the Session component, and values from AuthComponent::$flash.
* Set a flash message. Uses the Session component, and values from AuthComponent::$flash.
*
* @param string $message The message to set.
* @return void
*/
public function flash($message) {
$this->Session->setFlash($message, $this->flash['element'], $this->flash['params'], $this->flash['key']);
if ($message === false) {
return;
}
$this->Flash->set($message, $this->flash);
}
}

View file

@ -2,19 +2,18 @@
/**
* Cookie Component
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 1.2.0.4213
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
@ -28,7 +27,6 @@ App::uses('Hash', 'Utility');
*
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html
*
*/
class CookieComponent extends Component {
@ -61,7 +59,7 @@ class CookieComponent extends Component {
* $this->Cookie->path = '/';
*
* The path on the server in which the cookie will be available on.
* If public $cookiePath is set to '/foo/', the cookie will only be available
* If public $cookiePath is set to '/foo/', the cookie will only be available
* within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
* The default value is the entire domain.
*
@ -93,7 +91,7 @@ class CookieComponent extends Component {
* Indicates that the cookie should only be transmitted over a secure HTTPS connection.
* When set to true, the cookie will only be set if a secure connection exists.
*
* @var boolean
* @var bool
*/
public $secure = false;
@ -110,10 +108,10 @@ class CookieComponent extends Component {
/**
* HTTP only cookie
*
* Set to true to make HTTP only cookies. Cookies that are HTTP only
* are not accessible in Javascript.
* Set to true to make HTTP only cookies. Cookies that are HTTP only
* are not accessible in JavaScript.
*
* @var boolean
* @var bool
*/
public $httpOnly = false;
@ -131,7 +129,9 @@ class CookieComponent extends Component {
* Type of encryption to use.
*
* Currently two methods are available: cipher and rijndael
* Defaults to Security::cipher();
* Defaults to Security::cipher(). Cipher is horribly insecure and only
* the default because of backwards compatibility. In new applications you should
* always change this to 'aes' or 'rijndael'.
*
* @var string
*/
@ -177,14 +177,14 @@ class CookieComponent extends Component {
if ($controller && isset($controller->response)) {
$this->_response = $controller->response;
} else {
$this->_response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
$this->_response = new CakeResponse();
}
}
/**
* Start CookieComponent for use in the controller
*
* @param Controller $controller
* @param Controller $controller Controller instance.
* @return void
*/
public function startup(Controller $controller) {
@ -207,8 +207,9 @@ class CookieComponent extends Component {
*
* @param string|array $key Key for the value
* @param mixed $value Value
* @param boolean $encrypt Set to true to encrypt value, false otherwise
* @param integer|string $expires Can be either Unix timestamp, or date string
* @param bool $encrypt Set to true to encrypt value, false otherwise
* @param int|string $expires Can be either the number of seconds until a cookie
* expires, or a strtotime compatible time offset.
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::write
*/
@ -217,7 +218,7 @@ class CookieComponent extends Component {
$this->read();
}
if (is_null($encrypt)) {
if ($encrypt === null) {
$encrypt = true;
}
$this->_encrypted = $encrypt;
@ -228,17 +229,27 @@ class CookieComponent extends Component {
}
foreach ($key as $name => $value) {
if (strpos($name, '.') === false) {
$this->_values[$this->name][$name] = $value;
$this->_write("[$name]", $value);
} else {
$names = array($name);
if (strpos($name, '.') !== false) {
$names = explode('.', $name, 2);
if (!isset($this->_values[$this->name][$names[0]])) {
$this->_values[$this->name][$names[0]] = array();
}
$this->_values[$this->name][$names[0]] = Hash::insert($this->_values[$this->name][$names[0]], $names[1], $value);
$this->_write('[' . implode('][', $names) . ']', $value);
}
$firstName = $names[0];
$isMultiValue = (is_array($value) || count($names) > 1);
if (!isset($this->_values[$this->name][$firstName]) && $isMultiValue) {
$this->_values[$this->name][$firstName] = array();
}
if (count($names) > 1) {
$this->_values[$this->name][$firstName] = Hash::insert(
$this->_values[$this->name][$firstName],
$names[1],
$value
);
} else {
$this->_values[$this->name][$firstName] = $value;
}
$this->_write('[' . $firstName . ']', $this->_values[$this->name][$firstName]);
}
$this->_encrypted = true;
}
@ -250,7 +261,7 @@ class CookieComponent extends Component {
* $this->Cookie->read(Name.key);
*
* @param string $key Key of the value to be obtained. If none specified, obtain map key => values
* @return string or null, value for specified key
* @return string|null Value for specified key
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::read
*/
public function read($key = null) {
@ -260,7 +271,7 @@ class CookieComponent extends Component {
if (empty($this->_values[$this->name])) {
$this->_values[$this->name] = array();
}
if (is_null($key)) {
if ($key === null) {
return $this->_values[$this->name];
}
@ -273,20 +284,42 @@ class CookieComponent extends Component {
}
if (!empty($names[1])) {
return Hash::get($this->_values[$this->name][$key], $names[1]);
if (is_array($this->_values[$this->name][$key])) {
return Hash::get($this->_values[$this->name][$key], $names[1]);
}
return null;
}
return $this->_values[$this->name][$key];
}
/**
* Returns true if given variable is set in cookie.
*
* @param string $key Variable name to check for
* @return bool True if variable is there
*/
public function check($key = null) {
if (empty($key)) {
return false;
}
return $this->read($key) !== null;
}
/**
* Delete a cookie value
*
* Optional [Name.], required key
* $this->Cookie->read('Name.key);
* $this->Cookie->delete('Name.key);
*
* You must use this method before any output is sent to the browser.
* Failure to do so will result in header already sent errors.
*
* This method will delete both the top level and 2nd level cookies set.
* For example assuming that $name = App, deleting `User` will delete
* both `App[User]` and any other cookie values like `App[User][email]`
* This is done to clean up cookie storage from before 2.4.3, where cookies
* were stored inconsistently.
*
* @param string $key Key of the value to be deleted
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::delete
@ -306,7 +339,7 @@ class CookieComponent extends Component {
return;
}
$names = explode('.', $key, 2);
if (isset($this->_values[$this->name][$names[0]])) {
if (isset($this->_values[$this->name][$names[0]]) && is_array($this->_values[$this->name][$names[0]])) {
$this->_values[$this->name][$names[0]] = Hash::remove($this->_values[$this->name][$names[0]], $names[1]);
}
$this->_delete('[' . implode('][', $names) . ']');
@ -349,10 +382,11 @@ class CookieComponent extends Component {
public function type($type = 'cipher') {
$availableTypes = array(
'cipher',
'rijndael'
'rijndael',
'aes'
);
if (!in_array($type, $availableTypes)) {
trigger_error(__d('cake_dev', 'You must use cipher or rijndael for cookie encryption type'), E_USER_WARNING);
trigger_error(__d('cake_dev', 'You must use cipher, rijndael or aes for cookie encryption type'), E_USER_WARNING);
$type = 'cipher';
}
$this->_type = $type;
@ -368,24 +402,24 @@ class CookieComponent extends Component {
* CookieComponent::write(string, string, boolean, 8400);
* CookieComponent::write(string, string, boolean, '5 Days');
*
* @param integer|string $expires Can be either Unix timestamp, or date string
* @return integer Unix timestamp
* @param int|string $expires Can be either Unix timestamp, or date string
* @return int Unix timestamp
*/
protected function _expire($expires = null) {
$now = time();
if (is_null($expires)) {
if ($expires === null) {
return $this->_expires;
}
$this->_reset = $this->_expires;
if ($expires == 0) {
if (!$expires) {
return $this->_expires = 0;
}
$now = new DateTime();
if (is_integer($expires) || is_numeric($expires)) {
return $this->_expires = $now + intval($expires);
if (is_int($expires) || is_numeric($expires)) {
return $this->_expires = $now->format('U') + (int)$expires;
}
return $this->_expires = strtotime($expires, $now);
$now->modify($expires);
return $this->_expires = $now->format('U');
}
/**
@ -406,7 +440,7 @@ class CookieComponent extends Component {
'httpOnly' => $this->httpOnly
));
if (!is_null($this->_reset)) {
if (!empty($this->_reset)) {
$this->_expires = $this->_reset;
$this->_reset = null;
}
@ -434,19 +468,26 @@ class CookieComponent extends Component {
* Encrypts $value using public $type method in Security class
*
* @param string $value Value to encrypt
* @return string encrypted string
* @return string Encoded values
*/
protected function _encrypt($value) {
if (is_array($value)) {
$value = $this->_implode($value);
}
if ($this->_encrypted === true) {
$type = $this->_type;
$value = "Q2FrZQ==." . base64_encode(Security::$type($value, $this->key, 'encrypt'));
if (!$this->_encrypted) {
return $value;
}
return $value;
$prefix = "Q2FrZQ==.";
if ($this->_type === 'rijndael') {
$cipher = Security::rijndael($value, $this->key, 'encrypt');
}
if ($this->_type === 'cipher') {
$cipher = Security::cipher($value, $this->key);
}
if ($this->_type === 'aes') {
$cipher = Security::encrypt($value, $this->key);
}
return $prefix . base64_encode($cipher);
}
/**
@ -462,27 +503,40 @@ class CookieComponent extends Component {
foreach ((array)$values as $name => $value) {
if (is_array($value)) {
foreach ($value as $key => $val) {
$pos = strpos($val, 'Q2FrZQ==.');
$decrypted[$name][$key] = $this->_explode($val);
if ($pos !== false) {
$val = substr($val, 8);
$decrypted[$name][$key] = $this->_explode(Security::$type(base64_decode($val), $this->key, 'decrypt'));
}
$decrypted[$name][$key] = $this->_decode($val);
}
} else {
$pos = strpos($value, 'Q2FrZQ==.');
$decrypted[$name] = $this->_explode($value);
if ($pos !== false) {
$value = substr($value, 8);
$decrypted[$name] = $this->_explode(Security::$type(base64_decode($value), $this->key, 'decrypt'));
}
$decrypted[$name] = $this->_decode($value);
}
}
return $decrypted;
}
/**
* Decodes and decrypts a single value.
*
* @param string $value The value to decode & decrypt.
* @return string Decoded value.
*/
protected function _decode($value) {
$prefix = 'Q2FrZQ==.';
$pos = strpos($value, $prefix);
if ($pos === false) {
return $this->_explode($value);
}
$value = base64_decode(substr($value, strlen($prefix)));
if ($this->_type === 'rijndael') {
$plain = Security::rijndael($value, $this->key, 'decrypt');
}
if ($this->_type === 'cipher') {
$plain = Security::cipher($value, $this->key);
}
if ($this->_type === 'aes') {
$plain = Security::decrypt($value, $this->key);
}
return $this->_explode($plain);
}
/**
* Implode method to keep keys are multidimensional arrays
*
@ -504,7 +558,7 @@ class CookieComponent extends Component {
$first = substr($string, 0, 1);
if ($first === '{' || $first === '[') {
$ret = json_decode($string, true);
return ($ret != null) ? $ret : $string;
return ($ret !== null) ? $ret : $string;
}
$array = array();
foreach (explode(',', $string) as $pair) {
@ -517,4 +571,3 @@ class CookieComponent extends Component {
return $array;
}
}

View file

@ -2,19 +2,18 @@
/**
* Email Component
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 1.2.0.3467
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
@ -28,9 +27,9 @@ App::uses('CakeEmail', 'Network/Email');
* based on the standard outlined in http://www.rfc-editor.org/rfc/rfc2822.txt
*
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/email.html
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/email.html
* @deprecated Use Network/CakeEmail
* @link http://book.cakephp.org/2.0/en/core-libraries/components/email.html
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/email.html
* @deprecated 3.0.0 Will be removed in 3.0. Use Network/CakeEmail instead
*/
class EmailComponent extends Component {
@ -239,7 +238,7 @@ class EmailComponent extends Component {
* it be handled by sendmail (or similar) or a string
* to completely override the Message-ID.
*
* If you are sending Email from a shell, be sure to set this value. As you
* If you are sending Email from a shell, be sure to set this value. As you
* could encounter delivery issues if you do not.
*
* @var mixed
@ -283,7 +282,7 @@ class EmailComponent extends Component {
* If you are rendering a template this variable will be sent to the templates as `$content`
* @param string $template Template to use when sending email
* @param string $layout Layout to use to enclose email body
* @return boolean Success
* @return bool Success
*/
public function send($content = null, $template = null, $layout = null) {
$lib = new CakeEmail();
@ -310,14 +309,15 @@ class EmailComponent extends Component {
$lib->readReceipt($this->_formatAddresses((array)$this->readReceipt));
}
$lib->subject($this->subject)->messageID($this->messageId);
$lib->subject($this->subject);
$lib->messageID($this->messageId);
$lib->helpers($this->_controller->helpers);
$headers = array('X-Mailer' => $this->xMailer);
foreach ($this->headers as $key => $value) {
$headers['X-' . $key] = $value;
}
if ($this->date != false) {
if ($this->date) {
$headers['Date'] = $this->date;
}
$lib->setHeaders($headers);
@ -406,7 +406,7 @@ class EmailComponent extends Component {
* Find the specified attachment in the list of file paths
*
* @param string $attachment Attachment file name to find
* @return string Path to located file
* @return string|null Path to located file
*/
protected function _findFiles($attachment) {
if (file_exists($attachment)) {
@ -424,7 +424,7 @@ class EmailComponent extends Component {
/**
* Format addresses to be an array with email as key and alias as value
*
* @param array $addresses
* @param array $addresses Address to format.
* @return array
*/
protected function _formatAddresses($addresses) {
@ -445,11 +445,11 @@ class EmailComponent extends Component {
* Helps prevent header injection / manipulation on user content.
*
* @param string $value Value to strip
* @param boolean $message Set to true to indicate main message content
* @param bool $message Set to true to indicate main message content
* @return string Stripped value
*/
protected function _strip($value, $message = false) {
$search = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
$search = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
$search .= '|charset\=|mime-version\:|multipart/mixed|(?:[^a-z]to|b?cc)\:.*';
if ($message !== true) {

View file

@ -0,0 +1,118 @@
<?php
/**
* Flash Component
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 2.7.0-dev
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
App::uses('Inflector', 'Utility');
App::uses('CakeSession', 'Model/Datasource');
/**
* The CakePHP FlashComponent provides a way for you to write a flash variable
* to the session from your controllers, to be rendered in a view with the
* FlashHelper.
*
* @package Cake.Controller.Component
*/
class FlashComponent extends Component {
/**
* Default configuration
*
* @var array
*/
protected $_defaultConfig = array(
'key' => 'flash',
'element' => 'default',
'params' => array(),
);
/**
* Constructor
*
* @param ComponentCollection $collection The ComponentCollection object
* @param array $settings Settings passed via controller
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
$this->_defaultConfig = Hash::merge($this->_defaultConfig, $settings);
}
/**
* Used to set a session variable that can be used to output messages in the view.
*
* In your controller: $this->Flash->set('This has been saved');
*
* ### Options:
*
* - `key` The key to set under the session's Flash key
* - `element` The element used to render the flash message. Default to 'default'.
* - `params` An array of variables to make available when using an element
*
* @param string $message Message to be flashed. If an instance
* of Exception the exception message will be used and code will be set
* in params.
* @param array $options An array of options.
* @return void
*/
public function set($message, $options = array()) {
$options += $this->_defaultConfig;
if ($message instanceof Exception) {
$options['params'] += array('code' => $message->getCode());
$message = $message->getMessage();
}
list($plugin, $element) = pluginSplit($options['element'], true);
if (!empty($options['plugin'])) {
$plugin = $options['plugin'] . '.';
}
$options['element'] = $plugin . 'Flash/' . $element;
CakeSession::write('Message.' . $options['key'], array(
'message' => $message,
'key' => $options['key'],
'element' => $options['element'],
'params' => $options['params']
));
}
/**
* Magic method for verbose flash methods based on element names.
*
* For example: $this->Flash->success('My message') would use the
* success.ctp element under `app/View/Element/Flash` for rendering the
* flash message.
*
* @param string $name Element name to use.
* @param array $args Parameters to pass when calling `FlashComponent::set()`.
* @return void
* @throws InternalErrorException If missing the flash message.
*/
public function __call($name, $args) {
$options = array('element' => Inflector::underscore($name));
if (count($args) < 1) {
throw new InternalErrorException('Flash message missing.');
}
if (!empty($args[1])) {
$options += (array)$args[1];
}
$this->set($args[0], $options);
}
}

View file

@ -2,43 +2,44 @@
/**
* Paginator Component
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
App::uses('Hash', 'Utility');
/**
* This component is used to handle automatic model data pagination. The primary way to use this
* This component is used to handle automatic model data pagination. The primary way to use this
* component is to call the paginate() method. There is a convenience wrapper on Controller as well.
*
* ### Configuring pagination
*
* You configure pagination using the PaginatorComponent::$settings. This allows you to configure
* You configure pagination using the PaginatorComponent::$settings. This allows you to configure
* the default pagination behavior in general or for a specific model. General settings are used when there
* are no specific model configuration, or the model you are paginating does not have specific settings.
*
* {{{
* ```
* $this->Paginator->settings = array(
* 'limit' => 20,
* 'maxLimit' => 100
* );
* }}}
* ```
*
* The above settings will be used to paginate any model. You can configure model specific settings by
* The above settings will be used to paginate any model. You can configure model specific settings by
* keying the settings with the model name.
*
* {{{
* ```
* $this->Paginator->settings = array(
* 'Post' => array(
* 'limit' => 20,
@ -46,21 +47,35 @@ App::uses('Hash', 'Utility');
* ),
* 'Comment' => array( ... )
* );
* }}}
* ```
*
* This would allow you to have different pagination settings for `Comment` and `Post` models.
*
* #### Paginating with custom finders
*
* You can paginate with any find type defined on your model using the `findType` option.
*
* ```
* $this->Paginator->settings = array(
* 'Post' => array(
* 'findType' => 'popular'
* )
* );
* ```
*
* Would paginate using the `find('popular')` method.
*
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
*/
class PaginatorComponent extends Component {
/**
* Pagination settings. These settings control pagination at a general level.
* Pagination settings. These settings control pagination at a general level.
* You can also define sub arrays for pagination settings for specific models.
*
* - `maxLimit` The maximum limit users can choose to view. Defaults to 100
* - `limit` The initial number of items per page. Defaults to 20.
* - `limit` The initial number of items per page. Defaults to 20.
* - `page` The starting page, defaults to 1.
* - `paramType` What type of parameters you want pagination to use?
* - `named` Use named parameters / routed parameters.
@ -76,7 +91,7 @@ class PaginatorComponent extends Component {
);
/**
* A list of parameters users are allowed to set using request parameters. Modifying
* A list of parameters users are allowed to set using request parameters. Modifying
* this list will allow users to have more influence over pagination,
* be careful with what you permit.
*
@ -103,10 +118,12 @@ class PaginatorComponent extends Component {
*
* @param Model|string $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
* @param string|array $scope Additional find conditions to use while paginating
* @param array $whitelist List of allowed fields for ordering. This allows you to prevent ordering
* on non-indexed, or undesirable columns.
* @param array $whitelist List of allowed fields for ordering. This allows you to prevent ordering
* on non-indexed, or undesirable columns. See PaginatorComponent::validateSort() for additional details
* on how the whitelisting and sort field validation works.
* @return array Model query results
* @throws MissingModelException
* @throws NotFoundException
*/
public function paginate($object = null, $scope = array(), $whitelist = array()) {
if (is_array($object)) {
@ -152,11 +169,17 @@ class PaginatorComponent extends Component {
$extra = array_diff_key($options, compact(
'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
));
if (!empty($extra['findType'])) {
$type = $extra['findType'];
unset($extra['findType']);
}
if ($type !== 'all') {
$extra['type'] = $type;
}
if (intval($page) < 1) {
if ((int)$page < 1) {
$page = 1;
}
$page = $options['page'] = (int)$page;
@ -175,8 +198,12 @@ class PaginatorComponent extends Component {
$defaults = $this->getDefaults($object->alias);
unset($defaults[0]);
if ($object->hasMethod('paginateCount')) {
if (!$results) {
$count = 0;
} elseif ($object->hasMethod('paginateCount')) {
$count = $object->paginateCount($conditions, $recursive, $extra);
} elseif ($page === 1 && count($results) < $limit) {
$count = count($results);
} else {
$parameters = compact('conditions');
if ($recursive != $object->recursive) {
@ -184,7 +211,8 @@ class PaginatorComponent extends Component {
}
$count = $object->find('count', array_merge($parameters, $extra));
}
$pageCount = intval(ceil($count / $limit));
$pageCount = (int)ceil($count / $limit);
$requestedPage = $page;
$page = max(min($page, $pageCount), 1);
$paging = array(
@ -199,6 +227,7 @@ class PaginatorComponent extends Component {
'options' => Hash::diff($options, $defaults),
'paramType' => $options['paramType']
);
if (!isset($this->Controller->request['paging'])) {
$this->Controller->request['paging'] = array();
}
@ -207,8 +236,11 @@ class PaginatorComponent extends Component {
array($object->alias => $paging)
);
if (
!in_array('Paginator', $this->Controller->helpers) &&
if ($requestedPage > $page) {
throw new NotFoundException();
}
if (!in_array('Paginator', $this->Controller->helpers) &&
!array_key_exists('Paginator', $this->Controller->helpers)
) {
$this->Controller->helpers[] = 'Paginator';
@ -228,36 +260,34 @@ class PaginatorComponent extends Component {
if (strpos($object, '.') !== false) {
list($object, $assoc) = pluginSplit($object);
}
if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
$object = $this->Controller->{$object}->{$assoc};
} elseif (
$assoc && isset($this->Controller->{$this->Controller->modelClass}) &&
isset($this->Controller->{$this->Controller->modelClass}->{$assoc}
)) {
$object = $this->Controller->{$this->Controller->modelClass}->{$assoc};
} elseif (isset($this->Controller->{$object})) {
$object = $this->Controller->{$object};
} elseif (
isset($this->Controller->{$this->Controller->modelClass}) && isset($this->Controller->{$this->Controller->modelClass}->{$object}
)) {
$object = $this->Controller->{$this->Controller->modelClass}->{$object};
return $this->Controller->{$object}->{$assoc};
}
} elseif (empty($object) || $object === null) {
if ($assoc && isset($this->Controller->{$this->Controller->modelClass}->{$assoc})) {
return $this->Controller->{$this->Controller->modelClass}->{$assoc};
}
if (isset($this->Controller->{$object})) {
return $this->Controller->{$object};
}
if (isset($this->Controller->{$this->Controller->modelClass}->{$object})) {
return $this->Controller->{$this->Controller->modelClass}->{$object};
}
}
if (empty($object) || $object === null) {
if (isset($this->Controller->{$this->Controller->modelClass})) {
$object = $this->Controller->{$this->Controller->modelClass};
} else {
$className = null;
$name = $this->Controller->uses[0];
if (strpos($this->Controller->uses[0], '.') !== false) {
list($name, $className) = explode('.', $this->Controller->uses[0]);
}
if ($className) {
$object = $this->Controller->{$className};
} else {
$object = $this->Controller->{$name};
}
return $this->Controller->{$this->Controller->modelClass};
}
$className = null;
$name = $this->Controller->uses[0];
if (strpos($this->Controller->uses[0], '.') !== false) {
list($name, $className) = explode('.', $this->Controller->uses[0]);
}
if ($className) {
return $this->Controller->{$className};
}
return $this->Controller->{$name};
}
return $object;
}
@ -270,7 +300,7 @@ class PaginatorComponent extends Component {
* - Model specific settings.
* - Request parameters
*
* The result of this method is the aggregate of all the option sets combined together. You can change
* The result of this method is the aggregate of all the option sets combined together. You can change
* PaginatorComponent::$whitelist to modify which options/values can be set using request parameters.
*
* @param string $alias Model alias being paginated, if the general settings has a key with this value
@ -292,44 +322,53 @@ class PaginatorComponent extends Component {
}
/**
* Get the default settings for a $model. If there are no settings for a specific model, the general settings
* Get the default settings for a $model. If there are no settings for a specific model, the general settings
* will be used.
*
* @param string $alias Model name to get default settings for.
* @return array An array of pagination defaults for a model, or the general settings.
*/
public function getDefaults($alias) {
$defaults = $this->settings;
if (isset($this->settings[$alias])) {
$defaults = $this->settings[$alias];
} else {
$defaults = $this->settings;
}
return array_merge(
array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
$defaults
$defaults += array(
'page' => 1,
'limit' => 20,
'maxLimit' => 100,
'paramType' => 'named'
);
return $defaults;
}
/**
* Validate that the desired sorting can be performed on the $object. Only fields or
* virtualFields can be sorted on. The direction param will also be sanitized. Lastly
* Validate that the desired sorting can be performed on the $object. Only fields or
* virtualFields can be sorted on. The direction param will also be sanitized. Lastly
* sort + direction keys will be converted into the model friendly order key.
*
* You can use the whitelist parameter to control which columns/fields are available for sorting.
* This helps prevent users from ordering large result sets on un-indexed values.
*
* Any columns listed in the sort whitelist will be implicitly trusted. You can use this to sort
* on synthetic columns, or columns added in custom find operations that may not exist in the schema.
*
* @param Model $object The model being paginated.
* @param array $options The pagination options being used for this request.
* @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
* @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
* @return array An array of options with sort + direction removed and replaced with order if possible.
*/
public function validateSort($object, $options, $whitelist = array()) {
public function validateSort(Model $object, array $options, array $whitelist = array()) {
if (empty($options['order']) && is_array($object->order)) {
$options['order'] = $object->order;
}
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
$direction = strtolower($options['direction']);
}
if ($direction != 'asc' && $direction != 'desc') {
if (!in_array($direction, array('asc', 'desc'))) {
$direction = 'asc';
}
$options['order'] = array($options['sort'] => $direction);
@ -337,23 +376,30 @@ class PaginatorComponent extends Component {
if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
$field = key($options['order']);
if (!in_array($field, $whitelist)) {
$inWhitelist = in_array($field, $whitelist, true);
if (!$inWhitelist) {
$options['order'] = null;
}
return $options;
}
if (!empty($options['order']) && is_array($options['order'])) {
$order = array();
foreach ($options['order'] as $key => $value) {
if (is_int($key)) {
$key = $value;
$value = 'asc';
}
$field = $key;
$alias = $object->alias;
if (strpos($key, '.') !== false) {
list($alias, $field) = explode('.', $key);
}
$correctAlias = ($object->alias === $alias);
if ($object->hasField($field)) {
$order[$alias . '.' . $field] = $value;
} elseif ($object->hasField($key, true)) {
if ($correctAlias && $object->hasField($field)) {
$order[$object->alias . '.' . $field] = $value;
} elseif ($correctAlias && $object->hasField($key, true)) {
$order[$field] = $value;
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
$order[$alias . '.' . $field] = $value;
@ -371,7 +417,7 @@ class PaginatorComponent extends Component {
* @param array $options An array of options with a limit key to be checked.
* @return array An array of options for pagination
*/
public function checkLimit($options) {
public function checkLimit(array $options) {
$options['limit'] = (int)$options['limit'];
if (empty($options['limit']) || $options['limit'] < 1) {
$options['limit'] = 1;

View file

@ -3,22 +3,24 @@
* Request object for handling alternative HTTP requests
*
* Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
* and the like. These units have no use for Ajax requests, and this Component can tell how Cake
* and the like. These units have no use for Ajax requests, and this Component can tell how Cake
* should respond to the different needs of a handheld computer and a desktop machine.
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 0.10.4.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
App::uses('Xml', 'Utility');
/**
@ -30,7 +32,6 @@ App::uses('Xml', 'Utility');
*
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html
*
*/
class RequestHandlerComponent extends Component {
@ -45,7 +46,7 @@ class RequestHandlerComponent extends Component {
/**
* Determines whether or not callbacks will be fired on this component
*
* @var boolean
* @var bool
*/
public $enabled = true;
@ -88,6 +89,17 @@ class RequestHandlerComponent extends Component {
'json' => array('json_decode', true)
);
/**
* A mapping between type and viewClass
* By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap()
*
* @var array
*/
protected $_viewClassMap = array(
'json' => 'Json',
'xml' => 'Xml'
);
/**
* Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
*
@ -95,8 +107,7 @@ class RequestHandlerComponent extends Component {
* @param array $settings Array of settings.
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
$default = array('checkHttpCache' => true);
parent::__construct($collection, $settings + $default);
parent::__construct($collection, $settings + array('checkHttpCache' => true));
$this->addInputType('xml', array(array($this, 'convertXml')));
$Controller = $collection->getController();
@ -111,19 +122,20 @@ class RequestHandlerComponent extends Component {
* and the requested mime-types, RequestHandler::$ext is set to that value.
*
* @param Controller $controller A reference to the controller
* @param array $settings Array of settings to _set().
* @return void
* @see Router::parseExtensions()
*/
public function initialize(Controller $controller, $settings = array()) {
public function initialize(Controller $controller) {
if (isset($this->request->params['ext'])) {
$this->ext = $this->request->params['ext'];
}
if (empty($this->ext) || $this->ext == 'html') {
if (empty($this->ext) || $this->ext === 'html') {
$this->_setExtension();
}
$this->params = $controller->params;
$this->_set($settings);
if (!empty($this->settings['viewClassMap'])) {
$this->viewClassMap($this->settings['viewClassMap']);
}
}
/**
@ -131,6 +143,9 @@ class RequestHandlerComponent extends Component {
* Compares the accepted types and configured extensions.
* If there is one common type, that is assigned as the ext/content type
* for the response.
* Type with the highest weight will be set. If the highest weight has more
* then one type matching the extensions, the order in which extensions are specified
* determines which type will be set.
*
* If html is one of the preferred types, no content type will be set, this
* is to avoid issues with browsers that prefer html and several other content types.
@ -142,12 +157,20 @@ class RequestHandlerComponent extends Component {
if (empty($accept)) {
return;
}
$accepts = $this->response->mapType($accept);
$preferedTypes = current($accepts);
if (array_intersect($preferedTypes, array('html', 'xhtml'))) {
return;
}
$extensions = Router::extensions();
$preferred = array_shift($accept);
$preferredTypes = $this->response->mapType($preferred);
$similarTypes = array_intersect($extensions, $preferredTypes);
if (count($similarTypes) === 1 && !in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
$this->ext = array_shift($similarTypes);
foreach ($accepts as $types) {
$ext = array_intersect($extensions, $types);
if ($ext) {
$this->ext = current($ext);
break;
}
}
}
@ -157,11 +180,11 @@ class RequestHandlerComponent extends Component {
*
* - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
* - If Router::parseExtensions() is enabled, the layout and template type are
* switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
* switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
* is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if
* `controller/action` is requested with `Accept-Type: application/xml` in the headers
* the view path will become `app/View/Controller/xml/action.ctp`. Layout and template
* types will only switch to mime-types recognized by CakeResponse. If you need to declare
* the view path will become `app/View/Controller/xml/action.ctp`. Layout and template
* types will only switch to mime-types recognized by CakeResponse. If you need to declare
* additional mime-types, you can do so using CakeResponse::type() in your controllers beforeFilter()
* method.
* - If a helper with the same name as the extension exists, it is added to the controller.
@ -200,12 +223,12 @@ class RequestHandlerComponent extends Component {
* Helper method to parse xml input data, due to lack of anonymous functions
* this lives here.
*
* @param string $xml
* @param string $xml XML string.
* @return array Xml array data
*/
public function convertXml($xml) {
try {
$xml = Xml::build($xml);
$xml = Xml::build($xml, array('readFile' => false));
if (isset($xml->data)) {
return Xml::toArray($xml->data);
}
@ -221,14 +244,17 @@ class RequestHandlerComponent extends Component {
*
* @param Controller $controller A reference to the controller
* @param string|array $url A string or array containing the redirect location
* @param integer|array $status HTTP Status for redirect
* @param boolean $exit
* @param int|array $status HTTP Status for redirect
* @param bool $exit Whether to exit script, defaults to `true`.
* @return void
*/
public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
if (!$this->request->is('ajax')) {
return;
}
if (empty($url)) {
return;
}
$_SERVER['REQUEST_METHOD'] = 'GET';
foreach ($_POST as $key => $val) {
unset($_POST[$key]);
@ -252,12 +278,11 @@ class RequestHandlerComponent extends Component {
* render process is skipped. And the client will get a blank response with a
* "304 Not Modified" header.
*
* @params Controller $controller
* @return boolean false if the render process should be aborted
**/
* @param Controller $controller Controller instance.
* @return bool False if the render process should be aborted.
*/
public function beforeRender(Controller $controller) {
$shouldCheck = $this->settings['checkHttpCache'];
if ($shouldCheck && $this->response->checkNotModified($this->request)) {
if ($this->settings['checkHttpCache'] && $this->response->checkNotModified($this->request)) {
return false;
}
}
@ -265,8 +290,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current HTTP request is Ajax, false otherwise
*
* @return boolean True if call is Ajax
* @deprecated use `$this->request->is('ajax')` instead.
* @return bool True if call is Ajax
* @deprecated 3.0.0 Use `$this->request->is('ajax')` instead.
*/
public function isAjax() {
return $this->request->is('ajax');
@ -275,8 +300,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current HTTP request is coming from a Flash-based client
*
* @return boolean True if call is from Flash
* @deprecated use `$this->request->is('flash')` instead.
* @return bool True if call is from Flash
* @deprecated 3.0.0 Use `$this->request->is('flash')` instead.
*/
public function isFlash() {
return $this->request->is('flash');
@ -285,8 +310,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current request is over HTTPS, false otherwise.
*
* @return boolean True if call is over HTTPS
* @deprecated use `$this->request->is('ssl')` instead.
* @return bool True if call is over HTTPS
* @deprecated 3.0.0 Use `$this->request->is('ssl')` instead.
*/
public function isSSL() {
return $this->request->is('ssl');
@ -295,7 +320,7 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call accepts an XML response, false otherwise
*
* @return boolean True if client accepts an XML response
* @return bool True if client accepts an XML response
*/
public function isXml() {
return $this->prefers('xml');
@ -304,7 +329,7 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call accepts an RSS response, false otherwise
*
* @return boolean True if client accepts an RSS response
* @return bool True if client accepts an RSS response
*/
public function isRss() {
return $this->prefers('rss');
@ -313,7 +338,7 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call accepts an Atom response, false otherwise
*
* @return boolean True if client accepts an RSS response
* @return bool True if client accepts an RSS response
*/
public function isAtom() {
return $this->prefers('atom');
@ -323,7 +348,7 @@ class RequestHandlerComponent extends Component {
* Returns true if user agent string matches a mobile web browser, or if the
* client accepts WAP content.
*
* @return boolean True if user agent is a mobile web browser
* @return bool True if user agent is a mobile web browser
*/
public function isMobile() {
return $this->request->is('mobile') || $this->accepts('wap');
@ -332,7 +357,7 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the client accepts WAP content
*
* @return boolean
* @return bool
*/
public function isWap() {
return $this->prefers('wap');
@ -341,8 +366,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call a POST request
*
* @return boolean True if call is a POST
* @deprecated Use $this->request->is('post'); from your controller.
* @return bool True if call is a POST
* @deprecated 3.0.0 Use $this->request->is('post'); from your controller.
*/
public function isPost() {
return $this->request->is('post');
@ -351,8 +376,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call a PUT request
*
* @return boolean True if call is a PUT
* @deprecated Use $this->request->is('put'); from your controller.
* @return bool True if call is a PUT
* @deprecated 3.0.0 Use $this->request->is('put'); from your controller.
*/
public function isPut() {
return $this->request->is('put');
@ -361,8 +386,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call a GET request
*
* @return boolean True if call is a GET
* @deprecated Use $this->request->is('get'); from your controller.
* @return bool True if call is a GET
* @deprecated 3.0.0 Use $this->request->is('get'); from your controller.
*/
public function isGet() {
return $this->request->is('get');
@ -371,8 +396,8 @@ class RequestHandlerComponent extends Component {
/**
* Returns true if the current call a DELETE request
*
* @return boolean True if call is a DELETE
* @deprecated Use $this->request->is('delete'); from your controller.
* @return bool True if call is a DELETE
* @deprecated 3.0.0 Use $this->request->is('delete'); from your controller.
*/
public function isDelete() {
return $this->request->is('delete');
@ -382,17 +407,15 @@ class RequestHandlerComponent extends Component {
* Gets Prototype version if call is Ajax, otherwise empty string.
* The Prototype library sets a special "Prototype version" HTTP header.
*
* @return string Prototype version of component making Ajax call
* @return string|bool When Ajax the prototype version of component making the call otherwise false
*/
public function getAjaxVersion() {
if (env('HTTP_X_PROTOTYPE_VERSION') != null) {
return env('HTTP_X_PROTOTYPE_VERSION');
}
return false;
$httpX = env('HTTP_X_PROTOTYPE_VERSION');
return ($httpX === null) ? false : $httpX;
}
/**
* Adds/sets the Content-type(s) for the given name. This method allows
* Adds/sets the Content-type(s) for the given name. This method allows
* content-types to be mapped to friendly aliases (or extensions), which allows
* RequestHandler to automatically respond to requests of that type in the
* startup method.
@ -401,7 +424,7 @@ class RequestHandlerComponent extends Component {
* @param string|array $type The Content-type or array of Content-types assigned to the name,
* i.e. "text/html", or "application/xml"
* @return void
* @deprecated use `$this->response->type()` instead.
* @deprecated 3.0.0 Use `$this->response->type()` instead.
*/
public function setContent($name, $type = null) {
$this->response->type(array($name => $type));
@ -411,7 +434,7 @@ class RequestHandlerComponent extends Component {
* Gets the server name from which this request was referred
*
* @return string Server address
* @deprecated use $this->request->referer() from your controller instead
* @deprecated 3.0.0 Use $this->request->referer() from your controller instead
*/
public function getReferer() {
return $this->request->referer(false);
@ -420,16 +443,17 @@ class RequestHandlerComponent extends Component {
/**
* Gets remote client IP
*
* @param boolean $safe
* @param bool $safe Use safe = false when you think the user might manipulate
* their HTTP_CLIENT_IP header. Setting $safe = false will also look at HTTP_X_FORWARDED_FOR
* @return string Client IP address
* @deprecated use $this->request->clientIp() from your, controller instead.
* @deprecated 3.0.0 Use $this->request->clientIp() from your, controller instead.
*/
public function getClientIP($safe = true) {
return $this->request->clientIp($safe);
}
/**
* Determines which content types the client accepts. Acceptance is based on
* Determines which content types the client accepts. Acceptance is based on
* the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
* header. Unlike CakeRequest::accepts() this method deals entirely with mapped content types.
*
@ -446,17 +470,18 @@ class RequestHandlerComponent extends Component {
* @param string|array $type Can be null (or no parameter), a string type name, or an
* array of types
* @return mixed If null or no parameter is passed, returns an array of content
* types the client accepts. If a string is passed, returns true
* if the client accepts it. If an array is passed, returns true
* types the client accepts. If a string is passed, returns true
* if the client accepts it. If an array is passed, returns true
* if the client accepts one or more elements in the array.
* @see RequestHandlerComponent::setContent()
*/
public function accepts($type = null) {
$accepted = $this->request->accepts();
if ($type == null) {
if (!$type) {
return $this->mapType($accepted);
} elseif (is_array($type)) {
}
if (is_array($type)) {
foreach ($type as $t) {
$t = $this->mapAlias($t);
if (in_array($t, $accepted)) {
@ -464,9 +489,9 @@ class RequestHandlerComponent extends Component {
}
}
return false;
} elseif (is_string($type)) {
$type = $this->mapAlias($type);
return in_array($type, $accepted);
}
if (is_string($type)) {
return in_array($this->mapAlias($type), $accepted);
}
return false;
}
@ -475,33 +500,43 @@ class RequestHandlerComponent extends Component {
* Determines the content type of the data the client has sent (i.e. in a POST request)
*
* @param string|array $type Can be null (or no parameter), a string type name, or an array of types
* @return mixed If a single type is supplied a boolean will be returned. If no type is provided
* @return mixed If a single type is supplied a boolean will be returned. If no type is provided
* The mapped value of CONTENT_TYPE will be returned. If an array is supplied the first type
* in the request content type will be returned.
*/
public function requestedWith($type = null) {
if (!$this->request->is('post') && !$this->request->is('put')) {
if (
!$this->request->is('patch') &&
!$this->request->is('post') &&
!$this->request->is('put') &&
!$this->request->is('delete')
) {
return null;
}
list($contentType) = explode(';', env('CONTENT_TYPE'));
if ($type == null) {
return $this->mapType($contentType);
} elseif (is_array($type)) {
if (is_array($type)) {
foreach ($type as $t) {
if ($this->requestedWith($t)) {
return $t;
}
}
return false;
} elseif (is_string($type)) {
return ($type == $this->mapType($contentType));
}
list($contentType) = explode(';', env('CONTENT_TYPE'));
if ($contentType === '') {
list($contentType) = explode(';', CakeRequest::header('CONTENT_TYPE'));
}
if (!$type) {
return $this->mapType($contentType);
}
if (is_string($type)) {
return ($type === $this->mapType($contentType));
}
}
/**
* Determines which content-types the client prefers. If no parameters are given,
* the single content-type that the client most likely prefers is returned. If $type is
* Determines which content-types the client prefers. If no parameters are given,
* the single content-type that the client most likely prefers is returned. If $type is
* an array, the first item in the array that the client accepts is returned.
* Preference is determined primarily by the file extension parsed by the Router
* if provided, and secondarily by the list of content-types provided in
@ -510,7 +545,7 @@ class RequestHandlerComponent extends Component {
* @param string|array $type An optional array of 'friendly' content-type names, i.e.
* 'html', 'xml', 'js', etc.
* @return mixed If $type is null or not provided, the first content-type in the
* list, based on preference, is returned. If a single type is provided
* list, based on preference, is returned. If a single type is provided
* a boolean will be returned if that type is preferred.
* If an array of types are provided then the first preferred type is returned.
* If no type is provided the first preferred type is returned.
@ -522,10 +557,9 @@ class RequestHandlerComponent extends Component {
if (empty($acceptRaw)) {
return $this->ext;
}
$accepts = array_shift($acceptRaw);
$accepts = $this->mapType($accepts);
$accepts = $this->mapType(array_shift($acceptRaw));
if ($type == null) {
if (!$type) {
if (empty($this->ext) && !empty($accepts)) {
return $accepts[0];
}
@ -574,26 +608,34 @@ class RequestHandlerComponent extends Component {
if (Configure::read('App.encoding') !== null) {
$defaults['charset'] = Configure::read('App.encoding');
}
$options = array_merge($defaults, $options);
$options += $defaults;
if ($type == 'ajax') {
if ($type === 'ajax') {
$controller->layout = $this->ajaxLayout;
return $this->respondAs('html', $options);
}
$controller->ext = '.ctp';
$viewClass = Inflector::classify($type);
$pluginDot = null;
$viewClassMap = $this->viewClassMap();
if (array_key_exists($type, $viewClassMap)) {
list($pluginDot, $viewClass) = pluginSplit($viewClassMap[$type], true);
} else {
$viewClass = Inflector::classify($type);
}
$viewName = $viewClass . 'View';
if (!class_exists($viewName)) {
App::uses($viewName, 'View');
App::uses($viewName, $pluginDot . 'View');
}
if (class_exists($viewName)) {
$controller->viewClass = $viewClass;
} elseif (empty($this->_renderType)) {
$controller->viewPath .= DS . $type;
} else {
$remove = preg_replace("/([\/\\\\]{$this->_renderType})$/", DS . $type, $controller->viewPath);
$controller->viewPath = $remove;
$controller->viewPath = preg_replace(
"/([\/\\\\]{$this->_renderType})$/",
DS . $type,
$controller->viewPath
);
}
$this->_renderType = $type;
$controller->layoutPath = $type;
@ -603,12 +645,8 @@ class RequestHandlerComponent extends Component {
}
$helper = ucfirst($type);
$isAdded = (
in_array($helper, $controller->helpers) ||
array_key_exists($helper, $controller->helpers)
);
if (!$isAdded) {
if (!in_array($helper, $controller->helpers) && empty($controller->helpers[$helper])) {
App::uses('AppHelper', 'View/Helper');
App::uses($helper . 'Helper', 'View/Helper');
if (class_exists($helper . 'Helper')) {
@ -618,14 +656,14 @@ class RequestHandlerComponent extends Component {
}
/**
* Sets the response header based on type map index name. This wraps several methods
* Sets the response header based on type map index name. This wraps several methods
* available on CakeResponse. It also allows you to use Content-Type aliases.
*
* @param string|array $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
* like 'application/x-shockwave'.
* @param array $options If $type is a friendly type name that is associated with
* more than one type of content, $index is used to select which content-type to use.
* @return boolean Returns false if the friendly type name given in $type does
* @return bool Returns false if the friendly type name given in $type does
* not exist in the type map, or if the Content-type header has
* already been set by this method.
* @see RequestHandlerComponent::setContent()
@ -634,39 +672,35 @@ class RequestHandlerComponent extends Component {
$defaults = array('index' => null, 'charset' => null, 'attachment' => false);
$options = $options + $defaults;
$cType = $type;
if (strpos($type, '/') === false) {
$cType = $this->response->getMimeType($type);
if ($cType === false) {
return false;
}
if (is_array($cType) && isset($cType[$options['index']])) {
}
if (is_array($cType)) {
if (isset($cType[$options['index']])) {
$cType = $cType[$options['index']];
}
if (is_array($cType)) {
if ($this->prefers($cType)) {
$cType = $this->prefers($cType);
} else {
$cType = $cType[0];
}
if ($this->prefers($cType)) {
$cType = $this->prefers($cType);
} else {
$cType = $cType[0];
}
} else {
$cType = $type;
}
if ($cType != null) {
if (empty($this->request->params['requested'])) {
$this->response->type($cType);
}
if (!empty($options['charset'])) {
$this->response->charset($options['charset']);
}
if (!empty($options['attachment'])) {
$this->response->download($options['attachment']);
}
return true;
if (!$type) {
return false;
}
return false;
if (empty($this->request->params['requested'])) {
$this->response->type($cType);
}
if (!empty($options['charset'])) {
$this->response->charset($options['charset']);
}
if (!empty($options['attachment'])) {
$this->response->download($options['attachment']);
}
return true;
}
/**
@ -684,7 +718,7 @@ class RequestHandlerComponent extends Component {
*
* @param string|array $cType Either a string content type to map, or an array of types.
* @return string|array Aliases for the types provided.
* @deprecated Use $this->response->mapType() in your controller instead.
* @deprecated 3.0.0 Use $this->response->mapType() in your controller instead.
*/
public function mapType($cType) {
return $this->response->mapType($cType);
@ -694,7 +728,7 @@ class RequestHandlerComponent extends Component {
* Maps a content type alias back to its mime-type(s)
*
* @param string|array $alias String alias to convert back into a content type. Or an array of aliases to map.
* @return string Null on an undefined alias. String value of the mapped alias type. If an
* @return string|null Null on an undefined alias. String value of the mapped alias type. If an
* alias maps to more than one content type, the first one will be returned.
*/
public function mapAlias($alias) {
@ -712,11 +746,11 @@ class RequestHandlerComponent extends Component {
}
/**
* Add a new mapped input type. Mapped input types are automatically
* Add a new mapped input type. Mapped input types are automatically
* converted by RequestHandlerComponent during the startup() callback.
*
* @param string $type The type alias being converted, ie. json
* @param array $handler The handler array for the type. The first index should
* @param array $handler The handler array for the type. The first index should
* be the handling callback, all other arguments should be additional parameters
* for the handler.
* @return void
@ -729,4 +763,25 @@ class RequestHandlerComponent extends Component {
$this->_inputTypeMap[$type] = $handler;
}
/**
* Getter/setter for viewClassMap
*
* @param array|string $type The type string or array with format `array('type' => 'viewClass')` to map one or more
* @param array $viewClass The viewClass to be used for the type without `View` appended
* @return array|string Returns viewClass when only string $type is set, else array with viewClassMap
*/
public function viewClassMap($type = null, $viewClass = null) {
if (!$viewClass && is_string($type) && isset($this->_viewClassMap[$type])) {
return $this->_viewClassMap[$type];
}
if (is_string($type)) {
$this->_viewClassMap[$type] = $viewClass;
} elseif (is_array($type)) {
foreach ($type as $key => $value) {
$this->viewClassMap($key, $value);
}
}
return $this->_viewClassMap;
}
}

View file

@ -2,23 +2,22 @@
/**
* Security Component
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 0.10.8.2156
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
App::uses('String', 'Utility');
App::uses('CakeText', 'Utility');
App::uses('Hash', 'Utility');
App::uses('Security', 'Utility');
@ -48,6 +47,7 @@ class SecurityComponent extends Component {
* List of controller actions for which a POST request is required
*
* @var array
* @deprecated 3.0.0 Use CakeRequest::allowMethod() instead.
* @see SecurityComponent::requirePost()
*/
public $requirePost = array();
@ -56,6 +56,7 @@ class SecurityComponent extends Component {
* List of controller actions for which a GET request is required
*
* @var array
* @deprecated 3.0.0 Use CakeRequest::allowMethod() instead.
* @see SecurityComponent::requireGet()
*/
public $requireGet = array();
@ -64,6 +65,7 @@ class SecurityComponent extends Component {
* List of controller actions for which a PUT request is required
*
* @var array
* @deprecated 3.0.0 Use CakeRequest::allowMethod() instead.
* @see SecurityComponent::requirePut()
*/
public $requirePut = array();
@ -72,6 +74,7 @@ class SecurityComponent extends Component {
* List of controller actions for which a DELETE request is required
*
* @var array
* @deprecated 3.0.0 Use CakeRequest::allowMethod() instead.
* @see SecurityComponent::requireDelete()
*/
public $requireDelete = array();
@ -89,6 +92,7 @@ class SecurityComponent extends Component {
*
* @var array
* @see SecurityComponent::requireAuth()
* @deprecated 2.8.1 This feature is confusing and not useful.
*/
public $requireAuth = array();
@ -114,7 +118,7 @@ class SecurityComponent extends Component {
* Deprecated property, superseded by unlockedFields.
*
* @var array
* @deprecated
* @deprecated 3.0.0 Superseded by unlockedFields.
* @see SecurityComponent::$unlockedFields
*/
public $disabledFields = array();
@ -130,17 +134,26 @@ class SecurityComponent extends Component {
public $unlockedFields = array();
/**
* Whether to validate POST data. Set to false to disable for data coming from 3rd party
* Actions to exclude from CSRF and POST validation checks.
* Other checks like requireAuth(), requireSecure(),
* requirePost(), requireGet() etc. will still be applied.
*
* @var array
*/
public $unlockedActions = array();
/**
* Whether to validate POST data. Set to false to disable for data coming from 3rd party
* services, etc.
*
* @var boolean
* @var bool
*/
public $validatePost = true;
/**
* Whether to use CSRF protected forms. Set to false to disable CSRF protection on forms.
* Whether to use CSRF protected forms. Set to false to disable CSRF protection on forms.
*
* @var boolean
* @var bool
* @see http://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
* @see SecurityComponent::$csrfExpires
*/
@ -149,32 +162,32 @@ class SecurityComponent extends Component {
/**
* The duration from when a CSRF token is created that it will expire on.
* Each form/page request will generate a new token that can only be submitted once unless
* it expires. Can be any value compatible with strtotime()
* it expires. Can be any value compatible with strtotime()
*
* @var string
*/
public $csrfExpires = '+30 minutes';
/**
* Controls whether or not CSRF tokens are use and burn. Set to false to not generate
* new tokens on each request. One token will be reused until it expires. This reduces
* Controls whether or not CSRF tokens are use and burn. Set to false to not generate
* new tokens on each request. One token will be reused until it expires. This reduces
* the chances of users getting invalid requests because of token consumption.
* It has the side effect of making CSRF less secure, as tokens are reusable.
*
* @var boolean
* @var bool
*/
public $csrfUseOnce = true;
/**
* Control the number of tokens a user can keep open.
* This is most useful with one-time use tokens. Since new tokens
* This is most useful with one-time use tokens. Since new tokens
* are created on each request, having a hard limit on the number of open tokens
* can be useful in controlling the size of the session file.
*
* When tokens are evicted, the oldest ones will be removed, as they are the most likely
* to be dead/expired.
*
* @var integer
* @var int
*/
public $csrfLimit = 100;
@ -212,28 +225,26 @@ class SecurityComponent extends Component {
$this->_secureRequired($controller);
$this->_authRequired($controller);
$isPost = ($this->request->is('post') || $this->request->is('put'));
$hasData = !empty($this->request->data);
$isNotRequestAction = (
!isset($controller->request->params['requested']) ||
$controller->request->params['requested'] != 1
);
if ($this->_action == $this->blackHoleCallback) {
return $this->blackhole($controller, 'auth');
if ($this->_action === $this->blackHoleCallback) {
return $this->blackHole($controller, 'auth');
}
if ($isPost && $isNotRequestAction && $this->validatePost) {
if ($this->_validatePost($controller) === false) {
if (!in_array($this->_action, (array)$this->unlockedActions) && $hasData && $isNotRequestAction) {
if ($this->validatePost && $this->_validatePost($controller) === false) {
return $this->blackHole($controller, 'auth');
}
}
if ($isPost && $isNotRequestAction && $this->csrfCheck) {
if ($this->_validateCsrf($controller) === false) {
if ($this->csrfCheck && $this->_validateCsrf($controller) === false) {
return $this->blackHole($controller, 'csrf');
}
}
$this->generateToken($controller->request);
if ($isPost && is_array($controller->request->data)) {
if ($hasData && is_array($controller->request->data)) {
unset($controller->request->data['_Token']);
}
}
@ -242,6 +253,7 @@ class SecurityComponent extends Component {
* Sets the actions that require a POST request, or empty for all actions
*
* @return void
* @deprecated 3.0.0 Use CakeRequest::onlyAllow() instead.
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requirePost
*/
public function requirePost() {
@ -252,6 +264,7 @@ class SecurityComponent extends Component {
/**
* Sets the actions that require a GET request, or empty for all actions
*
* @deprecated 3.0.0 Use CakeRequest::onlyAllow() instead.
* @return void
*/
public function requireGet() {
@ -262,6 +275,7 @@ class SecurityComponent extends Component {
/**
* Sets the actions that require a PUT request, or empty for all actions
*
* @deprecated 3.0.0 Use CakeRequest::onlyAllow() instead.
* @return void
*/
public function requirePut() {
@ -272,6 +286,7 @@ class SecurityComponent extends Component {
/**
* Sets the actions that require a DELETE request, or empty for all actions
*
* @deprecated 3.0.0 Use CakeRequest::onlyAllow() instead.
* @return void
*/
public function requireDelete() {
@ -291,7 +306,11 @@ class SecurityComponent extends Component {
}
/**
* Sets the actions that require an authenticated request, or empty for all actions
* Sets the actions that require whitelisted form submissions.
*
* Adding actions with this method will enforce the restrictions
* set in SecurityComponent::$allowedControllers and
* SecurityComponent::$allowedActions.
*
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requireAuth
@ -330,24 +349,24 @@ class SecurityComponent extends Component {
if (isset($actions[0]) && is_array($actions[0])) {
$actions = $actions[0];
}
$this->{'require' . $method} = (empty($actions)) ? array('*'): $actions;
$this->{'require' . $method} = (empty($actions)) ? array('*') : $actions;
}
/**
* Check if HTTP methods are required
*
* @param Controller $controller Instantiating controller
* @return boolean true if $method is required
* @return bool True if $method is required
*/
protected function _methodsRequired(Controller $controller) {
foreach (array('Post', 'Get', 'Put', 'Delete') as $method) {
$property = 'require' . $method;
if (is_array($this->$property) && !empty($this->$property)) {
$require = $this->$property;
if (in_array($this->_action, $require) || $this->$property == array('*')) {
if (in_array($this->_action, $require) || $this->$property === array('*')) {
if (!$this->request->is($method)) {
if (!$this->blackHole($controller, $method)) {
return null;
return false;
}
}
}
@ -360,16 +379,16 @@ class SecurityComponent extends Component {
* Check if access requires secure connection
*
* @param Controller $controller Instantiating controller
* @return boolean true if secure connection required
* @return bool True if secure connection required
*/
protected function _secureRequired(Controller $controller) {
if (is_array($this->requireSecure) && !empty($this->requireSecure)) {
$requireSecure = $this->requireSecure;
if (in_array($this->_action, $requireSecure) || $this->requireSecure == array('*')) {
if (in_array($this->_action, $requireSecure) || $this->requireSecure === array('*')) {
if (!$this->request->is('ssl')) {
if (!$this->blackHole($controller, 'secure')) {
return null;
return false;
}
}
}
@ -381,14 +400,15 @@ class SecurityComponent extends Component {
* Check if authentication is required
*
* @param Controller $controller Instantiating controller
* @return boolean true if authentication required
* @return bool|null True if authentication required
* @deprecated 2.8.1 This feature is confusing and not useful.
*/
protected function _authRequired(Controller $controller) {
if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($this->request->data)) {
$requireAuth = $this->requireAuth;
if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) {
if (!isset($controller->request->data['_Token'] )) {
if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth === array('*')) {
if (!isset($controller->request->data['_Token'])) {
if (!$this->blackHole($controller, 'auth')) {
return null;
}
@ -397,8 +417,7 @@ class SecurityComponent extends Component {
if ($this->Session->check('_Token')) {
$tData = $this->Session->read('_Token');
if (
!empty($tData['allowedControllers']) &&
if (!empty($tData['allowedControllers']) &&
!in_array($this->request->params['controller'], $tData['allowedControllers']) ||
!empty($tData['allowedActions']) &&
!in_array($this->request->params['action'], $tData['allowedActions'])
@ -421,7 +440,7 @@ class SecurityComponent extends Component {
* Validate submitted form
*
* @param Controller $controller Instantiating controller
* @return boolean true if submitted form is valid
* @return bool true if submitted form is valid
*/
protected function _validatePost(Controller $controller) {
if (empty($controller->request->data)) {
@ -452,8 +471,8 @@ class SecurityComponent extends Component {
$multi = array();
foreach ($fieldList as $i => $key) {
if (preg_match('/(\.\d+)+$/', $key)) {
$multi[$i] = preg_replace('/(\.\d+)+$/', '', $key);
if (preg_match('/(\.\d+){1,10}$/', $key)) {
$multi[$i] = preg_replace('/(\.\d+){1,10}$/', '', $key);
unset($fieldList[$i]);
}
}
@ -492,7 +511,13 @@ class SecurityComponent extends Component {
$fieldList += $lockedFields;
$unlocked = implode('|', $unlocked);
$check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'));
$hashParts = array(
$this->request->here(),
serialize($fieldList),
$unlocked,
Configure::read('Security.salt')
);
$check = Security::hash(implode('', $hashParts), 'sha1');
return ($token === $check);
}
@ -500,7 +525,7 @@ class SecurityComponent extends Component {
* Manually add CSRF token information into the provided request object.
*
* @param CakeRequest $request The request object to add into.
* @return boolean
* @return bool
*/
public function generateToken(CakeRequest $request) {
if (isset($request->params['requested']) && $request->params['requested'] === 1) {
@ -509,7 +534,7 @@ class SecurityComponent extends Component {
}
return false;
}
$authKey = Security::generateAuthKey();
$authKey = hash('sha512', Security::randomBytes(16), false);
$token = array(
'key' => $authKey,
'allowedControllers' => $this->allowedControllers,
@ -530,7 +555,9 @@ class SecurityComponent extends Component {
}
if (!$this->csrfUseOnce) {
$csrfTokens = array_keys($token['csrfTokens']);
$token['key'] = $csrfTokens[0];
$authKey = $csrfTokens[0];
$token['key'] = $authKey;
$token['csrfTokens'][$authKey] = strtotime($this->csrfExpires);
}
$this->Session->write('_Token', $token);
$request->params['_Token'] = array(
@ -542,11 +569,11 @@ class SecurityComponent extends Component {
/**
* Validate that the controller has a CSRF token in the POST data
* and that the token is legit/not expired. If the token is valid
* and that the token is legit/not expired. If the token is valid
* it will be removed from the list of valid tokens.
*
* @param Controller $controller A controller to check
* @return boolean Valid csrf token.
* @return bool Valid csrf token.
*/
protected function _validateCsrf(Controller $controller) {
$token = $this->Session->read('_Token');
@ -591,11 +618,10 @@ class SecurityComponent extends Component {
* @throws BadRequestException When a the blackholeCallback is not callable.
*/
protected function _callback(Controller $controller, $method, $params = array()) {
if (is_callable(array($controller, $method))) {
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
} else {
if (!is_callable(array($controller, $method))) {
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
}
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
}
}

View file

@ -2,19 +2,18 @@
/**
* SessionComponent. Provides access to Sessions from the Controller layer
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller.Component
* @since CakePHP(tm) v 0.10.0.1232
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Component', 'Controller');
@ -35,21 +34,21 @@ class SessionComponent extends Component {
* Get / Set the userAgent
*
* @param string $userAgent Set the userAgent
* @return void
* @return string Current user agent.
*/
public function userAgent($userAgent = null) {
return CakeSession::userAgent($userAgent);
}
/**
* Used to write a value to a session key.
* Writes a value to a session key.
*
* In your controller: $this->Session->write('Controller.sessKey', 'session value');
*
* @param string $name The name of the key your are setting in the session.
* This should be in a Controller.key format for better organizing
* @param string $value The value you want to store in a session.
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write
*/
public function write($name, $value = null) {
@ -57,7 +56,7 @@ class SessionComponent extends Component {
}
/**
* Used to read a session values for a key or return values for all keys.
* Reads a session value for a key or returns values for all keys.
*
* In your controller: $this->Session->read('Controller.sessKey');
* Calling the method without a param will return all session vars
@ -71,12 +70,12 @@ class SessionComponent extends Component {
}
/**
* Wrapper for SessionComponent::del();
* Deletes a session value for a key.
*
* In your controller: $this->Session->delete('Controller.sessKey');
*
* @param string $name the name of the session key you want to delete
* @return boolean true is session variable is set and can be deleted, false is variable was not set.
* @return bool true is session variable is set and can be deleted, false is variable was not set.
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::delete
*/
public function delete($name) {
@ -84,12 +83,24 @@ class SessionComponent extends Component {
}
/**
* Used to check if a session variable is set
* Reads and deletes a session value for a key.
*
* In your controller: `$this->Session->consume('Controller.sessKey');`
*
* @param string $name the name of the session key you want to read
* @return mixed values from the session vars
*/
public function consume($name) {
return CakeSession::consume($name);
}
/**
* Checks if a session variable is set.
*
* In your controller: $this->Session->check('Controller.sessKey');
*
* @param string $name the name of the session key you want to check
* @return boolean true is session variable is set, false if not
* @return bool true is session variable is set, false if not
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::check
*/
public function check($name) {
@ -122,6 +133,7 @@ class SessionComponent extends Component {
* @param string $key Message key, default is 'flash'
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#creating-notification-messages
* @deprecated 3.0.0 Since 2.7, use the FlashComponent instead.
*/
public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') {
CakeSession::write('Message.' . $key, compact('message', 'element', 'params'));
@ -143,7 +155,7 @@ class SessionComponent extends Component {
*
* In your controller: $this->Session->valid();
*
* @return boolean true is session is valid, false is session is invalid
* @return bool true is session is valid, false is session is invalid
*/
public function valid() {
return CakeSession::valid();
@ -165,7 +177,7 @@ class SessionComponent extends Component {
* Get/Set the session id.
*
* When fetching the session id, the session will be started
* if it has not already been started. When setting the session id,
* if it has not already been started. When setting the session id,
* the session will not be started.
*
* @param string $id Id to use (optional)
@ -181,7 +193,7 @@ class SessionComponent extends Component {
/**
* Returns a bool, whether or not the session has been started.
*
* @return boolean
* @return bool
*/
public function started() {
return CakeSession::started();

View file

@ -4,16 +4,17 @@
* and constructing component class objects.
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('ObjectCollection', 'Utility');
@ -53,28 +54,38 @@ class ComponentCollection extends ObjectCollection implements CakeEventListener
}
}
/**
* Set the controller associated with the collection.
*
* @param Controller $Controller Controller to set
* @return void
*/
public function setController(Controller $Controller) {
$this->_Controller = $Controller;
}
/**
* Get the controller associated with the collection.
*
* @return Controller.
* @return Controller Controller instance
*/
public function getController() {
return $this->_Controller;
}
/**
* Loads/constructs a component. Will return the instance in the registry if it already exists.
* Loads/constructs a component. Will return the instance in the registry if it already exists.
* You can use `$settings['enabled'] = false` to disable callbacks on a component when loading it.
* Callbacks default to on. Disabled component methods work as normal, only callbacks are disabled.
* Callbacks default to on. Disabled component methods work as normal, only callbacks are disabled.
*
* You can alias your component as an existing component by setting the 'className' key, i.e.,
* {{{
* ```
* public $components = array(
* 'Email' => array(
* 'className' => 'AliasedEmail'
* );
* );
* }}}
* ```
* All calls to the `Email` component would use `AliasedEmail` instead.
*
* @param string $component Component name to load
@ -83,7 +94,7 @@ class ComponentCollection extends ObjectCollection implements CakeEventListener
* @throws MissingComponentException when the component could not be found
*/
public function load($component, $settings = array()) {
if (is_array($settings) && isset($settings['className'])) {
if (isset($settings['className'])) {
$alias = $component;
$component = $settings['className'];
}

View file

@ -1,16 +1,17 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller
* @since CakePHP(tm) v 0.2.9
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('CakeResponse', 'Network');
@ -26,20 +27,20 @@ App::uses('CakeEventManager', 'Event');
* Provides basic functionality, such as rendering views inside layouts,
* automatic model availability, redirection, callbacks, and more.
*
* Controllers should provide a number of 'action' methods. These are public methods on the controller
* that are not prefixed with a '_' and not part of Controller. Each action serves as an endpoint for
* performing a specific action on a resource or collection of resources. For example adding or editing a new
* Controllers should provide a number of 'action' methods. These are public methods on the controller
* that are not prefixed with a '_' and not part of Controller. Each action serves as an endpoint for
* performing a specific action on a resource or collection of resources. For example: adding or editing a new
* object, or listing a set of objects.
*
* You can access request parameters, using `$this->request`. The request object contains all the POST, GET and FILES
* You can access request parameters, using `$this->request`. The request object contains all the POST, GET and FILES
* that were part of the request.
*
* After performing the required actions, controllers are responsible for creating a response. This usually
* takes the form of a generated View, or possibly a redirection to another controller action. In either case
* After performing the required actions, controllers are responsible for creating a response. This usually
* takes the form of a generated View, or possibly a redirection to another controller action. In either case
* `$this->response` allows you to manipulate all aspects of the response.
*
* Controllers are created by Dispatcher based on request parameters and routing. By default controllers and actions
* use conventional names. For example `/posts/index` maps to `PostsController::index()`. You can re-map urls
* use conventional names. For example `/posts/index` maps to `PostsController::index()`. You can re-map URLs
* using Router::connect().
*
* @package Cake.Controller
@ -51,9 +52,10 @@ App::uses('CakeEventManager', 'Event');
* @property RequestHandlerComponent $RequestHandler
* @property SecurityComponent $Security
* @property SessionComponent $Session
* @property FlashComponent $Flash
* @link http://book.cakephp.org/2.0/en/controllers.html
*/
class Controller extends Object implements CakeEventListener {
class Controller extends CakeObject implements CakeEventListener {
/**
* The name of this controller. Controller names are plural, named after the model they manipulate.
@ -78,18 +80,18 @@ class Controller extends Object implements CakeEventListener {
*
* The default value is `true`.
*
* @var mixed A single name as a string or a list of names as an array.
* @var mixed
* @link http://book.cakephp.org/2.0/en/controllers.html#components-helpers-and-uses
*/
public $uses = true;
/**
* An array containing the names of helpers this controller uses. The array elements should
* not contain the "Helper" part of the classname.
* not contain the "Helper" part of the class name.
*
* Example: `public $helpers = array('Html', 'Javascript', 'Time', 'Ajax');`
* Example: `public $helpers = array('Html', 'Js', 'Time', 'Ajax');`
*
* @var mixed A single name as a string or a list of names as an array.
* @var mixed
* @link http://book.cakephp.org/2.0/en/controllers.html#components-helpers-and-uses
*/
public $helpers = array();
@ -113,7 +115,7 @@ class Controller extends Object implements CakeEventListener {
public $response;
/**
* The classname to use for creating the response object.
* The class name to use for creating the response object.
*
* @var string
*/
@ -161,14 +163,14 @@ class Controller extends Object implements CakeEventListener {
* Set to true to automatically render the view
* after action logic.
*
* @var boolean
* @var bool
*/
public $autoRender = true;
/**
* Set to true to automatically render the layout around views.
*
* @var boolean
* @var bool
*/
public $autoLayout = true;
@ -181,14 +183,14 @@ class Controller extends Object implements CakeEventListener {
/**
* Array containing the names of components this controller uses. Component names
* should not contain the "Component" portion of the classname.
* should not contain the "Component" portion of the class name.
*
* Example: `public $components = array('Session', 'RequestHandler', 'Acl');`
*
* @var array
* @link http://book.cakephp.org/2.0/en/controllers/components.html
*/
public $components = array('Session');
public $components = array('Session', 'Flash');
/**
* The name of the View class this controller sends output to.
@ -206,7 +208,7 @@ class Controller extends Object implements CakeEventListener {
public $View;
/**
* File extension for view templates. Defaults to Cake's conventional ".ctp".
* File extension for view templates. Defaults to CakePHP's conventional ".ctp".
*
* @var string
*/
@ -226,12 +228,12 @@ class Controller extends Object implements CakeEventListener {
*
* Example:
*
* {{{
* ```
* public $cacheAction = array(
* 'view/23/' => 21600,
* 'recalled/' => 86400
* );
* }}}
* ```
*
* $cacheAction can also be set to a strtotime() compatible string. This
* marks all the actions in the controller for view caching.
@ -258,7 +260,7 @@ class Controller extends Object implements CakeEventListener {
/**
* Holds current methods of the controller. This is a list of all the methods reachable
* via url. Modifying this array, will allow you to change which methods can be reached.
* via URL. Modifying this array will allow you to change which methods can be reached.
*
* @var array
*/
@ -284,9 +286,9 @@ class Controller extends Object implements CakeEventListener {
public $modelKey = null;
/**
* Holds any validation errors produced by the last call of the validateErrors() method/
* Holds any validation errors produced by the last call of the validateErrors() method.
*
* @var array Validation errors, or false if none
* @var array
*/
public $validationErrors = null;
@ -319,7 +321,7 @@ class Controller extends Object implements CakeEventListener {
$this->name = substr(get_class($this), 0, -10);
}
if ($this->viewPath == null) {
if (!$this->viewPath) {
$this->viewPath = $this->name;
}
@ -345,8 +347,8 @@ class Controller extends Object implements CakeEventListener {
* Provides backwards compatibility to avoid problems with empty and isset to alias properties.
* Lazy loads models using the loadModel() method if declared in $uses
*
* @param string $name
* @return void
* @param string $name Property name to check.
* @return bool
*/
public function __isset($name) {
switch ($name) {
@ -383,8 +385,8 @@ class Controller extends Object implements CakeEventListener {
* Provides backwards compatibility access to the request object properties.
* Also provides the params alias.
*
* @param string $name
* @return void
* @param string $name The name of the requested value
* @return mixed The requested value for valid variables/aliases else null
*/
public function __get($name) {
switch ($name) {
@ -411,8 +413,8 @@ class Controller extends Object implements CakeEventListener {
/**
* Provides backwards compatibility access for setting values to the request object.
*
* @param string $name
* @param mixed $value
* @param string $name Property name to set.
* @param mixed $value Value to set.
* @return void
*/
public function __set($name, $value) {
@ -421,20 +423,24 @@ class Controller extends Object implements CakeEventListener {
case 'here':
case 'webroot':
case 'data':
return $this->request->{$name} = $value;
$this->request->{$name} = $value;
return;
case 'action':
return $this->request->params['action'] = $value;
$this->request->params['action'] = $value;
return;
case 'params':
return $this->request->params = $value;
$this->request->params = $value;
return;
case 'paginate':
return $this->Components->load('Paginator')->settings = $value;
$this->Components->load('Paginator')->settings = $value;
return;
}
return $this->{$name} = $value;
$this->{$name} = $value;
}
/**
* Sets the request objects and configures a number of controller properties
* based on the contents of the request. The properties that get set are
* based on the contents of the request. The properties that get set are
*
* - $this->request - To the $request parameter
* - $this->plugin - To the $request->params['plugin']
@ -443,7 +449,7 @@ class Controller extends Object implements CakeEventListener {
* - $this->autoRender - To false if $request->params['return'] == 1
* - $this->passedArgs - The the combined results of params['named'] and params['pass]
*
* @param CakeRequest $request
* @param CakeRequest $request Request instance.
* @return void
*/
public function setRequest(CakeRequest $request) {
@ -454,7 +460,7 @@ class Controller extends Object implements CakeEventListener {
$this->passedArgs = array_merge($request->params['pass'], $request->params['named']);
}
if (array_key_exists('return', $request->params) && $request->params['return'] == 1) {
if (!empty($request->params['return']) && $request->params['return'] == 1) {
$this->autoRender = false;
}
if (!empty($request->params['bare'])) {
@ -463,10 +469,10 @@ class Controller extends Object implements CakeEventListener {
}
/**
* Dispatches the controller action. Checks that the action
* Dispatches the controller action. Checks that the action
* exists and isn't private.
*
* @param CakeRequest $request
* @param CakeRequest $request Request instance.
* @return mixed The resulting response.
* @throws PrivateActionException When actions are not public or prefixed by _
* @throws MissingActionException When actions are not defined and scaffolding is
@ -501,20 +507,20 @@ class Controller extends Object implements CakeEventListener {
*
* @param ReflectionMethod $method The method to be invoked.
* @param CakeRequest $request The request to check.
* @return boolean
* @return bool
*/
protected function _isPrivateAction(ReflectionMethod $method, CakeRequest $request) {
$privateAction = (
$method->name[0] === '_' ||
!$method->isPublic() ||
!in_array($method->name, $this->methods)
!in_array($method->name, $this->methods)
);
$prefixes = Router::prefixes();
$prefixes = array_map('strtolower', Router::prefixes());
if (!$privateAction && !empty($prefixes)) {
if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) {
list($prefix) = explode('_', $request->params['action']);
$privateAction = in_array($prefix, $prefixes);
$privateAction = in_array(strtolower($prefix), $prefixes);
}
}
return $privateAction;
@ -523,7 +529,7 @@ class Controller extends Object implements CakeEventListener {
/**
* Returns a scaffold object to use for dynamically scaffolded controllers.
*
* @param CakeRequest $request
* @param CakeRequest $request Request instance.
* @return Scaffold
*/
protected function _getScaffold(CakeRequest $request) {
@ -605,8 +611,8 @@ class Controller extends Object implements CakeEventListener {
}
/**
* Returns a list of all events that will fire in the controller during it's lifecycle.
* You can override this function to add you own listener callbacks
* Returns a list of all events that will fire in the controller during its lifecycle.
* You can override this function to add your own listener callbacks
*
* @return array
*/
@ -631,11 +637,11 @@ class Controller extends Object implements CakeEventListener {
*/
public function constructClasses() {
$this->_mergeControllerVars();
$this->Components->init($this);
if ($this->uses) {
$this->uses = (array)$this->uses;
list(, $this->modelClass) = pluginSplit(current($this->uses));
list(, $this->modelClass) = pluginSplit(reset($this->uses));
}
$this->Components->init($this);
return true;
}
@ -664,6 +670,8 @@ class Controller extends Object implements CakeEventListener {
* - triggers Component `startup` methods.
*
* @return void
* @triggers Controller.initialize $this
* @triggers Controller.startup $this
*/
public function startupProcess() {
$this->getEventManager()->dispatch(new CakeEvent('Controller.initialize', $this));
@ -678,6 +686,7 @@ class Controller extends Object implements CakeEventListener {
* - calls the Controller's `afterFilter` method.
*
* @return void
* @triggers Controller.shutdown $this
*/
public function shutdownProcess() {
$this->getEventManager()->dispatch(new CakeEvent('Controller.shutdown', $this));
@ -686,7 +695,7 @@ class Controller extends Object implements CakeEventListener {
/**
* Queries & sets valid HTTP response codes & messages.
*
* @param integer|array $code If $code is an integer, then the corresponding code/message is
* @param int|array $code If $code is an integer, then the corresponding code/message is
* returned if it exists, null if it does not exist. If $code is an array,
* then the 'code' and 'message' keys of each nested array are added to the default
* HTTP codes. Example:
@ -700,7 +709,7 @@ class Controller extends Object implements CakeEventListener {
*
* @return array Associative array of the HTTP codes as keys, and the message
* strings as values, or null of the given $code does not exist.
* @deprecated Use CakeResponse::httpCodes();
* @deprecated 3.0.0 Since 2.4. Will be removed in 3.0. Use CakeResponse::httpCodes().
*/
public function httpCodes($code = null) {
return $this->response->httpCodes($code);
@ -708,12 +717,12 @@ class Controller extends Object implements CakeEventListener {
/**
* Loads and instantiates models required by this controller.
* If the model is non existent, it will throw a missing database table error, as Cake generates
* If the model is non existent, it will throw a missing database table error, as CakePHP generates
* dynamic models for the time being.
*
* @param string $modelClass Name of model class to load
* @param integer|string $id Initial ID the instanced model class should have
* @return mixed true when single model found and instance created, error returned if model not found.
* @param int|string $id Initial ID the instanced model class should have
* @return bool True if the model was found
* @throws MissingModelException if the model class cannot be found.
*/
public function loadModel($modelClass = null, $id = null) {
@ -722,7 +731,7 @@ class Controller extends Object implements CakeEventListener {
}
$this->uses = ($this->uses) ? (array)$this->uses : array();
if (!in_array($modelClass, $this->uses)) {
if (!in_array($modelClass, $this->uses, true)) {
$this->uses[] = $modelClass;
}
@ -743,9 +752,10 @@ class Controller extends Object implements CakeEventListener {
*
* @param string|array $url A string or array-based URL pointing to another location within the app,
* or an absolute URL
* @param integer $status Optional HTTP status code (eg: 404)
* @param boolean $exit If true, exit() will be called after the redirect
* @return mixed void if $exit = false. Terminates script if $exit = true
* @param int|array|null $status HTTP status code (eg: 301). Defaults to 302 when null is passed.
* @param bool $exit If true, exit() will be called after the redirect
* @return \Cake\Network\Response|null
* @triggers Controller.beforeRedirect $this, array($url, $status, $exit)
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::redirect
*/
public function redirect($url, $status = null, $exit = true) {
@ -760,7 +770,7 @@ class Controller extends Object implements CakeEventListener {
$this->getEventManager()->dispatch($event);
if ($event->isStopped()) {
return;
return null;
}
$response = $event->result;
extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE);
@ -776,14 +786,17 @@ class Controller extends Object implements CakeEventListener {
}
}
if ($status) {
$this->response->statusCode($status);
if ($status === null) {
$status = 302;
}
$this->response->statusCode($status);
if ($exit) {
$this->response->send();
$this->_stop();
}
return $this->response;
}
/**
@ -791,8 +804,8 @@ class Controller extends Object implements CakeEventListener {
*
* @param mixed $response Response from beforeRedirect callback
* @param string|array $url The same value of beforeRedirect
* @param integer $status The same value of beforeRedirect
* @param boolean $exit The same value of beforeRedirect
* @param int $status The same value of beforeRedirect
* @param bool $exit The same value of beforeRedirect
* @return array Array with keys url, status and exit
*/
protected function _parseBeforeRedirect($response, $url, $status, $exit) {
@ -815,7 +828,7 @@ class Controller extends Object implements CakeEventListener {
*
* @param string $status The header message that is being set.
* @return void
* @deprecated Use CakeResponse::header()
* @deprecated 3.0.0 Will be removed in 3.0. Use CakeResponse::header().
*/
public function header($status) {
$this->response->header($status);
@ -848,14 +861,13 @@ class Controller extends Object implements CakeEventListener {
*
* Examples:
*
* {{{
* ```
* setAction('another_action');
* setAction('action_with_parameters', $parameter1);
* }}}
* ```
*
* @param string $action The new action to be 'redirected' to
* @param mixed Any other parameters passed to this method will be passed as
* parameters to the new action.
* @param string $action The new action to be 'redirected' to.
* Any other parameters passed to this method will be passed as parameters to the new action.
* @return mixed Returns the return value of the called action
*/
public function setAction($action) {
@ -869,7 +881,8 @@ class Controller extends Object implements CakeEventListener {
/**
* Returns number of errors in a submitted FORM.
*
* @return integer Number of errors
* @return int Number of errors
* @deprecated 3.0.0 This method will be removed in 3.0
*/
public function validate() {
$args = func_get_args();
@ -882,12 +895,13 @@ class Controller extends Object implements CakeEventListener {
}
/**
* Validates models passed by parameters. Example:
* Validates models passed by parameters. Takes a list of models as a variable argument.
* Example:
*
* `$errors = $this->validateErrors($this->Article, $this->User);`
*
* @param mixed A list of models as a variable argument
* @return array Validation errors, or false if none
* @deprecated 3.0.0 This method will be removed in 3.0
*/
public function validateErrors() {
$objects = func_get_args();
@ -914,6 +928,7 @@ class Controller extends Object implements CakeEventListener {
* @param string $view View to use for rendering
* @param string $layout Layout to use
* @return CakeResponse A response object containing the rendered view.
* @triggers Controller.beforeRender $this
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::render
*/
public function render($view = null, $layout = null) {
@ -931,29 +946,21 @@ class Controller extends Object implements CakeEventListener {
}
}
$viewClass = $this->viewClass;
if ($this->viewClass != 'View') {
list($plugin, $viewClass) = pluginSplit($viewClass, true);
$viewClass = $viewClass . 'View';
App::uses($viewClass, $plugin . 'View');
}
$View = new $viewClass($this);
$this->View = $this->_getViewObject();
$models = ClassRegistry::keys();
foreach ($models as $currentModel) {
$currentObject = ClassRegistry::getObject($currentModel);
if (is_a($currentObject, 'Model')) {
if ($currentObject instanceof Model) {
$className = get_class($currentObject);
list($plugin) = pluginSplit(App::location($className));
$this->request->params['models'][$currentObject->alias] = compact('plugin', 'className');
$View->validationErrors[$currentObject->alias] =& $currentObject->validationErrors;
$this->View->validationErrors[$currentObject->alias] =& $currentObject->validationErrors;
}
}
$this->autoRender = false;
$this->View = $View;
$this->response->body($View->render($view, $layout));
$this->response->body($this->View->render($view, $layout));
return $this->response;
}
@ -961,19 +968,20 @@ class Controller extends Object implements CakeEventListener {
* Returns the referring URL for this request.
*
* @param string $default Default URL to use if HTTP_REFERER cannot be read from headers
* @param boolean $local If true, restrict referring URLs to local server
* @param bool $local If true, restrict referring URLs to local server
* @return string Referring URL
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::referer
*/
public function referer($default = null, $local = false) {
if ($this->request) {
$referer = $this->request->referer($local);
if ($referer == '/' && $default != null) {
return Router::url($default, true);
}
return $referer;
if (!$this->request) {
return '/';
}
return '/';
$referer = $this->request->referer($local);
if ($referer === '/' && $default && $default !== $referer) {
return Router::url($default, !$local);
}
return $referer;
}
/**
@ -981,7 +989,7 @@ class Controller extends Object implements CakeEventListener {
*
* @return void
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::disableCache
* @deprecated Use CakeResponse::disableCache()
* @deprecated 3.0.0 Will be removed in 3.0. Use CakeResponse::disableCache().
*/
public function disableCache() {
$this->response->disableCache();
@ -994,17 +1002,18 @@ class Controller extends Object implements CakeEventListener {
*
* @param string $message Message to display to the user
* @param string|array $url Relative string or array-based URL to redirect to after the time expires
* @param integer $pause Time to show the message
* @param int $pause Time to show the message
* @param string $layout Layout you want to use, defaults to 'flash'
* @return void Renders flash layout
* @return void
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::flash
* @deprecated 3.0.0 Will be removed in 3.0. Use Flash::set() with version 2.7+ or Session::setFlash() prior to 2.7.
*/
public function flash($message, $url, $pause = 1, $layout = 'flash') {
$this->autoRender = false;
$this->set('url', Router::url($url));
$this->set('message', $message);
$this->set('pause', $pause);
$this->set('page_title', $message);
$this->set('pageTitle', $message);
$this->render(false, $layout);
}
@ -1015,10 +1024,10 @@ class Controller extends Object implements CakeEventListener {
* @param string|array $op A string containing an SQL comparison operator, or an array matching operators
* to fields
* @param string $bool SQL boolean operator: AND, OR, XOR, etc.
* @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be
* @param bool $exclusive If true, and $op is an array, fields not included in $op will not be
* included in the returned conditions
* @return array An array of model conditions
* @deprecated
* @return array|null An array of model conditions
* @deprecated 3.0.0 Will be removed in 3.0.
*/
public function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) {
if (!is_array($data) || empty($data)) {
@ -1055,13 +1064,13 @@ class Controller extends Object implements CakeEventListener {
if ($fieldOp === 'LIKE') {
$key = $key . ' LIKE';
$value = '%' . $value . '%';
} elseif ($fieldOp && $fieldOp != '=') {
} elseif ($fieldOp && $fieldOp !== '=') {
$key = $key . ' ' . $fieldOp;
}
$cond[$key] = $value;
}
}
if ($bool != null && strtoupper($bool) != 'AND') {
if ($bool && strtoupper($bool) !== 'AND') {
$cond = array($bool => $cond);
}
return $cond;
@ -1075,14 +1084,13 @@ class Controller extends Object implements CakeEventListener {
* @param array $whitelist List of allowed options for paging
* @return array Model query results
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::paginate
* @deprecated Use PaginatorComponent instead
*/
public function paginate($object = null, $scope = array(), $whitelist = array()) {
return $this->Components->load('Paginator', $this->paginate)->paginate($object, $scope, $whitelist);
}
/**
* Called before the controller action. You can use this method to configure and customize components
* Called before the controller action. You can use this method to configure and customize components
* or perform logic that needs to happen before each controller action.
*
* @return void
@ -1103,18 +1111,20 @@ class Controller extends Object implements CakeEventListener {
/**
* The beforeRedirect method is invoked when the controller's redirect method is called but before any
* further action. If this method returns false the controller will not continue on to redirect the request.
* further action.
*
* If this method returns false the controller will not continue on to redirect the request.
* The $url, $status and $exit variables have same meaning as for the controller's method. You can also
* return a string which will be interpreted as the url to redirect to or return associative array with
* return a string which will be interpreted as the URL to redirect to or return associative array with
* key 'url' and optionally 'status' and 'exit'.
*
* @param string|array $url A string or array-based URL pointing to another location within the app,
* or an absolute URL
* @param integer $status Optional HTTP status code (eg: 404)
* @param boolean $exit If true, exit() will be called after the redirect
* @param int $status Optional HTTP status code (eg: 404)
* @param bool $exit If true, exit() will be called after the redirect
* @return mixed
* false to stop redirection event,
* string controllers a new redirection url or
* string controllers a new redirection URL or
* array with the keys url, status and exit to be used by the redirect method.
* @link http://book.cakephp.org/2.0/en/controllers.html#request-life-cycle-callbacks
*/
@ -1134,7 +1144,7 @@ class Controller extends Object implements CakeEventListener {
* This method should be overridden in child classes.
*
* @param string $method name of method called example index, edit, etc.
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
*/
public function beforeScaffold($method) {
@ -1144,10 +1154,10 @@ class Controller extends Object implements CakeEventListener {
/**
* Alias to beforeScaffold()
*
* @param string $method
* @return boolean
* @param string $method Method name.
* @return bool
* @see Controller::beforeScaffold()
* @deprecated
* @deprecated 3.0.0 Will be removed in 3.0.
*/
protected function _beforeScaffold($method) {
return $this->beforeScaffold($method);
@ -1157,7 +1167,7 @@ class Controller extends Object implements CakeEventListener {
* This method should be overridden in child classes.
*
* @param string $method name of method called either edit or update.
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
*/
public function afterScaffoldSave($method) {
@ -1167,10 +1177,10 @@ class Controller extends Object implements CakeEventListener {
/**
* Alias to afterScaffoldSave()
*
* @param string $method
* @return boolean
* @param string $method Method name.
* @return bool
* @see Controller::afterScaffoldSave()
* @deprecated
* @deprecated 3.0.0 Will be removed in 3.0.
*/
protected function _afterScaffoldSave($method) {
return $this->afterScaffoldSave($method);
@ -1180,7 +1190,7 @@ class Controller extends Object implements CakeEventListener {
* This method should be overridden in child classes.
*
* @param string $method name of method called either edit or update.
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
*/
public function afterScaffoldSaveError($method) {
@ -1190,10 +1200,10 @@ class Controller extends Object implements CakeEventListener {
/**
* Alias to afterScaffoldSaveError()
*
* @param string $method
* @return boolean
* @param string $method Method name.
* @return bool
* @see Controller::afterScaffoldSaveError()
* @deprecated
* @deprecated 3.0.0 Will be removed in 3.0.
*/
protected function _afterScaffoldSaveError($method) {
return $this->afterScaffoldSaveError($method);
@ -1205,7 +1215,7 @@ class Controller extends Object implements CakeEventListener {
* Method MUST return true in child classes
*
* @param string $method name of method called example index, edit, etc.
* @return boolean Success
* @return bool Success
* @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
*/
public function scaffoldError($method) {
@ -1215,13 +1225,29 @@ class Controller extends Object implements CakeEventListener {
/**
* Alias to scaffoldError()
*
* @param string $method
* @return boolean
* @param string $method Method name.
* @return bool
* @see Controller::scaffoldError()
* @deprecated
* @deprecated 3.0.0 Will be removed in 3.0.
*/
protected function _scaffoldError($method) {
return $this->scaffoldError($method);
}
/**
* Constructs the view class instance based on the controller property
*
* @return View
*/
protected function _getViewObject() {
$viewClass = $this->viewClass;
if ($this->viewClass !== 'View') {
list($plugin, $viewClass) = pluginSplit($viewClass, true);
$viewClass = $viewClass . 'View';
App::uses($viewClass, $plugin . 'View');
}
return new $viewClass($this);
}
}

View file

@ -4,21 +4,19 @@
*
* Automatic forms and actions generation for rapid web application development.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Controller
* @since Cake v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Scaffold', 'View');
/**
* Scaffolding is a set of automatic actions for starting web development work faster.
@ -28,7 +26,8 @@ App::uses('Scaffold', 'View');
* and afford the web developer an early look at the data, and the possibility to over-ride
* scaffolded actions with custom-made ones.
*
* @package Cake.Controller
* @package Cake.Controller
* @deprecated 3.0.0 Dynamic scaffolding will be removed and replaced in 3.0
*/
class Scaffold {
@ -77,7 +76,7 @@ class Scaffold {
/**
* Valid session.
*
* @var boolean
* @var bool
*/
protected $_validSession = null;
@ -137,7 +136,7 @@ class Scaffold {
$associations = $this->_associations();
$this->controller->set(compact(
'title_for_layout', 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
'singularHumanName', 'pluralHumanName', 'scaffoldFields', 'associations'
));
$this->controller->set('title_for_layout', $title);
@ -146,7 +145,9 @@ class Scaffold {
$this->controller->viewClass = 'Scaffold';
}
$this->_validSession = (
isset($this->controller->Session) && $this->controller->Session->valid() != false
isset($this->controller->Session) &&
$this->controller->Session->valid() &&
isset($this->controller->Flash)
);
$this->_scaffold($request);
}
@ -199,7 +200,7 @@ class Scaffold {
* Renders an add or edit action for scaffolded model.
*
* @param string $action Action (add or edit)
* @return mixed A rendered view with a form to edit or add a record in the Models database table
* @return void
*/
protected function _scaffoldForm($action = 'edit') {
$this->controller->viewVars['scaffoldFields'] = array_merge(
@ -226,7 +227,7 @@ class Scaffold {
}
if ($this->controller->beforeScaffold($action)) {
if ($action == 'edit') {
if ($action === 'edit') {
if (isset($request->params['pass'][0])) {
$this->ScaffoldModel->id = $request['pass'][0];
}
@ -236,7 +237,7 @@ class Scaffold {
}
if (!empty($request->data)) {
if ($action == 'create') {
if ($action === 'create') {
$this->ScaffoldModel->create();
}
@ -247,14 +248,12 @@ class Scaffold {
Inflector::humanize($this->modelKey),
$success
);
return $this->_sendMessage($message);
} else {
return $this->controller->afterScaffoldSaveError($action);
}
} else {
if ($this->_validSession) {
$this->controller->Session->setFlash(__d('cake', 'Please correct errors below.'));
return $this->_sendMessage($message, 'success');
}
return $this->controller->afterScaffoldSaveError($action);
}
if ($this->_validSession) {
$this->controller->Flash->set(__d('cake', 'Please correct errors below.'));
}
}
@ -306,34 +305,33 @@ class Scaffold {
}
if ($this->ScaffoldModel->delete()) {
$message = __d('cake', 'The %1$s with id: %2$s has been deleted.', Inflector::humanize($this->modelClass), $id);
return $this->_sendMessage($message);
} else {
$message = __d('cake',
'There was an error deleting the %1$s with id: %2$s',
Inflector::humanize($this->modelClass),
$id
);
return $this->_sendMessage($message);
return $this->_sendMessage($message, 'success');
}
$message = __d('cake',
'There was an error deleting the %1$s with id: %2$s',
Inflector::humanize($this->modelClass),
$id
);
return $this->_sendMessage($message);
} elseif ($this->controller->scaffoldError('delete') === false) {
return $this->_scaffoldError();
}
}
/**
* Sends a message to the user. Either uses Sessions or flash messages depending
* Sends a message to the user. Either uses Sessions or flash messages depending
* on the availability of a session
*
* @param string $message Message to display
* @return void
* @param string $element Flash template to use
* @return \Cake\Network\Response|null
*/
protected function _sendMessage($message) {
protected function _sendMessage($message, $element = 'default') {
if ($this->_validSession) {
$this->controller->Session->setFlash($message);
$this->controller->redirect($this->redirect);
} else {
$this->controller->flash($message, $this->redirect);
$this->controller->Flash->set($message, compact('element'));
return $this->controller->redirect($this->redirect);
}
$this->controller->flash($message, $this->redirect);
}
/**
@ -351,7 +349,7 @@ class Scaffold {
* `public $scaffold;` is placed in the controller's class definition.
*
* @param CakeRequest $request Request object for scaffolding
* @return mixed A rendered view of scaffold action, or showing the error
* @return void
* @throws MissingActionException When methods are not scaffolded.
* @throws MissingDatabaseException When the database connection is undefined.
*/
@ -386,25 +384,25 @@ class Scaffold {
case 'index':
case 'list':
$this->_scaffoldIndex($request);
break;
break;
case 'view':
$this->_scaffoldView($request);
break;
break;
case 'add':
case 'create':
$this->_scaffoldSave($request, 'add');
break;
break;
case 'edit':
case 'update':
$this->_scaffoldSave($request, 'edit');
break;
break;
case 'delete':
$this->_scaffoldDelete($request);
break;
break;
}
} else {
throw new MissingActionException(array(
'controller' => $this->controller->name,
'controller' => get_class($this->controller),
'action' => $request->action
));
}
@ -422,7 +420,7 @@ class Scaffold {
$keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
$associations = array();
foreach ($keys as $key => $type) {
foreach ($keys as $type) {
foreach ($this->ScaffoldModel->{$type} as $assocKey => $assocData) {
$associations[$type][$assocKey]['primaryKey'] =
$this->ScaffoldModel->{$assocKey}->primaryKey;
@ -442,7 +440,7 @@ class Scaffold {
$associations[$type][$assocKey]['controller'] =
Inflector::pluralize(Inflector::underscore($model));
if ($type == 'hasAndBelongsToMany') {
if ($type === 'hasAndBelongsToMany') {
$associations[$type][$assocKey]['with'] = $assocData['with'];
}
}