. * */ namespace Vvveb\Controller; use function Vvveb\__; use function Vvveb\installedLanguages; use function Vvveb\session as sess; use function Vvveb\setLanguage; use Vvveb\Sql\LanguageSQL; use Vvveb\Sql\menuSQL; use Vvveb\Sql\RoleSQL; use Vvveb\Sql\SiteSQL; use Vvveb\System\Core\View; use Vvveb\System\Extensions\Plugins; use Vvveb\System\Extensions\Themes as ThemesList; use Vvveb\System\Functions\Str; use Vvveb\System\Media\Image; use Vvveb\System\User\Admin; use function Vvveb\userPreferedLanguage; define('REQUIRED_EXTENSIONS', ['mysqli', 'mysqlnd', 'xml', 'libxml', 'pcre', 'zip', 'dom', 'curl', 'gettext']); define('WRITABLE_FOLDERS', ['storage', 'storage/cache', 'storage/model', 'storage/compiled-templates', 'config', 'config/sites.php', 'public/media/', 'public/themes', 'public/image-cache', 'plugins']); define('MIN_PHP_VERSION', '7.4.0'); define('DEFAULT_LANG', 'en_US'); #[\AllowDynamicProperties] class Index extends Base { private $config = ['engine' => 'mysqli', 'host' => '127.0.0.1', 'database' => 'vvveb', 'user' => 'root', 'password' => '', 'port' => null, 'prefix' => '']; private $subdir = ''; function __construct() { if (! ($lang = sess('language'))) { $lang = userPreferedLanguage(); if ($lang) { sess(['language' => $lang, 'language_id' => 1]); } } if ($lang) { setLanguage($lang); } $this->subdir = (V_SUBDIR_INSTALL ? V_SUBDIR_INSTALL : \Vvveb\detectSubDir()); if (\Vvveb\is_installed()) { $admin = false; $message = ''; try { //check if super admin user is available $admin = Admin::get(['role_id' => 1]); } catch (\Exception $e) { $this->view = View :: getInstance(); $message = __('Missing admin table or data, remove config/db.php to reinstall!') . "\n\n" . $e->getMessage(); $this->view->info[] = $message; //die($message); } if ($admin && isset($admin['status']) && $admin['status'] == '1') { $this->redirect($this->subdir . '/'); die(__('Already installed! To reinstall remove config/db.php') . "\n"); } else { if (! $admin || ! isset($admin['role_id']) || $admin['role_id'] != '1') { $message .= __('Invalid installation. No user with "super admin" role found!'); $this->view = View :: getInstance(); $this->view->info[] = $message; } } } } private function checkRequirements() { $notMet = []; if (version_compare(PHP_VERSION, MIN_PHP_VERSION) < 0) { $notMet[] = sprintf(__('You need at least PHP %s , your current version %s'), MIN_PHP_VERSION, PHP_VERSION); } foreach (REQUIRED_EXTENSIONS as $extension) { if (! extension_loaded($extension)) { $notMet[] = sprintf(__('PHP extension %s is not installed'), $extension); } } foreach (WRITABLE_FOLDERS as $folder) { $path = DIR_ROOT . $folder; if (! is_writable($path) && ! @chmod($path, 0750)) { $notMet[] = sprintf(__('"%s" is not writable'), $folder); } } return $notMet; } function replaceInFile($file, $search, $replace) { $content = file_get_contents($file); if ($content) { $content = str_replace($search, $replace, $content); return file_put_contents($file, $content); } } private function writeConfig($data) { return \Vvveb\setConfig('db', $data); $configFile = DIR_ROOT . 'config/db.php'; file_put_contents($configFile, "config; array_walk($this->request->post, function ($value, $key) use (&$config) { if (isset($config[$key])) { $config[$key] = $value; } }); $config['engine'] = $config['engine'] ? $config['engine'] : 'mysqli'; if ($config['engine'] == 'sqlite') { $config['host'] = DIR_STORAGE . 'sqlite/vvveb.db'; } extract($config); $prefix = $prefix ?? ''; $data['default'] = $config['engine']; $data['connections'][$engine] = $config; try { if (! defined('DB_ENGINE')) { define('DB_ENGINE', $engine); define('DB_HOST', $host); define('DB_USER', $user); define('DB_PASS', $password); define('DB_NAME', $database); define('DB_PREFIX', $prefix); define('DB_PORT', $port); define('DIR_SQL', DIR_APP . 'sql/' . DB_ENGINE . '/'); } $import = new \Vvveb\System\Import\Sql($engine, $host, $database, $user, $password, $port, $prefix); //$import->createDb($database); if ($engine == 'mysqli') { $import->createDb($database); } $import->setPath(DIR_ROOT . "install/sql/$engine/schema/"); $import->createTables(); if ($noimport) { $exclude = ['post*', 'product*', 'vendor*', 'manufacturer*', 'taxonomy_*', 'attribute*', 'option*', 'user.sql', 'comment*', 'digital_asset*']; } else { $exclude = []; } $import->setPath(DIR_ROOT . 'install/sql/insert/'); $import->insertData([], $exclude); //$import->db->close(); $this->writeConfig($data); $this->redirect(($_SERVER['REQUEST_URI'] ?? 'localhost') . '?action=install'); } catch (\Exception $e) { $this->view->errors[] = sprintf(__('Db error: "%s" Error code: "%s"'), $e->getMessage(), $e->getCode()); } } function index() { $requirements = $this->checkRequirements(); $noimport = $this->request->post['noimport'] ?? false; if ($requirements) { $this->view->requirements = $requirements; } \Vvveb\System\CacheManager::clearFrontend(); //get defaults from get parameters if passed or from env if available foreach ($this->config as $key => &$value) { $env = 'DB_' . strtoupper($key); if (isset($_ENV[$env])) { $value = $_ENV[$env]; } if (isset($this->request->get[$key])) { $value = $this->request->get[$key]; } } if ($this->request->post) { if (isset($this->request->post['language'])) { $lang = $this->request->post['language']; sess(['language' => $lang, 'language_id' => 1]); setLanguage($lang); } else { $this->import($noimport); //if user data is provided (by CLI) run also step2 if (isset($this->request->post['admin'])) { $this->install(); } } } $installedLanguages = [DEFAULT_LANG => '0'] + array_flip(installedLanguages()); $languagesList = include DIR_SYSTEM . 'data/languages-list.php'; $languages = array_intersect_key($languagesList, $installedLanguages); $this->view->config = $this->config; if (! defined('CLI')) { $this->view->languagesList = $languages; $this->view->currentLanguage = sess('language') ?? DEFAULT_LANG; } } function install() { if (! defined('CLI')) { $themes = ThemesList :: getList(); $this->view->themes = $themes; $this->view->count = count($themes); } $isRootPublic = (constant('PUBLIC_PATH') == DIRECTORY_SEPARATOR) ? 'true' : 'false'; $this->view->isRootPublic = $isRootPublic; $languagesList = include DIR_SYSTEM . 'data/languages-list.php'; if (! defined('CLI')) { $this->view->languagesList = $languagesList; $this->view->currentLanguage = sess('language') ?? DEFAULT_LANG; } if ($this->request->post) { //set admin password $user = $this->request->post['admin'] ?? []; $settings = $this->request->post['settings'] ?? []; $theme = $this->request->post['theme'] ?? 'landing'; $noecommerce = $this->request->post['noecommerce'] ?? false; $hostname = $this->request->post['hostname'] ?? null; $adminPath = $this->request->post['admin-path'] ?? false; $language = $this->request->post['language'] ?? 'en_US'; $user['status'] = 1; $result = Admin::update($user, ['username' => 'admin']); $sites = new SiteSQL(); //$result = \Vvveb\setMultiSetting('site',$settings); if ($noecommerce) { Plugins::activate('hide-ecommerce', 1); } //set default website url $sites = new SiteSQL(); $siteSettings = $sites->get(['site_id' => 1]); $hasSiteSettings = false; if (is_array($settings) && is_array($siteSettings)) { $hasSiteSettings = true; $data = json_decode($siteSettings['settings'], true) ?? []; $settings = $settings + $data; } $settings['admin-email'] = $user['email']; $settings['contact-email'] = $user['email']; if (Image::formats('webp')) { $settings['image_format'] = 'webp'; } $site = [ 'host' => $hostname ?? '*.*.*', //$_SERVER['HTTP_HOST'] 'site_id' => 1, 'id' => 1, 'name' => 'Default', 'theme' => $theme, 'settings' => json_encode($settings), ]; if ($hasSiteSettings) { $sites->edit(['site' => $site, 'site_id' => 1]); } else { //empty installation $site['site_id'] = 1; $site['key'] = '* * *'; $site['name'] = 'default'; $sites->add(['site' => $site]); $role = new RoleSQL(); $role->add(['role' => [ 'role_id' => 1, 'name' => 'super_admin', 'display_name' => 'Super Administrator', 'permissions' => '{"allow":["*"], "deny":[]}', ]]); $languageModel = new LanguageSQL(); $languageModel->add(['language' => [ 'language_id' => 1, 'name' => 'English', 'code' => 'en_US', 'locale' => 'en-us', 'slug' => 'en', 'status' => 1, 'default' => 1, ]]); } unset($site['settings']); @\Vvveb\setConfig('sites.* * *', $site); $lang = $language ?? sess('language') ?? 'en_US'; //set default language if ($lang && $lang != 'en_US') { $languageModel = new LanguageSQL(); $language = $languagesList[$lang]; $language['name'] = preg_replace('/$(\w+).*/', '$1', $language['name']); $language['locale'] = $language['code']; $language['code'] = $lang; $language['status'] = 1; //$installed = $languageModel->get(['code' => $lang]); $result = $languageModel->edit(['language' => $language, 'language_id' => 1]); sess(['language' => $lang, 'language_id' => 1]); setLanguage($lang); } $error = ''; //change admin login path if ($isRootPublic && $adminPath && ($adminPath != 'admin' && $adminPath != 'vadmin')) { $from = DIR_PUBLIC . 'vadmin'; $to = DIR_PUBLIC . $adminPath; if (@rename($from, $to)) { @\Vvveb\setConfig('admin.path', $adminPath); //if succesful remove failsafe /admin login option @unlink(DIR_PUBLIC . 'admin' . DS . 'index.php'); } else { $error = sprintf(__('Renaming admin login path from %s to %s failed! use /admin/index.php path to login'), 'vadmin', $adminPath); } } @\Vvveb\setConfig('app.cronkey', Str::random(32)); @\Vvveb\setConfig('app.key', Str::random(32)); //set APCu memory cache if available instead of default file cache $cacheDriver = (function_exists('apcu_cache_info') && ini_get('apc.enabled')) ? 'APCu' : null; foreach (['app', 'admin', 'graphql', 'rest'] as $app) { if ($cacheDriver) { @\Vvveb\setConfig($app . '.cache.driver', $cacheDriver); } @\Vvveb\setConfig($app . '.cronkey', Str::random(32)); @\Vvveb\setConfig($app . '.key', Str::random(32)); } $subdir = $this->request->post['subdir'] ?? $this->subdir ?? false; if ($subdir) { $subdir = '/' . trim($subdir, '/ '); //add subdir path to menu links $menus = new menuSQL(); foreach ([1, 5] as $menu_id) { //main menu and footer menu id's $menuItems = $menus->get(['menu_id' => $menu_id, 'language_id' => 1])['menu'] ?? []; foreach ($menuItems as $menuItem) { $data = ['url' => $this->subdir . $menuItem['url'], 'menu_item_content' => []]; $menus->editMenuItem(['menu_item' => $data, 'menu_item_id' => $menuItem['menu_item_id']]); } } //try to set subdir in env.php and .htaccess $this->replaceInFile(DIR_ROOT . 'env.php', "define('V_SUBDIR_INSTALL', false" , "define('V_SUBDIR_INSTALL', '{$subdir}'"); $this->replaceInFile(DIR_ROOT . '.htaccess', 'RewriteRule ^ index.php [L]' , "RewriteRule ^ {$subdir}/index.php [L]"); } if ($error) { $this->view->error[] = $error; } //admin auto login if (! defined('CLI')) { $adminInfo = Admin::get(['admin_id' => 1]); if ($adminInfo) { \Vvveb\session(['admin' => $adminInfo]); } } $success = __('Installation succesful!'); $this->view->success[] = $success; $admin_path = \Vvveb\adminPath(); $admin_path = str_replace($this->subdir, '', $admin_path); $location = preg_replace('@/install.*$@', $admin_path . "/index.php?module=settings/site&site_id=1&success=$success&errors=$error#description", ($_SERVER['REQUEST_URI'] ?? '')); $this->redirect($location); } $this->view->template('install.html'); } }