This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Mouf\Composer; |
||
3 | |||
4 | /** |
||
5 | * The class maps a class name to one or many possible file names according to PSR-0 or PSR-4 rules. |
||
6 | * |
||
7 | * @author David Négrier <[email protected]> |
||
8 | */ |
||
9 | class ClassNameMapper |
||
10 | { |
||
11 | /** |
||
12 | * |
||
13 | * @var array<namespace, path[]> |
||
14 | */ |
||
15 | private $psr0Namespaces = array(); |
||
16 | |||
17 | /** |
||
18 | * |
||
19 | * @var array<namespace, path[]> |
||
20 | */ |
||
21 | private $psr4Namespaces = array(); |
||
22 | |||
23 | /** |
||
24 | * Registers a PSR-0 namespace. |
||
25 | * |
||
26 | * @param string $namespace The namespace to register |
||
27 | * @param string|array $path The path on the filesystem (or an array of paths) |
||
28 | */ |
||
29 | View Code Duplication | public function registerPsr0Namespace($namespace, $path) { |
|
0 ignored issues
–
show
|
|||
30 | // A namespace always ends with a \ |
||
31 | $namespace = trim($namespace, '\\').'\\'; |
||
32 | if ($namespace === '\\') { |
||
33 | $namespace = ''; |
||
34 | } |
||
35 | |||
36 | if (!is_array($path)) { |
||
37 | $path = [$path]; |
||
38 | } |
||
39 | // Paths always end with a / |
||
40 | $paths = array_map([self::class, 'normalizeDirectory'], $path); |
||
41 | |||
42 | if (!isset($this->psr0Namespaces[$namespace])) { |
||
43 | $this->psr0Namespaces[$namespace] = $paths; |
||
44 | } else { |
||
45 | $this->psr0Namespaces[$namespace] = array_merge($this->psr0Namespaces[$namespace], $paths); |
||
46 | } |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Registers a PSR-4 namespace. |
||
51 | * |
||
52 | * @param string $namespace The namespace to register |
||
53 | * @param string|array $path The path on the filesystem (or an array of paths) |
||
54 | */ |
||
55 | View Code Duplication | public function registerPsr4Namespace($namespace, $path) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
56 | // A namespace always ends with a \ |
||
57 | $namespace = trim($namespace, '\\').'\\'; |
||
58 | if ($namespace === '\\') { |
||
59 | $namespace = ''; |
||
60 | } |
||
61 | |||
62 | if (!is_array($path)) { |
||
63 | $path = [$path]; |
||
64 | } |
||
65 | // Paths always end with a / |
||
66 | $paths = array_map([self::class, 'normalizeDirectory'], $path); |
||
67 | |||
68 | if (!isset($this->psr4Namespaces[$namespace])) { |
||
69 | $this->psr4Namespaces[$namespace] = $paths; |
||
70 | } else { |
||
71 | $this->psr4Namespaces[$namespace] = array_merge($this->psr4Namespaces[$namespace], $paths); |
||
72 | } |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * @param string $composerJsonPath |
||
77 | * @param string $rootPath |
||
78 | * @param bool $useAutoloadDev |
||
79 | * @return ClassNameMapper |
||
80 | */ |
||
81 | public static function createFromComposerFile($composerJsonPath = null, $rootPath = null, $useAutoloadDev = false) { |
||
82 | $classNameMapper = new ClassNameMapper(); |
||
83 | |||
84 | if ($composerJsonPath === null) { |
||
85 | $composerJsonPath = __DIR__.'/../../../../composer.json'; |
||
86 | } |
||
87 | |||
88 | $classNameMapper->loadComposerFile($composerJsonPath, $rootPath, $useAutoloadDev); |
||
89 | |||
90 | return $classNameMapper; |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * |
||
95 | * @param string $composerJsonPath Path to the composer file |
||
96 | * @param string $rootPath Root path of the project (or null) |
||
97 | */ |
||
98 | public function loadComposerFile($composerJsonPath, $rootPath = null, $useAutoloadDev = false) { |
||
99 | $composer = json_decode(file_get_contents($composerJsonPath), true); |
||
100 | |||
101 | if ($rootPath) { |
||
0 ignored issues
–
show
The expression
$rootPath of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
102 | $relativePath = self::makePathRelative(dirname($composerJsonPath), $rootPath); |
||
103 | } else { |
||
104 | $relativePath = null; |
||
105 | } |
||
106 | |||
107 | View Code Duplication | if (isset($composer["autoload"]["psr-0"])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
108 | $psr0 = $composer["autoload"]["psr-0"]; |
||
109 | foreach ($psr0 as $namespace => $paths) { |
||
110 | if ($relativePath != null) { |
||
0 ignored issues
–
show
|
|||
111 | if (!is_array($paths)) { |
||
112 | $paths = [$paths]; |
||
113 | } |
||
114 | $paths = array_map(function($path) use ($relativePath) { |
||
115 | return rtrim($relativePath,'\\/').'/'.ltrim($path, '\\/'); |
||
116 | }, $paths); |
||
117 | } |
||
118 | $this->registerPsr0Namespace($namespace, $paths); |
||
119 | } |
||
120 | } |
||
121 | |||
122 | View Code Duplication | if (isset($composer["autoload"]["psr-4"])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
123 | $psr4 = $composer["autoload"]["psr-4"]; |
||
124 | foreach ($psr4 as $namespace => $paths) { |
||
125 | if ($relativePath != null) { |
||
0 ignored issues
–
show
|
|||
126 | if (!is_array($paths)) { |
||
127 | $paths = [$paths]; |
||
128 | } |
||
129 | $paths = array_map(function($path) use ($relativePath) { |
||
130 | return rtrim($relativePath,'\\/').'/'.ltrim($path, '\\/'); |
||
131 | }, $paths); |
||
132 | } |
||
133 | $this->registerPsr4Namespace($namespace, $paths); |
||
134 | } |
||
135 | } |
||
136 | |||
137 | if ($useAutoloadDev) { |
||
138 | View Code Duplication | if (isset($composer["autoload-dev"]["psr-0"])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
139 | $psr0 = $composer["autoload-dev"]["psr-0"]; |
||
140 | foreach ($psr0 as $namespace => $paths) { |
||
141 | if ($relativePath != null) { |
||
0 ignored issues
–
show
|
|||
142 | if (!is_array($paths)) { |
||
143 | $paths = [$paths]; |
||
144 | } |
||
145 | $paths = array_map(function($path) use ($relativePath) { |
||
146 | return rtrim($relativePath,'\\/').'/'.ltrim($path, '\\/'); |
||
147 | }, $paths); |
||
148 | } |
||
149 | $this->registerPsr0Namespace($namespace, $paths); |
||
150 | } |
||
151 | } |
||
152 | |||
153 | View Code Duplication | if (isset($composer["autoload-dev"]["psr-4"])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
154 | $psr4 = $composer["autoload-dev"]["psr-4"]; |
||
155 | foreach ($psr4 as $namespace => $paths) { |
||
156 | if ($relativePath != null) { |
||
0 ignored issues
–
show
|
|||
157 | if (!is_array($paths)) { |
||
158 | $paths = [$paths]; |
||
159 | } |
||
160 | $paths = array_map(function($path) use ($relativePath) { |
||
161 | return rtrim($relativePath,'\\/').'/'.ltrim($path, '\\/'); |
||
162 | }, $paths); |
||
163 | } |
||
164 | $this->registerPsr4Namespace($namespace, $paths); |
||
165 | } |
||
166 | } |
||
167 | } |
||
168 | |||
169 | return $this; |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * Given an existing path, convert it to a path relative to a given starting path. |
||
174 | * Shamelessly borrowed to Symfony :). Thanks guys. |
||
175 | * Note: we do not include Symfony's "FileSystem" component to avoid adding too many dependencies. |
||
176 | * |
||
177 | * @param string $endPath Absolute path of target |
||
178 | * @param string $startPath Absolute path where traversal begins |
||
179 | * |
||
180 | * @return string Path of target relative to starting path |
||
181 | */ |
||
182 | private static function makePathRelative($endPath, $startPath) |
||
183 | { |
||
184 | // Normalize separators on Windows |
||
185 | if ('\\' === DIRECTORY_SEPARATOR) { |
||
186 | $endPath = strtr($endPath, '\\', '/'); |
||
187 | $startPath = strtr($startPath, '\\', '/'); |
||
188 | } |
||
189 | // Split the paths into arrays |
||
190 | $startPathArr = explode('/', trim($startPath, '/')); |
||
191 | $endPathArr = explode('/', trim($endPath, '/')); |
||
192 | // Find for which directory the common path stops |
||
193 | $index = 0; |
||
194 | while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) { |
||
195 | $index++; |
||
196 | } |
||
197 | // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels) |
||
198 | $depth = count($startPathArr) - $index; |
||
199 | // Repeated "../" for each level need to reach the common path |
||
200 | $traverser = str_repeat('../', $depth); |
||
201 | $endPathRemainder = implode('/', array_slice($endPathArr, $index)); |
||
202 | // Construct $endPath from traversing to the common path, then to the remaining $endPath |
||
203 | $relativePath = $traverser.(strlen($endPathRemainder) > 0 ? $endPathRemainder.'/' : ''); |
||
204 | return (strlen($relativePath) === 0) ? './' : $relativePath; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Returns a list of all namespaces that are managed by the ClassNameMapper. |
||
209 | * |
||
210 | * @return string[] |
||
211 | */ |
||
212 | public function getManagedNamespaces() { |
||
213 | return array_keys(array_merge($this->psr0Namespaces, $this->psr4Namespaces)); |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * Returns a list of paths that can be used to store $className. |
||
218 | * |
||
219 | * @param string $className |
||
220 | * @return string[] |
||
221 | */ |
||
222 | public function getPossibleFileNames($className) { |
||
223 | $possibleFileNames = array(); |
||
224 | $className = ltrim($className, '\\'); |
||
225 | |||
226 | $psr0unfactorizedAutoload = $this->unfactorizeAutoload($this->psr0Namespaces); |
||
227 | |||
228 | foreach ($psr0unfactorizedAutoload as $result) { |
||
229 | $namespace = $result['namespace']; |
||
230 | $directory = $result['directory']; |
||
231 | |||
232 | if ($namespace === '') { |
||
233 | $tmpClassName = $className; |
||
234 | if ($lastNsPos = strripos($tmpClassName, '\\')) { |
||
235 | $namespace = substr($tmpClassName, 0, $lastNsPos); |
||
236 | $tmpClassName = substr($tmpClassName, $lastNsPos + 1); |
||
237 | } |
||
238 | |||
239 | $fileName = str_replace('\\', '/', $namespace) . '/' . str_replace('_', '/', $tmpClassName) . '.php'; |
||
240 | $possibleFileNames[] = $directory.$fileName; |
||
241 | } else { |
||
242 | if (strpos($className, $namespace) === 0) { |
||
243 | $tmpClassName = $className; |
||
244 | $fileName = ''; |
||
245 | if ($lastNsPos = strripos($tmpClassName, '\\')) { |
||
246 | $namespace = substr($tmpClassName, 0, $lastNsPos); |
||
247 | $tmpClassName = substr($tmpClassName, $lastNsPos + 1); |
||
248 | $fileName = str_replace('\\', '/', $namespace) . '/'; |
||
249 | } |
||
250 | $fileName .= str_replace('_', '/', $tmpClassName) . '.php'; |
||
251 | |||
252 | $possibleFileNames[] = $directory.$fileName; |
||
253 | } |
||
254 | } |
||
255 | } |
||
256 | |||
257 | $psr4unfactorizedAutoload = $this->unfactorizeAutoload($this->psr4Namespaces); |
||
258 | |||
259 | foreach ($psr4unfactorizedAutoload as $result) { |
||
260 | $namespace = $result['namespace']; |
||
261 | $directory = $result['directory']; |
||
262 | |||
263 | if ($namespace === '') { |
||
264 | $fileName = str_replace('\\', '/', $className) . '.php'; |
||
265 | $possibleFileNames[] = $directory.$fileName; |
||
266 | } else { |
||
267 | if (strpos($className, $namespace) === 0) { |
||
268 | $shortenedClassName = substr($className, strlen($namespace)); |
||
269 | |||
270 | if ($lastNsPos = strripos($shortenedClassName, '\\')) { |
||
271 | $namespace = substr($shortenedClassName, 0, $lastNsPos); |
||
272 | $shortenedClassName = substr($shortenedClassName, $lastNsPos + 1); |
||
273 | $fileName = str_replace('\\', '/', $namespace) . '/' . $shortenedClassName; |
||
274 | } else { |
||
275 | $fileName = $shortenedClassName; |
||
276 | } |
||
277 | $fileName .= '.php'; |
||
278 | |||
279 | $possibleFileNames[] = $directory . $fileName; |
||
280 | } |
||
281 | } |
||
282 | } |
||
283 | |||
284 | return $possibleFileNames; |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Takes in parameter an array like |
||
289 | * [{ "Mouf": "src/" }] or [{ "Mouf": ["src/", "src2/"] }] . |
||
290 | * returns |
||
291 | * [ |
||
292 | * {"namespace"=> "Mouf", "directory"=>"src/"}, |
||
293 | * {"namespace"=> "Mouf", "directory"=>"src2/"} |
||
294 | * ] |
||
295 | * |
||
296 | * @param array $autoload |
||
297 | * @return array<int, array<string, string>> |
||
0 ignored issues
–
show
The doc-type
array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.
Loading history...
|
|||
298 | */ |
||
299 | private static function unfactorizeAutoload(array $autoload) { |
||
300 | $result = array(); |
||
301 | foreach ($autoload as $namespace => $directories) { |
||
302 | if (!is_array($directories)) { |
||
303 | $result[] = array( |
||
304 | "namespace" => $namespace, |
||
305 | "directory" => self::normalizeDirectory($directories) |
||
306 | ); |
||
307 | } else { |
||
308 | foreach ($directories as $dir) { |
||
309 | $result[] = array( |
||
310 | "namespace" => $namespace, |
||
311 | "directory" => self::normalizeDirectory($dir) |
||
312 | ); |
||
313 | } |
||
314 | } |
||
315 | } |
||
316 | return $result; |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Makes sure the directory ends with a / (unless the string is empty) |
||
321 | * |
||
322 | * @param string $dir |
||
323 | * @return string |
||
324 | */ |
||
325 | private static function normalizeDirectory($dir) { |
||
326 | return $dir === '' ? '' : rtrim($dir, '\\/').'/'; |
||
327 | } |
||
328 | } |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.