Skip to content

Commit b8fc1d1

Browse files
authored
fix: Correctly scope call_user_func_array() (#889)
Related to #294.
1 parent f1e494a commit b8fc1d1

File tree

2 files changed

+257
-0
lines changed

2 files changed

+257
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
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' => 'String literal used as a function argument of an call_user_func_array call',
18+
// Default values. If not specified will be the one used
19+
'prefix' => 'Humbug',
20+
21+
'expose-global-constants' => false,
22+
'expose-global-classes' => false,
23+
'expose-global-functions' => false,
24+
'expose-namespaces' => [],
25+
'expose-constants' => [],
26+
'expose-classes' => [],
27+
'expose-functions' => [],
28+
29+
'exclude-namespaces' => [],
30+
'exclude-constants' => [],
31+
'exclude-classes' => [],
32+
'exclude-functions' => [],
33+
34+
'expected-recorded-classes' => [],
35+
'expected-recorded-functions' => [],
36+
],
37+
38+
'FQCN string argument' => <<<'PHP'
39+
<?php
40+
41+
call_user_func_array('sodiumCompatAutoloader', []);
42+
call_user_func_array('Sodium\compatAutoloader', []);
43+
call_user_func_array(['Swift', 'autoload'], []);
44+
call_user_func_array(['\Swift', 'autoload'], []);
45+
call_user_func_array(['Humbug\\Swift', 'autoload'], []);
46+
call_user_func_array(['\\Humbug\\Swift', 'autoload'], []);
47+
call_user_func_array(['\\Humbug\\Swift', 'autoload'], []);
48+
call_user_func_array(['DateTime', 'autoload'], []);
49+
call_user_func_array(['\\DateTime', 'autoload'], []);
50+
51+
----
52+
<?php
53+
54+
namespace Humbug;
55+
56+
\call_user_func_array('Humbug\\sodiumCompatAutoloader', []);
57+
\call_user_func_array('Humbug\\Sodium\\compatAutoloader', []);
58+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
59+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
60+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
61+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
62+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
63+
\call_user_func_array(['DateTime', 'autoload'], []);
64+
\call_user_func_array(['\\DateTime', 'autoload'], []);
65+
66+
PHP,
67+
68+
'FQCN string argument on exposed class' => [
69+
'expose-classes' => ['Symfony\Component\Yaml\Yaml', 'Swift'],
70+
'payload' => <<<'PHP'
71+
<?php
72+
73+
call_user_func_array(['Swift', 'autoload'], []);
74+
call_user_func_array(['Humbug\\Swift', 'autoload'], []);
75+
call_user_func_array(['\\Humbug\\Swift', 'autoload'], []);
76+
call_user_func_array(['DateTime', 'autoload'], []);
77+
78+
----
79+
<?php
80+
81+
namespace Humbug;
82+
83+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
84+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
85+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
86+
\call_user_func_array(['DateTime', 'autoload'], []);
87+
88+
PHP,
89+
],
90+
91+
'FQCN string argument on exposed function' => [
92+
'expose-functions' => ['sodiumCompatAutoloader'],
93+
'payload' => <<<'PHP'
94+
<?php
95+
96+
call_user_func_array('sodiumCompatAutoloader', []);
97+
98+
----
99+
<?php
100+
101+
namespace Humbug;
102+
103+
\call_user_func_array('Humbug\\sodiumCompatAutoloader', []);
104+
105+
PHP,
106+
],
107+
108+
'FQCN string argument on class from an excluded namespace' => [
109+
'exclude-namespaces' => [
110+
'Symfony\Component\Yaml',
111+
'/^$/',
112+
],
113+
'payload' => <<<'PHP'
114+
<?php
115+
116+
call_user_func_array(['Swift', 'autoload'], []);
117+
call_user_func_array(['Humbug\\Swift', 'autoload'], []);
118+
call_user_func_array(['\\Humbug\\Swift', 'autoload'], []);
119+
call_user_func_array(['DateTime', 'autoload'], []);
120+
121+
----
122+
<?php
123+
124+
namespace {
125+
\call_user_func_array(['Swift', 'autoload'], []);
126+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
127+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
128+
\call_user_func_array(['DateTime', 'autoload'], []);
129+
}
130+
131+
PHP,
132+
],
133+
134+
'FQCN string argument on function from an excluded namespace' => [
135+
'exclude-namespaces' => [
136+
'Sodium',
137+
'/^$/',
138+
],
139+
'payload' => <<<'PHP'
140+
<?php
141+
142+
call_user_func_array('Sodium\CompatAutoloader', []);
143+
144+
----
145+
<?php
146+
147+
namespace {
148+
\call_user_func_array('Sodium\\CompatAutoloader', []);
149+
}
150+
151+
PHP,
152+
],
153+
154+
'FQCN string argument with global functions not exposed' => [
155+
'expose-global-functions' => false,
156+
'payload' => <<<'PHP'
157+
<?php
158+
159+
call_user_func_array(['Swift', 'autoload'], []);
160+
call_user_func_array(['Humbug\\Swift', 'autoload'], []);
161+
call_user_func_array(['\\Humbug\\Swift', 'autoload'], []);
162+
call_user_func_array(['DateTime', 'autoload'], []);
163+
164+
----
165+
<?php
166+
167+
namespace Humbug;
168+
169+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
170+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
171+
\call_user_func_array(['Humbug\\Swift', 'autoload'], []);
172+
\call_user_func_array(['DateTime', 'autoload'], []);
173+
174+
PHP,
175+
],
176+
177+
'FQCN string argument formed by concatenated strings' => <<<'PHP'
178+
<?php
179+
180+
call_user_func_array(['Swift'.'', 'autoload'], []);
181+
182+
----
183+
<?php
184+
185+
namespace Humbug;
186+
187+
\call_user_func_array(['Swift' . '', 'autoload'], []);
188+
189+
PHP,
190+
191+
'FQC constant call' => <<<'PHP'
192+
<?php
193+
194+
namespace Symfony\Component\Yaml {
195+
class Yaml {}
196+
}
197+
198+
namespace {
199+
call_user_func_array([\Swift::class, 'autoload'], []);
200+
call_user_func_array([\Humbug\Swift::class, 'autoload'], []);
201+
call_user_func_array([\DateTime::class, 'autoload'], []);
202+
}
203+
----
204+
<?php
205+
206+
namespace Humbug\Symfony\Component\Yaml;
207+
208+
class Yaml
209+
{
210+
}
211+
namespace Humbug;
212+
213+
\call_user_func_array([\Humbug\Swift::class, 'autoload'], []);
214+
\call_user_func_array([\Humbug\Swift::class, 'autoload'], []);
215+
\call_user_func_array([\DateTime::class, 'autoload'], []);
216+
217+
PHP,
218+
219+
'FQC constant call on exposed class' => [
220+
'expose-classes' => ['Symfony\Component\Yaml\Ya_1'],
221+
'expected-recorded-classes' => [
222+
['Symfony\Component\Yaml\Ya_1', 'Humbug\Symfony\Component\Yaml\Ya_1'],
223+
],
224+
'payload' => <<<'PHP'
225+
<?php
226+
227+
namespace Symfony\Component\Yaml {
228+
class Ya_1 {}
229+
}
230+
231+
namespace {
232+
call_user_func_array([Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
233+
call_user_func_array([\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
234+
call_user_func_array([Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
235+
call_user_func_array([\Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
236+
}
237+
----
238+
<?php
239+
240+
namespace Humbug\Symfony\Component\Yaml;
241+
242+
class Ya_1
243+
{
244+
}
245+
\class_alias('Humbug\\Symfony\\Component\\Yaml\\Ya_1', 'Symfony\\Component\\Yaml\\Ya_1', \false);
246+
namespace Humbug;
247+
248+
\call_user_func_array([\Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
249+
\call_user_func_array([\Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
250+
\call_user_func_array([\Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
251+
\call_user_func_array([\Humbug\Symfony\Component\Yaml\Ya_1::class, 'autoload'], []);
252+
253+
PHP
254+
],
255+
];

src/PhpParser/NodeVisitor/StringScalarPrefixer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ final class StringScalarPrefixer extends NodeVisitorAbstract
7272

7373
// Function for which we know the argument IS a FQCN
7474
private const SPECIAL_FUNCTION_NAMES = [
75+
'call_user_func_array',
7576
'class_alias',
7677
'class_exists',
7778
'define',
@@ -87,6 +88,7 @@ final class StringScalarPrefixer extends NodeVisitorAbstract
8788

8889
// Function for which we know the FIRST argument IS a FQCN
8990
private const SPECIAL_ARRAY_FUNCTION_NAMES = [
91+
'call_user_func_array',
9092
'is_callable',
9193
'spl_autoload_register',
9294
];

0 commit comments

Comments
 (0)