Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
50.00% |
1 / 2 |
CRAP | |
84.67% |
116 / 137 |
| PhpExtensionCheck | |
0.00% |
0 / 1 |
|
50.00% |
1 / 2 |
35.69 | |
84.67% |
116 / 137 |
| getDefaultGroupName() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| run() | |
0.00% |
0 / 1 |
34.54 | |
84.56% |
115 / 136 |
|||
| <?php | |
| namespace Environaut\Checks; | |
| use Environaut\Checks\Check; | |
| use Environaut\Checks\PhpSettingCheck; | |
| /** | |
| * This check compares PHP extensions and their version and settings against given values. | |
| * By default the name of the check will be used as the PHP extension name that is checked. | |
| * | |
| * All supported parameters are: | |
| * - "extension": name of extension to check (defaults to the "name" of the check) | |
| * - "custom_name": name to be used for messages if the check's name is used as extension name | |
| * - "loaded": boolean parameter to determine if the extension should be loaded or not | |
| * - "version": the version string the extension should match (e.g. ">=2.6.30" or ">1.0.2") | |
| * - "regex": regular expression(s) that should match on the extension's info (see phpinfo) | |
| * - "help": message to display when the extension does not fulfil the "version", "regex" and/or "loaded" parameters | |
| * - "debug": var_dump's extension name, version and info string for regex analysis | |
| * | |
| * As the version of a PHP extension may be empty or some weird value you can use a version comparison of a phpinfo() | |
| * string by using a nested "version" parameter like this: | |
| * | |
| * <parameter name="version"> | |
| * <parameter name="regex"><![CDATA[#libXML (Compiled )?Version => (?P<version>\d+.+?)\n#]]></parameter> | |
| * <parameter name="value"><![CDATA[>=2.6.30]]></parameter> | |
| * </parameter> | |
| * | |
| * Notice, that you need a NAMED CAPTURING GROUP "version" in you regular expression. The "value" then specifies the | |
| * version comparison operation that should be done with that matching group. | |
| */ | |
| class PhpExtensionCheck extends Check | |
| { | |
| /** | |
| * Default group name used in messages of the report. | |
| * By default also used as default setting group name if not customized. | |
| */ | |
| const DEFAULT_CUSTOM_GROUP_NAME = 'PHP Extensions'; | |
| /** | |
| * Returns the default group name this check uses when none is specified. | |
| * | |
| * @return string default group name of the check | |
| */ | |
| public function getDefaultGroupName() | |
| { | |
| return self::DEFAULT_CUSTOM_GROUP_NAME; | |
| } | |
| public function run() | |
| { | |
| $params = $this->getParameters(); | |
| $extension = $params->get('extension', $this->getName()); | |
| if (empty($extension)) { | |
| throw new \InvalidArgumentException( | |
| 'Parameter "extension" must be a php extension name to check on class "' . get_class($this) . '".' | |
| ); | |
| } | |
| $custom_name = $params->get('custom_name', $this->getName()); | |
| $help = $params->get('help'); | |
| $wanted_version = $params->get('version'); | |
| $loaded = $params->get('loaded'); | |
| $regex = $params->get('regex'); | |
| $debug_mode = $params->get('debug', false); | |
| $okay = true; | |
| try { | |
| // GATHER DATA | |
| $extension_class = new \ReflectionExtension($extension); | |
| $extension_version = $extension_class->getVersion(); | |
| ob_start(); | |
| $extension_class->info(); | |
| $info = ob_get_clean(); | |
| if ($debug_mode) { | |
| var_dump($extension, $extension_version, $info, '============================================'); | |
| } | |
| // OPTIONS CHECK | |
| if (null !== $regex) { | |
| if (is_array($regex)) { // multiple regular expressions | |
| foreach ($regex as $key => $test) { | |
| if (!is_string($test)) { | |
| throw new \InvalidArgumentException( | |
| 'The extension requirements must be strings that are valid regular expressions.' | |
| ); | |
| } | |
| if (strpos($test, '(?P<contains>') !== false && !is_numeric($key)) { | |
| // explode "name" attribute & match each item in the named capturing group "contains" w/ it | |
| $values = explode(',', $key); | |
| $values = array_map('trim', $values); | |
| $regex_matches = preg_match($test, $info, $matches); | |
| if ($regex_matches) { | |
| $pool = $matches['contains']; | |
| foreach ($values as $value) { | |
| if (strpos($pool, $value) === false) { | |
| $this->addError( | |
| 'The extension "' . $extension . '" does not have "' . | |
| $value . '" support.', | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } else { | |
| $this->addInfo( | |
| 'The extension "' . $extension . '" does have "' . $value . '" support.', | |
| $custom_name | |
| ); | |
| } | |
| } | |
| } | |
| } else { // just preg_match the given regex string | |
| if (!preg_match($test, $info)) { | |
| $this->addError( | |
| 'The extension "' . $extension . '" does not match the requirement: ' . $test, | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } else { | |
| $this->addInfo( | |
| 'The extension "' . $extension . '" does match the requirement: ' . $test, | |
| $custom_name | |
| ); | |
| } | |
| } | |
| } | |
| } else { // single regex to test | |
| if (!preg_match($regex, $info)) { | |
| $this->addError( | |
| 'The extension "' . $extension . '" does not match the requirement: ' . $regex, | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } else { | |
| $this->addInfo( | |
| 'The extension "' . $extension . '" does match the requirement: ' . $regex, | |
| $custom_name | |
| ); | |
| } | |
| } | |
| } | |
| // VERSION COMPARISON | |
| if (null !== $wanted_version) { | |
| if (is_array($wanted_version) && array_key_exists('regex', $wanted_version) && | |
| array_key_exists('value', $wanted_version)) { | |
| $regex_matches = preg_match($wanted_version['regex'], $info, $matches); | |
| if (!$regex_matches || !array_key_exists('version', $matches)) { | |
| $this->addError( | |
| 'Version information of "' . $extension . '" could not be determined, as ' . | |
| 'the given regular expression did not match: "' . $wanted_version['regex'] . PHP_EOL . | |
| 'Remember that you need a valid named capturing group "version" in the ' . | |
| 'regexp, e.g.: #libXML (Compiled )?Version => (?P<version>\d+.+?)\n#' . PHP_EOL . | |
| 'Set the parameter "debug" to true to work on that matching regex.', | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } elseif ($regex_matches) { | |
| $operator = PhpSettingCheck::getOperator($wanted_version['value']); | |
| $wanted_version_without_operator = ltrim($wanted_version['value'], '<>!='); | |
| if (!version_compare($matches['version'], $wanted_version_without_operator, $operator)) { | |
| $this->addError( | |
| 'Version of "' . $extension . '" should be "' . $wanted_version['value'] . | |
| '", but is: "' . $matches['version'] . '"', | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } else { | |
| $this->addInfo( | |
| 'Version of extension "' . $extension . '" is "' . $matches['version'] . | |
| '" ("' . $wanted_version['value'] . '").', | |
| $custom_name | |
| ); | |
| } | |
| } | |
| } elseif (is_string($wanted_version)) { | |
| $operator = PhpSettingCheck::getOperator($wanted_version); | |
| $wanted_version_without_operator = ltrim($wanted_version, '<>!='); | |
| if (!version_compare($extension_version, $wanted_version_without_operator, $operator)) { | |
| $this->addError( | |
| 'Version of "' . $extension . '" should be "' . $wanted_version . | |
| '", but is: "' . $extension_version . '"', | |
| $custom_name | |
| ); | |
| $okay = false; | |
| } else { | |
| $this->addInfo( | |
| 'Version of extension "' . $extension . '" is "' . $extension_version . '"' . | |
| ' ("' . $wanted_version. '").', | |
| $custom_name | |
| ); | |
| } | |
| } else { | |
| throw new \InvalidArgumentException( | |
| 'A nested version parameter needs exactly two keys: ' . PHP_EOL . | |
| '- "regex" with one matching named capturing group "version" (e.g. ' . | |
| '"#libXML (Compiled )?Version => (?P<version>\d+.+?)\n#") and ' . PHP_EOL . | |
| '- "value" to compare the named capturing group content against' . | |
| '(version comparison, e.g. ">=2.6.26").' | |
| ); | |
| } | |
| } | |
| // LOADED CHECK | |
| if (null !== $loaded) { | |
| if ($loaded != extension_loaded($extension)) { | |
| $loaded_string = $loaded ? 'not loaded, but should be.' : 'loaded, but should not be.'; | |
| $this->addError('The extension "' . $extension . '" is ' . $loaded_string, $custom_name); | |
| $okay = false; | |
| } else { | |
| $this->addInfo('The extension "' . $extension . '" is loaded.', $custom_name); | |
| } | |
| } | |
| } catch (\ReflectionException $e) { | |
| $this->addError('There is no extension with the name "' . $extension . '".', $custom_name); | |
| $okay = false; | |
| } | |
| if (!$okay && $help !== null) { | |
| $this->addNotice($help, $custom_name); | |
| } | |
| if ($okay) { | |
| $this->addInfo('Extension "' . $extension . '" is available and correct.', $custom_name); | |
| } | |
| return $okay; | |
| } | |
| } |