N°9675 - Set up crash - cannot get class from production#968
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses issue N°9675, where the setup/CLI process could crash ("cannot get class from production") because CheckCliPhpVersionFromOutput required the CLI PHP version to exactly match the UI PHP major.minor version and threw a CoreException on any mismatch. The fix reworks the CLI PHP check to instead validate the CLI PHP version against the application's minimum-supported version by reusing the existing CheckPhpVersion() logic, which is a much more tolerant and correct criterion.
Changes:
CheckPhpVersion()now accepts optional$sPhpVersionand$sPhpVersionDescparameters so the same check can be reused for the CLI version with a custom label.CheckCliPhpVersionFromOutput()dropped the UI-vs-CLI equality comparison and now parses the version fromphp --versionoutput and runs it throughCheckPhpVersion(), throwing only on WARNING/ERROR-level results.- The two CLI-check methods were relocated next to
CheckPhpVersion(), and tests were updated/added for the new behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| setup/setuputils.class.inc.php | Reworks CLI PHP version validation to check against the minimum supported version instead of an exact UI match; parameterizes CheckPhpVersion(). |
| tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php | Updates and adds tests for the new CLI/PHP version-check behavior. |
Notes for the author:
- A latent bug remains in the version-parse guard:
false === preg_match(...)only catches internal regex errors, so an unparseable output falls through to an undefined$aMatches[0]and ends up checking the UI'sphpversion()rather than returning early. - Minor: the
CheckPhpVersiondocblock omits the new$sPhpVersionDescparameter and lost its asterisk alignment, and theCheckOKProviderdata provider now feeds a "Fail" test, making its name misleading.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (false === preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { | ||
| return; | ||
| } |
| /** | ||
| * @param CheckResult[] $aResult checks log | ||
| * | ||
| * @since 3.0.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE | ||
| * @param CheckResult[] $aResult checks log | ||
| * @param string|null $sPhpVersion: if not provided, use current version | ||
| * @return void | ||
| */ |
| $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, '6.6', 'sPHPExec', [$sOuput]]); | ||
| } | ||
|
|
||
| public function CheckOKProvider() |
| public function testCheckCliPhpVersionFromOutputFail($sOuput, $sFoundVersion = '7.4') | ||
| { | ||
| $this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); | ||
| $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, '7.4', 'sPHPExec', [$sOuput]]); | ||
|
|
||
| $this->expectException(\CoreException::class); | ||
| $sDetails = sprintf('The current CLI PHP Version (%s) is lower than the minimum version required to run %s, which is (%s)', $sFoundVersion, ITOP_APPLICATION, SetupUtils::PHP_MIN_VERSION); | ||
|
|
||
| $this->expectExceptionMessage("Data consistency check failed: $sDetails"); | ||
| $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, 'sPHPExec', [$sOuput]]); |
| if (false === preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Use
1 !== preg_match(...) so the early-return fires for both "no match" (returns 0) and "PCRE error" (returns false), preventing the silent fall-through to an undefined $aMatches[0].
| if (false === preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { | |
| return; | |
| } | |
| if (1 !== preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { | |
| return; | |
| } |
| private static function CheckCliPhpVersionFromOutput(string $sErrorLabel, string $sPHPExec, $aOutput): void | ||
| { | ||
| $sFoundVersion = trim($aOutput[0] ?? ""); | ||
| if (false === preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { |
| * @dataProvider CheckOKProvider | ||
| */ | ||
| public function testCheckCliPhpVersionFromOutputOK($sOuput) | ||
| public function testCheckCliPhpVersionFromOutputFail($sOutput, $sFoundVersion = '7.4') |
| * @param CheckResult[] $aResult checks log | ||
| * @param string|null $sPhpVersion: if not provided, use current version | ||
| * @return void |
No description provided.