diff --git a/composer.json b/composer.json index 216b3e5e..24ecaa12 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "squizlabs/php_codesniffer": "^3.0" }, "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", "ext-gmp": "Provides support for converting UUID to 128-bit integer (in string form).", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", diff --git a/src/Provider/Node/SystemNodeProvider.php b/src/Provider/Node/SystemNodeProvider.php index 895ff19b..ae6a09ea 100644 --- a/src/Provider/Node/SystemNodeProvider.php +++ b/src/Provider/Node/SystemNodeProvider.php @@ -62,6 +62,10 @@ public function getNode() */ protected function getIfconfig() { + if (strpos(strtolower(ini_get('disable_functions')), 'passthru') !== false) { + return ''; + } + ob_start(); switch (strtoupper(substr(php_uname('a'), 0, 3))) { case 'WIN': diff --git a/tests/Provider/Node/SystemNodeProviderTest.php b/tests/Provider/Node/SystemNodeProviderTest.php index c14e38cd..46c38e3c 100644 --- a/tests/Provider/Node/SystemNodeProviderTest.php +++ b/tests/Provider/Node/SystemNodeProviderTest.php @@ -19,6 +19,7 @@ * - php_uname * - passthru * - file_get_contents + * - ini_get * * On Linux systems `glob` would normally provide one or more paths were mac * address can be retrieved (using `file_get_contents`). On non-linux systems, @@ -37,6 +38,7 @@ class SystemNodeProviderTest extends TestCase const MOCK_UNAME = 'php_uname'; const MOCK_PASSTHRU = 'passthru'; const MOCK_FILE_GET_CONTENTS = 'file_get_contents'; + const MOCK_INI_GET = 'ini_get'; const PROVIDER_NAMESPACE = 'Ramsey\\Uuid\\Provider\\Node'; @@ -61,7 +63,8 @@ public function testGetNodeReturnsSystemNodeFromMacAddress($netstatOutput, $expe function () use ($netstatOutput) { echo $netstatOutput; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act upon the system under test/*/ @@ -69,7 +72,7 @@ function () use ($netstatOutput) { $node = $provider->getNode(); /*/ Assert the result match expectations /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertSame($expected, $node); @@ -97,7 +100,8 @@ public function testGetNodeShouldNotReturnsSystemNodeForInvalidMacAddress($netst function () use ($netstatOutput) { echo $netstatOutput; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -105,7 +109,7 @@ function () use ($netstatOutput) { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertFalse($node); } @@ -128,7 +132,8 @@ public function testGetNodeReturnsNodeStrippedOfNotationalFormatting($formatted, function () use ($formatted) { echo "\n{$formatted}\n"; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -136,7 +141,7 @@ function () use ($formatted) { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals($expected, $node); } @@ -158,7 +163,8 @@ public function testGetNodeDoesNotAcceptIncorrectNotationalFormatting($formatted function () use ($formatted) { echo "\n{$formatted}\n"; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -166,7 +172,7 @@ function () use ($formatted) { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals(false, $node); } @@ -184,7 +190,8 @@ public function testGetNodeReturnsFirstMacAddressFound() function () { echo "\nAA-BB-CC-DD-EE-FF\n00-11-22-33-44-55\nFF-11-EE-22-DD-33\n"; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -192,7 +199,7 @@ function () { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals('AABBCCDDEEFF', $node); } @@ -210,7 +217,8 @@ public function testGetNodeReturnsFalseWhenNodeIsNotFound() function () { echo 'some string that does not match the mac address'; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -218,7 +226,7 @@ function () { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertFalse($node); } @@ -236,7 +244,8 @@ public function testGetNodeWillNotExecuteSystemCallIfFailedFirstTime() function () { echo 'some string that does not match the mac address'; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -245,7 +254,7 @@ function () { $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertInstanceOf(SystemNodeProvider::class, $provider); } @@ -266,7 +275,8 @@ public function testGetNodeGetsNetworkInterfaceConfig($os, $command) 'whatever', ['mock address path'], 'whatever', - $os + $os, + 'nothing disabled' ); /*/ Act /*/ @@ -280,7 +290,7 @@ public function testGetNodeGetsNetworkInterfaceConfig($os, $command) $globBodyAssert = ['/sys/class/net/*/address']; $fileGetContentsAssert = ['mock address path']; } - $this->assertMockFunctions($fileGetContentsAssert, $globBodyAssert, [$command], [['a'], ['s']]); + $this->assertMockFunctions($fileGetContentsAssert, $globBodyAssert, [$command], [['a'], ['s']], ['disable_functions']); $this->assertInstanceOf(SystemNodeProvider::class, $provider); } @@ -298,7 +308,8 @@ public function testGetNodeReturnsSameNodeUponSubsequentCalls() function () { echo "\nAA-BB-CC-DD-EE-FF\n"; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -307,7 +318,7 @@ function () { $node2 = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals($node, $node2); } @@ -325,7 +336,8 @@ public function testSubsequentCallsToGetNodeDoNotRecallIfconfig() function () { echo "\nAA-BB-CC-DD-EE-FF\n"; }, - 'NOT LINUX' + 'NOT LINUX', + 'nothing disabled' ); /*/ Act /*/ @@ -334,7 +346,7 @@ function () { $node2 = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, null, ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals($node, $node2); } @@ -360,7 +372,8 @@ function () { function () { echo "\n01-02-03-04-05-06\n"; }, - $os + $os, + 'nothing disabled' ); /*/ Act /*/ @@ -372,14 +385,16 @@ function () { $globBodyAssert = null; $passthruBodyAssert = [$command]; $unameBodyAssert = [['a'], ['s']]; + $iniGetDisableFunctionsAssert = ['disable_functions']; if ($os === 'Linux') { $fileGetContentsAssert = [['mock address path 1'], ['mock address path 2']]; $globBodyAssert = ['/sys/class/net/*/address']; $passthruBodyAssert = null; $unameBodyAssert = ['s']; + $iniGetDisableFunctionsAssert = null; } - $this->assertMockFunctions($fileGetContentsAssert, $globBodyAssert, $passthruBodyAssert, $unameBodyAssert); + $this->assertMockFunctions($fileGetContentsAssert, $globBodyAssert, $passthruBodyAssert, $unameBodyAssert, $iniGetDisableFunctionsAssert); $this->assertEquals('010203040506', $node); } @@ -397,7 +412,8 @@ public function testCallGetsysfsOnLinuxWhenGlobReturnsFalse() function () { echo "\n01-02-03-04-05-06\n"; }, - 'Linux' + 'Linux', + 'nothing disabled' ); /*/ Act /*/ @@ -405,7 +421,7 @@ function () { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, ['/sys/class/net/*/address'], ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, ['/sys/class/net/*/address'], ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals('010203040506', $node); } @@ -423,7 +439,8 @@ public function testCallGetsysfsOnLinuxWhenGlobReturnsEmptyArray() function () { echo "\n01-02-03-04-05-06\n"; }, - 'Linux' + 'Linux', + 'nothing disabled' ); /*/ Act /*/ @@ -431,11 +448,36 @@ function () { $node = $provider->getNode(); /*/ Assert /*/ - $this->assertMockFunctions(null, ['/sys/class/net/*/address'], ['netstat -ie 2>&1'], [['a'], ['s']]); + $this->assertMockFunctions(null, ['/sys/class/net/*/address'], ['netstat -ie 2>&1'], [['a'], ['s']], ['disabled_functions']); $this->assertEquals('010203040506', $node); } + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testGetNodeReturnsFalseWhenPassthruIsDisabled() + { + /*/ Arrange /*/ + $this->arrangeMockFunctions( + null, + null, + null, + 'NOT LINUX', + 'PASSTHRU,some_other_function' + ); + + /*/ Act /*/ + $provider = new SystemNodeProvider(); + $node = $provider->getNode(); + + /*/ Assert /*/ + $this->assertMockFunctions(null, null, null, [['s']], ['disabled_functions']); + + $this->assertFalse($node); + } + /** * Replaces the return value for functions with the given value or callback. * @@ -443,14 +485,21 @@ function () { * @param callback|mixed|null $globBody * @param callback|mixed|null $passthruBody * @param callback|mixed|null $unameBody + * @param callback|mixed|null $iniGetDisableFunctionsBody */ - private function arrangeMockFunctions($fileGetContentsBody, $globBody, $passthruBody, $unameBody) - { + private function arrangeMockFunctions( + $fileGetContentsBody, + $globBody, + $passthruBody, + $unameBody, + $iniGetDisableFunctionsBody + ) { $mockFunction = [ self::MOCK_FILE_GET_CONTENTS => $fileGetContentsBody, self::MOCK_GLOB => $globBody, self::MOCK_PASSTHRU => $passthruBody, self::MOCK_UNAME => $unameBody, + self::MOCK_INI_GET => $iniGetDisableFunctionsBody, ]; array_walk($mockFunction, function ($body, $key) { @@ -467,14 +516,21 @@ private function arrangeMockFunctions($fileGetContentsBody, $globBody, $passthru * @param array|callable|null $globBodyAssert * @param array|callable|null $passthruBodyAssert * @param array|callable|null $unameBodyAssert + * @param array|callable|null $iniGetDisableFunctionsAssert */ - private function assertMockFunctions($fileGetContentsAssert, $globBodyAssert, $passthruBodyAssert, $unameBodyAssert) - { + private function assertMockFunctions( + $fileGetContentsAssert, + $globBodyAssert, + $passthruBodyAssert, + $unameBodyAssert, + $iniGetDisableFunctionsAssert + ) { $mockFunctionAsserts = [ self::MOCK_FILE_GET_CONTENTS => $fileGetContentsAssert, self::MOCK_GLOB => $globBodyAssert, self::MOCK_PASSTHRU => $passthruBodyAssert, self::MOCK_UNAME => $unameBodyAssert, + self::MOCK_INI_GET => $iniGetDisableFunctionsAssert, ]; array_walk($mockFunctionAsserts, function ($asserts, $key) {