
Fixed config switches not registering the correct current value Added better ux when image uploads are disabled Fixed an issue where uploaded files were not being handled correctly Added the ability to disable user registrations Fixed some variables being unintendedly protected
427 lines
18 KiB
PHP
427 lines
18 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';
|
|
$logoLarge = 'images/logoLarge.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']['logoLarge']['value'] = $logoLarge;
|
|
$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']['registrationEnabled']['value'] = $baseConfig['main']['registrationEnabled']['default'];
|
|
$baseConfig['main']['loginLimit']['value'] = $baseConfig['main']['loginLimit']['default'];
|
|
$baseConfig['main']['loginTimer']['value'] = $baseConfig['main']['loginTimer']['default'];
|
|
$baseConfig['uploads']['images']['value'] = $baseConfig['uploads']['images']['default'];
|
|
$baseConfig['uploads']['maxImageSize']['value'] = $baseConfig['uploads']['maxImageSize']['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;
|