@@ -56,12 +56,26 @@ class IncomingRequest extends Request
56
56
protected $ enableCSRF = false ;
57
57
58
58
/**
59
- * A \CodeIgniter\HTTP\URI instance.
59
+ * The URI representing the current URL for this request.
60
+ *
61
+ * Note: When this is returned as a shared instance via
62
+ * Services::request() this property points to the shared
63
+ * URI service and represents the primary "current URL"
64
+ * for the main app.
65
+ *
66
+ * @see CodeIgniter\CodeIgniter::getRequestObject()
60
67
*
61
68
* @var URI
62
69
*/
63
70
public $ uri ;
64
71
72
+ /**
73
+ * The detected path (relative to SCRIPT_NAME).
74
+ *
75
+ * @var string|null
76
+ */
77
+ protected $ path ;
78
+
65
79
/**
66
80
* File collection
67
81
*
@@ -142,31 +156,16 @@ public function __construct($config, URI $uri = null, $body = 'php://input', Use
142
156
$ body = file_get_contents ('php://input ' );
143
157
}
144
158
145
- $ this ->body = ! empty ($ body ) ? $ body : null ;
146
- $ this ->config = $ config ;
147
- $ this ->userAgent = $ userAgent ;
159
+ $ this ->config = $ config ;
160
+ $ this ->uri = $ uri ;
161
+ $ this ->body = ! empty ($ body ) ? $ body : null ;
162
+ $ this ->userAgent = $ userAgent ;
163
+ $ this ->validLocales = $ config ->supportedLocales ;
148
164
149
165
parent ::__construct ($ config );
150
166
151
167
$ this ->populateHeaders ();
152
-
153
- // Determine the current URI
154
- // NOTE: This WILL NOT match the actual URL in the browser since for
155
- // everything this cares about (and the router, etc) is the portion
156
- // AFTER the script name. So, if hosted in a sub-folder this will
157
- // appear different than actual URL. If you need that, use current_url().
158
- $ this ->uri = $ uri ;
159
-
160
- $ this ->detectURI ($ config ->uriProtocol , $ config ->baseURL );
161
-
162
- // Check if the baseURL scheme needs to be coerced into its secure version
163
- if ($ config ->forceGlobalSecureRequests && $ this ->uri ->getScheme () === 'http ' )
164
- {
165
- $ this ->uri ->setScheme ('https ' );
166
- }
167
-
168
- $ this ->validLocales = $ config ->supportedLocales ;
169
-
168
+ $ this ->detectURL ();
170
169
$ this ->detectLocale ($ config );
171
170
}
172
171
@@ -603,13 +602,67 @@ public function getFile(string $fileID)
603
602
604
603
//--------------------------------------------------------------------
605
604
605
+ /**
606
+ * Sets the components of the underlying URI instance to
607
+ * match the current URL as configured and detected.
608
+ */
609
+ protected function detectURL ()
610
+ {
611
+ // Require a baseURL for non-CLI requests
612
+ if ($ this ->config ->baseURL === '' )
613
+ {
614
+ if (is_cli ())
615
+ {
616
+ $ this ->uri ->setPath ($ this ->getPath ());
617
+ return ;
618
+ }
619
+
620
+ die ('You have an empty or invalid base URL. The baseURL value must be set in Config\App.php, or through the .env file. ' ); // @codeCoverageIgnore
621
+ }
622
+
623
+ // Build the full URL based on the config and relative path
624
+ $ path = $ this ->getPath ();
625
+ $ url = rtrim ($ this ->config ->baseURL , '/ ' ) . '/ ' ;
626
+
627
+ // Check for an index page
628
+ if ($ this ->config ->indexPage !== '' )
629
+ {
630
+ $ url .= $ this ->config ->indexPage ;
631
+
632
+ // If the path has anything other than ? (for query) we need a separator
633
+ if ($ path !== '' && strncmp ($ path , '? ' , 1 ) !== 0 )
634
+ {
635
+ $ url .= '/ ' ;
636
+ }
637
+ }
638
+
639
+ $ url .= $ path ;
640
+
641
+ $ this ->uri ->setURI ($ url );
642
+
643
+ // Check if the baseURL scheme needs to be coerced into its secure version
644
+ if ($ this ->config ->forceGlobalSecureRequests && $ this ->uri ->getScheme () === 'http ' )
645
+ {
646
+ $ this ->uri ->setScheme ('https ' );
647
+ }
648
+
649
+ // Set any remaining query vars
650
+ if (isset ($ _SERVER ['QUERY_STRING ' ]))
651
+ {
652
+ $ this ->uri ->setQuery ($ _SERVER ['QUERY_STRING ' ]);
653
+ }
654
+ }
655
+
606
656
/**
607
657
* Sets up our URI object based on the information we have. This is
608
658
* either provided by the user in the baseURL Config setting, or
609
659
* determined from the environment as needed.
610
660
*
611
661
* @param string $protocol
612
662
* @param string $baseURL
663
+ *
664
+ * @deprecated Use detectCurrentURI() instead
665
+ * @codeCoverageIgnore
613
666
*/
614
667
protected function detectURI (string $ protocol , string $ baseURL )
615
668
{
@@ -632,20 +685,34 @@ protected function detectURI(string $protocol, string $baseURL)
632
685
}
633
686
else
634
687
{
635
- // @codeCoverageIgnoreStart
636
688
if (! is_cli ())
637
689
{
638
690
die ('You have an empty or invalid base URL. The baseURL value must be set in Config\App.php, or through the .env file. ' );
639
691
}
640
- // @codeCoverageIgnoreEnd
641
692
}
642
693
}
643
694
644
695
//--------------------------------------------------------------------
645
696
646
697
/**
647
- * Based on the URIProtocol Config setting, will attempt to
648
- * detect the path portion of the current URI.
698
+ * Returns the path relative to SCRIPT_NAME,
699
+ * running detection as necessary.
700
+ *
701
+ * @return string
702
+ */
703
+ public function getPath (): string
704
+ {
705
+ if (is_null ($ this ->path ))
706
+ {
707
+ $ this ->detectPath ($ this ->config ->uriProtocol );
708
+ }
709
+
710
+ return $ this ->path ;
711
+ }
712
+
713
+ /**
714
+ * Detects the relative path based on
715
+ * the URIProtocol Config setting.
649
716
*
650
717
* @param string $protocol
651
718
*
@@ -661,18 +728,18 @@ public function detectPath(string $protocol = ''): string
661
728
switch ($ protocol )
662
729
{
663
730
case 'REQUEST_URI ' :
664
- $ path = $ this ->parseRequestURI ();
731
+ $ this -> path = $ this ->parseRequestURI ();
665
732
break ;
666
733
case 'QUERY_STRING ' :
667
- $ path = $ this ->parseQueryString ();
734
+ $ this -> path = $ this ->parseQueryString ();
668
735
break ;
669
736
case 'PATH_INFO ' :
670
737
default :
671
- $ path = $ this ->fetchGlobal ('server ' , $ protocol ) ?? $ this ->parseRequestURI ();
738
+ $ this -> path = $ this ->fetchGlobal ('server ' , $ protocol ) ?? $ this ->parseRequestURI ();
672
739
break ;
673
740
}
674
741
675
- return $ path ;
742
+ return $ this -> path ;
676
743
}
677
744
678
745
//--------------------------------------------------------------------
@@ -731,23 +798,23 @@ protected function parseRequestURI(): string
731
798
$ query = $ parts ['query ' ] ?? '' ;
732
799
$ uri = $ parts ['path ' ] ?? '' ;
733
800
734
- if (isset ($ _SERVER ['SCRIPT_NAME ' ][0 ]) && pathinfo ($ _SERVER ['SCRIPT_NAME ' ], PATHINFO_EXTENSION ) === 'php ' )
801
+ // Strip the SCRIPT_NAME path from the URI
802
+ if ($ uri !== '' && isset ($ _SERVER ['SCRIPT_NAME ' ][0 ]) && pathinfo ($ _SERVER ['SCRIPT_NAME ' ], PATHINFO_EXTENSION ) === 'php ' )
735
803
{
736
- // strip the script name from the beginning of the URI
737
- if (strpos ($ uri , $ _SERVER ['SCRIPT_NAME ' ]) === 0 && strpos ($ uri , '/index.php ' ) === 0 )
804
+ // Compare each segment, dropping them until there is no match
805
+ $ segments = $ keep = explode ('/ ' , $ uri );
806
+ foreach (explode ('/ ' , $ _SERVER ['SCRIPT_NAME ' ]) as $ i => $ segment )
738
807
{
739
- $ uri = (string ) substr ($ uri , strlen ($ _SERVER ['SCRIPT_NAME ' ]));
740
- }
741
- // if the script is nested, strip the parent folder & script from the URI
742
- elseif (strpos ($ uri , $ _SERVER ['SCRIPT_NAME ' ]) > 0 )
743
- {
744
- $ uri = (string ) substr ($ uri , strpos ($ uri , $ _SERVER ['SCRIPT_NAME ' ]) + strlen ($ _SERVER ['SCRIPT_NAME ' ]));
745
- }
746
- // or if index.php is implied
747
- elseif (strpos ($ uri , dirname ($ _SERVER ['SCRIPT_NAME ' ])) === 0 )
748
- {
749
- $ uri = (string ) substr ($ uri , strlen (dirname ($ _SERVER ['SCRIPT_NAME ' ])));
808
+ // If these segments are not the same then we're done
809
+ if ($ segment !== $ segments [$ i ])
810
+ {
811
+ break ;
812
+ }
813
+
814
+ array_shift ($ keep );
750
815
}
816
+
817
+ $ uri = implode ('/ ' , $ keep );
751
818
}
752
819
753
820
// This section ensures that even on servers that require the URI to contain the query string (Nginx) a correct
0 commit comments