Skip to content

Commit c53e361

Browse files
committed
Close the PHP session before making HTTP requests
Resolves #15643
1 parent 48d0bb5 commit c53e361

File tree

6 files changed

+48
-18
lines changed

6 files changed

+48
-18
lines changed

CHANGELOG-WIP.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
- Added `craft\base\ApplicationTrait::getEnvId()`. ([#15313](https://github.com/craftcms/cms/issues/15313))
1111
- Added `craft\base\ElementInterface::getRootOwner()`. ([#15534](https://github.com/craftcms/cms/discussions/15534))
1212
- Added `craft\elements\conditions\SiteGroupConditionRule`.
13+
- Added `craft\helpers\Session::close()`.
1314
- Added `craft\services\Sites::getEditableSitesByGroupId()`.
15+
- `craft\helpers\Session` methods are now safe to call on console requests.
1416
- Deprecated `craft\helpers\ElementHelper::rootElement()`. `craft\base\ElementInterface::getRootOwner()` should be used instead.
1517
- Deprecated `craft\db\mysql\Schema::quoteDatabaseName()`.
1618
- Deprecated `craft\db\pgqsl\Schema::quoteDatabaseName()`.
@@ -19,4 +21,5 @@
1921
- MySQL mutex locks and PHP session names are now namespaced using the application ID combined with the environment name. ([#15313](https://github.com/craftcms/cms/issues/15313))
2022
- `x-craft-preview` and `x-craft-live-preview` params are now hashed, and `craft\web\Request::getIsPreview()` will only return `true` if the param validates. ([#15605](https://github.com/craftcms/cms/discussions/15605))
2123
- Generated URLs no longer include `x-craft-preview` or `x-craft-live-preview` query string params based on the requested URL, if either were set to an unverified string. ([#15605](https://github.com/craftcms/cms/discussions/15605))
24+
- The PHP session is now closed before making API requests. ([#15643](https://github.com/craftcms/cms/issues/15643))
2225
- Updated Twig to 3.12. ([#15568](https://github.com/craftcms/cms/discussions/15568))

src/controllers/AppController.php

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use craft\helpers\DateTimeHelper;
2222
use craft\helpers\Html;
2323
use craft\helpers\Json;
24+
use craft\helpers\Session;
2425
use craft\helpers\Update as UpdateHelper;
2526
use craft\helpers\UrlHelper;
2627
use craft\models\Update;
@@ -96,6 +97,9 @@ public function actionResourceJs(string $url): Response
9697
throw new BadRequestHttpException("$url does not appear to be a resource URL");
9798
}
9899

100+
// Close the PHP session in case this takes a while
101+
Session::close();
102+
99103
$response = Craft::createGuzzleClient()->get($url);
100104
$this->response->setCacheHeaders();
101105
$this->response->getHeaders()->set('content-type', 'application/javascript');

src/helpers/Session.php

+31-17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace craft\helpers;
99

1010
use Craft;
11+
use craft\errors\MissingComponentException;
1112
use yii\web\Session as YiiSession;
1213

1314
/**
@@ -18,6 +19,16 @@
1819
*/
1920
class Session
2021
{
22+
/**
23+
* @see session()
24+
*/
25+
private static YiiSession|false|null $_session;
26+
27+
/**
28+
* @see exists()
29+
*/
30+
private static bool $_exists = false;
31+
2132
/**
2233
* Returns the session variable value with the session variable name.
2334
*
@@ -42,7 +53,7 @@ public static function get(string $key): mixed
4253
*/
4354
public static function set(string $key, mixed $value): void
4455
{
45-
self::session()->set($key, $value);
56+
self::session()?->set($key, $value);
4657
}
4758

4859
/**
@@ -61,7 +72,6 @@ public static function remove(string $key): mixed
6172

6273
/**
6374
* Removes all session variables.
64-
*
6575
*/
6676
public static function removeAll(): void
6777
{
@@ -85,13 +95,27 @@ public static function has(string $key): bool
8595
return self::session()->has($key);
8696
}
8797

88-
8998
/**
90-
* @return YiiSession
99+
* Closes the session, if open.
100+
*
101+
* @since 4.12.0
91102
*/
92-
private static function session(): YiiSession
103+
public static function close(): void
104+
{
105+
self::session()?->close();
106+
}
107+
108+
private static function session(): ?YiiSession
93109
{
94-
return self::$_session ?? (self::$_session = Craft::$app->getSession());
110+
if (!isset(self::$_session)) {
111+
try {
112+
self::$_session = Craft::$app->getSession();
113+
} catch (MissingComponentException) {
114+
self::$_session = false;
115+
}
116+
}
117+
118+
return self::$_session ?: null;
95119
}
96120

97121
/**
@@ -106,19 +130,9 @@ public static function exists(): bool
106130
}
107131

108132
// Keep re-checking until it does
109-
return self::$_exists = self::session()->getIsActive() || self::session()->getHasSessionId();
133+
return self::$_exists = self::session()?->getIsActive() || self::session()?->getHasSessionId();
110134
}
111135

112-
/**
113-
* @var YiiSession|null
114-
*/
115-
private static ?YiiSession $_session = null;
116-
117-
/**
118-
* @var bool
119-
*/
120-
private static bool $_exists = false;
121-
122136
/**
123137
* Resets the memoized database connection.
124138
*

src/services/Api.php

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use craft\helpers\Api as ApiHelper;
1212
use craft\helpers\ArrayHelper;
1313
use craft\helpers\Json;
14+
use craft\helpers\Session;
1415
use GuzzleHttp\Client;
1516
use GuzzleHttp\Exception\RequestException;
1617
use GuzzleHttp\RequestOptions;
@@ -118,6 +119,9 @@ public function getCountries(): array
118119
*/
119120
public function request(string $method, string $uri, array $options = []): ResponseInterface
120121
{
122+
// Close the PHP session in case this takes a while
123+
Session::close();
124+
121125
$options = ArrayHelper::merge($options, [
122126
'headers' => ApiHelper::headers(),
123127
]);

src/services/Webpack.php

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use craft\helpers\App;
1212
use craft\helpers\ArrayHelper;
1313
use craft\helpers\FileHelper;
14+
use craft\helpers\Session;
1415
use craft\helpers\StringHelper;
1516
use Exception;
1617
use GuzzleHttp\Exception\GuzzleException;
@@ -214,6 +215,9 @@ private function _isDevServerRunning(string $class, string $loopback): bool
214215
return $this->_isDevServerRunning[$class] = $this->_matchAsset($this->_serverResponse[$loopback], $class);
215216
}
216217

218+
// Close the PHP session in case this takes a while
219+
Session::close();
220+
217221
// Make sure the request isn't too strict for people running the dev server using https and outside the container
218222
$client = Craft::createGuzzleClient(['verify' => false]);
219223
try {

src/web/Response.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Craft;
1111
use craft\helpers\ArrayHelper;
12+
use craft\helpers\Session;
1213
use craft\helpers\UrlHelper;
1314
use Throwable;
1415
use yii\base\Application as BaseApplication;
@@ -305,7 +306,7 @@ public function sendAndClose(): void
305306
$this->send();
306307

307308
// Close the session.
308-
Craft::$app->getSession()->close();
309+
Session::close();
309310

310311
// In case we're running on php-fpm (https://secure.php.net/manual/en/book.fpm.php)
311312
if (function_exists('fastcgi_finish_request')) {

0 commit comments

Comments
 (0)