Skip to content

Commit 2cebb1e

Browse files
Merge branch 'develop' into fix/request-refresh-after-uri-normalization
2 parents 7ff3dff + 7822cde commit 2cebb1e

37 files changed

Lines changed: 2100 additions & 103 deletions

‎.github/workflows/verify-release.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
php-version: '8.2'
7777
tools: composer
7878
extensions: intl, gd
79-
coverage: none
79+
coverage: xdebug
8080

8181
- name: Wait for Packagist to serve the new framework version
8282
run: |

‎CHANGELOG.md‎

Lines changed: 154 additions & 0 deletions
Large diffs are not rendered by default.

‎app/Config/View.php‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class View extends BaseView
3030
* { title|esc(js) }
3131
* { created_on|date(Y-m-d)|esc(attr) }
3232
*
33-
* @var array<string, (callable(mixed): mixed)&string>
33+
* @var array<string, callable(mixed): mixed>
3434
*/
3535
public $filters = [];
3636

@@ -43,6 +43,14 @@ class View extends BaseView
4343
*/
4444
public $plugins = [];
4545

46+
/**
47+
* When true, Parser conditionals may only contain variables, literals,
48+
* arithmetic, comparison and logical operators, and parentheses. Enable
49+
* this when less-trusted users can edit Parser templates. Can be overridden per
50+
* call with the `restrictConditionals` render option.
51+
*/
52+
public bool $restrictParserConditionals = false;
53+
4654
/**
4755
* View Decorators are class methods that will be run in sequence to
4856
* have a chance to alter the generated output just prior to caching

‎phpdoc.dist.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<output>api/build/</output>
1111
<cache>api/cache/</cache>
1212
</paths>
13-
<version number="4.7.4">
13+
<version number="4.7.5">
1414
<api format="php">
1515
<source dsn=".">
1616
<path>system</path>

‎system/CodeIgniter.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class CodeIgniter
5555
/**
5656
* The current version of CodeIgniter Framework
5757
*/
58-
public const CI_VERSION = '4.7.5-dev';
58+
public const CI_VERSION = '4.7.6-dev';
5959

6060
/**
6161
* App startup time.

‎system/Config/View.php‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class View extends BaseConfig
3737
*
3838
* @psalm-suppress UndefinedDocblockClass
3939
*
40-
* @var array<string, (callable(mixed): mixed)&string>
40+
* @var array<string, callable(mixed): mixed>
4141
*/
4242
public $filters = [];
4343

@@ -52,6 +52,14 @@ class View extends BaseConfig
5252
*/
5353
public $plugins = [];
5454

55+
/**
56+
* When true, Parser conditionals may only contain variables, literals,
57+
* arithmetic, comparison and logical operators, and parentheses. Enable
58+
* this when less-trusted users can edit Parser templates. Can be overridden per
59+
* call with the `restrictConditionals` render option.
60+
*/
61+
public bool $restrictParserConditionals = false;
62+
5563
/**
5664
* Built-in View filters.
5765
*

‎system/HTTP/CURLRequest.php‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class CURLRequest extends OutgoingRequest
4848
*/
4949
protected $baseURI;
5050

51+
/**
52+
* The constructor's base URI, preserved independently of per-request changes.
53+
*/
54+
private readonly URI $defaultBaseURI;
55+
5156
/**
5257
* The setting values
5358
*
@@ -138,6 +143,7 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
138143

139144
$this->config = $this->defaultConfig;
140145
$this->parseOptions($options);
146+
$this->defaultBaseURI = clone $this->baseURI;
141147

142148
// Share Connection
143149
$optShareConnection = config(ConfigCURLRequest::class)->shareConnectionOptions ?? [ // @phpstan-ignore nullCoalesce.property
@@ -165,16 +171,18 @@ public function request($method, string $url, array $options = []): ResponseInte
165171
{
166172
$this->response = clone $this->responseOrig;
167173

168-
$this->parseOptions($options);
174+
try {
175+
$this->parseOptions($options);
169176

170-
$url = $this->prepareURL($url);
177+
$url = $this->prepareURL($url);
171178

172-
$method = esc(strip_tags($method));
179+
$method = esc(strip_tags($method));
173180

174-
$this->send($method, $url);
175-
176-
if ($this->shareOptions === false) {
177-
$this->resetOptions();
181+
$this->send($method, $url);
182+
} finally {
183+
if ($this->shareOptions === false) {
184+
$this->resetOptions();
185+
}
178186
}
179187

180188
return $this->response;
@@ -197,6 +205,9 @@ protected function resetOptions()
197205
// Reset configs
198206
$this->config = $this->defaultConfig;
199207

208+
$this->baseURI = clone $this->defaultBaseURI;
209+
$this->delay = 0.0;
210+
200211
// Set the default options for next request
201212
$this->parseOptions($this->defaultOptions);
202213
}

‎system/Language/en/View.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
'invalidCellClass' => 'Unable to locate view cell class: "{0}".',
2121
'tagSyntaxError' => 'You have a syntax error in your Parser tags: "{0}"',
2222
'invalidDecoratorClass' => '"{0}" is not a valid View Decorator.',
23+
'restrictedConditional' => 'The Parser conditional is not allowed in restricted mode: "{0}"',
2324
];

‎system/Validation/StrictRules/FileRules.php‎

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function max_size(?string $blank, string $params): bool
100100
}
101101

102102
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
103-
return true;
103+
continue;
104104
}
105105

106106
if ($file->getError() === UPLOAD_ERR_INI_SIZE) {
@@ -135,7 +135,7 @@ public function is_image(?string $blank, string $params): bool
135135
}
136136

137137
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
138-
return true;
138+
continue;
139139
}
140140

141141
// We know that our mimes list always has the first mime
@@ -149,6 +149,10 @@ public function is_image(?string $blank, string $params): bool
149149
if ($this->hasInvalidImageClientExtension($file)) {
150150
return false;
151151
}
152+
153+
if ($this->hasUnsafeClientFilename($file)) {
154+
return false;
155+
}
152156
}
153157

154158
return true;
@@ -173,7 +177,7 @@ public function mime_in(?string $blank, string $params): bool
173177
}
174178

175179
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
176-
return true;
180+
continue;
177181
}
178182

179183
if (! in_array($file->getMimeType(), $params, true)) {
@@ -183,6 +187,10 @@ public function mime_in(?string $blank, string $params): bool
183187
if ($this->hasMismatchedClientExtension($file)) {
184188
return false;
185189
}
190+
191+
if ($this->hasUnsafeClientFilename($file)) {
192+
return false;
193+
}
186194
}
187195

188196
return true;
@@ -207,7 +215,7 @@ public function ext_in(?string $blank, string $params): bool
207215
}
208216

209217
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
210-
return true;
218+
continue;
211219
}
212220

213221
// Check the real filename extension, not only the guessed extension.
@@ -220,6 +228,10 @@ public function ext_in(?string $blank, string $params): bool
220228
if ($file->guessExtension() !== $clientExtension) {
221229
return false;
222230
}
231+
232+
if ($this->hasUnsafeClientFilename($file)) {
233+
return false;
234+
}
223235
}
224236

225237
return true;
@@ -245,7 +257,11 @@ public function max_dims(?string $blank, string $params): bool
245257
}
246258

247259
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
248-
return true;
260+
continue;
261+
}
262+
263+
if ($file->getError() !== UPLOAD_ERR_OK) {
264+
return false;
249265
}
250266

251267
// Get Parameter sizes
@@ -291,7 +307,11 @@ public function min_dims(?string $blank, string $params): bool
291307
}
292308

293309
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
294-
return true;
310+
continue;
311+
}
312+
313+
if ($file->getError() !== UPLOAD_ERR_OK) {
314+
return false;
295315
}
296316

297317
// Get Parameter sizes
@@ -346,4 +366,35 @@ private function hasMismatchedClientExtension(UploadedFile $file): bool
346366

347367
return $file->guessExtension() !== $clientExtension;
348368
}
369+
370+
/**
371+
* Reject trailing-dot names and names with a PHP extension before the final extension.
372+
*/
373+
private function hasUnsafeClientFilename(UploadedFile $file): bool
374+
{
375+
helper('security');
376+
377+
// Check the name that UploadedFile::move() uses when no name is supplied.
378+
$filename = sanitize_filename($file->getClientName());
379+
$parts = explode('.', strtolower(rtrim($filename, ' ')));
380+
381+
if (count($parts) === 1) {
382+
return false;
383+
}
384+
385+
if (array_pop($parts) === '') {
386+
return true;
387+
}
388+
389+
// Some server configurations select a PHP handler from an earlier extension.
390+
array_shift($parts);
391+
392+
foreach ($parts as $part) {
393+
if (preg_match('/^php[0-9]*$/', $part) === 1 || in_array($part, ['pht', 'phtml', 'phar', 'phps'], true)) {
394+
return true;
395+
}
396+
}
397+
398+
return false;
399+
}
349400
}

‎system/View/Cells/Cell.php‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,16 @@ final protected function view(?string $view, array $data = []): string
111111

112112
$foundView = current($candidateViews);
113113

114-
return (function () use ($properties, $foundView): string {
114+
// The parameter is variadic on purpose: func_get_arg() returns the current
115+
// value of a named parameter, which extract() could overwrite with cell data.
116+
return (function (string ...$foundView) use ($properties): string {
117+
$foundView = $foundView[0]; // Keep $foundView available to the view as before.
115118
extract($properties);
116119
ob_start();
117-
include $foundView;
120+
include func_get_arg(0);
118121

119122
return ob_get_clean();
120-
})();
123+
})($foundView);
121124
}
122125

123126
/**

0 commit comments

Comments
 (0)