commit b6fd1d7ab5f3bf72c71920967c59a1171ee347f4
parent 226c366ef3db532beb80309a3cf4c178bf9edf33
Author: Felicitus <felicitus@felicitus.org>
Date: Tue, 7 Jul 2015 23:52:09 +0200
Forgot to add new sf2 requirement checks
Diffstat:
M | app/SymfonyRequirements.php | | | 150 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | app/check.php | | | 148 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
2 files changed, 215 insertions(+), 83 deletions(-)
diff --git a/app/SymfonyRequirements.php b/app/SymfonyRequirements.php
@@ -41,25 +41,25 @@ class Requirement
/**
* Constructor that initializes the requirement.
*
- * @param Boolean $fulfilled Whether the requirement is fulfilled
+ * @param bool $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)
- * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement
+ * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement
*/
public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false)
{
- $this->fulfilled = (Boolean) $fulfilled;
+ $this->fulfilled = (bool) $fulfilled;
$this->testMessage = (string) $testMessage;
$this->helpHtml = (string) $helpHtml;
$this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText;
- $this->optional = (Boolean) $optional;
+ $this->optional = (bool) $optional;
}
/**
* Returns whether the requirement is fulfilled.
*
- * @return Boolean true if fulfilled, otherwise false
+ * @return bool true if fulfilled, otherwise false
*/
public function isFulfilled()
{
@@ -99,7 +99,7 @@ class Requirement
/**
* Returns whether this is only an optional recommendation and not a mandatory requirement.
*
- * @return Boolean true if optional, false if mandatory
+ * @return bool true if optional, false if mandatory
*/
public function isOptional()
{
@@ -117,16 +117,16 @@ class PhpIniRequirement extends Requirement
/**
* Constructor that initializes the requirement.
*
- * @param string $cfgName The configuration name used for ini_get()
- * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
- * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
- * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
- * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
- * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
- * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
- * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
- * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
- * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
+ * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
+ * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement
*/
public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false)
{
@@ -193,7 +193,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Adds a mandatory requirement.
*
- * @param Boolean $fulfilled Whether the requirement is fulfilled
+ * @param bool $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)
@@ -206,7 +206,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Adds an optional recommendation.
*
- * @param Boolean $fulfilled Whether the recommendation is fulfilled
+ * @param bool $fulfilled Whether the recommendation is fulfilled
* @param string $testMessage The message for testing the recommendation
* @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)
@@ -219,15 +219,15 @@ class RequirementCollection implements IteratorAggregate
/**
* Adds a mandatory requirement in form of a php.ini configuration.
*
- * @param string $cfgName The configuration name used for ini_get()
- * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
- * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
- * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
- * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
- * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
- * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
- * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
- * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
+ * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
*/
public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
{
@@ -237,15 +237,15 @@ class RequirementCollection implements IteratorAggregate
/**
* Adds an optional recommendation in form of a php.ini configuration.
*
- * @param string $cfgName The configuration name used for ini_get()
- * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false,
- * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
- * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
- * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
- * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
- * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived)
- * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived)
- * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
+ * @param string $cfgName The configuration name used for ini_get()
+ * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
+ * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
+ * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
+ * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
+ * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
+ * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
+ * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
+ * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
*/
public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
{
@@ -343,7 +343,7 @@ class RequirementCollection implements IteratorAggregate
/**
* Returns whether a php.ini configuration is not correct.
*
- * @return Boolean php.ini configuration problem?
+ * @return bool php.ini configuration problem?
*/
public function hasPhpIniConfigIssue()
{
@@ -405,22 +405,24 @@ class SymfonyRequirements extends RequirementCollection
$this->addRequirement(
is_dir(__DIR__.'/../vendor/composer'),
'Vendor libraries must be installed',
- 'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. ' .
+ 'Vendor libraries are missing. Install composer following instructions from <a href="http://getcomposer.org/">http://getcomposer.org/</a>. '.
'Then run "<strong>php composer.phar install</strong>" to install them.'
);
- $baseDir = basename(__DIR__);
+ $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache';
$this->addRequirement(
- is_writable(__DIR__.'/cache'),
- "$baseDir/cache/ directory must be writable",
- "Change the permissions of the \"<strong>$baseDir/cache/</strong>\" directory so that the web server can write into it."
+ is_writable($cacheDir),
+ 'app/cache/ or var/cache/ directory must be writable',
+ 'Change the permissions of either "<strong>app/cache/</strong>" or "<strong>var/cache/</strong>" directory so that the web server can write into it.'
);
+ $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs';
+
$this->addRequirement(
- is_writable(__DIR__.'/logs'),
- "$baseDir/logs/ directory must be writable",
- "Change the permissions of the \"<strong>$baseDir/logs/</strong>\" directory so that the web server can write into it."
+ is_writable($logsDir),
+ 'app/logs/ or var/logs/ directory must be writable',
+ 'Change the permissions of either "<strong>app/logs/</strong>" or "<strong>var/logs/</strong>" directory so that the web server can write into it.'
);
$this->addPhpIniRequirement(
@@ -438,8 +440,8 @@ class SymfonyRequirements extends RequirementCollection
}
$this->addRequirement(
- isset($timezones[date_default_timezone_get()]),
- sprintf('Configured default timezone "%s" must be supported by your installation of PHP', date_default_timezone_get()),
+ isset($timezones[@date_default_timezone_get()]),
+ sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.'
);
}
@@ -528,6 +530,16 @@ class SymfonyRequirements extends RequirementCollection
'Install the <strong>PCRE</strong> extension (version 8.0+).'
);
+ if (extension_loaded('mbstring')) {
+ $this->addPhpIniRequirement(
+ 'mbstring.func_overload',
+ create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
+ true,
+ 'string functions should not be overloaded',
+ 'Set "<strong>mbstring.func_overload</strong>" to <strong>0</strong> in php.ini<a href="#phpini">*</a> to disable function overloading by the mbstring extension.'
+ );
+ }
+
/* optional recommendations follow */
if (file_exists(__DIR__.'/../vendor/composer')) {
@@ -611,6 +623,12 @@ class SymfonyRequirements extends RequirementCollection
'Install and enable the <strong>XML</strong> extension.'
);
+ $this->addRecommendation(
+ function_exists('filter_var'),
+ 'filter_var() should be available',
+ 'Install and enable the <strong>filter</strong> extension.'
+ );
+
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->addRecommendation(
function_exists('posix_isatty'),
@@ -667,6 +685,8 @@ class SymfonyRequirements extends RequirementCollection
||
(extension_loaded('apc') && ini_get('apc.enabled'))
||
+ (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable'))
+ ||
(extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
||
(extension_loaded('xcache') && ini_get('xcache.cacher'))
@@ -677,9 +697,17 @@ class SymfonyRequirements extends RequirementCollection
$this->addRecommendation(
$accelerator,
'a PHP accelerator should be installed',
- 'Install and enable a <strong>PHP accelerator</strong> like APC (highly recommended).'
+ 'Install and/or enable a <strong>PHP accelerator</strong> (highly recommended).'
);
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ $this->addRecommendation(
+ $this->getRealpathCacheSize() > 1000,
+ 'realpath_cache_size should be above 1024 in php.ini',
+ 'Set "<strong>realpath_cache_size</strong>" to e.g. "<strong>1024</strong>" in php.ini<a href="#phpini">*</a> to improve performance on windows.'
+ );
+ }
+
$this->addPhpIniRecommendation('short_open_tag', false);
$this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
@@ -697,10 +725,34 @@ class SymfonyRequirements extends RequirementCollection
if (class_exists('PDO')) {
$drivers = PDO::getAvailableDrivers();
$this->addRecommendation(
- count($drivers),
+ count($drivers) > 0,
sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
'Install <strong>PDO drivers</strong> (mandatory for Doctrine).'
);
}
}
+
+ /**
+ * Loads realpath_cache_size from php.ini and converts it to int.
+ *
+ * (e.g. 16k is converted to 16384 int)
+ *
+ * @return int
+ */
+ protected function getRealpathCacheSize()
+ {
+ $size = ini_get('realpath_cache_size');
+ $size = trim($size);
+ $unit = strtolower(substr($size, -1, 1));
+ switch ($unit) {
+ case 'g':
+ return $size * 1024 * 1024 * 1024;
+ case 'm':
+ return $size * 1024 * 1024;
+ case 'k':
+ return $size * 1024;
+ default:
+ return (int) $size;
+ }
+ }
}
diff --git a/app/check.php b/app/check.php
@@ -2,61 +2,141 @@
require_once dirname(__FILE__).'/SymfonyRequirements.php';
+$lineSize = 70;
$symfonyRequirements = new SymfonyRequirements();
-
$iniPath = $symfonyRequirements->getPhpIniConfigPath();
-echo "********************************\n";
-echo "* *\n";
-echo "* Symfony requirements check *\n";
-echo "* *\n";
-echo "********************************\n\n";
-
-echo $iniPath ? sprintf("* Configuration file used by PHP: %s\n\n", $iniPath) : "* WARNING: No configuration file (php.ini) used by PHP!\n\n";
+echo_title('Symfony2 Requirements Checker');
-echo "** ATTENTION **\n";
-echo "* The PHP CLI can use a different php.ini file\n";
-echo "* than the one used with your web server.\n";
-if ('\\' == DIRECTORY_SEPARATOR) {
- echo "* (especially on the Windows platform)\n";
+echo '> PHP is using the following php.ini file:'.PHP_EOL;
+if ($iniPath) {
+ echo_style('green', ' '.$iniPath);
+} else {
+ echo_style('warning', ' WARNING: No configuration file (php.ini) used by PHP!');
}
-echo "* To be on the safe side, please also launch the requirements check\n";
-echo "* from your web server using the web/config.php script.\n";
-echo_title('Mandatory requirements');
+echo PHP_EOL.PHP_EOL;
+
+echo '> Checking Symfony requirements:'.PHP_EOL.' ';
-$checkPassed = true;
+$messages = array();
foreach ($symfonyRequirements->getRequirements() as $req) {
/** @var $req Requirement */
- echo_requirement($req);
- if (!$req->isFulfilled()) {
- $checkPassed = false;
+ if ($helpText = get_error_message($req, $lineSize)) {
+ echo_style('red', 'E');
+ $messages['error'][] = $helpText;
+ } else {
+ echo_style('green', '.');
}
}
-echo_title('Optional recommendations');
+$checkPassed = empty($messages['error']);
foreach ($symfonyRequirements->getRecommendations() as $req) {
- echo_requirement($req);
+ if ($helpText = get_error_message($req, $lineSize)) {
+ echo_style('yellow', 'W');
+ $messages['warning'][] = $helpText;
+ } else {
+ echo_style('green', '.');
+ }
+}
+
+if ($checkPassed) {
+ echo_block('success', 'OK', 'Your system is ready to run Symfony2 projects', true);
+} else {
+ echo_block('error', 'ERROR', 'Your system is not ready to run Symfony2 projects', true);
+
+ echo_title('Fix the following mandatory requirements', 'red');
+
+ foreach ($messages['error'] as $helpText) {
+ echo ' * '.$helpText.PHP_EOL;
+ }
}
+if (!empty($messages['warning'])) {
+ echo_title('Optional recommendations to improve your setup', 'yellow');
+
+ foreach ($messages['warning'] as $helpText) {
+ echo ' * '.$helpText.PHP_EOL;
+ }
+}
+
+echo PHP_EOL;
+echo_style('title', 'Note');
+echo ' The command console could use a different php.ini file'.PHP_EOL;
+echo_style('title', '~~~~');
+echo ' than the one used with your web server. To be on the'.PHP_EOL;
+echo ' safe side, please check the requirements from your web'.PHP_EOL;
+echo ' server using the ';
+echo_style('yellow', 'web/config.php');
+echo ' script.'.PHP_EOL;
+echo PHP_EOL;
+
exit($checkPassed ? 0 : 1);
-/**
- * Prints a Requirement instance
- */
-function echo_requirement(Requirement $requirement)
+function get_error_message(Requirement $requirement, $lineSize)
{
- $result = $requirement->isFulfilled() ? 'OK' : ($requirement->isOptional() ? 'WARNING' : 'ERROR');
- echo ' ' . str_pad($result, 9);
- echo $requirement->getTestMessage() . "\n";
-
- if (!$requirement->isFulfilled()) {
- echo sprintf(" %s\n\n", $requirement->getHelpText());
+ if ($requirement->isFulfilled()) {
+ return;
}
+
+ $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL;
+ $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL;
+
+ return $errorMessage;
}
-function echo_title($title)
+function echo_title($title, $style = null)
{
- echo "\n** $title **\n\n";
+ $style = $style ?: 'title';
+
+ echo PHP_EOL;
+ echo_style($style, $title.PHP_EOL);
+ echo_style($style, str_repeat('~', strlen($title)).PHP_EOL);
+ echo PHP_EOL;
+}
+
+function echo_style($style, $message)
+{
+ // ANSI color codes
+ $styles = array(
+ 'reset' => "\033[0m",
+ 'red' => "\033[31m",
+ 'green' => "\033[32m",
+ 'yellow' => "\033[33m",
+ 'error' => "\033[37;41m",
+ 'success' => "\033[37;42m",
+ 'title' => "\033[34m",
+ );
+ $supports = has_color_support();
+
+ echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : '');
+}
+
+function echo_block($style, $title, $message)
+{
+ $message = ' '.trim($message).' ';
+ $width = strlen($message);
+
+ echo PHP_EOL.PHP_EOL;
+
+ echo_style($style, str_repeat(' ', $width).PHP_EOL);
+ echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT).PHP_EOL);
+ echo_style($style, str_pad($message, $width, ' ', STR_PAD_RIGHT).PHP_EOL);
+ echo_style($style, str_repeat(' ', $width).PHP_EOL);
+}
+
+function has_color_support()
+{
+ static $support;
+
+ if (null === $support) {
+ if (DIRECTORY_SEPARATOR == '\\') {
+ $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
+ } else {
+ $support = function_exists('posix_isatty') && @posix_isatty(STDOUT);
+ }
+ }
+
+ return $support;
}