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 | |||
3 | /* |
||
4 | * Composer plugin for pluggable extensions |
||
5 | * |
||
6 | * @link https://github.com/hiqdev/composer-extension-plugin |
||
7 | * @package composer-extension-plugin |
||
8 | * @license BSD-3-Clause |
||
9 | * @copyright Copyright (c) 2016, HiQDev (http://hiqdev.com/) |
||
10 | */ |
||
11 | |||
12 | namespace hiqdev\composerextensionplugin; |
||
13 | |||
14 | use Composer\Composer; |
||
15 | use Composer\EventDispatcher\EventSubscriberInterface; |
||
16 | use Composer\IO\IOInterface; |
||
17 | use Composer\Package\PackageInterface; |
||
18 | use Composer\Package\RootPackageInterface; |
||
19 | use Composer\Plugin\PluginInterface; |
||
20 | use Composer\Script\Event; |
||
21 | use Composer\Script\ScriptEvents; |
||
22 | use Composer\Util\Filesystem; |
||
23 | |||
24 | /** |
||
25 | * Plugin class. |
||
26 | * |
||
27 | * @author Andrii Vasyliev <[email protected]> |
||
28 | */ |
||
29 | class Plugin implements PluginInterface, EventSubscriberInterface |
||
30 | { |
||
31 | const PACKAGE_TYPE = 'yii2-extension'; |
||
32 | const EXTRA_OPTION_NAME = 'extension-plugin'; |
||
33 | const OUTPUT_PATH = 'hiqdev'; |
||
34 | const BASE_DIR_SAMPLE = '<base-dir>'; |
||
35 | const VENDOR_DIR_SAMPLE = '<base-dir>/vendor'; |
||
36 | |||
37 | /** |
||
38 | * @var PackageInterface[] the array of active composer packages |
||
39 | */ |
||
40 | protected $packages; |
||
41 | |||
42 | /** |
||
43 | * @var string absolute path to the package base directory. |
||
44 | */ |
||
45 | protected $baseDir; |
||
46 | |||
47 | /** |
||
48 | * @var string absolute path to vendor directory. |
||
49 | */ |
||
50 | protected $vendorDir; |
||
51 | |||
52 | /** |
||
53 | * @var Filesystem utility |
||
54 | */ |
||
55 | protected $filesystem; |
||
56 | |||
57 | /** |
||
58 | * @var array whole data |
||
59 | */ |
||
60 | protected $data = [ |
||
61 | 'aliases' => [], |
||
62 | 'extensions' => [], |
||
63 | ]; |
||
64 | |||
65 | /** |
||
66 | * @var Composer instance |
||
67 | */ |
||
68 | protected $composer; |
||
69 | |||
70 | /** |
||
71 | * @var IOInterface |
||
72 | */ |
||
73 | public $io; |
||
74 | |||
75 | /** |
||
76 | * Initializes the plugin object with the passed $composer and $io. |
||
77 | * @param Composer $composer |
||
78 | * @param IOInterface $io |
||
79 | */ |
||
80 | 2 | public function activate(Composer $composer, IOInterface $io) |
|
81 | { |
||
82 | 2 | $this->composer = $composer; |
|
83 | 2 | $this->io = $io; |
|
84 | 2 | } |
|
85 | |||
86 | /** |
||
87 | * Returns list of events the plugin is subscribed to. |
||
88 | * @return array list of events |
||
89 | */ |
||
90 | 1 | public static function getSubscribedEvents() |
|
91 | { |
||
92 | return [ |
||
93 | 1 | ScriptEvents::POST_AUTOLOAD_DUMP => [ |
|
94 | 1 | ['onPostAutoloadDump', 0], |
|
95 | 1 | ], |
|
96 | 1 | ]; |
|
97 | } |
||
98 | |||
99 | /** |
||
100 | * Simply rewrites extensions file from scratch. |
||
101 | * @param Event $event |
||
102 | */ |
||
103 | public function onPostAutoloadDump(Event $event) |
||
104 | { |
||
105 | $this->io->writeError('<info>Generating extensions files</info>'); |
||
106 | foreach ($this->getPackages() as $package) { |
||
107 | if ($package instanceof \Composer\Package\CompletePackageInterface) { |
||
108 | $this->processPackage($package); |
||
109 | } |
||
110 | } |
||
111 | $this->processPackage($this->composer->getPackage()); |
||
112 | |||
113 | foreach ($this->data as $name => $data) { |
||
114 | $this->saveFile($this->buildOutputPath($name), $data); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | public function buildOutputPath($name) |
||
119 | { |
||
120 | return static::OUTPUT_PATH . DIRECTORY_SEPARATOR . $name . '.php'; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Writes file. |
||
125 | * @param string $file |
||
126 | * @param array $data |
||
127 | */ |
||
128 | protected function saveFile($file, array $data) |
||
129 | { |
||
130 | $path = $this->getVendorDir() . '/' . $file; |
||
131 | if (!file_exists(dirname($path))) { |
||
132 | mkdir(dirname($path), 0777, true); |
||
133 | } |
||
134 | $array = str_replace("'" . self::BASE_DIR_SAMPLE, '$baseDir . \'', Helper::exportVar($data)); |
||
135 | file_put_contents($path, "<?php\n\n\$baseDir = dirname(dirname(__DIR__));\n\nreturn $array;\n"); |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Scans the given package and collects extensions data. |
||
140 | * @param PackageInterface $package |
||
141 | */ |
||
142 | public function processPackage(PackageInterface $package) |
||
143 | { |
||
144 | $extra = $package->getExtra(); |
||
145 | $files = isset($extra[self::EXTRA_OPTION_NAME]) ? $extra[self::EXTRA_OPTION_NAME] : null; |
||
146 | if ($package->getType() !== self::PACKAGE_TYPE && is_null($files)) { |
||
147 | return; |
||
148 | } |
||
149 | |||
150 | $extension = [ |
||
151 | 'name' => $package->getName(), |
||
152 | 'version' => $package->getVersion(), |
||
153 | ]; |
||
154 | if ($package->getVersion() === '9999999-dev') { |
||
155 | $reference = $package->getSourceReference() ?: $package->getDistReference(); |
||
156 | if ($reference) { |
||
157 | $extension['reference'] = $reference; |
||
158 | } |
||
159 | } |
||
160 | $this->data['extensions'][$package->getName()] = $extension; |
||
161 | |||
162 | $aliases = array_merge( |
||
163 | $this->prepareAliases($package, 'psr-0'), |
||
164 | $this->prepareAliases($package, 'psr-4') |
||
165 | ); |
||
166 | $this->data['aliases'] = array_merge($this->data['aliases'], $aliases); |
||
167 | foreach ((array) $files as $name => $path) { |
||
168 | $config = $this->readExtensionConfig($package, $path); |
||
169 | $config['aliases'] = array_merge( |
||
170 | $aliases, |
||
171 | isset($config['aliases']) ? (array) $config['aliases'] : [] |
||
172 | ); |
||
173 | $this->data['aliases'] = array_merge($this->data['aliases'], $config['aliases']); |
||
174 | $this->data[$name] = isset($this->data[$name]) ? Helper::mergeConfig($this->data[$name], $config) : $config; |
||
175 | } |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Read extra config. |
||
180 | * @param string $file |
||
181 | * @return array |
||
182 | */ |
||
183 | protected function readExtensionConfig(PackageInterface $package, $file) |
||
184 | { |
||
185 | $path = $this->preparePath($package, $file); |
||
186 | if (!file_exists($path)) { |
||
187 | $this->io->writeError('<error>Non existent extension config file</error> ' . $file . ' in ' . $package->getName()); |
||
188 | exit(1); |
||
0 ignored issues
–
show
|
|||
189 | } |
||
190 | return require $path; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Prepare aliases. |
||
195 | * |
||
196 | * @param PackageInterface $package |
||
197 | * @param string 'psr-0' or 'psr-4' |
||
198 | * @return array |
||
199 | */ |
||
200 | protected function prepareAliases(PackageInterface $package, $psr) |
||
201 | { |
||
202 | $autoload = $package->getAutoload(); |
||
203 | if (empty($autoload[$psr])) { |
||
204 | return []; |
||
205 | } |
||
206 | |||
207 | $aliases = []; |
||
208 | foreach ($autoload[$psr] as $name => $path) { |
||
209 | if (is_array($path)) { |
||
210 | // ignore psr-4 autoload specifications with multiple search paths |
||
211 | // we can not convert them into aliases as they are ambiguous |
||
212 | continue; |
||
213 | } |
||
214 | $name = str_replace('\\', '/', trim($name, '\\')); |
||
215 | $path = $this->preparePath($package, $path); |
||
216 | $path = $this->substitutePath($path, $this->getBaseDir(), self::BASE_DIR_SAMPLE); |
||
217 | if ('psr-0' === $psr) { |
||
218 | $path .= '/' . $name; |
||
219 | } |
||
220 | $aliases["@$name"] = $path; |
||
221 | } |
||
222 | |||
223 | return $aliases; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Substitute path with alias if applicable. |
||
228 | * @param string $path |
||
229 | * @param string $dir |
||
230 | * @param string $alias |
||
231 | * @return string |
||
232 | */ |
||
233 | public function substitutePath($path, $dir, $alias) |
||
234 | { |
||
235 | return (substr($path, 0, strlen($dir) + 1) === $dir . '/') ? $alias . substr($path, strlen($dir)) : $path; |
||
236 | } |
||
237 | |||
238 | public function preparePath(PackageInterface $package, $path) |
||
239 | { |
||
240 | if (!$this->getFilesystem()->isAbsolutePath($path)) { |
||
241 | $prefix = $package instanceof RootPackageInterface ? $this->getBaseDir() : $this->getVendorDir() . '/' . $package->getPrettyName(); |
||
242 | $path = $prefix . '/' . $path; |
||
243 | } |
||
244 | |||
245 | return $this->getFilesystem()->normalizePath($path); |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Sets [[packages]]. |
||
250 | * @param PackageInterface[] $packages |
||
251 | */ |
||
252 | 2 | public function setPackages(array $packages) |
|
253 | { |
||
254 | 2 | $this->packages = $packages; |
|
255 | 2 | } |
|
256 | |||
257 | /** |
||
258 | * Gets [[packages]]. |
||
259 | * @return \Composer\Package\PackageInterface[] |
||
260 | */ |
||
261 | 1 | public function getPackages() |
|
262 | { |
||
263 | 1 | if ($this->packages === null) { |
|
264 | $this->packages = $this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages(); |
||
265 | } |
||
266 | |||
267 | 1 | return $this->packages; |
|
268 | } |
||
269 | |||
270 | /** |
||
271 | * Get absolute path to package base dir. |
||
272 | * @return string |
||
273 | */ |
||
274 | public function getBaseDir() |
||
275 | { |
||
276 | if ($this->baseDir === null) { |
||
277 | $this->baseDir = dirname($this->getVendorDir()); |
||
278 | } |
||
279 | |||
280 | return $this->baseDir; |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * Get absolute path to composer vendor dir. |
||
285 | * @return string |
||
286 | */ |
||
287 | public function getVendorDir() |
||
288 | { |
||
289 | if ($this->vendorDir === null) { |
||
290 | $dir = $this->composer->getConfig()->get('vendor-dir', '/'); |
||
291 | $this->vendorDir = $this->getFilesystem()->normalizePath($dir); |
||
292 | } |
||
293 | |||
294 | return $this->vendorDir; |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * Getter for filesystem utility. |
||
299 | * @return Filesystem |
||
300 | */ |
||
301 | public function getFilesystem() |
||
302 | { |
||
303 | if ($this->filesystem === null) { |
||
304 | $this->filesystem = new Filesystem(); |
||
305 | } |
||
306 | |||
307 | return $this->filesystem; |
||
308 | } |
||
309 | } |
||
310 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.