pull/31/merge
Daniël Klabbers 2017-05-24 03:33:05 +00:00 committed by GitHub
commit b92c92057b
4 changed files with 386 additions and 4 deletions

View File

@ -1,5 +1,4 @@
<?php
/*
* This file is part of Flarum.
*
@ -9,8 +8,13 @@
* file that was distributed with this source code.
*/
require 'vendor/autoload.php';
if (file_exists('vendor/autoload.php')) {
require_once 'vendor/autoload.php';
$server = new Flarum\Forum\Server(__DIR__);
(new Flarum\Forum\Server(__DIR__))->listen();
$server->listen();
} 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;
}

13
install/index.php Normal file
View File

@ -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();

297
install/src/Installer.php Normal file
View File

@ -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'),
]);
}
}

View File

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flarum is installing</title>
<meta name="description"
content="Flarum is the next-generation forum software that makes online discussion fun. It's simple, fast, and free.">
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="http://flarum.org/css/main.css">
</head>
<body class="home">
<header class="Header">
<div class="container">
<h1 class="Header-brand">
<a href="/">
<img src="http://flarum.org/img/logo.png" alt="Flarum Forums Made Simple" width="149" height="34">
</a>
</h1>
</div>
</header>
<header class="Intro">
<h1 class="Intro-brand">
<object data="http://flarum.org/img/logo.svg">
<img src="http://flarum.org/img/logo.png" alt="Flarum">
</object>
</h1>
<div class="animated fadeIn">
<div class="Intro-beta">BETA</div>
<h2>Forums made simple.</h2>
<p>
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() {
var statusElement = $('p.status');
$.ajax('#', {
method: 'post',
success: function(state) {
if(state == 'true') {
location.replace(location.pathname.replace('install/index.php', ''));
} else if(statusElement.text() != state) {
statusElement.text(state);
}
}
});
}, 5000);
</script>
</body>
</html>