From 82d36f2dc40cab9e867d3848537bb44c8b39d1dd Mon Sep 17 00:00:00 2001
From: imcraftsman " . 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);
@@ -460,12 +501,6 @@ defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format);
unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style);
/*************************** ACTIONS ***************************/
-
-// file proxy
-if (isset($_GET['proxy_file'])) {
- header('Access-Control-Allow-Origin: *');
- header('Access-Control-Allow-Methods: GET');
-
function sanitizePath($path) {
if (substr($path, 0, 1) !== '/') {
die('Invalid file path.');
@@ -476,6 +511,72 @@ if (isset($_GET['proxy_file'])) {
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);
@@ -483,9 +584,9 @@ if (isset($_GET['proxy_file'])) {
if ($filePath === false || !file_exists($filePath)) {
http_response_code(404);
die('File not found or inaccessible.');
- }
+ }
- if (is_dir($filePath)) {
+ if (is_dir($filePath)) {
// if it is dir,list the content
$fileList = getFileList($filePath);
echo generateDirectoryListing($filePath, $fileList);
@@ -495,42 +596,111 @@ if (isset($_GET['proxy_file'])) {
http_response_code(403);
die("File is not readable.");
}
- $mimeType = mime_content_type($filePath);
+
+ // --- 增强 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");
+ 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'])) {
- list(, $range) = explode("=", $_SERVER['HTTP_RANGE'], 2);
- list($start, $end) = explode("-", $range);
- $start = intval($start);
- $end = ($end === '') ? $fileSize - 1 : intval($end);
+
+ 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) {
- header("HTTP/1.1 416 Range Not Satisfiable");
+ 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;
- $file = fopen($filePath, 'rb');
- fseek($file, $start);
-
+
+ // 设置 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) {
- echo fread($file, min(1024 * 16, $end - $p + 1));
+ $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;
- } else {
+ }
+ // --- 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");
- readfile($filePath);
+ 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
@@ -583,7 +753,7 @@ if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_
// get current path
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
// check path
if (!is_dir($path)) {
@@ -592,13 +762,13 @@ if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_
$file = $_GET['edit'];
$file = fm_clean_path($file);
$file = str_replace('/', '', $file);
- if ($file == '' || !is_file($path . '/' . $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 . '/' . $file;
+ $file_path = $path . ($path === '/' ? '' : '/') . $file;
$writedata = $_POST['content'];
$fd = fopen($file_path, "w");
@@ -615,6 +785,7 @@ if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_
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}/";
@@ -688,7 +859,7 @@ if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_
if (isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
function event_callback($message)
@@ -781,10 +952,10 @@ if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) {
if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
- $is_dir = is_dir($path . '/' . $del);
- if (fm_rdelete($path . '/' . $del)) {
+ $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 {
@@ -801,16 +972,16 @@ if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) {
// Create a new file/folder
if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) {
$type = urldecode($_POST['newfile']);
- $new = str_replace('/', '', fm_clean_path(strip_tags($_POST['newfilename'])));
+ $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 .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
if ($type == "file") {
- if (!file_exists($path . '/' . $new)) {
+ if (!file_exists($path . ($path === '/' ? '' : '/') . $new)) {
if (fm_is_valid_ext($new)) {
- @fopen($path . '/' . $new, 'w') or die('Cannot open file: ' . $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');
@@ -819,9 +990,9 @@ if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READ
fm_set_msg(sprintf(lng('File') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert');
}
} else {
- if (fm_mkdir($path . '/' . $new, false) === true) {
+ if (fm_mkdir($path . ($path === '/' ? '' : '/') . $new, false) === true) {
fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('Created'), $new));
- } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $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');
@@ -846,13 +1017,13 @@ if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) {
fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH));
}
// abs path from
- $from = FM_ROOT_PATH . '/' . $copy;
+ $from = FM_ROOT_PATH . (FM_ROOT_PATH === '/' ? '' : '/') . $copy;
// abs path to
$dest = FM_ROOT_PATH;
if (FM_PATH != '') {
- $dest .= '/' . FM_PATH;
+ $dest .= ($dest === '/' ? '' : '/') . FM_PATH;
}
- $dest .= '/' . basename($from);
+ $dest .= ($dest === '/' ? '' : '/') . basename($from);
// move?
$move = isset($_GET['move']);
$move = fm_clean_path(urldecode($move));
@@ -916,13 +1087,13 @@ if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token'])
// from
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . 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 .= '/' . $copy_to;
+ $copy_to_path .= ($path === '/' ? '' : '/') . $copy_to;
}
if ($path == $copy_to_path) {
fm_set_msg(lng('Paths must be not equal'), 'alert');
@@ -946,9 +1117,9 @@ if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token'])
if ($f != '') {
$f = fm_clean_path($f);
// abs path from
- $from = $path . '/' . $f;
+ $from = $path . ($path === '/' ? '' : '/') . $f;
// abs path to
- $dest = $copy_to_path . '/' . $f;
+ $dest = $copy_to_path . ($path === '/' ? '' : '/') . $f;
// do
if ($move) {
$rename = fm_rename($from, $dest);
@@ -992,11 +1163,11 @@ if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_RE
// path
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
// rename
if (fm_isvalid_filename($new) && $old != '' && $new != '') {
- if (fm_rename($path . '/' . $old, $path . '/' . $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');
@@ -1024,18 +1195,18 @@ if (isset($_GET['dl'], $_POST['token'])) {
// Define the file path
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
// Check if the file exists and is valid
- if ($dl != '' && is_file($path . '/' . $dl)) {
+ 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 . '/' . $dl, $dl, 1024); // Download with a buffer size of 1024 bytes
+ 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
@@ -1067,7 +1238,7 @@ if (!empty($_FILES) && !FM_READONLY) {
$path = FM_ROOT_PATH;
$ds = DIRECTORY_SEPARATOR;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
$errors = 0;
@@ -1094,7 +1265,7 @@ if (!empty($_FILES) && !FM_READONLY) {
$targetPath = $path . $ds;
if (is_writable($targetPath)) {
- $fullPath = $path . '/' . $fullPathInput;
+ $fullPath = $path . ($path === '/' ? '' : '/') . $fullPathInput;
$folder = substr($fullPath, 0, strrpos($fullPath, "/"));
if (!is_dir($folder)) {
@@ -1152,7 +1323,7 @@ if (!empty($_FILES) && !FM_READONLY) {
if ($chunkIndex == $chunkTotal - 1) {
if (file_exists($fullPath)) {
$ext_1 = $ext ? '.' . $ext : '';
- $fullPathTarget = $path . '/' . basename($fullPathInput, $ext_1) . '_' . date('ymdHis') . $ext_1;
+ $fullPathTarget = $path . ($path === '/' ? '' : '/') . basename($fullPathInput, $ext_1) . '_' . date('ymdHis') . $ext_1;
} else {
$fullPathTarget = $fullPath;
}
@@ -1198,7 +1369,7 @@ if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
$errors = 0;
@@ -1206,7 +1377,7 @@ if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) {
if (is_array($files) && count($files)) {
foreach ($files as $f) {
if ($f != '') {
- $new_path = $path . '/' . $f;
+ $new_path = $path . ($path === '/' ? '' : '/') . $f;
if (!fm_rdelete($new_path)) {
$errors++;
}
@@ -1235,7 +1406,7 @@ if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_
$path = FM_ROOT_PATH;
$ext = 'zip';
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
//set pack type
@@ -1303,11 +1474,11 @@ if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
- if ($unzip != '' && is_file($path . '/' . $unzip)) {
- $zip_path = $path . '/' . $unzip;
+ if ($unzip != '' && is_file($path . ($path === '/' ? '' : '/') . $unzip)) {
+ $zip_path = $path . ($path === '/' ? '' : '/') . $unzip;
$ext = pathinfo($zip_path, PATHINFO_EXTENSION);
$isValid = true;
} else {
@@ -1325,8 +1496,8 @@ if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) {
$tofolder = '';
if (isset($_POST['tofolder'])) {
$tofolder = pathinfo($zip_path, PATHINFO_FILENAME);
- if (fm_mkdir($path . '/' . $tofolder, true)) {
- $path .= '/' . $tofolder;
+ if (fm_mkdir($path . ($path === '/' ? '' : '/') . $tofolder, true)) {
+ $path .= ($path === '/' ? '' : '/') . $tofolder;
}
}
@@ -1368,13 +1539,13 @@ if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) {
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
$file = $_POST['chmod'];
$file = fm_clean_path($file);
$file = str_replace('/', '', $file);
- if ($file == '' || (!is_file($path . '/' . $file) && !is_dir($path . '/' . $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));
@@ -1409,7 +1580,7 @@ if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) {
$mode |= 0001;
}
- if (@chmod($path . '/' . $file, $mode)) {
+ if (@chmod($path . ($path === '/' ? '' : '/') . $file, $mode)) {
fm_set_msg(lng('Permissions changed'));
} else {
fm_set_msg(lng('Permissions not changed'), 'error');
@@ -1424,7 +1595,8 @@ if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) {
// get current path
$path = FM_ROOT_PATH;
if (FM_PATH != '') {
- $path .= '/' . FM_PATH;
+ //$path .= '/' . FM_PATH;
+ $path .= ($path === '/' ? '' : '/') . FM_PATH;
}
// check path
@@ -1435,25 +1607,45 @@ if (!is_dir($path)) {
// 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];
-if (is_array($objects) && fm_is_exclude_items($current_path, $path)) {
+
+// 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 . '/' . $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)) {
@@ -1566,154 +1758,248 @@ if (isset($_GET['upload']) && !FM_READONLY) {
fm_show_footer();
exit;
}
+const THUMB_TARGET_SIZE = 120;
-//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
-
+// -------------------------------------------------------------
+// 【新常量】定义统一的目标缩略图尺寸
+// -------------------------------------------------------------
/**
* create Thumbnail
- *
- * @param string $filePath Original image path
- * @param string $thumbnailPath Thumbnail save path
- * @param array $size Original image size
+ * * @param string $filePath Original image path
+ * @return string|false 成功时返回缩略图的完整路径,失败时返回 false。
*/
-function createThumbnail($filePath, $thumbnailPath, $size) {
- // Check if thumbnail already exists
+function createThumbnail($filePath) {
+$dirName = dirname($filePath);
+ $fileName = basename($filePath);
+ $thumbnailsDir = $dirName . '/thumbnails';
+ $thumbnailPath = $thumbnailsDir . '/' . $fileName; // 缩略图完整路径
+
+ //echo "DEBUG: 尝试生成缩略图: $fileName, 目标路径: $thumbnailPath
";
+
+ // 1. 判断同名缩略图文件是否存在
if (file_exists($thumbnailPath)) {
- return;
+ //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;
}
- // Determine which imagecreatefrom function to use
+ $sourceWidth = $size[0];
+ $sourceHeight = $size[1];
+
+
+ // 4. 确定图片创建函数和扩展名
$createFunc = null;
- switch (strtolower(pathinfo($filePath, PATHINFO_EXTENSION))) {
+ $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;
+ 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) {
- return; // Skip if image cannot be loaded
+ //echo "DEBUG ERROR: 无法从文件创建 GD 资源: $filePath
";
+ return false;
}
- // Create thumbnail
- $thumbWidth = 110;
- $thumbHeight = 90;
- $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);
+ // ------------------------------------------------------------------
+ // EXIF 旋转校正逻辑 需要安装php8-mod-exif
+ // ------------------------------------------------------------------
+ //echo "DEBUG: 初始尺寸: ${sourceWidth}x${sourceHeight}。
";
- // Handle transparent background
- imagealphablending($thumbImage, false);
- imagesavealpha($thumbImage, true);
- $transparent = imagecolorallocatealpha($thumbImage, 255, 255, 255, 127);
- imagefilledrectangle($thumbImage, 0, 0, $thumbWidth, $thumbHeight, $transparent);
+ 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 度。
";
- // Scale the image
- if (!imagecopyresampled($thumbImage, $sourceImage, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $size[0], $size[1])) {
- imagedestroy($sourceImage);
- imagedestroy($thumbImage);
- return;
+ // 旋转后更新尺寸
+ $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);
}
- // Save the thumbnail
+ // 缩放并裁剪
+ $success = imagecopyresampled($thumbImage, $sourceImage,
+ -$x_offset, -$y_offset,
+ 0, 0,
+ $tempWidth, $tempHeight,
+ $sourceWidth, $sourceHeight
+ );
+ // ------------------------------------------------------------------
+
+ // 5. 保存缩略图(移除 @ 符号,以便在失败时获得 PHP 警告)
$saveFunc = null;
- switch (strtolower(pathinfo($filePath, PATHINFO_EXTENSION))) {
+ switch ($ext) {
case 'jpg':
case 'jpeg':
case 'jfif':
$saveFunc = 'imagejpeg';
+ $quality = 80;
break;
- case 'png':
- $saveFunc = 'imagepng';
- break;
- case 'gif':
- $saveFunc = 'imagegif';
- break;
- case 'webp':
- $saveFunc = 'imagewebp';
- break;
- case 'bmp':
- $saveFunc = 'imagebmp';
- 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;
}
- if ($saveFunc && function_exists($saveFunc)) {
- $saveFunc($thumbImage, $thumbnailPath);
+ $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
";
+ }
}
-
- // Clean up resources
+
+ // 清理资源
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 = [];
- // Check if the directory is "thumbnails", skip unnecessary processing
+ // 检查是否是 "thumbnails" 目录,跳过不必要的处理 (保留)
$isThumbnailsDir = (basename($dir) === 'thumbnails');
+
+ // 【注意】这里不再需要手动创建 thumbnails 目录
- // Get all files in the directory
$files = scandir($dir);
if ($files === false) {
return $images;
}
- // If not "thumbnails", create a thumbnails directory
- if (!$isThumbnailsDir) {
- $thumbnailsDir = $dir . '/thumbnails';
- if (!is_dir($thumbnailsDir) && !mkdir($thumbnailsDir, 0755, true)) {
- echo "Error: Unable to create thumbnails directory '$thumbnailsDir'
";
- return false;
- }
- }
-
- // Iterate over the files in the directory
+ // 迭代文件
foreach ($files as $file) {
- if ($file === '.' || $file === '..') {
- continue; // Ignore current and parent directories
+ if ($file === '.' || $file === '..' || $file === 'thumbnails') {
+ continue; // 忽略 '.' '..' 和 'thumbnails' 文件夹本身
}
$filePath = $dir . '/' . $file;
- // Check if it's a supported image file
+ // 检查是否是支持的图片文件
if (is_file($filePath) && preg_match('/\.(jpg|jpeg|png|gif|jfif|bmp|webp)$/i', $file)) {
+
+ // 获取原始尺寸用于 PhotoSwipe
$size = @getimagesize($filePath);
if ($size === false) {
- continue; // Skip if image info cannot be obtained
+ continue;
}
- // Add image info to the results array
+ // 添加图片信息到结果数组
$fileName = basename($filePath);
$images[] = ['src' => $fileName, 'width' => $size[0], 'height' => $size[1]];
- // If not "thumbnails" directory, create thumbnails
+ // 如果不是 "thumbnails" 目录,生成缩略图
if (!$isThumbnailsDir) {
- $thumbnailPath = $thumbnailsDir . '/' . $fileName;
- createThumbnail($filePath, $thumbnailPath, $size);
+ // 【修改点 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
?>
@@ -1724,31 +2010,124 @@ function generateThumbnails($dir) {