Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
failOnWarning="true"
colors="true">
<testsuites>
<testsuite name="default">
<directory>tests</directory>
<testsuite name="unit">
<directory>tests/unit</directory>
</testsuite>

<testsuite name="end-to-end">
<directory suffix=".phpt">tests/end-to-end</directory>
</testsuite>
</testsuites>

Expand Down
42 changes: 31 additions & 11 deletions src/Runtime.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
use function php_ini_loaded_file;
use function php_ini_scanned_files;
use function phpversion;
use function preg_match;
use function sprintf;
use function str_replace;
use function strrpos;
use function version_compare;
use function xdebug_info;
Expand Down Expand Up @@ -245,8 +247,9 @@ public function hasPCOV(): bool
*/
public function getCurrentSettings(array $values): array
{
$diff = [];
$files = [];
$diff = [];
$files = [];
$config = [];

$file = php_ini_loaded_file();

Expand All @@ -267,19 +270,36 @@ public function getCurrentSettings(array $values): array
}

foreach ($files as $ini) {
$config = parse_ini_file($ini, true);
$parsed = parse_ini_file($ini, true);

foreach ($values as $value) {
$set = ini_get($value);
if ($parsed === false) {
continue;
}

$config = array_merge($config, $parsed);
}

foreach ($values as $value) {
$set = ini_get($value);

if ($set === false || $set === '') {
continue;
}
// any empty values must not be skipped
// e.g. off as in xdebug.mode=off is reported as empty string
if ($set === false) {
continue;
}

if (isset($config[$value]) && $set === $config[$value]) {
continue;
}

if ((!isset($config[$value]) || ($set !== $config[$value]))) {
$diff[$value] = sprintf('%s=%s', $value, $set);
}
// https://www.php.net/manual/en/function.parse-ini-file.php
// If a value in the ini file contains any non-alphanumeric characters
// it needs to be enclosed in double-quotes
if (preg_match('/\W/', $set) === 1) {
$set = '"' . str_replace(['\\', '"'], ['\\\\', '\\"'], $set) . '"';
}

$diff[$value] = sprintf('%s=%s', $value, $set);
}

return $diff;
Expand Down
2 changes: 2 additions & 0 deletions tests/end-to-end/_fixture/first.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
display_errors=0
log_errors=1
2 changes: 2 additions & 0 deletions tests/end-to-end/_fixture/second.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
display_errors=0
error_reporting=32767
14 changes: 14 additions & 0 deletions tests/end-to-end/getCurrentSettings_backslash_escaped.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
getCurrentSettings escapes backslashes in values containing special characters
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

ini_set('error_prepend_string', 'a\\b');

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['error_prepend_string']);

print $result['error_prepend_string'];
?>
--EXPECT--
error_prepend_string="a\\b"
13 changes: 13 additions & 0 deletions tests/end-to-end/getCurrentSettings_empty_input.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
getCurrentSettings returns empty array when no values are passed
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings([]);

var_dump($result);
?>
--EXPECT--
array(0) {
}
22 changes: 22 additions & 0 deletions tests/end-to-end/getCurrentSettings_multiple_ini_files.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
getCurrentSettings merges multiple INI files and does not produce duplicates
--ENV--
PHP_INI_SCAN_DIR={PWD}/_fixture
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

// display_errors is set to 0 in both INI files and the runtime value
// matches, so it must not appear in the diff
$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings([
'display_errors',
'log_errors',
'error_reporting',
]);

// None of these should appear because runtime values match file values
var_dump($result);
?>
--EXPECT--
array(0) {
}
13 changes: 13 additions & 0 deletions tests/end-to-end/getCurrentSettings_no_runtime_change.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
getCurrentSettings returns empty array when setting is not changed at runtime
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['display_errors']);

var_dump($result);
?>
--EXPECT--
array(0) {
}
16 changes: 16 additions & 0 deletions tests/end-to-end/getCurrentSettings_off_not_skipped.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
getCurrentSettings does not skip settings whose runtime value is an empty string
--INI--
display_errors=1
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

ini_set('display_errors', '');

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['display_errors']);

var_dump(isset($result['display_errors']));
?>
--EXPECT--
bool(true)
14 changes: 14 additions & 0 deletions tests/end-to-end/getCurrentSettings_plain_value_not_quoted.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
getCurrentSettings does not quote plain alphanumeric values
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

ini_set('display_errors', '1');

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['display_errors']);

var_dump($result['display_errors']);
?>
--EXPECT--
string(16) "display_errors=1"
16 changes: 16 additions & 0 deletions tests/end-to-end/getCurrentSettings_runtime_override.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
getCurrentSettings detects setting changed at runtime via ini_set
--INI--
display_errors=0
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

ini_set('display_errors', '1');

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['display_errors']);

var_dump(isset($result['display_errors']));
?>
--EXPECT--
bool(true)
14 changes: 14 additions & 0 deletions tests/end-to-end/getCurrentSettings_special_chars_escaped.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
getCurrentSettings escapes values containing special characters
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

ini_set('error_prepend_string', '<b>"hello"</b>');

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['error_prepend_string']);

print $result['error_prepend_string'];
?>
--EXPECT--
error_prepend_string="<b>\"hello\"</b>"
13 changes: 13 additions & 0 deletions tests/end-to-end/getCurrentSettings_unknown_setting.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
getCurrentSettings returns empty array for nonexistent setting
--FILE--
<?php declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';

$result = (new SebastianBergmann\Environment\Runtime)->getCurrentSettings(['nonexistent_setting_xyz']);

var_dump($result);
?>
--EXPECT--
array(0) {
}
13 changes: 1 addition & 12 deletions tests/RuntimeTest.php → tests/unit/RuntimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use function assert;
use function extension_loaded;
use function in_array;
use function ini_get;
use function is_array;
use function xdebug_info;
use PHPUnit\Framework\Attributes\CoversClass;
Expand Down Expand Up @@ -137,19 +136,9 @@ public function testGetCurrentSettingsReturnsEmptyDiffIfNoValuesArePassed(): voi
$this->assertSame([], (new Runtime)->getCurrentSettings([]));
}

#[RequiresPhpExtension('xdebug')]
public function testGetCurrentSettingsReturnsCorrectDiffIfXdebugValuesArePassed(): void
{
if (ini_get('xdebug.mode') === '') {
$this->markTestSkipped('xdebug.mode must not be set to "off"');
}

$this->assertArrayHasKey('xdebug.mode', (new Runtime)->getCurrentSettings(['xdebug.mode']));
}

public function testGetCurrentSettingsWillSkipSettingsThatIsNotSet(): void
{
$this->assertSame([], (new Runtime)->getCurrentSettings(['allow_url_include']));
$this->assertSame([], (new Runtime)->getCurrentSettings(['foo_nonexistent_setting']));
}

private function markTestSkippedWhenPcovIsLoaded(): void
Expand Down
Loading