diff --git a/app/Config/core.php b/app/Config/core.php index 61277674d..7bb39ee5a 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -116,10 +116,17 @@ * for any URL generation inside the application, set the following * configuration variable to the http(s) address to your domain. This * will override the automatic detection of full base URL and can be - * useful when generating links from the CLI (e.g. sending emails) + * useful when generating links from the CLI (e.g. sending emails). + * If the application runs in a subfolder, you should also set App.base. */ //Configure::write('App.fullBaseUrl', 'http://example.com'); +/** + * The base directory the app resides in. Should be used if the + * application runs in a subfolder and App.fullBaseUrl is set. + */ + //Configure::write('App.base', '/my_app'); + /** * Web path to the public images directory under webroot. * If not set defaults to 'img/' diff --git a/app/Controller/PagesController.php b/app/Controller/PagesController.php index e9ba9d9bd..5f8d1c4cc 100644 --- a/app/Controller/PagesController.php +++ b/app/Controller/PagesController.php @@ -40,7 +40,7 @@ class PagesController extends AppController { /** * Displays a view * - * @return \Cake\Network\Response|null + * @return CakeResponse|null * @throws ForbiddenException When a directory traversal attempt. * @throws NotFoundException When the view file could not be found * or MissingViewException in debug mode. diff --git a/app/webroot/.htaccess b/app/webroot/.htaccess index e3543be40..bb4c43955 100644 --- a/app/webroot/.htaccess +++ b/app/webroot/.htaccess @@ -6,6 +6,7 @@ RewriteEngine On + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] diff --git a/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php b/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php index 02144b171..86f70c8ca 100644 --- a/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php @@ -84,6 +84,12 @@ class BasicAuthenticate extends BaseAuthenticate { public function getUser(CakeRequest $request) { $username = env('PHP_AUTH_USER'); $pass = env('PHP_AUTH_PW'); + if (!strlen($username)) { + $httpAuthorization = $request->header('Authorization'); + if (strlen($httpAuthorization) > 0 && strpos($httpAuthorization, 'Basic') !== false) { + list($username, $pass) = explode(':', base64_decode(substr($httpAuthorization, 6))); + } + } if (!is_string($username) || $username === '' || !is_string($pass) || $pass === '') { return false; diff --git a/lib/Cake/Core/CakePlugin.php b/lib/Cake/Core/CakePlugin.php index 426e22a94..013b9d2d2 100644 --- a/lib/Cake/Core/CakePlugin.php +++ b/lib/Cake/Core/CakePlugin.php @@ -17,8 +17,9 @@ */ /** - * CakePlugin is responsible for loading and unloading plugins. It also can - * retrieve plugin paths and load their bootstrap and routes files. + * CakePlugin is responsible for loading and unloading plugins. + * + * It also can retrieve plugin paths and load their bootstrap and routes files. * * @package Cake.Core * @link http://book.cakephp.org/2.0/en/plugins.html @@ -37,45 +38,47 @@ class CakePlugin { * * Examples: * - * `CakePlugin::load('DebugKit')` + * `CakePlugin::load('DebugKit');` * - * Will load the DebugKit plugin and will not load any bootstrap nor route files + * Will load the DebugKit plugin and will not load any bootstrap nor route files. * - * `CakePlugin::load('DebugKit', array('bootstrap' => true, 'routes' => true))` + * `CakePlugin::load('DebugKit', array('bootstrap' => true, 'routes' => true));` * - * will load the bootstrap.php and routes.php files + * Will load the bootstrap.php and routes.php files. * - * `CakePlugin::load('DebugKit', array('bootstrap' => false, 'routes' => true))` + * `CakePlugin::load('DebugKit', array('bootstrap' => false, 'routes' => true));` * - * will load routes.php file but not bootstrap.php + * Will load routes.php file but not bootstrap.php. * - * `CakePlugin::load('DebugKit', array('bootstrap' => array('config1', 'config2')))` + * `CakePlugin::load('DebugKit', array('bootstrap' => array('config1', 'config2')));` * - * will load config1.php and config2.php files + * Will load config1.php and config2.php files. * - * `CakePlugin::load('DebugKit', array('bootstrap' => 'aCallableMethod'))` + * `CakePlugin::load('DebugKit', array('bootstrap' => 'aCallableMethod'));` * - * will run the aCallableMethod function to initialize it + * Will run the aCallableMethod function to initialize it. * * Bootstrap initialization functions can be expressed as a PHP callback type, * including closures. Callbacks will receive two parameters - * (plugin name, plugin configuration) + * (plugin name, plugin configuration). * * It is also possible to load multiple plugins at once. Examples: * - * `CakePlugin::load(array('DebugKit', 'ApiGenerator'))` + * `CakePlugin::load(array('DebugKit', 'ApiGenerator'));` * - * will load the DebugKit and ApiGenerator plugins + * Will load the DebugKit and ApiGenerator plugins. * - * `CakePlugin::load(array('DebugKit', 'ApiGenerator'), array('bootstrap' => true))` + * `CakePlugin::load(array('DebugKit', 'ApiGenerator'), array('bootstrap' => true));` * - * will load bootstrap file for both plugins + * Will load bootstrap file for both plugins. * * ``` * CakePlugin::load(array( - * 'DebugKit' => array('routes' => true), - * 'ApiGenerator' - * ), array('bootstrap' => true)) + * 'DebugKit' => array('routes' => true), + * 'ApiGenerator' + * ), + * array('bootstrap' => true) + * ); * ``` * * Will only load the bootstrap for ApiGenerator and only the routes for DebugKit. @@ -124,6 +127,7 @@ class CakePlugin { /** * Will load all the plugins located in the configured plugins folders + * * If passed an options array, it will be used as a common default for all plugins to be loaded * It is possible to set specific defaults for each plugins in the options array. Examples: * @@ -131,7 +135,7 @@ class CakePlugin { * CakePlugin::loadAll(array( * array('bootstrap' => true), * 'DebugKit' => array('routes' => true, 'bootstrap' => false), - * )) + * )); * ``` * * The above example will load the bootstrap file for all plugins, but for DebugKit it will only load @@ -140,11 +144,11 @@ class CakePlugin { * each plugin you can use the `ignoreMissing` option: * * ``` - * CakePlugin::loadAll(array( - * 'ignoreMissing' => true, - * 'bootstrap' => true, - * 'routes' => true, - * )); + * CakePlugin::loadAll(array( + * 'ignoreMissing' => true, + * 'bootstrap' => true, + * 'routes' => true, + * )); * ``` * * The ignoreMissing option will do additional file_exists() calls but is simpler @@ -155,12 +159,12 @@ class CakePlugin { */ public static function loadAll($options = array()) { $plugins = App::objects('plugins'); - foreach ($plugins as $p) { - $opts = isset($options[$p]) ? (array)$options[$p] : array(); + foreach ($plugins as $plugin) { + $pluginOptions = isset($options[$plugin]) ? (array)$options[$plugin] : array(); if (isset($options[0])) { - $opts += $options[0]; + $pluginOptions += $options[0]; } - static::load($p, $opts); + static::load($plugin, $pluginOptions); } } diff --git a/lib/Cake/I18n/L10n.php b/lib/Cake/I18n/L10n.php index c2bc64f56..46b63ef40 100644 --- a/lib/Cake/I18n/L10n.php +++ b/lib/Cake/I18n/L10n.php @@ -269,7 +269,7 @@ class L10n { 'hi' => array('language' => 'Hindi', 'locale' => 'hin', 'localeFallback' => 'hin', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hr' => array('language' => 'Croatian', 'locale' => 'hrv', 'localeFallback' => 'hrv', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hu' => array('language' => 'Hungarian', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'), - 'hu-hu' => array('language' => 'Hungarian (Hungary)', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'hu-hu' => array('language' => 'Hungarian (Hungary)', 'locale' => 'hu_hu', 'localeFallback' => 'hun', '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'), 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'), @@ -287,7 +287,7 @@ class L10n { 'li' => array('language' => 'Limburgish', 'locale' => 'lim', 'localeFallback' => 'nld', '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-lv' => array('language' => 'Latvian (Latvia)', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'lv-lv' => array('language' => 'Latvian (Latvia)', 'locale' => 'lv_lv', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mkd', 'localeFallback' => 'mkd', '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' => 'msa', 'localeFallback' => 'msa', 'charset' => 'utf-8', 'direction' => 'ltr'), @@ -301,6 +301,7 @@ class L10n { 'nn-no' => array('language' => 'Norwegian Nynorsk (Norway)', 'locale' => 'nn_no', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'), 'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'), 'pl' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'pl-pl' => array('language' => 'Polish (Poland)', 'locale' => 'pl_pl', 'localeFallback' => 'pol', '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'), 'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'), @@ -309,7 +310,7 @@ class L10n { 'ro-ro' => array('language' => 'Romanian (Romania)', 'locale' => 'ro_ro', 'localeFallback' => 'ron', '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-ru' => array('language' => 'Russian (Russia)', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'ru-ru' => array('language' => 'Russian (Russia)', 'locale' => 'ru_ru', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'), 'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', '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'), diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php index 4a9e16b57..34cb3af72 100644 --- a/lib/Cake/Model/CakeSchema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -611,9 +611,17 @@ class CakeSchema extends CakeObject { $db = $Obj->getDataSource(); $fields = $Obj->schema(true); + $hasPrimaryAlready = false; + foreach ($fields as $value) { + if (isset($value['key']) && $value['key'] === 'primary') { + $hasPrimaryAlready = true; + break; + } + } + $columns = array(); foreach ($fields as $name => $value) { - if ($Obj->primaryKey === $name) { + if ($Obj->primaryKey === $name && !$hasPrimaryAlready && !isset($value['key'])) { $value['key'] = 'primary'; } if (!isset($db->columns[$value['type']])) { diff --git a/lib/Cake/Model/Datasource/Database/Postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php index 341531320..c6f34a722 100644 --- a/lib/Cake/Model/Datasource/Database/Postgres.php +++ b/lib/Cake/Model/Datasource/Database/Postgres.php @@ -201,14 +201,26 @@ class Postgres extends DboSource { $fields = parent::describe($table); $this->_sequenceMap[$table] = array(); $cols = null; + $hasPrimary = false; if ($fields === null) { $cols = $this->_execute( - "SELECT DISTINCT table_schema AS schema, column_name AS name, data_type AS type, is_nullable AS null, - column_default AS default, ordinal_position AS position, character_maximum_length AS char_length, - character_octet_length AS oct_length FROM information_schema.columns - WHERE table_name = ? AND table_schema = ? ORDER BY position", - array($table, $this->config['schema']) + 'SELECT DISTINCT table_schema AS schema, + column_name AS name, + data_type AS type, + is_nullable AS null, + column_default AS default, + ordinal_position AS position, + character_maximum_length AS char_length, + character_octet_length AS oct_length, + pg_get_serial_sequence(attr.attrelid::regclass::text, attr.attname) IS NOT NULL AS has_serial + FROM information_schema.columns c + INNER JOIN pg_catalog.pg_namespace ns ON (ns.nspname = table_schema) + INNER JOIN pg_catalog.pg_class cl ON (cl.relnamespace = ns.oid AND cl.relname = table_name) + LEFT JOIN pg_catalog.pg_attribute attr ON (cl.oid = attr.attrelid AND column_name = attr.attname) + WHERE table_name = ? AND table_schema = ? AND table_catalog = ? + ORDER BY ordinal_position', + array($table, $this->config['schema'], $this->config['database']) ); // @codingStandardsIgnoreStart @@ -241,17 +253,25 @@ class Postgres extends DboSource { "$1", preg_replace('/::.*/', '', $c->default) ), - 'length' => $length + 'length' => $length, ); - if ($model instanceof Model) { - if ($c->name === $model->primaryKey) { - $fields[$c->name]['key'] = 'primary'; - if ( - $fields[$c->name]['type'] !== 'string' && - $fields[$c->name]['type'] !== 'uuid' - ) { - $fields[$c->name]['length'] = 11; - } + + // Serial columns are primary integer keys + if ($c->has_serial) { + $fields[$c->name]['key'] = 'primary'; + $fields[$c->name]['length'] = 11; + $hasPrimary = true; + } + if ($hasPrimary === false && + $model instanceof Model && + $c->name === $model->primaryKey + ) { + $fields[$c->name]['key'] = 'primary'; + if ( + $fields[$c->name]['type'] !== 'string' && + $fields[$c->name]['type'] !== 'uuid' + ) { + $fields[$c->name]['length'] = 11; } } if ( diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index 9b0af00d6..61ec5ff40 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -44,7 +44,8 @@ class CakeSocket { 'host' => 'localhost', 'protocol' => 'tcp', 'port' => 80, - 'timeout' => 30 + 'timeout' => 30, + 'cryptoType' => 'tls', ); /** @@ -96,7 +97,7 @@ class CakeSocket { '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 + 'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER, // @codingStandardsIgnoreEnd ); @@ -116,6 +117,44 @@ class CakeSocket { */ public function __construct($config = array()) { $this->config = array_merge($this->_baseConfig, $config); + + $this->_addTlsVersions(); + } + +/** + * Add TLS versions that are dependent on specific PHP versions. + * + * These TLS versions are not supported by older PHP versions, + * so we have to conditionally set them if they are supported. + * + * As of PHP5.6.6, STREAM_CRYPTO_METHOD_TLS_CLIENT does not include + * TLS1.1 or 1.2. If we have TLS1.2 support we need to update the method map. + * + * @see https://bugs.php.net/bug.php?id=69195 + * @see https://github.com/php/php-src/commit/10bc5fd4c4c8e1dd57bd911b086e9872a56300a0 + * @return void + */ + protected function _addTlsVersions() { + $conditionalCrypto = array( + 'tlsv1_1_client' => 'STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT', + 'tlsv1_2_client' => 'STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT', + 'tlsv1_1_server' => 'STREAM_CRYPTO_METHOD_TLSv1_1_SERVER', + 'tlsv1_2_server' => 'STREAM_CRYPTO_METHOD_TLSv1_2_SERVER' + ); + foreach ($conditionalCrypto as $key => $const) { + if (defined($const)) { + $this->_encryptMethods[$key] = constant($const); + } + } + + // @codingStandardsIgnoreStart + if (isset($this->_encryptMethods['tlsv1_2_client'])) { + $this->_encryptMethods['tls_client'] = STREAM_CRYPTO_METHOD_TLS_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + } + if (isset($this->_encryptMethods['tlsv1_2_server'])) { + $this->_encryptMethods['tls_server'] = STREAM_CRYPTO_METHOD_TLS_SERVER | STREAM_CRYPTO_METHOD_TLSv1_1_SERVER | STREAM_CRYPTO_METHOD_TLSv1_2_SERVER; + } + // @codingStandardsIgnoreEnd } /** @@ -205,7 +244,7 @@ class CakeSocket { } } - $this->enableCrypto('tls', 'client'); + $this->enableCrypto($this->config['cryptoType'], 'client'); } } return $this->connected; @@ -433,7 +472,7 @@ class CakeSocket { /** * Encrypts current stream socket, using one of the defined encryption methods. * - * @param string $type Type which can be one of 'sslv2', 'sslv3', 'sslv23' or 'tls'. + * @param string $type Type which can be one of 'sslv2', 'sslv3', 'sslv23', 'tls', 'tlsv1_1' or 'tlsv1_2'. * @param string $clientOrServer Can be one of 'client', 'server'. Default is 'client'. * @param bool $enable Enable or disable encryption. Default is true (enable) * @return bool True on success diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php index df18703c4..af5086caf 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php @@ -15,8 +15,6 @@ * @since CakePHP(tm) v 2.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ - -App::uses('AuthComponent', 'Controller/Component'); App::uses('BasicAuthenticate', 'Controller/Component/Auth'); App::uses('AppModel', 'Model'); App::uses('CakeRequest', 'Network'); @@ -197,6 +195,28 @@ class BasicAuthenticateTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * test authenticate success with header values + * + * @return void + */ + public function testAuthenticateSuccessFromHeaders() { + $_SERVER['HTTP_AUTHORIZATION'] = 'Basic ' . base64_encode('mariano:password'); + unset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); + + $request = new CakeRequest('posts/index', false); + $request->addParams(array('pass' => array(), 'named' => array())); + + $result = $this->auth->authenticate($request, $this->response); + $expected = array( + 'id' => 1, + 'user' => 'mariano', + 'created' => '2007-03-17 01:16:23', + 'updated' => '2007-03-17 01:18:31' + ); + $this->assertEquals($expected, $result); + } + /** * test contain success * diff --git a/lib/Cake/Test/Case/Model/CakeSchemaTest.php b/lib/Cake/Test/Case/Model/CakeSchemaTest.php index be096484b..baabd6603 100644 --- a/lib/Cake/Test/Case/Model/CakeSchemaTest.php +++ b/lib/Cake/Test/Case/Model/CakeSchemaTest.php @@ -366,6 +366,39 @@ class SchemaCrossDatabaseFixture extends CakeTestFixture { ); } +/** + * NonConventionalPrimaryKeyFixture class + * + * @package Cake.Test.Case.Model + */ +class NonConventionalPrimaryKeyFixture extends CakeTestFixture { + +/** + * name property + * + * @var string + */ + public $name = 'NonConventional'; + +/** + * table property + * + * @var string + */ + public $table = 'non_conventional'; + +/** + * fields property + * + * @var array + */ + public $fields = array( + 'version_id' => array('type' => 'integer', 'key' => 'primary'), + 'id' => array('type' => 'integer'), + 'name' => 'string' + ); +} + /** * SchemaPrefixAuthUser class * @@ -652,6 +685,33 @@ class CakeSchemaTest extends CakeTestCase { $fixture->drop($db); } +/** + * testSchemaRead method when a primary key is on a non-conventional column + * + * @return void + */ + public function testSchemaReadWithNonConventionalPrimaryKey() { + $db = ConnectionManager::getDataSource('test'); + $fixture = new NonConventionalPrimaryKeyFixture(); + $fixture->create($db); + + $read = $this->Schema->read(array( + 'connection' => 'test', + 'name' => 'TestApp', + 'models' => false + )); + $fixture->drop($db); + + $this->assertArrayHasKey('non_conventional', $read['tables']); + $versionIdHasKey = isset($read['tables']['non_conventional']['version_id']['key']); + $this->assertTrue($versionIdHasKey, 'version_id key should be set'); + $versionIdKeyIsPrimary = $read['tables']['non_conventional']['version_id']['key'] === 'primary'; + $this->assertTrue($versionIdKeyIsPrimary, 'version_id key should be primary'); + + $idHasKey = isset($read['tables']['non_conventional']['id']['key']); + $this->assertFalse($idHasKey, 'id key should not be set'); + } + /** * test that tables are generated correctly * diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index c678d9c5b..43a4c3936 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -54,11 +54,12 @@ class CakeSocketTest extends CakeTestCase { $this->Socket = new CakeSocket(); $config = $this->Socket->config; $this->assertSame($config, array( - 'persistent' => false, - 'host' => 'localhost', - 'protocol' => 'tcp', - 'port' => 80, - 'timeout' => 30 + 'persistent' => false, + 'host' => 'localhost', + 'protocol' => 'tcp', + 'port' => 80, + 'timeout' => 30, + 'cryptoType' => 'tls', )); $this->Socket->reset(); @@ -324,6 +325,20 @@ class CakeSocketTest extends CakeTestCase { $this->Socket->disconnect(); } +/** + * testEnableCrypto tlsv1_1 + * + * @return void + */ + public function testEnableCryptoTlsV11() { + $this->skipIf(!defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT'), 'TLS1.1 is not supported on this system'); + + // testing on tls server + $this->_connectSocketToSslTls(); + $this->assertTrue($this->Socket->enableCrypto('tlsv1_1', 'client')); + $this->Socket->disconnect(); + } + /** * testEnableCryptoExceptionEnableTwice * diff --git a/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php b/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php index 404f977f1..89bbcdb21 100644 --- a/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php +++ b/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php @@ -215,11 +215,13 @@ class HttpSocketTest extends CakeTestCase { $this->Socket->expects($this->never())->method('connect'); $this->Socket->__construct(array('host' => 'foo-bar')); $baseConfig['host'] = 'foo-bar'; + $baseConfig['cryptoType'] = 'tls'; $this->assertEquals($this->Socket->config, $baseConfig); $this->Socket->reset(); $baseConfig = $this->Socket->config; $this->Socket->__construct('http://www.cakephp.org:23/'); + $baseConfig['cryptoType'] = 'tls'; $baseConfig['host'] = $baseConfig['request']['uri']['host'] = 'www.cakephp.org'; $baseConfig['port'] = $baseConfig['request']['uri']['port'] = 23; $baseConfig['request']['uri']['scheme'] = 'http'; diff --git a/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php b/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php index 4f47c1e10..0819f8db3 100644 --- a/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php +++ b/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php @@ -624,4 +624,107 @@ class ControllerTestCaseTest extends CakeTestCase { $this->assertEquals($restored, $_POST); } +/** + * Tests that the `App.base` path is properly stripped from the URL generated from the + * given URL array, and that consequently the correct controller/action is being matched. + * + * @return void + */ + public function testAppBaseConfigCompatibilityWithArrayUrls() { + Configure::write('App.base', '/cakephp'); + + $this->Case->generate('TestsApps'); + $this->Case->testAction(array('controller' => 'tests_apps', 'action' => 'index')); + + $this->assertEquals('/cakephp', $this->Case->controller->request->base); + $this->assertEquals('/cakephp/', $this->Case->controller->request->webroot); + $this->assertEquals('/cakephp/tests_apps', $this->Case->controller->request->here); + $this->assertEquals('tests_apps', $this->Case->controller->request->url); + + $expected = array( + 'plugin' => null, + 'controller' => 'tests_apps', + 'action' => 'index', + 'named' => array(), + 'pass' => array(), + ); + $this->assertEquals($expected, array_intersect_key($this->Case->controller->request->params, $expected)); + } + +/** + * Tests that query string data from URL arrays properly makes it into the request object + * on GET requests. + * + * @return void + */ + public function testTestActionWithArrayUrlQueryStringDataViaGetRequest() { + $query = array('foo' => 'bar'); + + $this->Case->generate('TestsApps'); + $this->Case->testAction( + array( + 'controller' => 'tests_apps', + 'action' => 'index', + '?' => $query + ), + array( + 'method' => 'get' + ) + ); + + $this->assertEquals('tests_apps', $this->Case->controller->request->url); + $this->assertEquals($query, $this->Case->controller->request->query); + } + +/** + * Tests that query string data from URL arrays properly makes it into the request object + * on POST requests. + * + * @return void + */ + public function testTestActionWithArrayUrlQueryStringDataViaPostRequest() { + $query = array('foo' => 'bar'); + + $this->Case->generate('TestsApps'); + $this->Case->testAction( + array( + 'controller' => 'tests_apps', + 'action' => 'index', + '?' => $query + ), + array( + 'method' => 'post' + ) + ); + + $this->assertEquals('tests_apps', $this->Case->controller->request->url); + $this->assertEquals($query, $this->Case->controller->request->query); + } + +/** + * Tests that query string data from both, URL arrays as well as the `data` option, + * properly makes it into the request object. + * + * @return void + */ + public function testTestActionWithArrayUrlQueryStringDataAndDataOptionViaGetRequest() { + $query = array('foo' => 'bar'); + $data = array('bar' => 'foo'); + + $this->Case->generate('TestsApps'); + $this->Case->testAction( + array( + 'controller' => 'tests_apps', + 'action' => 'index', + '?' => $query + ), + array( + 'method' => 'get', + 'data' => $data + ) + ); + + $this->assertEquals('tests_apps', $this->Case->controller->request->url); + $this->assertEquals($data + $query, $this->Case->controller->request->query); + } } diff --git a/lib/Cake/Test/Case/Utility/ValidationTest.php b/lib/Cake/Test/Case/Utility/ValidationTest.php index bec844dcb..d10aa2f6e 100644 --- a/lib/Cake/Test/Case/Utility/ValidationTest.php +++ b/lib/Cake/Test/Case/Utility/ValidationTest.php @@ -148,6 +148,10 @@ class ValidationTest extends CakeTestCase { * @return void */ public function testNotBlank() { + $this->assertTrue(Validation::notBlank(0), 'zero should not be blank'); + $this->assertTrue(Validation::notBlank(0.0), 'zero should not be blank'); + $this->assertTrue(Validation::notBlank(0.0 * -1), 'negative 0 should not be blank'); + $this->assertTrue(Validation::notBlank(-0.0), 'negative 0 should not be blank'); $this->assertTrue(Validation::notBlank('abcdefg')); $this->assertTrue(Validation::notBlank('fasdf ')); $this->assertTrue(Validation::notBlank('fooo' . chr(243) . 'blabla')); diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 9169333d5..bc1bf1c22 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -592,7 +592,7 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id' + 'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id', 'autocomplete' )), '/div' ); @@ -713,11 +713,13 @@ class FormHelperTest extends CakeTestCase { 'type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => $hash, 'id' => 'preg:/TokenFields\d+/', 'form' => 'MyTestForm', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'form' => 'MyTestForm', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', @@ -754,13 +756,15 @@ class FormHelperTest extends CakeTestCase { 'type' => 'hidden', 'name' => 'data[_Token][fields]', 'id' => 'preg:/TokenFields\d+/', - 'value' => $hash + 'value' => $hash, + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'id' => 'preg:/TokenUnlocked\d+/', 'value' => '', + 'autocomplete' )), '/div' ); @@ -930,11 +934,13 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -989,11 +995,13 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/' + 'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -1135,11 +1143,13 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -1222,12 +1232,18 @@ class FormHelperTest extends CakeTestCase { $expected = array( 'div' => array('style' => 'display:none;'), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'type' => 'hidden', 'name' => + 'data[_Token][fields]', + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off' )), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][unlocked]', + 'value' => 'address%7Cfirst_name', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -1291,15 +1307,20 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => 'address%7Cfirst_name', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', - 'value' => $tokenDebug, 'id' => 'preg:/TokenDebug\d+/', + 'value' => $tokenDebug, + 'id' => 'preg:/TokenDebug\d+/', )), '/div' ); @@ -1359,11 +1380,15 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => 'address%7Cfirst_name', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -1412,11 +1437,15 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' + 'value' => 'address%7Cfirst_name', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' )), '/div' ); @@ -1460,12 +1489,18 @@ class FormHelperTest extends CakeTestCase { $expected = array( 'div' => array('style' => 'display:none;'), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][fields]', + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off', )), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][unlocked]', + 'value' => 'address%7Cfirst_name', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off', )), '/div' ); @@ -1504,8 +1539,11 @@ class FormHelperTest extends CakeTestCase { 'div' => array('style' => 'display:none;'), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][key]', - 'value' => 'testKey', 'id' => 'preg:/Token\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][key]', + 'value' => 'testKey', + 'id' => 'preg:/Token\d+/', + 'autocomplete' => 'off', )), '/div' ); @@ -1590,12 +1628,18 @@ class FormHelperTest extends CakeTestCase { $expected = array( 'div' => array('style' => 'display:none;'), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][fields]', + 'value' => $hash, + 'id' => 'preg:/TokenFields\d+/', + 'autocomplete' => 'off', )), array('input' => array( - 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', - 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' + 'type' => 'hidden', + 'name' => 'data[_Token][unlocked]', + 'value' => '', + 'id' => 'preg:/TokenUnlocked\d+/', + 'autocomplete' => 'off', )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', @@ -8461,14 +8505,14 @@ class FormHelperTest extends CakeTestCase { ), array('div' => array('style' => 'display:none;')), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete')), '/div', 'button' => array('type' => 'submit'), 'Delete', '/button', array('div' => array('style' => 'display:none;')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', 'value' => $tokenDebug, 'id' => 'preg:/TokenDebug\d+/', @@ -8598,10 +8642,10 @@ class FormHelperTest extends CakeTestCase { 'name', 'id', 'style' => 'display:none;' ), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'test', 'id')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'test', 'id', 'autocomplete')), 'div' => array('style' => 'display:none;'), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => $hash, 'id')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => $hash, 'id', 'autocomplete')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id', 'autocomplete')), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', 'value' => $tokenDebug, 'id' => 'preg:/TokenDebug\d+/', @@ -8689,10 +8733,10 @@ class FormHelperTest extends CakeTestCase { 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' ), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete' => 'off')), 'div' => array('style' => 'display:none;'), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', 'value' => $tokenDebug, 'id' => 'preg:/TokenDebug\d+/', @@ -8725,10 +8769,10 @@ class FormHelperTest extends CakeTestCase { 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' ), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete' => 'off')), 'div' => array('style' => 'display:none;'), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')), - array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][debug]', 'value' => $tokenDebug, 'id' => 'preg:/TokenDebug\d+/', diff --git a/lib/Cake/TestSuite/ControllerTestCase.php b/lib/Cake/TestSuite/ControllerTestCase.php index 768fea5f3..bd3dcf6ca 100644 --- a/lib/Cake/TestSuite/ControllerTestCase.php +++ b/lib/Cake/TestSuite/ControllerTestCase.php @@ -248,7 +248,16 @@ abstract class ControllerTestCase extends CakeTestCase { $_GET = array(); } } - $request = $this->getMock('CakeRequest', array('_readInput'), array($url)); + + if (strpos($url, '?') !== false) { + list($url, $query) = explode('?', $url, 2); + parse_str($query, $queryArgs); + $_GET += $queryArgs; + } + + $_SERVER['REQUEST_URI'] = $url; + /** @var CakeRequest|PHPUnit_Framework_MockObject_MockObject $request */ + $request = $this->getMock('CakeRequest', array('_readInput')); if (is_string($options['data'])) { $request->expects($this->any()) @@ -349,9 +358,12 @@ abstract class ControllerTestCase extends CakeTestCase { ), (array)$mocks); list($plugin, $name) = pluginSplit($controller); + /** @var Controller|PHPUnit_Framework_MockObject_MockObject $controllerObj */ $controllerObj = $this->getMock($name . 'Controller', $mocks['methods'], array(), '', false); $controllerObj->name = $name; + /** @var CakeRequest|PHPUnit_Framework_MockObject_MockObject $request */ $request = $this->getMock('CakeRequest'); + /** @var CakeResponse|PHPUnit_Framework_MockObject_MockObject $response */ $response = $this->getMock($this->_responseClass, array('_sendHeader')); $controllerObj->__construct($request, $response); $controllerObj->Components->setController($controllerObj); @@ -385,6 +397,7 @@ abstract class ControllerTestCase extends CakeTestCase { )); } $config = isset($controllerObj->components[$component]) ? $controllerObj->components[$component] : array(); + /** @var Component|PHPUnit_Framework_MockObject_MockObject $componentObj */ $componentObj = $this->getMock($componentClass, $methods, array($controllerObj->Components, $config)); $controllerObj->Components->set($name, $componentObj); $controllerObj->Components->enable($name); diff --git a/lib/Cake/Utility/Validation.php b/lib/Cake/Utility/Validation.php index da614de1d..bc7a18829 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -66,19 +66,14 @@ class Validation { * * Returns true if string contains something other than whitespace * - * $check can be passed as an array: - * array('check' => 'valueToCheck'); - * - * @param string|array $check Value to check + * @param string $check Value to check * @return bool Success */ public static function notBlank($check) { - if (!is_scalar($check)) { - return false; - } - if (empty($check) && (string)$check !== '0') { + if (empty($check) && !is_bool($check) && !is_numeric($check)) { return false; } + return static::_check($check, '/[^\s]+/m'); } diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 0bb58a9be..ca5cbd8c5 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -504,7 +504,8 @@ class FormHelper extends AppHelper { } return $this->hidden('_Token.key', array( 'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(), - 'secure' => static::SECURE_SKIP + 'secure' => static::SECURE_SKIP, + 'autocomplete' => 'off', )); } @@ -622,12 +623,14 @@ class FormHelper extends AppHelper { 'value' => urlencode($fields . ':' . $locked), 'id' => 'TokenFields' . mt_rand(), 'secure' => static::SECURE_SKIP, + 'autocomplete' => 'off', )); $out = $this->hidden('_Token.fields', $tokenFields); $tokenUnlocked = array_merge($secureAttributes, array( 'value' => urlencode($unlocked), 'id' => 'TokenUnlocked' . mt_rand(), 'secure' => static::SECURE_SKIP, + 'autocomplete' => 'off', )); $out .= $this->hidden('_Token.unlocked', $tokenUnlocked); if ($debugSecurity) {