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

Fix url helper functions to work when site hosted in subfolders. #2407

Merged
merged 2 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion app/Config/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class App extends BaseConfig
| environments.
|
*/
public $baseURL = 'http://localhost:8080';
public $baseURL = 'http://localhost:8080/';

/*
|--------------------------------------------------------------------------
Expand Down
14 changes: 8 additions & 6 deletions system/HTTP/IncomingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ public function __construct($config, URI $uri = null, $body = 'php://input', Use

$this->populateHeaders();

// Get our current URI.
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;

$this->detectURI($config->uriProtocol, $config->baseURL);
Expand Down Expand Up @@ -604,14 +609,10 @@ protected function detectURI(string $protocol, string $baseURL)
// baseURL, so let's help them out.
$baseURL = ! empty($baseURL) ? rtrim($baseURL, '/ ') . '/' : $baseURL;

// Based on our baseURL provided by the developer (if set)
// Based on our baseURL provided by the developer
// set our current domain name, scheme
if (! empty($baseURL))
{
// We cannot add the path here, otherwise it's possible
// that the routing will not work correctly if we are
// within a sub-folder scheme. So it's modified in
// the
$this->uri->setScheme(parse_url($baseURL, PHP_URL_SCHEME));
$this->uri->setHost(parse_url($baseURL, PHP_URL_HOST));
$this->uri->setPort(parse_url($baseURL, PHP_URL_PORT));
Expand Down Expand Up @@ -715,7 +716,8 @@ protected function parseRequestURI(): string
}

// parse_url() returns false if no host is present, but the path or query string
// contains a colon followed by a number
// contains a colon followed by a number. So we attach a dummy host since
// REQUEST_URI does not include the host. This allows us to parse out the query string and path.
$parts = parse_url('http://dummy' . $_SERVER['REQUEST_URI']);
$query = $parts['query'] ?? '';
$uri = $parts['path'] ?? '';
Expand Down
31 changes: 28 additions & 3 deletions system/Helpers/url_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,14 @@ function base_url($uri = '', string $protocol = null): string
// otherwise get rid of the path, because we have
// no way of knowing the intent...
$config = \CodeIgniter\Config\Services::request()->config;
$url = new \CodeIgniter\HTTP\URI($config->baseURL);

// If baseUrl does not have a trailing slash it won't resolve
// correctly for users hosting in a subfolder.
$baseUrl = ! empty($config->baseURL) && $config->baseURL !== '/'
? rtrim($config->baseURL, '/ ') . '/'
: $config->baseURL;

$url = new \CodeIgniter\HTTP\URI($baseUrl);
unset($config);

// Merge in the path set by the user, if any
Expand All @@ -132,7 +139,7 @@ function base_url($uri = '', string $protocol = null): string
$url->setScheme($protocol);
}

return (string) $url;
return rtrim((string) $url, '/ ');
}
}

Expand All @@ -152,7 +159,25 @@ function base_url($uri = '', string $protocol = null): string
*/
function current_url(bool $returnObject = false)
{
return $returnObject ? \CodeIgniter\Config\Services::request()->uri : (string) \CodeIgniter\Config\Services::request()->uri;
$uri = service('request')->uri;

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$baseUri = new \CodeIgniter\HTTP\URI(config('App')->baseURL);

if (! empty($baseUri->getPath()))
{
$path = rtrim($baseUri->getPath(), '/ ') . '/' . $uri->getPath();

$uri->setPath($path);
}

// Since we're basing off of the IncomingRequest URI,
// we are guaranteed to have a host based on our own configs.
return $returnObject
? $uri
: (string)$uri->setQuery('');
}
}

Expand Down
51 changes: 50 additions & 1 deletion tests/system/Helpers/URLHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ public function testSiteURLSegments()
$this->assertEquals('http://example.com/index.php/news/local/123', site_url(['news', 'local', '123'], null, $config));
}

public function testSiteURLInSubfolder()
{
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/foo/public/bar?baz=quip';

// Since we're on a CLI, we must provide our own URI
$config = new App();
$config->baseURL = 'http://example.com/foo/public';
$request = Services::request($config);
$request->uri = new URI('http://example.com/foo/public/bar');

Services::injectMock('request', $request);

$this->assertEquals('http://example.com/foo/public/bar', current_url());
}

/**
* @see https://github.com/codeigniter4/CodeIgniter4/issues/240
*/
Expand Down Expand Up @@ -281,7 +297,7 @@ public function testBaseURLWithSegments()

Services::injectMock('request', $request);

$this->assertEquals('http://example.com/', base_url());
$this->assertEquals('http://example.com', base_url());
}

/**
Expand Down Expand Up @@ -316,6 +332,23 @@ public function testBaseURLWithSegmentsAgain()
$this->assertEquals('http://example.com/profile', base_url('profile'));
}

public function testBaseURLHasSubfolder()
{
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/test';

// Since we're on a CLI, we must provide our own URI
$config = new App();
$config->baseURL = 'http://example.com/subfolder';
$request = Services::request($config, false);
$request->uri = new URI('http://example.com/subfolder/test');

Services::injectMock('request', $request);

$this->assertEquals('http://example.com/subfolder/foo', base_url('foo'));
$this->assertEquals('http://example.com/subfolder', base_url());
}

//--------------------------------------------------------------------
// Test current_url

Expand Down Expand Up @@ -370,6 +403,22 @@ public function testCurrentURLEquivalence()
$this->assertEquals(base_url(uri_string()), current_url());
}

public function testCurrentURLInSubfolder()
{
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/foo/public/bar?baz=quip';

// Since we're on a CLI, we must provide our own URI
$config = new App();
$config->baseURL = 'http://example.com/foo/public';
$request = Services::request($config);
$request->uri = new URI('http://example.com/foo/public/bar');

Services::injectMock('request', $request);

$this->assertEquals('http://example.com/foo/public/bar', current_url());
}

//--------------------------------------------------------------------
// Test previous_url

Expand Down