Skip to content

Commit 3e96fae

Browse files
fix(HTTP): keep $_REQUEST in sync with rewritten GET in SiteURIFactory
getVar() and validation read from $_REQUEST rather than $_GET. When the query string is rewritten by detectRoutePath() (e.g. /index.php?/ci/woot?code=good), the corrected GET values were only written to $_GET, leaving $_REQUEST stale, so getVar('code') returned the unset value. Both parseRequestURI() and parseQueryString() now mirror the parsed GET values into $_REQUEST so getVar()/validation see the corrected data.
1 parent 744e717 commit 3e96fae

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

system/HTTP/SiteURIFactory.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ private function parseRequestURI(): string
173173
parse_str($this->superglobals->server('QUERY_STRING'), $get);
174174
$this->superglobals->setGetArray($get);
175175

176+
// Keep $_REQUEST in sync with the parsed GET values, as getVar() and
177+
// validation read from $_REQUEST rather than $_GET.
178+
$this->syncRequestWithGet($get);
179+
176180
return URI::removeDotSegments($path);
177181
}
178182

@@ -205,9 +209,37 @@ private function parseQueryString(): string
205209
parse_str($this->superglobals->server('QUERY_STRING'), $get);
206210
$this->superglobals->setGetArray($get);
207211

212+
// Keep $_REQUEST in sync with the parsed GET values, as getVar() and
213+
// validation read from $_REQUEST rather than $_GET.
214+
$this->syncRequestWithGet($get);
215+
208216
return URI::removeDotSegments($path);
209217
}
210218

219+
/**
220+
* Keep $_REQUEST in sync with the latest parsed GET values.
221+
*
222+
* `getVar()` and validation read from $_REQUEST rather than $_GET, so when
223+
* the query string is rewritten here (e.g. `/index.php?/ci/woot?code=good#pos`),
224+
* the GET-originated keys must be reflected in $_REQUEST too. Otherwise
225+
* `getVar('code')` returns the stale or unset value.
226+
*
227+
* Only GET-originated keys are updated; values from POST, COOKIE and other
228+
* sources are left untouched.
229+
*
230+
* @param array<array-key, array|bool|float|int|string|null> $get The parsed GET values
231+
*/
232+
private function syncRequestWithGet(array $get): void
233+
{
234+
$request = $this->superglobals->getRequestArray();
235+
236+
foreach ($get as $key => $value) {
237+
$request[$key] = $value;
238+
}
239+
240+
$this->superglobals->setRequestArray($request);
241+
}
242+
211243
/**
212244
* Create current URI object.
213245
*

tests/system/HTTP/SiteURIFactoryDetectRoutePathTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,25 @@ public function testQueryStringWithQueryString(): void
258258
$this->assertSame(['code' => 'good'], $_GET);
259259
}
260260

261+
public function testQueryStringKeepsRequestInSyncWithGet(): void
262+
{
263+
// /index.php?/ci/woot?code=good#pos
264+
service('superglobals')
265+
->setServer('REQUEST_URI', '/index.php?/ci/woot?code=good')
266+
->setServer('QUERY_STRING', '/ci/woot?code=good')
267+
->setServer('SCRIPT_NAME', '/index.php')
268+
->setGet('/ci/woot?code', 'good');
269+
270+
$factory = $this->createSiteURIFactory(service('superglobals')->getServerArray());
271+
272+
$expected = 'ci/woot';
273+
$this->assertSame($expected, $factory->detectRoutePath('QUERY_STRING'));
274+
275+
// getVar() reads from $_REQUEST, so the corrected GET value must be
276+
// reflected there too, not just in $_GET.
277+
$this->assertSame(['code' => 'good'], $_REQUEST); // @phpstan-ignore codeigniter.superglobalsOffsetAccess (checks the live superglobal written by the factory)
278+
}
279+
261280
public function testQueryStringEmpty(): void
262281
{
263282
// /index.php?

0 commit comments

Comments
 (0)