Skip to content

Commit fecc042

Browse files
authored
Add support for the eval function (#277)
Attempt to scope the content of the eval function whenever possible. Leave the expression unchanged otherwise.
1 parent c508dde commit fecc042

File tree

5 files changed

+303
-26
lines changed

5 files changed

+303
-26
lines changed

specs/eval.php

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the humbug/php-scoper package.
7+
*
8+
* Copyright (c) 2017 Théo FIDRY <[email protected]>,
9+
* Pádraic Brady <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
return [
16+
'meta' => [
17+
'title' => 'Eval',
18+
// Default values. If not specified will be the one used
19+
'prefix' => 'Humbug',
20+
'whitelist' => [],
21+
'whitelist-global-constants' => false,
22+
'whitelist-global-classes' => false,
23+
'whitelist-global-functions' => false,
24+
'registered-classes' => [],
25+
'registered-functions' => [],
26+
],
27+
28+
'string' => <<<'PHP'
29+
<?php
30+
31+
eval('
32+
<?php
33+
34+
use Acme\Foo;
35+
36+
');
37+
38+
----
39+
<?php
40+
41+
namespace Humbug;
42+
43+
eval('
44+
<?php
45+
namespace Humbug;
46+
47+
use Humbug\\Acme\\Foo;
48+
');
49+
50+
PHP
51+
,
52+
53+
'string with invalid PHP' => <<<'PHP'
54+
<?php
55+
56+
eval('invalid PHP');
57+
58+
----
59+
<?php
60+
61+
namespace Humbug;
62+
63+
eval('invalid PHP');
64+
65+
PHP
66+
,
67+
68+
'concatenated string' => <<<'PHP'
69+
<?php
70+
71+
eval('<?php'.' echo "Hello!";');
72+
73+
----
74+
<?php
75+
76+
namespace Humbug;
77+
78+
eval('<?php' . ' echo "Hello!";');
79+
80+
PHP
81+
,
82+
83+
'Nowdoc' => <<<'PHP'
84+
<?php
85+
86+
eval(<<<'PHP_NOWDOC'
87+
<?php
88+
89+
use Acme\Foo;
90+
91+
PHP_NOWDOC
92+
);
93+
94+
eval(<<<'PHP_NOWDOC'
95+
<?php
96+
97+
use Acme\Foo;
98+
PHP_NOWDOC
99+
);
100+
101+
----
102+
<?php
103+
104+
namespace Humbug;
105+
106+
eval(<<<'PHP_NOWDOC'
107+
<?php
108+
109+
namespace Humbug;
110+
111+
use Humbug\Acme\Foo;
112+
113+
PHP_NOWDOC
114+
);
115+
eval(<<<'PHP_NOWDOC'
116+
<?php
117+
118+
namespace Humbug;
119+
120+
use Humbug\Acme\Foo;
121+
PHP_NOWDOC
122+
);
123+
124+
PHP
125+
,
126+
127+
'Nowdoc with invalid PHP' => <<<'PHP'
128+
<?php
129+
130+
eval(<<<'PHP_NOWDOC'
131+
Not.php
132+
PHP_NOWDOC
133+
);
134+
135+
----
136+
<?php
137+
138+
namespace Humbug;
139+
140+
eval(<<<'PHP_NOWDOC'
141+
Not.php
142+
PHP_NOWDOC
143+
);
144+
145+
PHP
146+
,
147+
148+
'Heredoc' => <<<'PHP'
149+
<?php
150+
151+
eval(<<<PHP_HEREDOC
152+
<?php
153+
154+
use Acme\Foo;
155+
156+
PHP_HEREDOC
157+
);
158+
159+
----
160+
<?php
161+
162+
namespace Humbug;
163+
164+
eval(<<<PHP_HEREDOC
165+
<?php
166+
167+
namespace Humbug;
168+
169+
use Humbug\\Acme\\Foo;
170+
171+
PHP_HEREDOC
172+
);
173+
174+
PHP
175+
,
176+
177+
'string with whitelisted function' => [
178+
'whitelist' => ['Acme\foo'],
179+
'registered-functions' => [
180+
['Acme\foo', 'Humbug\Acme\foo'],
181+
],
182+
'payload' => <<<'PHP'
183+
<?php
184+
185+
eval('<?php
186+
187+
namespace Acme;
188+
189+
function foo() {}
190+
191+
');
192+
193+
----
194+
<?php
195+
196+
namespace Humbug;
197+
198+
eval('<?php
199+
200+
namespace Humbug\\Acme;
201+
202+
function foo()
203+
{
204+
}
205+
');
206+
207+
PHP
208+
],
209+
];
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the humbug/php-scoper package.
7+
*
8+
* Copyright (c) 2017 Théo FIDRY <[email protected]>,
9+
* Pádraic Brady <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Humbug\PhpScoper\PhpParser\NodeVisitor;
16+
17+
use Humbug\PhpScoper\PhpParser\StringScoperPrefixer;
18+
use PhpParser\Node;
19+
use PhpParser\Node\Expr\Eval_;
20+
use PhpParser\Node\Scalar\String_;
21+
use PhpParser\NodeVisitorAbstract;
22+
23+
final class EvalPrefixer extends NodeVisitorAbstract
24+
{
25+
use StringScoperPrefixer;
26+
27+
/**
28+
* @inheritdoc
29+
*/
30+
public function enterNode(Node $node): Node
31+
{
32+
if ($node instanceof String_ && ParentNodeAppender::findParent($node) instanceof Eval_) {
33+
$this->scopeStringValue($node);
34+
}
35+
36+
return $node;
37+
}
38+
}

src/PhpParser/NodeVisitor/NewdocPrefixer.php

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414

1515
namespace Humbug\PhpScoper\PhpParser\NodeVisitor;
1616

17-
use Humbug\PhpScoper\Scoper\PhpScoper;
18-
use Humbug\PhpScoper\Whitelist;
19-
use PhpParser\Error as PhpParserError;
17+
use Humbug\PhpScoper\PhpParser\StringScoperPrefixer;
2018
use PhpParser\Node;
2119
use PhpParser\Node\Scalar\String_;
2220
use PhpParser\NodeVisitorAbstract;
@@ -26,36 +24,15 @@
2624

2725
final class NewdocPrefixer extends NodeVisitorAbstract
2826
{
29-
private $scoper;
30-
private $prefix;
31-
private $whitelist;
32-
33-
public function __construct(PhpScoper $scoper, string $prefix, Whitelist $whitelist)
34-
{
35-
$this->scoper = $scoper;
36-
$this->prefix = $prefix;
37-
$this->whitelist = $whitelist;
38-
}
27+
use StringScoperPrefixer;
3928

4029
/**
4130
* @inheritdoc
4231
*/
4332
public function enterNode(Node $node): Node
4433
{
4534
if ($node instanceof String_ && $this->isPhpNowdoc($node)) {
46-
try {
47-
$lastChar = substr($node->value, -1);
48-
49-
$newValue = $this->scoper->scopePhp($node->value, $this->prefix, $this->whitelist);
50-
51-
if ("\n" !== $lastChar) {
52-
$newValue = substr($newValue, 0, -1);
53-
}
54-
55-
$node->value = $newValue;
56-
} catch (PhpParserError $error) {
57-
// Continue without scoping the heredoc which for some reasons contains invalid PHP code
58-
}
35+
$this->scopeStringValue($node);
5936
}
6037

6138
return $node;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the humbug/php-scoper package.
7+
*
8+
* Copyright (c) 2017 Théo FIDRY <[email protected]>,
9+
* Pádraic Brady <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Humbug\PhpScoper\PhpParser;
16+
17+
use Humbug\PhpScoper\Scoper\PhpScoper;
18+
use Humbug\PhpScoper\Whitelist;
19+
use PhpParser\Error as PhpParserError;
20+
use PhpParser\Node\Scalar\String_;
21+
use function substr;
22+
23+
trait StringScoperPrefixer
24+
{
25+
private $scoper;
26+
private $prefix;
27+
private $whitelist;
28+
29+
public function __construct(PhpScoper $scoper, string $prefix, Whitelist $whitelist)
30+
{
31+
$this->scoper = $scoper;
32+
$this->prefix = $prefix;
33+
$this->whitelist = $whitelist;
34+
}
35+
36+
private function scopeStringValue(String_ $node): void
37+
{
38+
try {
39+
$lastChar = substr($node->value, -1);
40+
41+
$newValue = $this->scoper->scopePhp($node->value, $this->prefix, $this->whitelist);
42+
43+
if ("\n" !== $lastChar) {
44+
$newValue = substr($newValue, 0, -1);
45+
}
46+
47+
$node->value = $newValue;
48+
} catch (PhpParserError $error) {
49+
// Continue without scoping the heredoc which for some reasons contains invalid PHP code
50+
}
51+
}
52+
}

src/PhpParser/TraverserFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public function create(PhpScoper $scoper, string $prefix, Whitelist $whitelist):
5555
$traverser->addVisitor(new NodeVisitor\NameStmtPrefixer($prefix, $whitelist, $nameResolver, $this->reflector));
5656
$traverser->addVisitor(new NodeVisitor\StringScalarPrefixer($prefix, $whitelist, $this->reflector));
5757
$traverser->addVisitor(new NodeVisitor\NewdocPrefixer($scoper, $prefix, $whitelist));
58+
$traverser->addVisitor(new NodeVisitor\EvalPrefixer($scoper, $prefix, $whitelist));
5859

5960
$traverser->addVisitor(new NodeVisitor\ClassAliasStmtAppender($prefix, $whitelist, $nameResolver));
6061
$traverser->addVisitor(new NodeVisitor\ConstStmtReplacer($whitelist, $nameResolver));

0 commit comments

Comments
 (0)