1
1
Fork 0

Merge pull request #6041 from nupplaphil/install_to_module

Install to Module
This commit is contained in:
Hypolite Petovan 2018-10-30 08:17:26 -04:00 committed by GitHub
commit f7147fae96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 491 additions and 402 deletions

View file

@ -1,271 +0,0 @@
<?php
/**
* @file mod/install.php
*/
use Friendica\App;
use Friendica\Core\Install;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Util\Temporal;
$install_wizard_pass = 1;
function install_init(App $a) {
// $baseurl/install/testrwrite to test if rewite in .htaccess is working
if ($a->argc == 2 && $a->argv[1] == "testrewrite") {
echo "ok";
killme();
}
// We overwrite current theme css, because during install we could not have a working mod_rewrite
// so we could not have a css at all. Here we set a static css file for the install procedure pages
$a->setConfigValue('system', 'value', '../install');
$a->theme['stylesheet'] = System::baseUrl()."/view/install/style.css";
global $install_wizard_pass;
if (x($_POST, 'pass')) {
$install_wizard_pass = intval($_POST['pass']);
}
}
function install_post(App $a) {
global $install_wizard_pass;
switch($install_wizard_pass) {
case 1:
case 2:
return;
break; // just in case return don't return :)
case 3:
$dbhost = notags(trim($_POST['dbhost']));
$dbuser = notags(trim($_POST['dbuser']));
$dbpass = notags(trim($_POST['dbpass']));
$dbdata = notags(trim($_POST['dbdata']));
$phpath = notags(trim($_POST['phpath']));
require_once("include/dba.php");
if (!DBA::connect($dbhost, $dbuser, $dbpass, $dbdata)) {
$a->data['db_conn_failed'] = true;
}
return;
break;
case 4:
$urlpath = $a->getURLPath();
$dbhost = notags(trim($_POST['dbhost']));
$dbuser = notags(trim($_POST['dbuser']));
$dbpass = notags(trim($_POST['dbpass']));
$dbdata = notags(trim($_POST['dbdata']));
$phpath = notags(trim($_POST['phpath']));
$timezone = notags(trim($_POST['timezone']));
$language = notags(trim($_POST['language']));
$adminmail = notags(trim($_POST['adminmail']));
// connect to db
DBA::connect($dbhost, $dbuser, $dbpass, $dbdata);
$install = new Install();
$errors = $install->createConfig($phpath, $urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $timezone, $language, $adminmail, $a->getBasePath());
if ($errors !== true) {
$a->data['data'] = $errors;
return;
}
$errors = DBStructure::update(false, true, true);
if ($errors) {
$a->data['db_failed'] = $errors;
} else {
$a->data['db_installed'] = true;
}
return;
break;
}
}
function install_content(App $a) {
global $install_wizard_pass;
$o = '';
$wizard_status = "";
$install_title = L10n::t('Friendica Communications Server - Setup');
if (x($a->data, 'db_conn_failed')) {
$install_wizard_pass = 2;
$wizard_status = L10n::t('Could not connect to database.');
}
if (x($a->data, 'db_create_failed')) {
$install_wizard_pass = 2;
$wizard_status = L10n::t('Could not create table.');
}
$db_return_text = "";
if (x($a->data, 'db_installed')) {
$txt = '<p style="font-size: 130%;">';
$txt .= L10n::t('Your Friendica site database has been installed.') . EOL;
$db_return_text .= $txt;
}
if (x($a->data, 'db_failed')) {
$txt = L10n::t('You may need to import the file "database.sql" manually using phpmyadmin or mysql.') . EOL;
$txt .= L10n::t('Please see the file "INSTALL.txt".') . EOL ."<hr>";
$txt .= "<pre>".$a->data['db_failed'] . "</pre>". EOL;
$db_return_text .= $txt;
}
if (DBA::$connected) {
$r = q("SELECT COUNT(*) as `total` FROM `user`");
if (DBA::isResult($r) && $r[0]['total']) {
$install_wizard_pass = 2;
$wizard_status = L10n::t('Database already in use.');
}
}
if (x($a->data, 'txt') && strlen($a->data['txt'])) {
$db_return_text .= manual_config($a);
}
if ($db_return_text != "") {
$tpl = get_markup_template('install.tpl');
return replace_macros($tpl, [
'$title' => $install_title,
'$pass' => "",
'$text' => $db_return_text . what_next(),
]);
}
switch ($install_wizard_pass) {
case 1: { // System check
$phpath = defaults($_POST, 'phpath', 'php');
$install = new Install($phpath);
$status = $install->checkAll($a->getBasePath(), $a->getBaseURL());
$tpl = get_markup_template('install_checks.tpl');
$o .= replace_macros($tpl, [
'$title' => $install_title,
'$pass' => L10n::t('System check'),
'$checks' => $install->getChecks(),
'$passed' => $status,
'$see_install' => L10n::t('Please see the file "INSTALL.txt".'),
'$next' => L10n::t('Next'),
'$reload' => L10n::t('Check again'),
'$phpath' => $phpath,
'$baseurl' => $a->getBaseURL(),
]);
return $o;
}; break;
case 2: { // Database config
$dbhost = notags(trim(defaults($_POST, 'dbhost' , 'localhost')));
$dbuser = notags(trim(defaults($_POST, 'dbuser' , '' )));
$dbpass = notags(trim(defaults($_POST, 'dbpass' , '' )));
$dbdata = notags(trim(defaults($_POST, 'dbdata' , '' )));
$phpath = notags(trim(defaults($_POST, 'phpath' , '' )));
$adminmail = notags(trim(defaults($_POST, 'adminmail', '' )));
$tpl = get_markup_template('install_db.tpl');
$o .= replace_macros($tpl, [
'$title' => $install_title,
'$pass' => L10n::t('Database connection'),
'$info_01' => L10n::t('In order to install Friendica we need to know how to connect to your database.'),
'$info_02' => L10n::t('Please contact your hosting provider or site administrator if you have questions about these settings.'),
'$info_03' => L10n::t('The database you specify below should already exist. If it does not, please create it before continuing.'),
'$status' => $wizard_status,
'$dbhost' => ['dbhost', L10n::t('Database Server Name'), $dbhost, '', 'required'],
'$dbuser' => ['dbuser', L10n::t('Database Login Name'), $dbuser, '', 'required', 'autofocus'],
'$dbpass' => ['dbpass', L10n::t('Database Login Password'), $dbpass, L10n::t("For security reasons the password must not be empty"), 'required'],
'$dbdata' => ['dbdata', L10n::t('Database Name'), $dbdata, '', 'required'],
'$adminmail' => ['adminmail', L10n::t('Site administrator email address'), $adminmail, L10n::t('Your account email address must match this in order to use the web admin panel.'), 'required', 'autofocus', 'email'],
'$lbl_10' => L10n::t('Please select a default timezone for your website'),
'$baseurl' => $a->getBaseURL(),
'$phpath' => $phpath,
'$submit' => L10n::t('Submit'),
]);
return $o;
}; break;
case 3: { // Site settings
$dbhost = ((x($_POST, 'dbhost')) ? notags(trim($_POST['dbhost'])) : 'localhost');
$dbuser = notags(trim($_POST['dbuser']));
$dbpass = notags(trim($_POST['dbpass']));
$dbdata = notags(trim($_POST['dbdata']));
$phpath = notags(trim($_POST['phpath']));
$adminmail = notags(trim($_POST['adminmail']));
$timezone = ((x($_POST, 'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles');
/* Installed langs */
$lang_choices = L10n::getAvailableLanguages();
$tpl = get_markup_template('install_settings.tpl');
$o .= replace_macros($tpl, [
'$title' => $install_title,
'$pass' => L10n::t('Site settings'),
'$status' => $wizard_status,
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$phpath' => $phpath,
'$adminmail' => ['adminmail', L10n::t('Site administrator email address'), $adminmail, L10n::t('Your account email address must match this in order to use the web admin panel.'), 'required', 'autofocus', 'email'],
'$timezone' => Temporal::getTimezoneField('timezone', L10n::t('Please select a default timezone for your website'), $timezone, ''),
'$language' => ['language', L10n::t('System Language:'), 'en', L10n::t('Set the default language for your Friendica installation interface and to send emails.'), $lang_choices],
'$baseurl' => $a->getBaseURL(),
'$submit' => L10n::t('Submit'),
]);
return $o;
}; break;
}
}
function manual_config(App $a) {
$data = htmlentities($a->data['txt'],ENT_COMPAT, 'UTF-8');
$o = L10n::t('The database configuration file "config/local.ini.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.');
$o .= "<textarea rows=\"24\" cols=\"80\" >$data</textarea>";
return $o;
}
function load_database_rem($v, $i) {
$l = trim($i);
if (strlen($l)>1 && ($l[0] == "-" || ($l[0] == "/" && $l[1] == "*"))) {
return $v;
} else {
return $v."\n".$i;
}
}
function what_next() {
$baseurl = System::baseUrl();
return
L10n::t('<h1>What next</h1>')
."<p>".L10n::t('IMPORTANT: You will need to [manually] setup a scheduled task for the worker.')
.L10n::t('Please see the file "INSTALL.txt".')
."</p><p>"
.L10n::t('Go to your new Friendica node <a href="%s/register">registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.', $baseurl)
."</p>";
}

View file

@ -505,6 +505,7 @@ class App
$relative_script_path = defaults($_SERVER, 'REDIRECT_URI' , $relative_script_path); $relative_script_path = defaults($_SERVER, 'REDIRECT_URI' , $relative_script_path);
$relative_script_path = defaults($_SERVER, 'REDIRECT_SCRIPT_URL', $relative_script_path); $relative_script_path = defaults($_SERVER, 'REDIRECT_SCRIPT_URL', $relative_script_path);
$relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path); $relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path);
$relative_script_path = defaults($_SERVER, 'REQUEST_URI' , $relative_script_path);
$this->urlPath = $this->getConfigValue('system', 'urlpath'); $this->urlPath = $this->getConfigValue('system', 'urlpath');

View file

@ -5,7 +5,7 @@ namespace Friendica\Core\Console;
use Asika\SimpleConsole\Console; use Asika\SimpleConsole\Console;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Install; use Friendica\Core\Installer;
use Friendica\Core\Theme; use Friendica\Core\Theme;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Database\DBStructure; use Friendica\Database\DBStructure;
@ -76,7 +76,21 @@ HELP;
$a = BaseObject::getApp(); $a = BaseObject::getApp();
$install = new Install(); $installer = new Installer();
$this->out(" Complete!\n\n");
// Check Environment
$this->out("Checking environment...\n");
$installer->resetChecks();
if (!$this->runBasicChecks($installer)) {
$errorMessage = $this->extractErrors($installer->getChecks());
throw new RuntimeException($errorMessage);
}
$this->out(" Complete!\n\n");
// if a config file is set, // if a config file is set,
$config_file = $this->getOption(['f', 'file']); $config_file = $this->getOption(['f', 'file']);
@ -111,7 +125,11 @@ HELP;
$tz = $this->getOption(['T', 'tz'], (!empty('FRIENDICA_TZ')) ? getenv('FRIENDICA_TZ') : ''); $tz = $this->getOption(['T', 'tz'], (!empty('FRIENDICA_TZ')) ? getenv('FRIENDICA_TZ') : '');
$lang = $this->getOption(['L', 'lang'], (!empty('FRIENDICA_LANG')) ? getenv('FRIENDICA_LANG') : ''); $lang = $this->getOption(['L', 'lang'], (!empty('FRIENDICA_LANG')) ? getenv('FRIENDICA_LANG') : '');
$install->createConfig( if (empty($php_path)) {
$php_path = $installer->getPHPPath();
}
$installer->createConfig(
$php_path, $php_path,
$url_path, $url_path,
((!empty($db_port)) ? $db_host . ':' . $db_port : $db_host), ((!empty($db_port)) ? $db_host . ':' . $db_port : $db_host),
@ -127,30 +145,13 @@ HELP;
$this->out(" Complete!\n\n"); $this->out(" Complete!\n\n");
// Check basic setup
$this->out("Checking basic setup...\n");
$checkResults = [];
$this->runBasicChecks($install);
$checkResults['basic'] = $install->getChecks();
$errorMessage = $this->extractErrors($checkResults['basic']);
if ($errorMessage !== '') {
throw new RuntimeException($errorMessage);
}
$this->out(" Complete!\n\n");
// Check database connection // Check database connection
$this->out("Checking database...\n"); $this->out("Checking database...\n");
$checkResults['db'] = array(); $installer->resetChecks();
$checkResults['db'][] = $this->runDatabaseCheck($db_host, $db_user, $db_pass, $db_data);
$errorMessage = $this->extractErrors($checkResults['db']);
if ($errorMessage !== '') { if (!$installer->checkDB($db_host, $db_user, $db_pass, $db_data)) {
$errorMessage = $this->extractErrors($installer->getChecks());
throw new RuntimeException($errorMessage); throw new RuntimeException($errorMessage);
} }
@ -159,10 +160,11 @@ HELP;
// Install database // Install database
$this->out("Inserting data into database...\n"); $this->out("Inserting data into database...\n");
$checkResults['data'] = DBStructure::update(false, true, true); $installer->resetChecks();
if ($checkResults['data'] !== '') { if (!$installer->installDatabase()) {
throw new RuntimeException("ERROR: DB Database creation error. Is the DB empty?\n"); $errorMessage = $this->extractErrors($installer->getChecks());
throw new RuntimeException($errorMessage);
} }
$this->out(" Complete!\n\n"); $this->out(" Complete!\n\n");
@ -182,52 +184,43 @@ HELP;
} }
/** /**
* @param Install $install the Installer instance * @param Installer $installer the Installer instance
*
* @return bool true if checks were successfully, otherwise false
*/ */
private function runBasicChecks(Install $install) private function runBasicChecks(Installer $installer)
{ {
$install->resetChecks(); $checked = true;
$install->checkFunctions();
$install->checkImagick();
$install->checkLocalIni();
$install->checkSmarty3();
$install->checkKeys();
$installer->resetChecks();
if (!$installer->checkFunctions()) {
$checked = false;
}
if (!$installer->checkImagick()) {
$checked = false;
}
if (!$installer->checkLocalIni()) {
$checked = false;
}
if (!$installer->checkSmarty3()) {
$checked = false;
}
if (!$installer->checkKeys()) {
$checked = false;
}
$php_path = null;
if (!empty(Config::get('config', 'php_path'))) { if (!empty(Config::get('config', 'php_path'))) {
if (!$install->checkPHP(Config::get('config', 'php_path'), true)) { $php_path = Config::get('config', 'php_path');
throw new RuntimeException(" ERROR: The php_path is not valid in the config.\n"); }
}
} else { if (!$installer->checkPHP($php_path, true)) {
throw new RuntimeException(" ERROR: The php_path is not set in the config.\n"); $checked = false;
} }
$this->out(" NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.\n"); $this->out(" NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.\n");
}
/** return $checked;
* @param $db_host
* @param $db_user
* @param $db_pass
* @param $db_data
*
* @return array
*/
private function runDatabaseCheck($db_host, $db_user, $db_pass, $db_data)
{
$result = array(
'title' => 'MySQL Connection',
'required' => true,
'status' => true,
'help' => '',
);
if (!DBA::connect($db_host, $db_user, $db_pass, $db_data)) {
$result['status'] = false;
$result['help'] = 'Failed, please check your MySQL settings and credentials.';
}
return $result;
} }
/** /**

View file

@ -6,19 +6,31 @@ namespace Friendica\Core;
use DOMDocument; use DOMDocument;
use Exception; use Exception;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Object\Image; use Friendica\Object\Image;
use Friendica\Util\Network; use Friendica\Util\Network;
/** /**
* Contains methods for installation purpose of Friendica * Contains methods for installation purpose of Friendica
*/ */
class Install class Installer
{ {
// Default values for the install page
const DEFAULT_LANG = 'en';
const DEFAULT_TZ = 'America/Los_Angeles';
const DEFAULT_HOST = 'localhost';
/** /**
* @var array the check outcomes * @var array the check outcomes
*/ */
private $checks; private $checks;
/**
* @var string The path to the PHP binary
*/
private $phppath = null;
/** /**
* Returns all checks made * Returns all checks made
* *
@ -29,6 +41,22 @@ class Install
return $this->checks; return $this->checks;
} }
/**
* Returns the PHP path
*
* @return string the PHP Path
*/
public function getPHPPath()
{
// if not set, determine the PHP path
if (!isset($this->phppath)) {
$this->checkPHP();
$this->resetChecks();
}
return $this->phppath;
}
/** /**
* Resets all checks * Resets all checks
*/ */
@ -49,13 +77,12 @@ class Install
/** /**
* Checks the current installation environment. There are optional and mandatory checks. * Checks the current installation environment. There are optional and mandatory checks.
* *
* @param string $basepath The basepath of Friendica
* @param string $baseurl The baseurl of Friendica * @param string $baseurl The baseurl of Friendica
* @param string $phpath Optional path to the PHP binary * @param string $phpath Optional path to the PHP binary
* *
* @return bool if the check succeed * @return bool if the check succeed
*/ */
public function checkAll($basepath, $baseurl, $phpath = null) public function checkEnvironment($baseurl, $phpath = null)
{ {
$returnVal = true; $returnVal = true;
@ -85,7 +112,7 @@ class Install
$returnVal = false; $returnVal = false;
} }
if (!$this->checkHtAccess($basepath, $baseurl)) { if (!$this->checkHtAccess($baseurl)) {
$returnVal = false; $returnVal = false;
} }
@ -108,12 +135,12 @@ class Install
* @param string $adminmail Mail-Adress of the administrator * @param string $adminmail Mail-Adress of the administrator
* @param string $basepath The basepath of Friendica * @param string $basepath The basepath of Friendica
* *
* @return bool|string true if the config was created, the text if something went wrong * @return bool true if the config was created, otherwise false
*/ */
public function createConfig($phppath, $urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $timezone, $language, $adminmail, $basepath) public function createConfig($phppath, $urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $timezone, $language, $adminmail, $basepath)
{ {
$tpl = get_markup_template('local.ini.tpl'); $tpl = get_markup_template('local.ini.tpl');
$txt = replace_macros($tpl,[ $txt = replace_macros($tpl, [
'$phpath' => $phppath, '$phpath' => $phppath,
'$dbhost' => $dbhost, '$dbhost' => $dbhost,
'$dbuser' => $dbuser, '$dbuser' => $dbuser,
@ -128,10 +155,31 @@ class Install
$result = file_put_contents($basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php', $txt); $result = file_put_contents($basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php', $txt);
if (!$result) { if (!$result) {
return $txt; $this->addCheck(L10n::t('The database configuration file "config/local.ini.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'), false, false, htmlentities($txt, ENT_COMPAT, 'UTF-8'));
} else {
return true;
} }
return $result;
}
/***
* Installs the DB-Scheme for Friendica
*
* @return bool true if the installation was successful, otherwise false
*/
public function installDatabase()
{
$result = DBStructure::update(false, true, true);
if ($result) {
$txt = L10n::t('You may need to import the file "database.sql" manually using phpmyadmin or mysql.') . EOL;
$txt .= L10n::t('Please see the file "INSTALL.txt".');
$this->addCheck($txt, false, true, htmlentities($result, ENT_COMPAT, 'UTF-8'));
return false;
}
return true;
} }
/** /**
@ -170,11 +218,17 @@ class Install
*/ */
public function checkPHP($phppath = null, $required = false) public function checkPHP($phppath = null, $required = false)
{ {
$passed = $passed2 = $passed3 = false; $passed = false;
if (isset($phppath)) { $passed2 = false;
$passed = file_exists($phppath); $passed3 = false;
} else {
$phppath = trim(shell_exec('which php')); if (!isset($phppath)) {
$phppath = 'php';
}
$passed = file_exists($phppath);
if (!$passed) {
$phppath = trim(shell_exec('which ' . $phppath));
$passed = strlen($phppath); $passed = strlen($phppath);
} }
@ -205,12 +259,12 @@ class Install
$this->addCheck(L10n::t('PHP cli binary'), $passed2, true, $help); $this->addCheck(L10n::t('PHP cli binary'), $passed2, true, $help);
} else { } else {
// return if it was required // return if it was required
return $required; return !$required;
} }
if ($passed2) { if ($passed2) {
$str = autoname(8); $str = autoname(8);
$cmd = "$phppath testargs.php $str"; $cmd = "$phppath util/testargs.php $str";
$result = trim(shell_exec($cmd)); $result = trim(shell_exec($cmd));
$passed3 = $result == $str; $passed3 = $result == $str;
$help = ""; $help = "";
@ -444,26 +498,25 @@ class Install
* *
* Checks, if "url_rewrite" is enabled in the ".htaccess" file * Checks, if "url_rewrite" is enabled in the ".htaccess" file
* *
* @param string $basepath The basepath of the app
* @param string $baseurl The baseurl of the app * @param string $baseurl The baseurl of the app
* @return bool false if something required failed * @return bool false if something required failed
*/ */
public function checkHtAccess($basepath, $baseurl) public function checkHtAccess($baseurl)
{ {
$status = true; $status = true;
$help = ""; $help = "";
$error_msg = ""; $error_msg = "";
if (function_exists('curl_init')) { if (function_exists('curl_init')) {
$fetchResult = Network::fetchUrlFull($basepath . "/install/testrewrite"); $fetchResult = Network::fetchUrlFull($baseurl . "/install/testrewrite");
$url = normalise_link($baseurl . "/install/testrewrite"); $url = normalise_link($baseurl . "/install/testrewrite");
if ($fetchResult->getBody() != "ok") { if ($fetchResult->getReturnCode() != 204) {
$fetchResult = Network::fetchUrlFull($url); $fetchResult = Network::fetchUrlFull($url);
} }
if ($fetchResult->getBody() != "ok") { if ($fetchResult->getReturnCode() != 204) {
$status = false; $status = false;
$help = L10n::t('Url rewrite in .htaccess is not working. Check your server configuration.'); $help = L10n::t('Url rewrite in .htaccess is not working. Make sure you copied .htaccess-dist to .htaccess.');
$error_msg = []; $error_msg = [];
$error_msg['head'] = L10n::t('Error message from Curl when fetching'); $error_msg['head'] = L10n::t('Error message from Curl when fetching');
$error_msg['url'] = $fetchResult->getRedirectUrl(); $error_msg['url'] = $fetchResult->getRedirectUrl();
@ -510,4 +563,34 @@ class Install
// Imagick is not required // Imagick is not required
return true; return true;
} }
/**
* Checking the Database connection and if it is available for the current installation
*
* @param string $dbhost Hostname/IP of the Friendica Database
* @param string $dbuser Username of the Database connection credentials
* @param string $dbpass Password of the Database connection credentials
* @param string $dbdata Name of the Database
*
* @return bool true if the check was successful, otherwise false
*/
public function checkDB($dbhost, $dbuser, $dbpass, $dbdata)
{
require_once 'include/dba.php';
if (!DBA::connect($dbhost, $dbuser, $dbpass, $dbdata)) {
$this->addCheck(L10n::t('Could not connect to database.'), false, true, '');
return false;
}
if (DBA::connected()) {
if (DBStructure::existsTable('user')) {
$this->addCheck(L10n::t('Database already in use.'), false, true, '');
return false;
}
}
return true;
}
} }

267
src/Module/Install.php Normal file
View file

@ -0,0 +1,267 @@
<?php
namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Core;
use Friendica\Core\L10n;
use Friendica\Util\Temporal;
class Install extends BaseModule
{
/**
* Step one - System check
*/
const SYSTEM_CHECK = 1;
/**
* Step two - Database configuration
*/
const DATABASE_CONFIG = 2;
/**
* Step three - Adapat site settings
*/
const SITE_SETTINGS = 3;
/**
* Step four - All steps finished
*/
const FINISHED = 4;
/**
* @var int The current step of the wizard
*/
private static $currentWizardStep;
/**
* @var Core\Installer The installer
*/
private static $installer;
public static function init()
{
$a = self::getApp();
// route: install/testrwrite
// $baseurl/install/testrwrite to test if rewrite in .htaccess is working
if ($a->getArgumentValue(1, '') == 'testrewrite') {
// Status Code 204 means that it worked without content
Core\System::httpExit(204);
}
// We overwrite current theme css, because during install we may not have a working mod_rewrite
// so we may not have a css at all. Here we set a static css file for the install procedure pages
$a->theme['stylesheet'] = $a->getBaseURL() . '/view/install/style.css';
self::$installer = new Core\Installer();
self::$currentWizardStep = defaults($_POST, 'pass', self::SYSTEM_CHECK);
}
public static function post()
{
$a = self::getApp();
switch (self::$currentWizardStep) {
case self::SYSTEM_CHECK:
case self::DATABASE_CONFIG:
// Nothing to do in these steps
break;
case self::SITE_SETTINGS:
$dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
$dbuser = notags(trim(defaults($_POST, 'dbuser', '')));
$dbpass = notags(trim(defaults($_POST, 'dbpass', '')));
$dbdata = notags(trim(defaults($_POST, 'dbdata', '')));
// If we cannot connect to the database, return to the previous step
if (!self::$installer->checkDB($dbhost, $dbuser, $dbpass, $dbdata)) {
self::$currentWizardStep = self::DATABASE_CONFIG;
}
break;
case self::FINISHED:
$urlpath = $a->getURLPath();
$dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
$dbuser = notags(trim(defaults($_POST, 'dbuser', '')));
$dbpass = notags(trim(defaults($_POST, 'dbpass', '')));
$dbdata = notags(trim(defaults($_POST, 'dbdata', '')));
$timezone = notags(trim(defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ)));
$language = notags(trim(defaults($_POST, 'language', Core\Installer::DEFAULT_LANG)));
$adminmail = notags(trim(defaults($_POST, 'adminmail', '')));
// If we cannot connect to the database, return to the Database config wizard
if (!self::$installer->checkDB($dbhost, $dbuser, $dbpass, $dbdata)) {
self::$currentWizardStep = self::DATABASE_CONFIG;
return;
}
$phpath = self::$installer->getPHPPath();
if (!self::$installer->createConfig($phpath, $urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $timezone, $language, $adminmail, $a->getBasePath())) {
return;
}
self::$installer->installDatabase();
break;
}
}
public static function content()
{
$a = self::getApp();
$output = '';
$install_title = L10n::t('Friendica Communctions Server - Setup');
switch (self::$currentWizardStep) {
case self::SYSTEM_CHECK:
$phppath = defaults($_POST, 'phpath', null);
$status = self::$installer->checkEnvironment($a->getBaseURL(), $phppath);
$tpl = get_markup_template('install_checks.tpl');
$output .= replace_macros($tpl, [
'$title' => $install_title,
'$pass' => L10n::t('System check'),
'$checks' => self::$installer->getChecks(),
'$passed' => $status,
'$see_install' => L10n::t('Please see the file "Install.txt".'),
'$next' => L10n::t('Next'),
'$reload' => L10n::t('Check again'),
'$phpath' => $phppath,
'$baseurl' => $a->getBaseURL()
]);
break;
case self::DATABASE_CONFIG:
$dbhost = notags(trim(defaults($_POST, 'dbhost' , Core\Installer::DEFAULT_HOST)));
$dbuser = notags(trim(defaults($_POST, 'dbuser' , '' )));
$dbpass = notags(trim(defaults($_POST, 'dbpass' , '' )));
$dbdata = notags(trim(defaults($_POST, 'dbdata' , '' )));
$phpath = notags(trim(defaults($_POST, 'phpath' , '' )));
$adminmail = notags(trim(defaults($_POST, 'adminmail', '' )));
$tpl = get_markup_template('install_db.tpl');
$output .= replace_macros($tpl, [
'$title' => $install_title,
'$pass' => L10n::t('Database connection'),
'$info_01' => L10n::t('In order to install Friendica we need to know how to connect to your database.'),
'$info_02' => L10n::t('Please contact your hosting provider or site administrator if you have questions about these settings.'),
'$info_03' => L10n::t('The database you specify below should already exist. If it does not, please create it before continuing.'),
'checks' => self::$installer->getChecks(),
'$dbhost' => ['dbhost',
L10n::t('Database Server Name'),
$dbhost,
'',
'required'],
'$dbuser' => ['dbuser',
L10n::t('Database Login Name'),
$dbuser,
'',
'required',
'autofocus'],
'$dbpass' => ['dbpass',
L10n::t('Database Login Password'),
$dbpass,
L10n::t("For security reasons the password must not be empty"),
'required'],
'$dbdata' => ['dbdata',
L10n::t('Database Name'),
$dbdata,
'',
'required'],
'$adminmail' => ['adminmail',
L10n::t('Site administrator email address'),
$adminmail,
L10n::t('Your account email address must match this in order to use the web admin panel.'),
'required',
'autofocus',
'email'],
'$lbl_10' => L10n::t('Please select a default timezone for your website'),
'$baseurl' => $a->getBaseURL(),
'$phpath' => $phpath,
'$submit' => L10n::t('Submit')
]);
break;
case self::SITE_SETTINGS:
$dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
$dbuser = notags(trim(defaults($_POST, 'dbuser', '' )));
$dbpass = notags(trim(defaults($_POST, 'dbpass', '' )));
$dbdata = notags(trim(defaults($_POST, 'dbdata', '' )));
$phpath = notags(trim(defaults($_POST, 'phpath', '' )));
$adminmail = notags(trim(defaults($_POST, 'adminmail', '')));
$timezone = defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ);
/* Installed langs */
$lang_choices = L10n::getAvailableLanguages();
$tpl = get_markup_template('install_settings.tpl');
$output .= replace_macros($tpl, [
'$title' => $install_title,
'$checks' => self::$installer->getChecks(),
'$pass' => L10n::t('Site settings'),
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$phpath' => $phpath,
'$adminmail' => ['adminmail', L10n::t('Site administrator email address'), $adminmail, L10n::t('Your account email address must match this in order to use the web admin panel.'), 'required', 'autofocus', 'email'],
'$timezone' => Temporal::getTimezoneField('timezone', L10n::t('Please select a default timezone for your website'), $timezone, ''),
'$language' => ['language',
L10n::t('System Language:'),
Core\Installer::DEFAULT_LANG,
L10n::t('Set the default language for your Friendica installation interface and to send emails.'),
$lang_choices],
'$baseurl' => $a->getBaseURL(),
'$submit' => L10n::t('Submit')
]);
break;
case self::FINISHED:
$db_return_text = "";
if (count(self::$installer->getChecks()) == 0) {
$txt = '<p style="font-size: 130%;">';
$txt .= L10n::t('Your Friendica site database has been installed.') . EOL;
$db_return_text .= $txt;
}
$tpl = get_markup_template('install_finished.tpl');
$output .= replace_macros($tpl, [
'$title' => $install_title,
'$checks' => self::$installer->getChecks(),
'$pass' => L10n::t('Installation finished'),
'$text' => $db_return_text . self::whatNext($a),
]);
break;
}
return $output;
}
/**
* Creates the text for the next steps
*
* @param App $a The global App
*
* @return string The text for the next steps
*/
private static function whatNext($a)
{
$baseurl = $a->getBaseUrl();
return
L10n::t('<h1>What next</h1>')
. "<p>".L10n::t('IMPORTANT: You will need to [manually] setup a scheduled task for the worker.')
. L10n::t('Please see the file "INSTALL.txt".')
. "</p><p>"
. L10n::t('Go to your new Friendica node <a href="%s/register">registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.', $baseurl)
. "</p>";
}
}

View file

@ -31,6 +31,14 @@ class AutomaticInstallationConsoleTest extends ConsoleTest
$this->db_data = getenv('MYSQL_DATABASE'); $this->db_data = getenv('MYSQL_DATABASE');
$this->db_user = getenv('MYSQL_USERNAME') . getenv('MYSQL_USER'); $this->db_user = getenv('MYSQL_USERNAME') . getenv('MYSQL_USER');
$this->db_pass = getenv('MYSQL_PASSWORD'); $this->db_pass = getenv('MYSQL_PASSWORD');
// Mocking 'DBStructure::existsTable()' because with CI, we cannot create an empty database
// therefore we temporary override the existing database
/// @todo Mocking the DB-Calls of ConsoleTest so we don't need this specific mock anymore
$existsMock = \Mockery::mock('alias:Friendica\Database\DBStructure');
$existsMock->shouldReceive('existsTable')
->with('user')
->andReturn(false);
} }
private function assertConfig($family, $key, $value) private function assertConfig($family, $key, $value)
@ -48,6 +56,8 @@ class AutomaticInstallationConsoleTest extends ConsoleTest
Creating config file... Creating config file...
Complete!
CFG; CFG;
} }
@ -56,20 +66,23 @@ CFG;
Copying config file... Copying config file...
Complete!
CFG; CFG;
} }
$finished = <<<FIN $finished = <<<FIN
Initializing setup...{$cfg} Initializing setup...
Complete! Complete!
Checking basic setup... Checking environment...
NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation. NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.
Complete! Complete!
{$cfg}
Checking database... Checking database...

View file

@ -10,7 +10,7 @@ use PHPUnit\Framework\TestCase;
* @runTestsInSeparateProcesses * @runTestsInSeparateProcesses
* @preserveGlobalState disabled * @preserveGlobalState disabled
*/ */
class InstallTest extends TestCase class InstallerTest extends TestCase
{ {
use VFSTrait; use VFSTrait;
@ -74,11 +74,11 @@ class InstallTest extends TestCase
public function testCheckKeys() public function testCheckKeys()
{ {
$this->setFunctions(['openssl_pkey_new' => false]); $this->setFunctions(['openssl_pkey_new' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkKeys()); $this->assertFalse($install->checkKeys());
$this->setFunctions(['openssl_pkey_new' => true]); $this->setFunctions(['openssl_pkey_new' => true]);
$install = new Install(); $install = new Installer();
$this->assertTrue($install->checkKeys()); $this->assertTrue($install->checkKeys());
} }
@ -88,7 +88,7 @@ class InstallTest extends TestCase
public function testCheckFunctions() public function testCheckFunctions()
{ {
$this->setFunctions(['curl_init' => false]); $this->setFunctions(['curl_init' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(3, $this->assertCheckExist(3,
L10n::t('libCurl PHP module'), L10n::t('libCurl PHP module'),
@ -98,7 +98,7 @@ class InstallTest extends TestCase
$install->getChecks()); $install->getChecks());
$this->setFunctions(['imagecreatefromjpeg' => false]); $this->setFunctions(['imagecreatefromjpeg' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(4, $this->assertCheckExist(4,
L10n::t('GD graphics PHP module'), L10n::t('GD graphics PHP module'),
@ -108,7 +108,7 @@ class InstallTest extends TestCase
$install->getChecks()); $install->getChecks());
$this->setFunctions(['openssl_public_encrypt' => false]); $this->setFunctions(['openssl_public_encrypt' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(5, $this->assertCheckExist(5,
L10n::t('OpenSSL PHP module'), L10n::t('OpenSSL PHP module'),
@ -118,7 +118,7 @@ class InstallTest extends TestCase
$install->getChecks()); $install->getChecks());
$this->setFunctions(['mb_strlen' => false]); $this->setFunctions(['mb_strlen' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(6, $this->assertCheckExist(6,
L10n::t('mb_string PHP module'), L10n::t('mb_string PHP module'),
@ -128,7 +128,7 @@ class InstallTest extends TestCase
$install->getChecks()); $install->getChecks());
$this->setFunctions(['iconv_strlen' => false]); $this->setFunctions(['iconv_strlen' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(7, $this->assertCheckExist(7,
L10n::t('iconv PHP module'), L10n::t('iconv PHP module'),
@ -138,7 +138,7 @@ class InstallTest extends TestCase
$install->getChecks()); $install->getChecks());
$this->setFunctions(['posix_kill' => false]); $this->setFunctions(['posix_kill' => false]);
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkFunctions()); $this->assertFalse($install->checkFunctions());
$this->assertCheckExist(8, $this->assertCheckExist(8,
L10n::t('POSIX PHP module'), L10n::t('POSIX PHP module'),
@ -155,7 +155,7 @@ class InstallTest extends TestCase
'iconv_strlen' => true, 'iconv_strlen' => true,
'posix_kill' => true 'posix_kill' => true
]); ]);
$install = new Install(); $install = new Installer();
$this->assertTrue($install->checkFunctions()); $this->assertTrue($install->checkFunctions());
} }
@ -166,14 +166,14 @@ class InstallTest extends TestCase
{ {
$this->assertTrue($this->root->hasChild('config/local.ini.php')); $this->assertTrue($this->root->hasChild('config/local.ini.php'));
$install = new Install(); $install = new Installer();
$this->assertTrue($install->checkLocalIni()); $this->assertTrue($install->checkLocalIni());
$this->delConfigFile('local.ini.php'); $this->delConfigFile('local.ini.php');
$this->assertFalse($this->root->hasChild('config/local.ini.php')); $this->assertFalse($this->root->hasChild('config/local.ini.php'));
$install = new Install(); $install = new Installer();
$this->assertTrue($install->checkLocalIni()); $this->assertTrue($install->checkLocalIni());
} }
@ -185,8 +185,8 @@ class InstallTest extends TestCase
// Mocking the CURL Response // Mocking the CURL Response
$curlResult = \Mockery::mock('Friendica\Network\CurlResult'); $curlResult = \Mockery::mock('Friendica\Network\CurlResult');
$curlResult $curlResult
->shouldReceive('getBody') ->shouldReceive('getReturnCode')
->andReturn('not ok'); ->andReturn('404');
$curlResult $curlResult
->shouldReceive('getRedirectUrl') ->shouldReceive('getRedirectUrl')
->andReturn(''); ->andReturn('');
@ -211,9 +211,9 @@ class InstallTest extends TestCase
// needed because of "normalise_link" // needed because of "normalise_link"
require_once __DIR__ . '/../../../include/text.php'; require_once __DIR__ . '/../../../include/text.php';
$install = new Install(); $install = new Installer();
$this->assertFalse($install->checkHtAccess('https://test', 'https://test')); $this->assertFalse($install->checkHtAccess('https://test'));
$this->assertSame('test Error', $install->getChecks()[0]['error_msg']['msg']); $this->assertSame('test Error', $install->getChecks()[0]['error_msg']['msg']);
} }
@ -225,14 +225,14 @@ class InstallTest extends TestCase
// Mocking the failed CURL Response // Mocking the failed CURL Response
$curlResultF = \Mockery::mock('Friendica\Network\CurlResult'); $curlResultF = \Mockery::mock('Friendica\Network\CurlResult');
$curlResultF $curlResultF
->shouldReceive('getBody') ->shouldReceive('getReturnCode')
->andReturn('not ok'); ->andReturn('404');
// Mocking the working CURL Response // Mocking the working CURL Response
$curlResultW = \Mockery::mock('Friendica\Network\CurlResult'); $curlResultW = \Mockery::mock('Friendica\Network\CurlResult');
$curlResultW $curlResultW
->shouldReceive('getBody') ->shouldReceive('getReturnCode')
->andReturn('ok'); ->andReturn('204');
// Mocking the CURL Request // Mocking the CURL Request
$networkMock = \Mockery::mock('alias:Friendica\Util\Network'); $networkMock = \Mockery::mock('alias:Friendica\Util\Network');
@ -251,9 +251,9 @@ class InstallTest extends TestCase
// needed because of "normalise_link" // needed because of "normalise_link"
require_once __DIR__ . '/../../../include/text.php'; require_once __DIR__ . '/../../../include/text.php';
$install = new Install(); $install = new Installer();
$this->assertTrue($install->checkHtAccess('https://test', 'https://test')); $this->assertTrue($install->checkHtAccess('https://test'));
} }
/** /**
@ -268,7 +268,7 @@ class InstallTest extends TestCase
$this->setClasses(['Imagick' => true]); $this->setClasses(['Imagick' => true]);
$install = new Install(); $install = new Installer();
// even there is no supported type, Imagick should return true (because it is not required) // even there is no supported type, Imagick should return true (because it is not required)
$this->assertTrue($install->checkImagick()); $this->assertTrue($install->checkImagick());
@ -293,7 +293,7 @@ class InstallTest extends TestCase
$this->setClasses(['Imagick' => true]); $this->setClasses(['Imagick' => true]);
$install = new Install(); $install = new Installer();
// even there is no supported type, Imagick should return true (because it is not required) // even there is no supported type, Imagick should return true (because it is not required)
$this->assertTrue($install->checkImagick()); $this->assertTrue($install->checkImagick());
@ -309,7 +309,7 @@ class InstallTest extends TestCase
{ {
$this->setClasses(['Imagick' => false]); $this->setClasses(['Imagick' => false]);
$install = new Install(); $install = new Installer();
// even there is no supported type, Imagick should return true (because it is not required) // even there is no supported type, Imagick should return true (because it is not required)
$this->assertTrue($install->checkImagick()); $this->assertTrue($install->checkImagick());

View file

@ -1,11 +0,0 @@
<h1><img src="{{$baseurl}}/images/friendica-32.png"> {{$title}}</h1>
<h2>{{$pass}}</h2>
{{if $status}}
<h3 class="error-message">{{$status}}</h3>
{{/if}}
{{$text}}

View file

@ -10,9 +10,14 @@
{{$info_03}} {{$info_03}}
</p> </p>
{{if $status}} <table>
<h3 class="error-message">{{$status}}</h3> {{foreach $checks as $check}}
{{/if}} <tr><td>{{$check.title}} </td><td>
{{if ! $check.status}}
<img src="{{$baseurl}}/view/install/red.png" alt="Requirement not satisfied">
{{/if}}
{{/foreach}}
</table>
<form id="install-form" action="{{$baseurl}}/install" method="post"> <form id="install-form" action="{{$baseurl}}/install" method="post">

View file

@ -0,0 +1,13 @@
<h1><img src="{{$baseurl}}/images/friendica-32.png"> {{$title}}</h1>
<h2>{{$pass}}</h2>
{{foreach $checks as $check}}
<img src="{{$baseurl}}/view/install/red.png" alt="Requirement not satisfied">
{{$check.title}}
<textarea rows="24" cols="80">{{$check.help}}</textarea>
{{/foreach}}
{{$text}}

View file

@ -4,10 +4,6 @@
<h2>{{$pass}}</h2> <h2>{{$pass}}</h2>
{{if $status}}
<h3 class="error-message">{{$status}}</h3>
{{/if}}
<form id="install-form" action="{{$baseurl}}/install" method="post"> <form id="install-form" action="{{$baseurl}}/install" method="post">
<input type="hidden" name="phpath" value="{{$phpath|escape:'html'}}" /> <input type="hidden" name="phpath" value="{{$phpath|escape:'html'}}" />