Fixing bad base url

This commit is contained in:
SergiX44 2019-11-18 11:42:42 +01:00
parent 7e5a156939
commit 399901c7a8
8 changed files with 56 additions and 55 deletions

View file

@ -47,11 +47,11 @@ XBackBone require PHP >= `7.1`, with installed the required extensions:
cp config.example.php config.php && nano config.php cp config.example.php config.php && nano config.php
``` ```
By default, XBackBone will use Sqlite3 as DB engine, and a `storage` dir in the main directory. You can leave these settings unchanged for a simple personal installation. By default, XBackBone will use Sqlite3 as DB engine, and a `storage` dir in the main directory. You can leave these settings unchanged for a simple personal installation.
You must set the `base_path`, or remove it for get dynamically the url from request (not recommended). You must set the `base_url`, or remove it for get dynamically the url from request (not recommended).
```php ```php
return [ return [
'base_path' => '/', 'base_url' => 'https://example.com', // no trailing slash
'storage' => [ 'storage' => [
'driver' => 'local', 'driver' => 'local',
'path' => 'storage', 'path' => 'storage',

View file

@ -187,8 +187,8 @@ if (!function_exists('urlFor')) {
*/ */
function urlFor(string $path = '', string $append = ''): string function urlFor(string $path = '', string $append = ''): string
{ {
global $app; $baseUrl = resolve('config')['base_url'];
return $app->getBasePath().$path.$append; return $baseUrl.$path.$append;
} }
} }
@ -377,3 +377,16 @@ if (!function_exists('glob_recursive')) {
return $files; return $files;
} }
} }
if (!function_exists('dsnFromConfig')) {
/**
* Return the database DSN from config.
* @param array $config
* @return string
*/
function dsnFromConfig(array $config): string
{
$dsn = $config['db']['connection'] === 'sqlite' ? BASE_DIR.$config['db']['dsn'] : $config['db']['dsn'];
return $config['db']['connection'].':'.$dsn;
}
}

View file

@ -12,9 +12,6 @@ use Aws\S3\S3Client;
use DI\Bridge\Slim\Bridge; use DI\Bridge\Slim\Bridge;
use DI\ContainerBuilder; use DI\ContainerBuilder;
use Google\Cloud\Storage\StorageClient; use Google\Cloud\Storage\StorageClient;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use League\Flysystem\Adapter\Ftp as FtpAdapter; use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\Adapter\Local; use League\Flysystem\Adapter\Local;
use League\Flysystem\AwsS3v3\AwsS3Adapter; use League\Flysystem\AwsS3v3\AwsS3Adapter;
@ -23,6 +20,8 @@ use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger; use Monolog\Logger;
use Psr\Container\ContainerInterface as Container; use Psr\Container\ContainerInterface as Container;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Spatie\Dropbox\Client as DropboxClient; use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter; use Spatie\FlysystemDropbox\DropboxAdapter;
use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter; use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter;
@ -41,7 +40,7 @@ if (!file_exists('config.php') && is_dir('install/')) {
// Load the config // Load the config
$config = array_replace_recursive([ $config = array_replace_recursive([
'app_name' => 'XBackBone', 'app_name' => 'XBackBone',
'base_path' => $_SERVER['REQUEST_URI'], 'base_url' => isset($_SERVER['HTTPS']) ? 'https://'.$_SERVER['HTTP_HOST'] : 'http://'.$_SERVER['HTTP_HOST'],
'debug' => false, 'debug' => false,
'maintenance' => false, 'maintenance' => false,
'db' => [ 'db' => [
@ -65,7 +64,7 @@ if (!$config['debug']) {
$builder->addDefinitions([ $builder->addDefinitions([
'config' => value($config), 'config' => value($config),
'logger' => factory(function (Container $container) { 'logger' => factory(function () {
$logger = new Logger('app'); $logger = new Logger('app');
$streamHandler = new RotatingFileHandler(BASE_DIR.'logs/log.txt', 10, Logger::DEBUG); $streamHandler = new RotatingFileHandler(BASE_DIR.'logs/log.txt', 10, Logger::DEBUG);
@ -80,14 +79,13 @@ $builder->addDefinitions([
return $logger; return $logger;
}), }),
'session' => factory(function (Container $container) { 'session' => factory(function () {
return new Session('xbackbone_session', BASE_DIR.'resources/sessions'); return new Session('xbackbone_session', BASE_DIR.'resources/sessions');
}), }),
'database' => factory(function (Container $container) { 'database' => factory(function (Container $container) {
$config = $container->get('config'); $config = $container->get('config');
$dsn = $config['db']['connection'] === 'sqlite' ? BASE_DIR.$config['db']['dsn'] : $config['db']['dsn']; return new DB(dsnFromConfig($config), $config['db']['username'], $config['db']['password']);
return new DB($config['db']['connection'].':'.$dsn, $config['db']['username'], $config['db']['password']);
}), }),
'storage' => factory(function (Container $container) { 'storage' => factory(function (Container $container) {
@ -145,7 +143,7 @@ $builder->addDefinitions([
]); ]);
$app = Bridge::create($builder->build()); $app = Bridge::create($builder->build());
$app->setBasePath(substr($config['base_path'], 0, -1)); $app->setBasePath(parse_url($config['base_url'], PHP_URL_PATH));
if (!$config['debug']) { if (!$config['debug']) {
$app->getRouteCollector()->setCacheFile(BASE_DIR.'resources/cache/routes.cache.php'); $app->getRouteCollector()->setCacheFile(BASE_DIR.'resources/cache/routes.cache.php');
@ -155,18 +153,18 @@ $app->add(InjectMiddleware::class);
$app->add(RememberMiddleware::class); $app->add(RememberMiddleware::class);
// Permanently redirect paths with a trailing slash to their non-trailing counterpart // Permanently redirect paths with a trailing slash to their non-trailing counterpart
$app->add(function (Request $request, RequestHandler $handler) use (&$config) { $app->add(function (Request $request, RequestHandler $handler) use (&$app, &$config) {
$uri = $request->getUri(); $uri = $request->getUri();
$path = $uri->getPath(); $path = $uri->getPath();
if ($path !== $config['base_path'] && substr($path, -1) === '/') { if ($path !== $app->getBasePath().'/' && substr($path, -1) === '/') {
// permanently redirect paths with a trailing slash // permanently redirect paths with a trailing slash
// to their non-trailing counterpart // to their non-trailing counterpart
$uri = $uri->withPath(substr($path, 0, -1)); $uri = $uri->withPath(substr($path, 0, -1));
if ($request->getMethod() == 'GET') { if ($request->getMethod() === 'GET') {
$response = new Response(); return $app->getResponseFactory()
return $response->withStatus(301) ->createResponse(301)
->withHeader('Location', (string)$uri); ->withHeader('Location', (string)$uri);
} else { } else {
$request = $request->withUri($uri); $request = $request->withUri($uri);

View file

@ -1,6 +1,6 @@
<?php <?php
return [ return [
'base_path' => '/', 'base_url' => 'https://localhost', // no trailing slash
'db' => [ 'db' => [
'connection' => 'sqlite', 'connection' => 'sqlite',
'dsn' => 'resources/database/xbackbone.db', 'dsn' => 'resources/database/xbackbone.db',

View file

@ -11,17 +11,17 @@ use Aws\S3\S3Client;
use DI\Bridge\Slim\Bridge; use DI\Bridge\Slim\Bridge;
use DI\ContainerBuilder; use DI\ContainerBuilder;
use Google\Cloud\Storage\StorageClient; use Google\Cloud\Storage\StorageClient;
use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\Adapter\Local; use League\Flysystem\Adapter\Local;
use League\Flysystem\AwsS3v3\AwsS3Adapter; use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\FileExistsException; use League\Flysystem\FileExistsException;
use Spatie\Dropbox\Client as DropboxClient;
use League\Flysystem\Filesystem; use League\Flysystem\Filesystem;
use Psr\Container\ContainerInterface as Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter; use Spatie\FlysystemDropbox\DropboxAdapter;
use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter; use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter;
use Psr\Container\ContainerInterface as Container;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use function DI\factory; use function DI\factory;
use function DI\get; use function DI\get;
use function DI\value; use function DI\value;
@ -31,7 +31,7 @@ define('BASE_DIR', realpath(__DIR__.'/../').DIRECTORY_SEPARATOR);
// default config // default config
$config = [ $config = [
'base_path' => $_SERVER['REQUEST_URI'], 'base_url' => str_replace('/install/', '', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http')."://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"),
'debug' => true, 'debug' => true,
'db' => [ 'db' => [
'connection' => 'sqlite', 'connection' => 'sqlite',
@ -106,10 +106,10 @@ $builder->addDefinitions([
]); ]);
$app = Bridge::create($builder->build()); $app = Bridge::create($builder->build());
$app->setBasePath($_SERVER['REQUEST_URI']); $app->setBasePath(parse_url($config['base_url'].'/install', PHP_URL_PATH));
$app->addRoutingMiddleware(); $app->addRoutingMiddleware();
$app->get('', function (Response $response, View $view, Session $session) use (&$config) { $app->get('/', function (Response $response, View $view, Session $session) use (&$config) {
if (!extension_loaded('gd')) { if (!extension_loaded('gd')) {
$session->alert('The required "gd" extension is not loaded.', 'danger'); $session->alert('The required "gd" extension is not loaded.', 'danger');
@ -142,12 +142,11 @@ $app->get('', function (Response $response, View $view, Session $session) use (&
$installed = file_exists(__DIR__.'/../config.php'); $installed = file_exists(__DIR__.'/../config.php');
return $view->render($response, 'install.twig', [ return $view->render($response, 'install.twig', [
'installed' => $installed, 'installed' => $installed
'app_path' => str_replace('install/', '', $config['base_path']),
]); ]);
})->setName('install'); })->setName('install');
$app->post('', function (Request $request, Response $response, Filesystem $storage, Session $session) use (&$config) { $app->post('/', function (Request $request, Response $response, Filesystem $storage, Session $session) use (&$config) {
// Check if there is a previous installation, if not, setup the config file // Check if there is a previous installation, if not, setup the config file
$installed = true; $installed = true;
@ -155,7 +154,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora
$installed = false; $installed = false;
// config file setup // config file setup
$config['base_path'] = param($request, 'base_path'); $config['base_url'] = param($request, 'base_url');
$config['storage']['driver'] = param($request, 'storage_driver'); $config['storage']['driver'] = param($request, 'storage_driver');
unset($config['debug']); unset($config['debug']);
$config['db']['connection'] = param($request, 'connection'); $config['db']['connection'] = param($request, 'connection');
@ -179,7 +178,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora
case 'ftp': case 'ftp':
if (!extension_loaded('ftp')) { if (!extension_loaded('ftp')) {
$session->alert('The "ftp" extension is not loaded.', 'danger'); $session->alert('The "ftp" extension is not loaded.', 'danger');
return redirect($response, urlFor()); return redirect($response, urlFor('/'));
} }
$config['storage']['host'] = param($request, 'storage_host'); $config['storage']['host'] = param($request, 'storage_host');
$config['storage']['username'] = param($request, 'storage_username'); $config['storage']['username'] = param($request, 'storage_username');
@ -216,7 +215,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora
$storage->readAndDelete($storageTestFile); $storage->readAndDelete($storageTestFile);
} catch (Exception $e) { } catch (Exception $e) {
$session->alert("Storage setup error: {$e->getMessage()} [{$e->getCode()}]", 'danger'); $session->alert("Storage setup error: {$e->getMessage()} [{$e->getCode()}]", 'danger');
return redirect($response, urlFor()); return redirect($response, urlFor('/install'));
} }
// if from older installations with no support of other than local driver // if from older installations with no support of other than local driver
@ -227,31 +226,21 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora
unset($config['storage_dir']); unset($config['storage_dir']);
} }
// if from 2.x versions
// update the config
if ($installed && isset($config['base_url'])) {
$path = parse_url($config['base_url'], PHP_URL_PATH);
$config['base_path'] = $path.'/';
unset($config['base_url']);
}
// Build the dns string and run the migrations // Build the dns string and run the migrations
try { try {
$firstMigrate = false; $firstMigrate = false;
if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__.'/../'.$config['db']['dsn'])) { if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__.'/../'.$config['db']['dsn'])) {
touch(__DIR__.'/../'.$config['db']['dsn']); touch(__DIR__.'/../'.$config['db']['dsn']);
$firstMigrate = true; $firstMigrate = true;
} }
$dsn = $config['db']['connection'] === 'sqlite' ? __DIR__.'/../'.$config['db']['dsn'] : $config['db']['dsn']; $db = new DB(dsnFromConfig($config), $config['db']['username'], $config['db']['password']);
$db = new DB($config['db']['connection'].':'.$dsn, $config['db']['username'], $config['db']['password']);
$migrator = new Migrator($db, __DIR__.'/../resources/schemas', $firstMigrate); $migrator = new Migrator($db, __DIR__.'/../resources/schemas', $firstMigrate);
$migrator->migrate(); $migrator->migrate();
} catch (PDOException $e) { } catch (PDOException $e) {
$session->alert("Cannot connect to the database: {$e->getMessage()} [{$e->getCode()}]", 'danger'); $session->alert("Cannot connect to the database: {$e->getMessage()} [{$e->getCode()}]", 'danger');
return redirect($response, urlFor()); return redirect($response, urlFor('/install'));
} }
// if not installed, create the default admin account // if not installed, create the default admin account
@ -279,7 +268,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora
// Installed successfully, destroy the installer session // Installed successfully, destroy the installer session
$session->destroy(); $session->destroy();
return redirect($response, "{$config['base_path']}?afterInstall=true"); return redirect($response, urlFor('/?afterInstall=true'));
}); });
$app->run(); $app->run();

View file

@ -27,9 +27,10 @@
<form method="post" action=""> <form method="post" action="">
{% if not installed %} {% if not installed %}
<div class="form-group row"> <div class="form-group row">
<label for="base_path" class="col-sm-3 col-form-label">Base Path</label> <label for="base_url" class="col-sm-3 col-form-label">Base URL</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" class="form-control" id="base_path" name="base_path" value="{{ app_path }}" autocomplete="off" required> <input type="text" class="form-control" id="base_url" name="base_url" value="{{ config.base_url }}" autocomplete="off" required>
<small>No trailing slash.</small>
</div> </div>
</div> </div>
<hr> <hr>

View file

@ -21,7 +21,7 @@
<link href="{{ asset('/static/app/app.css') }}" rel="stylesheet"> <link href="{{ asset('/static/app/app.css') }}" rel="stylesheet">
<script> <script>
window.AppConfig = { window.AppConfig = {
'base_path': '{{ urlFor() }}', 'base_url': '{{ urlFor() }}',
'max_upload_size': {{ maxUploadSize }}, 'max_upload_size': {{ maxUploadSize }},
'lang': {'publish': '{{ lang('publish') }}', 'hide': '{{ lang('hide') }}', 'dropzone': '{{ lang('drop_to_upload') }}'} 'lang': {'publish': '{{ lang('publish') }}', 'hide': '{{ lang('hide') }}', 'dropzone': '{{ lang('drop_to_upload') }}'}
} }

View file

@ -51,7 +51,7 @@ var app = {
var isOutline = false; var isOutline = false;
if ($(this).data('published')) { if ($(this).data('published')) {
isOutline = $callerButton.hasClass('btn-outline-warning'); isOutline = $callerButton.hasClass('btn-outline-warning');
$.post(window.AppConfig.base_path + '/upload/' + id + '/unpublish', function () { $.post(window.AppConfig.base_url + '/upload/' + id + '/unpublish', function () {
$callerButton $callerButton
.data('published', false) .data('published', false)
.tooltip('dispose') .tooltip('dispose')
@ -64,7 +64,7 @@ var app = {
}); });
} else { } else {
isOutline = $callerButton.hasClass('btn-outline-info'); isOutline = $callerButton.hasClass('btn-outline-info');
$.post(window.AppConfig.base_path + '/upload/' + id + '/publish', function () { $.post(window.AppConfig.base_url + '/upload/' + id + '/publish', function () {
$callerButton $callerButton
.data('published', true) .data('published', true)
.tooltip('dispose') .tooltip('dispose')
@ -80,7 +80,7 @@ var app = {
mediaDelete: function () { mediaDelete: function () {
var id = $(this).data('id'); var id = $(this).data('id');
var $callerButton = $(this); var $callerButton = $(this);
$.post(window.AppConfig.base_path + '/upload/' + id + '/delete', function () { $.post(window.AppConfig.base_url + '/upload/' + id + '/delete', function () {
$callerButton.tooltip('dispose'); $callerButton.tooltip('dispose');
$('#media_' + id).fadeOut(200, function () { $('#media_' + id).fadeOut(200, function () {
$(this).remove(); $(this).remove();
@ -89,14 +89,14 @@ var app = {
}, },
refreshToken: function () { refreshToken: function () {
var id = $(this).data('id'); var id = $(this).data('id');
$.post(window.AppConfig.base_path + '/user/' + id + '/refreshToken', function (data) { $.post(window.AppConfig.base_url + '/user/' + id + '/refreshToken', function (data) {
$('#token').val(data); $('#token').val(data);
}); });
}, },
loadThemes: function (e) { loadThemes: function (e) {
e.preventDefault(); e.preventDefault();
var $themes = $('#themes'); var $themes = $('#themes');
$.get(window.AppConfig.base_path + '/system/themes', function (data) { $.get(window.AppConfig.base_url + '/system/themes', function (data) {
$themes.empty(); $themes.empty();
$.each(data, function (key, value) { $.each(data, function (key, value) {
var opt = document.createElement('option'); var opt = document.createElement('option');
@ -114,7 +114,7 @@ var app = {
checkForUpdates: function () { checkForUpdates: function () {
$('#checkForUpdatesMessage').empty().text('...'); $('#checkForUpdatesMessage').empty().text('...');
$('#doUpgradeButton').prop('disabled', true); $('#doUpgradeButton').prop('disabled', true);
$.get(window.AppConfig.base_path + '/system/checkForUpdates?prerelease=' + $(this).data('prerelease'), function (data) { $.get(window.AppConfig.base_url + '/system/checkForUpdates?prerelease=' + $(this).data('prerelease'), function (data) {
$('#checkForUpdatesMessage').empty().text(data.message); $('#checkForUpdatesMessage').empty().text(data.message);
if (data.upgrade) { if (data.upgrade) {
$('#doUpgradeButton').prop('disabled', false); $('#doUpgradeButton').prop('disabled', false);