Commit b918fa50 by Antonio Ramirez

Merge branch 'upstream' into 364-toAscii

* upstream: Fixed CSRF token masking issue. improved error message of calling invalid scope method. Fixed repo URL Fixes #1650: Added Connection::pdoClass. code style fix. added changelog codestyle fix improved checkIntegrity method Modified extension guidlines fix sphinx command signature fixed bug with forgotten param, fixed behavior for one table integrity fixed sequence reset added postgresql features to reset seq/check integrity
parents 61591ea4 4b569f3e
...@@ -17,9 +17,11 @@ using the following syntax: e.g. `[[name()]]`, `[[name\space\MyClass::name()]]`. ...@@ -17,9 +17,11 @@ using the following syntax: e.g. `[[name()]]`, `[[name\space\MyClass::name()]]`.
### Namespace and package names ### Namespace and package names
- Extension MUST use the type `yii2-extension` in `composer.json` file. - Extension MUST use the type `yii2-extension` in `composer.json` file.
- Extension MUST NOT use `yii` or `yii2` in the composer package name or in the namespaces used in the package. - Extension MUST NOT use `yiisoft` in the composer package name, the composer vendor name or in the namespaces used in the package.
- Additionally extensions MUST NOT use `yii` or `yii2` in their composer vendor name.
- Extension MUST NOT have a root-namespace named `\yii`, `\yii2` or `\yiisoft`.
- Extension SHOULD use namespaces in this format `vendor-name\package` (all lowercase). - Extension SHOULD use namespaces in this format `vendor-name\package` (all lowercase).
- Extension MAY use a `yii2-` prefix in the composer vendor name (URL). - Extension MAY use `yii2-` in the composer package name (e.g `vendor\yii2-api-adapter` or `vendor\my-yii2-package` (URL).
- Extension MAY use a `yii2-` prefix in the repository name (URL). - Extension MAY use a `yii2-` prefix in the repository name (URL).
### Dependencies ### Dependencies
...@@ -75,4 +77,4 @@ Authorization ...@@ -75,4 +77,4 @@ Authorization
Testing your extension Testing your extension
---------------------- ----------------------
- Extension SHOULD be testable with *PHPUnit*. - Extension SHOULD be testable with *PHPUnit*.
\ No newline at end of file
...@@ -18,10 +18,10 @@ then you must [setup your GIT installation to work with GitHub](http://help.gith ...@@ -18,10 +18,10 @@ then you must [setup your GIT installation to work with GitHub](http://help.gith
### 2. Add the main Yii repository as an additional git remote called "upstream" ### 2. Add the main Yii repository as an additional git remote called "upstream"
Change to the directory where you cloned Yii, normally, "yii". Then enter the following command: Change to the directory where you cloned Yii, normally, "yii2". Then enter the following command:
``` ```
git remote add upstream git://github.com/yiisoft/yii.git git remote add upstream git://github.com/yiisoft/yii2.git
``` ```
### 3. Make sure there is an issue created for the thing you are working on. ### 3. Make sure there is an issue created for the thing you are working on.
......
...@@ -319,7 +319,7 @@ class Command extends \yii\db\Command ...@@ -319,7 +319,7 @@ class Command extends \yii\db\Command
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function checkIntegrity($check = true, $schema = '') public function checkIntegrity($check = true, $schema = '', $table = '')
{ {
throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); throw new NotSupportedException('"' . __METHOD__ . '" is not supported.');
} }
......
...@@ -34,6 +34,8 @@ Yii Framework 2 Change Log ...@@ -34,6 +34,8 @@ Yii Framework 2 Change Log
- Enh #1611: Added `BaseActiveRecord::markAttributeDirty()` (qiangxue) - Enh #1611: Added `BaseActiveRecord::markAttributeDirty()` (qiangxue)
- Enh #1634: Use masked CSRF tokens to prevent BREACH exploits (qiangxue) - Enh #1634: Use masked CSRF tokens to prevent BREACH exploits (qiangxue)
- Enh #1641: Added `BaseActiveRecord::updateAttributes()` (qiangxue) - Enh #1641: Added `BaseActiveRecord::updateAttributes()` (qiangxue)
- Enh #1646: Added postgresql `QueryBuilder::checkIntegrity` and `QueryBuilder::resetSequence` (Ragazzo)
- Enh #1645: Added `Connection::$pdoClass` property (Ragazzo)
- Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
- Enh: Support for file aliases in console command 'message' (omnilight) - Enh: Support for file aliases in console command 'message' (omnilight)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\base\InvalidCallException;
/** /**
* ActiveQueryTrait implements the common methods and properties for active record query classes. * ActiveQueryTrait implements the common methods and properties for active record query classes.
...@@ -42,6 +43,10 @@ trait ActiveQueryTrait ...@@ -42,6 +43,10 @@ trait ActiveQueryTrait
public function __call($name, $params) public function __call($name, $params)
{ {
if (method_exists($this->modelClass, $name)) { if (method_exists($this->modelClass, $name)) {
$method = new \ReflectionMethod($this->modelClass, $name);
if (!$method->isStatic() || !$method->isPublic()) {
throw new InvalidCallException("The scope method \"{$this->modelClass}::$name()\" must be public and static.");
}
array_unshift($params, $this); array_unshift($params, $this);
call_user_func_array([$this->modelClass, $name], $params); call_user_func_array([$this->modelClass, $name], $params);
return $this; return $this;
......
...@@ -743,12 +743,13 @@ class Command extends \yii\base\Component ...@@ -743,12 +743,13 @@ class Command extends \yii\base\Component
* @param boolean $check whether to turn on or off the integrity check. * @param boolean $check whether to turn on or off the integrity check.
* @param string $schema the schema name of the tables. Defaults to empty string, meaning the current * @param string $schema the schema name of the tables. Defaults to empty string, meaning the current
* or default schema. * or default schema.
* @param string $table the table name.
* @return Command the command object itself * @return Command the command object itself
* @throws NotSupportedException if this is not supported by the underlying DBMS * @throws NotSupportedException if this is not supported by the underlying DBMS
*/ */
public function checkIntegrity($check = true, $schema = '') public function checkIntegrity($check = true, $schema = '', $table = '')
{ {
$sql = $this->db->getQueryBuilder()->checkIntegrity($check, $schema); $sql = $this->db->getQueryBuilder()->checkIntegrity($check, $schema, $table);
return $this->setSql($sql); return $this->setSql($sql);
} }
} }
...@@ -253,7 +253,10 @@ class Connection extends Component ...@@ -253,7 +253,10 @@ class Connection extends Component
* @var Schema the database schema * @var Schema the database schema
*/ */
private $_schema; private $_schema;
/**
* @var string Custom PDO wrapper class. If not set, it will use "PDO" or "yii\db\mssql\PDO" when MSSQL is used.
*/
public $pdoClass;
/** /**
* Returns a value indicating whether the DB connection is established. * Returns a value indicating whether the DB connection is established.
...@@ -338,13 +341,17 @@ class Connection extends Component ...@@ -338,13 +341,17 @@ class Connection extends Component
*/ */
protected function createPdoInstance() protected function createPdoInstance()
{ {
$pdoClass = 'PDO'; $pdoClass = $this->pdoClass;
if (($pos = strpos($this->dsn, ':')) !== false) { if ($pdoClass === null) {
$driver = strtolower(substr($this->dsn, 0, $pos)); $pdoClass = 'PDO';
if ($driver === 'mssql' || $driver === 'dblib' || $driver === 'sqlsrv') { if (($pos = strpos($this->dsn, ':')) !== false) {
$pdoClass = 'yii\db\mssql\PDO'; $driver = strtolower(substr($this->dsn, 0, $pos));
if ($driver === 'mssql' || $driver === 'dblib' || $driver === 'sqlsrv') {
$pdoClass = 'yii\db\mssql\PDO';
}
} }
} }
return new $pdoClass($this->dsn, $this->username, $this->password, $this->attributes); return new $pdoClass($this->dsn, $this->username, $this->password, $this->attributes);
} }
......
...@@ -280,7 +280,7 @@ class Schema extends \yii\db\Schema ...@@ -280,7 +280,7 @@ class Schema extends \yii\db\Schema
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO schema name prefix. * @return array all table names in the database. The names have NO schema name prefix.
*/ */
protected function findTableNames($schema = '') public function findTableNames($schema = '')
{ {
$sql = 'SHOW TABLES'; $sql = 'SHOW TABLES';
if ($schema !== '') { if ($schema !== '') {
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
namespace yii\db\pgsql; namespace yii\db\pgsql;
use yii\base\InvalidParamException;
/** /**
* QueryBuilder is the query builder for PostgreSQL databases. * QueryBuilder is the query builder for PostgreSQL databases.
* *
...@@ -62,6 +64,65 @@ class QueryBuilder extends \yii\db\QueryBuilder ...@@ -62,6 +64,65 @@ class QueryBuilder extends \yii\db\QueryBuilder
} }
/** /**
* Creates a SQL statement for resetting the sequence value of a table's primary key.
* The sequence will be reset such that the primary key of the next new row inserted
* will have the specified value or 1.
* @param string $tableName the name of the table whose primary key sequence will be reset
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
$table = $this->db->getTableSchema($tableName);
if ($table !== null && $table->sequenceName !== null) {
$sequence = '"' . $table->sequenceName . '"';
if (strpos($sequence, '.') !== false) {
$sequence = str_replace('.', '"."', $sequence);
}
$tableName = $this->db->quoteTableName($tableName);
if ($value === null) {
$key = reset($table->primaryKey);
$value = "(SELECT COALESCE(MAX(\"{$key}\"),0) FROM {$tableName})+1";
} else {
$value = (int)$value;
}
return "SELECT SETVAL('$sequence',$value,false)";
} elseif ($table === null) {
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidParamException("There is not sequence associated with table '$tableName'.");
}
}
/**
* Builds a SQL statement for enabling or disabling integrity check.
* @param boolean $check whether to turn on or off the integrity check.
* @param string $schema the schema of the tables.
* @param string $table the table name.
* @return string the SQL statement for checking integrity
*/
public function checkIntegrity($check = true, $schema = '', $table = '')
{
$enable = $check ? 'ENABLE' : 'DISABLE';
$schema = $schema ? $schema : $this->db->schema->defaultSchema;
$tableNames = $table ? [$table] : $this->db->schema->findTableNames($schema);
$command = '';
foreach ($tableNames as $tableName) {
$tableName = '"' . $schema . '"."' . $tableName . '"';
$command .= "ALTER TABLE $tableName $enable TRIGGER ALL; ";
}
#enable to have ability to alter several tables
$this->db->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
return $command;
}
/**
* Builds a SQL statement for changing the definition of a column. * Builds a SQL statement for changing the definition of a column.
* @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.
* @param string $column the name of the column to be changed. The name will be properly quoted by the method. * @param string $column the name of the column to be changed. The name will be properly quoted by the method.
......
...@@ -158,7 +158,7 @@ class Schema extends \yii\db\Schema ...@@ -158,7 +158,7 @@ class Schema extends \yii\db\Schema
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
* @return array all table names in the database. The names have NO schema name prefix. * @return array all table names in the database. The names have NO schema name prefix.
*/ */
protected function findTableNames($schema = '') public function findTableNames($schema = '')
{ {
if ($schema === '') { if ($schema === '') {
$schema = $this->defaultSchema; $schema = $this->defaultSchema;
......
...@@ -87,7 +87,7 @@ class Schema extends \yii\db\Schema ...@@ -87,7 +87,7 @@ class Schema extends \yii\db\Schema
* If not empty, the returned table names will be prefixed with the schema name. * If not empty, the returned table names will be prefixed with the schema name.
* @return array all table names in the database. * @return array all table names in the database.
*/ */
protected function findTableNames($schema = '') public function findTableNames($schema = '')
{ {
$sql = "SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'"; $sql = "SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'";
return $this->db->createCommand($sql)->queryColumn(); return $this->db->createCommand($sql)->queryColumn();
......
...@@ -146,6 +146,7 @@ class DbFixtureManager extends Component ...@@ -146,6 +146,7 @@ class DbFixtureManager extends Component
} }
$this->db->createCommand()->truncateTable($tableName)->execute(); $this->db->createCommand()->truncateTable($tableName)->execute();
$this->db->createCommand()->resetSequence($tableName,1)->execute();
$fileName = $this->basePath . '/' . $tableName . '.php'; $fileName = $this->basePath . '/' . $tableName . '.php';
if (!is_file($fileName)) { if (!is_file($fileName)) {
......
...@@ -1039,7 +1039,8 @@ class Request extends \yii\base\Request ...@@ -1039,7 +1039,8 @@ class Request extends \yii\base\Request
if ($this->_maskedCsrfToken === null) { if ($this->_maskedCsrfToken === null) {
$token = $this->getCsrfToken(); $token = $this->getCsrfToken();
$mask = Security::generateRandomKey(self::CSRF_MASK_LENGTH); $mask = Security::generateRandomKey(self::CSRF_MASK_LENGTH);
$this->_maskedCsrfToken = base64_encode($mask . $this->xorTokens($token, $mask)); // The + sign may be decoded as blank space later, which will fail the validation
$this->_maskedCsrfToken = str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));
} }
return $this->_maskedCsrfToken; return $this->_maskedCsrfToken;
} }
...@@ -1120,7 +1121,7 @@ class Request extends \yii\base\Request ...@@ -1120,7 +1121,7 @@ class Request extends \yii\base\Request
private function validateCsrfTokenInternal($token, $trueToken) private function validateCsrfTokenInternal($token, $trueToken)
{ {
$token = base64_decode($token); $token = str_replace('.', '+', base64_decode($token));
$n = StringHelper::byteLength($token); $n = StringHelper::byteLength($token);
if ($n <= self::CSRF_MASK_LENGTH) { if ($n <= self::CSRF_MASK_LENGTH) {
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment