Source of file FileSystemHelper.php
Size: 28,090 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Helpers/FileSystemHelper.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 | <?php /* This file is part of Jeedom. * * Jeedom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jeedom is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jeedom. If not, see <http://www.gnu.org/licenses/>. */ /* This file is part of NextDom Software. * * NextDom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NextDom Software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NextDom Software. If not, see <http://www.gnu.org/licenses/>. */ namespace NextDom\Helpers; use NextDom\Exceptions\CoreException; /** * Class FileSystemHelper * @package NextDom\Helpers */ class FileSystemHelper { /** * Includes a file from its type and name. * * @TODO: Doit être revue * @param string $folder Répertoire du fichier * @param string $filename Nom du fichier * @param string $_type Type de fichier * @param string $plugin Nom du plugin ou vide pour le core * @param bool $translate * @throws CoreException * @throws \Exception */ public static function includeFile($folder, $filename, $_type, $plugin = '', $translate = false) { if (strpos($folder, '..') !== false || strpos($filename, '..') !== false) { return; } // Aucune particularité pour les 3rdparty if ($folder == '3rdparty') { if ($plugin === '') { $file = sprintf("%s/%s.%s", $folder, $filename, $_type); $folder = null; $filename = self::getAssetPath($file); if (null === $filename) { $filename = 'assets/3rdparty/' . $filename . '.' . $_type; } } else { $filename .= '.' . $_type; } $type = $_type; } else { // Tableau de mappage des fichiers $config = [ 'class' => ['/class', '.class.php', 'php'], 'com' => ['/com', '.com.php', 'php'], 'repo' => ['/repo', '.repo.php', 'php'], 'config' => ['/config', '.config.php', 'php'], 'modal' => ['/modal', '.php', 'php'], 'modalhtml' => ['/modal', '.html', 'php'], 'php' => ['/php', '.php', 'php'], 'css' => ['/css', '.css', 'css'], 'js' => ['/js', '.js', 'js'], 'class.js' => ['/js', '.class.js', 'js'], 'custom.js' => ['/custom', 'custom.js', 'js'], 'custom.css' => ['/custom', 'custom.css', 'css'], 'themes.js' => ['/themes', '.js', 'js'], 'themes.css' => ['/themes', '.css', 'css'], 'api' => ['/api', '.api.php', 'php'], 'html' => ['/html', '.html', 'php'], 'configuration' => ['', '.php', 'php'], ]; $folder .= $config[$_type][0]; $filename .= $config[$_type][1]; $type = $config[$_type][2]; } if ($plugin != '') { $folder = 'plugins/' . $plugin . '/' . $folder; } /** * Modification pour la gestion du dossier public */ if ($folder === 'desktop/js') { $folder = 'public/js/desktop'; } if ($folder === null) { $path = NEXTDOM_ROOT . '/' . $filename; } else { $path = NEXTDOM_ROOT . '/' . $folder . '/' . $filename; } if (!file_exists($path)) { throw new CoreException('Fichier introuvable : ' . Utils::secureXSS($path), 35486); } if ($type == 'php') { // Les fichiers php sont traduits if ($_type != 'class') { ob_start(); require_once $path; if ($translate) { echo TranslateHelper::exec(ob_get_clean(), $folder . '/' . $filename); } else { echo ob_get_clean(); } } else { require_once $path; } } elseif ($type == 'css') { // @TODO : MD5 echo '<link href="' . $folder . '/' . $filename . '?md5=' . md5_file($path) . '" rel="stylesheet" />'; } elseif ($type == 'js') { // @TODO : MD5 echo '<script type="text/javascript" src="src/Api/getResource.php?file=' . $folder . '/' . $filename . '&md5=' . md5_file($path) . '&lang=' . TranslateHelper::getLanguage() . '"></script>'; } } /** * Returns paths to requested 3rdparty file with jeedom backward compatibility * * The function checks that returned file belongs to nextdom-core root directory * * @param string $path requested path under folder * @return null|string|string[] */ public static function getAssetPath($path) { $staticMapping = [ '3rdparty/bootstrap.slider/css/slider' => 'vendor/node_modules/bootstrap-slider/dist/css/bootstrap-slider.min', '3rdparty/bootstrap.slider/js/bootstrap-slider' => 'vendor/node_modules/bootstrap-slider/dist/bootstrap-slider.min', '3rdparty/bootstrap/css/bootstrap.min' => 'vendor/node_modules/bootstrap/dist/css/bootstrap.min', '3rdparty/bootstrap/js/bootstrap.min' => 'vendor/node_modules/bootstrap/dist/js/bootstrap.min', '3rdparty/codemirror/lib/codemirror' => 'vendor/node_modules/codemirror/lib/codemirror', '3rdparty/datetimepicker/jquery.datetimepicker' => 'vendor/node_modules/jquery-datetimepicker/jquery.datetimepicker', '3rdparty/highstock/highcharts-more' => 'vendor/node_modules/highcharts/highcharts-more', '3rdparty/highstock/highstock' => 'vendor/node_modules/highcharts/highstock', '3rdparty/jquery.fileupload/jquery.fileupload' => 'vendor/node_modules/blueimp-file-upload/js/jquery.fileupload', '3rdparty/jquery.fileupload/jquery.iframe-transport' => 'vendor/node_modules/blueimp-file-upload/js/jquery.iframe-transport', '3rdparty/jquery.fileupload/jquery.ui.widget' => 'vendor/node_modules/blueimp-file-upload/js/vendor/jquery.ui.widget', '3rdparty/jquery.lazyload/jquery.lazyload' => 'vendor/node_modules/jquery-lazyload/jquery.lazyload', '3rdparty/jquery.packery/jquery.packery' => 'vendor/node_modules/packery/dist/packery.pkgd', '3rdparty/jquery.tablesorter/jquery.tablesorter.min' => 'vendor/node_modules/tablesorter/dist/js/jquery.tablesorter.min', '3rdparty/jquery.tablesorter/jquery.tablesorter.widgets.min' => 'vendor/node_modules/tablesorter/dist/js/jquery.tablesorter.widgets.min', '3rdparty/jquery.tablesorter/theme.bootstrap' => 'vendor/node_modules/tablesorter/dist/css/theme.bootstrap.min', '3rdparty/jquery.ui/jquery-ui.min' => 'vendor/node_modules/jquery-ui-dist/jquery-ui.min', '3rdparty/jquery/jquery.min' => 'vendor/node_modules/jquery/dist/jquery.min', '3rdparty/roboto/roboto' => 'vendor/node_modules/roboto-fontface/css/roboto-fontface', '3rdparty/waves/waves.min' => 'vendor/node_modules/node-waves/waves.min', '3rdparty/jquery.ui/jquery-ui-bootstrap/jquery-ui' => 'vendor/node_modules/jquery-ui-bootstrap/jquery.ui.theme' ]; $reMapping = [ '%3rdparty/codemirror/(mode|addon)/(.*)%' => 'vendor/node_modules/codemirror/${1}/${2}' ]; $pathinfo = pathinfo($path); $extension = Utils::array_key_default($pathinfo, "extension", ""); $dirname = Utils::array_key_default($pathinfo, "dirname", ""); $filename = Utils::array_key_default($pathinfo, "filename", ""); $needle = sprintf("%s/%s", trim($dirname, "/"), $filename); $mappedValue = Utils::array_key_default($staticMapping, $needle, false); $staticValue = sprintf("assets/%s.%s", $needle, $extension); if (false !== $mappedValue) { // try conversion from static mapping $path = sprintf("%s.%s", $mappedValue, $extension); } elseif (true === file_exists(NEXTDOM_ROOT . '/' . $staticValue)) { // try conversion existing asset file $path = $staticValue; } else { // try conversion from regexp mapping (slowest mode) foreach ($reMapping as $c_match => $c_replace) { $path = preg_replace($c_match, $c_replace, $needle); if (($path !== null) && ($path !== $needle)) { $path = sprintf("%s.%s", $path, $extension); break; } } } // ensure that returned file belongs to NEXTDOM_ROOT $abspath = realpath(NEXTDOM_ROOT . '/' . $path); if ((false === $abspath) || (0 !== strpos($abspath, NEXTDOM_ROOT))) { return null; } return $path; } /** * Read content of a core template file * @param string $version View version * @param string $filename Name of the template file * @param string $pluginId Plugin (todo: remove) * @param string $theme Theme if necessary * @return string */ public static function getCoreTemplateFileContent($version, $filename, $pluginId = '', $theme = ''): string { return self::getTemplateFileContent('views', $version, $filename, $pluginId, $theme); } /** * Obtenir le contenu d'un fichier template. * * @param string $folder Répertoire dans lequel se trouve le fichier de template * @param string $version Version du template * @param string $filename Nom du fichier * @param string $pluginId Identifiant du plugin * @param string $theme Identifiant du plugin * * @return string Contenu du fichier ou une chaine vide. */ public static function getTemplateFileContent($folder, $version, $filename, $pluginId = '', $theme = ''): string { $result = ''; $filePath = NEXTDOM_ROOT . '/'; if ($pluginId == '') { if ($folder === 'core') { $folder = 'views'; } if ($theme == '') { $filePath .= $folder . '/templates/' . $version . '/' . $filename . '.html'; } else { $filePath .= $folder . '/templates/' . $version . '/themes/' . $theme . '/' . $filename . '.html'; } } else { $filePath .= 'plugins/' . $pluginId . '/core/template/' . $version . '/' . $filename . '.html'; } if (file_exists($filePath)) { $result = file_get_contents($filePath); } return $result; } /** * @param $allowPath * @param $path * @return bool */ public static function hadFileRight($allowPath, $path): bool { $path = Utils::cleanPath($path); foreach ($allowPath as $right) { if (strpos($right, '/') !== false || strpos($right, '\\') !== false) { if (strpos($right, '/') !== 0 || strpos($right, '\\') !== 0) { $right = NEXTDOM_ROOT . '/' . $right; } if (dirname($path) == $right || $path == $right) { return true; } } else { if (basename(dirname($path)) == $right || basename($path) == $right) { return true; } } } return false; } /** * Get content list of a folder * * @param string $folder Folder to list * @param string $pattern Pattern for filtering (*.php, *test*, etc.) * @param bool $recursivly List all files/folders in subfolders * @param array $options Limit files or folders * * @return array Content list */ public static function ls($folder = "", $pattern = "*", $recursivly = false, $options = ['files', 'folders']) { $currentFolder = ''; if ($folder) { $currentFolder = realpath('.'); if (in_array('quiet', $options)) { // If quiet is on, we will suppress the 'no such folder' error if (!file_exists($folder)) { return []; } } if (!is_dir($folder) || !chdir($folder)) { return []; } } $getFiles = in_array('files', $options); $getFolders = in_array('folders', $options); $both = []; $folders = []; // Get the all files and folders in the given directory. if ($getFiles) { $both = []; foreach (Utils::globBrace($pattern, GLOB_MARK) as $file) { if (!is_dir($folder . '/' . $file)) { $both[] = $file; } } } if ($recursivly || $getFolders) { $folders = glob("*", GLOB_ONLYDIR + GLOB_MARK); } //If a pattern is specified, make sure even the folders match that pattern. $matching_folders = []; if ($pattern !== '*') { $matching_folders = glob($pattern, GLOB_ONLYDIR + GLOB_MARK); } //Get just the files by removing the folders from the list of all files. $all = array_values(array_diff($both, $folders)); if ($recursivly || $getFolders) { foreach ($folders as $this_folder) { if ($getFolders) { //If a pattern is specified, make sure even the folders match that pattern. if ($pattern !== '*') { if (in_array($this_folder, $matching_folders)) { array_push($all, $this_folder); } } else { array_push($all, $this_folder); } } if ($recursivly) { // Continue calling this function for all the folders $folderItems = self::ls($this_folder, $pattern, $recursivly, $options); # :RECURSION: foreach ($folderItems as $item) { array_push($all, $this_folder . $item); } } } } if ($folder && is_dir($currentFolder)) { chdir($currentFolder); } if (in_array('datetime_asc', $options)) { global $current_dir; $current_dir = $folder; usort($all, function ($a, $b) { return filemtime($GLOBALS['current_dir'] . '/' . $a) < filemtime($GLOBALS['current_dir'] . '/' . $b); }); } if (in_array('datetime_desc', $options)) { global $current_dir; $current_dir = $folder; usort($all, function ($a, $b) { return filemtime($GLOBALS['current_dir'] . '/' . $a) > filemtime($GLOBALS['current_dir'] . '/' . $b); }); } return $all; } /** * @param $src * @param $dst * @param bool $_emptyDest * @param array $_exclude * @param bool $_noError * @param array $_params * @return bool */ public static function rcopy($src, $dst, $_emptyDest = true, $_exclude = [], $_noError = false, $_params = []) { if (!file_exists($src)) { return true; } if ($_emptyDest) { self::rrmdir($dst); } if (is_dir($src)) { if (!file_exists($dst)) { @mkdir($dst); } $files = scandir($src); foreach ($files as $file) { if ($file != "." && $file != ".." && !in_array($file, $_exclude) && !in_array(realpath($src . '/' . $file), $_exclude)) { if (!self::rcopy($src . '/' . $file, $dst . '/' . $file, $_emptyDest, $_exclude, $_noError, $_params) && !$_noError) { return false; } } } } else { if (!in_array(basename($src), $_exclude) && !in_array(realpath($src), $_exclude)) { $srcSize = filesize($src); if (isset($_params['ignoreFileSizeUnder']) && $srcSize < $_params['ignoreFileSizeUnder']) { if (strpos(realpath($src), 'empty') !== false) { return true; } if (strpos(realpath($src), '.git') !== false) { return true; } if (strpos(realpath($src), '.html') !== false) { return true; } if (strpos(realpath($src), '.txt') !== false) { return true; } if (isset($_params['log']) && $_params['log']) { echo 'Ignore file ' . $src . ' because size is ' . $srcSize . "\n"; } return true; } if (!copy($src, $dst)) { $output = []; $retval = 0; exec('sudo cp ' . $src . ' ' . $dst, $output, $retval); if ($retval != 0) { if (!$_noError) { return false; } elseif (isset($_params['log']) && $_params['log']) { echo 'Error on copy ' . $src . ' to ' . $dst . "\n"; } } } if ($srcSize != filesize($dst)) { if (!$_noError) { return false; } elseif (isset($_params['log']) && $_params['log']) { echo 'Error on copy ' . $src . ' to ' . $dst . "\n"; } } return true; } } return true; } /** * @abstract removes files and non-empty directories * @param $dir * @return bool */ public static function rrmdir($dir): bool { // Check if we remove our own folders/files only if (!(substr($dir, 0, strlen(NEXTDOM_ROOT)) === NEXTDOM_ROOT || substr($dir, 0, strlen(NEXTDOM_DATA)) === NEXTDOM_DATA || substr($dir, 0, strlen(NEXTDOM_LOG)) === NEXTDOM_LOG || substr($dir, 0, strlen(NEXTDOM_TMP)) === NEXTDOM_TMP || substr($dir, 0, strlen('/tmp')) === '/tmp')) { return false; } if (is_dir($dir)) { $files = scandir($dir); foreach ($files as $file) { if ($file != "." && $file != "..") { self::rrmdir("$dir/$file"); } } if (!is_writable($dir) || !rmdir($dir)) { $output = []; $retval = 0; exec('sudo rm -rf ' . $dir, $output, $retval); if ($retval != 0) { return false; } } } elseif (file_exists($dir)) { if (!is_writable($dir) || !unlink($dir)) { $output = []; $retval = 0; exec('sudo rm -rf ' . $dir, $output, $retval); if ($retval != 0) { return false; } } } return true; } /** * @abstract removes file * @param $file * @return bool */ public static function rrmfile($file): bool { if (file_exists($file)) { return unlink($file); } return false; } /** * @param $src * @param $dst * @param bool $_emptyDest * @param array $_exclude * @param bool $_noError * @param array $_params * @return bool */ public static function rmove($src, $dst, $_emptyDest = true, $_exclude = [], $_noError = false, $_params = []) { if (!file_exists($src)) { return true; } if ($_emptyDest) { self::rrmdir($dst); } if (is_dir($src)) { if (!file_exists($dst)) { @mkdir($dst); } $files = scandir($src); foreach ($files as $file) { if ($file != "." && $file != ".." && !in_array($file, $_exclude) && !in_array(realpath($src . '/' . $file), $_exclude)) { if (!self::rmove($src . '/' . $file, $dst . '/' . $file, $_emptyDest, $_exclude, $_noError, $_params) && !$_noError) { return false; } } } } else { if (!in_array(basename($src), $_exclude) && !in_array(realpath($src), $_exclude)) { $srcSize = filesize($src); if (isset($_params['ignoreFileSizeUnder']) && $srcSize < $_params['ignoreFileSizeUnder']) { if (strpos(realpath($src), 'empty') !== false) { return true; } if (strpos(realpath($src), '.git') !== false) { return true; } if (strpos(realpath($src), '.html') !== false) { return true; } if (strpos(realpath($src), '.txt') !== false) { return true; } if (isset($_params['log']) && $_params['log']) { echo 'Ignore file ' . $src . ' because size is ' . $srcSize . "\n"; } return true; } if (!rename($src, $dst)) { $output = []; $retval = 0; exec('sudo mv ' . $src . ' ' . $dst, $output, $retval); if ($retval != 0) { if (!$_noError) { return false; } elseif (isset($_params['log']) && $_params['log']) { echo 'Error on move ' . $src . ' to ' . $dst . "\n"; } } } if ($srcSize != filesize($dst)) { if (!$_noError) { return false; } elseif (isset($_params['log']) && $_params['log']) { echo 'Error on move ' . $src . ' to ' . $dst . "\n"; } } return true; } } return true; } /** * @param $source_arr * @param $destination * @param array $_excludes * @return bool * @throws CoreException */ public static function createZip($source_arr, $destination, $_excludes = []) { if (is_string($source_arr)) { $source_arr = [$source_arr]; } if (!extension_loaded('zip')) { throw new CoreException('Extension php ZIP non chargée'); } $zip = new \ZipArchive(); if (!$zip->open($destination, \ZIPARCHIVE::CREATE)) { throw new CoreException('Impossible de créer l\'archive ZIP dans le dossier de destination : ' . $destination); } foreach ($source_arr as $source) { if (!file_exists($source)) { continue; } $source = str_replace('\\', '/', realpath($source)); if (is_dir($source) === true) { $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST); foreach ($files as $file) { if (strpos($file, $source) === false) { continue; } if ($file == $source . '/.' || $file == $source . '/..' || in_array(basename($file), $_excludes) || in_array(realpath($file), $_excludes)) { continue; } foreach ($_excludes as $exclude) { if (strpos($file, trim('/' . $exclude . '/', '/')) !== false) { continue (2); } } $file = str_replace('\\', '/', realpath($file)); if (is_dir($file) === true) { $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); } elseif (is_file($file) === true) { $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); } } } elseif (is_file($source) === true) { $zip->addFromString(basename($source), file_get_contents($source)); } } return $zip->close(); } /** * @param $path * @return false|int */ public static function getDirectorySize($path) { $totalsize = 0; if ($handle = opendir($path)) { while (false !== ($file = readdir($handle))) { $nextpath = $path . '/' . $file; if ($file != '.' && $file != '..' && !is_link($nextpath)) { if (is_dir($nextpath)) { $totalsize += self::getDirectorySize($nextpath); } elseif (is_file($nextpath)) { $totalsize += filesize($nextpath); } } } closedir($handle); } return $totalsize; } /** * Get the free space of a directory * @param string $directory Directory in which we want free space information * @return int free space in Byte (Octet) */ public static function getDirectoryFreeSpace($directory) { return disk_free_space($directory); } /** * Get true if the file exists * @param string $file File we want to know if exists * @return bool exists or not */ public static function isFileExists($file) { return file_exists($file); } /** * Moves input file or directory to given destination (acts like mv) * * @param string $src source file or directory * @param string $dst destination file or directory * @return bool true if no error */ public static function mv($src, $dst): bool { $status = -1; $cmd = sprintf("mv %s %s", $src, $dst); system($cmd, $status); return ($status === 0); } /** * Create directory if not already exists * * @param string $path , path to create * @param int $mode , see mkdir parameter * @param boolean $recursive , see mkdir parameter * @throws CoreException when cannot create directory */ public static function mkdirIfNotExists($path, $mode = 0775, $recursive = false) { if (false === is_dir($path)) { if (false === mkdir($path, $mode, $recursive)) { throw new CoreException("unable to create directory : " . $path); } } } } |