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) { |
||
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) { |
||
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) { |
||
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) { |
||
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) { |
||
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>> |
||
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.