This commit is contained in:
planardothum 2012-11-13 19:50:38 -05:00
commit d1a591bd44
213 changed files with 11037 additions and 3108 deletions

View file

@ -1,11 +1,5 @@
<?php <?php
/** /**
* This is i18n Schema file
*
* Use it to configure database for i18n
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* *
@ -19,15 +13,16 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
// @codingStandardsIgnoreStart /**
/*
* *
* Using the Schema command line utility * Using the Schema command line utility
*
* Use it to configure database for i18n
*
* cake schema run create i18n * cake schema run create i18n
*/ */
class i18nSchema extends CakeSchema { // @codingStandardsIgnoreStart
class I18nSchema extends CakeSchema {
// @codingStandardsIgnoreEnd // @codingStandardsIgnoreEnd
public $name = 'i18n'; public $name = 'i18n';

View file

@ -232,17 +232,16 @@
//date_default_timezone_set('UTC'); //date_default_timezone_set('UTC');
/** /**
* Pick the caching engine to use. If APC is enabled use it. * Configure the cache handlers that CakePHP will use for internal
* If running via cli - apc is disabled by default. ensure it's available and enabled in this case * metadata like class maps, and model schema.
*
* By default File is used, but for improved performance you should use APC.
* *
* Note: 'default' and other application caches should be configured in app/Config/bootstrap.php. * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php.
* Please check the comments in boostrap.php for more info on the cache engines available * Please check the comments in boostrap.php for more info on the cache engines available
* and their setttings. * and their setttings.
*/ */
$engine = 'File'; $engine = 'File';
if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
$engine = 'Apc';
}
// In development mode, caches should expire quickly. // In development mode, caches should expire quickly.
$duration = '+999 days'; $duration = '+999 days';

View file

@ -17,17 +17,21 @@
# @license MIT License (http://www.opensource.org/licenses/mit-license.php) # @license MIT License (http://www.opensource.org/licenses/mit-license.php)
# #
################################################################################ ################################################################################
LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
while [ -h "$LIB" ]; do # Canonicalize by following every symlink of the given name recursively
DIR=$(dirname -- "$LIB") canonicalize() {
SYM=$(readlink "$LIB") NAME=$1
LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") while [ -h "$NAME" ]; do
done DIR=$(dirname -- "$NAME")
SYM=$(readlink "$NAME")
NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
echo "$NAME"
}
LIB=$(dirname -- "$LIB")/ CONSOLE=$(dirname $(canonicalize "$0"))
APP=$(dirname $(cd $(dirname $0) && pwd)) APP=$(dirname "$CONSOLE")
exec php -q "$LIB"cake.php -working "$APP" "$@" exec php -q $CONSOLE/cake.php -working "$APP" "$@"
exit; exit;

View file

@ -15,7 +15,7 @@
* @since CakePHP(tm) v 0.10.0.1076 * @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
if (Configure::read('debug') == 0): if (!Configure::read('debug')):
throw new NotFoundException(); throw new NotFoundException();
endif; endif;
App::uses('Debugger', 'Utility'); App::uses('Debugger', 'Utility');
@ -116,7 +116,7 @@ if (isset($filePresent)):
endif; endif;
?> ?>
</p> </p>
<?php endif;?> <?php endif; ?>
<?php <?php
App::uses('Validation', 'Utility'); App::uses('Validation', 'Utility');
if (!Validation::alphaNumeric('cakephp')) { if (!Validation::alphaNumeric('cakephp')) {
@ -127,6 +127,23 @@ if (isset($filePresent)):
echo '</span></p>'; echo '</span></p>';
} }
?> ?>
<p>
<?php
if (CakePlugin::loaded('DebugKit')):
echo '<span class="notice success">';
echo __d('cake_dev', 'DebugKit plugin is present');
echo '</span>';
else:
echo '<span class="notice">';
echo __d('cake_dev', 'DebugKit is not installed. It will help you inspect and debug different aspects of your application.');
echo '<br/>';
echo __d('cake_dev', 'You can install it from %s', $this->Html->link('github', 'https://github.com/cakephp/debug_kit'));
echo '</span>';
endif;
?>
</p>
<h3><?php echo __d('cake_dev', 'Editing this Page'); ?></h3> <h3><?php echo __d('cake_dev', 'Editing this Page'); ?></h3>
<p> <p>
<?php <?php
@ -156,6 +173,20 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
?> ?>
</p> </p>
<h3><?php echo __d('cake_dev', 'Official Plugins'); ?></h3>
<p>
<ul>
<li>
<?php echo $this->Html->link('DebugKit', 'https://github.com/cakephp/debug_kit') ?>:
<?php echo __d('cake_dev', 'provides a debugging toolbar and enhanced debugging tools for CakePHP applications.'); ?>
</li>
<li>
<?php echo $this->Html->link('Localized', 'https://github.com/cakephp/localized') ?>:
<?php echo __d('cake_dev', 'contains various localized validation classes and translations for specific countries'); ?>
</li>
</ul>
</p>
<h3><?php echo __d('cake_dev', 'More about Cake'); ?></h3> <h3><?php echo __d('cake_dev', 'More about Cake'); ?></h3>
<p> <p>
<?php echo __d('cake_dev', 'CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.'); ?> <?php echo __d('cake_dev', 'CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.'); ?>
@ -175,8 +206,8 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
<ul><li><?php echo __d('cake_dev', 'Quick Reference'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Quick Reference'); ?></li></ul></li>
<li><a href="http://bakery.cakephp.org"><?php echo __d('cake_dev', 'The Bakery'); ?> </a> <li><a href="http://bakery.cakephp.org"><?php echo __d('cake_dev', 'The Bakery'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'Everything CakePHP'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Everything CakePHP'); ?></li></ul></li>
<li><a href="http://live.cakephp.org"><?php echo __d('cake_dev', 'The Show'); ?> </a> <li><a href="http://plugins.cakephp.org"><?php echo __d('cake_dev', 'CakePHP plugins repo'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'The Show is a live and archived internet radio broadcast CakePHP-related topics and answer questions live via IRC, Skype, and telephone.'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'A comprehensive list of all CakePHP plugins created by the community'); ?></li></ul></li>
<li><a href="http://groups.google.com/group/cake-php"><?php echo __d('cake_dev', 'CakePHP Google Group'); ?> </a> <li><a href="http://groups.google.com/group/cake-php"><?php echo __d('cake_dev', 'CakePHP Google Group'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'Community mailing list'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Community mailing list'); ?></li></ul></li>
<li><a href="irc://irc.freenode.net/cakephp">irc.freenode.net #cakephp</a> <li><a href="irc://irc.freenode.net/cakephp">irc.freenode.net #cakephp</a>

View file

@ -70,6 +70,11 @@ if (!defined('WWW_ROOT')) {
define('WWW_ROOT', dirname(__FILE__) . DS); define('WWW_ROOT', dirname(__FILE__) . DS);
} }
// for built-in server
if (php_sapi_name() == 'cli-server') {
$_SERVER['PHP_SELF'] = '/' . basename(__FILE__);
}
if (!defined('CAKE_CORE_INCLUDE_PATH')) { if (!defined('CAKE_CORE_INCLUDE_PATH')) {
if (function_exists('ini_set')) { if (function_exists('ini_set')) {
ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
@ -89,4 +94,4 @@ if (!empty($failed)) {
App::uses('Dispatcher', 'Routing'); App::uses('Dispatcher', 'Routing');
$Dispatcher = new Dispatcher(); $Dispatcher = new Dispatcher();
$Dispatcher->dispatch(new CakeRequest(), new CakeResponse(array('charset' => Configure::read('App.encoding')))); $Dispatcher->dispatch(new CakeRequest(), new CakeResponse());

View file

@ -103,7 +103,7 @@ class Cache {
* - `path` Used by FileCache. Path to where cachefiles should be saved. * - `path` Used by FileCache. Path to where cachefiles should be saved.
* - `lock` Used by FileCache. Should files be locked before writing to them? * - `lock` Used by FileCache. Should files be locked before writing to them?
* - `user` Used by Xcache. Username for XCache * - `user` Used by Xcache. Username for XCache
* - `password` Used by Xcache. Password for XCache * - `password` Used by Xcache/Redis. Password for XCache/Redis
* *
* @see app/Config/core.php for configuration settings * @see app/Config/core.php for configuration settings
* @param string $name Name of the configuration * @param string $name Name of the configuration
@ -366,7 +366,7 @@ class Cache {
} }
$key = self::$_engines[$config]->key($key); $key = self::$_engines[$config]->key($key);
if (!$key || !is_integer($offset) || $offset < 0) { if (!$key || !is_int($offset) || $offset < 0) {
return false; return false;
} }
$success = self::$_engines[$config]->increment($settings['prefix'] . $key, $offset); $success = self::$_engines[$config]->increment($settings['prefix'] . $key, $offset);
@ -394,7 +394,7 @@ class Cache {
} }
$key = self::$_engines[$config]->key($key); $key = self::$_engines[$config]->key($key);
if (!$key || !is_integer($offset) || $offset < 0) { if (!$key || !is_int($offset) || $offset < 0) {
return false; return false;
} }
$success = self::$_engines[$config]->decrement($settings['prefix'] . $key, $offset); $success = self::$_engines[$config]->decrement($settings['prefix'] . $key, $offset);

View file

@ -61,9 +61,8 @@ class ApcEngine extends CacheEngine {
* @return boolean True if the data was successfully cached, false on failure * @return boolean True if the data was successfully cached, false on failure
*/ */
public function write($key, $value, $duration) { public function write($key, $value, $duration) {
if ($duration == 0) { $expires = 0;
$expires = 0; if ($duration) {
} else {
$expires = time() + $duration; $expires = time() + $duration;
} }
apc_store($key . '_expires', $expires, $duration); apc_store($key . '_expires', $expires, $duration);

View file

@ -62,6 +62,7 @@ class RedisEngine extends CacheEngine {
'prefix' => null, 'prefix' => null,
'server' => '127.0.0.1', 'server' => '127.0.0.1',
'port' => 6379, 'port' => 6379,
'password' => false,
'timeout' => 0, 'timeout' => 0,
'persistent' => true 'persistent' => true
), $settings) ), $settings)
@ -87,6 +88,9 @@ class RedisEngine extends CacheEngine {
} catch (RedisException $e) { } catch (RedisException $e) {
return false; return false;
} }
if ($return && $this->settings['password']) {
$return = $this->_Redis->auth($this->settings['password']);
}
return $return; return $return;
} }

3920
lib/Cake/Config/cacert.pem Normal file

File diff suppressed because it is too large Load diff

View file

@ -173,8 +173,10 @@ class IniReader implements ConfigReaderInterface {
public function dump($filename, $data) { public function dump($filename, $data) {
$result = array(); $result = array();
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
$isSection = false;
if ($key[0] != '[') { if ($key[0] != '[') {
$result[] = "[$key]"; $result[] = "[$key]";
$isSection = true;
} }
if (is_array($value)) { if (is_array($value)) {
$keyValues = Hash::flatten($value, '.'); $keyValues = Hash::flatten($value, '.');
@ -182,8 +184,11 @@ class IniReader implements ConfigReaderInterface {
$result[] = "$k = " . $this->_value($v); $result[] = "$k = " . $this->_value($v);
} }
} }
if ($isSection) {
$result[] = '';
}
} }
$contents = join("\n", $result); $contents = trim(implode("\n", $result));
if (substr($filename, -4) !== '.ini') { if (substr($filename, -4) !== '.ini') {
$filename .= '.ini'; $filename .= '.ini';

View file

@ -598,7 +598,7 @@ class AclShell extends AppShell {
* @return array Variables * @return array Variables
*/ */
protected function _dataVars($type = null) { protected function _dataVars($type = null) {
if ($type == null) { if (!$type) {
$type = $this->args[0]; $type = $this->args[0];
} }
$vars = array(); $vars = array();

View file

@ -73,12 +73,13 @@ class ApiShell extends AppShell {
$path = $this->paths['core']; $path = $this->paths['core'];
} }
if (count($this->args) == 1) { $count = count($this->args);
$file = $type; if ($count > 1) {
$class = Inflector::camelize($type);
} elseif (count($this->args) > 1) {
$file = Inflector::underscore($this->args[1]); $file = Inflector::underscore($this->args[1]);
$class = Inflector::camelize($this->args[1]); $class = Inflector::camelize($this->args[1]);
} elseif ($count) {
$file = $type;
$class = Inflector::camelize($type);
} }
$objects = App::objects('class', $path); $objects = App::objects('class', $path);
if (in_array($class, $objects)) { if (in_array($class, $objects)) {

View file

@ -182,7 +182,7 @@ class ConsoleShell extends AppShell {
$this->out(" - {$model}"); $this->out(" - {$model}");
} }
break; break;
case (preg_match("/^(\w+) bind (\w+) (\w+)/", $command, $tmp) == true): case preg_match("/^(\w+) bind (\w+) (\w+)/", $command, $tmp):
foreach ($tmp as $data) { foreach ($tmp as $data) {
$data = strip_tags($data); $data = strip_tags($data);
$data = str_replace($this->badCommandChars, "", $data); $data = str_replace($this->badCommandChars, "", $data);
@ -200,7 +200,7 @@ class ConsoleShell extends AppShell {
$this->out(__d('cake_console', "Please verify you are using valid models and association types")); $this->out(__d('cake_console', "Please verify you are using valid models and association types"));
} }
break; break;
case (preg_match("/^(\w+) unbind (\w+) (\w+)/", $command, $tmp) == true): case preg_match("/^(\w+) unbind (\w+) (\w+)/", $command, $tmp):
foreach ($tmp as $data) { foreach ($tmp as $data) {
$data = strip_tags($data); $data = strip_tags($data);
$data = str_replace($this->badCommandChars, "", $data); $data = str_replace($this->badCommandChars, "", $data);
@ -298,7 +298,7 @@ class ConsoleShell extends AppShell {
$this->out(__d('cake_console', 'Saved record for %s', $modelToSave)); $this->out(__d('cake_console', 'Saved record for %s', $modelToSave));
} }
break; break;
case (preg_match("/^(\w+) columns/", $command, $tmp) == true): case preg_match("/^(\w+) columns/", $command, $tmp):
$modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1])); $modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
if ($this->_isValidModel($modelToCheck)) { if ($this->_isValidModel($modelToCheck)) {
@ -315,22 +315,22 @@ class ConsoleShell extends AppShell {
$this->out(__d('cake_console', "Please verify that you selected a valid model")); $this->out(__d('cake_console', "Please verify that you selected a valid model"));
} }
break; break;
case (preg_match("/^routes\s+reload/i", $command, $tmp) == true): case preg_match("/^routes\s+reload/i", $command, $tmp):
if (!$this->_loadRoutes()) { if (!$this->_loadRoutes()) {
$this->err(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors.")); $this->err(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors."));
break; break;
} }
$this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes))); $this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes)));
break; break;
case (preg_match("/^routes\s+show/i", $command, $tmp) == true): case preg_match("/^routes\s+show/i", $command, $tmp):
$this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true)); $this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true));
break; break;
case (preg_match("/^route\s+(\(.*\))$/i", $command, $tmp) == true): case preg_match("/^route\s+(\(.*\))$/i", $command, $tmp):
if ($url = eval('return array' . $tmp[1] . ';')) { if ($url = eval('return array' . $tmp[1] . ';')) {
$this->out(Router::url($url)); $this->out(Router::url($url));
} }
break; break;
case (preg_match("/^route\s+(.*)/i", $command, $tmp) == true): case preg_match("/^route\s+(.*)/i", $command, $tmp):
$this->out(var_export(Router::parse($tmp[1]), true)); $this->out(var_export(Router::parse($tmp[1]), true));
break; break;
default: default:

View file

@ -89,6 +89,7 @@ class SchemaShell extends AppShell {
$name = $plugin; $name = $plugin;
} }
} }
$name = Inflector::classify($name);
$this->Schema = new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin')); $this->Schema = new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin'));
} }
@ -120,7 +121,9 @@ class SchemaShell extends AppShell {
$this->out(__d('cake_console', 'Generating Schema...')); $this->out(__d('cake_console', 'Generating Schema...'));
$options = array(); $options = array();
if ($this->params['force']) { if ($this->params['force']) {
$options = array('models' => false); $options['models'] = false;
} elseif (!empty($this->params['models'])) {
$options['models'] = String::tokenize($this->params['models']);
} }
$snapshot = false; $snapshot = false;
@ -459,6 +462,10 @@ class SchemaShell extends AppShell {
'short' => 's', 'short' => 's',
'help' => __d('cake_console', 'Snapshot number to use/make.') 'help' => __d('cake_console', 'Snapshot number to use/make.')
); );
$models = array(
'short' => 'm',
'help' => __d('cake_console', 'Specify models as comma separated list.'),
);
$dry = array( $dry = array(
'help' => __d('cake_console', 'Perform a dry run on create and update commands. Queries will be output instead of run.'), 'help' => __d('cake_console', 'Perform a dry run on create and update commands. Queries will be output instead of run.'),
'boolean' => true 'boolean' => true
@ -484,7 +491,7 @@ class SchemaShell extends AppShell {
))->addSubcommand('generate', array( ))->addSubcommand('generate', array(
'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'), 'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'),
'parser' => array( 'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force'), 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force', 'models'),
'arguments' => array( 'arguments' => array(
'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.')) 'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.'))
) )

View file

@ -0,0 +1,167 @@
<?php
/**
* built-in Server Shell
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.3.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('AppShell', 'Console/Command');
/**
* built-in Server Shell
*
* @package Cake.Console.Command
*/
class ServerShell extends AppShell {
/**
* Default ServerHost
*/
const DEFAULT_HOST = 'localhost';
/**
* Default ListenPort
*/
const DEFAULT_PORT = 80;
/**
* server host
*
* @var string
*/
protected $_host = null;
/**
* listen port
*
* @var string
*/
protected $_port = null;
/**
* document root
*
* @var string
*/
protected $_documentRoot = null;
/**
* Override initialize of the Shell
*
* @return void
*/
public function initialize() {
$this->_host = self::DEFAULT_HOST;
$this->_port = self::DEFAULT_PORT;
$this->_documentRoot = WWW_ROOT;
}
/**
* Starts up the Shell and displays the welcome message.
* Allows for checking and configuring prior to command or main execution
*
* Override this method if you want to remove the welcome information,
* or otherwise modify the pre-command flow.
*
* @return void
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup
*/
public function startup() {
if (!empty($this->params['host'])) {
$this->_host = $this->params['host'];
}
if (!empty($this->params['port'])) {
$this->_port = $this->params['port'];
}
if (!empty($this->params['document_root'])) {
$this->_documentRoot = $this->params['document_root'];
}
// for windows
if (substr($this->_documentRoot, -1, 1) == DIRECTORY_SEPARATOR) {
$this->_documentRoot = substr($this->_documentRoot, 0, strlen($this->_documentRoot) - 1);
}
if (preg_match("/^([a-z]:)[\\\]+(.+)$/i", $this->_documentRoot, $m)) {
$this->_documentRoot = $m[1] . '\\' . $m[2];
}
parent::startup();
}
/**
* Displays a header for the shell
*
* @return void
*/
protected function _welcome() {
$this->out();
$this->out(__d('cake_console', '<info>Welcome to CakePHP %s Console</info>', 'v' . Configure::version()));
$this->hr();
$this->out(__d('cake_console', 'App : %s', APP_DIR));
$this->out(__d('cake_console', 'Path: %s', APP));
$this->out(__d('cake_console', 'DocumentRoot: %s', $this->_documentRoot));
$this->hr();
}
/**
* Override main() to handle action
*
* @return void
*/
public function main() {
if (version_compare(PHP_VERSION, '5.4.0') < 0) {
$this->out(__d('cake_console', '<warning>This command is available on PHP5.4 or above</warning>'));
return;
}
$command = sprintf("php -S %s:%d -t %s",
$this->_host,
$this->_port,
$this->_documentRoot
);
$port = ($this->_port == self::DEFAULT_PORT) ? '' : ':' . $this->_port;
$this->out(__d('cake_console', 'built-in server is running in http://%s%s/', $this->_host, $port));
$ret = system($command);
}
/**
* Get and configure the optionparser.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->addOption('host', array(
'short' => 'H',
'help' => __d('cake_console', 'ServerHost')
));
$parser->addOption('port', array(
'short' => 'p',
'help' => __d('cake_console', 'ListenPort')
));
$parser->addOption('document_root', array(
'short' => 'd',
'help' => __d('cake_console', 'DocumentRoot')
));
$parser->description(array(
__d('cake_console', 'PHP Built-in Server for CakePHP'),
__d('cake_console', '<warning>[WARN] Don\'t use this at the production environment</warning>'),
));
return $parser;
}
}

View file

@ -349,7 +349,7 @@ class ControllerTask extends BakeTask {
public function doHelpers() { public function doHelpers() {
return $this->_doPropertyChoices( return $this->_doPropertyChoices(
__d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"), __d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"),
__d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Ajax, Javascript, Time'") __d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Text, Js, Time'")
); );
} }
@ -395,7 +395,7 @@ class ControllerTask extends BakeTask {
} }
$this->__tables = $this->Model->getAllTables($useDbConfig); $this->__tables = $this->Model->getAllTables($useDbConfig);
if ($this->interactive == true) { if ($this->interactive) {
$this->out(__d('cake_console', 'Possible Controllers based on your current database:')); $this->out(__d('cake_console', 'Possible Controllers based on your current database:'));
$this->hr(); $this->hr();
$this->_controllerNames = array(); $this->_controllerNames = array();
@ -419,20 +419,20 @@ class ControllerTask extends BakeTask {
$controllers = $this->listAll($useDbConfig); $controllers = $this->listAll($useDbConfig);
$enteredController = ''; $enteredController = '';
while ($enteredController == '') { while (!$enteredController) {
$enteredController = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q'); $enteredController = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q');
if ($enteredController === 'q') { if ($enteredController === 'q') {
$this->out(__d('cake_console', 'Exit')); $this->out(__d('cake_console', 'Exit'));
return $this->_stop(); return $this->_stop();
} }
if ($enteredController == '' || intval($enteredController) > count($controllers)) { if (!$enteredController || intval($enteredController) > count($controllers)) {
$this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again.")); $this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again."));
$enteredController = ''; $enteredController = '';
} }
} }
if (intval($enteredController) > 0 && intval($enteredController) <= count($controllers) ) { if (intval($enteredController) > 0 && intval($enteredController) <= count($controllers)) {
$controllerName = $controllers[intval($enteredController) - 1]; $controllerName = $controllers[intval($enteredController) - 1];
} else { } else {
$controllerName = Inflector::camelize($enteredController); $controllerName = Inflector::camelize($enteredController);

View file

@ -92,10 +92,10 @@ class DbConfigTask extends AppShell {
$done = false; $done = false;
$dbConfigs = array(); $dbConfigs = array();
while ($done == false) { while (!$done) {
$name = ''; $name = '';
while ($name == '') { while (!$name) {
$name = $this->in(__d('cake_console', "Name:"), null, 'default'); $name = $this->in(__d('cake_console', "Name:"), null, 'default');
if (preg_match('/[^a-z0-9_]/i', $name)) { if (preg_match('/[^a-z0-9_]/i', $name)) {
$name = ''; $name = '';
@ -116,12 +116,12 @@ class DbConfigTask extends AppShell {
} }
$host = ''; $host = '';
while ($host == '') { while (!$host) {
$host = $this->in(__d('cake_console', 'Database Host:'), null, 'localhost'); $host = $this->in(__d('cake_console', 'Database Host:'), null, 'localhost');
} }
$port = ''; $port = '';
while ($port == '') { while (!$port) {
$port = $this->in(__d('cake_console', 'Port?'), null, 'n'); $port = $this->in(__d('cake_console', 'Port?'), null, 'n');
} }
@ -130,16 +130,16 @@ class DbConfigTask extends AppShell {
} }
$login = ''; $login = '';
while ($login == '') { while (!$login) {
$login = $this->in(__d('cake_console', 'User:'), null, 'root'); $login = $this->in(__d('cake_console', 'User:'), null, 'root');
} }
$password = ''; $password = '';
$blankPassword = false; $blankPassword = false;
while ($password == '' && $blankPassword == false) { while (!$password && !$blankPassword) {
$password = $this->in(__d('cake_console', 'Password:')); $password = $this->in(__d('cake_console', 'Password:'));
if ($password == '') { if (!$password) {
$blank = $this->in(__d('cake_console', 'The password you supplied was empty. Use an empty password?'), array('y', 'n'), 'n'); $blank = $this->in(__d('cake_console', 'The password you supplied was empty. Use an empty password?'), array('y', 'n'), 'n');
if ($blank == 'y') { if ($blank == 'y') {
$blankPassword = true; $blankPassword = true;
@ -148,12 +148,12 @@ class DbConfigTask extends AppShell {
} }
$database = ''; $database = '';
while ($database == '') { while (!$database) {
$database = $this->in(__d('cake_console', 'Database Name:'), null, 'cake'); $database = $this->in(__d('cake_console', 'Database Name:'), null, 'cake');
} }
$prefix = ''; $prefix = '';
while ($prefix == '') { while (!$prefix) {
$prefix = $this->in(__d('cake_console', 'Table Prefix?'), null, 'n'); $prefix = $this->in(__d('cake_console', 'Table Prefix?'), null, 'n');
} }
if (strtolower($prefix) == 'n') { if (strtolower($prefix) == 'n') {
@ -161,7 +161,7 @@ class DbConfigTask extends AppShell {
} }
$encoding = ''; $encoding = '';
while ($encoding == '') { while (!$encoding) {
$encoding = $this->in(__d('cake_console', 'Table encoding?'), null, 'n'); $encoding = $this->in(__d('cake_console', 'Table encoding?'), null, 'n');
} }
if (strtolower($encoding) == 'n') { if (strtolower($encoding) == 'n') {
@ -170,7 +170,7 @@ class DbConfigTask extends AppShell {
$schema = ''; $schema = '';
if ($datasource == 'postgres') { if ($datasource == 'postgres') {
while ($schema == '') { while (!$schema) {
$schema = $this->in(__d('cake_console', 'Table schema?'), null, 'n'); $schema = $this->in(__d('cake_console', 'Table schema?'), null, 'n');
} }
} }
@ -180,7 +180,7 @@ class DbConfigTask extends AppShell {
$config = compact('name', 'datasource', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema'); $config = compact('name', 'datasource', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema');
while ($this->_verify($config) == false) { while (!$this->_verify($config)) {
$this->_interactive(); $this->_interactive();
} }
@ -277,11 +277,7 @@ class DbConfigTask extends AppShell {
$info['port'] = null; $info['port'] = null;
} }
if ($info['persistent'] === false) { $info['persistent'] = var_export((bool)$info['persistent'], true);
$info['persistent'] = 'false';
} else {
$info['persistent'] = ($info['persistent'] == true) ? 'true' : 'false';
}
$oldConfigs[] = array( $oldConfigs[] = array(
'name' => $configName, 'name' => $configName,

View file

@ -245,7 +245,7 @@ class ExtractTask extends AppShell {
if (empty($this->_translations[$domain][$msgid])) { if (empty($this->_translations[$domain][$msgid])) {
$this->_translations[$domain][$msgid] = array( $this->_translations[$domain][$msgid] = array(
'msgid_plural' => false 'msgid_plural' => false
); );
} }
if (isset($details['msgid_plural'])) { if (isset($details['msgid_plural'])) {
@ -391,7 +391,7 @@ class ExtractTask extends AppShell {
$position = $count; $position = $count;
$depth = 0; $depth = 0;
while ($depth == 0) { while (!$depth) {
if ($this->_tokens[$position] == '(') { if ($this->_tokens[$position] == '(') {
$depth++; $depth++;
} elseif ($this->_tokens[$position] == ')') { } elseif ($this->_tokens[$position] == ')') {
@ -480,7 +480,7 @@ class ExtractTask extends AppShell {
} }
$dims = Hash::dimensions($rules); $dims = Hash::dimensions($rules);
if ($dims == 1 || ($dims == 2 && isset($rules['message']))) { if ($dims === 1 || ($dims === 2 && isset($rules['message']))) {
$rules = array($rules); $rules = array($rules);
} }
@ -523,7 +523,7 @@ class ExtractTask extends AppShell {
$occurrences[] = $file . ':' . implode(';', $lines); $occurrences[] = $file . ':' . implode(';', $lines);
} }
$occurrences = implode("\n#: ", $occurrences); $occurrences = implode("\n#: ", $occurrences);
$header = '#: ' . str_replace($paths, '', $occurrences) . "\n"; $header = '#: ' . str_replace(DS, '/', str_replace($paths, '', $occurrences)) . "\n";
if ($plural === false) { if ($plural === false) {
$sentence = "msgid \"{$msgid}\"\n"; $sentence = "msgid \"{$msgid}\"\n";
@ -591,7 +591,7 @@ class ExtractTask extends AppShell {
); );
if (strtoupper($response) === 'N') { if (strtoupper($response) === 'N') {
$response = ''; $response = '';
while ($response == '') { while (!$response) {
$response = $this->in(__d('cake_console', "What would you like to name this file?"), null, 'new_' . $filename); $response = $this->in(__d('cake_console', "What would you like to name this file?"), null, 'new_' . $filename);
$File = new File($this->_output . $response); $File = new File($this->_output . $response);
$filename = $response; $filename = $response;

View file

@ -472,16 +472,14 @@ class ModelTask extends BakeTask {
} }
if ($choice != $defaultChoice) { if ($choice != $defaultChoice) {
$validate[$validatorName] = $choice;
if (is_numeric($choice) && isset($this->_validations[$choice])) { if (is_numeric($choice) && isset($this->_validations[$choice])) {
$validate[$validatorName] = $this->_validations[$choice]; $validate[$validatorName] = $this->_validations[$choice];
} else {
$validate[$validatorName] = $choice;
} }
} }
if ($this->interactive == true && $choice != $defaultChoice) { $anotherValidator = 'n';
if ($this->interactive && $choice != $defaultChoice) {
$anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n'); $anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n');
} else {
$anotherValidator = 'n';
} }
} }
return $validate; return $validate;
@ -583,7 +581,7 @@ class ModelTask extends BakeTask {
$pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/'; $pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
$possibleJoinTable = preg_match($pattern, $otherTable); $possibleJoinTable = preg_match($pattern, $otherTable);
if ($possibleJoinTable == true) { if ($possibleJoinTable) {
continue; continue;
} }
foreach ($modelFieldsTemp as $fieldName => $field) { foreach ($modelFieldsTemp as $fieldName => $field) {
@ -688,7 +686,7 @@ class ModelTask extends BakeTask {
$prompt = __d('cake_console', 'Would you like to define some additional model associations?'); $prompt = __d('cake_console', 'Would you like to define some additional model associations?');
$wannaDoMoreAssoc = $this->in($prompt, array('y', 'n'), 'n'); $wannaDoMoreAssoc = $this->in($prompt, array('y', 'n'), 'n');
$possibleKeys = $this->_generatePossibleKeys(); $possibleKeys = $this->_generatePossibleKeys();
while (strtolower($wannaDoMoreAssoc) == 'y') { while (strtolower($wannaDoMoreAssoc) === 'y') {
$assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
$this->out(__d('cake_console', 'What is the association type?')); $this->out(__d('cake_console', 'What is the association type?'));
$assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number'))); $assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number')));
@ -698,9 +696,9 @@ class ModelTask extends BakeTask {
$this->hr(); $this->hr();
$alias = $this->in(__d('cake_console', 'What is the alias for this association?')); $alias = $this->in(__d('cake_console', 'What is the alias for this association?'));
$className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias ); $className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias);
if ($assocType == 0) { if ($assocType === 0) {
if (!empty($possibleKeys[$model->table])) { if (!empty($possibleKeys[$model->table])) {
$showKeys = $possibleKeys[$model->table]; $showKeys = $possibleKeys[$model->table];
} else { } else {
@ -733,7 +731,7 @@ class ModelTask extends BakeTask {
if (!isset($foreignKey)) { if (!isset($foreignKey)) {
$foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey); $foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey);
} }
if ($assocType == 3) { if ($assocType === 3) {
$associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name)); $associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name));
$joinTable = $this->in(__d('cake_console', 'What is the joinTable?')); $joinTable = $this->in(__d('cake_console', 'What is the joinTable?'));
} }
@ -743,7 +741,7 @@ class ModelTask extends BakeTask {
$associations[$assocs[$assocType]][$i]['alias'] = $alias; $associations[$assocs[$assocType]][$i]['alias'] = $alias;
$associations[$assocs[$assocType]][$i]['className'] = $className; $associations[$assocs[$assocType]][$i]['className'] = $className;
$associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey; $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
if ($assocType == 3) { if ($assocType === 3) {
$associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey; $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
$associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable; $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
} }
@ -780,7 +778,7 @@ class ModelTask extends BakeTask {
*/ */
public function bake($name, $data = array()) { public function bake($name, $data = array()) {
if (is_object($name)) { if (is_object($name)) {
if ($data == false) { if (!$data) {
$data = array(); $data = array();
$data['associations'] = $this->doAssociations($name); $data['associations'] = $this->doAssociations($name);
$data['validate'] = $this->doValidation($name); $data['validate'] = $this->doValidation($name);
@ -935,7 +933,7 @@ class ModelTask extends BakeTask {
$enteredModel = ''; $enteredModel = '';
while ($enteredModel == '') { while (!$enteredModel) {
$enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\n" . $enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\n" .
"type in the name of another model, or 'q' to exit"), null, 'q'); "type in the name of another model, or 'q' to exit"), null, 'q');
@ -944,18 +942,17 @@ class ModelTask extends BakeTask {
$this->_stop(); $this->_stop();
} }
if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) { if (!$enteredModel || intval($enteredModel) > count($this->_modelNames)) {
$this->err(__d('cake_console', "The model name you supplied was empty,\n" . $this->err(__d('cake_console', "The model name you supplied was empty,\n" .
"or the number you selected was not an option. Please try again.")); "or the number you selected was not an option. Please try again."));
$enteredModel = ''; $enteredModel = '';
} }
} }
if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) { if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
$currentModelName = $this->_modelNames[intval($enteredModel) - 1]; return $this->_modelNames[intval($enteredModel) - 1];
} else {
$currentModelName = $enteredModel;
} }
return $currentModelName;
return $enteredModel;
} }
/** /**

View file

@ -66,7 +66,7 @@ class ProjectTask extends AppShell {
} }
$response = false; $response = false;
while ($response == false && is_dir($project) === true && file_exists($project . 'Config' . 'core.php')) { while (!$response && is_dir($project) === true && file_exists($project . 'Config' . 'core.php')) {
$prompt = __d('cake_console', '<warning>A project already exists in this location:</warning> %s Overwrite?', $project); $prompt = __d('cake_console', '<warning>A project already exists in this location:</warning> %s Overwrite?', $project);
$response = $this->in($prompt, array('y', 'n'), 'n'); $response = $this->in($prompt, array('y', 'n'), 'n');
if (strtolower($response) === 'n') { if (strtolower($response) === 'n') {
@ -92,6 +92,13 @@ class ProjectTask extends AppShell {
$success = false; $success = false;
} }
if ($this->cachePrefix($path)) {
$this->out(__d('cake_console', ' * Cache prefix set'));
} else {
$this->err(__d('cake_console', 'The cache prefix was <error>NOT</error> set'));
$success = false;
}
if ($this->consolePath($path) === true) { if ($this->consolePath($path) === true) {
$this->out(__d('cake_console', ' * app/Console/cake.php path set.')); $this->out(__d('cake_console', ' * app/Console/cake.php path set.'));
} else { } else {
@ -284,6 +291,23 @@ class ProjectTask extends AppShell {
return false; return false;
} }
/**
* Writes cache prefix using app's name
*
* @param string $dir Path to project
* @return boolean Success
*/
public function cachePrefix($dir) {
$app = basename($dir);
$File = new File($dir . 'Config' . DS . 'core.php');
$contents = $File->read();
if (preg_match('/(\$prefix = \'myapp_\';)/', $contents, $match)) {
$result = str_replace($match[0], '$prefix = \'' . $app . '_\';', $contents);
return $File->write($result);
}
return false;
}
/** /**
* Generates and writes CAKE_CORE_INCLUDE_PATH * Generates and writes CAKE_CORE_INCLUDE_PATH
* *
@ -325,10 +349,7 @@ class ProjectTask extends AppShell {
if (!file_put_contents($filename, $result)) { if (!file_put_contents($filename, $result)) {
return false; return false;
} }
if ($count == 0) { return (bool)$count;
return false;
}
return true;
} }
/** /**
@ -363,7 +384,7 @@ class ProjectTask extends AppShell {
$admin = ''; $admin = '';
$prefixes = Configure::read('Routing.prefixes'); $prefixes = Configure::read('Routing.prefixes');
if (!empty($prefixes)) { if (!empty($prefixes)) {
if (count($prefixes) == 1) { if (count($prefixes) === 1) {
return $prefixes[0] . '_'; return $prefixes[0] . '_';
} }
if ($this->interactive) { if ($this->interactive) {
@ -385,7 +406,7 @@ class ProjectTask extends AppShell {
$this->out(__d('cake_console', 'You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/Config/core.php to use prefix routing.')); $this->out(__d('cake_console', 'You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/Config/core.php to use prefix routing.'));
$this->out(__d('cake_console', 'What would you like the prefix route to be?')); $this->out(__d('cake_console', 'What would you like the prefix route to be?'));
$this->out(__d('cake_console', 'Example: www.example.com/admin/controller')); $this->out(__d('cake_console', 'Example: www.example.com/admin/controller'));
while ($admin == '') { while (!$admin) {
$admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin'); $admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin');
} }
if ($this->cakeAdmin($admin) !== true) { if ($this->cakeAdmin($admin) !== true) {

View file

@ -123,7 +123,7 @@ class TemplateTask extends AppShell {
$data = array($one => $two); $data = array($one => $two);
} }
if ($data == null) { if (!$data) {
return false; return false;
} }
$this->templateVars = $data + $this->templateVars; $this->templateVars = $data + $this->templateVars;
@ -166,7 +166,7 @@ class TemplateTask extends AppShell {
* @return string returns the path to the selected theme. * @return string returns the path to the selected theme.
*/ */
public function getThemePath() { public function getThemePath() {
if (count($this->templatePaths) == 1) { if (count($this->templatePaths) === 1) {
$paths = array_values($this->templatePaths); $paths = array_values($this->templatePaths);
return $paths[0]; return $paths[0];
} }

View file

@ -83,15 +83,16 @@ class TestTask extends BakeTask {
*/ */
public function execute() { public function execute() {
parent::execute(); parent::execute();
if (empty($this->args)) { $count = count($this->args);
if (!$count) {
$this->_interactive(); $this->_interactive();
} }
if (count($this->args) == 1) { if ($count === 1) {
$this->_interactive($this->args[0]); $this->_interactive($this->args[0]);
} }
if (count($this->args) > 1) { if ($count > 1) {
$type = Inflector::classify($this->args[0]); $type = Inflector::classify($this->args[0]);
if ($this->bake($type, $this->args[1])) { if ($this->bake($type, $this->args[1])) {
$this->out('<success>Done</success>'); $this->out('<success>Done</success>');
@ -334,7 +335,7 @@ class TestTask extends BakeTask {
* @param string $type The type the class having a test * @param string $type The type the class having a test
* generated for is in. * generated for is in.
* @return array Array of (class, type) * @return array Array of (class, type)
* @throws CakeException On invalid typename * @throws CakeException on invalid types.
*/ */
public function getBaseType($type) { public function getBaseType($type) {
if (empty($this->baseTypes[$type])) { if (empty($this->baseTypes[$type])) {

View file

@ -316,9 +316,9 @@ class ViewTask extends BakeTask {
*/ */
public function customAction() { public function customAction() {
$action = ''; $action = '';
while ($action == '') { while (!$action) {
$action = $this->in(__d('cake_console', 'Action Name? (use lowercase_underscored function name)')); $action = $this->in(__d('cake_console', 'Action Name? (use lowercase_underscored function name)'));
if ($action == '') { if (!$action) {
$this->out(__d('cake_console', 'The action name you supplied was empty. Please try again.')); $this->out(__d('cake_console', 'The action name you supplied was empty. Please try again.'));
} }
} }

View file

@ -81,7 +81,7 @@ class ConsoleErrorHandler {
$message = __d('cake_console', '%s in [%s, line %s]', $description, $file, $line); $message = __d('cake_console', '%s in [%s, line %s]', $description, $file, $line);
$stderr->write(__d('cake_console', "<error>%s Error:</error> %s\n", $name, $message)); $stderr->write(__d('cake_console', "<error>%s Error:</error> %s\n", $name, $message));
if (Configure::read('debug') == 0) { if (!Configure::read('debug')) {
CakeLog::write($log, $message); CakeLog::write($log, $message);
} }

View file

@ -154,7 +154,7 @@ class Shell extends Object {
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell
*/ */
public function __construct($stdout = null, $stderr = null, $stdin = null) { public function __construct($stdout = null, $stderr = null, $stdin = null) {
if ($this->name == null) { if (!$this->name) {
$this->name = Inflector::camelize(str_replace(array('Shell', 'Task'), '', get_class($this))); $this->name = Inflector::camelize(str_replace(array('Shell', 'Task'), '', get_class($this)));
} }
$this->Tasks = new TaskCollection($this); $this->Tasks = new TaskCollection($this);
@ -162,13 +162,13 @@ class Shell extends Object {
$this->stdout = $stdout; $this->stdout = $stdout;
$this->stderr = $stderr; $this->stderr = $stderr;
$this->stdin = $stdin; $this->stdin = $stdin;
if ($this->stdout == null) { if (!$this->stdout) {
$this->stdout = new ConsoleOutput('php://stdout'); $this->stdout = new ConsoleOutput('php://stdout');
} }
if ($this->stderr == null) { if (!$this->stderr) {
$this->stderr = new ConsoleOutput('php://stderr'); $this->stderr = new ConsoleOutput('php://stderr');
} }
if ($this->stdin == null) { if (!$this->stdin) {
$this->stdin = new ConsoleInput('php://stdin'); $this->stdin = new ConsoleInput('php://stdin');
} }
$this->_useLogger(); $this->_useLogger();
@ -325,7 +325,7 @@ class Shell extends Object {
*/ */
public function dispatchShell() { public function dispatchShell() {
$args = func_get_args(); $args = func_get_args();
if (is_string($args[0]) && count($args) == 1) { if (is_string($args[0]) && count($args) === 1) {
$args = explode(' ', $args[0]); $args = explode(' ', $args[0]);
} }

View file

@ -276,7 +276,11 @@ class ShellDispatcher {
if (isset($params['working'])) { if (isset($params['working'])) {
$params['working'] = trim($params['working']); $params['working'] = trim($params['working']);
} }
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0][0] !== '.')) {
if ($params['working'][0] === '.') {
$params['working'] = realpath($params['working']);
}
if (empty($this->params['app']) && $params['working'] != $params['root']) { if (empty($this->params['app']) && $params['working'] != $params['root']) {
$params['root'] = dirname($params['working']); $params['root'] = dirname($params['working']);
$params['app'] = basename($params['working']); $params['app'] = basename($params['working']);

View file

@ -36,11 +36,11 @@
* @return void * @return void
*/ */
public function <?php echo $admin ?>view($id = null) { public function <?php echo $admin ?>view($id = null) {
$this-><?php echo $currentModelName; ?>->id = $id; if (!$this-><?php echo $currentModelName; ?>->exists($id)) {
if (!$this-><?php echo $currentModelName; ?>->exists()) {
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>')); throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
} }
$this->set('<?php echo $singularName; ?>', $this-><?php echo $currentModelName; ?>->read(null, $id)); $options = array('conditions' => array('<?php echo $currentModelName; ?>.' . $this-><?php echo $currentModelName; ?>->primaryKey => $id));
$this->set('<?php echo $singularName; ?>', $this-><?php echo $currentModelName; ?>->find('first', $options));
} }
<?php $compact = array(); ?> <?php $compact = array(); ?>
@ -91,8 +91,7 @@
* @return void * @return void
*/ */
public function <?php echo $admin; ?>edit($id = null) { public function <?php echo $admin; ?>edit($id = null) {
$this-><?php echo $currentModelName; ?>->id = $id; if (!$this-><?php echo $currentModelName; ?>->exists($id)) {
if (!$this-><?php echo $currentModelName; ?>->exists()) {
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>')); throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
} }
if ($this->request->is('post') || $this->request->is('put')) { if ($this->request->is('post') || $this->request->is('put')) {
@ -109,7 +108,8 @@
<?php endif; ?> <?php endif; ?>
} }
} else { } else {
$this->request->data = $this-><?php echo $currentModelName; ?>->read(null, $id); $options = array('conditions' => array('<?php echo $currentModelName; ?>.' . $this-><?php echo $currentModelName; ?>->primaryKey => $id));
$this->request->data = $this-><?php echo $currentModelName; ?>->find('first', $options);
} }
<?php <?php
foreach (array('belongsTo', 'hasAndBelongsToMany') as $assoc): foreach (array('belongsTo', 'hasAndBelongsToMany') as $assoc):
@ -131,19 +131,17 @@
/** /**
* <?php echo $admin ?>delete method * <?php echo $admin ?>delete method
* *
* @throws MethodNotAllowedException
* @throws NotFoundException * @throws NotFoundException
* @throws MethodNotAllowedException
* @param string $id * @param string $id
* @return void * @return void
*/ */
public function <?php echo $admin; ?>delete($id = null) { public function <?php echo $admin; ?>delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this-><?php echo $currentModelName; ?>->id = $id; $this-><?php echo $currentModelName; ?>->id = $id;
if (!$this-><?php echo $currentModelName; ?>->exists()) { if (!$this-><?php echo $currentModelName; ?>->exists()) {
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>')); throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
} }
$this->request->onlyAllow('post', 'delete');
if ($this-><?php echo $currentModelName; ?>->delete()) { if ($this-><?php echo $currentModelName; ?>->delete()) {
<?php if ($wannaUseSession): ?> <?php if ($wannaUseSession): ?>
$this->Session->setFlash(__('<?php echo ucfirst(strtolower($singularHumanName)); ?> deleted')); $this->Session->setFlash(__('<?php echo ucfirst(strtolower($singularHumanName)); ?> deleted'));

View file

@ -49,33 +49,33 @@ class <?php echo $controllerName; ?>Controller extends <?php echo $plugin; ?>App
<?php else: <?php else:
if (count($helpers)): if (count($helpers)):
echo "/**\n * Helpers\n *\n * @var array\n */\n"; echo "/**\n * Helpers\n *\n * @var array\n */\n";
echo "\tpublic \$helpers = array("; echo "\tpublic \$helpers = array(";
for ($i = 0, $len = count($helpers); $i < $len; $i++): for ($i = 0, $len = count($helpers); $i < $len; $i++):
if ($i != $len - 1): if ($i != $len - 1):
echo "'" . Inflector::camelize($helpers[$i]) . "', "; echo "'" . Inflector::camelize($helpers[$i]) . "', ";
else: else:
echo "'" . Inflector::camelize($helpers[$i]) . "'"; echo "'" . Inflector::camelize($helpers[$i]) . "'";
endif; endif;
endfor; endfor;
echo ");\n\n"; echo ");\n\n";
endif; endif;
if (count($components)): if (count($components)):
echo "/**\n * Components\n *\n * @var array\n */\n"; echo "/**\n * Components\n *\n * @var array\n */\n";
echo "\tpublic \$components = array("; echo "\tpublic \$components = array(";
for ($i = 0, $len = count($components); $i < $len; $i++): for ($i = 0, $len = count($components); $i < $len; $i++):
if ($i != $len - 1): if ($i != $len - 1):
echo "'" . Inflector::camelize($components[$i]) . "', "; echo "'" . Inflector::camelize($components[$i]) . "', ";
else: else:
echo "'" . Inflector::camelize($components[$i]) . "'"; echo "'" . Inflector::camelize($components[$i]) . "'";
endif; endif;
endfor; endfor;
echo ");\n\n"; echo ");\n\n";
endif; endif;
echo trim($actions) . "\n"; echo trim($actions) . "\n";
endif; ?> endif; ?>
} }

View file

@ -48,9 +48,9 @@ class <?php echo $name ?> extends <?php echo $plugin; ?>AppModel {
<?php endif; <?php endif;
if ($useTable && $useTable !== Inflector::tableize($name)): if ($useTable && $useTable !== Inflector::tableize($name)):
$table = "'$useTable'"; $table = "'$useTable'";
echo "/**\n * Use table\n *\n * @var mixed False or table name\n */\n"; echo "/**\n * Use table\n *\n * @var mixed False or table name\n */\n";
echo "\tpublic \$useTable = $table;\n\n"; echo "\tpublic \$useTable = $table;\n\n";
endif; endif;
if ($primaryKey !== 'id'): ?> if ($primaryKey !== 'id'): ?>

View file

@ -20,14 +20,13 @@
<h2><?php echo "<?php echo __('{$pluralHumanName}'); ?>"; ?></h2> <h2><?php echo "<?php echo __('{$pluralHumanName}'); ?>"; ?></h2>
<table cellpadding="0" cellspacing="0"> <table cellpadding="0" cellspacing="0">
<tr> <tr>
<?php foreach ($fields as $field): ?> <?php foreach ($fields as $field): ?>
<th><?php echo "<?php echo \$this->Paginator->sort('{$field}'); ?>"; ?></th> <th><?php echo "<?php echo \$this->Paginator->sort('{$field}'); ?>"; ?></th>
<?php endforeach; ?> <?php endforeach; ?>
<th class="actions"><?php echo "<?php echo __('Actions'); ?>"; ?></th> <th class="actions"><?php echo "<?php echo __('Actions'); ?>"; ?></th>
</tr> </tr>
<?php <?php
echo "<?php echo "<?php foreach (\${$pluralVar} as \${$singularVar}): ?>\n";
foreach (\${$pluralVar} as \${$singularVar}): ?>\n";
echo "\t<tr>\n"; echo "\t<tr>\n";
foreach ($fields as $field) { foreach ($fields as $field) {
$isKey = false; $isKey = false;
@ -47,8 +46,8 @@
echo "\t\t<td class=\"actions\">\n"; echo "\t\t<td class=\"actions\">\n";
echo "\t\t\t<?php echo \$this->Html->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; echo "\t\t\t<?php echo \$this->Html->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t\t<?php echo \$this->Html->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; echo "\t\t\t<?php echo \$this->Html->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; echo "\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t</td>\n"; echo "\t\t</td>\n";
echo "\t</tr>\n"; echo "\t</tr>\n";
@ -62,7 +61,6 @@
)); ));
?>"; ?> ?>"; ?>
</p> </p>
<div class="paging"> <div class="paging">
<?php <?php
echo "<?php\n"; echo "<?php\n";

View file

@ -293,18 +293,20 @@
*/ */
/** /**
* Pick the caching engine to use. If APC is enabled use it. * Configure the cache handlers that CakePHP will use for internal
* If running via cli - apc is disabled by default. ensure it's available and enabled in this case * metadata like class maps, and model schema.
* *
* By default File is used, but for improved performance you should use APC.
*
* Note: 'default' and other application caches should be configured in app/Config/bootstrap.php.
* Please check the comments in boostrap.php for more info on the cache engines available
* and their setttings.
*/ */
$engine = 'File'; $engine = 'File';
if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
$engine = 'Apc';
}
// In development mode, caches should expire quickly. // In development mode, caches should expire quickly.
$duration = '+999 days'; $duration = '+999 days';
if (Configure::read('debug') >= 1) { if (Configure::read('debug') > 0) {
$duration = '+10 seconds'; $duration = '+10 seconds';
} }

View file

@ -10,24 +10,28 @@
# Licensed under The MIT License # Licensed under The MIT License
# Redistributions of files must retain the above copyright notice. # Redistributions of files must retain the above copyright notice.
# #
# @copyright Copyright 2005-2012, Cake Software Foundation, Inc. # @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
# @link http://cakephp.org CakePHP(tm) Project # @link http://cakephp.org CakePHP(tm) Project
# @package app.Console # @package app.Console
# @since CakePHP(tm) v 2.0 # @since CakePHP(tm) v 2.0
# @license MIT License (http://www.opensource.org/licenses/mit-license.php) # @license MIT License (http://www.opensource.org/licenses/mit-license.php)
# #
################################################################################ ################################################################################
LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
while [ -h "$LIB" ]; do # Canonicalize by following every symlink of the given name recursively
DIR=$(dirname -- "$LIB") canonicalize() {
SYM=$(readlink "$LIB") NAME=$1
LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") while [ -h "$NAME" ]; do
done DIR=$(dirname -- "$NAME")
SYM=$(readlink "$NAME")
NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
echo "$NAME"
}
LIB=$(dirname -- "$LIB")/ CONSOLE=$(dirname $(canonicalize "$0"))
APP=`pwd` APP=$(dirname "$CONSOLE")
exec php -q "$LIB"cake.php -working "$APP" "$@" exec php -q $CONSOLE/cake.php -working "$APP" "$@"
exit; exit;

View file

@ -18,6 +18,7 @@
* @since CakePHP(tm) v 0.2.9 * @since CakePHP(tm) v 0.2.9
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('AppController', 'Controller');
/** /**
* Static content controller * Static content controller

View file

@ -25,7 +25,7 @@
); ?> ); ?>
</p> </p>
<?php <?php
if (Configure::read('debug') > 0 ): if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace'); echo $this->element('exception_stack_trace');
endif; endif;
?> ?>

View file

@ -22,7 +22,7 @@
<?php echo __d('cake', 'An Internal Error Has Occurred.'); ?> <?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>
</p> </p>
<?php <?php
if (Configure::read('debug') > 0 ): if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace'); echo $this->element('exception_stack_trace');
endif; endif;
?> ?>

View file

@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
?> ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<?php echo $this->Html->charset(); ?> <?php echo $this->Html->charset(); ?>

View file

@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
?> ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<?php echo $this->Html->charset(); ?> <?php echo $this->Html->charset(); ?>

View file

@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
?> ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<?php echo $this->Html->charset(); ?> <?php echo $this->Html->charset(); ?>

View file

@ -15,7 +15,7 @@
* @since CakePHP(tm) v 0.10.0.1076 * @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
if (Configure::read('debug') == 0): if (!Configure::read('debug')):
throw new NotFoundException(); throw new NotFoundException();
endif; endif;
App::uses('Debugger', 'Utility'); App::uses('Debugger', 'Utility');
@ -127,11 +127,28 @@ if (isset($filePresent)):
echo '</span></p>'; echo '</span></p>';
} }
?> ?>
<p>
<?php
if (CakePlugin::loaded('DebugKit')):
echo '<span class="notice success">';
echo __d('cake_dev', 'DebugKit plugin is present');
echo '</span>';
else:
echo '<span class="notice">';
echo __d('cake_dev', 'DebugKit is not installed. It will help you inspect and debug different aspects of your application.');
echo '<br/>';
echo __d('cake_dev', 'You can install it from %s', $this->Html->link('github', 'https://github.com/cakephp/debug_kit'));
echo '</span>';
endif;
?>
</p>
<h3><?php echo __d('cake_dev', 'Editing this Page'); ?></h3> <h3><?php echo __d('cake_dev', 'Editing this Page'); ?></h3>
<p> <p>
<?php <?php
echo __d('cake_dev', 'To change the content of this page, create: APP/View/Pages/home.ctp.<br /> echo __d('cake_dev', 'To change the content of this page, edit: APP/View/Pages/home.ctp.<br />
To change its layout, create: APP/View/Layouts/default.ctp.<br /> To change its layout, edit: APP/View/Layouts/default.ctp.<br />
You can also add some CSS styles for your pages at: APP/webroot/css.'); You can also add some CSS styles for your pages at: APP/webroot/css.');
?> ?>
</p> </p>
@ -156,6 +173,20 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
?> ?>
</p> </p>
<h3><?php echo __d('cake_dev', 'Official Plugins'); ?></h3>
<p>
<ul>
<li>
<?php echo $this->Html->link('DebugKit', 'https://github.com/cakephp/debug_kit') ?>:
<?php echo __d('cake_dev', 'provides a debugging toolbar and enhanced debugging tools for CakePHP applications.'); ?>
</li>
<li>
<?php echo $this->Html->link('Localized', 'https://github.com/cakephp/localized') ?>:
<?php echo __d('cake_dev', 'contains various localized validation classes and translations for specific countries'); ?>
</li>
</ul>
</p>
<h3><?php echo __d('cake_dev', 'More about Cake'); ?></h3> <h3><?php echo __d('cake_dev', 'More about Cake'); ?></h3>
<p> <p>
<?php echo __d('cake_dev', 'CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.'); ?> <?php echo __d('cake_dev', 'CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.'); ?>
@ -175,8 +206,8 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
<ul><li><?php echo __d('cake_dev', 'Quick Reference'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Quick Reference'); ?></li></ul></li>
<li><a href="http://bakery.cakephp.org"><?php echo __d('cake_dev', 'The Bakery'); ?> </a> <li><a href="http://bakery.cakephp.org"><?php echo __d('cake_dev', 'The Bakery'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'Everything CakePHP'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Everything CakePHP'); ?></li></ul></li>
<li><a href="http://live.cakephp.org"><?php echo __d('cake_dev', 'The Show'); ?> </a> <li><a href="http://plugins.cakephp.org"><?php echo __d('cake_dev', 'CakePHP plugins repo'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'The Show is a live and archived internet radio broadcast CakePHP-related topics and answer questions live via IRC, Skype, and telephone.'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'A comprehensive list of all CakePHP plugins created by the community'); ?></li></ul></li>
<li><a href="http://groups.google.com/group/cake-php"><?php echo __d('cake_dev', 'CakePHP Google Group'); ?> </a> <li><a href="http://groups.google.com/group/cake-php"><?php echo __d('cake_dev', 'CakePHP Google Group'); ?> </a>
<ul><li><?php echo __d('cake_dev', 'Community mailing list'); ?></li></ul></li> <ul><li><?php echo __d('cake_dev', 'Community mailing list'); ?></li></ul></li>
<li><a href="irc://irc.freenode.net/cakephp">irc.freenode.net #cakephp</a> <li><a href="irc://irc.freenode.net/cakephp">irc.freenode.net #cakephp</a>

View file

@ -72,6 +72,11 @@ if (!defined('WWW_ROOT')) {
define('WWW_ROOT', dirname(__FILE__) . DS); define('WWW_ROOT', dirname(__FILE__) . DS);
} }
// for built-in server
if (php_sapi_name() == 'cli-server') {
$_SERVER['PHP_SELF'] = '/' . basename(__FILE__);
}
if (!defined('CAKE_CORE_INCLUDE_PATH')) { if (!defined('CAKE_CORE_INCLUDE_PATH')) {
if (function_exists('ini_set')) { if (function_exists('ini_set')) {
ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
@ -93,5 +98,5 @@ App::uses('Dispatcher', 'Routing');
$Dispatcher = new Dispatcher(); $Dispatcher = new Dispatcher();
$Dispatcher->dispatch( $Dispatcher->dispatch(
new CakeRequest(), new CakeRequest(),
new CakeResponse(array('charset' => Configure::read('App.encoding'))) new CakeResponse()
); );

View file

@ -86,7 +86,7 @@ if (!empty($failed)) {
} }
if (Configure::read('debug') < 1) { if (Configure::read('debug') < 1) {
die(__d('cake_dev', 'Debug setting does not allow access to this url.')); exit(__d('cake_dev', 'Debug setting does not allow access to this url.'));
} }
require_once CAKE . 'TestSuite' . DS . 'CakeTestSuiteDispatcher.php'; require_once CAKE . 'TestSuite' . DS . 'CakeTestSuiteDispatcher.php';

View file

@ -17,17 +17,21 @@
# @license MIT License (http://www.opensource.org/licenses/mit-license.php) # @license MIT License (http://www.opensource.org/licenses/mit-license.php)
# #
################################################################################ ################################################################################
LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
while [ -h "$LIB" ]; do # Canonicalize by following every symlink of the given name recursively
DIR=$(dirname -- "$LIB") canonicalize() {
SYM=$(readlink "$LIB") NAME=$1
LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") while [ -h "$NAME" ]; do
done DIR=$(dirname -- "$NAME")
SYM=$(readlink "$NAME")
NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
echo "$NAME"
}
LIB=$(dirname -- "$LIB")/ CONSOLE=$(dirname $(canonicalize "$0"))
APP=`pwd` APP=`pwd`
exec php -q "$LIB"cake.php -working "$APP" "$@" exec php -q $CONSOLE/cake.php -working "$APP" "$@"
exit; exit;

View file

@ -71,18 +71,4 @@ class CakeErrorController extends AppController {
$this->_set(array('cacheAction' => false, 'viewPath' => 'Errors')); $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

@ -91,7 +91,7 @@ class IniAcl extends Object implements AclInterface {
* @return boolean Success * @return boolean Success
*/ */
public function check($aro, $aco, $action = null) { public function check($aro, $aco, $action = null) {
if ($this->config == null) { if (!$this->config) {
$this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php'); $this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
} }
$aclConfig = $this->config; $aclConfig = $this->config;

View file

@ -170,11 +170,11 @@ class PhpAcl extends Object implements AclInterface {
foreach ($path as $depth => $node) { foreach ($path as $depth => $node) {
foreach ($prioritizedAros as $aros) { foreach ($prioritizedAros as $aros) {
if (!empty($node['allow'])) { 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'])) { if (!empty($node['deny'])) {
$allow = $allow && count(array_intersect($node['deny'], $aros)) == 0; $allow = $allow && !count(array_intersect($node['deny'], $aros));
} }
} }
} }

View file

@ -66,19 +66,28 @@ abstract class BaseAuthenticate {
/** /**
* Find a user record using the standard options. * Find a user record using the standard options.
* *
* @param string $username The username/identifier. * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). If
* @param string $password The unhashed password. * the password field is not included in the conditions the password will be returned.
*
* @param Mixed $conditions The username/identifier, or an array of find conditions.
* @param Mixed $password The password, only use if passing as $conditions = 'username'.
* @return Mixed Either false on failure, or an array of user data. * @return Mixed Either false on failure, or an array of user data.
*/ */
protected function _findUser($username, $password) { protected function _findUser($conditions, $password = null) {
$userModel = $this->settings['userModel']; $userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel); list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields']; $fields = $this->settings['fields'];
$conditions = array( if (!is_array($conditions)) {
$model . '.' . $fields['username'] => $username, if (!$password) {
$model . '.' . $fields['password'] => $this->_password($password), return false;
); }
$username = $conditions;
$conditions = array(
$model . '.' . $fields['username'] => $username,
$model . '.' . $fields['password'] => $this->_password($password),
);
}
if (!empty($this->settings['scope'])) { if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']); $conditions = array_merge($conditions, $this->settings['scope']);
} }
@ -91,7 +100,12 @@ abstract class BaseAuthenticate {
return false; return false;
} }
$user = $result[$model]; $user = $result[$model];
unset($user[$fields['password']]); if (
isset($conditions[$model . '.' . $fields['password']]) ||
isset($conditions[$fields['password']])
) {
unset($user[$fields['password']]);
}
unset($result[$model]); unset($result[$model]);
return array_merge($user, $result); return array_merge($user, $result);
} }

View file

@ -0,0 +1,78 @@
<?php
/**
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of the files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, 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)
*/
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 inital password hashing/creation see Security::hash(). Other than how the password is initally hashed,
* BlowfishAuthenticate works exactly the same way as FormAuthenticate.
*
* @package Cake.Controller.Component.Auth
* @since CakePHP(tm) v 2.3
* @see AuthComponent::$authenticate
*/
class BlowfishAuthenticate extends FormAuthenticate {
/**
* 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($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
$user = $this->_findUser(
array(
$model . '.' . $fields['username'] => $request->data[$model][$fields['username']],
)
);
if (!$user) {
return false;
}
$password = Security::hash(
$request->data[$model][$fields['password']],
'blowfish',
$user[$fields['password']]
);
if ($password === $user[$fields['password']]) {
unset($user[$fields['password']]);
return $user;
}
return false;
}
}

View file

@ -138,7 +138,7 @@ class DigestAuthenticate extends BaseAuthenticate {
if (empty($digest)) { if (empty($digest)) {
return false; return false;
} }
$user = $this->_findUser($digest['username'], null); $user = $this->_findUser($digest['username']);
if (empty($user)) { if (empty($user)) {
return false; return false;
} }
@ -157,7 +157,7 @@ class DigestAuthenticate extends BaseAuthenticate {
* @param string $password Unused password, digest doesn't require passwords. * @param string $password Unused password, digest doesn't require passwords.
* @return Mixed Either false on failure, or an array of user data. * @return Mixed 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']; $userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel); list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields']; $fields = $this->settings['fields'];

View file

@ -36,6 +36,27 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
*/ */
class FormAuthenticate extends BaseAuthenticate { class FormAuthenticate extends BaseAuthenticate {
/**
* Checks the fields to ensure they are supplied.
*
* @param CakeRequest $request The request that contains login information.
* @param string $model The model used for login verification.
* @param array $fields The fields to be checked.
* @return boolean False if the fields have not been supplied. True if they exist.
*/
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']])
) {
return false;
}
return true;
}
/** /**
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields` * 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 * to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
@ -50,13 +71,7 @@ class FormAuthenticate extends BaseAuthenticate {
list($plugin, $model) = pluginSplit($userModel); list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields']; $fields = $this->settings['fields'];
if (empty($request->data[$model])) { if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
if (
empty($request->data[$model][$fields['username']]) ||
empty($request->data[$model][$fields['password']])
) {
return false; return false;
} }
return $this->_findUser( return $this->_findUser(

View file

@ -211,6 +211,15 @@ class AuthComponent extends Component {
*/ */
public $authError = null; public $authError = null;
/**
* Controls handling of unauthorized access. By default unauthorized user is
* redirected to the referrer url or AuthComponent::$loginAction or '/'.
* If set to false a ForbiddenException exception is thrown instead of redirecting.
*
* @var boolean
*/
public $unauthorizedRedirect = true;
/** /**
* Controller actions for which user validation is not required. * Controller actions for which user validation is not required.
* *
@ -289,13 +298,7 @@ class AuthComponent extends Component {
$url = Router::normalize($url); $url = Router::normalize($url);
$loginAction = Router::normalize($this->loginAction); $loginAction = Router::normalize($this->loginAction);
$allowedActions = $this->allowedActions; if ($loginAction != $url && in_array($action, array_map('strtolower', $this->allowedActions))) {
$isAllowed = (
$this->allowedActions == array('*') ||
in_array($action, array_map('strtolower', $allowedActions))
);
if ($loginAction != $url && $isAllowed) {
return true; return true;
} }
@ -306,27 +309,43 @@ class AuthComponent extends Component {
} }
} }
return 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 (!$this->_getUser()) {
if (!$request->is('ajax')) {
$this->flash($this->authError);
$this->Session->write('Auth.redirect', $request->here());
$controller->redirect($loginAction);
return false;
}
if (!empty($this->ajaxLogin)) {
$controller->viewPath = 'Elements';
echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
$this->_stop();
return false;
}
$controller->redirect(null, 403);
}
if (empty($this->authorize) || $this->isAuthorized($this->user())) { if (empty($this->authorize) || $this->isAuthorized($this->user())) {
return true; return true;
} }
return $this->_unauthorized($controller);
}
/**
* Handle unauthorized access attempt
*
* @param Controller $controller A reference to the controller object
* @return boolean Returns false
* @throws ForbiddenException
*/
protected function _unauthorized(Controller $controller) {
if (!$this->unauthorizedRedirect) {
throw new ForbiddenException($this->authError);
}
$this->flash($this->authError); $this->flash($this->authError);
$default = '/'; $default = '/';
if (!empty($this->loginRedirect)) { if (!empty($this->loginRedirect)) {
@ -366,7 +385,8 @@ class AuthComponent extends Component {
public function isAuthorized($user = null, $request = null) { public function isAuthorized($user = null, $request = null) {
if (empty($user) && !$this->user()) { if (empty($user) && !$this->user()) {
return false; return false;
} elseif (empty($user)) { }
if (empty($user)) {
$user = $this->user(); $user = $this->user();
} }
if (empty($request)) { if (empty($request)) {
@ -434,12 +454,12 @@ class AuthComponent extends Component {
$args = func_get_args(); $args = func_get_args();
if (empty($args) || $action === null) { if (empty($args) || $action === null) {
$this->allowedActions = $this->_methods; $this->allowedActions = $this->_methods;
} else { return;
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
$this->allowedActions = array_merge($this->allowedActions, $args);
} }
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
$this->allowedActions = array_merge($this->allowedActions, $args);
} }
/** /**
@ -460,18 +480,18 @@ class AuthComponent extends Component {
$args = func_get_args(); $args = func_get_args();
if (empty($args) || $action === null) { if (empty($args) || $action === null) {
$this->allowedActions = array(); $this->allowedActions = array();
} else { 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);
} }
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);
} }
/** /**

View file

@ -177,7 +177,7 @@ class CookieComponent extends Component {
if ($controller && isset($controller->response)) { if ($controller && isset($controller->response)) {
$this->_response = $controller->response; $this->_response = $controller->response;
} else { } else {
$this->_response = new CakeResponse(array('charset' => Configure::read('App.encoding'))); $this->_response = new CakeResponse();
} }
} }
@ -278,6 +278,19 @@ class CookieComponent extends Component {
return $this->_values[$this->name][$key]; return $this->_values[$this->name][$key];
} }
/**
* Returns true if given variable is set in cookie.
*
* @param string $var Variable name to check for
* @return boolean True if variable is there
*/
public function check($key = null) {
if (empty($key)) {
return false;
}
return $this->read($key) !== null;
}
/** /**
* Delete a cookie value * Delete a cookie value
* *
@ -378,11 +391,11 @@ class CookieComponent extends Component {
} }
$this->_reset = $this->_expires; $this->_reset = $this->_expires;
if ($expires == 0) { if (!$expires) {
return $this->_expires = 0; return $this->_expires = 0;
} }
if (is_integer($expires) || is_numeric($expires)) { if (is_int($expires) || is_numeric($expires)) {
return $this->_expires = $now + intval($expires); return $this->_expires = $now + intval($expires);
} }
return $this->_expires = strtotime($expires, $now); return $this->_expires = strtotime($expires, $now);
@ -504,7 +517,7 @@ class CookieComponent extends Component {
$first = substr($string, 0, 1); $first = substr($string, 0, 1);
if ($first === '{' || $first === '[') { if ($first === '{' || $first === '[') {
$ret = json_decode($string, true); $ret = json_decode($string, true);
return ($ret != null) ? $ret : $string; return ($ret) ? $ret : $string;
} }
$array = array(); $array = array();
foreach (explode(',', $string) as $pair) { foreach (explode(',', $string) as $pair) {

View file

@ -316,7 +316,7 @@ class EmailComponent extends Component {
foreach ($this->headers as $key => $value) { foreach ($this->headers as $key => $value) {
$headers['X-' . $key] = $value; $headers['X-' . $key] = $value;
} }
if ($this->date != false) { if ($this->date) {
$headers['Date'] = $this->date; $headers['Date'] = $this->date;
} }
$lib->setHeaders($headers); $lib->setHeaders($headers);

View file

@ -16,6 +16,7 @@
* @since CakePHP(tm) v 2.0 * @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('Component', 'Controller');
App::uses('Hash', 'Utility'); App::uses('Hash', 'Utility');
/** /**
@ -50,6 +51,20 @@ App::uses('Hash', 'Utility');
* *
* This would allow you to have different pagination settings for `Comment` and `Post` models. * 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 * @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html * @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
*/ */
@ -152,6 +167,12 @@ class PaginatorComponent extends Component {
$extra = array_diff_key($options, compact( $extra = array_diff_key($options, compact(
'conditions', 'fields', 'order', 'limit', 'page', 'recursive' 'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
)); ));
if (!empty($extra['findType'])) {
$type = $extra['findType'];
unset($extra['findType']);
}
if ($type !== 'all') { if ($type !== 'all') {
$extra['type'] = $type; $extra['type'] = $type;
} }
@ -228,36 +249,34 @@ class PaginatorComponent extends Component {
if (strpos($object, '.') !== false) { if (strpos($object, '.') !== false) {
list($object, $assoc) = pluginSplit($object); list($object, $assoc) = pluginSplit($object);
} }
if ($assoc && isset($this->Controller->{$object}->{$assoc})) { if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
$object = $this->Controller->{$object}->{$assoc}; return $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};
} }
} 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})) { if (isset($this->Controller->{$this->Controller->modelClass})) {
$object = $this->Controller->{$this->Controller->modelClass}; return $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};
}
} }
$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; return $object;
} }
@ -299,10 +318,9 @@ class PaginatorComponent extends Component {
* @return array An array of pagination defaults for a model, or the general settings. * @return array An array of pagination defaults for a model, or the general settings.
*/ */
public function getDefaults($alias) { public function getDefaults($alias) {
$defaults = $this->settings;
if (isset($this->settings[$alias])) { if (isset($this->settings[$alias])) {
$defaults = $this->settings[$alias]; $defaults = $this->settings[$alias];
} else {
$defaults = $this->settings;
} }
return array_merge( return array_merge(
array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'), array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
@ -323,13 +341,13 @@ class PaginatorComponent extends Component {
* @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. * @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 (isset($options['sort'])) { if (isset($options['sort'])) {
$direction = null; $direction = null;
if (isset($options['direction'])) { if (isset($options['direction'])) {
$direction = strtolower($options['direction']); $direction = strtolower($options['direction']);
} }
if ($direction != 'asc' && $direction != 'desc') { if (!in_array($direction, array('asc', 'desc'))) {
$direction = 'asc'; $direction = 'asc';
} }
$options['order'] = array($options['sort'] => $direction); $options['order'] = array($options['sort'] => $direction);
@ -371,7 +389,7 @@ class PaginatorComponent extends Component {
* @param array $options An array of options with a limit key to be checked. * @param array $options An array of options with a limit key to be checked.
* @return array An array of options for pagination * @return array An array of options for pagination
*/ */
public function checkLimit($options) { public function checkLimit(array $options) {
$options['limit'] = (int)$options['limit']; $options['limit'] = (int)$options['limit'];
if (empty($options['limit']) || $options['limit'] < 1) { if (empty($options['limit']) || $options['limit'] < 1) {
$options['limit'] = 1; $options['limit'] = 1;

View file

@ -19,6 +19,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('Component', 'Controller');
App::uses('Xml', 'Utility'); App::uses('Xml', 'Utility');
/** /**
@ -88,6 +89,17 @@ class RequestHandlerComponent extends Component {
'json' => array('json_decode', true) '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 * 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. * @param array $settings Array of settings.
*/ */
public function __construct(ComponentCollection $collection, $settings = array()) { public function __construct(ComponentCollection $collection, $settings = array()) {
$default = array('checkHttpCache' => true); parent::__construct($collection, $settings + array('checkHttpCache' => true));
parent::__construct($collection, $settings + $default);
$this->addInputType('xml', array(array($this, 'convertXml'))); $this->addInputType('xml', array(array($this, 'convertXml')));
$Controller = $collection->getController(); $Controller = $collection->getController();
@ -111,11 +122,10 @@ class RequestHandlerComponent extends Component {
* and the requested mime-types, RequestHandler::$ext is set to that value. * and the requested mime-types, RequestHandler::$ext is set to that value.
* *
* @param Controller $controller A reference to the controller * @param Controller $controller A reference to the controller
* @param array $settings Array of settings to _set().
* @return void * @return void
* @see Router::parseExtensions() * @see Router::parseExtensions()
*/ */
public function initialize(Controller $controller, $settings = array()) { public function initialize(Controller $controller) {
if (isset($this->request->params['ext'])) { if (isset($this->request->params['ext'])) {
$this->ext = $this->request->params['ext']; $this->ext = $this->request->params['ext'];
} }
@ -123,7 +133,9 @@ class RequestHandlerComponent extends Component {
$this->_setExtension(); $this->_setExtension();
} }
$this->params = $controller->params; $this->params = $controller->params;
$this->_set($settings); if (!empty($this->settings['viewClassMap'])) {
$this->viewClassMap($this->settings['viewClassMap']);
}
} }
/** /**
@ -145,9 +157,11 @@ class RequestHandlerComponent extends Component {
$extensions = Router::extensions(); $extensions = Router::extensions();
$preferred = array_shift($accept); $preferred = array_shift($accept);
$preferredTypes = $this->response->mapType($preferred); $preferredTypes = $this->response->mapType($preferred);
$similarTypes = array_intersect($extensions, $preferredTypes); if (!in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
if (count($similarTypes) === 1 && !in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) { $similarTypes = array_intersect($extensions, $preferredTypes);
$this->ext = array_shift($similarTypes); if (count($similarTypes) === 1) {
$this->ext = array_shift($similarTypes);
}
} }
} }
@ -256,8 +270,7 @@ class RequestHandlerComponent extends Component {
* @return boolean false if the render process should be aborted * @return boolean false if the render process should be aborted
**/ **/
public function beforeRender(Controller $controller) { public function beforeRender(Controller $controller) {
$shouldCheck = $this->settings['checkHttpCache']; if ($this->settings['checkHttpCache'] && $this->response->checkNotModified($this->request)) {
if ($shouldCheck && $this->response->checkNotModified($this->request)) {
return false; return false;
} }
} }
@ -382,13 +395,11 @@ class RequestHandlerComponent extends Component {
* Gets Prototype version if call is Ajax, otherwise empty string. * Gets Prototype version if call is Ajax, otherwise empty string.
* The Prototype library sets a special "Prototype version" HTTP header. * The Prototype library sets a special "Prototype version" HTTP header.
* *
* @return string Prototype version of component making Ajax call * @return string|boolean When Ajax the prototype version of component making the call otherwise false
*/ */
public function getAjaxVersion() { public function getAjaxVersion() {
if (env('HTTP_X_PROTOTYPE_VERSION') != null) { $httpX = env('HTTP_X_PROTOTYPE_VERSION');
return env('HTTP_X_PROTOTYPE_VERSION'); return ($httpX === null) ? false : $httpX;
}
return false;
} }
/** /**
@ -454,9 +465,10 @@ class RequestHandlerComponent extends Component {
public function accepts($type = null) { public function accepts($type = null) {
$accepted = $this->request->accepts(); $accepted = $this->request->accepts();
if ($type == null) { if (!$type) {
return $this->mapType($accepted); return $this->mapType($accepted);
} elseif (is_array($type)) { }
if (is_array($type)) {
foreach ($type as $t) { foreach ($type as $t) {
$t = $this->mapAlias($t); $t = $this->mapAlias($t);
if (in_array($t, $accepted)) { if (in_array($t, $accepted)) {
@ -464,9 +476,9 @@ class RequestHandlerComponent extends Component {
} }
} }
return false; return false;
} elseif (is_string($type)) { }
$type = $this->mapAlias($type); if (is_string($type)) {
return in_array($type, $accepted); return in_array($this->mapAlias($type), $accepted);
} }
return false; return false;
} }
@ -483,18 +495,20 @@ class RequestHandlerComponent extends Component {
if (!$this->request->is('post') && !$this->request->is('put')) { if (!$this->request->is('post') && !$this->request->is('put')) {
return null; return null;
} }
if (is_array($type)) {
list($contentType) = explode(';', env('CONTENT_TYPE'));
if ($type == null) {
return $this->mapType($contentType);
} elseif (is_array($type)) {
foreach ($type as $t) { foreach ($type as $t) {
if ($this->requestedWith($t)) { if ($this->requestedWith($t)) {
return $t; return $t;
} }
} }
return false; return false;
} elseif (is_string($type)) { }
list($contentType) = explode(';', env('CONTENT_TYPE'));
if (!$type) {
return $this->mapType($contentType);
}
if (is_string($type)) {
return ($type == $this->mapType($contentType)); return ($type == $this->mapType($contentType));
} }
} }
@ -522,10 +536,9 @@ class RequestHandlerComponent extends Component {
if (empty($acceptRaw)) { if (empty($acceptRaw)) {
return $this->ext; return $this->ext;
} }
$accepts = array_shift($acceptRaw); $accepts = $this->mapType(array_shift($acceptRaw));
$accepts = $this->mapType($accepts);
if ($type == null) { if (!$type) {
if (empty($this->ext) && !empty($accepts)) { if (empty($this->ext) && !empty($accepts)) {
return $accepts[0]; return $accepts[0];
} }
@ -582,18 +595,27 @@ class RequestHandlerComponent extends Component {
} }
$controller->ext = '.ctp'; $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'; $viewName = $viewClass . 'View';
if (!class_exists($viewName)) { if (!class_exists($viewName)) {
App::uses($viewName, 'View'); App::uses($viewName, $pluginDot . 'View');
} }
if (class_exists($viewName)) { if (class_exists($viewName)) {
$controller->viewClass = $viewClass; $controller->viewClass = $viewClass;
} elseif (empty($this->_renderType)) { } elseif (empty($this->_renderType)) {
$controller->viewPath .= DS . $type; $controller->viewPath .= DS . $type;
} else { } else {
$remove = preg_replace("/([\/\\\\]{$this->_renderType})$/", DS . $type, $controller->viewPath); $controller->viewPath = preg_replace(
$controller->viewPath = $remove; "/([\/\\\\]{$this->_renderType})$/",
DS . $type,
$controller->viewPath
);
} }
$this->_renderType = $type; $this->_renderType = $type;
$controller->layoutPath = $type; $controller->layoutPath = $type;
@ -603,12 +625,8 @@ class RequestHandlerComponent extends Component {
} }
$helper = ucfirst($type); $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('AppHelper', 'View/Helper');
App::uses($helper . 'Helper', 'View/Helper'); App::uses($helper . 'Helper', 'View/Helper');
if (class_exists($helper . 'Helper')) { if (class_exists($helper . 'Helper')) {
@ -634,39 +652,35 @@ class RequestHandlerComponent extends Component {
$defaults = array('index' => null, 'charset' => null, 'attachment' => false); $defaults = array('index' => null, 'charset' => null, 'attachment' => false);
$options = $options + $defaults; $options = $options + $defaults;
$cType = $type;
if (strpos($type, '/') === false) { if (strpos($type, '/') === false) {
$cType = $this->response->getMimeType($type); $cType = $this->response->getMimeType($type);
if ($cType === false) { }
return false; if (is_array($cType)) {
} if (isset($cType[$options['index']])) {
if (is_array($cType) && isset($cType[$options['index']])) {
$cType = $cType[$options['index']]; $cType = $cType[$options['index']];
} }
if (is_array($cType)) {
if ($this->prefers($cType)) { if ($this->prefers($cType)) {
$cType = $this->prefers($cType); $cType = $this->prefers($cType);
} else { } else {
$cType = $cType[0]; $cType = $cType[0];
}
} }
} else {
$cType = $type;
} }
if ($cType != null) { if (!$type) {
if (empty($this->request->params['requested'])) { return false;
$this->response->type($cType);
}
if (!empty($options['charset'])) {
$this->response->charset($options['charset']);
}
if (!empty($options['attachment'])) {
$this->response->download($options['attachment']);
}
return true;
} }
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;
} }
/** /**
@ -729,4 +743,25 @@ class RequestHandlerComponent extends Component {
$this->_inputTypeMap[$type] = $handler; $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

@ -129,6 +129,13 @@ class SecurityComponent extends Component {
*/ */
public $unlockedFields = array(); public $unlockedFields = array();
/**
* Actions to exclude from any security checks
*
* @var array
*/
public $unlockedActions = array();
/** /**
* Whether to validate POST data. Set to false to disable for data coming from 3rd party * Whether to validate POST data. Set to false to disable for data coming from 3rd party
* services, etc. * services, etc.
@ -218,13 +225,11 @@ class SecurityComponent extends Component {
$controller->request->params['requested'] != 1 $controller->request->params['requested'] != 1
); );
if ($isPost && $isNotRequestAction && $this->validatePost) { if (!in_array($this->_action, (array)$this->unlockedActions) && $isPost && $isNotRequestAction) {
if ($this->_validatePost($controller) === false) { if ($this->validatePost && $this->_validatePost($controller) === false) {
return $this->blackHole($controller, 'auth'); return $this->blackHole($controller, 'auth');
} }
} if ($this->csrfCheck && $this->_validateCsrf($controller) === false) {
if ($isPost && $isNotRequestAction && $this->csrfCheck) {
if ($this->_validateCsrf($controller) === false) {
return $this->blackHole($controller, 'csrf'); return $this->blackHole($controller, 'csrf');
} }
} }
@ -309,11 +314,10 @@ class SecurityComponent extends Component {
* @throws BadRequestException * @throws BadRequestException
*/ */
public function blackHole(Controller $controller, $error = '') { public function blackHole(Controller $controller, $error = '') {
if ($this->blackHoleCallback == null) { if (!$this->blackHoleCallback) {
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed')); throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
} else {
return $this->_callback($controller, $this->blackHoleCallback, array($error));
} }
return $this->_callback($controller, $this->blackHoleCallback, array($error));
} }
/** /**
@ -385,7 +389,7 @@ class SecurityComponent extends Component {
$requireAuth = $this->requireAuth; $requireAuth = $this->requireAuth;
if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) { if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) {
if (!isset($controller->request->data['_Token'] )) { if (!isset($controller->request->data['_Token'])) {
if (!$this->blackHole($controller, 'auth')) { if (!$this->blackHole($controller, 'auth')) {
return null; return null;
} }
@ -489,7 +493,7 @@ class SecurityComponent extends Component {
$fieldList += $lockedFields; $fieldList += $lockedFields;
$unlocked = implode('|', $unlocked); $unlocked = implode('|', $unlocked);
$check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt')); $check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'), 'sha1');
return ($token === $check); return ($token === $check);
} }
@ -588,11 +592,10 @@ class SecurityComponent extends Component {
* @throws BadRequestException When a the blackholeCallback is not callable. * @throws BadRequestException When a the blackholeCallback is not callable.
*/ */
protected function _callback(Controller $controller, $method, $params = array()) { protected function _callback(Controller $controller, $method, $params = array()) {
if (is_callable(array($controller, $method))) { if (!is_callable(array($controller, $method))) {
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
} else {
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed')); 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

@ -319,7 +319,7 @@ class Controller extends Object implements CakeEventListener {
$this->name = substr(get_class($this), 0, -10); $this->name = substr(get_class($this), 0, -10);
} }
if ($this->viewPath == null) { if (!$this->viewPath) {
$this->viewPath = $this->name; $this->viewPath = $this->name;
} }
@ -454,7 +454,7 @@ class Controller extends Object implements CakeEventListener {
$this->passedArgs = array_merge($request->params['pass'], $request->params['named']); $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; $this->autoRender = false;
} }
if (!empty($request->params['bare'])) { if (!empty($request->params['bare'])) {
@ -966,14 +966,15 @@ class Controller extends Object implements CakeEventListener {
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::referer * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::referer
*/ */
public function referer($default = null, $local = false) { public function referer($default = null, $local = false) {
if ($this->request) { if (!$this->request) {
$referer = $this->request->referer($local); return '/';
if ($referer == '/' && $default != null) {
return Router::url($default, true);
}
return $referer;
} }
return '/';
$referer = $this->request->referer($local);
if ($referer == '/' && $default) {
return Router::url($default, true);
}
return $referer;
} }
/** /**
@ -1061,7 +1062,7 @@ class Controller extends Object implements CakeEventListener {
$cond[$key] = $value; $cond[$key] = $value;
} }
} }
if ($bool != null && strtoupper($bool) != 'AND') { if ($bool && strtoupper($bool) != 'AND') {
$cond = array($bool => $cond); $cond = array($bool => $cond);
} }
return $cond; return $cond;

View file

@ -146,7 +146,7 @@ class Scaffold {
$this->controller->viewClass = 'Scaffold'; $this->controller->viewClass = 'Scaffold';
} }
$this->_validSession = ( $this->_validSession = (
isset($this->controller->Session) && $this->controller->Session->valid() != false isset($this->controller->Session) && $this->controller->Session->valid()
); );
$this->_scaffold($request); $this->_scaffold($request);
} }

View file

@ -607,7 +607,7 @@ class App {
extract($parent, EXTR_OVERWRITE); extract($parent, EXTR_OVERWRITE);
} }
if ($name == null && $file == null) { if (!$name && !$file) {
return false; return false;
} }

View file

@ -170,6 +170,19 @@ class Configure {
return Hash::get(self::$_values, $var); return Hash::get(self::$_values, $var);
} }
/**
* Returns true if given variable is set in Configure.
*
* @param string $var Variable name to check for
* @return boolean True if variable is there
*/
public static function check($var = null) {
if (empty($var)) {
return false;
}
return Hash::get(self::$_values, $var) !== null;
}
/** /**
* Used to delete a variable from Configure. * Used to delete a variable from Configure.
* *
@ -306,10 +319,10 @@ class Configure {
public static function dump($key, $config = 'default', $keys = array()) { public static function dump($key, $config = 'default', $keys = array()) {
$reader = self::_getReader($config); $reader = self::_getReader($config);
if (!$reader) { if (!$reader) {
throw new ConfigureException(__d('cake', 'There is no "%s" adapter.', $config)); throw new ConfigureException(__d('cake_dev', 'There is no "%s" adapter.', $config));
} }
if (!method_exists($reader, 'dump')) { if (!method_exists($reader, 'dump')) {
throw new ConfigureException(__d('cake', 'The "%s" adapter, does not have a dump() method.', $config)); throw new ConfigureException(__d('cake_dev', 'The "%s" adapter, does not have a dump() method.', $config));
} }
$values = self::$_values; $values = self::$_values;
if (!empty($keys) && is_array($keys)) { if (!empty($keys) && is_array($keys)) {

View file

@ -102,10 +102,7 @@ class ExceptionRenderer {
if ($exception instanceof CakeException && !$methodExists) { if ($exception instanceof CakeException && !$methodExists) {
$method = '_cakeError'; $method = '_cakeError';
if (empty($template)) { if (empty($template) || $template == 'internalError') {
$template = 'error500';
}
if ($template == 'internalError') {
$template = 'error500'; $template = 'error500';
} }
} elseif ($exception instanceof PDOException) { } elseif ($exception instanceof PDOException) {
@ -119,13 +116,12 @@ class ExceptionRenderer {
} }
} }
if (Configure::read('debug') == 0) { $isNotDebug = !Configure::read('debug');
if ($method == '_cakeError') { if ($isNotDebug && $method == '_cakeError') {
$method = 'error400'; $method = 'error400';
} }
if ($code == 500) { if ($isNotDebug && $code == 500) {
$method = 'error500'; $method = 'error500';
}
} }
$this->template = $template; $this->template = $template;
$this->method = $method; $this->method = $method;
@ -147,7 +143,12 @@ class ExceptionRenderer {
if (!$request = Router::getRequest(true)) { if (!$request = Router::getRequest(true)) {
$request = new CakeRequest(); $request = new CakeRequest();
} }
$response = new CakeResponse(array('charset' => Configure::read('App.encoding'))); $response = new CakeResponse();
if (method_exists($exception, 'responseHeader')) {
$response->header($exception->responseHeader());
}
try { try {
$controller = new CakeErrorController($request, $response); $controller = new CakeErrorController($request, $response);
} catch (Exception $e) { } catch (Exception $e) {
@ -183,7 +184,7 @@ class ExceptionRenderer {
$this->controller->set(array( $this->controller->set(array(
'code' => $code, 'code' => $code,
'url' => h($url), 'url' => h($url),
'name' => $error->getMessage(), 'name' => h($error->getMessage()),
'error' => $error, 'error' => $error,
'_serialize' => array('code', 'url', 'name') '_serialize' => array('code', 'url', 'name')
)); ));
@ -199,13 +200,13 @@ class ExceptionRenderer {
*/ */
public function error400($error) { public function error400($error) {
$message = $error->getMessage(); $message = $error->getMessage();
if (Configure::read('debug') == 0 && $error instanceof CakeException) { if (!Configure::read('debug') && $error instanceof CakeException) {
$message = __d('cake', 'Not Found'); $message = __d('cake', 'Not Found');
} }
$url = $this->controller->request->here(); $url = $this->controller->request->here();
$this->controller->response->statusCode($error->getCode()); $this->controller->response->statusCode($error->getCode());
$this->controller->set(array( $this->controller->set(array(
'name' => $message, 'name' => h($message),
'url' => h($url), 'url' => h($url),
'error' => $error, 'error' => $error,
'_serialize' => array('name', 'url') '_serialize' => array('name', 'url')
@ -221,14 +222,14 @@ class ExceptionRenderer {
*/ */
public function error500($error) { public function error500($error) {
$message = $error->getMessage(); $message = $error->getMessage();
if (Configure::read('debug') == 0) { if (!Configure::read('debug')) {
$message = __d('cake', 'An Internal Error Has Occurred.'); $message = __d('cake', 'An Internal Error Has Occurred.');
} }
$url = $this->controller->request->here(); $url = $this->controller->request->here();
$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500; $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
$this->controller->response->statusCode($code); $this->controller->response->statusCode($code);
$this->controller->set(array( $this->controller->set(array(
'name' => $message, 'name' => h($message),
'message' => h($url), 'message' => h($url),
'error' => $error, 'error' => $error,
'_serialize' => array('name', 'message') '_serialize' => array('name', 'message')
@ -249,7 +250,7 @@ class ExceptionRenderer {
$this->controller->set(array( $this->controller->set(array(
'code' => $code, 'code' => $code,
'url' => h($url), 'url' => h($url),
'name' => $error->getMessage(), 'name' => h($error->getMessage()),
'error' => $error, 'error' => $error,
'_serialize' => array('code', 'url', 'name', 'error') '_serialize' => array('code', 'url', 'name', 'error')
)); ));

View file

@ -18,6 +18,43 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
/**
* Base class that all Exceptions extend.
*
* @package Cake.Error
*/
class CakeBaseException extends RuntimeException {
/**
* Array of headers to be passed to CakeResponse::header()
*
* @var array
*/
protected $_responseHeaders = null;
/**
* Get/set the response header to be used
*
* See also CakeResponse::header()
*
* @param string|array $header. An array of header strings or a single header string
* - an associative array of "header name" => "header value"
* - an array of string headers is also accepted
* @param string $value. The header value.
* @return array
*/
public function responseHeader($header = null, $value = null) {
if ($header) {
if (is_array($header)) {
return $this->_responseHeaders = $header;
}
$this->_responseHeaders = array($header => $value);
}
return $this->_responseHeaders;
}
}
/** /**
* Parent class for all of the HTTP related exceptions in CakePHP. * Parent class for all of the HTTP related exceptions in CakePHP.
* All HTTP status/error related exceptions should extend this class so * All HTTP status/error related exceptions should extend this class so
@ -26,7 +63,7 @@
* @package Cake.Error * @package Cake.Error
*/ */
if (!class_exists('HttpException')) { if (!class_exists('HttpException')) {
class HttpException extends RuntimeException { class HttpException extends CakeBaseException {
} }
} }
@ -168,7 +205,7 @@ class InternalErrorException extends HttpException {
* *
* @package Cake.Error * @package Cake.Error
*/ */
class CakeException extends RuntimeException { class CakeException extends CakeBaseException {
/** /**
* Array of attributes that are passed in from the constructor, and * Array of attributes that are passed in from the constructor, and

View file

@ -17,9 +17,9 @@
*/ */
/** /**
* Represent the transport class of events across the system, it receives a name, and subject and an optional * Represents the transport class of events across the system, it receives a name, and subject and an optional
* payload. The name can be any string that uniquely identifies the event across the application, while the subject * payload. The name can be any string that uniquely identifies the event across the application, while the subject
* represents the object that the event is applying to. * represents the object that the event applies to.
* *
* @package Cake.Event * @package Cake.Event
*/ */

View file

@ -18,15 +18,15 @@
/** /**
* Objects implementing this interface should declare the `implementedEvents` function * Objects implementing this interface should declare the `implementedEvents` function
* to hint the event manager what methods should be called when an event is triggered. * to notify the event manager what methods should be called when an event is triggered.
* *
* @package Cake.Event * @package Cake.Event
*/ */
interface CakeEventListener { interface CakeEventListener {
/** /**
* Returns a list of events this object is implementing, when the class is registered * Returns a list of events this object is implementing. When the class is registered
* in an event manager, each individual method will be associated to the respective event. * in an event manager, each individual method will be associated with the respective event.
* *
* ## Example: * ## Example:
* *

View file

@ -19,9 +19,9 @@
App::uses('CakeEventListener', 'Event'); App::uses('CakeEventListener', 'Event');
/** /**
* The event manager is responsible for keeping track of event listeners and pass the correct * The event manager is responsible for keeping track of event listeners, passing the correct
* data to them, and fire them in the correct order, when associated events are triggered. You * data to them, and firing them in the correct order, when associated events are triggered. You
* can create multiple instances of this objects to manage local events or keep a single instance * can create multiple instances of this object to manage local events or keep a single instance
* and pass it around to manage all events in your app. * and pass it around to manage all events in your app.
* *
* @package Cake.Event * @package Cake.Event
@ -29,7 +29,7 @@ App::uses('CakeEventListener', 'Event');
class CakeEventManager { class CakeEventManager {
/** /**
* The default priority queue value for new attached listeners * The default priority queue value for new, attached listeners
* *
* @var int * @var int
*/ */
@ -50,7 +50,7 @@ class CakeEventManager {
protected $_listeners = array(); protected $_listeners = array();
/** /**
* Internal flag to distinguish a common manager from the sigleton * Internal flag to distinguish a common manager from the singleton
* *
* @var boolean * @var boolean
*/ */
@ -62,7 +62,7 @@ class CakeEventManager {
* other managers were created. Usually for creating hook systems or inter-class * other managers were created. Usually for creating hook systems or inter-class
* communication * communication
* *
* If called with a first params, it will be set as the globally available instance * If called with the first parameter, it will be set as the globally available instance
* *
* @param CakeEventManager $manager * @param CakeEventManager $manager
* @return CakeEventManager the global event manager * @return CakeEventManager the global event manager
@ -83,15 +83,15 @@ class CakeEventManager {
* Adds a new listener to an event. Listeners * Adds a new listener to an event. Listeners
* *
* @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called * @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called
* when the event named with $eventKey is triggered. If a CakeEventListener instances is passed, then the `implementedEvents` * when the event named with $eventKey is triggered. If a CakeEventListener instance is passed, then the `implementedEvents`
* method will be called on the object to register the declared events individually as methods to be managed by this class. * method will be called on the object to register the declared events individually as methods to be managed by this class.
* It is possible to define multiple event handlers per event name. * It is possible to define multiple event handlers per event name.
* *
* @param string $eventKey The event unique identifier name to with the callback will be associated. If $callable * @param string $eventKey The event unique identifier name with which the callback will be associated. If $callable
* is an instance of CakeEventListener this argument will be ignored * is an instance of CakeEventListener this argument will be ignored
* *
* @param array $options used to set the `priority` and `passParams` flags to the listener. * @param array $options used to set the `priority` and `passParams` flags to the listener.
* Priorities are handled like queues, and multiple attachments into the same priority queue will be treated in * Priorities are handled like queues, and multiple attachments added to the same priority queue will be treated in
* the order of insertion. `passParams` means that the event data property will be converted to function arguments * the order of insertion. `passParams` means that the event data property will be converted to function arguments
* when the listener is called. If $called is an instance of CakeEventListener, this parameter will be ignored * when the listener is called. If $called is an instance of CakeEventListener, this parameter will be ignored
* *
@ -145,7 +145,7 @@ class CakeEventManager {
* Auxiliary function to extract and return a PHP callback type out of the callable definition * Auxiliary function to extract and return a PHP callback type out of the callable definition
* from the return value of the `implementedEvents` method on a CakeEventListener * from the return value of the `implementedEvents` method on a CakeEventListener
* *
* @param array $function the array taken from a handler definition for a event * @param array $function the array taken from a handler definition for an event
* @param CakeEventListener $object The handler object * @param CakeEventListener $object The handler object
* @return callback * @return callback
*/ */
@ -256,7 +256,7 @@ class CakeEventManager {
} }
/** /**
* Returns a list of all listeners for a eventKey in the order they should be called * Returns a list of all listeners for an eventKey in the order they should be called
* *
* @param string $eventKey * @param string $eventKey
* @return array * @return array

View file

@ -405,7 +405,7 @@ class I18n {
$header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header); $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
extract($header); extract($header);
if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) { if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && !$version) {
for ($n = 0; $n < $count; $n++) { for ($n = 0; $n < $count; $n++) {
$r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8)); $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
$msgid = substr($data, $r["offs"], $r["len"]); $msgid = substr($data, $r["offs"], $r["len"]);
@ -585,19 +585,19 @@ class I18n {
$string = $string[1]; $string = $string[1];
if (substr($string, 0, 2) === $this->_escape . 'x') { if (substr($string, 0, 2) === $this->_escape . 'x') {
$delimiter = $this->_escape . 'x'; $delimiter = $this->_escape . 'x';
return join('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string))))); return implode('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string)))));
} }
if (substr($string, 0, 2) === $this->_escape . 'd') { if (substr($string, 0, 2) === $this->_escape . 'd') {
$delimiter = $this->_escape . 'd'; $delimiter = $this->_escape . 'd';
return join('', array_map('chr', array_filter(explode($delimiter, $string)))); return implode('', array_map('chr', array_filter(explode($delimiter, $string))));
} }
if ($string[0] === $this->_escape && isset($string[1]) && is_numeric($string[1])) { if ($string[0] === $this->_escape && isset($string[1]) && is_numeric($string[1])) {
$delimiter = $this->_escape; $delimiter = $this->_escape;
return join('', array_map('chr', array_filter(explode($delimiter, $string)))); return implode('', array_map('chr', array_filter(explode($delimiter, $string))));
} }
if (substr($string, 0, 3) === 'U00') { if (substr($string, 0, 3) === 'U00') {
$delimiter = 'U00'; $delimiter = 'U00';
return join('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string))))); return implode('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string)))));
} }
if (preg_match('/U([0-9a-fA-F]{4})/', $string, $match)) { if (preg_match('/U([0-9a-fA-F]{4})/', $string, $match)) {
return Multibyte::ascii(array(hexdec($match[1]))); return Multibyte::ascii(array(hexdec($match[1])));

View file

@ -85,47 +85,53 @@ class L10n {
/** /**
* Maps ISO 639-3 to I10n::_l10nCatalog * Maps ISO 639-3 to I10n::_l10nCatalog
* The terminological codes (first one per language) should be used if possible.
* They are the ones building the path in `/APP/Locale/[code]/`
* The bibliographic codes are aliases.
* *
* @var array * @var array
*/ */
protected $_l10nMap = array( protected $_l10nMap = array(
/* Afrikaans */ 'afr' => 'af', /* Afrikaans */ 'afr' => 'af',
/* Albanian */ 'alb' => 'sq', /* Albanian */ 'sqi' => 'sq',
/* Albanian - bibliographic */ 'alb' => 'sq',
/* Arabic */ 'ara' => 'ar', /* Arabic */ 'ara' => 'ar',
/* Armenian - Armenia */ 'hye' => 'hy', /* Armenian/Armenia */ 'hye' => 'hy',
/* Basque */ 'eus' => 'eu',
/* Basque */ 'baq' => 'eu', /* Basque */ 'baq' => 'eu',
/* Tibetan */ 'bod' => 'bo', /* Tibetan */ 'bod' => 'bo',
/* Tibetan - bibliographic */ 'tib' => 'bo',
/* Bosnian */ 'bos' => 'bs', /* Bosnian */ 'bos' => 'bs',
/* Bulgarian */ 'bul' => 'bg', /* Bulgarian */ 'bul' => 'bg',
/* Byelorussian */ 'bel' => 'be', /* Byelorussian */ 'bel' => 'be',
/* Catalan */ 'cat' => 'ca', /* Catalan */ 'cat' => 'ca',
/* Chinese */ 'chi' => 'zh',
/* Chinese */ 'zho' => 'zh', /* Chinese */ 'zho' => 'zh',
/* Chinese - bibliographic */ 'chi' => 'zh',
/* Croatian */ 'hrv' => 'hr', /* Croatian */ 'hrv' => 'hr',
/* Czech */ 'cze' => 'cs',
/* Czech */ 'ces' => 'cs', /* Czech */ 'ces' => 'cs',
/* Czech - bibliographic */ 'cze' => 'cs',
/* Danish */ 'dan' => 'da', /* Danish */ 'dan' => 'da',
/* Dutch (Standard) */ 'dut' => 'nl',
/* Dutch (Standard) */ 'nld' => 'nl', /* Dutch (Standard) */ 'nld' => 'nl',
/* Dutch (Standard) - bibliographic */ 'dut' => 'nl',
/* English */ 'eng' => 'en', /* English */ 'eng' => 'en',
/* Estonian */ 'est' => 'et', /* Estonian */ 'est' => 'et',
/* Faeroese */ 'fao' => 'fo', /* Faeroese */ 'fao' => 'fo',
/* Farsi */ 'fas' => 'fa', /* Farsi/Persian */ 'fas' => 'fa',
/* Farsi */ 'per' => 'fa', /* Farsi/Persian - bibliographic */ 'per' => 'fa',
/* Finnish */ 'fin' => 'fi', /* Finnish */ 'fin' => 'fi',
/* French (Standard) */ 'fre' => 'fr',
/* French (Standard) */ 'fra' => 'fr', /* French (Standard) */ 'fra' => 'fr',
/* French (Standard) - bibliographic */ 'fre' => 'fr',
/* Gaelic (Scots) */ 'gla' => 'gd', /* Gaelic (Scots) */ 'gla' => 'gd',
/* Galician */ 'glg' => 'gl', /* Galician */ 'glg' => 'gl',
/* German (Standard) */ 'deu' => 'de', /* German (Standard) */ 'deu' => 'de',
/* German (Standard) */ 'ger' => 'de', /* German (Standard) - bibliographic */ 'ger' => 'de',
/* Greek */ 'gre' => 'el', /* Greek */ 'gre' => 'el',
/* Greek */ 'ell' => 'el', /* Greek */ 'ell' => 'el',
/* Hebrew */ 'heb' => 'he', /* Hebrew */ 'heb' => 'he',
/* Hindi */ 'hin' => 'hi', /* Hindi */ 'hin' => 'hi',
/* Hungarian */ 'hun' => 'hu', /* Hungarian */ 'hun' => 'hu',
/* Icelandic */ 'ice' => 'is',
/* Icelandic */ 'isl' => 'is', /* Icelandic */ 'isl' => 'is',
/* Icelandic - bibliographic */ 'ice' => 'is',
/* Indonesian */ 'ind' => 'id', /* Indonesian */ 'ind' => 'id',
/* Irish */ 'gle' => 'ga', /* Irish */ 'gle' => 'ga',
/* Italian */ 'ita' => 'it', /* Italian */ 'ita' => 'it',
@ -133,10 +139,10 @@ class L10n {
/* Korean */ 'kor' => 'ko', /* Korean */ 'kor' => 'ko',
/* Latvian */ 'lav' => 'lv', /* Latvian */ 'lav' => 'lv',
/* Lithuanian */ 'lit' => 'lt', /* Lithuanian */ 'lit' => 'lt',
/* Macedonian */ 'mac' => 'mk',
/* Macedonian */ 'mkd' => 'mk', /* Macedonian */ 'mkd' => 'mk',
/* Malaysian */ 'may' => 'ms', /* Macedonian - bibliographic */ 'mac' => 'mk',
/* Malaysian */ 'msa' => 'ms', /* Malaysian */ 'msa' => 'ms',
/* Malaysian - bibliographic */ 'may' => 'ms',
/* Maltese */ 'mlt' => 'mt', /* Maltese */ 'mlt' => 'mt',
/* Norwegian */ 'nor' => 'no', /* Norwegian */ 'nor' => 'no',
/* Norwegian Bokmal */ 'nob' => 'nb', /* Norwegian Bokmal */ 'nob' => 'nb',
@ -144,14 +150,13 @@ class L10n {
/* Polish */ 'pol' => 'pl', /* Polish */ 'pol' => 'pl',
/* Portuguese (Portugal) */ 'por' => 'pt', /* Portuguese (Portugal) */ 'por' => 'pt',
/* Rhaeto-Romanic */ 'roh' => 'rm', /* Rhaeto-Romanic */ 'roh' => 'rm',
/* Romanian */ 'rum' => 'ro',
/* Romanian */ 'ron' => 'ro', /* Romanian */ 'ron' => 'ro',
/* Romanian - bibliographic */ 'rum' => 'ro',
/* Russian */ 'rus' => 'ru', /* Russian */ 'rus' => 'ru',
/* Sami (Lappish) */ 'smi' => 'sz', /* Sami (Lappish) */ 'smi' => 'sz',
/* Serbian */ 'scc' => 'sr',
/* Serbian */ 'srp' => 'sr', /* Serbian */ 'srp' => 'sr',
/* Slovak */ 'slo' => 'sk',
/* Slovak */ 'slk' => 'sk', /* Slovak */ 'slk' => 'sk',
/* Slovak - bibliographic */ 'slo' => 'sk',
/* Slovenian */ 'slv' => 'sl', /* Slovenian */ 'slv' => 'sl',
/* Sorbian */ 'wen' => 'sb', /* Sorbian */ 'wen' => 'sb',
/* Spanish (Spain - Traditional) */ 'spa' => 'es', /* Spanish (Spain - Traditional) */ 'spa' => 'es',
@ -165,6 +170,7 @@ class L10n {
/* Venda */ 'ven' => 've', /* Venda */ 'ven' => 've',
/* Vietnamese */ 'vie' => 'vi', /* Vietnamese */ 'vie' => 'vi',
/* Welsh */ 'cym' => 'cy', /* Welsh */ 'cym' => 'cy',
/* Welsh - bibliographic */ 'wel' => 'cy',
/* Xhosa */ 'xho' => 'xh', /* Xhosa */ 'xho' => 'xh',
/* Yiddish */ 'yid' => 'yi', /* Yiddish */ 'yid' => 'yi',
/* Zulu */ 'zul' => 'zu' /* Zulu */ 'zul' => 'zu'
@ -203,7 +209,7 @@ class L10n {
'bo-in' => array('language' => 'Tibetan (India)', 'locale' => 'bo_in', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'), 'bo-in' => array('language' => 'Tibetan (India)', 'locale' => 'bo_in', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'),
'bs' => array('language' => 'Bosnian', 'locale' => 'bos', 'localeFallback' => 'bos', 'charset' => 'utf-8', 'direction' => 'ltr'), 'bs' => array('language' => 'Bosnian', 'locale' => 'bos', 'localeFallback' => 'bos', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ca' => array('language' => 'Catalan', 'locale' => 'cat', 'localeFallback' => 'cat', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ca' => array('language' => 'Catalan', 'locale' => 'cat', 'localeFallback' => 'cat', 'charset' => 'utf-8', 'direction' => 'ltr'),
'cs' => array('language' => 'Czech', 'locale' => 'cze', 'localeFallback' => 'cze', 'charset' => 'utf-8', 'direction' => 'ltr'), 'cs' => array('language' => 'Czech', 'locale' => 'ces', 'localeFallback' => 'ces', 'charset' => 'utf-8', 'direction' => 'ltr'),
'da' => array('language' => 'Danish', 'locale' => 'dan', 'localeFallback' => 'dan', 'charset' => 'utf-8', 'direction' => 'ltr'), 'da' => array('language' => 'Danish', 'locale' => 'dan', 'localeFallback' => 'dan', 'charset' => 'utf-8', 'direction' => 'ltr'),
'de' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'), 'de' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
'de-at' => array('language' => 'German (Austria)', 'locale' => 'de_at', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'), 'de-at' => array('language' => 'German (Austria)', 'locale' => 'de_at', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
@ -245,16 +251,16 @@ class L10n {
'es-uy' => array('language' => 'Spanish (Uruguay)', 'locale' => 'es_uy', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'), 'es-uy' => array('language' => 'Spanish (Uruguay)', 'locale' => 'es_uy', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'es-ve' => array('language' => 'Spanish (Venezuela)', 'locale' => 'es_ve', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'), 'es-ve' => array('language' => 'Spanish (Venezuela)', 'locale' => 'es_ve', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'et' => array('language' => 'Estonian', 'locale' => 'est', 'localeFallback' => 'est', 'charset' => 'utf-8', 'direction' => 'ltr'), 'et' => array('language' => 'Estonian', 'locale' => 'est', 'localeFallback' => 'est', 'charset' => 'utf-8', 'direction' => 'ltr'),
'eu' => array('language' => 'Basque', 'locale' => 'baq', 'localeFallback' => 'baq', 'charset' => 'utf-8', 'direction' => 'ltr'), 'eu' => array('language' => 'Basque', 'locale' => 'eus', 'localeFallback' => 'eus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fa' => array('language' => 'Farsi', 'locale' => 'per', 'localeFallback' => 'per', 'charset' => 'utf-8', 'direction' => 'rtl'), 'fa' => array('language' => 'Farsi', 'locale' => 'per', 'localeFallback' => 'per', 'charset' => 'utf-8', 'direction' => 'rtl'),
'fi' => array('language' => 'Finnish', 'locale' => 'fin', 'localeFallback' => 'fin', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fi' => array('language' => 'Finnish', 'locale' => 'fin', 'localeFallback' => 'fin', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fo' => array('language' => 'Faeroese', 'locale' => 'fao', 'localeFallback' => 'fao', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fo' => array('language' => 'Faeroese', 'locale' => 'fao', 'localeFallback' => 'fao', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr' => array('language' => 'French (Standard)', 'locale' => 'fre', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr' => array('language' => 'French (Standard)', 'locale' => 'fra', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'), 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ga' => array('language' => 'Irish', 'locale' => 'gle', 'localeFallback' => 'gle', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ga' => array('language' => 'Irish', 'locale' => 'gle', 'localeFallback' => 'gle', 'charset' => 'utf-8', 'direction' => 'ltr'),
'gd' => array('language' => 'Gaelic (Scots)', 'locale' => 'gla', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'), 'gd' => array('language' => 'Gaelic (Scots)', 'locale' => 'gla', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
'gd-ie' => array('language' => 'Gaelic (Irish)', 'locale' => 'gd_ie', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'), 'gd-ie' => array('language' => 'Gaelic (Irish)', 'locale' => 'gd_ie', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
@ -266,7 +272,7 @@ class L10n {
'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'),
'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'), 'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
'in' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'), 'in' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
'is' => array('language' => 'Icelandic', 'locale' => 'ice', 'localeFallback' => 'ice', 'charset' => 'utf-8', 'direction' => 'ltr'), 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'), 'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'), 'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'),
@ -276,14 +282,14 @@ class L10n {
'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'), 'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'),
'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'), 'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'),
'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'), 'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'),
'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'),
'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ms' => array('language' => 'Malaysian', 'locale' => 'may', 'localeFallback' => 'may', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ms' => array('language' => 'Malaysian', 'locale' => 'msa', 'localeFallback' => 'msa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'mt' => array('language' => 'Maltese', 'locale' => 'mlt', 'localeFallback' => 'mlt', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mt' => array('language' => 'Maltese', 'locale' => 'mlt', 'localeFallback' => 'mlt', 'charset' => 'utf-8', 'direction' => 'ltr'),
'n' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'), 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nb' => array('language' => 'Norwegian Bokmal', 'locale' => 'nob', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'), 'nb' => array('language' => 'Norwegian Bokmal', 'locale' => 'nob', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'), 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'), 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nn' => array('language' => 'Norwegian Nynorsk', 'locale' => 'nno', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'), 'nn' => array('language' => 'Norwegian Nynorsk', 'locale' => 'nno', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'), 'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
'p' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'), 'p' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
@ -291,15 +297,15 @@ class L10n {
'pt' => array('language' => 'Portuguese (Portugal)', 'locale' => 'por', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'), 'pt' => array('language' => 'Portuguese (Portugal)', 'locale' => 'por', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'), 'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'), 'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ro' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ro' => array('language' => 'Romanian', 'locale' => 'ron', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ru' => array('language' => 'Russian', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ru' => array('language' => 'Russian', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ru-mo' => array('language' => 'Russian (Moldavia)', 'locale' => 'ru_mo', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ru-mo' => array('language' => 'Russian (Moldavia)', 'locale' => 'ru_mo', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sk' => array('language' => 'Slovak', 'locale' => 'slo', 'localeFallback' => 'slo', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sk' => array('language' => 'Slovak', 'locale' => 'slk', 'localeFallback' => 'slk', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sl' => array('language' => 'Slovenian', 'locale' => 'slv', 'localeFallback' => 'slv', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sl' => array('language' => 'Slovenian', 'locale' => 'slv', 'localeFallback' => 'slv', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sq' => array('language' => 'Albanian', 'locale' => 'alb', 'localeFallback' => 'alb', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sq' => array('language' => 'Albanian', 'locale' => 'sqi', 'localeFallback' => 'sqi', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sr' => array('language' => 'Serbian', 'locale' => 'scc', 'localeFallback' => 'scc', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sr' => array('language' => 'Serbian', 'locale' => 'srp', 'localeFallback' => 'srp', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sv' => array('language' => 'Swedish', 'locale' => 'swe', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sv' => array('language' => 'Swedish', 'locale' => 'swe', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sv-fi' => array('language' => 'Swedish (Finland)', 'locale' => 'sv_fi', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sv-fi' => array('language' => 'Swedish (Finland)', 'locale' => 'sv_fi', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sx' => array('language' => 'Sutu', 'locale' => 'sx', 'localeFallback' => 'sx', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sx' => array('language' => 'Sutu', 'locale' => 'sx', 'localeFallback' => 'sx', 'charset' => 'utf-8', 'direction' => 'ltr'),
@ -315,11 +321,11 @@ class L10n {
'cy' => array('language' => 'Welsh', 'locale' => 'cym', 'localeFallback' => 'cym', 'charset' => 'utf-8', 'direction' => 'ltr'), 'cy' => array('language' => 'Welsh', 'locale' => 'cym', 'localeFallback' => 'cym', 'charset' => 'utf-8', 'direction' => 'ltr'),
'xh' => array('language' => 'Xhosa', 'locale' => 'xho', 'localeFallback' => 'xho', 'charset' => 'utf-8', 'direction' => 'ltr'), 'xh' => array('language' => 'Xhosa', 'locale' => 'xho', 'localeFallback' => 'xho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'yi' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr'), 'yi' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zh' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh' => array('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'chi', 'charset' => 'GB2312', 'direction' => 'ltr'), 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'zho', 'charset' => 'GB2312', 'direction' => 'ltr'),
'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zu' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr') 'zu' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr')
); );

View file

@ -18,261 +18,6 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
if (!function_exists('mb_stripos')) {
/**
* Find position of first occurrence of a case-insensitive string.
*
* @param string $haystack The string from which to get the position of the first occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param integer $offset The position in $haystack to start searching.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer|boolean The numeric position of the first occurrence of $needle in the $haystack string, or false
* if $needle is not found.
*/
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) {
return Multibyte::stripos($haystack, $needle, $offset);
}
}
if (!function_exists('mb_stristr')) {
/**
* Finds first occurrence of a string within another, case insensitive.
*
* @param string $haystack The string from which to get the first occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param boolean $part Determines which portion of $haystack this function returns.
* If set to true, it returns all of $haystack from the beginning to the first occurrence of $needle.
* If set to false, it returns all of $haystack from the first occurrence of $needle to the end,
* Default value is false.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string|boolean The portion of $haystack, or false if $needle is not found.
*/
function mb_stristr($haystack, $needle, $part = false, $encoding = null) {
return Multibyte::stristr($haystack, $needle, $part);
}
}
if (!function_exists('mb_strlen')) {
/**
* Get string length.
*
* @param string $string The string being checked for length.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer The number of characters in string $string having character encoding encoding.
* A multi-byte character is counted as 1.
*/
function mb_strlen($string, $encoding = null) {
return Multibyte::strlen($string);
}
}
if (!function_exists('mb_strpos')) {
/**
* Find position of first occurrence of a string.
*
* @param string $haystack The string being checked.
* @param string $needle The position counted from the beginning of haystack.
* @param integer $offset The search offset. If it is not specified, 0 is used.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer|boolean The numeric position of the first occurrence of $needle in the $haystack string.
* If $needle is not found, it returns false.
*/
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) {
return Multibyte::strpos($haystack, $needle, $offset);
}
}
if (!function_exists('mb_strrchr')) {
/**
* Finds the last occurrence of a character in a string within another.
*
* @param string $haystack The string from which to get the last occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param boolean $part Determines which portion of $haystack this function returns.
* If set to true, it returns all of $haystack from the beginning to the last occurrence of $needle.
* If set to false, it returns all of $haystack from the last occurrence of $needle to the end,
* Default value is false.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string|boolean The portion of $haystack. or false if $needle is not found.
*/
function mb_strrchr($haystack, $needle, $part = false, $encoding = null) {
return Multibyte::strrchr($haystack, $needle, $part);
}
}
if (!function_exists('mb_strrichr')) {
/**
* Finds the last occurrence of a character in a string within another, case insensitive.
*
* @param string $haystack The string from which to get the last occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param boolean $part Determines which portion of $haystack this function returns.
* If set to true, it returns all of $haystack from the beginning to the last occurrence of $needle.
* If set to false, it returns all of $haystack from the last occurrence of $needle to the end,
* Default value is false.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string|boolean The portion of $haystack. or false if $needle is not found.
*/
function mb_strrichr($haystack, $needle, $part = false, $encoding = null) {
return Multibyte::strrichr($haystack, $needle, $part);
}
}
if (!function_exists('mb_strripos')) {
/**
* Finds position of last occurrence of a string within another, case insensitive
*
* @param string $haystack The string from which to get the position of the last occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param integer $offset The position in $haystack to start searching.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string,
* or false if $needle is not found.
*/
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) {
return Multibyte::strripos($haystack, $needle, $offset);
}
}
if (!function_exists('mb_strrpos')) {
/**
* Find position of last occurrence of a string in a string.
*
* @param string $haystack The string being checked, for the last occurrence of $needle.
* @param string $needle The string to find in $haystack.
* @param integer $offset May be specified to begin searching an arbitrary number of characters into the string.
* Negative values will stop searching at an arbitrary point prior to the end of the string.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string.
* If $needle is not found, it returns false.
*/
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) {
return Multibyte::strrpos($haystack, $needle, $offset);
}
}
if (!function_exists('mb_strstr')) {
/**
* Finds first occurrence of a string within another
*
* @param string $haystack The string from which to get the first occurrence of $needle.
* @param string $needle The string to find in $haystack
* @param boolean $part Determines which portion of $haystack this function returns.
* If set to true, it returns all of $haystack from the beginning to the first occurrence of $needle.
* If set to false, it returns all of $haystack from the first occurrence of $needle to the end,
* Default value is FALSE.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string|boolean The portion of $haystack, or true if $needle is not found.
*/
function mb_strstr($haystack, $needle, $part = false, $encoding = null) {
return Multibyte::strstr($haystack, $needle, $part);
}
}
if (!function_exists('mb_strtolower')) {
/**
* Make a string lowercase
*
* @param string $string The string being lowercased.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string with all alphabetic characters converted to lowercase.
*/
function mb_strtolower($string, $encoding = null) {
return Multibyte::strtolower($string);
}
}
if (!function_exists('mb_strtoupper')) {
/**
* Make a string uppercase
*
* @param string $string The string being uppercased.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string with all alphabetic characters converted to uppercase.
*/
function mb_strtoupper($string, $encoding = null) {
return Multibyte::strtoupper($string);
}
}
if (!function_exists('mb_substr_count')) {
/**
* Count the number of substring occurrences
*
* @param string $haystack The string being checked.
* @param string $needle The string being found.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return integer The number of times the $needle substring occurs in the $haystack string.
*/
function mb_substr_count($haystack, $needle, $encoding = null) {
return Multibyte::substrCount($haystack, $needle);
}
}
if (!function_exists('mb_substr')) {
/**
* Get part of string
*
* @param string $string The string being checked.
* @param integer $start The first position used in $string.
* @param integer $length The maximum length of the returned string.
* @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
* @return string The portion of $string specified by the $string and $length parameters.
*/
function mb_substr($string, $start, $length = null, $encoding = null) {
return Multibyte::substr($string, $start, $length);
}
}
if (!function_exists('mb_encode_mimeheader')) {
/**
* Encode string for MIME header
*
* @param string $str The string being encoded
* @param string $charset specifies the name of the character set in which str is represented in.
* The default value is determined by the current NLS setting (mbstring.language).
* @param string $transfer_encoding specifies the scheme of MIME encoding.
* It should be either "B" (Base64) or "Q" (Quoted-Printable). Falls back to "B" if not given.
* @param string $linefeed specifies the EOL (end-of-line) marker with which
* mb_encode_mimeheader() performs line-folding
* (a » RFC term, the act of breaking a line longer than a certain length into multiple lines.
* The length is currently hard-coded to 74 characters). Falls back to "\r\n" (CRLF) if not given.
* @param integer $indent [definition unknown and appears to have no affect]
* @return string A converted version of the string represented in ASCII.
*/
function mb_encode_mimeheader($str, $charset = 'UTF-8', $transferEncoding = 'B', $linefeed = "\r\n", $indent = 1) {
return Multibyte::mimeEncode($str, $charset, $linefeed);
}
}
/** /**
* Multibyte handling methods. * Multibyte handling methods.
* *
@ -1124,7 +869,7 @@ class Multibyte {
public static function checkMultibyte($string) { public static function checkMultibyte($string) {
$length = strlen($string); $length = strlen($string);
for ($i = 0; $i < $length; $i++ ) { for ($i = 0; $i < $length; $i++) {
$value = ord(($string[$i])); $value = ord(($string[$i]));
if ($value > 128) { if ($value > 128) {
return true; return true;

View file

@ -18,6 +18,7 @@
*/ */
App::uses('BaseLog', 'Log/Engine'); App::uses('BaseLog', 'Log/Engine');
App::uses('Hash', 'Utility');
/** /**
* File Storage stream for Logging. Writes logs to different files * File Storage stream for Logging. Writes logs to different files

View file

@ -18,6 +18,7 @@
* @since CakePHP v 1.2.0.4487 * @since CakePHP v 1.2.0.4487
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('ModelBehavior', 'Model');
App::uses('AclNode', 'Model'); App::uses('AclNode', 'Model');
App::uses('Hash', 'Utility'); App::uses('Hash', 'Utility');

View file

@ -18,6 +18,7 @@
* @since CakePHP(tm) v 1.2.0.5669 * @since CakePHP(tm) v 1.2.0.5669
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('ModelBehavior', 'Model');
/** /**
* Behavior to allow for dynamic and atomic manipulation of a Model's associations * Behavior to allow for dynamic and atomic manipulation of a Model's associations
@ -174,7 +175,7 @@ class ContainableBehavior extends ModelBehavior {
} }
if ($this->settings[$Model->alias]['recursive']) { if ($this->settings[$Model->alias]['recursive']) {
$query['recursive'] = (isset($query['recursive'])) ? $query['recursive'] : $containments['depth']; $query['recursive'] = (isset($query['recursive'])) ? max($query['recursive'], $containments['depth']) : $containments['depth'];
} }
$autoFields = ($this->settings[$Model->alias]['autoFields'] $autoFields = ($this->settings[$Model->alias]['autoFields']

View file

@ -13,6 +13,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('ModelBehavior', 'Model');
App::uses('I18n', 'I18n'); App::uses('I18n', 'I18n');
App::uses('I18nModel', 'Model'); App::uses('I18nModel', 'Model');
@ -128,7 +129,7 @@ class TranslateBehavior extends ModelBehavior {
'conditions' => array( 'conditions' => array(
$Model->escapeField() => $db->identifier($RuntimeModel->escapeField('foreign_key')), $Model->escapeField() => $db->identifier($RuntimeModel->escapeField('foreign_key')),
$RuntimeModel->escapeField('model') => $Model->name, $RuntimeModel->escapeField('model') => $Model->name,
$RuntimeModel->escapeField('locale') => $locale $RuntimeModel->escapeField('locale') => $locale
) )
); );
$conditionFields = $this->_checkConditions($Model, $query); $conditionFields = $this->_checkConditions($Model, $query);
@ -193,7 +194,7 @@ class TranslateBehavior extends ModelBehavior {
*/ */
protected function _checkConditions(Model $Model, $query) { protected function _checkConditions(Model $Model, $query) {
$conditionFields = array(); $conditionFields = array();
if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions'])) ) { if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions']))) {
return $conditionFields; return $conditionFields;
} }
foreach ($query['conditions'] as $col => $val) { foreach ($query['conditions'] as $col => $val) {
@ -337,7 +338,7 @@ class TranslateBehavior extends ModelBehavior {
* @return boolean true. * @return boolean true.
*/ */
public function beforeSave(Model $Model, $options = array()) { public function beforeSave(Model $Model, $options = array()) {
if (isset($options['validate']) && $options['validate'] == false) { if (isset($options['validate']) && !$options['validate']) {
unset($this->runtime[$Model->alias]['beforeSave']); unset($this->runtime[$Model->alias]['beforeSave']);
} }
if (isset($this->runtime[$Model->alias]['beforeSave'])) { if (isset($this->runtime[$Model->alias]['beforeSave'])) {
@ -409,7 +410,6 @@ class TranslateBehavior extends ModelBehavior {
if (!isset($this->runtime[$Model->alias]['beforeValidate']) && !isset($this->runtime[$Model->alias]['beforeSave'])) { if (!isset($this->runtime[$Model->alias]['beforeValidate']) && !isset($this->runtime[$Model->alias]['beforeSave'])) {
return true; return true;
} }
$locale = $this->_getLocale($Model);
if (isset($this->runtime[$Model->alias]['beforeValidate'])) { if (isset($this->runtime[$Model->alias]['beforeValidate'])) {
$tempData = $this->runtime[$Model->alias]['beforeValidate']; $tempData = $this->runtime[$Model->alias]['beforeValidate'];
} else { } else {
@ -420,21 +420,10 @@ class TranslateBehavior extends ModelBehavior {
$conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id); $conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id);
$RuntimeModel = $this->translateModel($Model); $RuntimeModel = $this->translateModel($Model);
$fields = array_merge(
$this->settings[$Model->alias],
$this->runtime[$Model->alias]['fields']
);
if ($created) { if ($created) {
// set each field value to an empty string $tempData = $this->_prepareTranslations($Model, $tempData);
foreach ($fields as $key => $field) {
if (!is_numeric($key)) {
$field = $key;
}
if (!isset($tempData[$field])) {
$tempData[$field] = '';
}
}
} }
$locale = $this->_getLocale($Model);
foreach ($tempData as $field => $value) { foreach ($tempData as $field => $value) {
unset($conditions['content']); unset($conditions['content']);
@ -451,7 +440,10 @@ class TranslateBehavior extends ModelBehavior {
} }
$translations = $RuntimeModel->find('list', array( $translations = $RuntimeModel->find('list', array(
'conditions' => $conditions, 'conditions' => $conditions,
'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id') 'fields' => array(
$RuntimeModel->alias . '.locale',
$RuntimeModel->alias . '.id'
)
)); ));
foreach ($value as $_locale => $_value) { foreach ($value as $_locale => $_value) {
$RuntimeModel->create(); $RuntimeModel->create();
@ -470,6 +462,37 @@ class TranslateBehavior extends ModelBehavior {
} }
} }
/**
* Prepares the data to be saved for translated records.
* Add blank fields, and populates data for multi-locale saves.
*
* @param array $data The sparse data that was provided.
* @return array The fully populated data to save.
*/
protected function _prepareTranslations(Model $Model, $data) {
$fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']);
$locales = array();
foreach ($data as $key => $value) {
if (is_array($value)) {
$locales = array_merge($locales, array_keys($value));
}
}
$locales = array_unique($locales);
$hasLocales = count($locales) > 0;
foreach ($fields as $key => $field) {
if (!is_numeric($key)) {
$field = $key;
}
if ($hasLocales && !isset($data[$field])) {
$data[$field] = array_fill_keys($locales, '');
} elseif (!isset($data[$field])) {
$data[$field] = '';
}
}
return $data;
}
/** /**
* afterDelete Callback * afterDelete Callback
* *
@ -478,10 +501,7 @@ class TranslateBehavior extends ModelBehavior {
*/ */
public function afterDelete(Model $Model) { public function afterDelete(Model $Model) {
$RuntimeModel = $this->translateModel($Model); $RuntimeModel = $this->translateModel($Model);
$conditions = array( $conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id);
'model' => $Model->alias,
'foreign_key' => $Model->id
);
$RuntimeModel->deleteAll($conditions); $RuntimeModel->deleteAll($conditions);
} }
@ -549,10 +569,7 @@ class TranslateBehavior extends ModelBehavior {
} }
$associations = array(); $associations = array();
$RuntimeModel = $this->translateModel($Model); $RuntimeModel = $this->translateModel($Model);
$default = array( $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
'className' => $RuntimeModel->alias,
'foreignKey' => 'foreign_key'
);
foreach ($fields as $key => $value) { foreach ($fields as $key => $value) {
if (is_numeric($key)) { if (is_numeric($key)) {

View file

@ -18,6 +18,7 @@
* @since CakePHP v 1.2.0.4487 * @since CakePHP v 1.2.0.4487
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('ModelBehavior', 'Model');
/** /**
* Tree Behavior. * Tree Behavior.
@ -354,17 +355,16 @@ class TreeBehavior extends ModelBehavior {
$recursive = $overrideRecursive; $recursive = $overrideRecursive;
} }
if ($keyPath == null && $valuePath == null && $Model->hasField($Model->displayField)) { $fields = null;
if (!$keyPath && !$valuePath && $Model->hasField($Model->displayField)) {
$fields = array($Model->primaryKey, $Model->displayField, $left, $right); $fields = array($Model->primaryKey, $Model->displayField, $left, $right);
} else {
$fields = null;
} }
if ($keyPath == null) { if (!$keyPath) {
$keyPath = '{n}.' . $Model->alias . '.' . $Model->primaryKey; $keyPath = '{n}.' . $Model->alias . '.' . $Model->primaryKey;
} }
if ($valuePath == null) { if (!$valuePath) {
$valuePath = array('%s%s', '{n}.tree_prefix', '{n}.' . $Model->alias . '.' . $Model->displayField); $valuePath = array('%s%s', '{n}.tree_prefix', '{n}.' . $Model->alias . '.' . $Model->displayField);
} elseif (is_string($valuePath)) { } elseif (is_string($valuePath)) {
@ -644,9 +644,8 @@ class TreeBehavior extends ModelBehavior {
$db = ConnectionManager::getDataSource($Model->useDbConfig); $db = ConnectionManager::getDataSource($Model->useDbConfig);
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) { foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
$path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]); $path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]);
if ($path == null || count($path) < 2) { $parentId = null;
$parentId = null; if (count($path) > 1) {
} else {
$parentId = $path[count($path) - 2][$Model->alias][$Model->primaryKey]; $parentId = $path[count($path) - 2][$Model->alias][$Model->primaryKey];
} }
$Model->updateAll(array($parent => $db->value($parentId, $parent)), array($Model->escapeField() => $array[$Model->alias][$Model->primaryKey])); $Model->updateAll(array($parent => $db->value($parentId, $parent)), array($Model->escapeField() => $array[$Model->alias][$Model->primaryKey]));
@ -799,7 +798,7 @@ class TreeBehavior extends ModelBehavior {
$scope, 'OR' => array($Model->escapeField($left) => $i, $Model->escapeField($right) => $i) $scope, 'OR' => array($Model->escapeField($left) => $i, $Model->escapeField($right) => $i)
))); )));
if ($count != 1) { if ($count != 1) {
if ($count == 0) { if (!$count) {
$errors[] = array('index', $i, 'missing'); $errors[] = array('index', $i, 'missing');
} else { } else {
$errors[] = array('index', $i, 'duplicate'); $errors[] = array('index', $i, 'duplicate');

View file

@ -254,44 +254,50 @@ class CakeSchema extends Object {
continue; continue;
} }
if (!is_object($Object) || $Object->useTable === false) {
continue;
}
$db = $Object->getDataSource(); $db = $Object->getDataSource();
if (is_object($Object) && $Object->useTable !== false) {
$fulltable = $table = $db->fullTableName($Object, false, false); $fulltable = $table = $db->fullTableName($Object, false, false);
if ($prefix && strpos($table, $prefix) !== 0) { if ($prefix && strpos($table, $prefix) !== 0) {
continue;
}
if (!in_array($fulltable, $currentTables)) {
continue;
}
$table = $this->_noPrefixTable($prefix, $table);
$key = array_search($fulltable, $currentTables);
if (empty($tables[$table])) {
$tables[$table] = $this->_columns($Object);
$tables[$table]['indexes'] = $db->index($Object);
$tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
unset($currentTables[$key]);
}
if (empty($Object->hasAndBelongsToMany)) {
continue;
}
foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) {
if (isset($assocData['with'])) {
$class = $assocData['with'];
}
if (!is_object($Object->$class)) {
continue; continue;
} }
$table = $this->_noPrefixTable($prefix, $table); $withTable = $db->fullTableName($Object->$class, false, false);
if ($prefix && strpos($withTable, $prefix) !== 0) {
continue;
}
if (in_array($withTable, $currentTables)) {
$key = array_search($withTable, $currentTables);
$noPrefixWith = $this->_noPrefixTable($prefix, $withTable);
if (in_array($fulltable, $currentTables)) { $tables[$noPrefixWith] = $this->_columns($Object->$class);
$key = array_search($fulltable, $currentTables); $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class);
if (empty($tables[$table])) { $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable);
$tables[$table] = $this->_columns($Object); unset($currentTables[$key]);
$tables[$table]['indexes'] = $db->index($Object);
$tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
unset($currentTables[$key]);
}
if (!empty($Object->hasAndBelongsToMany)) {
foreach ($Object->hasAndBelongsToMany as $assocData) {
if (isset($assocData['with'])) {
$class = $assocData['with'];
}
if (is_object($Object->$class)) {
$withTable = $db->fullTableName($Object->$class, false, false);
if ($prefix && strpos($withTable, $prefix) !== 0) {
continue;
}
if (in_array($withTable, $currentTables)) {
$key = array_search($withTable, $currentTables);
$noPrefixWith = $this->_noPrefixTable($prefix, $withTable);
$tables[$noPrefixWith] = $this->_columns($Object->$class);
$tables[$noPrefixWith]['indexes'] = $db->index($Object->$class);
$tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable);
unset($currentTables[$key]);
}
}
}
}
} }
} }
} }
@ -412,28 +418,28 @@ class CakeSchema extends Object {
} }
$col = "\t\t'{$field}' => array('type' => '" . $value['type'] . "', "; $col = "\t\t'{$field}' => array('type' => '" . $value['type'] . "', ";
unset($value['type']); unset($value['type']);
$col .= join(', ', $this->_values($value)); $col .= implode(', ', $this->_values($value));
} elseif ($field == 'indexes') { } elseif ($field == 'indexes') {
$col = "\t\t'indexes' => array(\n\t\t\t"; $col = "\t\t'indexes' => array(\n\t\t\t";
$props = array(); $props = array();
foreach ((array)$value as $key => $index) { foreach ((array)$value as $key => $index) {
$props[] = "'{$key}' => array(" . join(', ', $this->_values($index)) . ")"; $props[] = "'{$key}' => array(" . implode(', ', $this->_values($index)) . ")";
} }
$col .= join(",\n\t\t\t", $props) . "\n\t\t"; $col .= implode(",\n\t\t\t", $props) . "\n\t\t";
} elseif ($field == 'tableParameters') { } elseif ($field == 'tableParameters') {
$col = "\t\t'tableParameters' => array("; $col = "\t\t'tableParameters' => array(";
$props = array(); $props = array();
foreach ((array)$value as $key => $param) { foreach ((array)$value as $key => $param) {
$props[] = "'{$key}' => '$param'"; $props[] = "'{$key}' => '$param'";
} }
$col .= join(', ', $props); $col .= implode(', ', $props);
} }
$col .= ")"; $col .= ")";
$cols[] = $col; $cols[] = $col;
} }
$out .= join(",\n", $cols); $out .= implode(",\n", $cols);
} }
$out .= "\n\t);\n"; $out .= "\n\t);\n\n";
return $out; return $out;
} }
@ -574,7 +580,7 @@ class CakeSchema extends Object {
if (is_array($values)) { if (is_array($values)) {
foreach ($values as $key => $val) { foreach ($values as $key => $val) {
if (is_array($val)) { if (is_array($val)) {
$vals[] = "'{$key}' => array('" . implode("', '", $val) . "')"; $vals[] = "'{$key}' => array('" . implode("', '", $val) . "')";
} elseif (!is_numeric($key)) { } elseif (!is_numeric($key)) {
$val = var_export($val, true); $val = var_export($val, true);
if ($val === 'NULL') { if ($val === 'NULL') {
@ -597,7 +603,7 @@ class CakeSchema extends Object {
$db = $Obj->getDataSource(); $db = $Obj->getDataSource();
$fields = $Obj->schema(true); $fields = $Obj->schema(true);
$columns = array(); $columns = $props = array();
foreach ($fields as $name => $value) { foreach ($fields as $name => $value) {
if ($Obj->primaryKey == $name) { if ($Obj->primaryKey == $name) {
$value['key'] = 'primary'; $value['key'] = 'primary';

View file

@ -131,7 +131,7 @@ class CakeSession {
self::$time = time(); self::$time = time();
$checkAgent = Configure::read('Session.checkAgent'); $checkAgent = Configure::read('Session.checkAgent');
if (($checkAgent === true || $checkAgent === null) && env('HTTP_USER_AGENT') != null) { if (($checkAgent === true || $checkAgent === null) && env('HTTP_USER_AGENT')) {
self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
} }
self::_setPath($base); self::_setPath($base);
@ -218,8 +218,7 @@ class CakeSession {
if (empty($name)) { if (empty($name)) {
return false; return false;
} }
$result = Hash::get($_SESSION, $name); return Hash::get($_SESSION, $name) !== null;
return isset($result);
} }
/** /**
@ -248,7 +247,7 @@ class CakeSession {
public static function delete($name) { public static function delete($name) {
if (self::check($name)) { if (self::check($name)) {
self::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); self::_overwrite($_SESSION, Hash::remove($_SESSION, $name));
return (self::check($name) == false); return !self::check($name);
} }
self::_setError(2, __d('cake_dev', "%s doesn't exist", $name)); self::_setError(2, __d('cake_dev', "%s doesn't exist", $name));
return false; return false;
@ -283,9 +282,8 @@ class CakeSession {
protected static function _error($errorNumber) { protected static function _error($errorNumber) {
if (!is_array(self::$error) || !array_key_exists($errorNumber, self::$error)) { if (!is_array(self::$error) || !array_key_exists($errorNumber, self::$error)) {
return false; return false;
} else {
return self::$error[$errorNumber];
} }
return self::$error[$errorNumber];
} }
/** /**
@ -662,7 +660,7 @@ class CakeSession {
*/ */
public static function renew() { public static function renew() {
if (session_id()) { if (session_id()) {
if (session_id() != '' || isset($_COOKIE[session_name()])) { if (session_id() || isset($_COOKIE[session_name()])) {
setcookie(Configure::read('Session.cookie'), '', time() - 42000, self::$path); setcookie(Configure::read('Session.cookie'), '', time() - 42000, self::$path);
} }
session_regenerate_id(true); session_regenerate_id(true);

View file

@ -108,6 +108,7 @@ class Mysql extends DboSource {
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'), 'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
'string' => array('name' => 'varchar', 'limit' => '255'), 'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'), 'text' => array('name' => 'text'),
'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'), 'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'), 'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@ -118,6 +119,13 @@ class Mysql extends DboSource {
'boolean' => array('name' => 'tinyint', 'limit' => '1') 'boolean' => array('name' => 'tinyint', 'limit' => '1')
); );
/**
* Mapping of collation names to character set names
*
* @var array
*/
protected $_charsets = array();
/** /**
* Connects to the database using options in the given configuration array. * Connects to the database using options in the given configuration array.
* *
@ -155,6 +163,7 @@ class Mysql extends DboSource {
)); ));
} }
$this->_charsets = array();
$this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">="); $this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">=");
return $this->connected; return $this->connected;
@ -177,7 +186,7 @@ class Mysql extends DboSource {
*/ */
public function listSources($data = null) { public function listSources($data = null) {
$cache = parent::listSources(); $cache = parent::listSources();
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database'])); $result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']));
@ -261,15 +270,24 @@ class Mysql extends DboSource {
* @return string Character set name * @return string Character set name
*/ */
public function getCharsetName($name) { public function getCharsetName($name) {
if ((bool)version_compare($this->getVersion(), "5", ">=")) { if ((bool)version_compare($this->getVersion(), "5", "<")) {
$r = $this->_execute('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?', array($name)); return false;
$cols = $r->fetch(PDO::FETCH_ASSOC);
if (isset($cols['CHARACTER_SET_NAME'])) {
return $cols['CHARACTER_SET_NAME'];
}
} }
return false; if (isset($this->_charsets[$name])) {
return $this->_charsets[$name];
}
$r = $this->_execute(
'SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?',
array($name)
);
$cols = $r->fetch(PDO::FETCH_ASSOC);
if (isset($cols['CHARACTER_SET_NAME'])) {
$this->_charsets[$name] = $cols['CHARACTER_SET_NAME'];
} else {
$this->_charsets[$name] = false;
}
return $this->_charsets[$name];
} }
/** /**
@ -282,7 +300,7 @@ class Mysql extends DboSource {
public function describe($model) { public function describe($model) {
$key = $this->fullTableName($model, false); $key = $this->fullTableName($model, false);
$cache = parent::describe($key); $cache = parent::describe($key);
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
$table = $this->fullTableName($model); $table = $this->fullTableName($model);
@ -334,7 +352,7 @@ class Mysql extends DboSource {
return parent::update($model, $fields, $values, $conditions); return parent::update($model, $fields, $values, $conditions);
} }
if ($values == null) { if (!$values) {
$combined = $fields; $combined = $fields;
} else { } else {
$combined = array_combine($fields, $values); $combined = array_combine($fields, $values);
@ -425,17 +443,22 @@ class Mysql extends DboSource {
$table = $this->fullTableName($model); $table = $this->fullTableName($model);
$old = version_compare($this->getVersion(), '4.1', '<='); $old = version_compare($this->getVersion(), '4.1', '<=');
if ($table) { if ($table) {
$indices = $this->_execute('SHOW INDEX FROM ' . $table); $indexes = $this->_execute('SHOW INDEX FROM ' . $table);
// @codingStandardsIgnoreStart // @codingStandardsIgnoreStart
// MySQL columns don't match the cakephp conventions. // MySQL columns don't match the cakephp conventions.
while ($idx = $indices->fetch(PDO::FETCH_OBJ)) { while ($idx = $indexes->fetch(PDO::FETCH_OBJ)) {
if ($old) { if ($old) {
$idx = (object)current((array)$idx); $idx = (object)current((array)$idx);
} }
if (!isset($index[$idx->Key_name]['column'])) { if (!isset($index[$idx->Key_name]['column'])) {
$col = array(); $col = array();
$index[$idx->Key_name]['column'] = $idx->Column_name; $index[$idx->Key_name]['column'] = $idx->Column_name;
$index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
if ($idx->Index_type === 'FULLTEXT') {
$index[$idx->Key_name]['type'] = strtolower($idx->Index_type);
} else {
$index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
}
} else { } else {
if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) { if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) {
$col[] = $index[$idx->Key_name]['column']; $col[] = $index[$idx->Key_name]['column'];
@ -445,7 +468,7 @@ class Mysql extends DboSource {
} }
} }
// @codingStandardsIgnoreEnd // @codingStandardsIgnoreEnd
$indices->closeCursor(); $indexes->closeCursor();
} }
return $index; return $index;
} }
@ -555,31 +578,18 @@ class Mysql extends DboSource {
if (isset($indexes['drop'])) { if (isset($indexes['drop'])) {
foreach ($indexes['drop'] as $name => $value) { foreach ($indexes['drop'] as $name => $value) {
$out = 'DROP '; $out = 'DROP ';
if ($name == 'PRIMARY') { if ($name === 'PRIMARY') {
$out .= 'PRIMARY KEY'; $out .= 'PRIMARY KEY';
} else { } else {
$out .= 'KEY ' . $name; $out .= 'KEY ' . $this->startQuote . $name . $this->endQuote;
} }
$alter[] = $out; $alter[] = $out;
} }
} }
if (isset($indexes['add'])) { if (isset($indexes['add'])) {
foreach ($indexes['add'] as $name => $value) { $add = $this->buildIndex($indexes['add']);
$out = 'ADD '; foreach ($add as $index) {
if ($name == 'PRIMARY') { $alter[] = 'ADD ' . $index;
$out .= 'PRIMARY ';
$name = null;
} else {
if (!empty($value['unique'])) {
$out .= 'UNIQUE ';
}
}
if (is_array($value['column'])) {
$out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
} else {
$out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
}
$alter[] = $out;
} }
} }
return $alter; return $alter;
@ -645,9 +655,12 @@ class Mysql extends DboSource {
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) { if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
return $col; return $col;
} }
if (($col === 'tinyint' && $limit == 1) || $col === 'boolean') { if (($col === 'tinyint' && $limit === 1) || $col === 'boolean') {
return 'boolean'; return 'boolean';
} }
if (strpos($col, 'bigint') !== false || $col === 'bigint') {
return 'biginteger';
}
if (strpos($col, 'int') !== false) { if (strpos($col, 'int') !== false) {
return 'integer'; return 'integer';
} }

View file

@ -59,6 +59,7 @@ class Postgres extends DboSource {
'string' => array('name' => 'varchar', 'limit' => '255'), 'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'), 'text' => array('name' => 'text'),
'integer' => array('name' => 'integer', 'formatter' => 'intval'), 'integer' => array('name' => 'integer', 'formatter' => 'intval'),
'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'float' => array('name' => 'float', 'formatter' => 'floatval'), 'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@ -148,7 +149,7 @@ class Postgres extends DboSource {
public function listSources($data = null) { public function listSources($data = null) {
$cache = parent::listSources(); $cache = parent::listSources();
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
@ -158,17 +159,17 @@ class Postgres extends DboSource {
if (!$result) { if (!$result) {
return array(); return array();
} else {
$tables = array();
foreach ($result as $item) {
$tables[] = $item->name;
}
$result->closeCursor();
parent::listSources($tables);
return $tables;
} }
$tables = array();
foreach ($result as $item) {
$tables[] = $item->name;
}
$result->closeCursor();
parent::listSources($tables);
return $tables;
} }
/** /**
@ -286,13 +287,34 @@ class Postgres extends DboSource {
if (is_object($table)) { if (is_object($table)) {
$table = $this->fullTableName($table, false, false); $table = $this->fullTableName($table, false, false);
} }
if (isset($this->_sequenceMap[$table]) && isset($this->_sequenceMap[$table][$field])) { if (!isset($this->_sequenceMap[$table])) {
$this->describe($table);
}
if (isset($this->_sequenceMap[$table][$field])) {
return $this->_sequenceMap[$table][$field]; return $this->_sequenceMap[$table][$field];
} else { } else {
return "{$table}_{$field}_seq"; return "{$table}_{$field}_seq";
} }
} }
/**
* Reset a sequence based on the MAX() value of $column. Useful
* for resetting sequences after using insertMulti().
*
* @param string $table The name of the table to update.
* @param string $column The column to use when reseting the sequence value, the
* sequence name will be fetched using Postgres::getSequence();
* @return boolean success.
*/
public function resetSequence($table, $column) {
$tableName = $this->fullTableName($table, false, false);
$fullTable = $this->fullTableName($table);
$sequence = $this->value($this->getSequence($tableName, $column));
$this->execute("SELECT setval($sequence, (SELECT MAX(id) FROM $fullTable))");
return true;
}
/** /**
* Deletes all the records in a table and drops all associated auto-increment sequences * Deletes all the records in a table and drops all associated auto-increment sequences
* *
@ -640,6 +662,8 @@ class Postgres extends DboSource {
return 'datetime'; return 'datetime';
case (strpos($col, 'time') === 0): case (strpos($col, 'time') === 0):
return 'time'; return 'time';
case ($col == 'bigint'):
return 'biginteger';
case (strpos($col, 'int') !== false && $col != 'interval'): case (strpos($col, 'int') !== false && $col != 'interval'):
return 'integer'; return 'integer';
case (strpos($col, 'char') !== false || $col == 'uuid'): case (strpos($col, 'char') !== false || $col == 'uuid'):
@ -671,7 +695,7 @@ class Postgres extends DboSource {
if ($col == 'uuid') { if ($col == 'uuid') {
return 36; return 36;
} }
if ($limit != null) { if ($limit) {
return intval($limit); return intval($limit);
} }
return null; return null;
@ -801,7 +825,19 @@ class Postgres extends DboSource {
if (!isset($col['length']) && !isset($col['limit'])) { if (!isset($col['length']) && !isset($col['limit'])) {
unset($column['length']); unset($column['length']);
} }
$out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column)); $out = parent::buildColumn($column);
$out = preg_replace(
'/integer\([0-9]+\)/',
'integer',
$out
);
$out = preg_replace(
'/bigint\([0-9]+\)/',
'bigint',
$out
);
$out = str_replace('integer serial', 'serial', $out); $out = str_replace('integer serial', 'serial', $out);
if (strpos($out, 'timestamp DEFAULT')) { if (strpos($out, 'timestamp DEFAULT')) {
if (isset($column['null']) && $column['null']) { if (isset($column['null']) && $column['null']) {

View file

@ -70,6 +70,7 @@ class Sqlite extends DboSource {
'string' => array('name' => 'varchar', 'limit' => '255'), 'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'), 'text' => array('name' => 'text'),
'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'), 'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'),
'biginteger' => array('name' => 'bigint', 'limit' => 20),
'float' => array('name' => 'float', 'formatter' => 'floatval'), 'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@ -138,7 +139,7 @@ class Sqlite extends DboSource {
*/ */
public function listSources($data = null) { public function listSources($data = null) {
$cache = parent::listSources(); $cache = parent::listSources();
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
@ -146,14 +147,14 @@ class Sqlite extends DboSource {
if (!$result || empty($result)) { if (!$result || empty($result)) {
return array(); return array();
} else {
$tables = array();
foreach ($result as $table) {
$tables[] = $table[0]['name'];
}
parent::listSources($tables);
return $tables;
} }
$tables = array();
foreach ($result as $table) {
$tables[] = $table[0]['name'];
}
parent::listSources($tables);
return $tables;
} }
/** /**
@ -165,7 +166,7 @@ class Sqlite extends DboSource {
public function describe($model) { public function describe($model) {
$table = $this->fullTableName($model, false, false); $table = $this->fullTableName($model, false, false);
$cache = parent::describe($table); $cache = parent::describe($table);
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
$fields = array(); $fields = array();
@ -251,9 +252,22 @@ class Sqlite extends DboSource {
$limit = null; $limit = null;
@list($col, $limit) = explode('(', $col); @list($col, $limit) = explode('(', $col);
if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) { $standard = array(
'text',
'integer',
'float',
'boolean',
'timestamp',
'date',
'datetime',
'time'
);
if (in_array($col, $standard)) {
return $col; return $col;
} }
if ($col === 'bigint') {
return 'biginteger';
}
if (strpos($col, 'char') !== false) { if (strpos($col, 'char') !== false) {
return 'string'; return 'string';
} }
@ -448,7 +462,7 @@ class Sqlite extends DboSource {
$out .= 'UNIQUE '; $out .= 'UNIQUE ';
} }
if (is_array($value['column'])) { if (is_array($value['column'])) {
$value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column'])); $value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
} else { } else {
$value['column'] = $this->name($value['column']); $value['column'] = $this->name($value['column']);
} }
@ -513,10 +527,10 @@ class Sqlite extends DboSource {
case 'schema': case 'schema':
extract($data); extract($data);
if (is_array($columns)) { if (is_array($columns)) {
$columns = "\t" . join(",\n\t", array_filter($columns)); $columns = "\t" . implode(",\n\t", array_filter($columns));
} }
if (is_array($indexes)) { if (is_array($indexes)) {
$indexes = "\t" . join("\n\t", array_filter($indexes)); $indexes = "\t" . implode("\n\t", array_filter($indexes));
} }
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}"; return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
default: default:

View file

@ -86,16 +86,17 @@ class Sqlserver extends DboSource {
*/ */
public $columns = array( public $columns = array(
'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'), 'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
'string' => array('name' => 'nvarchar', 'limit' => '255'), 'string' => array('name' => 'nvarchar', 'limit' => '255'),
'text' => array('name' => 'nvarchar', 'limit' => 'MAX'), 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
'integer' => array('name' => 'int', 'formatter' => 'intval'), 'integer' => array('name' => 'int', 'formatter' => 'intval'),
'float' => array('name' => 'numeric', 'formatter' => 'floatval'), 'biginteger' => array('name' => 'bigint'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'), 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'), 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
'binary' => array('name' => 'varbinary'), 'binary' => array('name' => 'varbinary'),
'boolean' => array('name' => 'bit') 'boolean' => array('name' => 'bit')
); );
/** /**
@ -186,7 +187,7 @@ class Sqlserver extends DboSource {
public function describe($model) { public function describe($model) {
$table = $this->fullTableName($model, false); $table = $this->fullTableName($model, false);
$cache = parent::describe($table); $cache = parent::describe($table);
if ($cache != null) { if ($cache) {
return $cache; return $cache;
} }
$fields = array(); $fields = array();
@ -402,6 +403,9 @@ class Sqlserver extends DboSource {
if ($col == 'bit') { if ($col == 'bit') {
return 'boolean'; return 'boolean';
} }
if (strpos($col, 'bigint') !== false) {
return 'biginteger';
}
if (strpos($col, 'int') !== false) { if (strpos($col, 'int') !== false) {
return 'integer'; return 'integer';
} }
@ -618,7 +622,7 @@ class Sqlserver extends DboSource {
*/ */
public function insertMulti($table, $fields, $values) { public function insertMulti($table, $fields, $values) {
$primaryKey = $this->_getPrimaryKey($table); $primaryKey = $this->_getPrimaryKey($table);
$hasPrimaryKey = $primaryKey != null && ( $hasPrimaryKey = $primaryKey && (
(is_array($fields) && in_array($primaryKey, $fields) (is_array($fields) && in_array($primaryKey, $fields)
|| (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false)) || (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
); );
@ -644,7 +648,7 @@ class Sqlserver extends DboSource {
*/ */
public function buildColumn($column) { public function buildColumn($column) {
$result = parent::buildColumn($column); $result = parent::buildColumn($column);
$result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', $result); $result = preg_replace('/(bigint|int|integer)\([0-9]+\)/i', '$1', $result);
$result = preg_replace('/(bit)\([0-9]+\)/i', '$1', $result); $result = preg_replace('/(bit)\([0-9]+\)/i', '$1', $result);
if (strpos($result, 'DEFAULT NULL') !== false) { if (strpos($result, 'DEFAULT NULL') !== false) {
if (isset($column['default']) && $column['default'] === '') { if (isset($column['default']) && $column['default'] === '') {
@ -731,7 +735,7 @@ class Sqlserver extends DboSource {
*/ */
protected function _execute($sql, $params = array(), $prepareOptions = array()) { protected function _execute($sql, $params = array(), $prepareOptions = array()) {
$this->_lastAffected = false; $this->_lastAffected = false;
if (strncasecmp($sql, 'SELECT', 6) == 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) { if (strncasecmp($sql, 'SELECT', 6) === 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) {
$prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL); $prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
return parent::_execute($sql, $params, $prepareOptions); return parent::_execute($sql, $params, $prepareOptions);
} }

View file

@ -600,7 +600,7 @@ class DboSource extends DataSource {
} else { } else {
if (isset($args[1]) && $args[1] === true) { if (isset($args[1]) && $args[1] === true) {
return $this->fetchAll($args[0], true); return $this->fetchAll($args[0], true);
} elseif (isset($args[1]) && !is_array($args[1]) ) { } elseif (isset($args[1]) && !is_array($args[1])) {
return $this->fetchAll($args[0], false); return $this->fetchAll($args[0], false);
} elseif (isset($args[1]) && is_array($args[1])) { } elseif (isset($args[1]) && is_array($args[1])) {
if (isset($args[2])) { if (isset($args[2])) {
@ -671,7 +671,7 @@ class DboSource extends DataSource {
if ($this->hasResult()) { if ($this->hasResult()) {
$first = $this->fetchRow(); $first = $this->fetchRow();
if ($first != null) { if ($first) {
$out[] = $first; $out[] = $first;
} }
while ($item = $this->fetchResult()) { while ($item = $this->fetchResult()) {
@ -984,7 +984,7 @@ class DboSource extends DataSource {
public function create(Model $model, $fields = null, $values = null) { public function create(Model $model, $fields = null, $values = null) {
$id = null; $id = null;
if ($fields == null) { if (!$fields) {
unset($fields, $values); unset($fields, $values);
$fields = array_keys($model->data); $fields = array_keys($model->data);
$values = array_values($model->data); $values = array_values($model->data);
@ -1054,7 +1054,7 @@ class DboSource extends DataSource {
if ($model->recursive == -1) { if ($model->recursive == -1) {
$_associations = array(); $_associations = array();
} elseif ($model->recursive == 0) { } elseif ($model->recursive === 0) {
unset($_associations[2], $_associations[3]); unset($_associations[2], $_associations[3]);
} }
@ -1408,10 +1408,9 @@ class DboSource extends DataSource {
} }
} }
if (!isset($data[$association])) { if (!isset($data[$association])) {
if ($merge[0][$association] != null) { $data[$association] = array();
if ($merge[0][$association]) {
$data[$association] = $merge[0][$association]; $data[$association] = $merge[0][$association];
} else {
$data[$association] = array();
} }
} else { } else {
if (is_array($merge[0][$association])) { if (is_array($merge[0][$association])) {
@ -1767,7 +1766,7 @@ class DboSource extends DataSource {
case 'schema': case 'schema':
foreach (array('columns', 'indexes', 'tableParameters') as $var) { foreach (array('columns', 'indexes', 'tableParameters') as $var) {
if (is_array(${$var})) { if (is_array(${$var})) {
${$var} = "\t" . join(",\n\t", array_filter(${$var})); ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
} else { } else {
${$var} = ''; ${$var} = '';
} }
@ -1821,7 +1820,7 @@ class DboSource extends DataSource {
* @return boolean Success * @return boolean Success
*/ */
public function update(Model $model, $fields = array(), $values = null, $conditions = null) { public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
if ($values == null) { if (!$values) {
$combined = $fields; $combined = $fields;
} else { } else {
$combined = array_combine($fields, $values); $combined = array_combine($fields, $values);
@ -2514,7 +2513,7 @@ class DboSource extends DataSource {
$data = $this->_parseKey($model, trim($key), $value); $data = $this->_parseKey($model, trim($key), $value);
} }
if ($data != null) { if ($data) {
$out[] = $data; $out[] = $data;
$data = null; $data = null;
} }
@ -2925,6 +2924,19 @@ class DboSource extends DataSource {
return $this->commit(); return $this->commit();
} }
/**
* Reset a sequence based on the MAX() value of $column. Useful
* for resetting sequences after using insertMulti().
*
* This method should be implemented by datasources that require sequences to be used.
*
* @param string $table The name of the table to update.
* @param string $column The column to use when reseting the sequence value.
* @return boolean success.
*/
public function resetSequence($table, $column) {
}
/** /**
* Returns an array of the indexes in given datasource name. * Returns an array of the indexes in given datasource name.
* *
@ -3071,7 +3083,7 @@ class DboSource extends DataSource {
} }
$out = $this->_buildFieldParameters($out, $column, 'beforeDefault'); $out = $this->_buildFieldParameters($out, $column, 'beforeDefault');
if (isset($column['key']) && $column['key'] === 'primary' && $type === 'integer') { if (isset($column['key']) && $column['key'] === 'primary' && ($type === 'integer' || $type === 'biginteger')) {
$out .= ' ' . $this->columns['primary_key']['name']; $out .= ' ' . $this->columns['primary_key']['name'];
} elseif (isset($column['key']) && $column['key'] === 'primary') { } elseif (isset($column['key']) && $column['key'] === 'primary') {
$out .= ' NOT NULL'; $out .= ' NOT NULL';
@ -3117,7 +3129,7 @@ class DboSource extends DataSource {
} }
/** /**
* Format indexes for create table * Format indexes for create table.
* *
* @param array $indexes * @param array $indexes
* @param string $table * @param string $table
@ -3133,6 +3145,8 @@ class DboSource extends DataSource {
} else { } else {
if (!empty($value['unique'])) { if (!empty($value['unique'])) {
$out .= 'UNIQUE '; $out .= 'UNIQUE ';
} elseif (!empty($value['type']) && strtoupper($value['type']) === 'FULLTEXT') {
$out .= 'FULLTEXT ';
} }
$name = $this->startQuote . $name . $this->endQuote; $name = $this->startQuote . $name . $this->endQuote;
} }

View file

@ -12,6 +12,7 @@
* @since CakePHP(tm) v 1.2.0.4525 * @since CakePHP(tm) v 1.2.0.4525
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('AppModel', 'Model');
/** /**
* A model used by TranslateBehavior to access the translation tables. * A model used by TranslateBehavior to access the translation tables.

View file

@ -235,6 +235,13 @@ class Model extends Object implements CakeEventListener {
*/ */
public $tablePrefix = null; public $tablePrefix = null;
/**
* Plugin model belongs to.
*
* @var string
*/
public $plugin = null;
/** /**
* Name of the model. * Name of the model.
* *
@ -669,12 +676,16 @@ class Model extends Object implements CakeEventListener {
extract(array_merge( extract(array_merge(
array( array(
'id' => $this->id, 'table' => $this->useTable, 'ds' => $this->useDbConfig, 'id' => $this->id, 'table' => $this->useTable, 'ds' => $this->useDbConfig,
'name' => $this->name, 'alias' => $this->alias 'name' => $this->name, 'alias' => $this->alias, 'plugin' => $this->plugin
), ),
$id $id
)); ));
} }
if ($this->plugin === null) {
$this->plugin = (isset($plugin) ? $plugin : $this->plugin);
}
if ($this->name === null) { if ($this->name === null) {
$this->name = (isset($name) ? $name : get_class($this)); $this->name = (isset($name) ? $name : get_class($this));
} }
@ -720,7 +731,7 @@ class Model extends Object implements CakeEventListener {
$this->useTable = Inflector::tableize($this->name); $this->useTable = Inflector::tableize($this->name);
} }
if ($this->displayField == null) { if (!$this->displayField) {
unset($this->displayField); unset($this->displayField);
} }
$this->table = $this->useTable; $this->table = $this->useTable;
@ -1393,7 +1404,7 @@ class Model extends Object implements CakeEventListener {
$this->schema(); $this->schema();
} }
if ($this->_schema != null) { if ($this->_schema) {
return isset($this->_schema[$name]); return isset($this->_schema[$name]);
} }
return false; return false;
@ -1447,7 +1458,7 @@ class Model extends Object implements CakeEventListener {
* or false if none $field exist. * or false if none $field exist.
*/ */
public function getVirtualField($field = null) { public function getVirtualField($field = null) {
if ($field == null) { if (!$field) {
return empty($this->virtualFields) ? false : $this->virtualFields; return empty($this->virtualFields) ? false : $this->virtualFields;
} }
if ($this->isVirtualField($field)) { if ($this->isVirtualField($field)) {
@ -1503,7 +1514,7 @@ class Model extends Object implements CakeEventListener {
public function read($fields = null, $id = null) { public function read($fields = null, $id = null) {
$this->validationErrors = array(); $this->validationErrors = array();
if ($id != null) { if ($id) {
$this->id = $id; $this->id = $id;
} }
@ -1519,9 +1530,8 @@ class Model extends Object implements CakeEventListener {
'fields' => $fields 'fields' => $fields
)); ));
return $this->data; return $this->data;
} else {
return false;
} }
return false;
} }
/** /**
@ -1874,7 +1884,7 @@ class Model extends Object implements CakeEventListener {
if ($keepExisting && !empty($links)) { if ($keepExisting && !empty($links)) {
foreach ($links as $link) { foreach ($links as $link) {
$oldJoin = $link[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']]; $oldJoin = $link[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
if (! in_array($oldJoin, $newJoins) ) { if (!in_array($oldJoin, $newJoins)) {
$conditions[$associationForeignKey] = $oldJoin; $conditions[$associationForeignKey] = $oldJoin;
$db->delete($this->{$join}, $conditions); $db->delete($this->{$join}, $conditions);
} else { } else {
@ -2220,6 +2230,7 @@ class Model extends Object implements CakeEventListener {
} else { } else {
$data = array_merge(array($key => $this->{$association}->id), $data, array($key => $this->{$association}->id)); $data = array_merge(array($key => $this->{$association}->id), $data, array($key => $this->{$association}->id));
} }
$options = $this->_addToWhiteList($key, $options);
} else { } else {
$validationErrors[$association] = $this->{$association}->validationErrors; $validationErrors[$association] = $this->{$association}->validationErrors;
} }
@ -2250,6 +2261,7 @@ class Model extends Object implements CakeEventListener {
$validates = $this->{$association}->create(null) !== null; $validates = $this->{$association}->create(null) !== null;
$saved = false; $saved = false;
if ($validates) { if ($validates) {
$options = $this->{$association}->_addToWhiteList($key, $options);
if ($options['deep']) { if ($options['deep']) {
$saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false))); $saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
} else { } else {
@ -2270,6 +2282,7 @@ class Model extends Object implements CakeEventListener {
$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id)); $values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
} }
} }
$options = $this->{$association}->_addToWhiteList($key, $options);
$_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false))); $_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
if (in_array(false, $_return, true)) { if (in_array(false, $_return, true)) {
$validationErrors[$association] = $this->{$association}->validationErrors; $validationErrors[$association] = $this->{$association}->validationErrors;
@ -2302,6 +2315,29 @@ class Model extends Object implements CakeEventListener {
return false; return false;
} }
/**
* Helper method for saveAll() and friends, to add foreign key to fieldlist
*
* @param string $key fieldname to be added to list
* @param array $options
* @return array $options
*/
protected function _addToWhiteList($key, $options) {
if (empty($options['fieldList']) && $this->whitelist && !in_array($key, $this->whitelist)) {
$options['fieldList'][$this->alias] = $this->whitelist;
$options['fieldList'][$this->alias][] = $key;
return $options;
}
if (!empty($options['fieldList'][$this->alias]) && is_array($options['fieldList'][$this->alias])) {
$options['fieldList'][$this->alias][] = $key;
return $options;
}
if (!empty($options['fieldList']) && is_array($options['fieldList'])) {
$options['fieldList'][] = $key;
}
return $options;
}
/** /**
* Validates a single record, as well as all its directly associated records. * Validates a single record, as well as all its directly associated records.
* *
@ -2566,7 +2602,7 @@ class Model extends Object implements CakeEventListener {
* @return boolean True if such a record exists * @return boolean True if such a record exists
*/ */
public function hasAny($conditions = null) { public function hasAny($conditions = null) {
return ($this->find('count', array('conditions' => $conditions, 'recursive' => -1)) != false); return (bool)$this->find('count', array('conditions' => $conditions, 'recursive' => -1));
} }
/** /**
@ -2731,7 +2767,7 @@ class Model extends Object implements CakeEventListener {
*/ */
protected function _findCount($state, $query, $results = array()) { protected function _findCount($state, $query, $results = array()) {
if ($state === 'before') { if ($state === 'before') {
if (!empty($query['type']) && isset($this->findMethods[$query['type']]) && $query['type'] !== 'count' ) { if (!empty($query['type']) && isset($this->findMethods[$query['type']]) && $query['type'] !== 'count') {
$query['operation'] = 'count'; $query['operation'] = 'count';
$query = $this->{'_find' . ucfirst($query['type'])}('before', $query); $query = $this->{'_find' . ucfirst($query['type'])}('before', $query);
} }
@ -2987,7 +3023,7 @@ class Model extends Object implements CakeEventListener {
if (!empty($this->id)) { if (!empty($this->id)) {
$fields[$this->alias . '.' . $this->primaryKey . ' !='] = $this->id; $fields[$this->alias . '.' . $this->primaryKey . ' !='] = $this->id;
} }
return ($this->find('count', array('conditions' => $fields, 'recursive' => -1)) == 0); return !$this->find('count', array('conditions' => $fields, 'recursive' => -1));
} }
/** /**
@ -3158,7 +3194,7 @@ class Model extends Object implements CakeEventListener {
public function setDataSource($dataSource = null) { public function setDataSource($dataSource = null) {
$oldConfig = $this->useDbConfig; $oldConfig = $this->useDbConfig;
if ($dataSource != null) { if ($dataSource) {
$this->useDbConfig = $dataSource; $this->useDbConfig = $dataSource;
} }
$db = ConnectionManager::getDataSource($this->useDbConfig); $db = ConnectionManager::getDataSource($this->useDbConfig);
@ -3204,7 +3240,7 @@ class Model extends Object implements CakeEventListener {
* @return array Associations * @return array Associations
*/ */
public function getAssociated($type = null) { public function getAssociated($type = null) {
if ($type == null) { if (!$type) {
$associated = array(); $associated = array();
foreach ($this->_associations as $assoc) { foreach ($this->_associations as $assoc) {
if (!empty($this->{$assoc})) { if (!empty($this->{$assoc})) {

View file

@ -81,7 +81,7 @@ class Permission extends AppModel {
* @return boolean Success (true if ARO has access to action in ACO, false otherwise) * @return boolean Success (true if ARO has access to action in ACO, false otherwise)
*/ */
public function check($aro, $aco, $action = "*") { public function check($aro, $aco, $action = "*") {
if ($aro == null || $aco == null) { if (!$aro || !$aco) {
return false; return false;
} }
@ -89,12 +89,12 @@ class Permission extends AppModel {
$aroPath = $this->Aro->node($aro); $aroPath = $this->Aro->node($aro);
$acoPath = $this->Aco->node($aco); $acoPath = $this->Aco->node($aco);
if (empty($aroPath) || empty($acoPath)) { if (!$aroPath || !$acoPath) {
trigger_error(__d('cake_dev', "DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); trigger_error(__d('cake_dev', "DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
return false; return false;
} }
if ($acoPath == null || $acoPath == array()) { if (!$acoPath) {
trigger_error(__d('cake_dev', "DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); trigger_error(__d('cake_dev', "DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
return false; return false;
} }
@ -146,7 +146,6 @@ class Permission extends AppModel {
return false; return false;
case 0: case 0:
continue; continue;
break;
case 1: case 1:
return true; return true;
} }
@ -171,7 +170,7 @@ class Permission extends AppModel {
$permKeys = $this->getAcoKeys($this->schema()); $permKeys = $this->getAcoKeys($this->schema());
$save = array(); $save = array();
if ($perms == false) { if (!$perms) {
trigger_error(__d('cake_dev', 'DbAcl::allow() - Invalid node'), E_USER_WARNING); trigger_error(__d('cake_dev', 'DbAcl::allow() - Invalid node'), E_USER_WARNING);
return false; return false;
} }
@ -198,7 +197,7 @@ class Permission extends AppModel {
} }
list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']); list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']);
if ($perms['link'] != null && !empty($perms['link'])) { if ($perms['link'] && !empty($perms['link'])) {
$save['id'] = $perms['link'][0][$this->alias]['id']; $save['id'] = $perms['link'][0][$this->alias]['id'];
} else { } else {
unset($save['id']); unset($save['id']);

View file

@ -273,7 +273,7 @@ class CakeValidationRule {
$this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams); $this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams);
} elseif (is_string($validator['rule'])) { } elseif (is_string($validator['rule'])) {
$this->_valid = preg_match($this->_rule, $data[$field]); $this->_valid = preg_match($this->_rule, $data[$field]);
} elseif (Configure::read('debug') > 0) { } else {
trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $this->_rule, $field), E_USER_WARNING); trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $this->_rule, $field), E_USER_WARNING);
return false; return false;
} }

View file

@ -366,17 +366,17 @@ class CakeRequest implements ArrayAccess {
* @return string The client IP. * @return string The client IP.
*/ */
public function clientIp($safe = true) { public function clientIp($safe = true) {
if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) { if (!$safe && env('HTTP_X_FORWARDED_FOR')) {
$ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR')); $ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
} else { } else {
if (env('HTTP_CLIENT_IP') != null) { if (env('HTTP_CLIENT_IP')) {
$ipaddr = env('HTTP_CLIENT_IP'); $ipaddr = env('HTTP_CLIENT_IP');
} else { } else {
$ipaddr = env('REMOTE_ADDR'); $ipaddr = env('REMOTE_ADDR');
} }
} }
if (env('HTTP_CLIENTADDRESS') != null) { if (env('HTTP_CLIENTADDRESS')) {
$tmpipaddr = env('HTTP_CLIENTADDRESS'); $tmpipaddr = env('HTTP_CLIENTADDRESS');
if (!empty($tmpipaddr)) { if (!empty($tmpipaddr)) {
@ -696,8 +696,50 @@ class CakeRequest implements ArrayAccess {
* @return array An array of prefValue => array(content/types) * @return array An array of prefValue => array(content/types)
*/ */
public function parseAccept() { public function parseAccept() {
return $this->_parseAcceptWithQualifier($this->header('accept'));
}
/**
* Get the languages accepted by the client, or check if a specific language is accepted.
*
* Get the list of accepted languages:
*
* {{{ CakeRequest::acceptLanguage(); }}}
*
* Check if a specific language is accepted:
*
* {{{ CakeRequest::acceptLanguage('es-es'); }}}
*
* @param string $language The language to test.
* @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
*/
public static function acceptLanguage($language = null) {
$raw = self::_parseAcceptWithQualifier(self::header('Accept-Language'));
$accept = array(); $accept = array();
$header = explode(',', $this->header('accept')); foreach ($raw as $qualifier => $languages) {
foreach ($languages as &$lang) {
if (strpos($lang, '_')) {
$lang = str_replace('_', '-', $lang);
}
$lang = strtolower($lang);
}
$accept = array_merge($accept, $languages);
}
if ($language === null) {
return $accept;
}
return in_array(strtolower($language), $accept);
}
/**
* Parse Accept* headers with qualifier options
*
* @param string $header
* @return array
*/
protected static function _parseAcceptWithQualifier($header) {
$accept = array();
$header = explode(',', $header);
foreach (array_filter($header) as $value) { foreach (array_filter($header) as $value) {
$prefPos = strpos($value, ';'); $prefPos = strpos($value, ';');
if ($prefPos !== false) { if ($prefPos !== false) {
@ -719,31 +761,13 @@ class CakeRequest implements ArrayAccess {
} }
/** /**
* Get the languages accepted by the client, or check if a specific language is accepted. * Provides a read accessor for `$this->query`. Allows you
* to use a syntax similar to `CakeSession` for reading url query data.
* *
* Get the list of accepted languages: * @return mixed The value being read
*
* {{{ CakeRequest::acceptLanguage(); }}}
*
* Check if a specific language is accepted:
*
* {{{ CakeRequest::acceptLanguage('es-es'); }}}
*
* @param string $language The language to test.
* @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
*/ */
public static function acceptLanguage($language = null) { public function query($name) {
$accepts = preg_split('/[;,]/', self::header('Accept-Language')); return Hash::get($this->query, $name);
foreach ($accepts as &$accept) {
$accept = strtolower($accept);
if (strpos($accept, '_') !== false) {
$accept = str_replace('_', '-', $accept);
}
}
if ($language === null) {
return $accepts;
}
return in_array($language, $accepts);
} }
/** /**
@ -805,6 +829,38 @@ class CakeRequest implements ArrayAccess {
return $input; return $input;
} }
/**
* Only allow certain HTTP request methods, if the request method does not match
* a 405 error will be shown and the required "Allow" response header will be set.
*
* Example:
*
* $this->request->onlyAllow('post', 'delete');
* or
* $this->request->onlyAllow(array('post', 'delete'));
*
* If the request would be GET, response header "Allow: POST, DELETE" will be set
* and a 405 error will be returned
*
* @param string|array $methods Allowed HTTP request methods
* @return boolean true
* @throws MethodNotAllowedException
*/
public function onlyAllow($methods) {
if (!is_array($methods)) {
$methods = func_get_args();
}
foreach ($methods as $method) {
if ($this->is($method)) {
return true;
}
}
$allowed = strtoupper(implode(', ', $methods));
$e = new MethodNotAllowedException();
$e->responseHeader('Allow', $allowed);
throw $e;
}
/** /**
* Read data from php://input, mocked in tests. * Read data from php://input, mocked in tests.
* *

View file

@ -17,6 +17,8 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('File', 'Utility');
/** /**
* CakeResponse is responsible for managing the response text, status and headers of a HTTP response. * CakeResponse is responsible for managing the response text, status and headers of a HTTP response.
* *
@ -115,10 +117,10 @@ class CakeResponse {
'7z' => 'application/x-7z-compressed', '7z' => 'application/x-7z-compressed',
'hdf' => 'application/x-hdf', 'hdf' => 'application/x-hdf',
'hqx' => 'application/mac-binhex40', 'hqx' => 'application/mac-binhex40',
'ico' => 'image/vnd.microsoft.icon', 'ico' => 'image/x-icon',
'ips' => 'application/x-ipscript', 'ips' => 'application/x-ipscript',
'ipx' => 'application/x-ipix', 'ipx' => 'application/x-ipix',
'js' => 'text/javascript', 'js' => 'application/javascript',
'latex' => 'application/x-latex', 'latex' => 'application/x-latex',
'lha' => 'application/octet-stream', 'lha' => 'application/octet-stream',
'lsp' => 'application/x-lisp', 'lsp' => 'application/x-lisp',
@ -171,6 +173,7 @@ class CakeResponse {
'texinfo' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo',
'tr' => 'application/x-troff', 'tr' => 'application/x-troff',
'tsp' => 'application/dsptype', 'tsp' => 'application/dsptype',
'ttc' => 'font/ttf',
'ttf' => 'font/ttf', 'ttf' => 'font/ttf',
'unv' => 'application/i-deas', 'unv' => 'application/i-deas',
'ustar' => 'application/x-ustar', 'ustar' => 'application/x-ustar',
@ -237,6 +240,12 @@ class CakeResponse {
'ogv' => 'video/ogg', 'ogv' => 'video/ogg',
'webm' => 'video/webm', 'webm' => 'video/webm',
'mp4' => 'video/mp4', 'mp4' => 'video/mp4',
'm4v' => 'video/mp4',
'f4v' => 'video/mp4',
'f4p' => 'video/mp4',
'm4a' => 'audio/mp4',
'f4a' => 'audio/mp4',
'f4b' => 'audio/mp4',
'gif' => 'image/gif', 'gif' => 'image/gif',
'ief' => 'image/ief', 'ief' => 'image/ief',
'jpe' => 'image/jpeg', 'jpe' => 'image/jpeg',
@ -265,7 +274,7 @@ class CakeResponse {
'mime' => 'www/mime', 'mime' => 'www/mime',
'pdb' => 'chemical/x-pdb', 'pdb' => 'chemical/x-pdb',
'xyz' => 'chemical/x-pdb', 'xyz' => 'chemical/x-pdb',
'javascript' => 'text/javascript', 'javascript' => 'application/javascript',
'form' => 'application/x-www-form-urlencoded', 'form' => 'application/x-www-form-urlencoded',
'file' => 'multipart/form-data', 'file' => 'multipart/form-data',
'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
@ -276,6 +285,19 @@ class CakeResponse {
'wml' => 'text/vnd.wap.wml', 'wml' => 'text/vnd.wap.wml',
'wmlscript' => 'text/vnd.wap.wmlscript', 'wmlscript' => 'text/vnd.wap.wmlscript',
'wbmp' => 'image/vnd.wap.wbmp', 'wbmp' => 'image/vnd.wap.wbmp',
'woff' => 'application/x-font-woff',
'webp' => 'image/webp',
'appcache' => 'text/cache-manifest',
'manifest' => 'text/cache-manifest',
'htc' => 'text/x-component',
'rdf' => 'application/xml',
'crx' => 'application/x-chrome-extension',
'oex' => 'application/x-opera-extension',
'xpi' => 'application/x-xpinstall',
'safariextz' => 'application/octet-stream',
'webapp' => 'application/x-web-app-manifest+json',
'vcf' => 'text/x-vcard',
'vtt' => 'text/vtt',
); );
/** /**
@ -314,6 +336,13 @@ class CakeResponse {
*/ */
protected $_body = null; protected $_body = null;
/**
* File object for file to be read out as response
*
* @var File
*/
protected $_file = null;
/** /**
* The charset the response body is encoded with * The charset the response body is encoded with
* *
@ -355,9 +384,10 @@ class CakeResponse {
if (isset($options['type'])) { if (isset($options['type'])) {
$this->type($options['type']); $this->type($options['type']);
} }
if (isset($options['charset'])) { if (!isset($options['charset'])) {
$this->charset($options['charset']); $options['charset'] = Configure::read('App.encoding');
} }
$this->charset($options['charset']);
} }
/** /**
@ -380,7 +410,12 @@ class CakeResponse {
foreach ($this->_headers as $header => $value) { foreach ($this->_headers as $header => $value) {
$this->_sendHeader($header, $value); $this->_sendHeader($header, $value);
} }
$this->_sendContent($this->_body); if ($this->_file) {
$this->_sendFile($this->_file);
$this->_file = null;
} else {
$this->_sendContent($this->_body);
}
} }
/** /**
@ -712,7 +747,7 @@ class CakeResponse {
* @return void * @return void
*/ */
public function cache($since, $time = '+1 day') { public function cache($since, $time = '+1 day') {
if (!is_integer($time)) { if (!is_int($time)) {
$time = strtotime($time); $time = strtotime($time);
} }
$this->header(array( $this->header(array(
@ -755,7 +790,7 @@ class CakeResponse {
unset($this->_cacheDirectives['public']); unset($this->_cacheDirectives['public']);
$this->maxAge($time); $this->maxAge($time);
} }
if ($time == null) { if (!$time) {
$this->_setCacheControl(); $this->_setCacheControl();
} }
return (bool)$public; return (bool)$public;
@ -974,7 +1009,7 @@ class CakeResponse {
protected function _getUTCDate($time = null) { protected function _getUTCDate($time = null) {
if ($time instanceof DateTime) { if ($time instanceof DateTime) {
$result = clone $time; $result = clone $time;
} elseif (is_integer($time)) { } elseif (is_int($time)) {
$result = new DateTime(date('Y-m-d H:i:s', $time)); $result = new DateTime(date('Y-m-d H:i:s', $time));
} else { } else {
$result = new DateTime($time); $result = new DateTime($time);
@ -1036,7 +1071,7 @@ class CakeResponse {
* @return int * @return int
*/ */
public function length($bytes = null) { public function length($bytes = null) {
if ($bytes !== null ) { if ($bytes !== null) {
$this->_headers['Content-Length'] = $bytes; $this->_headers['Content-Length'] = $bytes;
} }
if (isset($this->_headers['Content-Length'])) { if (isset($this->_headers['Content-Length'])) {
@ -1052,12 +1087,11 @@ class CakeResponse {
* is marked as so accordingly so the client can be informed of that. * is marked as so accordingly so the client can be informed of that.
* *
* In order to mark a response as not modified, you need to set at least * In order to mark a response as not modified, you need to set at least
* the Last-Modified response header or a response etag to be compared * the Last-Modified etag response header before calling this method. Otherwise
* with the request itself * a comparison will not be possible.
* *
* @return boolean whether the response was marked as not modified or * @return boolean whether the response was marked as not modified or not.
* not */
**/
public function checkNotModified(CakeRequest $request) { public function checkNotModified(CakeRequest $request) {
$etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY); $etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY);
$modifiedSince = $request->header('If-Modified-Since'); $modifiedSince = $request->header('If-Modified-Since');
@ -1154,4 +1188,138 @@ class CakeResponse {
$this->_cookies[$options['name']] = $options; $this->_cookies[$options['name']] = $options;
} }
/**
* Setup for display or download the given file
*
* @param string $path Path to file
* @param array $options Options
* ### Options keys
* - name: Alternate download name
* - download: If `true` sets download header and forces file to be downloaded rather than displayed in browser
* @return void
* @throws NotFoundException
*/
public function file($path, $options = array()) {
$options += array(
'name' => null,
'download' => null
);
if (!is_file($path)) {
$path = APP . $path;
}
$file = new File($path);
if (!$file->exists() || !$file->readable()) {
if (Configure::read('debug')) {
throw new NotFoundException(__d('cake_dev', 'The requested file %s was not found or not readable', $path));
}
throw new NotFoundException(__d('cake', 'The requested file was not found'));
}
$extension = strtolower($file->ext());
$download = $options['download'];
if ((!$extension || $this->type($extension) === false) && is_null($download)) {
$download = true;
}
$fileSize = $file->size();
if ($download) {
$agent = env('HTTP_USER_AGENT');
if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) {
$contentType = 'application/octetstream';
} elseif (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
$contentType = 'application/force-download';
}
if (!empty($contentType)) {
$this->type($contentType);
}
if (is_null($options['name'])) {
$name = $file->name;
} else {
$name = $options['name'];
}
$this->download($name);
$this->header('Accept-Ranges', 'bytes');
$httpRange = env('HTTP_RANGE');
if (isset($httpRange)) {
list($toss, $range) = explode('=', $httpRange);
$size = $fileSize - 1;
$length = $fileSize - $range;
$this->header(array(
'Content-Length' => $length,
'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize
));
$this->statusCode(206);
$file->open('rb', true);
$file->offset($range);
} else {
$this->header('Content-Length', $fileSize);
}
} else {
$this->header('Content-Length', $fileSize);
}
$this->_clearBuffer();
$this->_file = $file;
}
/**
* Reads out a file, and echos the content to the client.
*
* @param File $file File object
* @return boolean True is whole file is echoed successfully or false if client connection is lost in between
*/
protected function _sendFile($file) {
$compress = $this->outputCompressed();
$file->open('rb');
while (!feof($file->handle)) {
if (!$this->_isActive()) {
$file->close();
return false;
}
set_time_limit(0);
echo fread($file->handle, 8192);
if (!$compress) {
$this->_flushBuffer();
}
}
$file->close();
return true;
}
/**
* Returns true if connection is still active
*
* @return boolean
*/
protected function _isActive() {
return connection_status() === CONNECTION_NORMAL && !connection_aborted();
}
/**
* Clears the contents of the topmost output buffer and discards them
*
* @return boolean
*/
protected function _clearBuffer() {
return @ob_end_clean();
}
/**
* Flushes the contents of the output buffer
*
* @return void
*/
protected function _flushBuffer() {
@flush();
@ob_flush();
}
} }

View file

@ -41,11 +41,11 @@ class CakeSocket {
* @var array * @var array
*/ */
protected $_baseConfig = array( protected $_baseConfig = array(
'persistent' => false, 'persistent' => false,
'host' => 'localhost', 'host' => 'localhost',
'protocol' => 'tcp', 'protocol' => 'tcp',
'port' => 80, 'port' => 80,
'timeout' => 30 'timeout' => 30
); );
/** /**
@ -76,6 +76,39 @@ class CakeSocket {
*/ */
public $lastError = array(); public $lastError = array();
/**
* True if the socket stream is encrypted after a CakeSocket::enableCrypto() call
*
* @var boolean
*/
public $encrypted = false;
/**
* Contains all the encryption methods available
*
* @var array
*/
protected $_encryptMethods = array(
// @codingStandardsIgnoreStart
'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
'sslv23_client' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
'tls_client' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER,
'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER,
'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER,
'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER
// @codingStandardsIgnoreEnd
);
/**
* Used to capture connection warnings which can happen when there are
* SSL errors for example.
*
* @var array
*/
protected $_connectionErrors = array();
/** /**
* Constructor. * Constructor.
* *
@ -96,26 +129,47 @@ class CakeSocket {
* @throws SocketException * @throws SocketException
*/ */
public function connect() { public function connect() {
if ($this->connection != null) { if ($this->connection) {
$this->disconnect(); $this->disconnect();
} }
$scheme = null; $scheme = null;
if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') { if (isset($this->config['request']['uri']) && $this->config['request']['uri']['scheme'] == 'https') {
$scheme = 'ssl://'; $scheme = 'ssl://';
} }
if ($this->config['persistent'] == true) { if (!empty($this->config['context'])) {
$this->connection = @pfsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); $context = stream_context_create($this->config['context']);
} else { } else {
$this->connection = @fsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); $context = stream_context_create();
} }
$connectAs = STREAM_CLIENT_CONNECT;
if ($this->config['persistent']) {
$connectAs |= STREAM_CLIENT_PERSISTENT;
}
set_error_handler(array($this, '_connectionErrorHandler'));
$this->connection = stream_socket_client(
$scheme . $this->config['host'] . ':' . $this->config['port'],
$errNum,
$errStr,
$this->config['timeout'],
$connectAs,
$context
);
restore_error_handler();
if (!empty($errNum) || !empty($errStr)) { if (!empty($errNum) || !empty($errStr)) {
$this->setLastError($errNum, $errStr); $this->setLastError($errNum, $errStr);
throw new SocketException($errStr, $errNum); throw new SocketException($errStr, $errNum);
} }
if (!$this->connection && $this->_connectionErrors) {
$message = implode("\n", $this->_connectionErrors);
throw new SocketException($message, E_WARNING);
}
$this->connected = is_resource($this->connection); $this->connected = is_resource($this->connection);
if ($this->connected) { if ($this->connected) {
stream_set_timeout($this->connection, $this->config['timeout']); stream_set_timeout($this->connection, $this->config['timeout']);
@ -123,6 +177,31 @@ class CakeSocket {
return $this->connected; return $this->connected;
} }
/**
* socket_stream_client() does not populate errNum, or $errStr when there are
* connection errors, as in the case of SSL verification failure.
*
* Instead we need to handle those errors manually.
*
* @param int $code
* @param string $message
*/
protected function _connectionErrorHandler($code, $message) {
$this->_connectionErrors[] = $message;
}
/**
* Get the connection context.
*
* @return null|array Null when there is no connnection, an array when there is.
*/
public function context() {
if (!$this->connection) {
return;
}
return stream_context_get_options($this->connection);
}
/** /**
* Get the host name of the current connection. * Get the host name of the current connection.
* *
@ -277,4 +356,36 @@ class CakeSocket {
return true; return true;
} }
/**
* Encrypts current stream socket, using one of the defined encryption methods
*
* @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls'
* @param string $clientOrServer can be one of 'client', 'server'. Default is 'client'
* @param boolean $enable enable or disable encryption. Default is true (enable)
* @return boolean True on success
* @throws InvalidArgumentException When an invalid encryption scheme is chosen.
* @throws SocketException When attempting to enable SSL/TLS fails
* @see stream_socket_enable_crypto
*/
public function enableCrypto($type, $clientOrServer = 'client', $enable = true) {
if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) {
throw new InvalidArgumentException(__d('cake_dev', 'Invalid encryption scheme chosen'));
}
$enableCryptoResult = false;
try {
$enableCryptoResult = stream_socket_enable_crypto($this->connection, $enable, $this->_encryptMethods[$type . '_' . $clientOrServer]);
} catch (Exception $e) {
$this->setLastError(null, $e->getMessage());
throw new SocketException($e->getMessage());
}
if ($enableCryptoResult === true) {
$this->encrypted = $enable;
return true;
} else {
$errorMessage = __d('cake_dev', 'Unable to perform enableCrypto operation on CakeSocket');
$this->setLastError(null, $errorMessage);
throw new SocketException($errorMessage);
}
}
} }

View file

@ -946,13 +946,17 @@ class CakeEmail {
* $email->attachments(array('custom_name.png' => array( * $email->attachments(array('custom_name.png' => array(
* 'file' => 'path/to/file', * 'file' => 'path/to/file',
* 'mimetype' => 'image/png', * 'mimetype' => 'image/png',
* 'contentId' => 'abc123' * 'contentId' => 'abc123',
* 'contentDisposition' => false
* )); * ));
* }}} * }}}
* *
* The `contentId` key allows you to specify an inline attachment. In your email text, you * The `contentId` key allows you to specify an inline attachment. In your email text, you
* can use `<img src="cid:abc123" />` to display the image inline. * can use `<img src="cid:abc123" />` to display the image inline.
* *
* The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve
* attachment compatibility with outlook email clients.
*
* @param string|array $attachments String with the filename or array with filenames * @param string|array $attachments String with the filename or array with filenames
* @return array|CakeEmail Either the array of attachments when getting or $this when setting. * @return array|CakeEmail Either the array of attachments when getting or $this when setting.
* @throws SocketException * @throws SocketException
@ -991,6 +995,7 @@ class CakeEmail {
* @param string|array $attachments String with the filename or array with filenames * @param string|array $attachments String with the filename or array with filenames
* @return CakeEmail $this * @return CakeEmail $this
* @throws SocketException * @throws SocketException
* @see CakeEmail::attachments()
*/ */
public function addAttachments($attachments) { public function addAttachments($attachments) {
$current = $this->_attachments; $current = $this->_attachments;
@ -1355,7 +1360,12 @@ class CakeEmail {
$msg[] = '--' . $boundary; $msg[] = '--' . $boundary;
$msg[] = 'Content-Type: ' . $fileInfo['mimetype']; $msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
$msg[] = 'Content-Transfer-Encoding: base64'; $msg[] = 'Content-Transfer-Encoding: base64';
$msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"'; if (
!isset($fileInfo['contentDisposition']) ||
$fileInfo['contentDisposition']
) {
$msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';
}
$msg[] = ''; $msg[] = '';
$msg[] = $data; $msg[] = $data;
$msg[] = ''; $msg[] = '';

View file

@ -79,7 +79,8 @@ class SmtpTransport extends AbstractTransport {
'timeout' => 30, 'timeout' => 30,
'username' => null, 'username' => null,
'password' => null, 'password' => null,
'client' => null 'client' => null,
'tls' => false
); );
$this->_config = $config + $default; $this->_config = $config + $default;
} }
@ -107,7 +108,15 @@ class SmtpTransport extends AbstractTransport {
try { try {
$this->_smtpSend("EHLO {$host}", '250'); $this->_smtpSend("EHLO {$host}", '250');
if ($this->_config['tls']) {
$this->_smtpSend("STARTTLS", '220');
$this->_socket->enableCrypto('tls');
$this->_smtpSend("EHLO {$host}", '250');
}
} catch (SocketException $e) { } catch (SocketException $e) {
if ($this->_config['tls']) {
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
}
try { try {
$this->_smtpSend("HELO {$host}", '250'); $this->_smtpSend("HELO {$host}", '250');
} catch (SocketException $e2) { } catch (SocketException $e2) {
@ -132,6 +141,8 @@ class SmtpTransport extends AbstractTransport {
if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) { if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.')); throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
} }
} elseif ($authRequired == '504') {
throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS'));
} elseif ($authRequired != '503') { } elseif ($authRequired != '503') {
throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.')); throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
} }

View file

@ -12,437 +12,24 @@
* *
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project * @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Network.Http
* @since CakePHP(tm) v 2.0.0 * @since CakePHP(tm) v 2.0.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/ */
App::uses('HttpSocketResponse', 'Network/Http');
if (class_exists('HttpResponse')) {
trigger_error(__d(
'cake_dev',
"HttpResponse is deprecated due to naming conflicts. Use HttpSocketResponse instead."
), E_USER_ERROR);
}
/** /**
* HTTP Response from HttpSocket. * HTTP Response from HttpSocket.
* *
* @package Cake.Network.Http * @package Cake.Network.Http
* @deprecated This class is deprecated as it has naming conflicts with pecl/http
*/ */
class HttpResponse implements ArrayAccess { class HttpResponse extends HttpSocketResponse {
/**
* Body content
*
* @var string
*/
public $body = '';
/**
* Headers
*
* @var array
*/
public $headers = array();
/**
* Cookies
*
* @var array
*/
public $cookies = array();
/**
* HTTP version
*
* @var string
*/
public $httpVersion = 'HTTP/1.1';
/**
* Response code
*
* @var integer
*/
public $code = 0;
/**
* Reason phrase
*
* @var string
*/
public $reasonPhrase = '';
/**
* Pure raw content
*
* @var string
*/
public $raw = '';
/**
* Constructor
*
* @param string $message
*/
public function __construct($message = null) {
if ($message !== null) {
$this->parseResponse($message);
}
}
/**
* Body content
*
* @return string
*/
public function body() {
return (string)$this->body;
}
/**
* Get header in case insensitive
*
* @param string $name Header name
* @param array $headers
* @return mixed String if header exists or null
*/
public function getHeader($name, $headers = null) {
if (!is_array($headers)) {
$headers =& $this->headers;
}
if (isset($headers[$name])) {
return $headers[$name];
}
foreach ($headers as $key => $value) {
if (strcasecmp($key, $name) == 0) {
return $value;
}
}
return null;
}
/**
* If return is 200 (OK)
*
* @return boolean
*/
public function isOk() {
return $this->code == 200;
}
/**
* If return is a valid 3xx (Redirection)
*
* @return boolean
*/
public function isRedirect() {
return in_array($this->code, array(301, 302, 303, 307)) && !is_null($this->getHeader('Location'));
}
/**
* Parses the given message and breaks it down in parts.
*
* @param string $message Message to parse
* @return void
* @throws SocketException
*/
public function parseResponse($message) {
if (!is_string($message)) {
throw new SocketException(__d('cake_dev', 'Invalid response.'));
}
if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
}
list(, $statusLine, $header) = $match;
$this->raw = $message;
$this->body = (string)substr($message, strlen($match[0]));
if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) {
$this->httpVersion = $match[1];
$this->code = $match[2];
$this->reasonPhrase = $match[3];
}
$this->headers = $this->_parseHeader($header);
$transferEncoding = $this->getHeader('Transfer-Encoding');
$decoded = $this->_decodeBody($this->body, $transferEncoding);
$this->body = $decoded['body'];
if (!empty($decoded['header'])) {
$this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
}
if (!empty($this->headers)) {
$this->cookies = $this->parseCookies($this->headers);
}
}
/**
* Generic function to decode a $body with a given $encoding. Returns either an array with the keys
* 'body' and 'header' or false on failure.
*
* @param string $body A string containing the body to decode.
* @param string|boolean $encoding Can be false in case no encoding is being used, or a string representing the encoding.
* @return mixed Array of response headers and body or false.
*/
protected function _decodeBody($body, $encoding = 'chunked') {
if (!is_string($body)) {
return false;
}
if (empty($encoding)) {
return array('body' => $body, 'header' => false);
}
$decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
if (!is_callable(array(&$this, $decodeMethod))) {
return array('body' => $body, 'header' => false);
}
return $this->{$decodeMethod}($body);
}
/**
* Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
* a result.
*
* @param string $body A string containing the chunked body to decode.
* @return mixed Array of response headers and body or false.
* @throws SocketException
*/
protected function _decodeChunkedBody($body) {
if (!is_string($body)) {
return false;
}
$decodedBody = null;
$chunkLength = null;
while ($chunkLength !== 0) {
if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.'));
}
$chunkSize = 0;
$hexLength = 0;
$chunkExtensionName = '';
$chunkExtensionValue = '';
if (isset($match[0])) {
$chunkSize = $match[0];
}
if (isset($match[1])) {
$hexLength = $match[1];
}
if (isset($match[2])) {
$chunkExtensionName = $match[2];
}
if (isset($match[3])) {
$chunkExtensionValue = $match[3];
}
$body = substr($body, strlen($chunkSize));
$chunkLength = hexdec($hexLength);
$chunk = substr($body, 0, $chunkLength);
if (!empty($chunkExtensionName)) {
// @todo See if there are popular chunk extensions we should implement
}
$decodedBody .= $chunk;
if ($chunkLength !== 0) {
$body = substr($body, $chunkLength + strlen("\r\n"));
}
}
$entityHeader = false;
if (!empty($body)) {
$entityHeader = $this->_parseHeader($body);
}
return array('body' => $decodedBody, 'header' => $entityHeader);
}
/**
* Parses an array based header.
*
* @param array $header Header as an indexed array (field => value)
* @return array Parsed header
*/
protected function _parseHeader($header) {
if (is_array($header)) {
return $header;
} elseif (!is_string($header)) {
return false;
}
preg_match_all("/(.+):(.+)(?:(?<![\t ])\r\n|\$)/Uis", $header, $matches, PREG_SET_ORDER);
$header = array();
foreach ($matches as $match) {
list(, $field, $value) = $match;
$value = trim($value);
$value = preg_replace("/[\t ]\r\n/", "\r\n", $value);
$field = $this->_unescapeToken($field);
if (!isset($header[$field])) {
$header[$field] = $value;
} else {
$header[$field] = array_merge((array)$header[$field], (array)$value);
}
}
return $header;
}
/**
* Parses cookies in response headers.
*
* @param array $header Header array containing one ore more 'Set-Cookie' headers.
* @return mixed Either false on no cookies, or an array of cookies received.
* @todo Make this 100% RFC 2965 confirm
*/
public function parseCookies($header) {
$cookieHeader = $this->getHeader('Set-Cookie', $header);
if (!$cookieHeader) {
return false;
}
$cookies = array();
foreach ((array)$cookieHeader as $cookie) {
if (strpos($cookie, '";"') !== false) {
$cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
$parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
} else {
$parts = preg_split('/\;[ \t]*/', $cookie);
}
list($name, $value) = explode('=', array_shift($parts), 2);
$cookies[$name] = compact('value');
foreach ($parts as $part) {
if (strpos($part, '=') !== false) {
list($key, $value) = explode('=', $part);
} else {
$key = $part;
$value = true;
}
$key = strtolower($key);
if (!isset($cookies[$name][$key])) {
$cookies[$name][$key] = $value;
}
}
}
return $cookies;
}
/**
* Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
*
* @param string $token Token to unescape
* @param array $chars
* @return string Unescaped token
* @todo Test $chars parameter
*/
protected function _unescapeToken($token, $chars = null) {
$regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
$token = preg_replace($regex, '\\1', $token);
return $token;
}
/**
* Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
*
* @param boolean $hex true to get them as HEX values, false otherwise
* @param array $chars
* @return array Escape chars
* @todo Test $chars parameter
*/
protected function _tokenEscapeChars($hex = true, $chars = null) {
if (!empty($chars)) {
$escape = $chars;
} else {
$escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
for ($i = 0; $i <= 31; $i++) {
$escape[] = chr($i);
}
$escape[] = chr(127);
}
if ($hex == false) {
return $escape;
}
foreach ($escape as $key => $char) {
$escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
}
return $escape;
}
/**
* ArrayAccess - Offset Exists
*
* @param string $offset
* @return boolean
*/
public function offsetExists($offset) {
return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
}
/**
* ArrayAccess - Offset Get
*
* @param string $offset
* @return mixed
*/
public function offsetGet($offset) {
switch ($offset) {
case 'raw':
$firstLineLength = strpos($this->raw, "\r\n") + 2;
if ($this->raw[$firstLineLength] === "\r") {
$header = null;
} else {
$header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
}
return array(
'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
'header' => $header,
'body' => $this->body,
'response' => $this->raw
);
case 'status':
return array(
'http-version' => $this->httpVersion,
'code' => $this->code,
'reason-phrase' => $this->reasonPhrase
);
case 'header':
return $this->headers;
case 'body':
return $this->body;
case 'cookies':
return $this->cookies;
}
return null;
}
/**
* ArrayAccess - Offset Set
*
* @param string $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value) {
}
/**
* ArrayAccess - Offset Unset
*
* @param string $offset
* @return void
*/
public function offsetUnset($offset) {
}
/**
* Instance as string
*
* @return string
*/
public function __toString() {
return $this->body();
}
} }

View file

@ -18,6 +18,7 @@
*/ */
App::uses('CakeSocket', 'Network'); App::uses('CakeSocket', 'Network');
App::uses('Router', 'Routing'); App::uses('Router', 'Routing');
App::uses('Hash', 'Utility');
/** /**
* Cake network socket connection class. * Cake network socket connection class.
@ -64,7 +65,7 @@ class HttpSocket extends CakeSocket {
), ),
'raw' => null, 'raw' => null,
'redirect' => false, 'redirect' => false,
'cookies' => array() 'cookies' => array(),
); );
/** /**
@ -79,7 +80,7 @@ class HttpSocket extends CakeSocket {
* *
* @var string * @var string
*/ */
public $responseClass = 'HttpResponse'; public $responseClass = 'HttpSocketResponse';
/** /**
* Configuration settings for the HttpSocket and the requests * Configuration settings for the HttpSocket and the requests
@ -92,6 +93,9 @@ class HttpSocket extends CakeSocket {
'protocol' => 'tcp', 'protocol' => 'tcp',
'port' => 80, 'port' => 80,
'timeout' => 30, 'timeout' => 30,
'ssl_verify_peer' => true,
'ssl_verify_depth' => 5,
'ssl_verify_host' => true,
'request' => array( 'request' => array(
'uri' => array( 'uri' => array(
'scheme' => array('http', 'https'), 'scheme' => array('http', 'https'),
@ -99,7 +103,7 @@ class HttpSocket extends CakeSocket {
'port' => array(80, 443) 'port' => array(80, 443)
), ),
'redirect' => false, 'redirect' => false,
'cookies' => array() 'cookies' => array(),
) )
); );
@ -246,7 +250,7 @@ class HttpSocket extends CakeSocket {
* method and provide a more granular interface. * method and provide a more granular interface.
* *
* @param string|array $request Either an URI string, or an array defining host/uri * @param string|array $request Either an URI string, or an array defining host/uri
* @return mixed false on error, HttpResponse on success * @return mixed false on error, HttpSocketResponse on success
* @throws SocketException * @throws SocketException
*/ */
public function request($request = array()) { public function request($request = array()) {
@ -348,6 +352,8 @@ class HttpSocket extends CakeSocket {
return false; return false;
} }
$this->_configContext($this->request['uri']['host']);
$this->request['raw'] = ''; $this->request['raw'] = '';
if ($this->request['line'] !== false) { if ($this->request['line'] !== false) {
$this->request['raw'] = $this->request['line']; $this->request['raw'] = $this->request['line'];
@ -395,6 +401,7 @@ class HttpSocket extends CakeSocket {
throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass)); throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass));
} }
$this->response = new $responseClass($response); $this->response = new $responseClass($response);
if (!empty($this->response->cookies)) { if (!empty($this->response->cookies)) {
if (!isset($this->config['request']['cookies'][$Host])) { if (!isset($this->config['request']['cookies'][$Host])) {
$this->config['request']['cookies'][$Host] = array(); $this->config['request']['cookies'][$Host] = array();
@ -643,6 +650,33 @@ class HttpSocket extends CakeSocket {
return true; return true;
} }
/**
* Configure the socket's context. Adds in configuration
* that can not be declared in the class definition.
*
* @param string $host The host you're connecting to.
* @return void
*/
protected function _configContext($host) {
foreach ($this->config as $key => $value) {
if (substr($key, 0, 4) !== 'ssl_') {
continue;
}
$contextKey = substr($key, 4);
if (empty($this->config['context']['ssl'][$contextKey])) {
$this->config['context']['ssl'][$contextKey] = $value;
}
unset($this->config[$key]);
}
if (empty($this->_context['ssl']['cafile'])) {
$this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem';
}
if (!empty($this->config['context']['ssl']['verify_host'])) {
$this->config['context']['ssl']['CN_match'] = $host;
unset($this->config['context']['ssl']['verify_host']);
}
}
/** /**
* Takes a $uri array and turns it into a fully qualified URL string * Takes a $uri array and turns it into a fully qualified URL string
* *
@ -944,7 +978,7 @@ class HttpSocket extends CakeSocket {
$escape[] = chr(127); $escape[] = chr(127);
} }
if ($hex == false) { if (!$hex) {
return $escape; return $escape;
} }
foreach ($escape as $key => $char) { foreach ($escape as $key => $char) {

View file

@ -0,0 +1,455 @@
<?php
/**
* HTTP Response from HttpSocket.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.0.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* HTTP Response from HttpSocket.
*
* @package Cake.Network.Http
*/
class HttpSocketResponse implements ArrayAccess {
/**
* Body content
*
* @var string
*/
public $body = '';
/**
* Headers
*
* @var array
*/
public $headers = array();
/**
* Cookies
*
* @var array
*/
public $cookies = array();
/**
* HTTP version
*
* @var string
*/
public $httpVersion = 'HTTP/1.1';
/**
* Response code
*
* @var integer
*/
public $code = 0;
/**
* Reason phrase
*
* @var string
*/
public $reasonPhrase = '';
/**
* Pure raw content
*
* @var string
*/
public $raw = '';
/**
* Context data in the response.
* Contains SSL certificates for example.
*
* @var array
*/
public $context = array();
/**
* Constructor
*
* @param string $message
*/
public function __construct($message = null) {
if ($message !== null) {
$this->parseResponse($message);
}
}
/**
* Body content
*
* @return string
*/
public function body() {
return (string)$this->body;
}
/**
* Get header in case insensitive
*
* @param string $name Header name
* @param array $headers
* @return mixed String if header exists or null
*/
public function getHeader($name, $headers = null) {
if (!is_array($headers)) {
$headers =& $this->headers;
}
if (isset($headers[$name])) {
return $headers[$name];
}
foreach ($headers as $key => $value) {
if (strcasecmp($key, $name) === 0) {
return $value;
}
}
return null;
}
/**
* If return is 200 (OK)
*
* @return boolean
*/
public function isOk() {
return $this->code == 200;
}
/**
* If return is a valid 3xx (Redirection)
*
* @return boolean
*/
public function isRedirect() {
return in_array($this->code, array(301, 302, 303, 307)) && !is_null($this->getHeader('Location'));
}
/**
* Parses the given message and breaks it down in parts.
*
* @param string $message Message to parse
* @return void
* @throws SocketException
*/
public function parseResponse($message) {
if (!is_string($message)) {
throw new SocketException(__d('cake_dev', 'Invalid response.'));
}
if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
}
list(, $statusLine, $header) = $match;
$this->raw = $message;
$this->body = (string)substr($message, strlen($match[0]));
if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) {
$this->httpVersion = $match[1];
$this->code = $match[2];
$this->reasonPhrase = $match[3];
}
$this->headers = $this->_parseHeader($header);
$transferEncoding = $this->getHeader('Transfer-Encoding');
$decoded = $this->_decodeBody($this->body, $transferEncoding);
$this->body = $decoded['body'];
if (!empty($decoded['header'])) {
$this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
}
if (!empty($this->headers)) {
$this->cookies = $this->parseCookies($this->headers);
}
}
/**
* Generic function to decode a $body with a given $encoding. Returns either an array with the keys
* 'body' and 'header' or false on failure.
*
* @param string $body A string containing the body to decode.
* @param string|boolean $encoding Can be false in case no encoding is being used, or a string representing the encoding.
* @return mixed Array of response headers and body or false.
*/
protected function _decodeBody($body, $encoding = 'chunked') {
if (!is_string($body)) {
return false;
}
if (empty($encoding)) {
return array('body' => $body, 'header' => false);
}
$decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
if (!is_callable(array(&$this, $decodeMethod))) {
return array('body' => $body, 'header' => false);
}
return $this->{$decodeMethod}($body);
}
/**
* Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
* a result.
*
* @param string $body A string containing the chunked body to decode.
* @return mixed Array of response headers and body or false.
* @throws SocketException
*/
protected function _decodeChunkedBody($body) {
if (!is_string($body)) {
return false;
}
$decodedBody = null;
$chunkLength = null;
while ($chunkLength !== 0) {
if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.'));
}
$chunkSize = 0;
$hexLength = 0;
$chunkExtensionName = '';
$chunkExtensionValue = '';
if (isset($match[0])) {
$chunkSize = $match[0];
}
if (isset($match[1])) {
$hexLength = $match[1];
}
if (isset($match[2])) {
$chunkExtensionName = $match[2];
}
if (isset($match[3])) {
$chunkExtensionValue = $match[3];
}
$body = substr($body, strlen($chunkSize));
$chunkLength = hexdec($hexLength);
$chunk = substr($body, 0, $chunkLength);
if (!empty($chunkExtensionName)) {
// @todo See if there are popular chunk extensions we should implement
}
$decodedBody .= $chunk;
if ($chunkLength !== 0) {
$body = substr($body, $chunkLength + strlen("\r\n"));
}
}
$entityHeader = false;
if (!empty($body)) {
$entityHeader = $this->_parseHeader($body);
}
return array('body' => $decodedBody, 'header' => $entityHeader);
}
/**
* Parses an array based header.
*
* @param array $header Header as an indexed array (field => value)
* @return array Parsed header
*/
protected function _parseHeader($header) {
if (is_array($header)) {
return $header;
} elseif (!is_string($header)) {
return false;
}
preg_match_all("/(.+):(.+)(?:(?<![\t ])\r\n|\$)/Uis", $header, $matches, PREG_SET_ORDER);
$header = array();
foreach ($matches as $match) {
list(, $field, $value) = $match;
$value = trim($value);
$value = preg_replace("/[\t ]\r\n/", "\r\n", $value);
$field = $this->_unescapeToken($field);
if (!isset($header[$field])) {
$header[$field] = $value;
} else {
$header[$field] = array_merge((array)$header[$field], (array)$value);
}
}
return $header;
}
/**
* Parses cookies in response headers.
*
* @param array $header Header array containing one ore more 'Set-Cookie' headers.
* @return mixed Either false on no cookies, or an array of cookies received.
* @todo Make this 100% RFC 2965 confirm
*/
public function parseCookies($header) {
$cookieHeader = $this->getHeader('Set-Cookie', $header);
if (!$cookieHeader) {
return false;
}
$cookies = array();
foreach ((array)$cookieHeader as $cookie) {
if (strpos($cookie, '";"') !== false) {
$cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
$parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
} else {
$parts = preg_split('/\;[ \t]*/', $cookie);
}
list($name, $value) = explode('=', array_shift($parts), 2);
$cookies[$name] = compact('value');
foreach ($parts as $part) {
if (strpos($part, '=') !== false) {
list($key, $value) = explode('=', $part);
} else {
$key = $part;
$value = true;
}
$key = strtolower($key);
if (!isset($cookies[$name][$key])) {
$cookies[$name][$key] = $value;
}
}
}
return $cookies;
}
/**
* Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
*
* @param string $token Token to unescape
* @param array $chars
* @return string Unescaped token
* @todo Test $chars parameter
*/
protected function _unescapeToken($token, $chars = null) {
$regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
$token = preg_replace($regex, '\\1', $token);
return $token;
}
/**
* Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
*
* @param boolean $hex true to get them as HEX values, false otherwise
* @param array $chars
* @return array Escape chars
* @todo Test $chars parameter
*/
protected function _tokenEscapeChars($hex = true, $chars = null) {
if (!empty($chars)) {
$escape = $chars;
} else {
$escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
for ($i = 0; $i <= 31; $i++) {
$escape[] = chr($i);
}
$escape[] = chr(127);
}
if (!$hex) {
return $escape;
}
foreach ($escape as $key => $char) {
$escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
}
return $escape;
}
/**
* ArrayAccess - Offset Exists
*
* @param string $offset
* @return boolean
*/
public function offsetExists($offset) {
return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
}
/**
* ArrayAccess - Offset Get
*
* @param string $offset
* @return mixed
*/
public function offsetGet($offset) {
switch ($offset) {
case 'raw':
$firstLineLength = strpos($this->raw, "\r\n") + 2;
if ($this->raw[$firstLineLength] === "\r") {
$header = null;
} else {
$header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
}
return array(
'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
'header' => $header,
'body' => $this->body,
'response' => $this->raw
);
case 'status':
return array(
'http-version' => $this->httpVersion,
'code' => $this->code,
'reason-phrase' => $this->reasonPhrase
);
case 'header':
return $this->headers;
case 'body':
return $this->body;
case 'cookies':
return $this->cookies;
}
return null;
}
/**
* ArrayAccess - Offset Set
*
* @param string $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value) {
}
/**
* ArrayAccess - Offset Unset
*
* @param string $offset
* @return void
*/
public function offsetUnset($offset) {
}
/**
* Instance as string
*
* @return string
*/
public function __toString() {
return $this->body();
}
}

View file

@ -209,12 +209,6 @@ class Dispatcher implements CakeEventListener {
public function parseParams($event) { public function parseParams($event) {
$request = $event->data['request']; $request = $event->data['request'];
Router::setRequestInfo($request); Router::setRequestInfo($request);
if (count(Router::$routes) == 0) {
$namedExpressions = Router::getNamedExpressions();
extract($namedExpressions);
$this->_loadRoutes();
}
$params = Router::parse($request->url); $params = Router::parse($request->url);
$request->addParams($params); $request->addParams($params);
@ -269,13 +263,4 @@ class Dispatcher implements CakeEventListener {
return false; return false;
} }
/**
* Loads route configuration
*
* @return void
*/
protected function _loadRoutes() {
include APP . 'Config' . DS . 'routes.php';
}
} }

View file

@ -42,8 +42,6 @@ class AssetDispatcher extends DispatcherFilter {
*/ */
public function beforeDispatch($event) { public function beforeDispatch($event) {
$url = $event->data['request']->url; $url = $event->data['request']->url;
$response = $event->data['response'];
if (strpos($url, '..') !== false || strpos($url, '.') === false) { if (strpos($url, '..') !== false || strpos($url, '.') === false) {
return; return;
} }
@ -53,43 +51,27 @@ class AssetDispatcher extends DispatcherFilter {
return $result; return $result;
} }
$pathSegments = explode('.', $url); $assetFile = $this->_getAssetFile($url);
$ext = array_pop($pathSegments); if ($assetFile === null || !file_exists($assetFile)) {
$parts = explode('/', $url); return null;
$assetFile = null;
if ($parts[0] === 'theme') {
$themeName = $parts[1];
unset($parts[0], $parts[1]);
$fileFragment = urldecode(implode(DS, $parts));
$path = App::themePath($themeName) . 'webroot' . DS;
if (file_exists($path . $fileFragment)) {
$assetFile = $path . $fileFragment;
}
} else {
$plugin = Inflector::camelize($parts[0]);
if (CakePlugin::loaded($plugin)) {
unset($parts[0]);
$fileFragment = urldecode(implode(DS, $parts));
$pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
if (file_exists($pluginWebroot . $fileFragment)) {
$assetFile = $pluginWebroot . $fileFragment;
}
}
} }
if ($assetFile !== null) { $response = $event->data['response'];
$event->stopPropagation(); $event->stopPropagation();
$response->modified(filemtime($assetFile));
if (!$response->checkNotModified($event->data['request'])) { $response->modified(filemtime($assetFile));
$this->_deliverAsset($response, $assetFile, $ext); if ($response->checkNotModified($event->data['request'])) {
}
return $response; return $response;
} }
$pathSegments = explode('.', $url);
$ext = array_pop($pathSegments);
$this->_deliverAsset($response, $assetFile, $ext);
return $response;
} }
/** /**
* Checks if the client is requeting a filtered asset and runs the corresponding * Checks if the client is requesting a filtered asset and runs the corresponding
* filter if any is configured * filter if any is configured
* *
* @param CakeEvent $event containing the request and response object * @param CakeEvent $event containing the request and response object
@ -111,15 +93,44 @@ class AssetDispatcher extends DispatcherFilter {
if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) { if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) {
$response->statusCode(404); $response->statusCode(404);
return $response; return $response;
} elseif ($isCss) { }
if ($isCss) {
include WWW_ROOT . DS . $filters['css']; include WWW_ROOT . DS . $filters['css'];
return $response; return $response;
} elseif ($isJs) { }
if ($isJs) {
include WWW_ROOT . DS . $filters['js']; include WWW_ROOT . DS . $filters['js'];
return $response; return $response;
} }
} }
/**
* Builds asset file path based off url
*
* @param string $url
* @return string Absolute path for asset file
*/
protected function _getAssetFile($url) {
$parts = explode('/', $url);
if ($parts[0] === 'theme') {
$themeName = $parts[1];
unset($parts[0], $parts[1]);
$fileFragment = urldecode(implode(DS, $parts));
$path = App::themePath($themeName) . 'webroot' . DS;
return $path . $fileFragment;
}
$plugin = Inflector::camelize($parts[0]);
if (CakePlugin::loaded($plugin)) {
unset($parts[0]);
$fileFragment = urldecode(implode(DS, $parts));
$pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
return $pluginWebroot . $fileFragment;
}
}
/** /**
* Sends an asset file to the client * Sends an asset file to the client
* *

View file

@ -154,7 +154,8 @@ class CakeRoute {
if (preg_match('#\/\*\*$#', $route)) { if (preg_match('#\/\*\*$#', $route)) {
$parsed = preg_replace('#/\\\\\*\\\\\*$#', '(?:/(?P<_trailing_>.*))?', $parsed); $parsed = preg_replace('#/\\\\\*\\\\\*$#', '(?:/(?P<_trailing_>.*))?', $parsed);
$this->_greedy = true; $this->_greedy = true;
} elseif (preg_match('#\/\*$#', $route)) { }
if (preg_match('#\/\*$#', $route)) {
$parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed); $parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed);
$this->_greedy = true; $this->_greedy = true;
} }
@ -163,7 +164,7 @@ class CakeRoute {
$this->_compiledRoute = '#^' . $parsed . '[/]*$#'; $this->_compiledRoute = '#^' . $parsed . '[/]*$#';
$this->keys = $names; $this->keys = $names;
//remove defaults that are also keys. They can cause match failures // Remove defaults that are also keys. They can cause match failures
foreach ($this->keys as $key) { foreach ($this->keys as $key) {
unset($this->defaults[$key]); unset($this->defaults[$key]);
} }
@ -219,7 +220,7 @@ class CakeRoute {
if (isset($route[$key])) { if (isset($route[$key])) {
continue; continue;
} }
if (is_integer($key)) { if (is_int($key)) {
$route['pass'][] = $value; $route['pass'][] = $value;
continue; continue;
} }

View file

@ -74,7 +74,7 @@ class RedirectRoute extends CakeRoute {
$this->response = new CakeResponse(); $this->response = new CakeResponse();
} }
$redirect = $this->redirect; $redirect = $this->redirect;
if (count($this->redirect) == 1 && !isset($this->redirect['controller'])) { if (count($this->redirect) === 1 && !isset($this->redirect['controller'])) {
$redirect = $this->redirect[0]; $redirect = $this->redirect[0];
} }
if (isset($this->options['persist']) && is_array($redirect)) { if (isset($this->options['persist']) && is_array($redirect)) {

View file

@ -48,6 +48,13 @@ class Router {
*/ */
public static $routes = array(); public static $routes = array();
/**
* Have routes been loaded
*
* @var boolean
*/
public static $initialized = false;
/** /**
* List of action prefixes used in connected routes. * List of action prefixes used in connected routes.
* Includes admin prefix * Includes admin prefix
@ -284,6 +291,8 @@ class Router {
* @throws RouterException * @throws RouterException
*/ */
public static function connect($route, $defaults = array(), $options = array()) { public static function connect($route, $defaults = array(), $options = array()) {
self::$initialized = true;
foreach (self::$_prefixes as $prefix) { foreach (self::$_prefixes as $prefix) {
if (isset($defaults[$prefix])) { if (isset($defaults[$prefix])) {
if ($defaults[$prefix]) { if ($defaults[$prefix]) {
@ -304,7 +313,12 @@ class Router {
} }
$routeClass = self::$_routeClass; $routeClass = self::$_routeClass;
if (isset($options['routeClass'])) { if (isset($options['routeClass'])) {
$routeClass = self::_validateRouteClass($options['routeClass']); if (strpos($options['routeClass'], '.') === false) {
$routeClass = $options['routeClass'];
} else {
list($plugin, $routeClass) = pluginSplit($options['routeClass'], true);
}
$routeClass = self::_validateRouteClass($routeClass);
unset($options['routeClass']); unset($options['routeClass']);
} }
if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) { if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) {
@ -420,7 +434,7 @@ class Router {
$options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options); $options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options);
} }
if ($options['reset'] == true || self::$_namedConfig['rules'] === false) { if ($options['reset'] || self::$_namedConfig['rules'] === false) {
self::$_namedConfig['rules'] = array(); self::$_namedConfig['rules'] = array();
} }
@ -515,6 +529,10 @@ class Router {
* @return array Parsed elements from URL * @return array Parsed elements from URL
*/ */
public static function parse($url) { public static function parse($url) {
if (!self::$initialized) {
self::_loadRoutes();
}
$ext = null; $ext = null;
$out = array(); $out = array();
@ -743,6 +761,10 @@ class Router {
* @return string Full translated URL with base path. * @return string Full translated URL with base path.
*/ */
public static function url($url = null, $full = false) { public static function url($url = null, $full = false) {
if (!self::$initialized) {
self::_loadRoutes();
}
$params = array('plugin' => null, 'controller' => null, 'action' => 'index'); $params = array('plugin' => null, 'controller' => null, 'action' => 'index');
if (is_bool($full)) { if (is_bool($full)) {
@ -829,12 +851,7 @@ class Router {
$output = self::_handleNoRoute($url); $output = self::_handleNoRoute($url);
} }
} else { } else {
if ( if (preg_match('/:\/\/|^(javascript|mailto|tel|sms):|\#/i', $url)) {
(strpos($url, '://') !== false ||
(strpos($url, 'javascript:') === 0) ||
(strpos($url, 'mailto:') === 0)) ||
(!strncmp($url, '#', 1))
) {
return $url; return $url;
} }
if (substr($url, 0, 1) === '/') { if (substr($url, 0, 1) === '/') {
@ -928,9 +945,9 @@ class Router {
if (!empty($named)) { if (!empty($named)) {
foreach ($named as $name => $value) { foreach ($named as $name => $value) {
if (is_array($value)) { if (is_array($value)) {
$flattend = Hash::flatten($value, ']['); $flattend = Hash::flatten($value, '%5D%5B');
foreach ($flattend as $namedKey => $namedValue) { foreach ($flattend as $namedKey => $namedValue) {
$output .= '/' . $name . "[$namedKey]" . self::$_namedConfig['separator'] . rawurlencode($namedValue); $output .= '/' . $name . "%5B{$namedKey}%5D" . self::$_namedConfig['separator'] . rawurlencode($namedValue);
} }
} else { } else {
$output .= '/' . $name . self::$_namedConfig['separator'] . rawurlencode($value); $output .= '/' . $name . self::$_namedConfig['separator'] . rawurlencode($value);
@ -1073,7 +1090,7 @@ class Router {
* @return string base url with plugin name removed if present * @return string base url with plugin name removed if present
*/ */
public static function stripPlugin($base, $plugin = null) { public static function stripPlugin($base, $plugin = null) {
if ($plugin != null) { if ($plugin) {
$base = preg_replace('/(?:' . $plugin . ')/', '', $base); $base = preg_replace('/(?:' . $plugin . ')/', '', $base);
$base = str_replace('//', '', $base); $base = str_replace('//', '', $base);
$pos1 = strrpos($base, '/'); $pos1 = strrpos($base, '/');
@ -1117,6 +1134,10 @@ class Router {
* @return array Array of extensions Router is configured to parse. * @return array Array of extensions Router is configured to parse.
*/ */
public static function extensions() { public static function extensions() {
if (!self::$initialized) {
self::_loadRoutes();
}
return self::$_validExtensions; return self::$_validExtensions;
} }
@ -1138,6 +1159,16 @@ class Router {
return self::$_validExtensions = array_merge(self::$_validExtensions, $extensions); return self::$_validExtensions = array_merge(self::$_validExtensions, $extensions);
} }
/**
* Loads route configuration
*
* @return void
*/
protected static function _loadRoutes() {
self::$initialized = true;
include APP . 'Config' . DS . 'routes.php';
}
} }
//Save the initial state //Save the initial state

View file

@ -825,6 +825,18 @@ EXPECTED;
########## DEBUG ########## ########## DEBUG ##########
'<div>this-is-a-test</div>' '<div>this-is-a-test</div>'
########################### ###########################
EXPECTED;
$expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 8);
$this->assertEquals($expected, $result);
ob_start();
debug(false, false, false);
$result = ob_get_clean();
$expected = <<<EXPECTED
########## DEBUG ##########
false
###########################
EXPECTED; EXPECTED;
$expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 8); $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 8);
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);

View file

@ -73,7 +73,8 @@ class RegisEngineTest extends CakeTestCase {
'server' => '127.0.0.1', 'server' => '127.0.0.1',
'port' => 6379, 'port' => 6379,
'timeout' => 0, 'timeout' => 0,
'persistent' => true 'persistent' => true,
'password' => false,
); );
$this->assertEquals($expecting, $settings); $this->assertEquals($expecting, $settings);
} }

View file

@ -261,6 +261,7 @@ three.four = value four
is_null = null is_null = null
bool_false = false bool_false = false
bool_true = true bool_true = true
[Asset] [Asset]
timestamp = force timestamp = force
INI; INI;

View file

@ -88,7 +88,7 @@ class CommandListShellTest extends CakeTestCase {
$expected = "/\[.*TestPluginTwo.*\] example, welcome/"; $expected = "/\[.*TestPluginTwo.*\] example, welcome/";
$this->assertRegExp($expected, $output); $this->assertRegExp($expected, $output);
$expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, test, testsuite, upgrade/"; $expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, server, test, testsuite, upgrade/";
$this->assertRegExp($expected, $output); $this->assertRegExp($expected, $output);
$expected = "/\[.*app.*\] sample/"; $expected = "/\[.*app.*\] sample/";

Some files were not shown because too many files have changed in this diff Show more