99 * file that was distributed with this source code.
1010 */
1111
12+ use CodeIgniter \HTTP \IncomingRequest ;
1213use CodeIgniter \HTTP \URI ;
1314use CodeIgniter \Router \Exceptions \RouterException ;
1415use Config \App ;
1819 * CodeIgniter URL Helpers
1920 */
2021
21- if (! function_exists ('site_url ' ))
22+ if (! function_exists ('_get_uri ' ))
2223{
2324 /**
24- * Return a site URL to use in views
25+ * Used by the other URL functions to build a
26+ * framework-specific URI based on the App config.
2527 *
26- * @param mixed $uri URI string or array of URI segments
27- * @param string|null $protocol
28- * @param App|null $altConfig Alternate configuration to use
28+ * @internal Outside of the framework this should not be used directly.
2929 *
30- * @return string
30+ * @param string $relativePath May include queries or fragments
31+ * @param App|null $config
32+ *
33+ * @return URI
34+ *
35+ * @throws InvalidArgumentException For invalid paths or config
3136 */
32- function site_url ( $ uri = '' , string $ protocol = null , App $ altConfig = null ): string
37+ function _get_uri ( string $ relativePath = '' , App $ config = null ): URI
3338 {
34- // convert segment array to string
35- if (is_array ($ uri ))
39+ $ config = $ config ?? config ('App ' );
40+
41+ if ($ config ->baseURL === '' )
3642 {
37- $ uri = implode ('/ ' , $ uri );
43+ throw new InvalidArgumentException ('_get_uri() requires a valid baseURL. ' );
44+ }
45+ if (is_int (strpos ($ relativePath , ':// ' )))
46+ {
47+ throw new InvalidArgumentException ('_get_uri() only accepts relative paths. ' );
3848 }
3949
40- // use alternate config if provided, else default one
41- $ config = $ altConfig ?? config (App::class);
50+ $ relativePath = URI ::removeDotSegments ($ relativePath );
4251
43- $ fullPath = rtrim (base_url (), '/ ' ) . '/ ' ;
52+ // Build the full URL based on $config and $relativePath
53+ $ url = rtrim ($ config ->baseURL , '/ ' ) . '/ ' ;
4454
45- // Add index page, if so configured
46- if (! empty ($ config ->indexPage ))
47- {
48- $ fullPath .= rtrim ($ config ->indexPage , '/ ' );
49- }
50- if ($ uri !== '' )
55+ // Check for an index page
56+ if ($ config ->indexPage !== '' )
5157 {
52- $ fullPath .= '/ ' . $ uri ;
58+ $ url .= $ config ->indexPage ;
59+
60+ // Check if we need a separator
61+ if ($ relativePath !== '' && $ relativePath [0 ] !== '/ ' && $ relativePath [0 ] !== '? ' )
62+ {
63+ $ url .= '/ ' ;
64+ }
5365 }
5466
55- $ url = new URI ( $ fullPath ) ;
67+ $ url .= $ relativePath ;
5668
57- // allow the scheme to be over-ridden; else, use default
58- if (! empty ($ protocol ))
69+ $ uri = new URI ($ url );
70+
71+ // Check if the baseURL scheme needs to be coerced into its secure version
72+ if ($ config ->forceGlobalSecureRequests && $ uri ->getScheme () === 'http ' )
5973 {
60- $ url ->setScheme ($ protocol );
74+ $ uri ->setScheme (' https ' );
6175 }
6276
63- return ( string ) $ url ;
77+ return $ uri ;
6478 }
6579}
6680
6781//--------------------------------------------------------------------
6882
69- if (! function_exists ('base_url ' ))
83+ if (! function_exists ('site_url ' ))
7084{
7185 /**
72- * Return the base URL to use in views
86+ * Returns a site URL as defined by the App config.
87+ *
88+ * @param mixed $relativePath URI string or array of URI segments
89+ * @param string|null $scheme
90+ * @param App|null $config Alternate configuration to use
7391 *
74- * @param mixed $uri URI string or array of URI segments
75- * @param string $protocol
7692 * @return string
7793 */
78- function base_url ( $ uri = '' , string $ protocol = null ): string
94+ function site_url ( $ relativePath = '' , string $ scheme = null , App $ config = null ): string
7995 {
80- // convert segment array to string
81- if (is_array ($ uri ))
96+ // Convert array of segments to a string
97+ if (is_array ($ relativePath ))
8298 {
83- $ uri = implode ('/ ' , $ uri );
99+ $ relativePath = implode ('/ ' , $ relativePath );
84100 }
85- $ uri = trim ($ uri , '/ ' );
86-
87- // We should be using the configured baseURL that the user set;
88- // otherwise get rid of the path, because we have
89- // no way of knowing the intent...
90- $ config = Services::request ()->config ;
91-
92- // If baseUrl does not have a trailing slash it won't resolve
93- // correctly for users hosting in a subfolder.
94- $ baseUrl = ! empty ($ config ->baseURL ) && $ config ->baseURL !== '/ '
95- ? rtrim ($ config ->baseURL , '/ ' ) . '/ '
96- : $ config ->baseURL ;
97101
98- $ url = new URI ($ baseUrl );
99- unset($ config );
102+ $ uri = _get_uri ($ relativePath , $ config );
100103
101- // Merge in the path set by the user, if any
102- if ($ uri !== '' )
103- {
104- $ url = $ url ->resolveRelativeURI ($ uri );
105- }
104+ return URI ::createURIString ($ scheme ?? $ uri ->getScheme (), $ uri ->getAuthority (), $ uri ->getPath (), $ uri ->getQuery (), $ uri ->getFragment ());
105+ }
106+ }
106107
107- // If the scheme wasn't provided, check to
108- // see if it was a secure request
109- if (empty ($ protocol ) && Services::request ()->isSecure ())
110- {
111- $ protocol = 'https ' ;
112- }
108+ //--------------------------------------------------------------------
113109
114- if (! empty ($ protocol ))
115- {
116- $ url ->setScheme ($ protocol );
117- }
110+ if (! function_exists ('base_url ' ))
111+ {
112+ /**
113+ * Returns the base URL as defined by the App config.
114+ * Base URLs are trimmed site URLs without the index page.
115+ *
116+ * @param mixed $relativePath URI string or array of URI segments
117+ * @param string $scheme
118+ * @return string
119+ */
120+ function base_url ($ relativePath = '' , string $ scheme = null ): string
121+ {
122+ $ config = clone config ('App ' );
123+ $ config ->indexPage = '' ;
118124
119- return rtrim (( string ) $ url , ' / ' );
125+ return rtrim (site_url ( $ relativePath , $ scheme , $ config ), ' / ' );
120126 }
121127}
122128
@@ -125,22 +131,32 @@ function base_url($uri = '', string $protocol = null): string
125131if (! function_exists ('current_url ' ))
126132{
127133 /**
128- * Current URL
134+ * Returns the current full URL based on the IncomingRequest.
135+ * String returns ignore query and fragment parts.
129136 *
130- * Returns the full URL (including segments) of the page where this
131- * function is placed
132- *
133- * @param boolean $returnObject True to return an object instead of a strong
137+ * @param boolean $returnObject True to return an object instead of a string
138+ * @param IncomingRequest|null $request A request to use when retrieving the path
134139 *
135140 * @return string|URI
136141 */
137- function current_url (bool $ returnObject = false )
142+ function current_url (bool $ returnObject = false , IncomingRequest $ request = null )
138143 {
139- $ uri = clone Services::request ()->uri ;
144+ $ request = $ request ?? Services::request ();
145+ $ path = $ request ->getPath ();
146+
147+ // Append queries and fragments
148+ if ($ query = $ request ->getUri ()->getQuery ())
149+ {
150+ $ path .= '? ' . $ query ;
151+ }
152+ if ($ fragment = $ request ->getUri ()->getFragment ())
153+ {
154+ $ path .= '# ' . $ fragment ;
155+ }
156+
157+ $ uri = _get_uri ($ path );
140158
141- // Since we're basing off of the IncomingRequest URI,
142- // we are guaranteed to have a host based on our own configs.
143- return $ returnObject ? $ uri : (string ) $ uri ->setQuery ('' );
159+ return $ returnObject ? $ uri : URI ::createURIString ($ uri ->getScheme (), $ uri ->getAuthority (), $ uri ->getPath ());
144160 }
145161}
146162
@@ -285,7 +301,7 @@ function anchor_popup($uri = '', string $title = '', $attributes = false, App $a
285301 // use alternate config if provided, else default one
286302 $ config = $ altConfig ?? config (App::class);
287303
288- $ siteUrl = preg_match ('#^(\w+:)?//#i ' , $ uri ) ? $ uri : site_url ($ uri , '' , $ config );
304+ $ siteUrl = preg_match ('#^(\w+:)?//#i ' , $ uri ) ? $ uri : site_url ($ uri , null , $ config );
289305 $ siteUrl = rtrim ($ siteUrl , '/ ' );
290306
291307 if ($ title === '' )
0 commit comments