Merge branch '2.x' into 2.next

This commit is contained in:
mark_story 2017-05-27 21:47:22 -04:00
commit cf679a3233
19 changed files with 458 additions and 113 deletions

View file

@ -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/'

View file

@ -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.

View file

@ -6,6 +6,7 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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'),

View file

@ -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']])) {

View file

@ -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 (

View file

@ -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

View file

@ -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
*

View file

@ -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
*

View file

@ -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
*

View file

@ -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';

View file

@ -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);
}
}

View file

@ -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'));

View file

@ -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+/',

View file

@ -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);

View file

@ -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');
}

View file

@ -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) {