@@ -463,6 +463,40 @@ static public function isProxyTrusted()
463463 return self ::$ trustProxy ;
464464 }
465465
466+ /**
467+ * Normalizes a query string.
468+ *
469+ * It builds a normalized query string, where keys/value pairs are alphabetized
470+ * and have consistent escaping.
471+ *
472+ * @param string $qs Query string
473+ *
474+ * @return string|null A normalized query string for the Request
475+ */
476+ static public function normalizeQueryString ($ qs = null )
477+ {
478+ if (!$ qs ) {
479+ return null ;
480+ }
481+
482+ $ parts = array ();
483+ $ order = array ();
484+
485+ foreach (explode ('& ' , $ qs ) as $ segment ) {
486+ if (false === strpos ($ segment , '= ' )) {
487+ $ parts [] = $ segment ;
488+ $ order [] = $ segment ;
489+ } else {
490+ $ tmp = explode ('= ' , rawurldecode ($ segment ), 2 );
491+ $ parts [] = rawurlencode ($ tmp [0 ]).'= ' .rawurlencode ($ tmp [1 ]);
492+ $ order [] = $ tmp [0 ];
493+ }
494+ }
495+ array_multisort ($ order , SORT_ASC , $ parts );
496+
497+ return implode ('& ' , $ parts );
498+ }
499+
466500 /**
467501 * Gets a "parameter" value.
468502 *
@@ -809,26 +843,7 @@ public function getUriForPath($path)
809843 */
810844 public function getQueryString ()
811845 {
812- if (!$ qs = $ this ->server ->get ('QUERY_STRING ' )) {
813- return null ;
814- }
815-
816- $ parts = array ();
817- $ order = array ();
818-
819- foreach (explode ('& ' , $ qs ) as $ segment ) {
820- if (false === strpos ($ segment , '= ' )) {
821- $ parts [] = $ segment ;
822- $ order [] = $ segment ;
823- } else {
824- $ tmp = explode ('= ' , rawurldecode ($ segment ), 2 );
825- $ parts [] = rawurlencode ($ tmp [0 ]).'= ' .rawurlencode ($ tmp [1 ]);
826- $ order [] = $ tmp [0 ];
827- }
828- }
829- array_multisort ($ order , SORT_ASC , $ parts );
830-
831- return implode ('& ' , $ parts );
846+ return static ::normalizeQueryString ($ this ->server ->get ('QUERY_STRING ' ));
832847 }
833848
834849 /**
0 commit comments