Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework: URI creation and URL helper #7282

Merged
merged 34 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d01c783
refactor: current URI creation
kenjis Feb 20, 2023
fc0a1b8
refactor: URL helper site_url(), base_url(), current_url(), uri_string()
kenjis Feb 20, 2023
468b8b5
test: fix incorrect REQUEST_URI
kenjis Feb 21, 2023
c29c172
test: update FormHelperTest
kenjis Feb 21, 2023
e68379e
test: fix failed test
kenjis Feb 21, 2023
8464087
test: update URLs in assertions
kenjis Feb 23, 2023
76dfd39
feat: add Services::siteurifactory()
kenjis Feb 23, 2023
0674874
refactor: remove adjustPathTrailingSlash()
kenjis Feb 24, 2023
de46d3e
fix: SiteURI's query is not set in FeatureTestTrait
kenjis Feb 26, 2023
9827e0e
fix: use SiteURI in ControllerTestTrait
kenjis Feb 26, 2023
3207842
test: update assertion URL (add `index.php/`)
kenjis Feb 26, 2023
a4ba66d
refactor: remove unused private method
kenjis Jul 25, 2023
9ec7fbc
feat: add Services::superglobals()
kenjis Jul 25, 2023
f00cd8c
fix: out-of-dated parameters
kenjis Jul 25, 2023
7017919
test: use Services::superglobals()
kenjis Jul 25, 2023
715bd00
test: update out-of-dated parameters
kenjis Jul 25, 2023
f24ca6a
docs: add doc comments
kenjis Jul 25, 2023
7514d6d
fix: support protocol-relative links
kenjis Jul 28, 2023
ae4f7c8
docs: add @deprecated versions
kenjis Jul 28, 2023
6c83470
docs: update user guide
kenjis Jul 28, 2023
e4a2523
docs: add @deprecated versions
kenjis Jul 28, 2023
c2f8860
docs: add Deprecations
kenjis Jul 28, 2023
e01d622
test: remove unused private method
kenjis Jul 31, 2023
eeca9e9
docs: fix section level
kenjis Aug 4, 2023
9752815
test: update data provider method name
kenjis Aug 4, 2023
d80c7b5
fix: ControllerTestTrait::withUri() updates Request instance
kenjis Aug 9, 2023
3a76189
test: update data provider method name
kenjis Aug 9, 2023
0eebc5e
test: add tests for SiteURIFactory
kenjis Aug 9, 2023
d9a5a6d
fix: when URI string does not have path
kenjis Aug 9, 2023
546d112
test: remove redundant test
kenjis Aug 10, 2023
16621bf
test: add tests for uri_string() and current_url()
kenjis Aug 9, 2023
cce185c
docs: add upgrade_440
kenjis Aug 10, 2023
f35dc9b
docs: fix typo
kenjis Aug 14, 2023
c6f3d57
refactor: use Services::superglobals()
kenjis Aug 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions system/Config/BaseService.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use CodeIgniter\HTTP\Request;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\HTTP\SiteURIFactory;
use CodeIgniter\HTTP\URI;
use CodeIgniter\Images\Handlers\BaseHandler;
use CodeIgniter\Language\Language;
Expand All @@ -47,6 +48,7 @@
use CodeIgniter\Router\Router;
use CodeIgniter\Security\Security;
use CodeIgniter\Session\Session;
use CodeIgniter\Superglobals;
use CodeIgniter\Throttle\Throttler;
use CodeIgniter\Typography\Typography;
use CodeIgniter\Validation\ValidationInterface;
Expand Down Expand Up @@ -123,6 +125,8 @@
* @method static RouteCollection routes($getShared = true)
* @method static Security security(App $config = null, $getShared = true)
* @method static Session session(App $config = null, $getShared = true)
* @method static SiteURIFactory siteurifactory(App $config = null, Superglobals $superglobals = null, $getShared = true)
* @method static Superglobals superglobals(array $server = null, array $get = null, bool $getShared = true)
* @method static Throttler throttler($getShared = true)
* @method static Timer timer($getShared = true)
* @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true)
Expand Down
48 changes: 47 additions & 1 deletion system/Config/Services.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\HTTP\SiteURIFactory;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Images\Handlers\BaseHandler;
Expand All @@ -52,6 +53,7 @@
use CodeIgniter\Session\Handlers\Database\PostgreHandler;
use CodeIgniter\Session\Handlers\DatabaseHandler;
use CodeIgniter\Session\Session;
use CodeIgniter\Superglobals;
use CodeIgniter\Throttle\Throttler;
use CodeIgniter\Typography\Typography;
use CodeIgniter\Validation\Validation;
Expand Down Expand Up @@ -693,6 +695,43 @@ public static function session(?SessionConfig $config = null, bool $getShared =
return $session;
}

/**
* The Factory for SiteURI.
*
* @return SiteURIFactory
*/
public static function siteurifactory(
?App $config = null,
?Superglobals $superglobals = null,
bool $getShared = true
) {
if ($getShared) {
return static::getSharedInstance('siteurifactory', $config, $superglobals);
}

$config ??= config('App');
$superglobals ??= AppServices::superglobals();

return new SiteURIFactory($config, $superglobals);
}

/**
* Superglobals.
*
* @return Superglobals
*/
public static function superglobals(
?array $server = null,
?array $get = null,
bool $getShared = true
) {
if ($getShared) {
return static::getSharedInstance('superglobals', $server, $get);
}

return new Superglobals($server, $get);
}

/**
* The Throttler class provides a simple method for implementing
* rate limiting in your applications.
Expand Down Expand Up @@ -744,14 +783,21 @@ public static function toolbar(?ToolbarConfig $config = null, bool $getShared =
*
* @param string $uri
*
* @return URI
* @return URI The current URI if $uri is null.
*/
public static function uri(?string $uri = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('uri', $uri);
}

if ($uri === null) {
$appConfig = config(App::class);
$factory = AppServices::siteurifactory($appConfig, AppServices::superglobals());

return $factory->createFromGlobals();
}

return new URI($uri);
}

Expand Down
85 changes: 12 additions & 73 deletions system/HTTP/IncomingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,12 @@ public function __construct($config, ?URI $uri = null, $body = 'php://input', ?U

parent::__construct($config);

$this->detectURI($config->uriProtocol, $config->baseURL);
if ($uri instanceof SiteURI) {
$this->setPath($uri->getRoutePath());
} else {
$this->setPath($uri->getPath());
}

$this->detectLocale($config);
}

Expand Down Expand Up @@ -227,9 +232,9 @@ public function detectLocale($config)
* either provided by the user in the baseURL Config setting, or
* determined from the environment as needed.
*
* @deprecated $protocol and $baseURL are deprecated. No longer used.
*
* @return void
*
* @deprecated 4.4.0 No longer used.
*/
protected function detectURI(string $protocol, string $baseURL)
{
Expand Down Expand Up @@ -447,7 +452,7 @@ public function isSecure(): bool
}

/**
* Sets the relative path and updates the URI object.
* Sets the URI path relative to baseURL.
*
* Note: Since current_url() accesses the shared request
* instance, this can be used to change the "current URL"
Expand All @@ -457,88 +462,22 @@ public function isSecure(): bool
* @param App|null $config Optional alternate config to use
*
* @return $this
*
* @deprecated 4.4.0 This method will be private. The parameter $config is deprecated. No longer used.
*/
public function setPath(string $path, ?App $config = null)
{
$this->path = $path;

// @TODO remove this. The path of the URI object should be a full URI path,
// not a URI path relative to baseURL.
$this->uri->setPath($path);

$config ??= $this->config;

// It's possible the user forgot a trailing slash on their
// baseURL, so let's help them out.
$baseURL = ($config->baseURL === '') ? $config->baseURL : rtrim($config->baseURL, '/ ') . '/';

// Based on our baseURL and allowedHostnames provided by the developer
// and HTTP_HOST, set our current domain name, scheme.
if ($baseURL !== '') {
$host = $this->determineHost($config, $baseURL);

// Set URI::$baseURL
$uri = new URI($baseURL);
$currentBaseURL = (string) $uri->setHost($host);
$this->uri->setBaseURL($currentBaseURL);

$this->uri->setScheme(parse_url($baseURL, PHP_URL_SCHEME));
$this->uri->setHost($host);
$this->uri->setPort(parse_url($baseURL, PHP_URL_PORT));

// Ensure we have any query vars
$this->uri->setQuery($_SERVER['QUERY_STRING'] ?? '');

// Check if the scheme needs to be coerced into its secure version
if ($config->forceGlobalSecureRequests && $this->uri->getScheme() === 'http') {
$this->uri->setScheme('https');
}
} elseif (! is_cli()) {
// Do not change exit() to exception; Request is initialized before
// setting the exception handler, so if an exception is raised, an
// error will be displayed even if in the production environment.
// @codeCoverageIgnoreStart
exit('You have an empty or invalid baseURL. The baseURL value must be set in app/Config/App.php, or through the .env file.');
// @codeCoverageIgnoreEnd
}

return $this;
}

/**
* @deprecated 4.4.0 Moved to SiteURIFactory.
*/
private function determineHost(App $config, string $baseURL): string
{
$host = parse_url($baseURL, PHP_URL_HOST);

if (empty($config->allowedHostnames)) {
return $host;
}

// Update host if it is valid.
$httpHostPort = $this->getServer('HTTP_HOST');
if ($httpHostPort !== null) {
[$httpHost] = explode(':', $httpHostPort, 2);

if (in_array($httpHost, $config->allowedHostnames, true)) {
$host = $httpHost;
}
}

return $host;
}

/**
* Returns the URI path relative to baseURL,
* running detection as necessary.
*/
public function getPath(): string
{
if ($this->path === null) {
$this->detectPath($this->config->uriProtocol);
}

return $this->path;
}

Expand Down Expand Up @@ -972,7 +911,7 @@ public function getFile(string $fileID)
*
* Do some final cleaning of the URI and return it, currently only used in static::_parse_request_uri()
*
* @deprecated Use URI::removeDotSegments() directly
* @deprecated 4.1.2 Use URI::removeDotSegments() directly
*/
protected function removeRelativeDirectory(string $uri): string
{
Expand Down
65 changes: 64 additions & 1 deletion system/HTTP/SiteURI.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ private function determineBaseURL(
$uri = new URI($baseURL);

// Update scheme
if ($scheme !== null) {
if ($scheme !== null && $scheme !== '') {
MGatner marked this conversation as resolved.
Show resolved Hide resolved
$uri->setScheme($scheme);
} elseif ($configApp->forceGlobalSecureRequests) {
$uri->setScheme('https');
Expand Down Expand Up @@ -363,4 +363,67 @@ protected function applyParts(array $parts): void
$this->password = $parts['pass'];
}
}

/**
* For base_url() helper.
*
* @param array|string $relativePath URI string or array of URI segments
* @param string|null $scheme URI scheme. E.g., http, ftp
*/
public function baseUrl($relativePath = '', ?string $scheme = null): string
{
$relativePath = $this->stringifyRelativePath($relativePath);

$config = clone config(App::class);
$config->indexPage = '';

$host = $this->getHost();

$uri = new self($config, $relativePath, $host, $scheme);

// Support protocol-relative links
if ($scheme === '') {
MGatner marked this conversation as resolved.
Show resolved Hide resolved
return substr((string) $uri, strlen($uri->getScheme()) + 1);
}

return (string) $uri;
}

/**
* @param array|string $relativePath URI string or array of URI segments
*/
private function stringifyRelativePath($relativePath): string
{
if (is_array($relativePath)) {
$relativePath = implode('/', $relativePath);
}

return $relativePath;
}

/**
* For site_url() helper.
*
* @param array|string $relativePath URI string or array of URI segments
* @param string|null $scheme URI scheme. E.g., http, ftp
* @param App|null $config Alternate configuration to use
*/
public function siteUrl($relativePath = '', ?string $scheme = null, ?App $config = null): string
{
$relativePath = $this->stringifyRelativePath($relativePath);

// Check current host.
$host = $config === null ? $this->getHost() : null;

$config ??= config(App::class);

$uri = new self($config, $relativePath, $host, $scheme);

// Support protocol-relative links
if ($scheme === '') {
return substr((string) $uri, strlen($uri->getScheme()) + 1);
}

return (string) $uri;
}
}
9 changes: 8 additions & 1 deletion system/HTTP/SiteURIFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
use CodeIgniter\Superglobals;
use Config\App;

/**
* Creates SiteURI using superglobals.
*
* This class also updates superglobal $_SERVER and $_GET.
*/
final class SiteURIFactory
{
private App $appConfig;
Expand Down Expand Up @@ -42,6 +47,7 @@ public function createFromGlobals(): SiteURI
* Create the SiteURI object from URI string.
*
* @internal Used for testing purposes only.
* @testTag
MGatner marked this conversation as resolved.
Show resolved Hide resolved
*/
public function createFromString(string $uri): SiteURI
{
Expand All @@ -64,7 +70,7 @@ public function createFromString(string $uri): SiteURI
$fragment = '#' . $parts['fragment'];
}

$relativePath = $parts['path'] . $query . $fragment;
$relativePath = ($parts['path'] ?? '') . $query . $fragment;
$host = $this->getValidHost($parts['host']);

return new SiteURI($this->appConfig, $relativePath, $host, $parts['scheme']);
Expand All @@ -79,6 +85,7 @@ public function createFromString(string $uri): SiteURI
* @return string The route path
*
* @internal Used for testing purposes only.
* @testTag
*/
public function detectRoutePath(string $protocol = ''): string
{
Expand Down
Loading