You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
10 KiB
378 lines
10 KiB
<?php
|
|
/* For licensing terms, see /license.txt */
|
|
|
|
use Symfony\Component\Filesystem\Filesystem;
|
|
|
|
/**
|
|
* This is the file manage library for Chamilo.
|
|
* Include/require it in your code to use its functionality.
|
|
*
|
|
* @package chamilo.library
|
|
*/
|
|
|
|
/**
|
|
* Cheks a file or a directory actually exist at this location.
|
|
*
|
|
* @author Hugues Peeters <peeters@ipm.ucl.ac.be>
|
|
*
|
|
* @param string $file_path Path of the presume existing file or dir
|
|
*
|
|
* @return bool TRUE if the file or the directory exists or FALSE otherwise
|
|
*/
|
|
function check_name_exist($file_path)
|
|
{
|
|
clearstatcache();
|
|
$save_dir = getcwd();
|
|
if (!is_dir(dirname($file_path))) {
|
|
return false;
|
|
}
|
|
chdir(dirname($file_path));
|
|
$file_name = basename($file_path);
|
|
|
|
if (file_exists($file_name)) {
|
|
chdir($save_dir);
|
|
|
|
return true;
|
|
} else {
|
|
chdir($save_dir);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes a file or a directory.
|
|
*
|
|
* @author - Hugues Peeters
|
|
*
|
|
* @param $file (String) - the path of file or directory to delete
|
|
*
|
|
* @return bool - true if the delete succeed, false otherwise
|
|
*
|
|
* @see - delete() uses check_name_exist() and removeDir() functions
|
|
*/
|
|
function my_delete($file)
|
|
{
|
|
if (check_name_exist($file)) {
|
|
if (is_file($file)) { // FILE CASE
|
|
unlink($file);
|
|
|
|
return true;
|
|
} elseif (is_dir($file)) { // DIRECTORY CASE
|
|
removeDir($file);
|
|
|
|
return true;
|
|
}
|
|
} else {
|
|
return false; // no file or directory to delete
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a directory recursively.
|
|
*
|
|
* @returns true if OK, otherwise false
|
|
*
|
|
* @author Amary <MasterNES@aol.com> (from Nexen.net)
|
|
* @author Olivier Brouckaert <oli.brouckaert@skynet.be>
|
|
*
|
|
* @param string $dir directory to remove
|
|
*/
|
|
function removeDir($dir)
|
|
{
|
|
if (!@$opendir = opendir($dir)) {
|
|
return false;
|
|
}
|
|
|
|
while ($readdir = readdir($opendir)) {
|
|
if ($readdir != '..' && $readdir != '.') {
|
|
if (is_file($dir.'/'.$readdir)) {
|
|
if (!@unlink($dir.'/'.$readdir)) {
|
|
return false;
|
|
}
|
|
} elseif (is_dir($dir.'/'.$readdir)) {
|
|
if (!removeDir($dir.'/'.$readdir)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir($opendir);
|
|
|
|
if (!@rmdir($dir)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Return true if folder is empty.
|
|
*
|
|
* @author hubert.borderiou@grenet.fr
|
|
*
|
|
* @param string $in_folder folder path on disk
|
|
*
|
|
* @return int 1 if folder is empty, 0 otherwise
|
|
*/
|
|
function folder_is_empty($in_folder)
|
|
{
|
|
$folder_is_empty = 0;
|
|
if (is_dir($in_folder)) {
|
|
$tab_folder_content = scandir($in_folder);
|
|
if ((
|
|
count($tab_folder_content) == 2 &&
|
|
in_array(".", $tab_folder_content) &&
|
|
in_array("..", $tab_folder_content)
|
|
) ||
|
|
(count($tab_folder_content) < 2)
|
|
) {
|
|
$folder_is_empty = 1;
|
|
}
|
|
}
|
|
|
|
return $folder_is_empty;
|
|
}
|
|
|
|
/**
|
|
* Renames a file or a directory.
|
|
*
|
|
* @author Hugues Peeters <peeters@ipm.ucl.ac.be>
|
|
*
|
|
* @param string $file_path complete path of the file or the directory
|
|
* @param string $new_file_name new name for the file or the directory
|
|
*
|
|
* @return bool true if succeed, false otherwise
|
|
*
|
|
* @see rename() uses the check_name_exist() and php2phps() functions
|
|
*/
|
|
function my_rename($file_path, $new_file_name)
|
|
{
|
|
$save_dir = getcwd();
|
|
$path = dirname($file_path);
|
|
$old_file_name = basename($file_path);
|
|
$new_file_name = api_replace_dangerous_char($new_file_name);
|
|
|
|
// If no extension, take the old one
|
|
if ((strpos($new_file_name, '.') === false) && ($dotpos = strrpos($old_file_name, '.'))) {
|
|
$new_file_name .= substr($old_file_name, $dotpos);
|
|
}
|
|
|
|
// Note: still possible: 'xx.yy' -rename-> '.yy' -rename-> 'zz'
|
|
// This is useful for folder names, where otherwise '.' would be sticky
|
|
|
|
// Extension PHP is not allowed, change to PHPS
|
|
$new_file_name = php2phps($new_file_name);
|
|
|
|
if ($new_file_name == $old_file_name) {
|
|
return $old_file_name;
|
|
}
|
|
|
|
if (strtolower($new_file_name) != strtolower($old_file_name) && check_name_exist($path.'/'.$new_file_name)) {
|
|
return false;
|
|
}
|
|
// On a Windows server, it would be better not to do the above check
|
|
// because it succeeds for some new names resembling the old name.
|
|
// But on Unix/Linux the check must be done because rename overwrites.
|
|
|
|
chdir($path);
|
|
$res = rename($old_file_name, $new_file_name) ? $new_file_name : false;
|
|
chdir($save_dir);
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Moves a file or a directory to an other area.
|
|
*
|
|
* @author Hugues Peeters <peeters@ipm.ucl.ac.be>
|
|
*
|
|
* @param string $source the path of file or directory to move
|
|
* @param string $target the path of the new area
|
|
* @param bool $forceMove Whether to force a move or to make a copy (safer but slower) and then delete the original
|
|
* @param bool $moveContent In some cases (including migrations), we need to move the *content* and not the folder itself
|
|
*
|
|
* @return bool true if the move succeed, false otherwise
|
|
*
|
|
* @see move() uses check_name_exist() and copyDirTo() functions
|
|
*/
|
|
function move($source, $target, $forceMove = true, $moveContent = false)
|
|
{
|
|
$target = realpath($target); // remove trailing slash
|
|
$source = realpath($source);
|
|
if (check_name_exist($source)) {
|
|
$file_name = basename($source);
|
|
// move onto self illegal: mv a/b/c a/b/c or mv a/b/c a/b
|
|
if (strcasecmp($target, dirname($source)) === 0) {
|
|
return false;
|
|
}
|
|
$isWindowsOS = api_is_windows_os();
|
|
$canExec = function_exists('exec');
|
|
|
|
/* File case */
|
|
if (is_file($source)) {
|
|
if ($forceMove) {
|
|
if (!$isWindowsOS && $canExec) {
|
|
exec('mv '.$source.' '.$target.'/'.$file_name);
|
|
} else {
|
|
// Try copying
|
|
copy($source, $target.'/'.$file_name);
|
|
unlink($source);
|
|
}
|
|
} else {
|
|
copy($source, $target.'/'.$file_name);
|
|
unlink($source);
|
|
}
|
|
|
|
return true;
|
|
} elseif (is_dir($source)) {
|
|
// move dir down will cause loop: mv a/b/ a/b/c/ not legal
|
|
if (strncasecmp($target, $source, strlen($source)) == 0) {
|
|
return false;
|
|
}
|
|
/* Directory */
|
|
if ($forceMove && !$isWindowsOS && $canExec) {
|
|
if ($moveContent) {
|
|
$base = basename($source);
|
|
$out = [];
|
|
$retVal = -1;
|
|
exec('mv '.$source.'/* '.$target.'/'.$base, $out, $retVal);
|
|
if ($retVal !== 0) {
|
|
return false; // mv should return 0 on success
|
|
}
|
|
exec('rm -rf '.$source);
|
|
} else {
|
|
$out = [];
|
|
$retVal = -1;
|
|
exec("mv $source $target", $out, $retVal);
|
|
if ($retVal !== 0) {
|
|
error_log("Chamilo error fileManage.lib.php: mv $source $target\n");
|
|
|
|
return false; // mv should return 0 on success
|
|
}
|
|
}
|
|
} else {
|
|
return copyDirTo($source, $target);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Moves a directory and its content to an other area.
|
|
*
|
|
* @author Hugues Peeters <peeters@ipm.ucl.ac.be>
|
|
*
|
|
* @param string $source the path of the directory to move
|
|
* @param string $destination the path of the new area
|
|
*
|
|
* @return bool false on error
|
|
*/
|
|
function copyDirTo($source, $destination, $move = true)
|
|
{
|
|
$fs = new Filesystem();
|
|
if (is_dir($source)) {
|
|
$fs->mkdir($destination);
|
|
if (!is_dir($destination)) {
|
|
error_log("Chamilo copyDirTo cannot mkdir $destination\n");
|
|
|
|
return false; // could not create destination dir
|
|
}
|
|
$fs->mirror($source, $destination);
|
|
if ($move) {
|
|
$fs->remove($source);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Copy a directory and its directories (not files) to an other area.
|
|
*
|
|
* @param string $source the path of the directory to move
|
|
* @param string $destination the path of the new area
|
|
*
|
|
* @return bool false on error
|
|
*/
|
|
function copyDirWithoutFilesTo($source, $destination)
|
|
{
|
|
$fs = new Filesystem();
|
|
|
|
if (!is_dir($source)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$fs->exists($destination)) {
|
|
$fs->mkdir($destination);
|
|
}
|
|
|
|
$dirIterator = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
|
|
$iterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST);
|
|
|
|
/** @var \SplFileInfo $item */
|
|
foreach ($iterator as $item) {
|
|
if ($item->isFile()) {
|
|
continue;
|
|
}
|
|
|
|
$newDir = $destination.'/'.$item->getFilename();
|
|
|
|
if (!$fs->exists($newDir)) {
|
|
$fs->mkdir($destination.'/'.$item->getFilename());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Extracting extension of a filename.
|
|
*
|
|
* @returns array
|
|
*
|
|
* @param string $filename filename
|
|
*/
|
|
function getextension($filename)
|
|
{
|
|
$bouts = explode('.', $filename);
|
|
|
|
return [array_pop($bouts), implode('.', $bouts)];
|
|
}
|
|
|
|
/**
|
|
* Get a list of all PHP (.php) files in a given directory. Includes .tpl files
|
|
* @param $base_path The base path in which to find the corresponding files
|
|
* @return array
|
|
*/
|
|
function getAllPhpFiles($base_path)
|
|
{
|
|
$list = scandir($base_path);
|
|
$files = [];
|
|
foreach ($list as $item) {
|
|
if (substr($item, 0, 1) == '.') {
|
|
continue;
|
|
}
|
|
$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)];
|
|
if (in_array($base_path.$item.'/', $special_dirs)) {
|
|
continue;
|
|
}
|
|
if (is_dir($base_path.$item)) {
|
|
$files = array_merge($files, get_all_php_files($base_path.$item.'/'));
|
|
} else {
|
|
//only analyse php files
|
|
$sub = substr($item, -4);
|
|
if ($sub == '.php' or $sub == '.tpl') {
|
|
$files[] = $base_path.$item;
|
|
}
|
|
}
|
|
}
|
|
$list = null;
|
|
|
|
return $files;
|
|
} |