diff --git a/src/Install/BaseUrl.php b/src/Install/BaseUrl.php new file mode 100644 index 000000000..b2e801454 --- /dev/null +++ b/src/Install/BaseUrl.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Install; + +use Psr\Http\Message\UriInterface; + +final class BaseUrl +{ + /** @var UriInterface|string */ + private $baseUrl; + + /** + * @param UriInterface|string $baseUrl + */ + private function __construct($baseUrl) + { + $this->baseUrl = $this->normalise($baseUrl); + } + + /** + * @param string $baseUrl + * @return \Flarum\Install\BaseUrl + */ + public static function fromString(string $baseUrl): self + { + return new self($baseUrl); + } + + /** + * @param \Psr\Http\Message\UriInterface $baseUrl + * @return \Flarum\Install\BaseUrl + */ + public static function fromUri(UriInterface $baseUrl): self + { + return self::fromString((string) $baseUrl); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->baseUrl; + } + + /** + * @param UriInterface|string $baseUrl + * @return string + */ + private function normalise($baseUrl): string + { + // Empty base url is still valid + if (empty($baseUrl)) { + return ''; + } + + $normalisedBaseUrl = trim($baseUrl, '/'); + if (! preg_match('#^https?://#i', $normalisedBaseUrl)) { + $normalisedBaseUrl = sprintf('http://%s', $normalisedBaseUrl); + } + + $parseUrl = parse_url($normalisedBaseUrl); + + $path = $parseUrl['path'] ?? null; + if (isset($parseUrl['path']) && strrpos($parseUrl['path'], '.php') !== false) { + $path = substr($parseUrl['path'], 0, strrpos($parseUrl['path'], '/')); + } + + return rtrim( + sprintf('%s://%s%s', $parseUrl['scheme'], $parseUrl['host'], $path), + '/' + ); + } +} diff --git a/src/Install/Console/FileDataProvider.php b/src/Install/Console/FileDataProvider.php index 6e0be233a..bbce20c11 100644 --- a/src/Install/Console/FileDataProvider.php +++ b/src/Install/Console/FileDataProvider.php @@ -11,6 +11,7 @@ namespace Flarum\Install\Console; use Exception; use Flarum\Install\AdminUser; +use Flarum\Install\BaseUrl; use Flarum\Install\DatabaseConfig; use Flarum\Install\Installation; use Symfony\Component\Console\Input\InputInterface; @@ -43,7 +44,7 @@ class FileDataProvider implements DataProviderInterface // Define configuration variables $this->debug = $configuration['debug'] ?? false; - $this->baseUrl = isset($configuration['baseUrl']) ? rtrim($configuration['baseUrl'], '/') : null; + $this->baseUrl = $configuration['baseUrl'] ?? 'http://flarum.local'; $this->databaseConfiguration = $configuration['databaseConfiguration'] ?? []; $this->adminUser = $configuration['adminUser'] ?? []; $this->settings = $configuration['settings'] ?? []; @@ -56,7 +57,7 @@ class FileDataProvider implements DataProviderInterface { return $installation ->debugMode($this->debug) - ->baseUrl($this->baseUrl ?? 'http://flarum.local') + ->baseUrl(BaseUrl::fromString($this->baseUrl)) ->databaseConfig($this->getDatabaseConfiguration()) ->adminUser($this->getAdminUser()) ->settings($this->settings); diff --git a/src/Install/Console/UserDataProvider.php b/src/Install/Console/UserDataProvider.php index 434962219..b87dbd399 100644 --- a/src/Install/Console/UserDataProvider.php +++ b/src/Install/Console/UserDataProvider.php @@ -10,6 +10,7 @@ namespace Flarum\Install\Console; use Flarum\Install\AdminUser; +use Flarum\Install\BaseUrl; use Flarum\Install\DatabaseConfig; use Flarum\Install\Installation; use Illuminate\Support\Str; @@ -39,7 +40,7 @@ class UserDataProvider implements DataProviderInterface { return $installation ->debugMode(false) - ->baseUrl($this->getBaseUrl()) + ->baseUrl(BaseUrl::fromString($this->getBaseUrl())) ->databaseConfig($this->getDatabaseConfiguration()) ->adminUser($this->getAdminUser()) ->settings($this->getSettings()); @@ -47,7 +48,7 @@ class UserDataProvider implements DataProviderInterface private function getDatabaseConfiguration(): DatabaseConfig { - $host = $this->ask('Database host:'); + $host = $this->ask('Database host (required):'); $port = 3306; if (Str::contains($host, ':')) { @@ -58,31 +59,31 @@ class UserDataProvider implements DataProviderInterface 'mysql', $host, intval($port), - $this->ask('Database name:'), - $this->ask('Database user:'), + $this->ask('Database name (required):'), + $this->ask('Database user (required):'), $this->secret('Database password:'), $this->ask('Prefix:') ); } - private function getBaseUrl() + private function getBaseUrl(): string { - return $this->baseUrl = rtrim($this->ask('Base URL:'), '/'); + return $this->baseUrl = $this->ask('Base URL:(Default: http://flarum.local)', 'http://flarum.local'); } private function getAdminUser(): AdminUser { return new AdminUser( - $this->ask('Admin username:'), + $this->ask('Admin username:(Default: admin)', 'admin'), $this->askForAdminPassword(), - $this->ask('Admin email address:') + $this->ask('Admin email address (required):') ); } private function askForAdminPassword() { while (true) { - $password = $this->secret('Admin password:'); + $password = $this->secret('Admin password (required >= 8 characters):'); if (strlen($password) < 8) { $this->validationError('Password must be at least 8 characters.'); @@ -103,11 +104,10 @@ class UserDataProvider implements DataProviderInterface private function getSettings() { $title = $this->ask('Forum title:'); - $baseUrl = $this->baseUrl ?: 'http://localhost'; return [ 'forum_title' => $title, - 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($baseUrl, PHP_URL_HOST)), + 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($this->baseUrl, PHP_URL_HOST)), 'welcome_title' => 'Welcome to '.$title, ]; } diff --git a/src/Install/Controller/InstallController.php b/src/Install/Controller/InstallController.php index 180bebe26..51fa5358c 100644 --- a/src/Install/Controller/InstallController.php +++ b/src/Install/Controller/InstallController.php @@ -11,6 +11,7 @@ namespace Flarum\Install\Controller; use Flarum\Http\SessionAuthenticator; use Flarum\Install\AdminUser; +use Flarum\Install\BaseUrl; use Flarum\Install\DatabaseConfig; use Flarum\Install\Installation; use Flarum\Install\StepFailed; @@ -52,16 +53,16 @@ class InstallController implements RequestHandlerInterface public function handle(Request $request): ResponseInterface { $input = $request->getParsedBody(); - $baseUrl = rtrim((string) $request->getUri(), '/'); + $baseUrl = $request->getUri(); try { $pipeline = $this->installation - ->baseUrl($baseUrl) + ->baseUrl(BaseUrl::fromUri($baseUrl)) ->databaseConfig($this->makeDatabaseConfig($input)) ->adminUser($this->makeAdminUser($input)) ->settings([ 'forum_title' => Arr::get($input, 'forumTitle'), - 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', parse_url($baseUrl, PHP_URL_HOST)), + 'mail_from' => 'noreply@'.preg_replace('/^www\./i', '', $baseUrl->getHost()), 'welcome_title' => 'Welcome to '.Arr::get($input, 'forumTitle'), ]) ->build(); diff --git a/src/Install/Installation.php b/src/Install/Installation.php index 5a5ddb090..835370950 100644 --- a/src/Install/Installation.php +++ b/src/Install/Installation.php @@ -63,9 +63,13 @@ class Installation return $this; } - public function baseUrl($baseUrl) + /** + * @param \Flarum\Install\BaseUrl $baseUrl + * @return $this + */ + public function baseUrl(BaseUrl $baseUrl) { - $this->baseUrl = $baseUrl; + $this->baseUrl = (string) $baseUrl; return $this; } diff --git a/tests/integration/setup.php b/tests/integration/setup.php index d31315806..8403acf5c 100644 --- a/tests/integration/setup.php +++ b/tests/integration/setup.php @@ -8,6 +8,7 @@ */ use Flarum\Install\AdminUser; +use Flarum\Install\BaseUrl; use Flarum\Install\DatabaseConfig; use Flarum\Install\Installation; @@ -46,7 +47,7 @@ $installation = new Installation( $pipeline = $installation ->configPath('config.php') ->debugMode(true) - ->baseUrl('http://localhost') + ->baseUrl(BaseUrl::fromString('http://localhost')) ->databaseConfig(new DatabaseConfig( 'mysql', env('DB_HOST', 'localhost'), diff --git a/tests/unit/Install/BaseUrlTest.php b/tests/unit/Install/BaseUrlTest.php new file mode 100644 index 000000000..af7363b14 --- /dev/null +++ b/tests/unit/Install/BaseUrlTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Tests\unit; + +use Flarum\Install\BaseUrl; +use Flarum\Tests\integration\TestCase; + +class BaseUrlTest extends TestCase +{ + /** + * @dataProvider urlProvider + * @param $uri + * @param $expected + */ + public function test_base_url_simulating_cli_installer($uri, $expected) + { + $this->assertEquals($expected, BaseUrl::fromString($uri)); + } + + /** + * @dataProvider urlProvider + * @param $uri + * @param $expected + */ + public function test_base_url_simulating_web_installer($uri, $expected) + { + $request = $this->request('get', $uri); + + $this->assertEquals($expected, BaseUrl::fromUri($request->getUri())); + } + + public function urlProvider() + { + return [ + ['', ''], + ['flarum.org', 'http://flarum.org'], + ['flarum.org/', 'http://flarum.org'], + ['http://flarum.org', 'http://flarum.org'], + ['http://flarum.org/', 'http://flarum.org'], + ['https://flarum.org', 'https://flarum.org'], + ['http://flarum.org/index.php', 'http://flarum.org'], + ['http://flarum.org/index.php/', 'http://flarum.org'], + ['http://flarum.org/flarum', 'http://flarum.org/flarum'], + ['http://flarum.org/flarum/index.php', 'http://flarum.org/flarum'], + ['http://flarum.org/flarum/index.php/', 'http://flarum.org/flarum'], + ['sub.flarum.org', 'http://sub.flarum.org'], + ['http://sub.flarum.org', 'http://sub.flarum.org'], + ]; + } +}