Converted installer

This commit is contained in:
Sergio Brighenti 2019-11-13 13:02:31 +01:00
parent 9c228247c9
commit b5784abb52
14 changed files with 543 additions and 512 deletions

View file

@ -84,7 +84,7 @@ class UploadController extends Controller
$json['message'] = 'OK.';
$json['url'] = urlFor("/$user->user_code/$code.$fileInfo[extension]");
$this->logger->info("User $user->username uploaded new media.", [$this->database->raw()->lastInsertId()]);
$this->logger->info("User $user->username uploaded new media.", [$this->database->getPdo()->lastInsertId()]);
return json($response, $json, 201);
}

View file

@ -11,25 +11,14 @@ class DB
/** @var DB */
protected static $instance;
/** @var string */
private static $password;
/** @var string */
private static $username;
/** @var PDO */
protected $pdo;
/** @var string */
protected static $dsn = 'sqlite:database.db';
/** @var string */
protected $currentDriver;
public function __construct(string $dsn, string $username = null, string $password = null)
{
self::setDsn($dsn, $username, $password);
$this->pdo = new PDO($dsn, $username, $password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
@ -72,58 +61,4 @@ class DB
{
return $this->currentDriver;
}
public static function getInstance(): DB
{
if (self::$instance === null) {
self::$instance = new self(self::$dsn, self::$username, self::$password);
}
return self::$instance;
}
/**
* Perform a query
* @param string $query
* @param array $parameters
* @return bool|\PDOStatement|string
*/
public static function doQuery(string $query, $parameters = [])
{
return self::getInstance()->query($query, $parameters);
}
/**
* Static method to get the current driver name
* @return string
*/
public static function driver(): string
{
return self::getInstance()->getCurrentDriver();
}
/**
* Get directly the PDO instance
* @return PDO
*/
public static function raw(): PDO
{
return self::getInstance()->getPdo();
}
/**
* Set the PDO connection string
* @param string $dsn
* @param string|null $username
* @param string|null $password
*/
public static function setDsn(string $dsn, string $username = null, string $password = null)
{
self::$dsn = $dsn;
self::$username = $username;
self::$password = $password;
}
}

98
app/Database/Migrator.php Normal file
View file

@ -0,0 +1,98 @@
<?php
namespace App\Database;
use PDOException;
class Migrator
{
/**
* @var DB
*/
private $db;
/**
* @var string
*/
private $schemaPath;
/**
* @var bool
*/
private $firstMigrate;
/**
* Migrator constructor.
* @param DB $db
* @param string $schemaPath
* @param bool $firstMigrate
*/
public function __construct(DB $db, string $schemaPath, bool $firstMigrate = false)
{
$this->db = $db;
$this->schemaPath = $schemaPath;
$this->firstMigrate = $firstMigrate;
}
public function migrate()
{
try {
$this->db->query('SELECT 1 FROM `migrations` LIMIT 1');
} catch (PDOException $exception) {
$this->firstMigrate = true;
}
if ($this->firstMigrate) {
$this->db->getPdo()->exec(file_get_contents($this->schemaPath.DIRECTORY_SEPARATOR.'migrations.sql'));
}
$files = glob($this->schemaPath.DIRECTORY_SEPARATOR.$this->db->getCurrentDriver().'/*.sql');
$names = array_map(function ($path) {
return basename($path);
}, $files);
$in = str_repeat('?, ', count($names) - 1).'?';
$inMigrationsTable = $this->db->query("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
foreach ($files as $file) {
$continue = false;
$exists = false;
foreach ($inMigrationsTable as $migration) {
if (basename($file) === $migration->name && $migration->migrated) {
$continue = true;
break;
} else {
if (basename($file) === $migration->name && !$migration->migrated) {
$exists = true;
break;
}
}
}
if ($continue) {
continue;
}
$sql = file_get_contents($file);
try {
$this->db->getPdo()->exec($sql);
if (!$exists) {
$this->db->query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
} else {
$this->db->query('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
}
} catch (PDOException $exception) {
if (!$exists) {
$this->db->query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
}
throw $exception;
}
}
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace App\Factories;
use App\Web\View;
use Psr\Container\ContainerInterface as Container;
use Slim\Factory\ServerRequestCreatorFactory;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\TwigFunction;
class ViewFactory
{
public static function createAppInstance(Container $container)
{
$config = $container->get('config');
$loader = new FilesystemLoader(BASE_DIR.'resources/templates');
$twig = new Environment($loader, [
'cache' => BASE_DIR.'resources/cache/twig',
'autoescape' => 'html',
'debug' => $config['debug'],
'auto_reload' => $config['debug'],
]);
$request = ServerRequestCreatorFactory::create()->createServerRequestFromGlobals();
$twig->addGlobal('config', $config);
$twig->addGlobal('request', $request);
$twig->addGlobal('alerts', $container->get('session')->getAlert());
$twig->addGlobal('session', $container->get('session')->all());
$twig->addGlobal('current_lang', $container->get('lang')->getLang());
$twig->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
$twig->addFunction(new TwigFunction('route', 'route'));
$twig->addFunction(new TwigFunction('lang', 'lang'));
$twig->addFunction(new TwigFunction('urlFor', 'urlFor'));
$twig->addFunction(new TwigFunction('asset', 'asset'));
$twig->addFunction(new TwigFunction('mime2font', 'mime2font'));
$twig->addFunction(new TwigFunction('queryParams', 'queryParams'));
$twig->addFunction(new TwigFunction('isDisplayableImage', 'isDisplayableImage'));
return new View($twig);
}
public static function createInstallerInstance(Container $container) {
$config = $container->get('config');
$loader = new FilesystemLoader([BASE_DIR . 'install/templates', BASE_DIR.'resources/templates']);
$twig = new Environment($loader, [
'cache' => false,
'autoescape' => 'html',
'debug' => $config['debug'],
'auto_reload' => $config['debug'],
]);
$request = ServerRequestCreatorFactory::create()->createServerRequestFromGlobals();
$twig->addGlobal('config', $config);
$twig->addGlobal('request', $request);
$twig->addGlobal('alerts', $container->get('session')->getAlert());
$twig->addGlobal('session', $container->get('session')->all());
$twig->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
return new View($twig);
}
}

View file

@ -17,11 +17,10 @@ class CheckForMaintenanceMiddleware extends Middleware
*/
public function __invoke(Request $request, RequestHandler $handler): Response
{
if (isset($this->config['maintenance']) && $this->settings['maintenance'] && !$this->database->query('SELECT `id`, `is_admin` FROM `users` WHERE `id` = ? LIMIT 1', [$this->session->get('user_id')])->fetch()->is_admin) {
if (isset($this->config['maintenance']) && $this->config['maintenance'] && !$this->database->query('SELECT `id`, `is_admin` FROM `users` WHERE `id` = ? LIMIT 1', [$this->session->get('user_id')])->fetch()->is_admin) {
throw new UnderMaintenanceException($request);
}
$response = $handler->handle($request);
return $response;
return $handler->handle($request);
}
}

View file

@ -3,11 +3,26 @@
namespace App\Middleware;
use App\Database\DB;
use App\Web\Lang;
use App\Web\Session;
use DI\Container;
use League\Flysystem\Filesystem;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Twig\Environment;
/**
* @property Session|null session
* @property Environment view
* @property DB|null database
* @property Logger|null logger
* @property Filesystem|null storage
* @property Lang lang
* @property array config
*/
abstract class Middleware
{
/** @var Container */

View file

@ -6,134 +6,138 @@ namespace App\Web;
class Lang
{
const DEFAULT_LANG = 'en';
const LANG_PATH = __DIR__ . '../../resources/lang/';
const DEFAULT_LANG = 'en';
const LANG_PATH = __DIR__.'../../resources/lang/';
/** @var string */
protected static $langPath = self::LANG_PATH;
/** @var string */
protected static $langPath = self::LANG_PATH;
/** @var string */
protected static $lang;
/** @var string */
protected static $lang;
/** @var Lang */
protected static $instance;
/** @var Lang */
protected static $instance;
/** @var array */
protected $cache = [];
/** @var array */
protected $cache = [];
/**
* @return Lang
*/
public static function getInstance(): Lang
{
if (self::$instance === null) {
self::$instance = new self();
}
/**
* @return Lang
*/
public static function getInstance(): Lang
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
return self::$instance;
}
/**
* @param string $lang
* @param string $langPath
* @return Lang
*/
public static function build($lang = self::DEFAULT_LANG, $langPath = null): Lang
{
self::$lang = $lang;
/**
* @param string $lang
* @param string $langPath
* @return Lang
*/
public static function build($lang = self::DEFAULT_LANG, $langPath = null): Lang
{
self::$lang = $lang;
if ($langPath !== null) {
self::$langPath = $langPath;
}
if ($langPath !== null) {
self::$langPath = $langPath;
}
self::$instance = new self();
self::$instance = new self();
return self::$instance;
}
return self::$instance;
}
/**
* Recognize the current language from the request.
* @return bool|string
*/
public static function recognize()
{
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']);
}
return self::DEFAULT_LANG;
}
/**
* Recognize the current language from the request.
* @return bool|string
*/
public static function recognize()
{
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']);
}
return self::DEFAULT_LANG;
}
/**
* @return string
*/
public static function getLang(): string
{
return self::$lang;
}
/**
* @return string
*/
public static function getLang(): string
{
return self::$lang;
}
/**
* @return array
*/
public static function getList()
{
$languages = [];
/**
* @return array
*/
public static function getList()
{
$languages = [];
$default = count(include self::$langPath . self::DEFAULT_LANG . '.lang.php') - 1;
$default = count(include self::$langPath.self::DEFAULT_LANG.'.lang.php') - 1;
foreach (glob(self::$langPath . '*.lang.php') as $file) {
$dict = include $file;
foreach (glob(self::$langPath.'*.lang.php') as $file) {
$dict = include $file;
$count = count($dict) - 1;
$prepend = "[{$count}/{$default}] ";
$count = count($dict) - 1;
$percent = round(($count / $default) * 100);
$languages[str_replace('.lang.php', '', basename($file))] = $prepend . $dict['lang'];
}
$languages[str_replace('.lang.php', '', basename($file))] = "[{$percent}%] ".$dict['lang'];
}
return $languages;
}
return $languages;
}
/**
* @param $key
* @param array $args
* @return string
*/
public function get($key, $args = []): string
{
return $this->getString($key, self::$lang, $args);
}
/**
* @param $key
* @param array $args
* @return string
*/
public function get($key, $args = []): string
{
return $this->getString($key, self::$lang, $args);
}
/**
* @param $key
* @param $lang
* @param $args
* @return string
*/
private function getString($key, $lang, $args): string
{
$redLang = strtolower(substr($lang, 0, 2));
/**
* @param $key
* @param $lang
* @param $args
* @return string
*/
private function getString($key, $lang, $args): string
{
$redLang = strtolower(substr($lang, 0, 2));
if (array_key_exists($lang, $this->cache)) {
$transDict = $this->cache[$lang];
} else if (file_exists(self::$langPath . $lang . '.lang.php')) {
$transDict = include self::$langPath . $lang . '.lang.php';
$this->cache[$lang] = $transDict;
} else if (file_exists(self::$langPath . $redLang . '.lang.php')) {
$transDict = include self::$langPath . $redLang . '.lang.php';
$this->cache[$lang] = $transDict;
} else {
$transDict = [];
}
if (array_key_exists($lang, $this->cache)) {
$transDict = $this->cache[$lang];
} else {
if (file_exists(self::$langPath.$lang.'.lang.php')) {
$transDict = include self::$langPath.$lang.'.lang.php';
$this->cache[$lang] = $transDict;
} else {
if (file_exists(self::$langPath.$redLang.'.lang.php')) {
$transDict = include self::$langPath.$redLang.'.lang.php';
$this->cache[$lang] = $transDict;
} else {
$transDict = [];
}
}
}
if (array_key_exists($key, $transDict)) {
return vsprintf($transDict[$key], $args);
}
if (array_key_exists($key, $transDict)) {
return vsprintf($transDict[$key], $args);
}
if ($lang !== self::DEFAULT_LANG) {
return $this->getString($key, self::DEFAULT_LANG, $args);
}
if ($lang !== self::DEFAULT_LANG) {
return $this->getString($key, self::DEFAULT_LANG, $args);
}
return $key;
}
return $key;
}
}

View file

@ -24,40 +24,10 @@ class View
/**
* View constructor.
* @param Container $container
* @throws \DI\DependencyException
* @throws \DI\NotFoundException
* @param Environment $twig
*/
public function __construct(Container $container)
public function __construct(Environment $twig)
{
$config = $container->get('config');
$loader = new FilesystemLoader(BASE_DIR.'resources/templates');
$twig = new Environment($loader, [
'cache' => BASE_DIR.'resources/cache/twig',
'autoescape' => 'html',
'debug' => $config['debug'],
'auto_reload' => $config['debug'],
]);
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
$twig->addGlobal('config', $config);
$twig->addGlobal('request', $request);
$twig->addGlobal('alerts', $container->get('session')->getAlert());
$twig->addGlobal('session', $container->get('session')->all());
$twig->addGlobal('current_lang', $container->get('lang')->getLang());
$twig->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
$twig->addFunction(new TwigFunction('route', 'route'));
$twig->addFunction(new TwigFunction('lang', 'lang'));
$twig->addFunction(new TwigFunction('urlFor', 'urlFor'));
$twig->addFunction(new TwigFunction('asset', 'asset'));
$twig->addFunction(new TwigFunction('mime2font', 'mime2font'));
$twig->addFunction(new TwigFunction('queryParams', 'queryParams'));
$twig->addFunction(new TwigFunction('isDisplayableImage', 'isDisplayableImage'));
$this->twig = $twig;
}

View file

@ -3,9 +3,9 @@
use App\Database\DB;
use App\Exception\Handlers\AppErrorHandler;
use App\Exception\Handlers\Renderers\HtmlErrorRenderer;
use App\Factories\ViewFactory;
use App\Web\Lang;
use App\Web\Session;
use App\Web\View;
use Aws\S3\S3Client;
use DI\Bridge\Slim\Bridge;
use DI\ContainerBuilder;
@ -137,8 +137,8 @@ $builder->addDefinitions([
return Lang::build(Lang::recognize(), BASE_DIR.'resources/lang/');
}),
'view' => factory(function ($container) {
return new View($container);
'view' => factory(function (Container $container) {
return ViewFactory::createAppInstance($container);
}),
]);

48
composer.lock generated
View file

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e7ad26b98d3ded901c5c663673f3bfff",
"content-hash": "a5d4341b89b81518c0e488cd3bc47127",
"packages": [
{
"name": "aws/aws-sdk-php",
"version": "3.115.2",
"version": "3.116.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "15792196be1b3b1b5663bca7b6cd021d005e2265"
"reference": "b0669936681365a6c5201a6d28bfa76553052912"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/15792196be1b3b1b5663bca7b6cd021d005e2265",
"reference": "15792196be1b3b1b5663bca7b6cd021d005e2265",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b0669936681365a6c5201a6d28bfa76553052912",
"reference": "b0669936681365a6c5201a6d28bfa76553052912",
"shasum": ""
},
"require": {
@ -87,7 +87,7 @@
"s3",
"sdk"
],
"time": "2019-11-11T19:22:34+00:00"
"time": "2019-11-12T19:15:09+00:00"
},
{
"name": "firebase/php-jwt",
@ -249,16 +249,16 @@
},
{
"name": "google/cloud-storage",
"version": "v1.15.0",
"version": "v1.16.0",
"source": {
"type": "git",
"url": "https://github.com/googleapis/google-cloud-php-storage.git",
"reference": "003eb1a735d77f8196f816c4a921199d15c4a82c"
"reference": "308ad790b257286e02777e3bf1a2c0473a4651a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/003eb1a735d77f8196f816c4a921199d15c4a82c",
"reference": "003eb1a735d77f8196f816c4a921199d15c4a82c",
"url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/308ad790b257286e02777e3bf1a2c0473a4651a7",
"reference": "308ad790b257286e02777e3bf1a2c0473a4651a7",
"shasum": ""
},
"require": {
@ -296,7 +296,7 @@
"Apache-2.0"
],
"description": "Cloud Storage Client for PHP",
"time": "2019-10-28T19:05:44+00:00"
"time": "2019-11-12T23:35:42+00:00"
},
{
"name": "google/crc32",
@ -893,16 +893,16 @@
},
{
"name": "monolog/monolog",
"version": "1.25.1",
"version": "1.25.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf"
"reference": "d5e2fb341cb44f7e2ab639d12a1e5901091ec287"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/70e65a5470a42cfec1a7da00d30edb6e617e8dcf",
"reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/d5e2fb341cb44f7e2ab639d12a1e5901091ec287",
"reference": "d5e2fb341cb44f7e2ab639d12a1e5901091ec287",
"shasum": ""
},
"require": {
@ -967,7 +967,7 @@
"logging",
"psr-3"
],
"time": "2019-09-06T13:49:17+00:00"
"time": "2019-11-13T10:00:05+00:00"
},
{
"name": "mtdowling/jmespath.php",
@ -3073,16 +3073,16 @@
},
{
"name": "symfony/console",
"version": "v4.3.7",
"version": "v4.3.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "d2e39dbddae68560fa6be0c576da6ad4e945b90d"
"reference": "831424efae0a1fe6642784bd52aae14ece6538e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/d2e39dbddae68560fa6be0c576da6ad4e945b90d",
"reference": "d2e39dbddae68560fa6be0c576da6ad4e945b90d",
"url": "https://api.github.com/repos/symfony/console/zipball/831424efae0a1fe6642784bd52aae14ece6538e6",
"reference": "831424efae0a1fe6642784bd52aae14ece6538e6",
"shasum": ""
},
"require": {
@ -3144,11 +3144,11 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2019-11-05T15:00:49+00:00"
"time": "2019-11-13T07:29:07+00:00"
},
{
"name": "symfony/finder",
"version": "v4.3.7",
"version": "v4.3.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
@ -3313,9 +3313,9 @@
}
],
"aliases": [],
"minimum-stability": "dev",
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": true,
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.1",

View file

@ -1,10 +1,15 @@
<?php
(PHP_MAJOR_VERSION >= 7 && PHP_MINOR_VERSION >= 1) ?: die('Sorry, PHP 7.1 or above is required to run XBackBone.');
require __DIR__ . '/../vendor/autoload.php';
require __DIR__.'/../vendor/autoload.php';
use App\Database\DB;
use App\Database\Migrator;
use App\Factories\ViewFactory;
use App\Web\Session;
use App\Web\View;
use Aws\S3\S3Client;
use DI\Bridge\Slim\Bridge;
use DI\ContainerBuilder;
use Google\Cloud\Storage\StorageClient;
use League\Flysystem\Adapter\Local;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
@ -12,322 +17,262 @@ use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\FileExistsException;
use Spatie\Dropbox\Client as DropboxClient;
use League\Flysystem\Filesystem;
use Slim\App;
use Slim\Container;
use Slim\Http\Environment;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Http\Uri;
use Slim\Views\Twig;
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;
define('PLATFORM_VERSION', json_decode(file_get_contents(__DIR__ . '/../composer.json'))->version);
define('PLATFORM_VERSION', json_decode(file_get_contents(__DIR__.'/../composer.json'))->version);
define('BASE_DIR', realpath(__DIR__.'/../').DIRECTORY_SEPARATOR);
// default config
$config = [
'base_url' => str_replace('/install/', '', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"),
'displayErrorDetails' => true,
'db' => [
'connection' => 'sqlite',
'dsn' => realpath(__DIR__ . '/../') . implode(DIRECTORY_SEPARATOR, ['resources', 'database', 'xbackbone.db']),
'username' => null,
'password' => null,
],
'storage' => [
'driver' => 'local',
'path' => realpath(__DIR__ . '/../') . DIRECTORY_SEPARATOR . 'storage',
],
'base_url' => str_replace('/install/', '', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http')."://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"),
'debug' => true,
'db' => [
'connection' => 'sqlite',
'dsn' => realpath(__DIR__.'/../').implode(DIRECTORY_SEPARATOR, ['resources', 'database', 'xbackbone.db']),
'username' => null,
'password' => null,
],
'storage' => [
'driver' => 'local',
'path' => realpath(__DIR__.'/../').DIRECTORY_SEPARATOR.'storage',
],
];
if (file_exists(__DIR__ . '/../config.php')) {
$config = array_replace_recursive($config, require __DIR__ . '/../config.php');
if (file_exists(__DIR__.'/../config.php')) {
$config = array_replace_recursive($config, require __DIR__.'/../config.php');
}
$container = new Container(['settings' => $config]);
$builder = new ContainerBuilder();
$container['session'] = function ($container) {
return new Session('xbackbone_session');
};
$builder->addDefinitions([
'config' => value($config),
$container['view'] = function ($container) use (&$config) {
$view = new Twig([__DIR__ . '/templates', __DIR__ . '/../resources/templates'], [
'cache' => false,
'autoescape' => 'html',
'debug' => $config['displayErrorDetails'],
'auto_reload' => $config['displayErrorDetails'],
]);
Session::class => factory(function () {
return new Session('xbackbone_session');
}),
'session' => get(Session::class),
// Instantiate and add Slim specific extension
$router = $container->get('router');
$uri = Uri::createFromEnvironment(new Environment($_SERVER));
$view->addExtension(new Slim\Views\TwigExtension($router, $uri));
Filesystem::class => factory(function (Container $container) {
$config = $container->get('config');
switch ($config['storage']['driver']) {
case 'local':
return new Filesystem(new Local($config['storage']['path']));
case 's3':
$client = new S3Client([
'credentials' => [
'key' => $config['storage']['key'],
'secret' => $config['storage']['secret'],
],
'region' => $config['storage']['region'],
'version' => 'latest',
]);
$view->getEnvironment()->addGlobal('config', $config);
$view->getEnvironment()->addGlobal('request', $container->get('request'));
$view->getEnvironment()->addGlobal('alerts', $container->get('session')->getAlert());
$view->getEnvironment()->addGlobal('session', $container->get('session')->all());
$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
return $view;
};
return new Filesystem(new AwsS3Adapter($client, $config['storage']['bucket'], $config['storage']['path']));
case 'dropbox':
$client = new DropboxClient($config['storage']['token']);
return new Filesystem(new DropboxAdapter($client), ['case_sensitive' => false]);
case 'ftp':
return new Filesystem(new FtpAdapter([
'host' => $config['storage']['host'],
'username' => $config['storage']['username'],
'password' => $config['storage']['password'],
'port' => $config['storage']['port'],
'root' => $config['storage']['path'],
'passive' => $config['storage']['passive'],
'ssl' => $config['storage']['ssl'],
'timeout' => 30,
]));
case 'google-cloud':
$client = new StorageClient([
'projectId' => $config['storage']['project_id'],
'keyFilePath' => $config['storage']['key_path'],
]);
return new Filesystem(new GoogleStorageAdapter($client, $client->bucket($config['storage']['bucket'])));
default:
throw new InvalidArgumentException('The driver specified is not supported.');
}
}),
$container['storage'] = function ($container) use (&$config) {
View::class => factory(function ($container) {
return ViewFactory::createInstallerInstance($container);
}),
]);
switch ($config['storage']['driver']) {
case 'local':
return new Filesystem(new Local($config['storage']['path']));
case 's3':
$client = new S3Client([
'credentials' => [
'key' => $config['storage']['key'],
'secret' => $config['storage']['secret'],
],
'region' => $config['storage']['region'],
'version' => 'latest',
]);
$app = Bridge::create($builder->build());
$app->addRoutingMiddleware();
$app->setBasePath('/install');
return new Filesystem(new AwsS3Adapter($client, $config['storage']['bucket'], $config['storage']['path']));
case 'dropbox':
$client = new DropboxClient($config['storage']['token']);
return new Filesystem(new DropboxAdapter($client), ['case_sensitive' => false]);
case 'ftp':
return new Filesystem(new FtpAdapter([
'host' => $config['storage']['host'],
'username' => $config['storage']['username'],
'password' => $config['storage']['password'],
'port' => $config['storage']['port'],
'root' => $config['storage']['path'],
'passive' => $config['storage']['passive'],
'ssl' => $config['storage']['ssl'],
'timeout' => 30,
]));
case 'google-cloud':
$client = new StorageClient([
'projectId' => $config['storage']['project_id'],
'keyFilePath' => $config['storage']['key_path'],
]);
return new Filesystem(new GoogleStorageAdapter($client, $client->bucket($config['storage']['bucket'])));
default:
throw new InvalidArgumentException('The driver specified is not supported.');
}
};
$app->get('/', function (Response $response, View $view, Session $session) {
function migrate($config) {
$firstMigrate = false;
if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__ . '/../' . $config['db']['dsn'])) {
touch(__DIR__ . '/../' . $config['db']['dsn']);
$firstMigrate = true;
}
if (!extension_loaded('gd')) {
$session->alert('The required "gd" extension is not loaded.', 'danger');
}
try {
DB::doQuery('SELECT 1 FROM `migrations` LIMIT 1');
} catch (PDOException $exception) {
$firstMigrate = true;
}
if (!extension_loaded('intl')) {
$session->alert('The required "intl" extension is not loaded.', 'danger');
}
if ($firstMigrate) {
DB::raw()->exec(file_get_contents(__DIR__ . '/../resources/schemas/migrations.sql'));
}
if (!extension_loaded('json')) {
$session->alert('The required "json" extension is not loaded.', 'danger');
}
$files = glob(__DIR__ . '/../resources/schemas/' . DB::driver() . '/*.sql');
if (!extension_loaded('fileinfo')) {
$session->alert('The required "fileinfo" extension is not loaded.', 'danger');
}
$names = array_map(function ($path) {
return basename($path);
}, $files);
if (!is_writable(__DIR__.'/../resources/cache')) {
$session->alert('The cache folder is not writable ('.__DIR__.'/../resources/cache'.')', 'danger');
}
$in = str_repeat('?, ', count($names) - 1) . '?';
if (!is_writable(__DIR__.'/../resources/database')) {
$session->alert('The database folder is not writable ('.__DIR__.'/../resources/database'.')', 'danger');
}
$inMigrationsTable = DB::doQuery("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
if (!is_writable(__DIR__.'/../resources/sessions')) {
$session->alert('The sessions folder is not writable ('.__DIR__.'/../resources/sessions'.')', 'danger');
}
$installed = file_exists(__DIR__.'/../config.php');
foreach ($files as $file) {
$continue = false;
$exists = false;
foreach ($inMigrationsTable as $migration) {
if (basename($file) === $migration->name && $migration->migrated) {
$continue = true;
break;
} else if (basename($file) === $migration->name && !$migration->migrated) {
$exists = true;
break;
}
}
if ($continue) continue;
$sql = file_get_contents($file);
try {
DB::raw()->exec($sql);
if (!$exists) {
DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
} else {
DB::doQuery('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
}
} catch (PDOException $exception) {
if (!$exists) {
DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
}
throw $exception;
}
}
}
$app = new App($container);
$app->get('/', function (Request $request, Response $response) {
if (!extension_loaded('gd')) {
$this->session->alert('The required "gd" extension is not loaded.', 'danger');
}
if (!extension_loaded('intl')) {
$this->session->alert('The required "intl" extension is not loaded.', 'danger');
}
if (!extension_loaded('json')) {
$this->session->alert('The required "json" extension is not loaded.', 'danger');
}
if (!is_writable(__DIR__ . '/../resources/cache')) {
$this->session->alert('The cache folder is not writable (' . __DIR__ . '/../resources/cache' . ')', 'danger');
}
if (!is_writable(__DIR__ . '/../resources/database')) {
$this->session->alert('The database folder is not writable (' . __DIR__ . '/../resources/database' . ')', 'danger');
}
if (!is_writable(__DIR__ . '/../resources/sessions')) {
$this->session->alert('The sessions folder is not writable (' . __DIR__ . '/../resources/sessions' . ')', 'danger');
}
$installed = file_exists(__DIR__ . '/../config.php');
return $this->view->render($response, 'install.twig', [
'installed' => $installed,
]);
return $view->render($response, 'install.twig', [
'installed' => $installed,
]);
});
$app->post('/', function (Request $request, Response $response) 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;
if (!file_exists(__DIR__ . '/../config.php')) {
$installed = false;
// Check if there is a previous installation, if not, setup the config file
$installed = true;
if (!file_exists(__DIR__.'/../config.php')) {
$installed = false;
// config file setup
$config['base_url'] = $request->getParam('base_url');
$config['storage']['driver'] = $request->getParam('storage_driver');
unset($config['displayErrorDetails']);
$config['db']['connection'] = $request->getParam('connection');
$config['db']['dsn'] = $request->getParam('dsn');
$config['db']['username'] = $request->getParam('db_user');
$config['db']['password'] = $request->getParam('db_password');
// config file setup
$config['base_url'] = param($request, 'base_url');
$config['storage']['driver'] = param($request, 'storage_driver');
unset($config['debug']);
$config['db']['connection'] = param($request, 'connection');
$config['db']['dsn'] = param($request, 'dsn');
$config['db']['username'] = param($request, 'db_user');
$config['db']['password'] = param($request, 'db_password');
// setup storage configuration
switch ($config['storage']['driver']) {
case 's3':
$config['storage']['key'] = $request->getParam('storage_key');
$config['storage']['secret'] = $request->getParam('storage_secret');
$config['storage']['region'] = $request->getParam('storage_region');
$config['storage']['bucket'] = $request->getParam('storage_bucket');
$config['storage']['path'] = $request->getParam('storage_path');
break;
case 'dropbox':
$config['storage']['token'] = $request->getParam('storage_token');
break;
case 'ftp':
$config['storage']['host'] = $request->getParam('storage_host');
$config['storage']['username'] = $request->getParam('storage_username');
$config['storage']['password'] = $request->getParam('storage_password');
$config['storage']['port'] = $request->getParam('storage_port');
$config['storage']['path'] = $request->getParam('storage_path');
$config['storage']['passive'] = $request->getParam('storage_passive') === '1';
$config['storage']['ssl'] = $request->getParam('storage_ssl') === '1';
break;
case 'google-cloud':
$config['storage']['project_id'] = $request->getParam('storage_project_id');
$config['storage']['key_path'] = $request->getParam('storage_key_path');
$config['storage']['bucket'] = $request->getParam('storage_bucket');
break;
case 'local':
default:
$config['storage']['path'] = $request->getParam('storage_path');
break;
}
// setup storage configuration
switch ($config['storage']['driver']) {
case 's3':
$config['storage']['key'] = param($request, 'storage_key');
$config['storage']['secret'] = param($request, 'storage_secret');
$config['storage']['region'] = param($request, 'storage_region');
$config['storage']['bucket'] = param($request, 'storage_bucket');
$config['storage']['path'] = param($request, 'storage_path');
break;
case 'dropbox':
$config['storage']['token'] = param($request, 'storage_token');
break;
case 'ftp':
$config['storage']['host'] = param($request, 'storage_host');
$config['storage']['username'] = param($request, 'storage_username');
$config['storage']['password'] = param($request, 'storage_password');
$config['storage']['port'] = param($request, 'storage_port');
$config['storage']['path'] = param($request, 'storage_path');
$config['storage']['passive'] = param($request, 'storage_passive') === '1';
$config['storage']['ssl'] = param($request, 'storage_ssl') === '1';
break;
case 'google-cloud':
$config['storage']['project_id'] = param($request, 'storage_project_id');
$config['storage']['key_path'] = param($request, 'storage_key_path');
$config['storage']['bucket'] = param($request, 'storage_bucket');
break;
case 'local':
default:
$config['storage']['path'] = param($request, 'storage_path');
break;
}
// check if the storage is valid
$storageTestFile = 'storage_test.xbackbone.txt';
try {
try {
$success = $this->storage->write($storageTestFile, 'XBACKBONE_TEST_FILE');
} catch (FileExistsException $fileExistsException) {
$success = $this->storage->update($storageTestFile, 'XBACKBONE_TEST_FILE');
}
// check if the storage is valid
$storageTestFile = 'storage_test.xbackbone.txt';
try {
try {
$success = $storage->write($storageTestFile, 'XBACKBONE_TEST_FILE');
} catch (FileExistsException $fileExistsException) {
$success = $storage->update($storageTestFile, 'XBACKBONE_TEST_FILE');
}
if (!$success) {
throw new Exception('The storage is not writable.');
}
$this->storage->readAndDelete($storageTestFile);
} catch (Exception $e) {
$this->session->alert("Storage setup error: {$e->getMessage()} [{$e->getCode()}]", 'danger');
return redirect($response, '/install');
}
if (!$success) {
throw new Exception('The storage is not writable.');
}
$storage->readAndDelete($storageTestFile);
} catch (Exception $e) {
$session->alert("Storage setup error: {$e->getMessage()} [{$e->getCode()}]", 'danger');
return redirect($response, '/install');
}
$ret = file_put_contents(__DIR__ . '/../config.php', '<?php' . PHP_EOL . 'return ' . var_export($config, true) . ';');
if ($ret === false) {
$this->session->alert('The config folder is not writable (' . __DIR__ . '/../config.php' . ')', 'danger');
return redirect($response, '/install');
}
}
$ret = file_put_contents(__DIR__.'/../config.php', '<?php'.PHP_EOL.'return '.var_export($config, true).';');
if ($ret === false) {
$session->alert('The config folder is not writable ('.__DIR__.'/../config.php'.')', 'danger');
return redirect($response, '/install');
}
}
// if from older installations with no support of other than local driver
// update the config
if ($installed && isset($config['storage_dir'])) {
$config['storage']['driver'] = 'local';
$config['storage']['path'] = $config['storage_dir'];
unset($config['storage_dir']);
}
// if from older installations with no support of other than local driver
// update the config
if ($installed && isset($config['storage_dir'])) {
$config['storage']['driver'] = 'local';
$config['storage']['path'] = $config['storage_dir'];
unset($config['storage_dir']);
}
// Build the dns string and run the migrations
try {
// Build the dns string and run the migrations
try {
$dsn = $config['db']['connection'] === 'sqlite' ? __DIR__ . '/../' . $config['db']['dsn'] : $config['db']['dsn'];
DB::setDsn($config['db']['connection'] . ':' . $dsn, $config['db']['username'], $config['db']['password']);
$firstMigrate = false;
if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__.'/../'.$config['db']['dsn'])) {
touch(__DIR__.'/../'.$config['db']['dsn']);
$firstMigrate = true;
}
migrate($config);
} catch (PDOException $e) {
$this->session->alert("Cannot connect to the database: {$e->getMessage()} [{$e->getCode()}]", 'danger');
return redirect($response, '/install');
}
$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']);
// if not installed, create the default admin account
if (!$installed) {
DB::doQuery("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES (?, 'admin', ?, 1, ?)", [$request->getParam('email'), password_hash($request->getParam('password'), PASSWORD_DEFAULT), humanRandomString(5)]);
}
$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, '/install');
}
// post install cleanup
cleanDirectory(__DIR__ . '/../resources/cache');
cleanDirectory(__DIR__ . '/../resources/sessions');
// if not installed, create the default admin account
if (!$installed) {
$db->query("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES (?, 'admin', ?, 1, ?)", [param($request, 'email'), password_hash(param($request, 'password'), PASSWORD_DEFAULT), humanRandomString(5)]);
}
removeDirectory(__DIR__ . '/../install');
// post install cleanup
cleanDirectory(__DIR__.'/../resources/cache');
cleanDirectory(__DIR__.'/../resources/sessions');
// if is upgrading and existing installation, put it out maintenance
if ($installed) {
unset($config['maintenance']);
removeDirectory(__DIR__.'/../install');
$ret = file_put_contents(__DIR__ . '/../config.php', '<?php' . PHP_EOL . 'return ' . var_export($config, true) . ';');
if ($ret === false) {
$this->session->alert('The config folder is not writable (' . __DIR__ . '/../config.php' . ')', 'danger');
return redirect($response, '/install');
}
}
// if is upgrading and existing installation, put it out maintenance
if ($installed) {
unset($config['maintenance']);
// Installed successfully, destroy the installer session
session_destroy();
return $response->withRedirect("{$config['base_url']}/?afterInstall=true");
$ret = file_put_contents(__DIR__.'/../config.php', '<?php'.PHP_EOL.'return '.var_export($config, true).';');
if ($ret === false) {
$session->alert('The config folder is not writable ('.__DIR__.'/../config.php'.')', 'danger');
return redirect($response, '/install');
}
}
// Installed successfully, destroy the installer session
session_destroy();
return redirect($response, "{$config['base_url']}/?afterInstall=true");
});
$app->run();

View file

@ -96,10 +96,7 @@ return [
'maintenance_in_progress' => 'Platform under maintenance, try again later...',
'cancel' => 'Cancel',
'auto_set' => 'Set automatically',
'translated_strings' => 'translated strings',
'total_strings' => 'total strings',
'lang_name' => 'language name',
'default_lang_behavior' => 'XBackBone will try to match the browser language by default (fallback is English).',
'default_lang_behavior' => 'XBackBone will try to match the browser language by default (the fallback is English).',
'lang_set' => 'System language enforced to "%s"',
'prerelease_channel' => 'Prerelease Channel',
];

View file

@ -96,10 +96,7 @@ return [
'cancel' => 'Annulla',
'enforce_language' => 'Imponi lingua',
'auto_set' => 'Imposta automaticamente',
'translated_strings' => 'stringhe tradotte',
'total_strings' => 'stringhe totali',
'lang_name' => 'nome della lingua',
'default_lang_behavior' => 'Per impostazione predefinita, XBackbone cercherà di abbinare la lingua del browser (il fallback è l\'inglese).',
'default_lang_behavior' => 'Per impostazione predefinita, XBackbone cercherà di abbinare la lingua del browser (il fallback è l\'Inglese).',
'lang_set' => 'Lingua di sistema applicata a "%s"',
'prerelease_channel' => 'Canale prerelease',
];

View file

@ -87,7 +87,7 @@
<option value="{{ lang }}">{{ name }}</option>
{% endfor %}
</select>
<small>[{{ lang('translated_strings') }} / {{ lang('total_strings') }}] {{ lang('lang_name') }}. {{ lang('default_lang_behavior') }}</small>
<small>{{ lang('default_lang_behavior') }}</small>
</div>
</div>
<div class="form-group row">