Skip to content

Commit

Permalink
Merge branch 'master' into without-bc-break
Browse files Browse the repository at this point in the history
  • Loading branch information
chriscpty authored Dec 6, 2024
2 parents a92c9b3 + 65e3369 commit c887d4e
Show file tree
Hide file tree
Showing 21 changed files with 609 additions and 106 deletions.
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@
"bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/inputmask": "^5.0.8 ",
"bower-asset/punycode": "^2.2",
"bower-asset/yii2-pjax": "~2.0.1",
"paragonie/random_compat": ">=1"
"bower-asset/yii2-pjax": "~2.0.1"
},
"require-dev": {
"cebe/indent": "~1.0.2",
Expand Down
52 changes: 1 addition & 51 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

285 changes: 285 additions & 0 deletions docs/guide-uk/runtime-sessions-cookies.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ Yii Framework 2 Change Log
- Enh #20247: Support for variadic console controller action methods (brandonkelly)
- Bug #20256: Add support for dropping views in MSSQL server when running migrate/fresh (ambrozt)
- Enh #20248: Add support for attaching behaviors in configurations with Closure (timkelty)
- Enh #20267: Fixed called class check in `Widget::end()` when widget configured using callable (rob006, jrajamaki)
- Enh #20268: Minor optimisation in `\yii\helpers\BaseArrayHelper::map` (chriscpty)
- Enh #20273: Remove unnecessary `paragonie/random_compat` dependency (timwolla)
- Chg #20276: Removed autogenerated migration phpdoc (userator)
- Bug #20282: Fix compatibility with PHP 8.4: deprecated constant E_STRICT (Izumi-kun)
- Bug #20284: Revert punycode to 1.4.x which supports pre ES6 format (mtangoo)
- New #20279: Add to the `\yii\web\Request` CSRF validation by custom HTTP header (olegbaturin)
- Enh #20279: Add to the `\yii\web\Request` `csrfHeader` property to configure a custom HTTP header for CSRF validation (olegbaturin)
- Enh #20279: Add to the `\yii\web\Request` `csrfTokenSafeMethods` property to configure a custom safe HTTP methods list (olegbaturin)
- Bug #20140: Fix compatibility with PHP 8.4: calling `session_set_save_handler()` (Izumi-kun)
- Enh #20277: Eager loading in `\yii\db\ActiveRecord::refresh` (chriscpty)

2.0.51 July 18, 2024
Expand Down
7 changes: 7 additions & 0 deletions framework/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ if you want to upgrade from version A to version C and there is
version B between A and C, you need to follow the instructions
for both A and B.

Upgrade from Yii 2.0.51
-----------------------

* The function signature for `yii\web\Session::readSession()` and `yii\web\Session::gcSession()` have been changed.
They now have the same return types as `\SessionHandlerInterface::read()` and `\SessionHandlerInterface::gc()` respectively.
In case those methods have overwritten you will need to update your child classes accordingly.

Upgrade from Yii 2.0.50
-----------------------

Expand Down
5 changes: 2 additions & 3 deletions framework/base/ErrorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,14 @@ public function getName()
E_NOTICE => 'PHP Notice',
E_PARSE => 'PHP Parse Error',
E_RECOVERABLE_ERROR => 'PHP Recoverable Error',
E_STRICT => 'PHP Strict Warning',
E_USER_DEPRECATED => 'PHP User Deprecated Warning',
E_USER_ERROR => 'PHP User Error',
E_USER_NOTICE => 'PHP User Notice',
E_USER_WARNING => 'PHP User Warning',
E_WARNING => 'PHP Warning',
self::E_HHVM_FATAL_ERROR => 'HHVM Fatal Error',
];
] + (PHP_VERSION_ID < 80400 ? [E_STRICT => 'PHP Strict Warning'] : []);

return isset($names[$this->getCode()]) ? $names[$this->getCode()] : 'Error';
return $names[$this->getCode()] ?? 'Error';
}
}
10 changes: 6 additions & 4 deletions framework/base/Widget.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class Widget extends Component implements ViewContextInterface
*/
public static $stack = [];

/**
* @var string[] used widget classes that have been resolved to their actual class name.
*/
private static $_resolvedClasses = [];

/**
* Initializes the object.
Expand Down Expand Up @@ -88,6 +92,7 @@ public static function begin($config = [])
/* @var $widget Widget */
$widget = Yii::createObject($config);
self::$stack[] = $widget;
self::$_resolvedClasses[get_called_class()] = get_class($widget);

return $widget;
}
Expand All @@ -104,10 +109,7 @@ public static function end()
if (!empty(self::$stack)) {
$widget = array_pop(self::$stack);

$calledClass = get_called_class();
if (Yii::$container->has($calledClass) && isset(Yii::$container->getDefinitions()[$calledClass]['class'])) {
$calledClass = Yii::$container->getDefinitions()[$calledClass]['class'];
}
$calledClass = self::$_resolvedClasses[get_called_class()] ?? get_called_class();

if (get_class($widget) === $calledClass) {
/* @var $widget Widget */
Expand Down
5 changes: 2 additions & 3 deletions framework/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,8 @@
"cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
"bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/inputmask": "^5.0.8 ",
"bower-asset/punycode": "^2.2",
"bower-asset/yii2-pjax": "~2.0.1",
"paragonie/random_compat": ">=1"
"bower-asset/punycode": "^1.4",
"bower-asset/yii2-pjax": "~2.0.1"
},
"autoload": {
"psr-4": {"yii\\": ""}
Expand Down
2 changes: 1 addition & 1 deletion framework/db/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -1783,7 +1783,7 @@ private function isValueDifferent($newValue, $oldValue)
{
if (is_array($newValue) && is_array($oldValue)) {
// Only sort associative arrays
$sorter = function(&$array) {
$sorter = function (&$array) {
if (ArrayHelper::isAssociative($array)) {
ksort($array);
}
Expand Down
1 change: 0 additions & 1 deletion framework/db/mssql/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -823,5 +823,4 @@ public function createColumnSchemaBuilder($type, $length = null)
{
return Yii::createObject(ColumnSchemaBuilder::className(), [$type, $length, $this->db]);
}

}
3 changes: 0 additions & 3 deletions framework/views/migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@

use yii\db\Migration;

/**
* Class <?= $className . "\n" ?>
*/
class <?= $className ?> extends Migration
{
/**
Expand Down
2 changes: 1 addition & 1 deletion framework/web/CacheSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public function openSession($savePath, $sessionName)
* Session read handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return string the session data
* @return string|false the session data, or false on failure
*/
public function readSession($id)
{
Expand Down
8 changes: 3 additions & 5 deletions framework/web/DbSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public function close()
* Session read handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return string the session data
* @return string|false the session data, or false on failure
*/
public function readSession($id)
{
Expand Down Expand Up @@ -247,15 +247,13 @@ public function destroySession($id)
* Session GC (garbage collection) handler.
* @internal Do not call this method directly.
* @param int $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
* @return bool whether session is GCed successfully
* @return int|false the number of deleted sessions on success, or false on failure
*/
public function gcSession($maxLifetime)
{
$this->db->createCommand()
return $this->db->createCommand()
->delete($this->sessionTable, '[[expire]]<:expire', [':expire' => time()])
->execute();

return true;
}

/**
Expand Down
55 changes: 48 additions & 7 deletions framework/web/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* not available.
* @property-read CookieCollection $cookies The cookie collection.
* @property-read string $csrfToken The token used to perform CSRF validation.
* @property-read string|null $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is
* @property-read string|null $csrfTokenFromHeader The CSRF token sent via [[csrfHeader]] by browser. Null is
* returned if no such header is sent.
* @property-read array $eTags The entity tags.
* @property-read HeaderCollection $headers The header collection.
Expand Down Expand Up @@ -91,7 +91,7 @@
class Request extends \yii\base\Request
{
/**
* The name of the HTTP header for sending CSRF token.
* Default name of the HTTP header for sending CSRF token.
*/
const CSRF_HEADER = 'X-CSRF-Token';
/**
Expand All @@ -113,10 +113,41 @@ class Request extends \yii\base\Request
* `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered.
* You also need to include CSRF meta tags in your pages by using [[\yii\helpers\Html::csrfMetaTags()]].
*
* For SPA, you can use CSRF validation by custom header with a random or an empty value.
* Include a header with the name specified by [[csrfHeader]] to requests that must be validated.
* Warning! CSRF validation by custom header can be used only for same-origin requests or
* with CORS configured to allow requests from the list of specific origins only.
*
* @see Controller::enableCsrfValidation
* @see https://en.wikipedia.org/wiki/Cross-site_request_forgery
*/
public $enableCsrfValidation = true;
/**
* @var string the name of the HTTP header for sending CSRF token. Defaults to [[CSRF_HEADER]].
* This property may be changed for Yii API applications only.
* Don't change this property for Yii Web application.
*/
public $csrfHeader = self::CSRF_HEADER;
/**
* @var array the name of the HTTP header for sending CSRF token.
* by default validate CSRF token on non-"safe" methods only
* This property is used only when [[enableCsrfValidation]] is true.
* @see https://datatracker.ietf.org/doc/html/rfc9110#name-safe-methods
*/
public $csrfTokenSafeMethods = ['GET', 'HEAD', 'OPTIONS'];
/**
* @var array "unsafe" methods not triggered a CORS-preflight request
* This property is used only when both [[enableCsrfValidation]] and [[validateCsrfHeaderOnly]] are true.
* @see https://fetch.spec.whatwg.org/#http-cors-protocol
*/
public $csrfHeaderUnsafeMethods = ['GET', 'HEAD', 'POST'];
/**
* @var bool whether to use custom header only to CSRF validation of SPA. Defaults to false.
* If false and [[enableCsrfValidation]] is true, CSRF validation by token will used.
* Warning! CSRF validation by custom header can be used for Yii API applications only.
* @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#employing-custom-request-headers-for-ajaxapi
*/
public $validateCsrfHeaderOnly = false;
/**
* @var string the name of the token used to prevent CSRF. Defaults to '_csrf'.
* This property is used only when [[enableCsrfValidation]] is true.
Expand Down Expand Up @@ -1772,10 +1803,14 @@ protected function loadCookies()
* along via a hidden field of an HTML form or an HTTP header value to support CSRF validation.
* @param bool $regenerate whether to regenerate CSRF token. When this parameter is true, each time
* this method is called, a new CSRF token will be generated and persisted (in session or cookie).
* @return string the token used to perform CSRF validation.
* @return null|string the token used to perform CSRF validation. Null is returned if the [[validateCsrfHeaderOnly]] is true.
*/
public function getCsrfToken($regenerate = false)
{
if ($this->validateCsrfHeaderOnly) {
return null;
}

if ($this->_csrfToken === null || $regenerate) {
$token = $this->loadCsrfToken();
if ($regenerate || empty($token)) {
Expand Down Expand Up @@ -1819,11 +1854,11 @@ protected function generateCsrfToken()
}

/**
* @return string|null the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent.
* @return string|null the CSRF token sent via [[csrfHeader]] by browser. Null is returned if no such header is sent.
*/
public function getCsrfTokenFromHeader()
{
return $this->headers->get(static::CSRF_HEADER);
return $this->headers->get($this->csrfHeader);
}

/**
Expand Down Expand Up @@ -1860,8 +1895,14 @@ protected function createCsrfCookie($token)
public function validateCsrfToken($clientSuppliedToken = null)
{
$method = $this->getMethod();
// only validate CSRF token on non-"safe" methods https://tools.ietf.org/html/rfc2616#section-9.1.1
if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {

if ($this->validateCsrfHeaderOnly) {
return in_array($method, $this->csrfHeaderUnsafeMethods, true)
? $this->headers->has($this->csrfHeader)
: true;
}

if (!$this->enableCsrfValidation || in_array($method, $this->csrfTokenSafeMethods, true)) {
return true;
}

Expand Down
Loading

0 comments on commit c887d4e

Please sign in to comment.