Add Safe PHP functions

This commit is contained in:
Alex Cabal 2019-03-07 12:11:50 -06:00
parent 04a956886a
commit 58cc098058
260 changed files with 49458 additions and 45 deletions

View file

@ -0,0 +1,28 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
class DocPageTest extends TestCase
{
public function testDetectFalsyFunction() {
$pregMatch = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/pcre/functions/preg-match.xml');
$implode = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/strings/functions/implode.xml');
$getCwd = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/dir/functions/getcwd.xml');
$setTime = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/datetime/datetime/settime.xml');
$filesize = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/filesystem/functions/filesize.xml');
$sessionRegister = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/session/functions/session-register.xml');
$mcryptDecrypt = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/mcrypt/functions/mcrypt-decrypt.xml');
$fsockopen = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/network/functions/fsockopen.xml');
$this->assertTrue($pregMatch->detectFalsyFunction());
$this->assertFalse($implode->detectFalsyFunction());
$this->assertTrue($getCwd->detectFalsyFunction());
$this->assertTrue($setTime->detectFalsyFunction());
$this->assertTrue($filesize->detectFalsyFunction());
$this->assertFalse($sessionRegister->detectFalsyFunction());
$this->assertTrue($mcryptDecrypt->detectFalsyFunction());
$this->assertTrue($fsockopen->detectFalsyFunction());
}
}

View file

@ -0,0 +1,142 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
use function restore_error_handler;
use Safe\Exceptions\StringsException;
use SimpleXMLElement;
/**
* This test must be called AFTER generation of files has occurred
*/
class GeneratedFilesTest extends TestCase
{
public function testSprintf()
{
require_once __DIR__ . '/../../generated/strings.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../generated/Exceptions/StringsException.php';
$this->assertSame('foo', sprintf('foo'));
$this->assertSame('foobar', sprintf('foo%s', 'bar'));
$this->assertSame('foobarbaz', sprintf('foo%s%s', 'bar', 'baz'));
set_error_handler(function () {
});
try {
$this->expectException(StringsException::class);
sprintf('foo%s%s', 'bar');
} finally {
restore_error_handler();
}
}
public function testPregMatch()
{
require_once __DIR__ . '/../../generated/pcre.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../lib/Exceptions/PcreException.php';
$url = 'https://open.spotify.com/track/0nCqpKBrvDchO1BIvt7DTR?si=iLUKDfkLSy-IpnLA7qImnw';
$spotifyRegex = "/https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/";
preg_match($spotifyRegex, $url, $matches);
\preg_match($spotifyRegex, $url, $originalMatches);
$this->assertSame($originalMatches, $matches);
}
public function testObjects()
{
require_once __DIR__ . '/../../generated/simplexml.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../generated/Exceptions/SimplexmlException.php';
$xmlStr = <<<XML
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>PHP: Behind the Parser</title>
</movie>
</movies>
XML;
$movies = simplexml_load_string($xmlStr);
$this->assertInstanceOf(SimpleXMLElement::class, $movies);
$domImplementation = new \DOMImplementation();
$doc = $domImplementation->createDocument(null, 'foo');
$xmlElem = simplexml_import_dom($doc);
$this->assertInstanceOf(SimpleXMLElement::class, $xmlElem);
}
/**
* Tests that the limit parameter is nullable.
* See https://github.com/thecodingmachine/safe/issues/56
*/
public function testPregSplit()
{
require_once __DIR__ . '/../../generated/pcre.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../lib/Exceptions/PcreException.php';
$keywords = preg_split("/[\s,]+/", "hypertext language, programming", null);
$this->assertSame(['hypertext', 'language', 'programming'], $keywords);
}
/**
* Tests that parameters with "time()" default value are correctly handled.
*/
public function testStrtotime()
{
require_once __DIR__ . '/../../generated/datetime.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../generated/Exceptions/DatetimeException.php';
$this->assertSame(\strtotime('+1 day'), strtotime('+1 day'));
}
/**
* Tests that parameters signature can be not passed. See https://github.com/thecodingmachine/safe/issues/86
*/
public function testOpenSslSign()
{
require_once __DIR__ . '/../../generated/openssl.php';
require_once __DIR__ . '/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__ . '/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__ . '/../../generated/Exceptions/OpensslException.php';
\openssl_sign('foo', $signature, file_get_contents(__DIR__ . '/fixtures/id_rsa'));
openssl_sign('foo', $signatureSafe, file_get_contents(__DIR__ . '/fixtures/id_rsa'));
$this->assertSame($signature, $signatureSafe);
}
public function testOpenSslEncrypt()
{
$result = \openssl_encrypt(
'test',
'aes-256-cbc',
pack('H*', 'a2e8ccd0e7985cc0b6213a55815a1034afc252980e970ca90e5202689f9473b0'),
\OPENSSL_RAW_DATA,
pack('H*', '123ce954203b7caaaa9da67f59839456'));
$resultSafe = openssl_encrypt(
'test',
'aes-256-cbc',
pack('H*', 'a2e8ccd0e7985cc0b6213a55815a1034afc252980e970ca90e5202689f9473b0'),
\OPENSSL_RAW_DATA,
pack('H*', '123ce954203b7caaaa9da67f59839456'));
$this->assertSame($result, $resultSafe);
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
use Safe\PhpStanFunctions\PhpStanFunctionMapReader;
class MethodTest extends TestCase
{
public function testGetFunctionName() {
$docPage = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/pcre/functions/preg-match.xml');
$xmlObject = $docPage->getMethodSynopsis();
$method = new Method($xmlObject[0], $docPage->loadAndResolveFile(), $docPage->getModule(), new PhpStanFunctionMapReader());
$name = $method->getFunctionName();
$this->assertEquals('preg_match', $name);
}
public function testGetFunctionType() {
$docPage = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/pcre/functions/preg-match.xml');
$xmlObject = $docPage->getMethodSynopsis();
$method = new Method($xmlObject[0], $docPage->loadAndResolveFile(), $docPage->getModule(), new PhpStanFunctionMapReader());
$type = $method->getReturnType();
$this->assertEquals('int', $type);
}
public function testGetFunctionParam() {
$docPage = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/pcre/functions/preg-match.xml');
$xmlObject = $docPage->getMethodSynopsis();
$method = new Method($xmlObject[0], $docPage->loadAndResolveFile(), $docPage->getModule(), new PhpStanFunctionMapReader());
$params = $method->getParams();
$this->assertEquals('string', $params[0]->getType());
$this->assertEquals('pattern', $params[0]->getParameter());
}
public function testGetInitializer() {
$docPage = new DocPage(__DIR__ . '/../doc/doc-en/en/reference/apc/functions/apc-cache-info.xml');
$xmlObject = $docPage->getMethodSynopsis();
$method = new Method($xmlObject[0], $docPage->loadAndResolveFile(), $docPage->getModule(), new PhpStanFunctionMapReader());
$params = $method->getParams();
$this->assertEquals('', $params[0]->getDefaultValue());
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Safe\PhpStanFunctions;
use PHPStan\Testing\TestCase;
class PhpStanFunctionMapReaderTest extends TestCase
{
public function testHas(): void
{
$mapReader = new PhpStanFunctionMapReader();
$this->assertTrue($mapReader->hasFunction('strpos'));
$this->assertFalse($mapReader->hasFunction('foobar'));
}
public function testGet(): void
{
$mapReader = new PhpStanFunctionMapReader();
$function = $mapReader->getFunction('apcu_fetch');
// 'apcu_fetch' => ['mixed', 'key'=>'string|string[]', '&w_success='=>'bool'],
$this->assertSame('mixed', $function->getReturnType());
$parameters = $function->getParameters();
$this->assertCount(2, $parameters);
$this->assertSame('success', $parameters['success']->getName());
$this->assertSame('bool', $parameters['success']->getType());
$this->assertFalse($parameters['success']->isVariadic());
$this->assertTrue($parameters['success']->isByReference());
$this->assertTrue($parameters['success']->isOptional());
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
class ScannerTest extends TestCase
{
public function testGetMethodsPaths()
{
$scanner = new Scanner(__DIR__ . '/../doc/doc-en/en/reference/');
$paths = $scanner->getFunctionsPaths();
$this->assertArrayHasKey(__DIR__.'/../doc/doc-en/en/reference/filesystem/functions/chmod.xml', $paths);
$this->assertArrayNotHasKey(__DIR__.'/../doc/doc-en/en/reference/spl/appenditerator/getarrayiterator.xml', $paths);
}
public function testGetFunctionsPaths()
{
$scanner = new Scanner(__DIR__ . '/../doc/doc-en/en/reference/');
$paths = $scanner->getMethodsPaths();
$this->assertArrayNotHasKey(__DIR__.'/../doc/doc-en/en/reference/filesystem/functions/chmod.xml', $paths);
$this->assertArrayHasKey(__DIR__.'/../doc/doc-en/en/reference/spl/appenditerator/getarrayiterator.xml', $paths);
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
use Safe\Exceptions\PcreException;
class SpecialCasesTest extends TestCase
{
public function testPregReplace()
{
require_once __DIR__.'/../../lib/special_cases.php';
require_once __DIR__.'/../../lib/Exceptions/SafeExceptionInterface.php';
require_once __DIR__.'/../../lib/Exceptions/AbstractSafeException.php';
require_once __DIR__.'/../../lib/Exceptions/PcreException.php';
$this->expectException(PcreException::class);
$this->expectExceptionMessage('PREG_BAD_UTF8_ERROR: Invalid UTF8 character');
preg_replace("/([\s,]+)/u", "foo", "\xc3\x28");
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Safe;
use PHPUnit\Framework\TestCase;
class TypeTest extends TestCase
{
public function testIsClass()
{
$this->assertSame('\\stdClass', Type::toRootNamespace('stdClass'));
$this->assertSame('\\SimpleXMLElement', Type::toRootNamespace('SimpleXMLElement'));
$this->assertSame('bool', Type::toRootNamespace('bool'));
$this->assertSame('int', Type::toRootNamespace('int'));
}
}

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoc4Ay97wfke5L1RLeiUtstzzdiSrzhwdgirjLSUeniEtXI6g
Yj7PxX2rBV6f6a4o9CpkkeoSbj3lA82hkDzc411XVSws+OJ4cz4cc4K5fZ5HLJFA
GpCqgO2ywCXH2pPmse+ACrdX1fPdZPqSyW1M+ZKYUDRAaHjlSsCkR8KSTN8Max2A
4EMsntrWVWiMdOGg5jB7CAAwIz3a6R3gKEmFml2gs77gpYme/bTVERuNW+TCG/x3
3xUhkdOrvRKPE81K4D6rtCXuBrqfmE8r1vp29yPbjIM6KStKLTCIJHLx1/h34CNj
MXW6d8abQ7KKxAycw4ADwCO4VNhAMxhhyylNGQIDAQABAoIBABBoiaAjDZRgxaDN
FZJfbtDyoyXZ9ipCo6NtofgUCZTTnHwEYrNT11IZulwjCmhyJukL24MIj7HqSO0n
zziHU4cjEhYrEqxymvBk3hHAsfrRMDqOyEdpYEEO2c+uhSPfV8e3l+5+RUQHJO52
kqgmk2XDvfp0MgvmJqp7+qzkSF3PH2R00c2AdjbPQoFxXv5Tkk7EBWa92pw+81Om
YEK7ch/a5tqqz2AHrcU6P8I7MsqIDLc0AuUg/Xx5Nb9K2phBpQ9Extu1cg3t769C
RR/5gqHRh3QgdaG6PGaGDSpb4ZIxNYdH7DxSVZGtZ/rBCCV8UNFBoiuXemm+QzQ2
ob8e+/kCgYEA15FgAOTsSINZIFsWnuUTK8vQHTCkf0IL/89vvN8CIvN86Mri2yw8
n4cQrVKjxBhhCdhu7coLzrMlo9saL9oS14Z43mPtAx6C4ACr5lcFcxcKd4zqoBP7
YM7TJ6DN9oYd7yWQTPjUJHZXYuuVisqXDMics+rccQrsSdrN7hSFwB8CgYEAwCcn
9SU9BFZ2LnCAmMDve4+xotaxiYJMwkVLr4f/7/fOWxgsmjQUThXNfLMHgFGA0kE2
tn1Z9axsdlZGkhr7CRQ2gUHhpEldNEKWswoj6I1uKU7fVTPuRQP7FmMYAN0cGtpC
NvQLcQbKI51VDKp6BN1JpDhw4RaWfWAntYOca8cCgYAM65GtfAsNbZHx9oOskl5L
ybN3jGrPlc3ST0SLNXKTVbSu3zopmMUpapb9TG60WiG2zVoYtntusB4ZbBBtvcxT
TqP/8E1MWo/NjTzAWYbiFwdxkuidH5V5f+v3/BNcKz2wD7hOZLuSU+V48FXOM8ZJ
5dw+jF0aCWWQJ6UgF+rMUQKBgQCdnICN+CmAcVsm5GjW4wqMk2TlaKzfWd2UTDq0
lB0+vEirN7z+D1HIauHOMxsoCbJcw9kY/uDXPsMInePs2+ylmcrLYzquAu9MeoIa
AWtKyRdfEq7luF7shUNjLYz2yGbRL824PZ1U7HjJlbe5V+wWKVzKMvGD738o/8IS
hQ286QKBgQCeIP6DWRAvIYNWs+R1oe5jln8N7SrQUCA2F5AmffBaRU+gLcHHyTBM
VPtwF5uOAU7C7/ZhLe0MuMdVBvHSrfGh4y1qUXj1qu3KKrgF5kohyxlYvmEylDHY
mFgG7Mb6/WmP+RORcAaaIrBg9rAj6v4wdLP5FRcvQY+csP/GmksZXw==
-----END RSA PRIVATE KEY-----