From 2dddec6783a786c9365e9881549a7d5e6fc71489 Mon Sep 17 00:00:00 2001 From: jalexiscv Date: Sun, 17 May 2026 21:27:21 -0500 Subject: [PATCH] fix: sync $_REQUEST after modifying $_GET in SiteURIFactory Fixes #9872 When SiteURIFactory modifies $_GET via setGetArray(), it does not update $_REQUEST. Since IncomingRequest::getVar() reads from $_REQUEST (via fetchGlobal('request')), validation with $validator->withRequest() receives stale data. Changes: - Add Superglobals::syncRequest() method that rebuilds $_REQUEST from $_GET, $_POST, and $_COOKIE respecting PHP's request_order - Call syncRequest() in SiteURIFactory after each setGetArray() call Ref: https://github.com/codeigniter4/CodeIgniter4/issues/9872 --- system/HTTP/SiteURIFactory.php | 6 ++++++ system/Superglobals.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/system/HTTP/SiteURIFactory.php b/system/HTTP/SiteURIFactory.php index 73cc9fe84ee4..ceabfbf27346 100644 --- a/system/HTTP/SiteURIFactory.php +++ b/system/HTTP/SiteURIFactory.php @@ -173,6 +173,9 @@ private function parseRequestURI(): string parse_str($this->superglobals->server('QUERY_STRING'), $get); $this->superglobals->setGetArray($get); + // Sync $_REQUEST so that getVar() works correctly + $this->superglobals->syncRequest(); + return URI::removeDotSegments($path); } @@ -205,6 +208,9 @@ private function parseQueryString(): string parse_str($this->superglobals->server('QUERY_STRING'), $get); $this->superglobals->setGetArray($get); + // Sync $_REQUEST so that getVar() works correctly + $this->superglobals->syncRequest(); + return URI::removeDotSegments($path); } diff --git a/system/Superglobals.php b/system/Superglobals.php index 2175728e862e..31557ded5c42 100644 --- a/system/Superglobals.php +++ b/system/Superglobals.php @@ -456,4 +456,34 @@ public function setGlobalArray(string $name, array $array): void ), }; } + + /** + * Rebuilds $_REQUEST from $_GET, $_POST, and $_COOKIE according to PHP's + * request_order / variables_order ini setting. + * + * This is necessary when superglobals like $_GET are modified after the + * initial request population, since PHP does not automatically keep + * $_REQUEST in sync. + * + * @see https://www.php.net/manual/en/ini.core.php#ini.request-order + */ + public function syncRequest(): self + { + $requestOrder = ini_get('request_order') ?: ini_get('variables_order'); + + $this->request = []; + + foreach (str_split($requestOrder) as $type) { + match ($type) { + 'G' => $this->request = array_replace($this->request, $this->get), + 'P' => $this->request = array_replace($this->request, $this->post), + 'C' => $this->request = array_replace($this->request, $this->cookie), + default => null, + }; + } + + $_REQUEST = $this->request; + + return $this; + } }