"; // 在弹窗中显示消息,\n 是换行符 echo "alert('--- 调试信息 ---\\n" . $safe_message . "');"; echo ""; // 4. 根据参数决定是否终止脚本 if ($terminate_script) { // 强制终止后续 PHP 代码的执行 die("脚本已终止,用于调试。"); } } //Default Configuration $CONFIG = '{"lang":"en","error_reporting":false,"show_hidden":false,"hide_Cols":false,"theme":"light"}'; /** * H3K - Tiny File Manager V2.6 * @author CCP Programmers * @github https://github.com/prasathmani/tinyfilemanager * @link https://tinyfilemanager.github.io */ //TFM version define('VERSION', '2.6'); //Application Title define('APP_TITLE', 'Tiny File Manager'); // --- EDIT BELOW CONFIGURATION CAREFULLY --- // Auth with login/password // set true/false to enable/disable it // Is independent from IP white- and blacklisting $use_auth = true; // Login user name and password // Users: array('Username' => 'Password', 'Username2' => 'Password2', ...) // Generate secure password hash - https://tinyfilemanager.github.io/docs/pwd.html $auth_users = array( 'admin' => '$2y$10$/K.hjNr84lLNDt8fTXjoI.DBp6PpeyoJ.mGwrrLuCZfAwfSAGqhOW', //admin@123 'user' => '$2y$10$Fg6Dz8oH9fPoZ2jJan5tZuv6Z4Kp7avtQ9bDfrdRntXtPeiMAZyGO' //12345 ); // Readonly users // e.g. array('users', 'guest', ...) $readonly_users = array( 'user' ); // Global readonly, including when auth is not being used $global_readonly = false; // user specific directories // array('Username' => 'Directory path', 'Username2' => 'Directory path', ...) $directories_users = array(); // Enable highlight.js (https://highlightjs.org/) on view's page $use_highlightjs = true; // highlight.js style // for dark theme use 'ir-black' $highlightjs_style = 'vs'; // Enable ace.js (https://ace.c9.io/) on view's page $edit_files = true; // Default timezone for date() and time() // Doc - http://php.net/manual/en/timezones.php $default_timezone = 'Etc/UTC'; // UTC // Root path for file manager // use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder' //make sure update $root_url in next section $root_path = $_SERVER['DOCUMENT_ROOT']; // Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder' // Will not working if $root_path will be outside of server document root $root_url = ''; // Server hostname. Can set manually if wrong // $_SERVER['HTTP_HOST'].'/folder' $http_host = $_SERVER['HTTP_HOST']; // input encoding for iconv $iconv_input_encoding = 'UTF-8'; // date() format for file modification date // Doc - https://www.php.net/manual/en/function.date.php $datetime_format = 'm/d/Y g:i A'; // Path display mode when viewing file information // 'full' => show full path // 'relative' => show path relative to root_path // 'host' => show path on the host $path_display_mode = 'full'; // Allowed file extensions for create and rename files // e.g. 'txt,html,css,js' $allowed_file_extensions = ''; // Allowed file extensions for upload files // e.g. 'gif,png,jpg,html,txt' $allowed_upload_extensions = ''; // Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. // full path, e.g http://example.com/favicon.png // local path, e.g images/icons/favicon.png $favicon_path = ''; // Files and folders to excluded from listing // e.g. array('myfile.html', 'personal-folder', '*.php', '/path/to/folder', ...) $exclude_items = array(); // Online office Docs Viewer // Available rules are 'google', 'microsoft' or false // Google => View documents using Google Docs Viewer // Microsoft => View documents using Microsoft Web Apps Viewer // false => disable online doc viewer $online_viewer = 'google'; // Sticky Nav bar // true => enable sticky header // false => disable sticky header $sticky_navbar = true; // Maximum file upload size // Increase the following values in php.ini to work properly // memory_limit, upload_max_filesize, post_max_size $max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB) // chunk size used for upload // eg. decrease to 1MB if nginx reports problem 413 entity too large $upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB) // Possible rules are 'OFF', 'AND' or 'OR' // OFF => Don't check connection IP, defaults to OFF // AND => Connection must be on the whitelist, and not on the blacklist // OR => Connection must be on the whitelist, or not on the blacklist $ip_ruleset = 'OFF'; // Should users be notified of their block? $ip_silent = true; // IP-addresses, both ipv4 and ipv6 $ip_whitelist = array( '127.0.0.1', // local ipv4 '::1' // local ipv6 ); // IP-addresses, both ipv4 and ipv6 $ip_blacklist = array( '0.0.0.0', // non-routable meta ipv4 '::' // non-routable meta ipv6 ); // if User has the external config file, try to use it to override the default config above [config.php] // sample config - https://tinyfilemanager.github.io/config-sample.txt $config_file = __DIR__ . '/config.php'; if (is_readable($config_file)) { @include($config_file); } // External CDN resources that can be used in the HTML (replace for GDPR compliance) $external = array( 'css-photoswipe' => '', 'js-photoswipe-lightbox' => 'https://cdn.jsdelivr.net/npm/photoswipe@5.4.3/dist/photoswipe-lightbox.esm.js', 'js-photoswipe-module' => 'https://cdn.jsdelivr.net/npm/photoswipe@5.4.3/dist/photoswipe.esm.js', 'css-bootstrap' => '', 'css-dropzone' => '', 'css-font-awesome' => '', 'css-highlightjs' => '', 'js-ace' => '', 'js-bootstrap' => '', 'js-dropzone' => '', 'js-jquery' => '', 'js-jquery-datatables' => '', 'js-highlightjs' => '', 'pre-jsdelivr' => '', 'pre-cloudflare' => '' ); // --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL --- // max upload file size define('MAX_UPLOAD_SIZE', $max_upload_size_bytes); // upload chunk size define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes); // private key and session name to store to the session if (!defined('FM_SESSION_ID')) { define('FM_SESSION_ID', 'filemanager'); } // Configuration $cfg = new FM_Config(); // Default language $lang = isset($cfg->data['lang']) ? $cfg->data['lang'] : 'en'; // Show or hide files and folders that starts with a dot $show_hidden_files = isset($cfg->data['show_hidden']) ? $cfg->data['show_hidden'] : true; // PHP error reporting - false = Turns off Errors, true = Turns on Errors $report_errors = isset($cfg->data['error_reporting']) ? $cfg->data['error_reporting'] : true; // Hide Permissions and Owner cols in file-listing $hide_Cols = isset($cfg->data['hide_Cols']) ? $cfg->data['hide_Cols'] : true; // Theme $theme = isset($cfg->data['theme']) ? $cfg->data['theme'] : 'light'; define('FM_THEME', $theme); //available languages $lang_list = array( 'en' => 'English' ); if ($report_errors == true) { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 1); } else { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 0); } // if fm included if (defined('FM_EMBED')) { $use_auth = false; $sticky_navbar = false; } else { @set_time_limit(600); date_default_timezone_set($default_timezone); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) { mb_internal_encoding('UTF-8'); } if (function_exists('mb_regex_encoding')) { mb_regex_encoding('UTF-8'); } session_cache_limiter('nocache'); // Prevent logout issue after page was cached session_name(FM_SESSION_ID); function session_error_handling_function($code, $msg, $file, $line) { // Permission denied for default session, try to create a new one if ($code == 2) { session_abort(); session_id(session_create_id()); @session_start(); } } set_error_handler('session_error_handling_function'); session_start(); restore_error_handler(); } //Generating CSRF Token if (empty($_SESSION['token'])) { if (function_exists('random_bytes')) { $_SESSION['token'] = bin2hex(random_bytes(32)); } else { $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32)); } } if (empty($auth_users)) { $use_auth = false; } $is_https = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; // update $root_url based on user specific directories if (isset($_SESSION[FM_SESSION_ID]['logged']) && !empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']])) { $wd = fm_clean_path(dirname($_SERVER['PHP_SELF'])); $root_url = $root_url . $wd . DIRECTORY_SEPARATOR . $directories_users[$_SESSION[FM_SESSION_ID]['logged']]; } // clean $root_url $root_url = fm_clean_path($root_url); // abs path for site defined('FM_ROOT_URL') || define('FM_ROOT_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . (!empty($root_url) ? '/' . $root_url : '')); defined('FM_SELF_URL') || define('FM_SELF_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . $_SERVER['PHP_SELF']); // logout if (isset($_GET['logout'])) { unset($_SESSION[FM_SESSION_ID]['logged']); unset($_SESSION['token']); fm_redirect(FM_SELF_URL); } // Validate connection IP if ($ip_ruleset != 'OFF') { function getClientIP() { if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { return $_SERVER["HTTP_CF_CONNECTING_IP"]; } else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { return $_SERVER["HTTP_X_FORWARDED_FOR"]; } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { return $_SERVER['REMOTE_ADDR']; } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { return $_SERVER['HTTP_CLIENT_IP']; } return ''; } $clientIp = getClientIP(); $proceed = false; $whitelisted = in_array($clientIp, $ip_whitelist); $blacklisted = in_array($clientIp, $ip_blacklist); if ($ip_ruleset == 'AND') { if ($whitelisted == true && $blacklisted == false) { $proceed = true; } } else if ($ip_ruleset == 'OR') { if ($whitelisted == true || $blacklisted == false) { $proceed = true; } } if ($proceed == false) { trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING); if ($ip_silent == false) { fm_set_msg(lng('Access denied. IP restriction applicable'), 'error'); fm_show_header_login(); fm_show_message(); } exit(); } } // Checking if the user is logged in or not. If not, it will show the login form. if ($use_auth) { if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) { // Logged } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) { // Logging In sleep(1); if (function_exists('password_verify')) { if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) { $_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr']; fm_set_msg(lng('You are logged in')); fm_redirect(FM_SELF_URL); } else { unset($_SESSION[FM_SESSION_ID]['logged']); fm_set_msg(lng('Login failed. Invalid username or password'), 'error'); fm_redirect(FM_SELF_URL); } } else { fm_set_msg(lng('password_hash not supported, Upgrade PHP version'), 'error');; } } else { // Form unset($_SESSION[FM_SESSION_ID]['logged']); fm_show_header_login(); ?>
" . lng('Root path') . " \"{$root_path}\" " . lng('not found!') . " "; exit; } defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files); defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path); // fm_set_msg(sprintf('%s **0',$root_path), 'alert'); defined('FM_LANG') || define('FM_LANG', $lang); defined('FM_FILE_EXTENSION') || define('FM_FILE_EXTENSION', $allowed_file_extensions); defined('FM_UPLOAD_EXTENSION') || define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions); defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($exclude_items) : $exclude_items)); defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER', $online_viewer); define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset($_SESSION[FM_SESSION_ID]['logged']) && in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users))); define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\'); // always use ?p= if (!isset($_GET['p']) && empty($_FILES)) { fm_redirect(FM_SELF_URL . '?p='); } // get path $p = isset($_GET['p']) ? $_GET['p'] : (isset($_POST['p']) ? $_POST['p'] : ''); // clean path $p = fm_clean_path($p); // for ajax request - save $input = file_get_contents('php://input'); $_POST = (strpos($input, 'ajax') != FALSE && strpos($input, 'save') != FALSE) ? json_decode($input, true) : $_POST; // instead globals vars define('FM_PATH', $p); define('FM_USE_AUTH', $use_auth); define('FM_EDIT_FILE', $edit_files); defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding); defined('FM_USE_HIGHLIGHTJS') || define('FM_USE_HIGHLIGHTJS', $use_highlightjs); defined('FM_HIGHLIGHTJS_STYLE') || define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style); defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); /*************************** ACTIONS ***************************/ function sanitizePath($path) { if (substr($path, 0, 1) !== '/') { die('Invalid file path.'); } if ($path === '/') { return '/'; } return realpath($path); } // 忽略用户断开连接,确保脚本完成输出 ignore_user_abort(true); // 设置脚本执行时间无限制,关闭输出缓冲(重要) set_time_limit(0); if (ob_get_level()) { ob_end_clean(); } // 定义一个调试文件路径(请确保 PHP 有写入权限) define('DEBUG_LOG_FILE', '/tmp/proxy_debug.log'); /** * 记录调试信息到文件 */ function logDebug(string $message): void { file_put_contents(DEBUG_LOG_FILE, "[" . date('Y-m-d H:i:s') . "] " . $message . "\n", FILE_APPEND); } /** * 增强 MIME 类型识别(用于替换老代码中的 finfo 逻辑) * 增强 MIME 类型识别(已添加 AVI 和其他常见格式) */ function getMimeTypeEnhanced(string $filePath, string $defaultMime): string { $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); // Fallback/优先级: 增强对常见图片和视频的识别 $mimes = [ // 图片 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'webp' => 'image/webp', // 视频 (已添加 avi) 'mp4' => 'video/mp4', 'webm' => 'video/webm', 'ogg' => 'video/ogg', 'avi' => 'video/x-msvideo', // <-- 关键修正 'mov' => 'video/quicktime', // <-- 针对您之前成功的 .mov 视频 'mkv' => 'video/x-matroska', // 文档/其他 'pdf' => 'application/pdf', 'txt' => 'text/plain', ]; if (isset($mimes[$ext])) { return $mimes[$ext]; // 优先返回我们手动定义的准确 MIME } // 如果 finfo_file 可用,使用它 if (extension_loaded('fileinfo')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $result = $finfo ? finfo_file($finfo, $filePath) : $defaultMime; if ($finfo) finfo_close($finfo); // 如果 finfo 返回的值不准确(例如 'application/octet-stream'),我们保持其值, // 但由于有上面的优先检查,这里主要是作为更复杂的格式的补充。 return $result; } return $defaultMime; } // file proxy if (isset($_GET['proxy_file'])) { header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET'); // get file path $filePath = isset($_GET['path']) ? $_GET['path'] : "/"; $filePath = sanitizePath($filePath); if ($filePath === false || !file_exists($filePath)) { http_response_code(404); die('File not found or inaccessible.'); } if (is_dir($filePath)) { // if it is dir,list the content $fileList = getFileList($filePath); echo generateDirectoryListing($filePath, $fileList); exit; } else { if (!is_readable($filePath)) { http_response_code(403); die("File is not readable."); } // --- 增强 MIME 类型获取 (替换老代码中的 finfo 逻辑) --- // 清空日志文件,开始新的记录 file_put_contents(DEBUG_LOG_FILE, "--- NEW REQUEST START ---\n"); logDebug("INFO: Processing file: " . $filePath); $defaultMime = 'application/octet-stream'; $mimeType = getMimeTypeEnhanced($filePath, $defaultMime); header('Content-Type: ' . $mimeType); $fileSize = filesize($filePath); header("Accept-Ranges: bytes"); // 关键:宣布支持分段下载 logDebug("INFO: File Size: $fileSize | MIME: $mimeType"); logDebug("Requested Headers (Range): " . ($_SERVER['HTTP_RANGE'] ?? 'NONE')); // --- 5. 增强的 HTTP Range Requests (206) 分支 --- if (isset($_SERVER['HTTP_RANGE'])) { logDebug("PATH: Entering 206 (Range) logic."); $range = $_SERVER['HTTP_RANGE']; // 使用更健壮的正则解析 Range 头部 (仅支持单段请求) if (!preg_match('/bytes=(\d*)-(\d*)/', $range, $matches)) { logDebug("ERROR: Invalid Range format: $range"); header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes */$fileSize"); exit; } $start = $matches[1] === '' ? null : (int)$matches[1]; $end = $matches[2] === '' ? null : (int)$matches[2]; // 处理缺失的起始或结束字节 $start = $start ?? 0; $end = $end ?? $fileSize - 1; if ($start > $end || $start >= $fileSize || $end >= $fileSize) { logDebug("ERROR: Range boundary invalid. Start: $start, End: $end"); header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes */$fileSize"); exit; } $length = $end - $start + 1; // 设置 206 响应头 header("HTTP/1.1 206 Partial Content"); header("Content-Length: $length"); header("Content-Range: bytes $start-$end/$fileSize"); logDebug("RESPONSE: 206 Partial Content | Range: $start-$end/$fileSize | Length: $length"); // 流式输出分段内容 $file = fopen($filePath, 'rb'); fseek($file, $start); $buffer = 1024 * 16; $bytesSent = 0; while (!feof($file) && ($p = ftell($file)) <= $end) { $bytesToRead = min($buffer, $end - $p + 1); $chunk = fread($file, $bytesToRead); echo $chunk; $bytesSent += strlen($chunk); flush(); } fclose($file); logDebug("SUCCESS: Sent $bytesSent bytes (Range)."); exit; } // --- 6. 强制流式传输 (200 OK) 分支 (用于解决大文件超时问题) --- else { logDebug("PATH: Entering 200 (Full Content) logic. FORCING STREAMING for large file stability."); http_response_code(200); header("Content-Length: $fileSize"); logDebug("RESPONSE: 200 OK | Content-Length: $fileSize"); $file = fopen($filePath, 'rb'); $buffer = 1024 * 256; // 128KB 缓冲区 $bytesSent = 0; $logInterval = 50 * 1024 * 1024; // 每 50MB 记录一次日志 $nextLogPoint = $logInterval; while (!feof($file)) { $chunk = fread($file, $buffer); echo $chunk; $bytesSent += strlen($chunk); // 检查是否达到日志记录点 if ($bytesSent >= $nextLogPoint) { logDebug("STREAM: Sent " . round($bytesSent / 1024 / 1024, 2) . " MB."); $nextLogPoint += $logInterval; } flush(); } fclose($file); logDebug("SUCCESS: Sent $bytesSent bytes (Full) via forced streaming."); exit; } } // 结束 if (isset($_GET['proxy_file'])) 块 } // get file lists function getFileList($dir) { $files = array(); $entries = scandir($dir); foreach ($entries as $entry) { if ($entry != "." && $entry != "..") { $files[] = $entry; } } return $files; } // create file lists HTML function generateDirectoryListing($dir, $fileList) { $html = "Index of {$dir}"; $html .= "

Index of {$dir}



"; return $html; } // Handle all AJAX Request if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token']) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { header('HTTP/1.0 401 Unauthorized'); die("Invalid Token."); } //search : get list of files from the current folder if (isset($_POST['type']) && $_POST['type'] == "search") { $dir = $_POST['path'] == "." ? '' : $_POST['path']; $response = scan(fm_clean_path($dir), $_POST['content']); echo json_encode($response); exit(); } // save editor file if (isset($_POST['type']) && $_POST['type'] == "save") { // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } $file = $_GET['edit']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || !is_file($path . ($path === '/' ? '' : '/') . $file)) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } header('X-XSS-Protection:0'); $file_path = $path . ($path === '/' ? '' : '/') . $file; $writedata = $_POST['content']; $fd = fopen($file_path, "w"); $write_results = @fwrite($fd, $writedata); fclose($fd); if ($write_results === false) { header("HTTP/1.1 500 Internal Server Error"); die("Could Not Write File! - Check Permissions / Ownership"); } die(true); } // backup files if (isset($_POST['type']) && $_POST['type'] == "backup" && !empty($_POST['file'])) { $fileName = fm_clean_path($_POST['file']); $fullPath = FM_ROOT_PATH . '/'; $fullPath = FM_ROOT_PATH ==='/'? FM_ROOT_PATH : FM_ROOT_PATH . '/'; if (!empty($_POST['path'])) { $relativeDirPath = fm_clean_path($_POST['path']); $fullPath .= "{$relativeDirPath}/"; } $date = date("dMy-His"); $newFileName = "{$fileName}-{$date}.bak"; $fullyQualifiedFileName = $fullPath . $fileName; try { if (!file_exists($fullyQualifiedFileName)) { throw new Exception("File {$fileName} not found"); } if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) { echo "Backup {$newFileName} created"; } else { throw new Exception("Could not copy file {$fileName}"); } } catch (Exception $e) { echo $e->getMessage(); } } // Save Config if (isset($_POST['type']) && $_POST['type'] == "settings") { global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list, $hide_Cols, $theme; $newLng = $_POST['js-language']; fm_get_translations([]); if (!array_key_exists($newLng, $lang_list)) { $newLng = 'en'; } $erp = isset($_POST['js-error-report']) && $_POST['js-error-report'] == "true" ? true : false; $shf = isset($_POST['js-show-hidden']) && $_POST['js-show-hidden'] == "true" ? true : false; $hco = isset($_POST['js-hide-cols']) && $_POST['js-hide-cols'] == "true" ? true : false; $te3 = $_POST['js-theme-3']; if ($cfg->data['lang'] != $newLng) { $cfg->data['lang'] = $newLng; $lang = $newLng; } if ($cfg->data['error_reporting'] != $erp) { $cfg->data['error_reporting'] = $erp; $report_errors = $erp; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['hide_Cols'] != $hco) { $cfg->data['hide_Cols'] = $hco; $hide_Cols = $hco; } if ($cfg->data['theme'] != $te3) { $cfg->data['theme'] = $te3; $theme = $te3; } $cfg->save(); echo true; } // new password hash if (isset($_POST['type']) && $_POST['type'] == "pwdhash") { $res = isset($_POST['inputPassword2']) && !empty($_POST['inputPassword2']) ? password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) : ''; echo $res; } //upload using url if (isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } function event_callback($message) { global $callback; echo json_encode($message); } function get_file_path() { global $path, $fileinfo, $temp_file; return $path . "/" . basename($fileinfo->name); } $url = !empty($_REQUEST["uploadurl"]) && preg_match("|^http(s)?://.+$|", stripslashes($_REQUEST["uploadurl"])) ? stripslashes($_REQUEST["uploadurl"]) : null; //prevent 127.* domain and known ports $domain = parse_url($url, PHP_URL_HOST); $port = parse_url($url, PHP_URL_PORT); $knownPorts = [22, 23, 25, 3306]; if (preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i", $domain) || in_array($port, $knownPorts)) { $err = array("message" => "URL is not allowed"); event_callback(array("fail" => $err)); exit(); } $use_curl = false; $temp_file = tempnam(sys_get_temp_dir(), "upload-"); $fileinfo = new stdClass(); $fileinfo->name = trim(urldecode(basename($url)), ".\x00..\x20"); $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $ext = strtolower(pathinfo($fileinfo->name, PATHINFO_EXTENSION)); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; $err = false; if (!$isFileAllowed) { $err = array("message" => "File extension is not allowed"); event_callback(array("fail" => $err)); exit(); } if (!$url) { $success = false; } else if ($use_curl) { @$fp = fopen($temp_file, "w"); @$ch = curl_init($url); curl_setopt($ch, CURLOPT_NOPROGRESS, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_FILE, $fp); @$success = curl_exec($ch); $curl_info = curl_getinfo($ch); if (!$success) { $err = array("message" => curl_error($ch)); } @curl_close($ch); fclose($fp); $fileinfo->size = $curl_info["size_download"]; $fileinfo->type = $curl_info["content_type"]; } else { $ctx = stream_context_create(); @$success = copy($url, $temp_file, $ctx); if (!$success) { $err = error_get_last(); } } if ($success) { $success = rename($temp_file, strtok(get_file_path(), '?')); } if ($success) { event_callback(array("done" => $fileinfo)); } else { unlink($temp_file); if (!$err) { $err = array("message" => "Invalid url parameter"); } event_callback(array("fail" => $err)); } } exit(); } // Delete file / folder if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) { $del = str_replace('/', '', fm_clean_path($_GET['del'])); if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } $is_dir = is_dir($path . ($path === '/' ? '' : '/') . $del); if (fm_rdelete($path . ($path === '/' ? '' : '/') . $del)) { $msg = $is_dir ? lng('Folder') . ' %s ' . lng('Deleted') : lng('File') . ' %s ' . lng('Deleted'); fm_set_msg(sprintf($msg, fm_enc($del))); } else { $msg = $is_dir ? lng('Folder') . ' %s ' . lng('not deleted') : lng('File') . ' %s ' . lng('not deleted'); fm_set_msg(sprintf($msg, fm_enc($del)), 'error'); } } else { fm_set_msg(lng('Invalid file or folder name'), 'error'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Create a new file/folder if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) { $type = urldecode($_POST['newfile']); $new = str_replace(($path === '/' ? '' : '/') , '', fm_clean_path(strip_tags($_POST['newfilename']))); if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } if ($type == "file") { if (!file_exists($path . ($path === '/' ? '' : '/') . $new)) { if (fm_is_valid_ext($new)) { @fopen($path . ($path === '/' ? '' : '/') . $new, 'w') or die('Cannot open file: ' . $new); fm_set_msg(sprintf(lng('File') . ' %s ' . lng('Created'), fm_enc($new))); } else { fm_set_msg(lng('File extension is not allowed'), 'error'); } } else { fm_set_msg(sprintf(lng('File') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); } } else { if (fm_mkdir($path . ($path === '/' ? '' : '/') . $new, false) === true) { fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('Created'), $new)); } elseif (fm_mkdir($path . ($path === '/' ? '' : '/') . $new, false) === $path . ($path === '/' ? '' : '/') . $new) { fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); } else { fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('not created'), fm_enc($new)), 'error'); } } } else { fm_set_msg(lng('Invalid characters in file or folder name'), 'error'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Copy folder / file if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) { // from $copy = urldecode($_GET['copy']); $copy = fm_clean_path($copy); // empty path if ($copy == '') { fm_set_msg(lng('Source path not defined'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // abs path from $from = FM_ROOT_PATH . (FM_ROOT_PATH === '/' ? '' : '/') . $copy; // abs path to $dest = FM_ROOT_PATH; if (FM_PATH != '') { $dest .= ($dest === '/' ? '' : '/') . FM_PATH; } $dest .= ($dest === '/' ? '' : '/') . basename($from); // move? $move = isset($_GET['move']); $move = fm_clean_path(urldecode($move)); // copy/move/duplicate if ($from != $dest) { $msg_from = trim(FM_PATH . '/' . basename($from), '/'); if ($move) { // Move and to != from so just perform move $rename = fm_rename($from, $dest); if ($rename) { fm_set_msg(sprintf(lng('Moved from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); } elseif ($rename === null) { fm_set_msg(lng('File or folder with this path already exists'), 'alert'); } else { fm_set_msg(sprintf(lng('Error while moving from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } else { // Not move and to != from so copy with original name if (fm_rcopy($from, $dest)) { fm_set_msg(sprintf(lng('Copied from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); } else { fm_set_msg(sprintf(lng('Error while copying from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } } else { if (!$move) { //Not move and to = from so duplicate $msg_from = trim(FM_PATH . '/' . basename($from), '/'); $fn_parts = pathinfo($from); $extension_suffix = ''; if (!is_dir($from)) { $extension_suffix = '.' . $fn_parts['extension']; } //Create new name for duplicate $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-' . date('YmdHis') . $extension_suffix; $loop_count = 0; $max_loop = 1000; // Check if a file with the duplicate name already exists, if so, make new name (edge case...) while (file_exists($fn_duplicate) & $loop_count < $max_loop) { $fn_parts = pathinfo($fn_duplicate); $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-copy' . $extension_suffix; $loop_count++; } if (fm_rcopy($from, $fn_duplicate, False)) { fm_set_msg(sprintf('Copied from %s to %s', fm_enc($copy), fm_enc($fn_duplicate))); } else { fm_set_msg(sprintf('Error while copying from %s to %s', fm_enc($copy), fm_enc($fn_duplicate)), 'error'); } } else { fm_set_msg(lng('Paths must be not equal'), 'alert'); } } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Mass copy files/ folders if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { fm_set_msg(lng('Invalid Token.'), 'error'); } // from $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } // to $copy_to_path = FM_ROOT_PATH; $copy_to = fm_clean_path($_POST['copy_to']); if ($copy_to != '') { $copy_to_path .= ($path === '/' ? '' : '/') . $copy_to; } if ($path == $copy_to_path) { fm_set_msg(lng('Paths must be not equal'), 'alert'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if (!is_dir($copy_to_path)) { if (!fm_mkdir($copy_to_path, true)) { fm_set_msg('Unable to create destination folder', 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // move? $move = isset($_POST['move']); // copy/move $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $f = fm_clean_path($f); // abs path from $from = $path . ($path === '/' ? '' : '/') . $f; // abs path to $dest = $copy_to_path . ($path === '/' ? '' : '/') . $f; // do if ($move) { $rename = fm_rename($from, $dest); if ($rename === false) { $errors++; } } else { if (!fm_rcopy($from, $dest)) { $errors++; } } } } if ($errors == 0) { $msg = $move ? 'Selected files and folders moved' : 'Selected files and folders copied'; fm_set_msg($msg); } else { $msg = $move ? 'Error while moving items' : 'Error while copying items'; fm_set_msg($msg, 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Rename if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); } // old name $old = urldecode($_POST['rename_from']); $old = fm_clean_path($old); $old = str_replace('/', '', $old); // new name $new = urldecode($_POST['rename_to']); $new = fm_clean_path(strip_tags($new)); $new = str_replace('/', '', $new); // path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } // rename if (fm_isvalid_filename($new) && $old != '' && $new != '') { if (fm_rename($path . ($path === '/' ? '' : '/') . $old, $path . ($path === '/' ? '' : '/') . $new)) { fm_set_msg(sprintf(lng('Renamed from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new))); } else { fm_set_msg(sprintf(lng('Error while renaming from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new)), 'error'); } } else { fm_set_msg(lng('Invalid characters in file name'), 'error'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Download if (isset($_GET['dl'], $_POST['token'])) { // Verify the token to ensure it's valid if (!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); exit; } // Clean the download file path $dl = urldecode($_GET['dl']); $dl = fm_clean_path($dl); $dl = str_replace('/', '', $dl); // Prevent directory traversal attacks // Define the file path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } // Check if the file exists and is valid if ($dl != '' && is_file($path . ($path === '/' ? '' : '/') . $dl)) { // Close the session to prevent session locking if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); } // Call the download function fm_download_file($path . ($path === '/' ? '' : '/') . $dl, $dl, 1024); // Download with a buffer size of 1024 bytes exit; } else { // Handle the case where the file is not found fm_set_msg(lng('File not found'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // Upload if (!empty($_FILES) && !FM_READONLY) { if (isset($_POST['token'])) { if (!verifyToken($_POST['token'])) { $response = array('status' => 'error', 'info' => "Invalid Token."); echo json_encode($response); exit(); } } else { $response = array('status' => 'error', 'info' => "Token Missing."); echo json_encode($response); exit(); } $chunkIndex = $_POST['dzchunkindex']; $chunkTotal = $_POST['dztotalchunkcount']; $fullPathInput = fm_clean_path($_REQUEST['fullpath']); $f = $_FILES; $path = FM_ROOT_PATH; $ds = DIRECTORY_SEPARATOR; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } $errors = 0; $uploads = 0; $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $response = array( 'status' => 'error', 'info' => 'Oops! Try again' ); $filename = $f['file']['name']; $tmp_name = $f['file']['tmp_name']; $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : ''; $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; if (!fm_isvalid_filename($filename) && !fm_isvalid_filename($fullPathInput)) { $response = array( 'status' => 'error', 'info' => "Invalid File name!", ); echo json_encode($response); exit(); } $targetPath = $path . $ds; if (is_writable($targetPath)) { $fullPath = $path . ($path === '/' ? '' : '/') . $fullPathInput; $folder = substr($fullPath, 0, strrpos($fullPath, "/")); if (!is_dir($folder)) { $old = umask(0); mkdir($folder, 0777, true); umask($old); } if (empty($f['file']['error']) && !empty($tmp_name) && $tmp_name != 'none' && $isFileAllowed) { if ($chunkTotal) { $out = @fopen("{$fullPath}.part", $chunkIndex == 0 ? "wb" : "ab"); if ($out) { $in = @fopen($tmp_name, "rb"); if ($in) { if (PHP_VERSION_ID < 80009) { // workaround https://bugs.php.net/bug.php?id=81145 do { for (;;) { $buff = fread($in, 4096); if ($buff === false || $buff === '') { break; } fwrite($out, $buff); } } while (!feof($in)); } else { stream_copy_to_stream($in, $out); } $response = array( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array( 'status' => 'error', 'info' => "failed to open output stream", 'errorDetails' => error_get_last() ); } @fclose($in); @fclose($out); @unlink($tmp_name); $response = array( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array( 'status' => 'error', 'info' => "failed to open output stream" ); } if ($chunkIndex == $chunkTotal - 1) { if (file_exists($fullPath)) { $ext_1 = $ext ? '.' . $ext : ''; $fullPathTarget = $path . ($path === '/' ? '' : '/') . basename($fullPathInput, $ext_1) . '_' . date('ymdHis') . $ext_1; } else { $fullPathTarget = $fullPath; } rename("{$fullPath}.part", $fullPathTarget); } } else if (move_uploaded_file($tmp_name, $fullPath)) { // Be sure that the file has been uploaded if (file_exists($fullPath)) { $response = array( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array( 'status' => 'error', 'info' => 'Couldn\'t upload the requested file.' ); } } else { $response = array( 'status' => 'error', 'info' => "Error while uploading files. Uploaded files $uploads", ); } } } else { $response = array( 'status' => 'error', 'info' => 'The specified folder for upload isn\'t writeable.' ); } // Return the response echo json_encode($response); exit(); } // Mass deleting if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $new_path = $path . ($path === '/' ? '' : '/') . $f; if (!fm_rdelete($new_path)) { $errors++; } } } if ($errors == 0) { fm_set_msg(lng('Selected files and folder deleted')); } else { fm_set_msg(lng('Error while deleting items'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Pack files zip, tar if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; $ext = 'zip'; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } //set pack type $ext = isset($_POST['tar']) ? 'tar' : 'zip'; if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $files = $_POST['file']; $sanitized_files = array(); // clean path foreach ($files as $file) { array_push($sanitized_files, fm_clean_path($file)); } $files = $sanitized_files; if (!empty($files)) { chdir($path); if (count($files) == 1) { $one_file = reset($files); $one_file = basename($one_file); $zipname = $one_file . '_' . date('ymd_His') . '.' . $ext; } else { $zipname = 'archive_' . date('ymd_His') . '.' . $ext; } if ($ext == 'zip') { $zipper = new FM_Zipper(); $res = $zipper->create($zipname, $files); } elseif ($ext == 'tar') { $tar = new FM_Zipper_Tar(); $res = $tar->create($zipname, $files); } if ($res) { fm_set_msg(sprintf(lng('Archive') . ' %s ' . lng('Created'), fm_enc($zipname))); } else { fm_set_msg(lng('Archive not created'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Unpack zip, tar if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) { if (!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $unzip = urldecode($_POST['unzip']); $unzip = fm_clean_path($unzip); $unzip = str_replace('/', '', $unzip); $isValid = false; $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } if ($unzip != '' && is_file($path . ($path === '/' ? '' : '/') . $unzip)) { $zip_path = $path . ($path === '/' ? '' : '/') . $unzip; $ext = pathinfo($zip_path, PATHINFO_EXTENSION); $isValid = true; } else { fm_set_msg(lng('File not found'), 'error'); } if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if ($isValid) { //to folder $tofolder = ''; if (isset($_POST['tofolder'])) { $tofolder = pathinfo($zip_path, PATHINFO_FILENAME); if (fm_mkdir($path . ($path === '/' ? '' : '/') . $tofolder, true)) { $path .= ($path === '/' ? '' : '/') . $tofolder; } } if ($ext == "zip") { $zipper = new FM_Zipper(); $res = $zipper->unzip($zip_path, $path); } elseif ($ext == "tar") { try { $gzipper = new PharData($zip_path); if (@$gzipper->extractTo($path, null, true)) { $res = true; } else { $res = false; } } catch (Exception $e) { //TODO:: need to handle the error $res = true; } } if ($res) { fm_set_msg(lng('Archive unpacked')); } else { fm_set_msg(lng('Archive not unpacked'), 'error'); } } else { fm_set_msg(lng('File not found'), 'error'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Change Perms (not for Windows) if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) { if (!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= ($path === '/' ? '' : '/') . FM_PATH; } $file = $_POST['chmod']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || (!is_file($path . ($path === '/' ? '' : '/') . $file) && !is_dir($path . ($path === '/' ? '' : '/') . $file))) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $mode = 0; if (!empty($_POST['ur'])) { $mode |= 0400; } if (!empty($_POST['uw'])) { $mode |= 0200; } if (!empty($_POST['ux'])) { $mode |= 0100; } if (!empty($_POST['gr'])) { $mode |= 0040; } if (!empty($_POST['gw'])) { $mode |= 0020; } if (!empty($_POST['gx'])) { $mode |= 0010; } if (!empty($_POST['or'])) { $mode |= 0004; } if (!empty($_POST['ow'])) { $mode |= 0002; } if (!empty($_POST['ox'])) { $mode |= 0001; } if (@chmod($path . ($path === '/' ? '' : '/') . $file, $mode)) { fm_set_msg(lng('Permissions changed')); } else { fm_set_msg(lng('Permissions not changed'), 'error'); } $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } /*************************** ACTIONS ***************************/ // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { //$path .= '/' . FM_PATH; $path .= ($path === '/' ? '' : '/') . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } // get parent folder $parent = fm_get_parent_path(FM_PATH); //fm_set_msg(sprintf(' %s , %s **1', $path, FM_PATH ), 'alert'); $objects = is_readable($path) ? scandir($path) : array(); $folders = array(); $files = array(); $current_path = array_slice(explode("/", $path), -1)[0]; // mnt # /mnt //$current_path =''; // fm_set_msg(sprintf('%s # %s **1', $current_path,$path ), 'alert'); if (is_array($objects) ) { //if (is_array($objects) && fm_is_exclude_items($current_path, $path)) { $n =0; foreach ($objects as $file) { $n = $n +1; if ($file == '.' || $file == '..') { continue; } if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') { continue; } //$new_path = $path . '/' . $file; $new_path = $path . ($path === '/' ? '' : '/') . $file; if (@is_file($new_path) && fm_is_exclude_items($file, $new_path)) { $files[] = $file; } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file, $new_path)) { $folders[] = $file; } } // fm_set_msg(sprintf('%s # %s ---%s **2', $current_path,$path , $n), 'alert'); }else{ fm_set_msg(sprintf('%s # %s **3', $current_path,$path ), 'alert'); } if (!empty($files)) { natcasesort($files); } if (!empty($folders)) { natcasesort($folders); } // upload form if (isset($_GET['upload']) && !FM_READONLY) { fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path //get the allowed file extensions function getUploadExt() { $extArr = explode(',', FM_UPLOAD_EXTENSION); if (FM_UPLOAD_EXTENSION && $extArr) { array_walk($extArr, function (&$x) { $x = ".$x"; }); return implode(',', $extArr); } return ''; } ?>

:

"; // 1. 判断同名缩略图文件是否存在 if (file_exists($thumbnailPath)) { //echo "DEBUG: 缩略图已存在,跳过。
"; return $thumbnailPath; } // 2. 判断子目录 thumbnails 是否存在,如果不存在则创建 if (!is_dir($thumbnailsDir)) { // 尝试创建目录,使用 0775 权限(Web用户可能在组内) if (!@mkdir($thumbnailsDir, 0775, true)) { //echo "DEBUG ERROR: 无法创建目录!请手动检查或设置权限: chmod 775 $thumbnailsDir
"; return false; } else { // 尝试设置权限,防止目录创建成功但权限不足 @chmod($thumbnailsDir, 0775); //echo "DEBUG: 目录 $thumbnailsDir 创建成功。
"; } } // 3. 获取图片尺寸信息 $size = @getimagesize($filePath); if ($size === false) { //echo "DEBUG ERROR: 无法获取图片尺寸: $filePath
"; return false; } $sourceWidth = $size[0]; $sourceHeight = $size[1]; // 4. 确定图片创建函数和扩展名 $createFunc = null; $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); $isJpeg = false; switch ($ext) { case 'jpg': case 'jpeg': case 'jfif': $createFunc = 'imagecreatefromjpeg'; $isJpeg = true; break; case 'png': $createFunc = 'imagecreatefrompng'; break; case 'gif': $createFunc = 'imagecreatefromgif'; break; case 'webp': $createFunc = 'imagecreatefromwebp'; break; case 'bmp': $createFunc = 'imagecreatefrombmp'; break; } if ($createFunc && function_exists($createFunc)) { $sourceImage = @$createFunc($filePath); if ($sourceImage === false) { //echo "DEBUG ERROR: 无法从文件创建 GD 资源: $filePath
"; return false; } // ------------------------------------------------------------------ // EXIF 旋转校正逻辑 需要安装php8-mod-exif // ------------------------------------------------------------------ //echo "DEBUG: 初始尺寸: ${sourceWidth}x${sourceHeight}。
"; if ($isJpeg && function_exists('exif_read_data')) { $exif = @exif_read_data($filePath); if (!empty($exif['Orientation'])) { $orientation = $exif['Orientation']; $rotate_angle = 0; //echo "DEBUG: 发现 EXIF Orientation 标签: $orientation。
"; switch ($orientation) { case 3: $rotate_angle = 180; break; case 6: $rotate_angle = -90; break; // 对应您的竖拍问题 case 8: $rotate_angle = 90; break; } if ($rotate_angle != 0) { // 使用 imagerotate 时,确保背景色为透明 (0) $sourceImage = imagerotate($sourceImage, $rotate_angle, 0); //echo "DEBUG: 应用旋转 $rotate_angle 度。
"; // 旋转后更新尺寸 $sourceWidth = imagesx($sourceImage); $sourceHeight = imagesy($sourceImage); //echo "DEBUG: 旋转后新尺寸: ${sourceWidth}x${sourceHeight}。
"; } } else { //echo "DEBUG: 未发现 EXIF Orientation 标签或值为 1 (正常)。
"; } } else { //echo "DEBUG: 非 JPEG 或缺少 Exif 扩展。
"; } // ------------------------------------------------------------------ // ------------------------------------------------------------------ // '裁剪并覆盖' (Object-fit: cover) 逻辑 // ------------------------------------------------------------------ $thumbSize = THUMB_TARGET_SIZE; $ratio = max($thumbSize / $sourceWidth, $thumbSize / $sourceHeight); $tempWidth = (int)($sourceWidth * $ratio); $tempHeight = (int)($sourceHeight * $ratio); $x_offset = (int)(($tempWidth - $thumbSize) / 2); $y_offset = (int)(($tempHeight - $thumbSize) / 2); $thumbImage = imagecreatetruecolor($thumbSize, $thumbSize); // 处理透明背景 if ($ext === 'png' || $ext === 'gif') { imagealphablending($thumbImage, false); imagesavealpha($thumbImage, true); $transparent = imagecolorallocatealpha($thumbImage, 255, 255, 255, 127); imagefilledrectangle($thumbImage, 0, 0, $thumbSize, $thumbSize, $transparent); } // 缩放并裁剪 $success = imagecopyresampled($thumbImage, $sourceImage, -$x_offset, -$y_offset, 0, 0, $tempWidth, $tempHeight, $sourceWidth, $sourceHeight ); // ------------------------------------------------------------------ // 5. 保存缩略图(移除 @ 符号,以便在失败时获得 PHP 警告) $saveFunc = null; switch ($ext) { case 'jpg': case 'jpeg': case 'jfif': $saveFunc = 'imagejpeg'; $quality = 80; break; case 'png': $saveFunc = 'imagepng'; $quality = 9; break; case 'gif': $saveFunc = 'imagegif'; $quality = null; break; case 'webp': $saveFunc = 'imagewebp'; $quality = 80; break; case 'bmp': $saveFunc = 'imagebmp'; $quality = null; break; default: $saveFunc = null; } $save_success = false; if ($success && $saveFunc && function_exists($saveFunc)) { // 明确调用保存函数,并在保存失败时输出调试信息 if ($quality !== null) { $save_success = $saveFunc($thumbImage, $thumbnailPath, $quality); } else { $save_success = $saveFunc($thumbImage, $thumbnailPath); } if (!$save_success) { //echo "DEBUG ERROR: 保存文件失败,可能是**写入权限不足**。请检查目录权限:
\$ chmod 775 $thumbnailsDir
"; } } // 清理资源 imagedestroy($sourceImage); imagedestroy($thumbImage); // 6. 返回结果 if ($save_success && file_exists($thumbnailPath)) { //echo "DEBUG: 缩略图生成成功: $thumbnailPath
"; return $thumbnailPath; } } //echo "DEBUG: 缩略图生成失败: $filePath
"; return false; } // ------------------------------------------------------------- // 【次要修改】 generateThumbnails 函数 (仅确保它调用了 createThumbnail) // ------------------------------------------------------------- function generateThumbnails($dir) { $images = []; // 检查是否是 "thumbnails" 目录,跳过不必要的处理 (保留) $isThumbnailsDir = (basename($dir) === 'thumbnails'); // 【注意】这里不再需要手动创建 thumbnails 目录 $files = scandir($dir); if ($files === false) { return $images; } // 迭代文件 foreach ($files as $file) { if ($file === '.' || $file === '..' || $file === 'thumbnails') { continue; // 忽略 '.' '..' 和 'thumbnails' 文件夹本身 } $filePath = $dir . '/' . $file; // 检查是否是支持的图片文件 if (is_file($filePath) && preg_match('/\.(jpg|jpeg|png|gif|jfif|bmp|webp)$/i', $file)) { // 获取原始尺寸用于 PhotoSwipe $size = @getimagesize($filePath); if ($size === false) { continue; } // 添加图片信息到结果数组 $fileName = basename($filePath); $images[] = ['src' => $fileName, 'width' => $size[0], 'height' => $size[1]]; // 如果不是 "thumbnails" 目录,生成缩略图 if (!$isThumbnailsDir) { // 【修改点 4】不再手动拼接 $thumbnailPath,直接调用 createThumbnail // 此时 createThumbnail 会在后台进行目录检查和文件生成 createThumbnail($filePath); } } } return $images; } //album form if (isset($_GET['photoalbum']) && !FM_READONLY) { fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path //get the allowed file extensions ?>

' . PHP_EOL; } ?>

: , ', $copy_files) ?>

:
/

 

Copying

Source path:
Destination folder:

Copy   Move   Cancel

/>
/>
/>
* .
  • :
  • :
  • :
  • :
  • :
  • :
  • :
  • :
  • : %
  • ' . lng('Image size') . ': ' . (isset($image_size[0]) ? $image_size[0] : '0') . ' x ' . (isset($image_size[1]) ? $image_size[1] : '0') . ''; } // Text info if ($is_text) { $is_utf8 = fm_is_utf8($content); if (function_exists('iconv')) { if (!$is_utf8) { $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); } } echo '
  • ' . lng('Charset') . ': ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
  • '; } ?>
'; } else if ($online_viewer == 'microsoft') { echo ''; } } elseif ($is_zip) { // ZIP content if ($filenames !== false) { echo ''; foreach ($filenames as $fn) { if ($fn['folder']) { echo '' . fm_enc($fn['name']) . '
'; } else { echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; } } echo '
'; } else { echo '

' . lng('Error while fetching archive info') . '

'; } } elseif ($is_image) { // Image content if (in_array($ext, array('gif', 'jpg', 'jpeg','jfif', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { echo '

'; } } elseif ($is_audio) { // Audio content echo '

'; } elseif ($is_video) { // Video content echo '
'; } elseif ($is_text) { if (FM_USE_HIGHLIGHTJS) { // highlight $hljs_classes = array( 'shtml' => 'xml', 'htaccess' => 'apache', 'phtml' => 'php', 'lock' => 'json', 'svg' => 'xml', ); $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { $hljs_class = 'nohighlight'; } $content = '
' . fm_enc($content) . '
'; } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { // php highlight $content = highlight_string($content, true); } else { $content = '
' . fm_enc($content) . '
'; } echo $content; } ?>
' . $file . ''; header('X-XSS-Protection:0'); fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); $file_path = $path . ($path=== '/' ? '' : '/') . $file; // normal editer $isNormalEditor = true; if (isset($_GET['env'])) { if ($_GET['env'] == "ace") { $isNormalEditor = false; } } // Save File if (isset($_POST['savedata'])) { $writedata = $_POST['savedata']; $fd = fopen($file_path, "w"); @fwrite($fd, $writedata); fclose($fd); fm_set_msg(lng('File Saved Successfully')); } $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); $mime_type = fm_get_mime_type($file_path); $filesize = filesize($file_path); $is_text = false; $content = ''; // for text if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { $is_text = true; $content = file_get_contents($file_path); } ?>
' . htmlspecialchars($content) . ''; echo ''; } elseif ($is_text) { echo '
' . htmlspecialchars($content) . '
'; } else { fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); } ?>

:

 

'?'); $group = array('name' => '?'); if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { try { $owner_id = fileowner($path . ($path=== '/' ? '' : '/') . $f); if ($owner_id != 0) { $owner_info = posix_getpwuid($owner_id); if ($owner_info) { $owner = $owner_info; } } $group_id = filegroup($path . ($path=== '/' ? '' : '/') . $f); $group_info = posix_getgrgid($group_id); if ($group_info) { $group = $group_info; } } catch (Exception $e) { error_log("exception:" . $e->getMessage()); } } ?> '?'); $group = array('name' => '?'); if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { try { $owner_id = fileowner($path . ($path=== '/' ? '' : '/') . $f); if ($owner_id != 0) { $owner_info = posix_getpwuid($owner_id); if ($owner_info) { $owner = $owner_info; } } $group_id = filegroup($path . ($path=== '/' ? '' : '/') . $f); $group_info = posix_getgrgid($group_id); if ($group_info) { $group = $group_info; } } catch (Exception $e) { error_log("exception:" . $e->getMessage()); } } ?>
..
>
' . readlink($path . ($path=== '/' ? '' : '/') . $f) . '' : '') ?>
">
>
' . readlink($path . ($path=== '/' ? '' : '/') . $f) . '' : '') ?>
">
' . fm_get_filesize($all_files_size) . '' ?> ' . $num_files . '' ?> ' . $num_folders . '' ?>
"; return; } echo "$external[$key]"; } /** * Verify CSRF TOKEN and remove after certified * @param string $token * @return bool */ function verifyToken($token) { if (hash_equals($_SESSION['token'], $token)) { return true; } return false; } /** * Delete file or folder (recursively) * @param string $path * @return bool */ function fm_rdelete($path) { if (is_link($path)) { return unlink($path); } elseif (is_dir($path)) { $objects = scandir($path); $ok = true; if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rdelete($path . ($path=== '/' ? '' : '/') . $file)) { $ok = false; } } } } return ($ok) ? rmdir($path) : false; } elseif (is_file($path)) { return unlink($path); } return false; } /** * Recursive chmod * @param string $path * @param int $filemode * @param int $dirmode * @return bool * @todo Will use in mass chmod */ function fm_rchmod($path, $filemode, $dirmode) { if (is_dir($path)) { if (!chmod($path, $dirmode)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rchmod($path . ($path=== '/' ? '' : '/') . $file, $filemode, $dirmode)) { return false; } } } } return true; } elseif (is_link($path)) { return true; } elseif (is_file($path)) { return chmod($path, $filemode); } return false; } /** * Check the file extension which is allowed or not * @param string $filename * @return bool */ function fm_is_valid_ext($filename) { $allowed = (FM_FILE_EXTENSION) ? explode(',', FM_FILE_EXTENSION) : false; $ext = pathinfo($filename, PATHINFO_EXTENSION); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; return ($isFileAllowed) ? true : false; } /** * Safely rename * @param string $old * @param string $new * @return bool|null */ function fm_rename($old, $new) { $isFileAllowed = fm_is_valid_ext($new); if (!is_dir($old)) { if (!$isFileAllowed) return false; } return (!file_exists($new) && file_exists($old)) ? rename($old, $new) : null; } /** * Copy file or folder (recursively). * @param string $path * @param string $dest * @param bool $upd Update files * @param bool $force Create folder with same names instead file * @return bool */ function fm_rcopy($path, $dest, $upd = true, $force = true) { if (!is_dir($path) && !is_file($path)) { return false; } if (is_dir($path)) { if (!fm_mkdir($dest, $force)) { return false; } $objects = array_diff(scandir($path), ['.', '..']); foreach ($objects as $file) { if (!fm_rcopy("$path/$file", "$dest/$file", $upd, $force)) { return false; } } return true; } // Handle file copying return fm_copy($path, $dest, $upd); } /** * Safely create folder * @param string $dir * @param bool $force * @return bool */ function fm_mkdir($dir, $force) { if (file_exists($dir)) { if (is_dir($dir)) { return $dir; } elseif (!$force) { return false; } unlink($dir); } return mkdir($dir, 0777, true); } /** * Safely copy file * @param string $f1 * @param string $f2 * @param bool $upd Indicates if file should be updated with new content * @return bool */ function fm_copy($f1, $f2, $upd) { $time1 = filemtime($f1); if (file_exists($f2)) { $time2 = filemtime($f2); if ($time2 >= $time1 && $upd) { return false; } } $ok = copy($f1, $f2); if ($ok) { touch($f2, $time1); } return $ok; } /** * Get mime type * @param string $file_path * @return mixed|string */ function fm_get_mime_type($file_path) { if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $file_path); finfo_close($finfo); return $mime; } elseif (function_exists('mime_content_type')) { return mime_content_type($file_path); } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { $file = escapeshellarg($file_path); $mime = shell_exec('file -bi ' . $file); return $mime; } else { return '--'; } } /** * HTTP Redirect * @param string $url * @param int $code */ function fm_redirect($url, $code = 302) { header('Location: ' . $url, true, $code); exit; } /** * Path traversal prevention and clean the url * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. * @param $path * @return string */ function get_absolute_path($path) { $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part) continue; if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } return implode(DIRECTORY_SEPARATOR, $absolutes); } /** * Clean path * @param string $path * @return string */ function fm_clean_path($path, $trim = true) { if ($path == '/') { return $path; } $path = $trim ? trim($path) : $path; $path = trim($path, '\\/'); $path = str_replace(array('../', '..\\'), '', $path); $path = get_absolute_path($path); if ($path == '..') { $path = ''; } return str_replace('\\', '/', $path); } /** * Get parent path * @param string $path * @return bool|string */ function fm_get_parent_path($path) { if ($path == '/') { return $path; } $path = fm_clean_path($path); if ($path != '') { $array = explode('/', $path); if (count($array) > 1) { $array = array_slice($array, 0, -1); return implode('/', $array); } return ''; } return false; } function fm_get_display_path($file_path) { global $path_display_mode, $root_path, $root_url; switch ($path_display_mode) { case 'relative': return array( 'label' => 'Path', 'path' => fm_enc(fm_convert_win(str_replace($root_path, '', $file_path))) ); case 'host': $relative_path = str_replace($root_path, '', $file_path); return array( 'label' => 'Host Path', 'path' => fm_enc(fm_convert_win('/' . $root_url . '/' . ltrim(str_replace('\\', '/', $relative_path), '/'))) ); case 'full': default: return array( 'label' => 'Full Path', 'path' => fm_enc(fm_convert_win($file_path)) ); } } /** * Check file is in exclude list * @param string $name The name of the file/folder * @param string $path The full path of the file/folder * @return bool */ function fm_is_exclude_items($name, $path) { $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); if (isset($exclude_items) and sizeof($exclude_items)) { unset($exclude_items); } $exclude_items = FM_EXCLUDE_ITEMS; if (version_compare(PHP_VERSION, '7.0.0', '<')) { $exclude_items = unserialize($exclude_items); } if (!in_array($name, $exclude_items) && !in_array("*.$ext", $exclude_items) && !in_array($path, $exclude_items)) { return true; } return false; } /** * get language translations from json file * @param int $tr * @return array */ function fm_get_translations($tr) { try { $content = @file_get_contents('translation.json'); if ($content !== FALSE) { $lng = json_decode($content, TRUE); global $lang_list; foreach ($lng["language"] as $key => $value) { $code = $value["code"]; $lang_list[$code] = $value["name"]; if ($tr) $tr[$code] = $value["translation"]; } return $tr; } } catch (Exception $e) { echo $e; } } /** * @param string $file * Recover all file sizes larger than > 2GB. * Works on php 32bits and 64bits and supports linux * @return int|string */ function fm_get_size($file) { static $iswin = null; static $isdarwin = null; static $exec_works = null; // Set static variables once if ($iswin === null) { $iswin = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; $isdarwin = strtoupper(PHP_OS) === 'DARWIN'; $exec_works = function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') === 'EXEC'; } // Attempt shell command if exec is available if ($exec_works) { $arg = escapeshellarg($file); $cmd = $iswin ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); @exec($cmd, $output); if (!empty($output) && ctype_digit($size = trim(implode("\n", $output)))) { return $size; } } // Attempt Windows COM interface for Windows systems if ($iswin && class_exists('COM')) { try { $fsobj = new COM('Scripting.FileSystemObject'); $f = $fsobj->GetFile(realpath($file)); if (ctype_digit($size = $f->Size)) { return $size; } } catch (Exception $e) { // COM failed, fallback to filesize } } // Default to PHP's filesize function return filesize($file); } /** * Get nice filesize * @param int $size * @return string */ function fm_get_filesize($size) { $size = (float) $size; $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $power = ($size > 0) ? floor(log($size, 1024)) : 0; $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); } /** * Get info about zip archive * @param string $path * @return array|bool */ function fm_get_zif_info($path, $ext) { if ($ext == 'zip' && function_exists('zip_open')) { $arch = @zip_open($path); if ($arch) { $filenames = array(); while ($zip_entry = @zip_read($arch)) { $zip_name = @zip_entry_name($zip_entry); $zip_folder = substr($zip_name, -1) == '/'; $filenames[] = array( 'name' => $zip_name, 'filesize' => @zip_entry_filesize($zip_entry), 'compressed_size' => @zip_entry_compressedsize($zip_entry), 'folder' => $zip_folder //'compression_method' => zip_entry_compressionmethod($zip_entry), ); } @zip_close($arch); return $filenames; } } elseif ($ext == 'tar' && class_exists('PharData')) { $archive = new PharData($path); $filenames = array(); foreach (new RecursiveIteratorIterator($archive) as $file) { $parent_info = $file->getPathInfo(); $zip_name = str_replace("phar://" . $path, '', $file->getPathName()); $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); $zip_folder = $parent_info->getFileName(); $zip_info = new SplFileInfo($file); $filenames[] = array( 'name' => $zip_name, 'filesize' => $zip_info->getSize(), 'compressed_size' => $file->getCompressedSize(), 'folder' => $zip_folder ); } return $filenames; } return false; } /** * Encode html entities * @param string $text * @return string */ function fm_enc($text) { return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); } /** * Prevent XSS attacks * @param string $text * @return string */ function fm_isvalid_filename($text) { return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; } /** * Save message in session * @param string $msg * @param string $status */ function fm_set_msg($msg, $status = 'ok') { $_SESSION[FM_SESSION_ID]['message'] = $msg; $_SESSION[FM_SESSION_ID]['status'] = $status; } /** * Check if string is in UTF-8 * @param string $string * @return int */ function fm_is_utf8($string) { return preg_match('//u', $string); } /** * Convert file name to UTF-8 in Windows * @param string $filename * @return string */ function fm_convert_win($filename) { if (FM_IS_WIN && function_exists('iconv')) { $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); } return $filename; } /** * @param $obj * @return array */ function fm_object_to_array($obj) { if (!is_object($obj) && !is_array($obj)) { return $obj; } if (is_object($obj)) { $obj = get_object_vars($obj); } return array_map('fm_object_to_array', $obj); } /** * Get CSS classname for file * @param string $path * @return string */ function fm_get_file_icon_class($path) { // get extension $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); switch ($ext) { case 'ico': case 'gif': case 'jpg': case 'jpeg': case 'jfif': case 'jpc': case 'jp2': case 'jpx': case 'xbm': case 'wbmp': case 'png': case 'bmp': case 'tif': case 'tiff': case 'webp': case 'avif': case 'svg': $img = 'fa fa-picture-o'; break; case 'passwd': case 'ftpquota': case 'sql': case 'js': case 'ts': case 'jsx': case 'tsx': case 'hbs': case 'json': case 'sh': case 'config': case 'twig': case 'tpl': case 'md': case 'gitignore': case 'c': case 'cpp': case 'cs': case 'py': case 'rs': case 'map': case 'lock': case 'dtd': case 'ps1': $img = 'fa fa-file-code-o'; break; case 'txt': case 'ini': case 'conf': case 'log': case 'htaccess': case 'yaml': case 'yml': case 'toml': case 'tmp': case 'top': case 'bot': case 'dat': case 'bak': case 'htpasswd': case 'pl': $img = 'fa fa-file-text-o'; break; case 'css': case 'less': case 'sass': case 'scss': $img = 'fa fa-css3'; break; case 'bz2': case 'tbz2': case 'tbz': case 'zip': case 'rar': case 'gz': case 'tgz': case 'tar': case '7z': case 'xz': case 'txz': case 'zst': case 'tzst': $img = 'fa fa-file-archive-o'; break; case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': $img = 'fa fa-code'; break; case 'htm': case 'html': case 'shtml': case 'xhtml': $img = 'fa fa-html5'; break; case 'xml': case 'xsl': $img = 'fa fa-file-excel-o'; break; case 'wav': case 'mp3': case 'mp2': case 'm4a': case 'aac': case 'ogg': case 'oga': case 'wma': case 'mka': case 'flac': case 'ac3': case 'tds': $img = 'fa fa-music'; break; case 'm3u': case 'm3u8': case 'pls': case 'cue': case 'xspf': $img = 'fa fa-headphones'; break; case 'avi': case 'mpg': case 'mpeg': case 'mp4': case 'm4v': case 'flv': case 'f4v': case 'ogm': case 'ogv': case 'mov': case 'mkv': case '3gp': case 'asf': case 'wmv': case 'webm': $img = 'fa fa-file-video-o'; break; case 'eml': case 'msg': $img = 'fa fa-envelope-o'; break; case 'xls': case 'xlsx': case 'ods': $img = 'fa fa-file-excel-o'; break; case 'csv': $img = 'fa fa-file-text-o'; break; case 'bak': case 'swp': $img = 'fa fa-clipboard'; break; case 'doc': case 'docx': case 'odt': $img = 'fa fa-file-word-o'; break; case 'ppt': case 'pptx': $img = 'fa fa-file-powerpoint-o'; break; case 'ttf': case 'ttc': case 'otf': case 'woff': case 'woff2': case 'eot': case 'fon': $img = 'fa fa-font'; break; case 'pdf': $img = 'fa fa-file-pdf-o'; break; case 'psd': case 'ai': case 'eps': case 'fla': case 'swf': $img = 'fa fa-file-image-o'; break; case 'exe': case 'msi': $img = 'fa fa-file-o'; break; case 'bat': $img = 'fa fa-terminal'; break; default: $img = 'fa fa-info-circle'; } return $img; } /** * Get image files extensions * @return array */ function fm_get_image_exts() { return array('ico', 'gif', 'jpg', 'jpeg','jfif', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); } /** * Get video files extensions * @return array */ function fm_get_video_exts() { return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); } /** * Get audio files extensions * @return array */ function fm_get_audio_exts() { return array('wav', 'mp3', 'ogg', 'm4a'); } /** * Get text file extensions * @return array */ function fm_get_text_exts() { return array( 'txt', 'css', 'ini', 'conf', 'log', 'htaccess', 'passwd', 'ftpquota', 'sql', 'js', 'ts', 'jsx', 'tsx', 'mjs', 'json', 'sh', 'config', 'php', 'php4', 'php5', 'phps', 'phtml', 'htm', 'html', 'shtml', 'xhtml', 'xml', 'xsl', 'm3u', 'm3u8', 'pls', 'cue', 'bash', 'vue', 'eml', 'msg', 'csv', 'bat', 'twig', 'tpl', 'md', 'gitignore', 'less', 'sass', 'scss', 'c', 'cpp', 'cs', 'py', 'go', 'zsh', 'swift', 'map', 'lock', 'dtd', 'svg', 'asp', 'aspx', 'asx', 'asmx', 'ashx', 'jsp', 'jspx', 'cgi', 'dockerfile', 'ruby', 'yml', 'yaml', 'toml', 'vhost', 'scpt', 'applescript', 'csx', 'cshtml', 'c++', 'coffee', 'cfm', 'rb', 'graphql', 'mustache', 'jinja', 'http', 'handlebars', 'java', 'es', 'es6', 'markdown', 'wiki', 'tmp', 'top', 'bot', 'dat', 'bak', 'htpasswd', 'pl', 'ps1' ); } /** * Get mime types of text files * @return array */ function fm_get_text_mimes() { return array( 'application/xml', 'application/javascript', 'application/x-javascript', 'image/svg+xml', 'message/rfc822', 'application/json', ); } /** * Get file names of text files w/o extensions * @return array */ function fm_get_text_names() { return array( 'license', 'readme', 'authors', 'contributors', 'changelog', ); } /** * Get online docs viewer supported files extensions * @return array */ function fm_get_onlineViewer_exts() { return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); } /** * It returns the mime type of a file based on its extension. * @param extension The file extension of the file you want to get the mime type for. * @return string|string[] The mime type of the file. */ function fm_get_file_mimes($extension) { $fileTypes['swf'] = 'application/x-shockwave-flash'; $fileTypes['pdf'] = 'application/pdf'; $fileTypes['exe'] = 'application/octet-stream'; $fileTypes['zip'] = 'application/zip'; $fileTypes['doc'] = 'application/msword'; $fileTypes['xls'] = 'application/vnd.ms-excel'; $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; $fileTypes['gif'] = 'image/gif'; $fileTypes['png'] = 'image/png'; $fileTypes['jpeg'] = 'image/jpg'; $fileTypes['jfif'] = 'image/jfif'; $fileTypes['jpg'] = 'image/jpg'; $fileTypes['webp'] = 'image/webp'; $fileTypes['avif'] = 'image/avif'; $fileTypes['rar'] = 'application/rar'; $fileTypes['ra'] = 'audio/x-pn-realaudio'; $fileTypes['ram'] = 'audio/x-pn-realaudio'; $fileTypes['ogg'] = 'audio/x-pn-realaudio'; $fileTypes['wav'] = 'video/x-msvideo'; $fileTypes['wmv'] = 'video/x-msvideo'; $fileTypes['avi'] = 'video/x-msvideo'; $fileTypes['asf'] = 'video/x-msvideo'; $fileTypes['divx'] = 'video/x-msvideo'; $fileTypes['mp3'] = 'audio/mpeg'; $fileTypes['mp4'] = 'audio/mpeg'; $fileTypes['mpeg'] = 'video/mpeg'; $fileTypes['mpg'] = 'video/mpeg'; $fileTypes['mpe'] = 'video/mpeg'; $fileTypes['mov'] = 'video/quicktime'; $fileTypes['swf'] = 'video/quicktime'; $fileTypes['3gp'] = 'video/quicktime'; $fileTypes['m4a'] = 'video/quicktime'; $fileTypes['aac'] = 'video/quicktime'; $fileTypes['m3u'] = 'video/quicktime'; $fileTypes['php'] = ['application/x-php']; $fileTypes['html'] = ['text/html']; $fileTypes['txt'] = ['text/plain']; //Unknown mime-types should be 'application/octet-stream' if (empty($fileTypes[$extension])) { $fileTypes[$extension] = ['application/octet-stream']; } return $fileTypes[$extension]; } /** * This function scans the files and folder recursively, and return matching files * @param string $dir * @param string $filter * @return array|null */ function scan($dir = '', $filter = '') { $path = FM_ROOT_PATH . (FM_ROOT_PATH=== '/' ? '' : '/') . $dir; if ($path) { $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); $files = array(); foreach ($rii as $file) { if (!$file->isDir()) { $fileName = $file->getFilename(); $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); $files[] = array( "name" => $fileName, "type" => "file", "path" => $location, ); } } return $files; } } /** * Parameters: downloadFile(File Location, File Name, * max speed, is streaming * If streaming - videos will show as videos, images as images * instead of download prompt * https://stackoverflow.com/a/13821992/1164642 */ function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) { if (connection_status() != 0) return (false); $extension = pathinfo($fileName, PATHINFO_EXTENSION); $contentType = fm_get_file_mimes($extension); if (is_array($contentType)) { $contentType = implode(' ', $contentType); } $size = filesize($fileLocation); if ($size == 0) { fm_set_msg(lng('Zero byte file! Aborting download'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } @ini_set('magic_quotes_runtime', 0); $fp = fopen("$fileLocation", "rb"); if ($fp === false) { fm_set_msg(lng('Cannot open file! Aborting download'), 'error'); $FM_PATH = FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } // headers header('Content-Description: File Transfer'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header("Content-Transfer-Encoding: binary"); header("Content-Type: $contentType"); $contentDisposition = 'attachment'; if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } else { header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } header("Accept-Ranges: bytes"); $range = 0; if (isset($_SERVER['HTTP_RANGE'])) { list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); str_replace($range, "-", $range); $size2 = $size - 1; $new_length = $size - $range; header("HTTP/1.1 206 Partial Content"); header("Content-Length: $new_length"); header("Content-Range: bytes $range$size2/$size"); } else { $size2 = $size - 1; header("Content-Range: bytes 0-$size2/$size"); header("Content-Length: " . $size); } $fileLocation = realpath($fileLocation); while (ob_get_level()) ob_end_clean(); readfile($fileLocation); fclose($fp); return ((connection_status() == 0) and !connection_aborted()); } /** * Class to work with zip files (using ZipArchive) */ class FM_Zipper { private $zip; public function __construct() { $this->zip = new ZipArchive(); } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $res = $this->zip->open($filename, ZipArchive::CREATE); if ($res !== true) { return false; } if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { $this->zip->close(); return false; } } $this->zip->close(); return true; } else { if ($this->addFileOrDir($files)) { $this->zip->close(); return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->zip->open($filename); if ($res !== true) { return false; } if ($this->zip->extractTo($path)) { $this->zip->close(); return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { return $this->zip->addFile($filename); } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { if (!$this->zip->addEmptyDir($path)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . ($path=== '/' ? '' : '/') . $file)) { if (!$this->addDir($path . ($path=== '/' ? '' : '/') . $file)) { return false; } } elseif (is_file($path . ($path=== '/' ? '' : '/') . $file)) { if (!$this->zip->addFile($path . ($path=== '/' ? '' : '/') . $file)) { return false; } } } } return true; } return false; } } /** * Class to work with Tar files (using PharData) */ class FM_Zipper_Tar { private $tar; public function __construct() { $this->tar = null; } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $this->tar = new PharData($filename); if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { return false; } } return true; } else { if ($this->addFileOrDir($files)) { return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->tar->open($filename); if ($res !== true) { return false; } if ($this->tar->extractTo($path)) { return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { try { $this->tar->addFile($filename); return true; } catch (Exception $e) { return false; } } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . ($path=== '/' ? '' : '/') . $file)) { if (!$this->addDir($path . ($path=== '/' ? '' : '/') . $file)) { return false; } } elseif (is_file($path . ($path=== '/' ? '' : '/') . $file)) { try { $this->tar->addFile($path . ($path=== '/' ? '' : '/') . $file); } catch (Exception $e) { return false; } } } } return true; } return false; } } /** * Save Configuration */ class FM_Config { var $data; function __construct() { global $root_path, $root_url, $CONFIG; $fm_url = $root_url . $_SERVER["PHP_SELF"]; $this->data = array( 'lang' => 'en', 'error_reporting' => true, 'show_hidden' => true ); $data = false; if (strlen($CONFIG)) { $data = fm_object_to_array(json_decode($CONFIG)); } else { $msg = 'Tiny File Manager
Error: Cannot load configuration'; if (substr($fm_url, -1) == '/') { $fm_url = rtrim($fm_url, '/'); $msg .= '
'; $msg .= '
Seems like you have a trailing slash on the URL.'; $msg .= '
Try this link: ' . $fm_url . ''; } die($msg); } if (is_array($data) && count($data)) $this->data = $data; else $this->save(); } function save() { global $config_file; $fm_file = is_readable($config_file) ? $config_file : __FILE__; $var_name = '$CONFIG'; $var_value = var_export(json_encode($this->data), true); $config_string = " ' . $_SESSION[FM_SESSION_ID]['message'] . '

'; unset($_SESSION[FM_SESSION_ID]['message']); unset($_SESSION[FM_SESSION_ID]['status']); } } /** * Show page header in Login Form */ function fm_show_header_login() { header("Content-Type: text/html; charset=utf-8"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); global $favicon_path; ?> "> '; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
'; } ?> <?php echo fm_enc(APP_TITLE) ?> | <?php echo (isset($_GET['view']) ? $_GET['view'] : ((isset($_GET['edit'])) ? $_GET['edit'] : "H3K")); ?> ">