421 lines
17 KiB
PHP
421 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* install.php
|
|
*
|
|
* This is the install controller for the application.
|
|
* After completion: YOU SHOULD DELETE THIS FILE.
|
|
*
|
|
* @version 3.0
|
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
|
* @link https://TheTempusProject.com
|
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
|
*/
|
|
namespace TheTempusProject\Controllers;
|
|
|
|
require_once 'bin/autoload.php';
|
|
|
|
use TheTempusProject\TheTempusProject;
|
|
use TheTempusProject\Classes\Controller;
|
|
use TheTempusProject\Classes\Plugin;
|
|
use TheTempusProject\Classes\Installer;
|
|
use TheTempusProject\Classes\Forms;
|
|
use TheTempusProject\Models\User;
|
|
use TheTempusProject\Classes\Email;
|
|
use TheTempusProject\Bedrock\Functions\Code;
|
|
use TheTempusProject\Bedrock\Functions\Check;
|
|
use TheTempusProject\Bedrock\Functions\Cookie;
|
|
use TheTempusProject\Bedrock\Functions\Input;
|
|
use TheTempusProject\Bedrock\Functions\Upload;
|
|
use TheTempusProject\Bedrock\Functions\Hash;
|
|
use TheTempusProject\Bedrock\Functions\Session;
|
|
use TheTempusProject\Houdini\Classes\Issues;
|
|
use TheTempusProject\Houdini\Classes\Views;
|
|
use TheTempusProject\Houdini\Classes\Components;
|
|
use TheTempusProject\Houdini\Classes\Template;
|
|
use TheTempusProject\Hermes\Functions\Redirect;
|
|
use TheTempusProject\Hermes\Functions\Route;
|
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
|
|
|
class Install extends Controller {
|
|
private $installer;
|
|
private $location = false;
|
|
private $steps = [
|
|
'Welcome',
|
|
'Terms',
|
|
'Verify',
|
|
'Configure',
|
|
'Routing',
|
|
'Models',
|
|
'Plugins',
|
|
'Install',
|
|
'Resources',
|
|
'User',
|
|
'Complete',
|
|
];
|
|
|
|
/**
|
|
* This is the main builder for the rest of the controller. It mostly handle template variables used on all pages.
|
|
*/
|
|
public function __construct() {
|
|
parent::__construct();
|
|
self::$title = 'TP Installer';
|
|
self::$pageDescription = 'This is the install script for The Tempus Project.';
|
|
$this->installer = new Installer();
|
|
Template::noIndex();
|
|
Template::noFollow();
|
|
foreach ( $this->steps as $step ) {
|
|
Components::set( 'menu-' . $step, 'disabled' );
|
|
}
|
|
if ( $this->checkSession() !== false ) {
|
|
$this->location = $this->getStep();
|
|
Components::set( 'menu-' . ucfirst( $this->location ), 'active' );
|
|
} else {
|
|
Components::set( 'menu-Welcome', 'active' );
|
|
}
|
|
Components::set( 'installer-nav', Views::simpleView( 'install.nav' ) );
|
|
}
|
|
|
|
/**
|
|
* This method will reset the install hash, set the saved install step, update the session and cookie, and refresh if required.
|
|
*
|
|
* @param string $page
|
|
* @param boolean $redirect
|
|
* @return void
|
|
*/
|
|
public function nextStep( $page, $redirect = false ) {
|
|
$newHash = Code::genInstall();
|
|
$this->installer->setNode( 'installHash', $newHash, true );
|
|
$this->installer->setNode( 'installStep', $page, true );
|
|
Session::put( 'installHash', $newHash );
|
|
Cookie::put( 'installHash', $newHash );
|
|
if ( $redirect === true ) {
|
|
Redirect::reload();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function checkSession() {
|
|
if ( empty( $this->installer->getNode('installHash') ) ) {
|
|
Debug::error( 'install hash not found on file.' );
|
|
return false;
|
|
}
|
|
$session = Session::get( 'installHash' );
|
|
$cookie = Cookie::get( 'installHash' );
|
|
$file = $this->installer->getNode('installHash');
|
|
|
|
if ( ! $session && ! $cookie ) {
|
|
Debug::error( 'install hash not found in session or cookie.' );
|
|
return false;
|
|
}
|
|
if ( $cookie && ! $session ) {
|
|
if ( $cookie !== $file ) {
|
|
Debug::error( 'install cookie did not match install file.' );
|
|
Cookie::delete( 'installHash' );
|
|
return false;
|
|
}
|
|
Debug::error( 'cookie matches file, using as session' );
|
|
Session::put( 'installHash', $cookie );
|
|
return true;
|
|
}
|
|
if ( $session !== $file ) {
|
|
Debug::error( 'session did not match file, deleting session' );
|
|
Session::delete( 'installHash' );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function getStep() {
|
|
if ( !empty( $this->installer->getNode('installStep') ) ) {
|
|
return $this->installer->getNode('installStep');
|
|
}
|
|
Debug::error( 'install status not found.' );
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* The index method is called on the first request and all requests thereafter and is responsible for routing
|
|
* the current request to the appropriate installer step/method.
|
|
*/
|
|
public function index() {
|
|
if ( false === $this->location ) {
|
|
return $this->welcome();
|
|
}
|
|
// this seems dumb, i could probably do this better
|
|
$location = $this->location;
|
|
return $this->$location();
|
|
}
|
|
|
|
/**
|
|
* The welcome method is is just a page to submit a form and save the install.json for the first time.
|
|
*/
|
|
public function welcome() {
|
|
if ( Forms::Check( 'installStart' ) ) {
|
|
return $this->nextStep( 'terms', true );
|
|
}
|
|
if ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with the Installation.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.welcome' );
|
|
}
|
|
|
|
/**
|
|
* The terms step is pretty straight forward. You simply need to continue to the next step, understanding
|
|
* that you agree to these terms when you continue the installation.
|
|
*/
|
|
public function terms() {
|
|
if ( Forms::Check( 'installAgreement' ) ) {
|
|
return $this->nextStep( 'verify', true );
|
|
}
|
|
if ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', [ 'There was an error with the Installation.' => Check::userErrors() ] );
|
|
}
|
|
Components::set( 'TERMS', Views::simpleView( 'terms' ) );
|
|
Views::view( 'install.terms' );
|
|
}
|
|
|
|
/**
|
|
* There is a small list a of requirements for the application to run properly. These are things like sessions, emails, cookies, etc.
|
|
* This step verifies that all of these features are working as expected.
|
|
*/
|
|
public function verify() {
|
|
if ( Forms::Check( 'installCheck' ) ) {
|
|
return $this->nextStep( 'configure', true );
|
|
}
|
|
if ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with the Installation.' => array_merge( Check::userErrors(), Check::systemErrors() )] );
|
|
}
|
|
Views::view( 'install.verify' );
|
|
}
|
|
|
|
/**
|
|
* One of the most important steps for installation, is the configuration. In this step, we will define some very core settings
|
|
* for the app including the app's name and database credentials.
|
|
*/
|
|
public function configure() {
|
|
if ( Forms::Check( 'installConfigure' ) ) {
|
|
$logo = 'images/logo.png';
|
|
if ( Input::exists( 'logo' ) && Upload::image( 'logo', 'System' ) ) {
|
|
$logo = 'Uploads/Images/System/' . Upload::last();
|
|
}
|
|
TheTempusProject::$activeConfig->load( BEDROCK_CONFIG_JSON );
|
|
$baseConfig = TheTempusProject::$configMatrix;
|
|
$baseConfig['main']['logo']['value'] = $logo;
|
|
$baseConfig['main']['name']['value'] = Input::postNull( 'siteName' );
|
|
$baseConfig['main']['template']['value'] = $baseConfig['main']['template']['default'];
|
|
$baseConfig['main']['tokenEnabled']['value'] = $baseConfig['main']['tokenEnabled']['default'];
|
|
$baseConfig['main']['loginLimit']['value'] = $baseConfig['main']['loginLimit']['default'];
|
|
$baseConfig['database']['dbEnabled']['value'] = $baseConfig['database']['dbEnabled']['default'];
|
|
$baseConfig['database']['dbHost']['value'] = Input::postNull( 'dbHost' );
|
|
$baseConfig['database']['dbMaxQuery']['value'] = $baseConfig['database']['dbMaxQuery']['default'];
|
|
$baseConfig['database']['dbName']['value'] = Input::postNull( 'dbName' );
|
|
$baseConfig['database']['dbPassword']['value'] = Input::postNull( 'dbPassword' );
|
|
$baseConfig['database']['dbPrefix']['value'] = Input::postNull( 'dbPrefix' );
|
|
$baseConfig['database']['dbUsername']['value'] = Input::postNull( 'dbUsername' );
|
|
if ( ! TheTempusProject::$activeConfig->generate( CONFIG_JSON, $baseConfig ) ) {
|
|
return Issues::add( 'error', 'Config file already exists so the installer has been halted. If there was an error with installation, please delete app/config/config.json manually and try again. The installer should automatically bring you back to this step.' );
|
|
}
|
|
Session::flash( 'success', 'Config saved successfully.' );
|
|
return $this->nextStep( 'routing', true );
|
|
}
|
|
if ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with your form.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.configure' );
|
|
}
|
|
|
|
/**
|
|
* For the application to function properly on nginx or apache, the web servers must be configured correctly.
|
|
* Depending on which server you use, this step will help you set up and test the routing required for the
|
|
* application to function as expected.
|
|
*/
|
|
public function routing() {
|
|
if ( Input::exists( 'submit' ) && Forms::Check( 'installRouting' ) ) {
|
|
// if its Apache, attempt to generate the htaccess file before testing
|
|
if ( Check::isApache() ) {
|
|
if ( !$this->installer->checkHtaccess() ) {
|
|
if ( !$this->installer->saveHtaccess() ) {
|
|
Issues::add( 'error', 'There was an unexpected error when generating your htaccess file. Please see the error logs for more information.' );
|
|
}
|
|
}
|
|
}
|
|
// Apache should have the htaccess now, and Nginx should have been configured this way out of the box
|
|
if ( Route::testRouting() ) {
|
|
Session::flash( 'success', 'Routing is working as expected.' );
|
|
return $this->nextStep( 'models', true );
|
|
} else {
|
|
Issues::add( 'error', 'Could not verify url routing' );
|
|
}
|
|
// routing is busted, if its Apache, we already have the error from htaccess generation
|
|
// so Nginx is the only one that needs more info
|
|
if ( Check::isNginx() ) {
|
|
Issues::add( 'error', 'There appears to be an issue with your configuration. Certain urls are not being routed as expected.' );
|
|
}
|
|
} elseif ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with your form.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.routing' );
|
|
}
|
|
|
|
/**
|
|
* Since models are required for the proper function of the app, this step is required and has no selection to make.
|
|
* This step will install all the required models excluding resources.
|
|
*/
|
|
public function models() {
|
|
$errors = [];
|
|
$options = [ 'installResources' => false ];
|
|
$models = $this->installer->getModelList( MODEL_DIRECTORY );
|
|
if ( Input::exists( 'submit' ) && Forms::Check( 'installModels' ) ) {
|
|
$error = false;
|
|
foreach ( $models as $model ) {
|
|
$result = $this->installer->installModel( $model, $options );
|
|
|
|
if ( $result === false ) {
|
|
$error = true;
|
|
continue;
|
|
}
|
|
}
|
|
if ( $error ) {
|
|
Issues::add( 'error', [ 'There was an error with the Installation.' => $this->installer->getErrors() ] );
|
|
} else {
|
|
Session::flash( 'success', [ 'Models Have been installed successfully.' => $this->installer->getErrors() ] );
|
|
return $this->nextStep( 'plugins', true );
|
|
}
|
|
} elseif ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
|
}
|
|
Views::view( 'install.models', $models );
|
|
}
|
|
|
|
/**
|
|
* This step will allow the user to install any plugins currently available for installing excluding resources.
|
|
*/
|
|
public function plugins() {
|
|
$errors = [];
|
|
$options = [ 'resources_installed' => false ];
|
|
$plugins = $this->installer->getAvailablePlugins();
|
|
$selected_plugins = Input::post( 'P_' );
|
|
|
|
if ( Input::exists( 'submit' ) && Forms::Check( 'installPlugins' ) ) {
|
|
$error = false;
|
|
foreach ( $plugins as $plugin ) {
|
|
if ( ! in_array( $plugin->name, $selected_plugins ) ) {
|
|
continue;
|
|
}
|
|
$result = $this->installer->installPlugin( $plugin, $options );
|
|
|
|
if ( !$result ) {
|
|
$error = true;
|
|
continue;
|
|
}
|
|
Plugin::enable( $plugin->name, true );
|
|
}
|
|
if ( $error ) {
|
|
Issues::add( 'error', ['There was an error with the Installation.' => $this->installer->getErrors()] );
|
|
} else {
|
|
Session::flash( 'success', [ 'Plugins Have been installed successfully.' => $this->installer->getErrors() ] );
|
|
return $this->nextStep( 'resources', true );
|
|
}
|
|
} elseif ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with your form.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.plugins', $plugins );
|
|
}
|
|
|
|
/**
|
|
* The resource step will cycle through the partially installed models and install any missing resources.
|
|
*/
|
|
public function resources() {
|
|
$errors = [];
|
|
if ( Input::exists( 'submit' ) && Forms::Check( 'installResources' ) ) {
|
|
$error = false;
|
|
$allModules = $this->installer->getModules(true);
|
|
foreach ( $allModules as $name => $module ) {
|
|
if ( empty( $module ) || 'unknown' === $name || empty( $name ) || empty( $module['installedVersion'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( 'plugin' == $module['type'] ) {
|
|
$installResult = $this->installer->installPlugin( (object) $module, [ 'resources_installed' => true ], false );
|
|
} else {
|
|
$installResult = $this->installer->installModel( (object) $module, [ 'installResources' => true ], false );
|
|
}
|
|
if ( !$installResult ) {
|
|
$error = true;
|
|
}
|
|
}
|
|
if ( $error ) {
|
|
Issues::add( 'error', ['There was an error with the Installation.' => $this->installer->getErrors()] );
|
|
} else {
|
|
Session::flash( 'success', ['Resources have been installed successfully.' => $this->installer->getErrors()] );
|
|
return $this->nextStep( 'user', true );
|
|
}
|
|
} elseif ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with your form.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.resources' );
|
|
}
|
|
|
|
/**
|
|
* This is the registration step; allowing the installer to create the super admin account.
|
|
*/
|
|
public function user() {
|
|
if ( Input::exists( 'submit' ) && Forms::Check( 'installAdminUser' ) ) {
|
|
$user = new User();
|
|
if ( !$user->create( [
|
|
'username' => Input::post( 'newUsername' ),
|
|
'password' => Hash::make( Input::post( 'userPassword' ) ),
|
|
'email' => Input::post( 'userEmail' ),
|
|
'lastLogin' => time(),
|
|
'registered' => time(),
|
|
'confirmed' => 1,
|
|
'terms' => 1,
|
|
'userGroup' => 1,
|
|
] ) ) {
|
|
Issues::add( 'error', 'There was an error creating the admin user.' );
|
|
return;
|
|
}
|
|
$this->nextStep( 'complete' );
|
|
return $this->complete( true );
|
|
} elseif ( Input::exists( 'submit' ) ) {
|
|
Issues::add( 'error', ['There was an error with your form.' => Check::userErrors()] );
|
|
}
|
|
Views::view( 'install.user' );
|
|
}
|
|
|
|
/**
|
|
* This is the final step of installation. On first load it will send an email and show the final view.
|
|
* It will then redirect to the index controller and prompt the user to delete this file on any subsequent loads.
|
|
*
|
|
* @param bool $sendEmail
|
|
*/
|
|
public function complete( $sendEmail = false ) {
|
|
if ( $sendEmail ) {
|
|
Issues::add( 'success', 'The Tempus Project has been installed successfully.' );
|
|
Email::send( Input::post( 'email' ), 'install', null, [ 'template' => true ] );
|
|
return Views::view( 'install.complete' );
|
|
}
|
|
Session::flash( 'notice', 'Installation has been completed. Updates and installation can be managed in the admin panel. Please delete the install.php file.' );
|
|
Redirect::to( 'home/index' );
|
|
}
|
|
}
|
|
|
|
$app = new TheTempusProject();
|
|
|
|
if ( CANARY_ENABLED ) {
|
|
// ini_set( 'display_errors', '1' );
|
|
// ini_set( 'display_startup_errors', '1' );
|
|
// error_reporting( E_ALL );
|
|
// $app->printDebug();
|
|
}
|
|
|
|
$app->setUrl( 'install/index' );
|
|
$app->load();
|
|
|
|
if ( CANARY_DEBUG_TO_CONSOLE ) {
|
|
Components::set( 'DEBUGGING_LOG', Debug::dump() );
|
|
register_shutdown_function( [ $app::class, 'handle_shutdown' ] );
|
|
}
|
|
|
|
exit;
|