diff --git a/README.md b/README.md index 9d32942..9ef8bca 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ XBackBone require PHP >= `7.1`, with installed the required extensions: 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. -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 return [ - 'base_path' => '/', + 'base_url' => 'https://example.com', // no trailing slash 'storage' => [ 'driver' => 'local', 'path' => 'storage', diff --git a/app/helpers.php b/app/helpers.php index f0dc47b..102d137 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -187,8 +187,8 @@ if (!function_exists('urlFor')) { */ function urlFor(string $path = '', string $append = ''): string { - global $app; - return $app->getBasePath().$path.$append; + $baseUrl = resolve('config')['base_url']; + return $baseUrl.$path.$append; } } @@ -376,4 +376,17 @@ if (!function_exists('glob_recursive')) { } 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; + } } \ No newline at end of file diff --git a/bootstrap/app.php b/bootstrap/app.php index 6c04172..fb20c54 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,9 +12,6 @@ use Aws\S3\S3Client; use DI\Bridge\Slim\Bridge; use DI\ContainerBuilder; 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\Local; use League\Flysystem\AwsS3v3\AwsS3Adapter; @@ -23,6 +20,8 @@ use Monolog\Formatter\LineFormatter; use Monolog\Handler\RotatingFileHandler; use Monolog\Logger; 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\FlysystemDropbox\DropboxAdapter; use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter; @@ -41,7 +40,7 @@ if (!file_exists('config.php') && is_dir('install/')) { // Load the config $config = array_replace_recursive([ 'app_name' => 'XBackBone', - 'base_path' => $_SERVER['REQUEST_URI'], + 'base_url' => isset($_SERVER['HTTPS']) ? 'https://'.$_SERVER['HTTP_HOST'] : 'http://'.$_SERVER['HTTP_HOST'], 'debug' => false, 'maintenance' => false, 'db' => [ @@ -65,7 +64,7 @@ if (!$config['debug']) { $builder->addDefinitions([ 'config' => value($config), - 'logger' => factory(function (Container $container) { + 'logger' => factory(function () { $logger = new Logger('app'); $streamHandler = new RotatingFileHandler(BASE_DIR.'logs/log.txt', 10, Logger::DEBUG); @@ -80,14 +79,13 @@ $builder->addDefinitions([ return $logger; }), - 'session' => factory(function (Container $container) { + 'session' => factory(function () { return new Session('xbackbone_session', BASE_DIR.'resources/sessions'); }), 'database' => factory(function (Container $container) { $config = $container->get('config'); - $dsn = $config['db']['connection'] === 'sqlite' ? BASE_DIR.$config['db']['dsn'] : $config['db']['dsn']; - return new DB($config['db']['connection'].':'.$dsn, $config['db']['username'], $config['db']['password']); + return new DB(dsnFromConfig($config), $config['db']['username'], $config['db']['password']); }), 'storage' => factory(function (Container $container) { @@ -145,7 +143,7 @@ $builder->addDefinitions([ ]); $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']) { $app->getRouteCollector()->setCacheFile(BASE_DIR.'resources/cache/routes.cache.php'); @@ -155,18 +153,18 @@ $app->add(InjectMiddleware::class); $app->add(RememberMiddleware::class); // 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(); $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 // to their non-trailing counterpart $uri = $uri->withPath(substr($path, 0, -1)); - if ($request->getMethod() == 'GET') { - $response = new Response(); - return $response->withStatus(301) + if ($request->getMethod() === 'GET') { + return $app->getResponseFactory() + ->createResponse(301) ->withHeader('Location', (string)$uri); } else { $request = $request->withUri($uri); diff --git a/config.example.php b/config.example.php index 87d7f7e..f27b636 100644 --- a/config.example.php +++ b/config.example.php @@ -1,6 +1,6 @@ '/', + 'base_url' => 'https://localhost', // no trailing slash 'db' => [ 'connection' => 'sqlite', 'dsn' => 'resources/database/xbackbone.db', diff --git a/install/index.php b/install/index.php index 45135ca..10c1868 100644 --- a/install/index.php +++ b/install/index.php @@ -11,17 +11,17 @@ use Aws\S3\S3Client; use DI\Bridge\Slim\Bridge; use DI\ContainerBuilder; use Google\Cloud\Storage\StorageClient; +use League\Flysystem\Adapter\Ftp as FtpAdapter; use League\Flysystem\Adapter\Local; use League\Flysystem\AwsS3v3\AwsS3Adapter; -use League\Flysystem\Adapter\Ftp as FtpAdapter; use League\Flysystem\FileExistsException; -use Spatie\Dropbox\Client as DropboxClient; 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 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\get; use function DI\value; @@ -31,7 +31,7 @@ define('BASE_DIR', realpath(__DIR__.'/../').DIRECTORY_SEPARATOR); // default 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, 'db' => [ 'connection' => 'sqlite', @@ -106,10 +106,10 @@ $builder->addDefinitions([ ]); $app = Bridge::create($builder->build()); -$app->setBasePath($_SERVER['REQUEST_URI']); +$app->setBasePath(parse_url($config['base_url'].'/install', PHP_URL_PATH)); $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')) { $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'); return $view->render($response, 'install.twig', [ - 'installed' => $installed, - 'app_path' => str_replace('install/', '', $config['base_path']), + 'installed' => $installed ]); })->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 $installed = true; @@ -155,7 +154,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora $installed = false; // config file setup - $config['base_path'] = param($request, 'base_path'); + $config['base_url'] = param($request, 'base_url'); $config['storage']['driver'] = param($request, 'storage_driver'); unset($config['debug']); $config['db']['connection'] = param($request, 'connection'); @@ -179,7 +178,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora case 'ftp': if (!extension_loaded('ftp')) { $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']['username'] = param($request, 'storage_username'); @@ -216,7 +215,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora $storage->readAndDelete($storageTestFile); } catch (Exception $e) { $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 @@ -227,31 +226,21 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora 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 try { - $firstMigrate = false; if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__.'/../'.$config['db']['dsn'])) { touch(__DIR__.'/../'.$config['db']['dsn']); $firstMigrate = true; } - $dsn = $config['db']['connection'] === 'sqlite' ? __DIR__.'/../'.$config['db']['dsn'] : $config['db']['dsn']; - $db = new DB($config['db']['connection'].':'.$dsn, $config['db']['username'], $config['db']['password']); + $db = new DB(dsnFromConfig($config), $config['db']['username'], $config['db']['password']); $migrator = new Migrator($db, __DIR__.'/../resources/schemas', $firstMigrate); $migrator->migrate(); } catch (PDOException $e) { $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 @@ -279,7 +268,7 @@ $app->post('', function (Request $request, Response $response, Filesystem $stora // Installed successfully, destroy the installer session $session->destroy(); - return redirect($response, "{$config['base_path']}?afterInstall=true"); + return redirect($response, urlFor('/?afterInstall=true')); }); $app->run(); \ No newline at end of file diff --git a/install/templates/install.twig b/install/templates/install.twig index eefb0c0..025ad28 100644 --- a/install/templates/install.twig +++ b/install/templates/install.twig @@ -27,9 +27,10 @@
{% if not installed %}
- +
- + + No trailing slash.

diff --git a/resources/templates/base.twig b/resources/templates/base.twig index dc6c1b3..02b8589 100644 --- a/resources/templates/base.twig +++ b/resources/templates/base.twig @@ -21,7 +21,7 @@