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 | namespace Robo\Task\Filesystem; |
||
4 | |||
5 | use Robo\Result; |
||
6 | use Robo\Exception\TaskException; |
||
7 | use Symfony\Component\Finder\Finder; |
||
8 | |||
9 | /** |
||
10 | * Searches for files in a nested directory structure and copies them to |
||
11 | * a target directory with or without the parent directories. The task was |
||
12 | * inspired by [gulp-flatten](https://www.npmjs.com/package/gulp-flatten). |
||
13 | * |
||
14 | * Example directory structure: |
||
15 | * |
||
16 | * ``` |
||
17 | * └── assets |
||
18 | * ├── asset-library1 |
||
19 | * │ ├── README.md |
||
20 | * │ └── asset-library1.min.js |
||
21 | * └── asset-library2 |
||
22 | * ├── README.md |
||
23 | * └── asset-library2.min.js |
||
24 | * ``` |
||
25 | * |
||
26 | * The following code will search the `*.min.js` files and copy them |
||
27 | * inside a new `dist` folder: |
||
28 | * |
||
29 | * ``` php |
||
30 | * <?php |
||
31 | * $this->taskFlattenDir(['assets/*.min.js' => 'dist'])->run(); |
||
32 | * // or use shortcut |
||
33 | * $this->_flattenDir('assets/*.min.js', 'dist'); |
||
34 | * ?> |
||
35 | * ``` |
||
36 | * |
||
37 | * You can also define the target directory with an additional method, instead of |
||
38 | * key/value pairs. More similar to the gulp-flatten syntax: |
||
39 | * |
||
40 | * ``` php |
||
41 | * <?php |
||
42 | * $this->taskFlattenDir(['assets/*.min.js']) |
||
43 | * ->to('dist') |
||
44 | * ->run(); |
||
45 | * ?> |
||
46 | * ``` |
||
47 | * |
||
48 | * You can also append parts of the parent directories to the target path. If you give |
||
49 | * the value `1` to the `includeParents()` method, then the top parent will be appended |
||
50 | * to the target directory resulting in a path such as `dist/assets/asset-library1.min.js`. |
||
51 | * |
||
52 | * If you give a negative number, such as `-1` (the same as specifying `array(0, 1)` then |
||
53 | * the bottom parent will be appended, resulting in a path such as |
||
54 | * `dist/asset-library1/asset-library1.min.js`. |
||
55 | * |
||
56 | * The top parent directory will always be starting from the relative path to the current |
||
57 | * directory. You can override that with the `parentDir()` method. If in the above example |
||
58 | * you would specify `assets`, then the top parent directory would be `asset-library1`. |
||
59 | * |
||
60 | * ``` php |
||
61 | * <?php |
||
62 | * $this->taskFlattenDir(['assets/*.min.js' => 'dist']) |
||
63 | * ->parentDir('assets') |
||
64 | * ->includeParents(1) |
||
65 | * ->run(); |
||
66 | * ?> |
||
67 | * ``` |
||
68 | */ |
||
69 | class FlattenDir extends BaseDir |
||
70 | { |
||
71 | /** |
||
72 | * @var int |
||
73 | */ |
||
74 | protected $chmod = 0755; |
||
75 | |||
76 | /** |
||
77 | * @var int[] |
||
78 | */ |
||
79 | protected $parents = array(0, 0); |
||
80 | |||
81 | /** |
||
82 | * @var string |
||
83 | */ |
||
84 | protected $parentDir = ''; |
||
85 | |||
86 | /** |
||
87 | * @var string |
||
88 | */ |
||
89 | protected $to; |
||
90 | |||
91 | /** |
||
92 | * {@inheritdoc} |
||
93 | */ |
||
94 | public function __construct($dirs) |
||
95 | { |
||
96 | parent::__construct($dirs); |
||
97 | $this->parentDir = getcwd(); |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * {@inheritdoc} |
||
102 | */ |
||
103 | public function run() |
||
104 | { |
||
105 | // find the files |
||
106 | $files = $this->findFiles($this->dirs); |
||
107 | |||
108 | // copy the files |
||
109 | $this->copyFiles($files); |
||
0 ignored issues
–
show
|
|||
110 | |||
111 | $fileNoun = count($files) == 1 ? ' file' : ' files'; |
||
112 | $this->printTaskSuccess("Copied {count} $fileNoun to {destination}", ['count' => count($files), 'destination' => $this->to]); |
||
113 | |||
114 | return Result::success($this); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Sets the default folder permissions for the destination if it does not exist. |
||
119 | * |
||
120 | * @link http://en.wikipedia.org/wiki/Chmod |
||
121 | * @link http://php.net/manual/en/function.mkdir.php |
||
122 | * @link http://php.net/manual/en/function.chmod.php |
||
123 | * |
||
124 | * @param int $permission |
||
125 | * |
||
126 | * @return $this |
||
127 | */ |
||
128 | public function dirPermissions($permission) |
||
129 | { |
||
130 | $this->chmod = (int) $permission; |
||
131 | |||
132 | return $this; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Sets the value from which direction and how much parent dirs should be included. |
||
137 | * Accepts a positive or negative integer or an array with two integer values. |
||
138 | * |
||
139 | * @param int|int[] $parents |
||
140 | * |
||
141 | * @return $this |
||
142 | * |
||
143 | * @throws TaskException |
||
144 | */ |
||
145 | public function includeParents($parents) |
||
146 | { |
||
147 | if (is_int($parents)) { |
||
148 | // if an integer is given check whether it is for top or bottom parent |
||
149 | if ($parents >= 0) { |
||
150 | $this->parents[0] = $parents; |
||
151 | return $this; |
||
152 | } |
||
153 | $this->parents[1] = 0 - $parents; |
||
154 | return $this; |
||
155 | } |
||
156 | |||
157 | if (is_array($parents)) { |
||
158 | // check if the array has two values no more, no less |
||
159 | if (count($parents) == 2) { |
||
160 | $this->parents = $parents; |
||
161 | return $this; |
||
162 | } |
||
163 | } |
||
164 | |||
165 | throw new TaskException($this, 'includeParents expects an integer or an array with two values'); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Sets the parent directory from which the relative parent directories will be calculated. |
||
170 | * |
||
171 | * @param string $dir |
||
172 | * |
||
173 | * @return $this |
||
174 | */ |
||
175 | public function parentDir($dir) |
||
176 | { |
||
177 | if (!$this->fs->isAbsolutePath($dir)) { |
||
178 | // attach the relative path to current working directory |
||
179 | $dir = getcwd() . '/' . $dir; |
||
180 | } |
||
181 | $this->parentDir = $dir; |
||
182 | |||
183 | return $this; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Sets the target directory where the files will be copied to. |
||
188 | * |
||
189 | * @param string $target |
||
190 | * |
||
191 | * @return $this |
||
192 | */ |
||
193 | public function to($target) |
||
194 | { |
||
195 | $this->to = rtrim($target, '/'); |
||
196 | |||
197 | return $this; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * @param array $dirs |
||
202 | * |
||
203 | * @return array|\Robo\Result |
||
204 | * |
||
205 | * @throws \Robo\Exception\TaskException |
||
206 | */ |
||
207 | View Code Duplication | protected function findFiles($dirs) |
|
208 | { |
||
209 | $files = array(); |
||
210 | |||
211 | // find the files |
||
212 | foreach ($dirs as $k => $v) { |
||
213 | // reset finder |
||
214 | $finder = new Finder(); |
||
215 | |||
216 | $dir = $k; |
||
217 | $to = $v; |
||
218 | // check if target was given with the to() method instead of key/value pairs |
||
219 | if (is_int($k)) { |
||
220 | $dir = $v; |
||
221 | if (isset($this->to)) { |
||
222 | $to = $this->to; |
||
223 | } else { |
||
224 | throw new TaskException($this, 'target directory is not defined'); |
||
225 | } |
||
226 | } |
||
227 | |||
228 | try { |
||
229 | $finder->files()->in($dir); |
||
230 | } catch (\InvalidArgumentException $e) { |
||
231 | // if finder cannot handle it, try with in()->name() |
||
232 | if (strpos($dir, '/') === false) { |
||
233 | $dir = './' . $dir; |
||
234 | } |
||
235 | $parts = explode('/', $dir); |
||
236 | $new_dir = implode('/', array_slice($parts, 0, -1)); |
||
237 | try { |
||
238 | $finder->files()->in($new_dir)->name(array_pop($parts)); |
||
239 | } catch (\InvalidArgumentException $e) { |
||
240 | return Result::fromException($this, $e); |
||
241 | } |
||
242 | } |
||
243 | |||
244 | foreach ($finder as $file) { |
||
245 | // store the absolute path as key and target as value in the files array |
||
246 | $files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to); |
||
247 | } |
||
248 | $fileNoun = count($files) == 1 ? ' file' : ' files'; |
||
249 | $this->printTaskInfo("Found {count} $fileNoun in {dir}", ['count' => count($files), 'dir' => $dir]); |
||
250 | } |
||
251 | |||
252 | return $files; |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * @param string $file |
||
257 | * @param string $to |
||
258 | * |
||
259 | * @return string |
||
260 | */ |
||
261 | protected function getTarget($file, $to) |
||
262 | { |
||
263 | $target = $to . '/' . basename($file); |
||
264 | if ($this->parents !== array(0, 0)) { |
||
265 | // if the parent is set, create additional directories inside target |
||
266 | // get relative path to parentDir |
||
267 | $rel_path = $this->fs->makePathRelative(dirname($file), $this->parentDir); |
||
268 | // get top parents and bottom parents |
||
269 | $parts = explode('/', rtrim($rel_path, '/')); |
||
270 | $prefix_dir = ''; |
||
271 | $prefix_dir .= ($this->parents[0] > 0 ? implode('/', array_slice($parts, 0, $this->parents[0])) . '/' : ''); |
||
272 | $prefix_dir .= ($this->parents[1] > 0 ? implode('/', array_slice($parts, (0 - $this->parents[1]), $this->parents[1])) : ''); |
||
273 | $prefix_dir = rtrim($prefix_dir, '/'); |
||
274 | $target = $to . '/' . $prefix_dir . '/' . basename($file); |
||
275 | } |
||
276 | |||
277 | return $target; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * @param array $files |
||
282 | */ |
||
283 | protected function copyFiles($files) |
||
284 | { |
||
285 | // copy the files |
||
286 | foreach ($files as $from => $to) { |
||
287 | // check if target dir exists |
||
288 | if (!is_dir(dirname($to))) { |
||
289 | $this->fs->mkdir(dirname($to), $this->chmod); |
||
290 | } |
||
291 | $this->fs->copy($from, $to); |
||
292 | } |
||
293 | } |
||
294 | } |
||
295 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.