mirror of https://github.com/flarum/flarum
moved code to class, cleaned up, removed requirement of composer.phar in scripts, added ajaxified status updates, redirection to install path and back
parent
743e1884ba
commit
4a63d51338
99
index.php
99
index.php
|
@ -8,98 +8,13 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// prevent all those questions concerning ::class and possible composer installation errors (5.3+)
|
||||
if (PHP_VERSION_ID < 50509) {
|
||||
throw new Exception('At least PHP 5.5.9 is required to make Flarum work. See the system requirements: http://flarum.org/docs/installation/#system-requirements');
|
||||
} elseif (file_exists('vendor/autoload.php')) {
|
||||
if (file_exists('vendor/autoload.php')) {
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Start up the Flarum installation wizard or the Forums.
|
||||
*/
|
||||
require 'vendor/autoload.php';
|
||||
(new Flarum\Forum\Server(__DIR__))->listen();
|
||||
|
||||
// delete /_install_tmp using composer functionality
|
||||
if (is_dir('_install_tmp') && file_exists('_install_tmp/composer/vendor/autoload.php')) {
|
||||
if (array_key_exists('install-done', $_GET)) {
|
||||
echo 1;
|
||||
exit;
|
||||
}
|
||||
// include the extracted composer libraries
|
||||
require_once '_install_tmp/composer/vendor/autoload.php';
|
||||
|
||||
$fs = new Composer\Util\Filesystem();
|
||||
$fs->removeDirectory('_install_tmp');
|
||||
}
|
||||
|
||||
$server = new Flarum\Forum\Server(__DIR__);
|
||||
|
||||
$server->listen();
|
||||
|
||||
} elseif ((ini_get('allow_url_fopen') && !ini_get('phar.readonly')) || file_exists('scripts/composer.phar')) {
|
||||
if (array_key_exists('install-done', $_GET)) {
|
||||
echo 0;
|
||||
exit;
|
||||
}
|
||||
// prevent time out of page, drawback of running in browser
|
||||
@set_time_limit(0);
|
||||
// prevent extracting composer anew if already exists
|
||||
if (!is_dir('_install_tmp/composer')) {
|
||||
// attempt to download the latest composer file
|
||||
if (!file_exists('scripts/composer.phar') && ini_get('allow_url_fopen')) {
|
||||
file_put_contents('https://getcomposer.org/installer', 'scripts/composer.phar');
|
||||
}
|
||||
// use Phar to extract the composer package
|
||||
$composer = new Phar('scripts/composer.phar');
|
||||
// create a temporary directory for saving the package
|
||||
mkdir('_install_tmp');
|
||||
// extract composer
|
||||
$composer->extractTo('_install_tmp/composer');
|
||||
}
|
||||
// if extraction succeeded, let's run the update command.
|
||||
if (is_dir('_install_tmp/composer') && file_exists('_install_tmp/composer/vendor/autoload.php')) {
|
||||
// force memory to at least 1GB (default for composer) otherwise composer will run out of memory
|
||||
if (function_exists('ini_set')) {
|
||||
ini_set('memory_limit', '1G');
|
||||
}
|
||||
|
||||
// show an installation html
|
||||
include "storage/views/composer-installation.html";
|
||||
// force the template to the user
|
||||
ob_flush();
|
||||
// sets a home directory for storing information
|
||||
putenv('COMPOSER_HOME=' . getcwd() . '/_install_tmp/home');
|
||||
// prevents any interaction composer might require
|
||||
putenv('COMPOSER_NO_INTERACTION=true');
|
||||
|
||||
require_once '_install_tmp/composer/vendor/autoload.php';
|
||||
|
||||
// run the composer installation command
|
||||
$application = new Composer\Console\Application();
|
||||
|
||||
// disable auto exit
|
||||
$application->setAutoExit(false);
|
||||
|
||||
// first set the github token to prevent installation errors
|
||||
$input = new \Symfony\Component\Console\Input\ArrayInput([
|
||||
'command' => 'config',
|
||||
'github-oauth.github.com' => 'ec785da935d5535e151f7b3386190265f00e8fe2'
|
||||
]);
|
||||
$application->run($input);
|
||||
|
||||
// set the input for the composer install command
|
||||
$input = new Symfony\Component\Console\Input\ArrayInput([
|
||||
'command' => 'install',
|
||||
'--no-dev' => true,
|
||||
'--prefer-dist' => true,
|
||||
'--optimize-autoloader' => true,
|
||||
'-q' => true
|
||||
]);
|
||||
$application->run($input);
|
||||
|
||||
// application installation is now done, redirect to Flarum installer
|
||||
// we cannot send a header or redirect because we're already flushed the buffer
|
||||
}
|
||||
} else {
|
||||
// todo provide proper error message
|
||||
throw new Exception('This method of installation is currently unsupported.');
|
||||
} elseif (file_exists('install/index.php')) {
|
||||
$url = 'http://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/') . '/install/index.php';
|
||||
header("Location:{$url}", true, 301);
|
||||
exit;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require_once 'src/Installer.php';
|
||||
|
||||
(new Flarum\Installer\Installer(__DIR__ . '/../'))->listen();
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Installer;
|
||||
|
||||
use Composer\Console\Application;
|
||||
use Phar;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class Installer
|
||||
{
|
||||
|
||||
const GITHUB_TOKEN = 'ec785da935d5535e151f7b3386190265f00e8fe2';
|
||||
|
||||
/**
|
||||
* Absolute path to Flarum installation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePath;
|
||||
|
||||
/**
|
||||
* Absolute path to directory for storing temporary installation files.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tmpPath;
|
||||
|
||||
/**
|
||||
* The installation path, temporary files needed for running the Installer.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $installPath;
|
||||
|
||||
public function __construct($basePath)
|
||||
{
|
||||
$this->setBasePath($basePath);
|
||||
$this->setTmpPath($this->getBasePath('/storage/tmp'));
|
||||
$this->setInstallPath();
|
||||
|
||||
$this->setupEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up environment specifics
|
||||
*/
|
||||
public function setupEnvironment()
|
||||
{
|
||||
// prevent time out of page, drawback of running in browser
|
||||
@set_time_limit(0);
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// sets a home directory for storing information
|
||||
putenv('COMPOSER_HOME=' . $this->getTmpPath('/composer-home'));
|
||||
// prevents any interaction composer might require
|
||||
putenv('COMPOSER_NO_INTERACTION=true');
|
||||
|
||||
// force memory to at least 1GB (default for composer) otherwise composer will run out of memory
|
||||
if (function_exists('ini_set')) {
|
||||
ini_set('memory_limit', '1G');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $basePath
|
||||
* @return Installer
|
||||
*/
|
||||
public function setBasePath($basePath)
|
||||
{
|
||||
$this->basePath = realpath($basePath);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getBasePath($path = '')
|
||||
{
|
||||
return $this->basePath . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Installer
|
||||
*/
|
||||
public function setInstallPath()
|
||||
{
|
||||
$this->installPath = realpath(__DIR__ . '/../');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getInstallPath($path = '')
|
||||
{
|
||||
return $this->installPath . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tmpPath
|
||||
* @return Installer
|
||||
*/
|
||||
public function setTmpPath($tmpPath)
|
||||
{
|
||||
$this->tmpPath = realpath($tmpPath);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getTmpPath($path = '')
|
||||
{
|
||||
return $this->tmpPath . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports about specific stages during installation.
|
||||
*
|
||||
* @param null $state
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function progressReport($state = null)
|
||||
{
|
||||
switch ($state) {
|
||||
case 'phar-downloaded':
|
||||
return file_exists($this->getTmpPath('/composer.phar'));
|
||||
case 'phar-extracted':
|
||||
return file_exists($this->getTmpPath('/composer-phar-extracted/vendor/autoload.php'));
|
||||
case 'dependencies-loaded':
|
||||
return file_exists($this->getBasePath('/vendor/autoload.php'));
|
||||
case 'cleaned-up':
|
||||
return $this->progressReport('dependencies-loaded') && !$this->progressReport('phar-extracted');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a json payload identifying the current state of installing.
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public function getCurrentState()
|
||||
{
|
||||
$state = null;
|
||||
|
||||
if ($this->progressReport('cleaned-up')) {
|
||||
$state = true;
|
||||
} elseif ($this->progressReport('dependencies-loaded')) {
|
||||
$state = 'Dependencies downloaded. Cleaning up ..';
|
||||
} elseif ($this->progressReport('phar-extracted')) {
|
||||
$state = 'Composer extracted. Loading dependencies, this will take the longest ..';
|
||||
} elseif ($this->progressReport('phar-downloaded')) {
|
||||
$state = 'Composer downloaded. Extracting ..';
|
||||
}
|
||||
|
||||
return json_encode($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for HTTP connections.
|
||||
*/
|
||||
public function listen()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
return $this->listenAjax();
|
||||
}
|
||||
// show temporary installation page
|
||||
ob_end_clean();
|
||||
ob_start();
|
||||
include $this->getInstallPath('/views/composer-installation.html');
|
||||
ob_end_flush();
|
||||
|
||||
$this->runInstall();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for XHR calls.
|
||||
*/
|
||||
public function listenAjax()
|
||||
{
|
||||
echo $this->getCurrentState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the actual installation steps.
|
||||
*/
|
||||
protected function runInstall()
|
||||
{
|
||||
if (!$this->progressReport('phar-extracted') && !$this->progressReport('phar-downloaded')) {
|
||||
$this->downloadComposerPhar();
|
||||
}
|
||||
if (!$this->progressReport('phar-extracted') && $this->progressReport('phar-downloaded')) {
|
||||
$this->extractComposerPhar();
|
||||
}
|
||||
if ($this->progressReport('phar-extracted')) {
|
||||
$this->installDependencies();
|
||||
}
|
||||
if ($this->progressReport('dependencies-loaded')) {
|
||||
$this->cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the composer.phar.
|
||||
*/
|
||||
protected function downloadComposerPhar()
|
||||
{
|
||||
$c = curl_init('https://getcomposer.org/composer.phar');
|
||||
curl_setopt_array($c, [
|
||||
CURLOPT_RETURNTRANSFER => true
|
||||
]);
|
||||
$phar = curl_exec($c);
|
||||
curl_close($c);
|
||||
|
||||
file_put_contents($this->getTmpPath('/composer.phar'), $phar);
|
||||
|
||||
unset($phar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the composer.phar.
|
||||
*/
|
||||
protected function extractComposerPhar()
|
||||
{
|
||||
$composer = new Phar($this->getTmpPath('/composer.phar'));
|
||||
$composer->extractTo($this->getTmpPath('/composer-phar-extracted'), null, true);
|
||||
|
||||
unset($composer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs dependencies using composer phar packages.
|
||||
*/
|
||||
protected function installDependencies()
|
||||
{
|
||||
require_once $this->getTmpPath('/composer-phar-extracted/vendor/autoload.php');
|
||||
|
||||
chdir($this->getBasePath());
|
||||
|
||||
// run the composer installation command
|
||||
$application = new Application();
|
||||
// disable auto exit
|
||||
$application->setAutoExit(false);
|
||||
|
||||
// first set the github token to prevent installation errors
|
||||
$input = new ArrayInput([
|
||||
'command' => 'config',
|
||||
'github-oauth.github.com' => self::GITHUB_TOKEN
|
||||
]);
|
||||
$application->run($input);
|
||||
|
||||
// set the input for the composer install command
|
||||
$input = new ArrayInput([
|
||||
'command' => 'install',
|
||||
'--no-dev' => true,
|
||||
'--prefer-dist' => true,
|
||||
'--optimize-autoloader' => true,
|
||||
'-q' => true
|
||||
]);
|
||||
$application->run($input);
|
||||
|
||||
unset($input, $application);
|
||||
|
||||
chdir($this->getInstallPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up all tmp files.
|
||||
*/
|
||||
protected function cleanUp()
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
|
||||
$fs->remove([
|
||||
$this->getTmpPath('/composer.phar'),
|
||||
$this->getTmpPath('/composer-home'),
|
||||
$this->getTmpPath('/composer-phar-extracted'),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -42,17 +42,24 @@
|
|||
You are installing Flarum without composer. We need to download some missing packages. This will take a few
|
||||
minutes to complete.
|
||||
</p>
|
||||
<p class="status">
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
|
||||
<script>
|
||||
setInterval(function() {
|
||||
$.ajax('?install-done', {
|
||||
success: function(done) {
|
||||
console.log(done);
|
||||
if(done == 1) {
|
||||
location.reload();
|
||||
var statusElement = $('p.status');
|
||||
$.ajax('#', {
|
||||
method: 'post',
|
||||
success: function(state) {
|
||||
console.log(state);
|
||||
if(state == 'true') {
|
||||
location.replace(location.pathname.replace('/install/index.php', ''));
|
||||
} else if(statusElement.text() != state) {
|
||||
statusElement.text(state);
|
||||
}
|
||||
}
|
||||
});
|
Binary file not shown.
Loading…
Reference in New Issue