Skip to content

Commit 28e3a64

Browse files
committed
Refactor URL functions
1 parent 3509f60 commit 28e3a64

4 files changed

Lines changed: 197 additions & 410 deletions

File tree

system/Helpers/url_helper.php

Lines changed: 90 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* file that was distributed with this source code.
1010
*/
1111

12+
use CodeIgniter\HTTP\IncomingRequest;
1213
use CodeIgniter\HTTP\URI;
1314
use CodeIgniter\Router\Exceptions\RouterException;
1415
use Config\App;
@@ -18,105 +19,110 @@
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
125131
if (! 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

Comments
 (0)