1 | <?php |
||
2 | /* For licensing terms, see /license.txt */ |
||
3 | |||
4 | use Symfony\Component\Filesystem\Filesystem; |
||
5 | |||
6 | /** |
||
7 | * This is the file manage library for Chamilo. |
||
8 | * Include/require it in your code to use its functionality. |
||
9 | */ |
||
10 | |||
11 | /** |
||
12 | * Cheks a file or a directory actually exist at this location. |
||
13 | * |
||
14 | * @author Hugues Peeters <[email protected]> |
||
15 | * |
||
16 | * @param string $file_path Path of the presume existing file or dir |
||
17 | * |
||
18 | * @return bool TRUE if the file or the directory exists or FALSE otherwise |
||
19 | */ |
||
20 | function check_name_exist($file_path) |
||
21 | { |
||
22 | clearstatcache(); |
||
23 | $save_dir = getcwd(); |
||
24 | if (!is_dir(dirname($file_path))) { |
||
25 | return false; |
||
26 | } |
||
27 | chdir(dirname($file_path)); |
||
28 | $file_name = basename($file_path); |
||
29 | |||
30 | if (file_exists($file_name)) { |
||
31 | chdir($save_dir); |
||
32 | |||
33 | return true; |
||
34 | } else { |
||
35 | chdir($save_dir); |
||
36 | |||
37 | return false; |
||
38 | } |
||
39 | } |
||
40 | |||
41 | /** |
||
42 | * Deletes a file or a directory. |
||
43 | * |
||
44 | * @author - Hugues Peeters |
||
45 | * |
||
46 | * @param $file (String) - the path of file or directory to delete |
||
47 | * |
||
48 | * @return bool - true if the delete succeed, false otherwise |
||
49 | * |
||
50 | * @see - delete() uses check_name_exist() and removeDir() functions |
||
51 | */ |
||
52 | function my_delete($file) |
||
53 | { |
||
54 | if (check_name_exist($file)) { |
||
55 | if (is_file($file)) { // FILE CASE |
||
56 | unlink($file); |
||
57 | |||
58 | return true; |
||
59 | } elseif (is_dir($file)) { // DIRECTORY CASE |
||
60 | removeDir($file); |
||
61 | |||
62 | return true; |
||
63 | } |
||
64 | } |
||
65 | |||
66 | return false; // no file or directory to delete |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Removes a directory recursively. |
||
71 | * |
||
72 | * @returns true if OK, otherwise false |
||
73 | * |
||
74 | * @author Amary <[email protected]> (from Nexen.net) |
||
75 | * @author Olivier Brouckaert <[email protected]> |
||
76 | * |
||
77 | * @param string $dir directory to remove |
||
78 | */ |
||
79 | function removeDir($dir) |
||
80 | { |
||
81 | if (!@$opendir = opendir($dir)) { |
||
82 | return false; |
||
83 | } |
||
84 | |||
85 | while ($readdir = readdir($opendir)) { |
||
86 | if ($readdir != '..' && $readdir != '.') { |
||
87 | if (is_file($dir.'/'.$readdir)) { |
||
88 | if (!@unlink($dir.'/'.$readdir)) { |
||
89 | return false; |
||
90 | } |
||
91 | } elseif (is_dir($dir.'/'.$readdir)) { |
||
92 | if (!removeDir($dir.'/'.$readdir)) { |
||
93 | return false; |
||
94 | } |
||
95 | } |
||
96 | } |
||
97 | } |
||
98 | |||
99 | closedir($opendir); |
||
100 | |||
101 | if (!@rmdir($dir)) { |
||
102 | return false; |
||
103 | } |
||
104 | |||
105 | return true; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Return true if folder is empty. |
||
110 | * |
||
111 | * @author [email protected] |
||
112 | * |
||
113 | * @param string $in_folder folder path on disk |
||
114 | * |
||
115 | * @return int 1 if folder is empty, 0 otherwise |
||
116 | */ |
||
117 | function folder_is_empty($in_folder) |
||
118 | { |
||
119 | $folder_is_empty = 0; |
||
120 | if (is_dir($in_folder)) { |
||
121 | $tab_folder_content = scandir($in_folder); |
||
122 | if (( |
||
123 | count($tab_folder_content) == 2 && |
||
124 | in_array(".", $tab_folder_content) && |
||
125 | in_array("..", $tab_folder_content) |
||
126 | ) || |
||
127 | (count($tab_folder_content) < 2) |
||
128 | ) { |
||
129 | $folder_is_empty = 1; |
||
130 | } |
||
131 | } |
||
132 | |||
133 | return $folder_is_empty; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Renames a file or a directory. |
||
138 | * |
||
139 | * @author Hugues Peeters <[email protected]> |
||
140 | * |
||
141 | * @param string $file_path complete path of the file or the directory |
||
142 | * @param string $new_file_name new name for the file or the directory |
||
143 | * |
||
144 | * @return bool true if succeed, false otherwise |
||
145 | * |
||
146 | * @see rename() uses the check_name_exist() and php2phps() functions |
||
147 | */ |
||
148 | function my_rename($file_path, $new_file_name) |
||
149 | { |
||
150 | $save_dir = getcwd(); |
||
151 | $path = dirname($file_path); |
||
152 | $old_file_name = basename($file_path); |
||
153 | $new_file_name = api_replace_dangerous_char($new_file_name); |
||
154 | |||
155 | // If no extension, take the old one |
||
156 | if ((strpos($new_file_name, '.') === false) && ($dotpos = strrpos($old_file_name, '.'))) { |
||
157 | $new_file_name .= substr($old_file_name, $dotpos); |
||
158 | } |
||
159 | |||
160 | // Note: still possible: 'xx.yy' -rename-> '.yy' -rename-> 'zz' |
||
161 | // This is useful for folder names, where otherwise '.' would be sticky |
||
162 | |||
163 | // Extension PHP is not allowed, change to PHPS |
||
164 | $new_file_name = php2phps($new_file_name); |
||
165 | |||
166 | if ($new_file_name == $old_file_name) { |
||
167 | return $old_file_name; |
||
168 | } |
||
169 | |||
170 | if (strtolower($new_file_name) != strtolower($old_file_name) && check_name_exist($path.'/'.$new_file_name)) { |
||
171 | return false; |
||
172 | } |
||
173 | // On a Windows server, it would be better not to do the above check |
||
174 | // because it succeeds for some new names resembling the old name. |
||
175 | // But on Unix/Linux the check must be done because rename overwrites. |
||
176 | |||
177 | chdir($path); |
||
178 | $res = rename($old_file_name, $new_file_name) ? $new_file_name : false; |
||
179 | chdir($save_dir); |
||
180 | |||
181 | return $res; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Moves a file or a directory to an other area. |
||
186 | * |
||
187 | * @author Hugues Peeters <[email protected]> |
||
188 | * |
||
189 | * @param string $source the path of file or directory to move |
||
190 | * @param string $target the path of the new area |
||
191 | * @param bool $forceMove Whether to force a move or to make a copy (safer but slower) and then delete the original |
||
192 | * @param bool $moveContent In some cases (including migrations), we need to move the *content* and not the folder itself |
||
193 | * |
||
194 | * @return bool true if the move succeed, false otherwise |
||
195 | * |
||
196 | * @see move() uses check_name_exist() and copyDirTo() functions |
||
197 | */ |
||
198 | function move($source, $target, $forceMove = true, $moveContent = false) |
||
199 | { |
||
200 | $target = realpath($target); // remove trailing slash |
||
201 | $source = realpath($source); |
||
202 | if (check_name_exist($source)) { |
||
203 | $file_name = basename($source); |
||
204 | // move onto self illegal: mv a/b/c a/b/c or mv a/b/c a/b |
||
205 | if (strcasecmp($target, dirname($source)) === 0) { |
||
206 | return false; |
||
207 | } |
||
208 | $isWindowsOS = api_is_windows_os(); |
||
209 | $canExec = function_exists('exec'); |
||
210 | |||
211 | /* File case */ |
||
212 | if (is_file($source)) { |
||
213 | if ($forceMove) { |
||
214 | if (!$isWindowsOS && $canExec) { |
||
215 | exec('mv '.$source.' '.$target.'/'.$file_name); |
||
216 | } else { |
||
217 | // Try copying |
||
218 | copy($source, $target.'/'.$file_name); |
||
219 | unlink($source); |
||
220 | } |
||
221 | } else { |
||
222 | copy($source, $target.'/'.$file_name); |
||
223 | unlink($source); |
||
224 | } |
||
225 | |||
226 | return true; |
||
227 | } elseif (is_dir($source)) { |
||
228 | // move dir down will cause loop: mv a/b/ a/b/c/ not legal |
||
229 | if (strncasecmp($target, $source, strlen($source)) == 0) { |
||
230 | return false; |
||
231 | } |
||
232 | /* Directory */ |
||
233 | if ($forceMove && !$isWindowsOS && $canExec) { |
||
234 | if ($moveContent) { |
||
235 | $base = basename($source); |
||
236 | $out = []; |
||
237 | $retVal = -1; |
||
238 | exec('mv '.$source.'/* '.$target.'/'.$base, $out, $retVal); |
||
239 | if ($retVal !== 0) { |
||
240 | return false; // mv should return 0 on success |
||
241 | } |
||
242 | exec('rm -rf '.$source); |
||
243 | } else { |
||
244 | $out = []; |
||
245 | $retVal = -1; |
||
246 | exec("mv $source $target", $out, $retVal); |
||
247 | if ($retVal !== 0) { |
||
248 | error_log("Chamilo error fileManage.lib.php: mv $source $target\n"); |
||
249 | |||
250 | return false; // mv should return 0 on success |
||
251 | } |
||
252 | } |
||
253 | } else { |
||
254 | $base = basename($source); |
||
255 | |||
256 | return copyDirTo($source, $target.'/'.$base); |
||
257 | } |
||
258 | |||
259 | return true; |
||
260 | } |
||
261 | } |
||
262 | |||
263 | return false; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Moves a directory and its content to an other area. |
||
268 | * |
||
269 | * @author Hugues Peeters <[email protected]> |
||
270 | * |
||
271 | * @param string $source the path of the directory to move |
||
272 | * @param string $destination the path of the new area |
||
273 | * @param bool $move Whether we want to remove the source at the end |
||
274 | * |
||
275 | * @return bool false on error |
||
276 | */ |
||
277 | function copyDirTo($source, $destination, $move = true) |
||
278 | { |
||
279 | $fs = new Filesystem(); |
||
280 | if (is_dir($source)) { |
||
281 | $fs->mkdir($destination); |
||
282 | if (!is_dir($destination)) { |
||
283 | error_log("Chamilo copyDirTo cannot mkdir $destination\n"); |
||
284 | |||
285 | return false; // could not create destination dir |
||
286 | } |
||
287 | $fs->mirror($source, $destination); |
||
288 | if ($move) { |
||
289 | $fs->remove($source); |
||
290 | } |
||
291 | } |
||
292 | |||
293 | return true; |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Copy a directory and its directories (not files) to an other area. |
||
298 | * |
||
299 | * @param string $source the path of the directory to move |
||
300 | * @param string $destination the path of the new area |
||
301 | * |
||
302 | * @return bool false on error |
||
303 | */ |
||
304 | function copyDirWithoutFilesTo($source, $destination) |
||
305 | { |
||
306 | $fs = new Filesystem(); |
||
307 | |||
308 | if (!is_dir($source)) { |
||
309 | return false; |
||
310 | } |
||
311 | |||
312 | if (!$fs->exists($destination)) { |
||
313 | $fs->mkdir($destination); |
||
314 | } |
||
315 | |||
316 | $dirIterator = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS); |
||
317 | $iterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST); |
||
318 | |||
319 | /** @var \SplFileInfo $item */ |
||
320 | foreach ($iterator as $item) { |
||
321 | if ($item->isFile()) { |
||
322 | continue; |
||
323 | } |
||
324 | |||
325 | $newDir = $destination.'/'.$item->getFilename(); |
||
326 | |||
327 | if (!$fs->exists($newDir)) { |
||
328 | $fs->mkdir($destination.'/'.$item->getFilename()); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | return true; |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * Extracting extension of a filename. |
||
337 | * |
||
338 | * @returns array |
||
339 | * |
||
340 | * @param string $filename filename |
||
341 | */ |
||
342 | function getextension($filename) |
||
343 | { |
||
344 | $bouts = explode('.', $filename); |
||
345 | |||
346 | return [array_pop($bouts), implode('.', $bouts)]; |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * Get a list of all PHP (.php) files in a given directory. Includes .tpl files. |
||
351 | * |
||
352 | * @param string $base_path The base path in which to find the corresponding files |
||
353 | * @param bool $includeStatic Include static .html, .htm and .css files |
||
354 | * |
||
355 | * @return array |
||
356 | */ |
||
357 | function getAllPhpFiles($base_path, $includeStatic = false) |
||
358 | { |
||
359 | $list = scandir($base_path); |
||
360 | $files = []; |
||
361 | $extensionsArray = ['.php', '.tpl']; |
||
362 | if ($includeStatic) { |
||
363 | $extensionsArray[] = 'html'; |
||
364 | $extensionsArray[] = '.htm'; |
||
365 | $extensionsArray[] = '.css'; |
||
366 | } |
||
367 | foreach ($list as $item) { |
||
368 | if (substr($item, 0, 1) == '.') { |
||
369 | continue; |
||
370 | } |
||
371 | $special_dirs = [api_get_path(SYS_TEST_PATH), api_get_path(SYS_COURSE_PATH), api_get_path(SYS_LANG_PATH), api_get_path(SYS_ARCHIVE_PATH)]; |
||
372 | if (in_array($base_path.$item.'/', $special_dirs)) { |
||
373 | continue; |
||
374 | } |
||
375 | if (is_dir($base_path.$item)) { |
||
376 | $files = array_merge($files, getAllPhpFiles($base_path.$item.'/', $includeStatic)); |
||
377 | } else { |
||
378 | //only analyse php files |
||
379 | $sub = substr($item, -4); |
||
380 | if (in_array($sub, $extensionsArray)) { |
||
381 | $files[] = $base_path.$item; |
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | $list = null; |
||
386 | |||
387 | return $files; |
||
388 | } |
||
389 |