You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
418 lines
13 KiB
418 lines
13 KiB
<?php
|
|
|
|
require_once __DIR__ . '/SymfonyRequirements.php';
|
|
|
|
use Symfony\Component\Process\ProcessBuilder;
|
|
use Symfony\Component\Intl\Intl;
|
|
|
|
use Chamilo\InstallerBundle\Process\PhpExecutableFinder;
|
|
|
|
/**
|
|
* This class specifies all requirements and optional recommendations
|
|
* that are necessary to run the Chamilo Application.
|
|
*/
|
|
class ChamiloRequirements extends SymfonyRequirements
|
|
{
|
|
const REQUIRED_PHP_VERSION = '5.3.3';
|
|
const REQUIRED_GD_VERSION = '2.0';
|
|
const REQUIRED_CURL_VERSION = '7.0';
|
|
const REQUIRED_ICU_VERSION = '3.8';
|
|
|
|
const EXCLUDE_REQUIREMENTS_MASK = '/5\.3\.(3|4|8|16)|5\.4\.0/';
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$phpVersion = phpversion();
|
|
$gdVersion = defined('GD_VERSION') ? GD_VERSION : null;
|
|
$curlVersion = function_exists('curl_version') ? curl_version() : null;
|
|
$icuVersion = Intl::getIcuVersion();
|
|
|
|
$this->addChamiloRequirement(
|
|
version_compare($phpVersion, self::REQUIRED_PHP_VERSION, '>='),
|
|
sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $phpVersion),
|
|
sprintf(
|
|
'You are running PHP version "<strong>%s</strong>", but Chamilo needs at least PHP "<strong>%s</strong>" to run.' .
|
|
'Before using Chamilo, upgrade your PHP installation, preferably to the latest version.',
|
|
$phpVersion,
|
|
self::REQUIRED_PHP_VERSION
|
|
),
|
|
sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $phpVersion)
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
null !== $gdVersion && version_compare($gdVersion, self::REQUIRED_GD_VERSION, '>='),
|
|
'GD extension must be at least ' . self::REQUIRED_GD_VERSION,
|
|
'Install and enable the <strong>GD</strong> extension at least ' . self::REQUIRED_GD_VERSION . ' version'
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
null !== $curlVersion && version_compare($curlVersion['version'], self::REQUIRED_CURL_VERSION, '>='),
|
|
'cURL extension must be at least ' . self::REQUIRED_CURL_VERSION,
|
|
'Install and enable the <strong>cURL</strong> extension at least ' . self::REQUIRED_CURL_VERSION . ' version'
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
function_exists('mcrypt_encrypt'),
|
|
'mcrypt_encrypt() should be available',
|
|
'Install and enable the <strong>Mcrypt</strong> extension.'
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
class_exists('Locale'),
|
|
'intl extension should be available',
|
|
'Install and enable the <strong>intl</strong> extension.'
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
null !== $icuVersion && version_compare($icuVersion, self::REQUIRED_ICU_VERSION, '>='),
|
|
'icu library must be at least ' . self::REQUIRED_ICU_VERSION,
|
|
'Install and enable the <strong>icu</strong> library at least ' . self::REQUIRED_ICU_VERSION . ' version'
|
|
);
|
|
|
|
$this->addRecommendation(
|
|
class_exists('SoapClient'),
|
|
'SOAP extension should be installed (API calls)',
|
|
'Install and enable the <strong>SOAP</strong> extension.'
|
|
);
|
|
|
|
// Windows specific checks
|
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
|
$this->addRecommendation(
|
|
function_exists('finfo_open'),
|
|
'finfo_open() should be available',
|
|
'Install and enable the <strong>Fileinfo</strong> extension.'
|
|
);
|
|
|
|
$this->addRecommendation(
|
|
class_exists('COM'),
|
|
'COM extension should be installed',
|
|
'Install and enable the <strong>COM</strong> extension.'
|
|
);
|
|
}
|
|
|
|
// Unix specific checks
|
|
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
|
$this->addRequirement(
|
|
$this->checkFileNameLength(),
|
|
'Cache folder should not be inside encrypted directory',
|
|
'Move <strong>app/cache</strong> folder outside encrypted directory.'
|
|
);
|
|
}
|
|
|
|
// Web installer specific checks
|
|
if ('cli' !== PHP_SAPI) {
|
|
$output = $this->checkCliRequirements();
|
|
|
|
$requirement = new CliRequirement(
|
|
!$output,
|
|
'Requirements validation for PHP CLI',
|
|
'If you have multiple PHP versions installed, you need to configure CHAMILO_PHP_PATH variable with PHP binary path used by web server'
|
|
);
|
|
|
|
$requirement->setOutput($output);
|
|
|
|
$this->add($requirement);
|
|
}
|
|
|
|
$baseDir = realpath(__DIR__ . '/..');
|
|
$mem = $this->getBytes(ini_get('memory_limit'));
|
|
|
|
$this->addPhpIniRequirement(
|
|
'memory_limit',
|
|
function ($cfgValue) use ($mem) {
|
|
return $mem >= 256 * 1024 * 1024 || -1 == $mem;
|
|
},
|
|
false,
|
|
'memory_limit should be at least 256M',
|
|
'Set the "<strong>memory_limit</strong>" setting in php.ini<a href="#phpini">*</a> to at least "256M".'
|
|
);
|
|
|
|
/*$this->addRecommendation(
|
|
$this->checkNodeExists(),
|
|
'NodeJS should be installed',
|
|
'Install the <strong>NodeJS</strong>.'
|
|
);*/
|
|
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web/uploads'),
|
|
'web/uploads/ directory must be writable',
|
|
'Change the permissions of the "<strong>web/uploads/</strong>" directory so that the web server can write into it.'
|
|
);
|
|
|
|
/*$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web/media'),
|
|
'web/media/ directory must be writable',
|
|
'Change the permissions of the "<strong>web/media/</strong>" directory so that the web server can write into it.'
|
|
);
|
|
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web/bundles'),
|
|
'web/bundles/ directory must be writable',
|
|
'Change the permissions of the "<strong>web/bundles/</strong>" directory so that the web server can write into it.'
|
|
);*/
|
|
|
|
/*$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/app/attachment'),
|
|
'app/attachment/ directory must be writable',
|
|
'Change the permissions of the "<strong>app/attachment/</strong>" directory so that the web server can write into it.'
|
|
);*/
|
|
|
|
if (is_dir($baseDir . '/web/js')) {
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web/js'),
|
|
'web/js directory must be writable',
|
|
'Change the permissions of the "<strong>web/js</strong>" directory so that the web server can write into it.'
|
|
);
|
|
}
|
|
|
|
if (is_dir($baseDir . '/web/css')) {
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web/css'),
|
|
'web/css directory must be writable',
|
|
'Change the permissions of the "<strong>web/css</strong>" directory so that the web server can write into it.'
|
|
);
|
|
}
|
|
|
|
if (!is_dir($baseDir . '/web/css') || !is_dir($baseDir . '/web/js')) {
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/web'),
|
|
'web directory must be writable',
|
|
'Change the permissions of the "<strong>web</strong>" directory so that the web server can write into it.'
|
|
);
|
|
}
|
|
|
|
if (is_file($baseDir . '/app/config/parameters.yml')) {
|
|
$this->addChamiloRequirement(
|
|
is_writable($baseDir . '/app/config/parameters.yml'),
|
|
'app/config/parameters.yml file must be writable',
|
|
'Change the permissions of the "<strong>app/config/parameters.yml</strong>" file so that the web server can write into it.'
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Adds an Chamilo specific requirement.
|
|
*
|
|
* @param boolean $fulfilled Whether the requirement is fulfilled
|
|
* @param string $testMessage The message for testing the requirement
|
|
* @param string $helpHtml The help text formatted in HTML for resolving the problem
|
|
* @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
|
|
*/
|
|
public function addChamiloRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
|
|
{
|
|
$this->add(new ChamiloRequirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
|
|
}
|
|
|
|
/**
|
|
* Get the list of mandatory requirements (all requirements excluding PhpIniRequirement)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getMandatoryRequirements()
|
|
{
|
|
return array_filter(
|
|
$this->getRequirements(),
|
|
function ($requirement) {
|
|
return !($requirement instanceof PhpIniRequirement)
|
|
&& !($requirement instanceof ChamiloRequirement)
|
|
&& !($requirement instanceof CliRequirement);
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the list of PHP ini requirements
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPhpIniRequirements()
|
|
{
|
|
return array_filter(
|
|
$this->getRequirements(),
|
|
function ($requirement) {
|
|
return $requirement instanceof PhpIniRequirement;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the list of Chamilo specific requirements
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getChamiloRequirements()
|
|
{
|
|
return array_filter(
|
|
$this->getRequirements(),
|
|
function ($requirement) {
|
|
return $requirement instanceof ChamiloRequirement;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getCliRequirements()
|
|
{
|
|
return array_filter(
|
|
$this->getRequirements(),
|
|
function ($requirement) {
|
|
return $requirement instanceof CliRequirement;
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $val
|
|
* @return int
|
|
*/
|
|
protected function getBytes($val)
|
|
{
|
|
if (empty($val)) {
|
|
return 0;
|
|
}
|
|
|
|
preg_match('/([\-0-9]+)[\s]*([a-z]*)$/i', trim($val), $matches);
|
|
|
|
if (isset($matches[1])) {
|
|
$val = (int)$matches[1];
|
|
}
|
|
|
|
switch (strtolower($matches[2])) {
|
|
case 'g':
|
|
case 'gb':
|
|
$val *= 1024;
|
|
// no break
|
|
case 'm':
|
|
case 'mb':
|
|
$val *= 1024;
|
|
// no break
|
|
case 'k':
|
|
case 'kb':
|
|
$val *= 1024;
|
|
// no break
|
|
}
|
|
|
|
return (float)$val;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getRequirements()
|
|
{
|
|
$requirements = parent::getRequirements();
|
|
|
|
foreach ($requirements as $key => $requirement) {
|
|
$testMessage = $requirement->getTestMessage();
|
|
if (preg_match_all(self::EXCLUDE_REQUIREMENTS_MASK, $testMessage, $matches)) {
|
|
unset($requirements[$key]);
|
|
}
|
|
}
|
|
|
|
return $requirements;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getRecommendations()
|
|
{
|
|
$recommendations = parent::getRecommendations();
|
|
|
|
foreach ($recommendations as $key => $recommendation) {
|
|
$testMessage = $recommendation->getTestMessage();
|
|
if (preg_match_all(self::EXCLUDE_REQUIREMENTS_MASK, $testMessage, $matches)) {
|
|
unset($recommendations[$key]);
|
|
}
|
|
}
|
|
|
|
return $recommendations;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
protected function checkNodeExists()
|
|
{
|
|
$nodeExists = new ProcessBuilder(array('node', '--version'));
|
|
$nodeExists = $nodeExists->getProcess();
|
|
|
|
if (isset($_SERVER['PATH'])) {
|
|
$nodeExists->setEnv(array('PATH' => $_SERVER['PATH']));
|
|
}
|
|
$nodeExists->run();
|
|
|
|
return $nodeExists->getErrorOutput() === null;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
protected function checkFileNameLength()
|
|
{
|
|
$getConf = new ProcessBuilder(array('getconf', 'NAME_MAX', __DIR__));
|
|
$getConf = $getConf->getProcess();
|
|
|
|
if (isset($_SERVER['PATH'])) {
|
|
$getConf->setEnv(array('PATH' => $_SERVER['PATH']));
|
|
}
|
|
$getConf->run();
|
|
|
|
if ($getConf->getErrorOutput()) {
|
|
// getconf not installed
|
|
return true;
|
|
}
|
|
|
|
$fileLength = trim($getConf->getOutput());
|
|
|
|
return $fileLength == 255;
|
|
}
|
|
|
|
/**
|
|
* @return null|string
|
|
*/
|
|
protected function checkCliRequirements()
|
|
{
|
|
$finder = new PhpExecutableFinder();
|
|
$command = sprintf(
|
|
'%s %schamilo-check.php',
|
|
$finder->find(),
|
|
__DIR__ . DIRECTORY_SEPARATOR
|
|
);
|
|
|
|
return shell_exec($command);
|
|
}
|
|
}
|
|
|
|
class ChamiloRequirement extends Requirement
|
|
{
|
|
}
|
|
|
|
class CliRequirement extends Requirement
|
|
{
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $output;
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getOutput()
|
|
{
|
|
return $this->output;
|
|
}
|
|
|
|
/**
|
|
* @param string $output
|
|
*/
|
|
public function setOutput($output)
|
|
{
|
|
$this->output = $output;
|
|
}
|
|
}
|
|
|