Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 115 additions & 37 deletions upload/web/picupload_action.php
Original file line number Diff line number Diff line change
@@ -1,44 +1,122 @@
<?php

// 允许上传的图片后缀
$allowedExts = array("jpeg", "jpg", "png", "gif", "webp", "JPG", "PNG", "JPEG", "WEBP", "GIF", "bmp", "BMP", "tif", "tiff", "TIF", "TIFF", "ICO");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/tiff")
|| ($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png")
|| ($_FILES["file"]["type"] == "image/bmp")
|| ($_FILES["file"]["type"] == "image/webp")
|| ($_FILES["file"]["type"] == "image/x-icon"))
&& ($_FILES["file"]["size"] < 3072000) // 小于 3MB
&& in_array($extension, $allowedExts))
const UPLOAD_DIR = __DIR__ . '/../web/picupload/';
const MAX_FILE_SIZE_BYTES = 3 * 1024 * 1024; // 3 MB

const ALLOWED_MIME_TYPES = [
'image/jpeg',
'image/pjpeg', // Common for IE
'image/jpg',
'image/png',
'image/x-png', // Common for IE
'image/gif',
'image/webp',
'image/bmp',
'image/tiff',
'image/x-icon' // For .ico files
];

const ALLOWED_EXTENSIONS = [
'jpeg', 'jpg', 'png', 'gif', 'webp', 'bmp', 'tif', 'tiff', 'ico'
];

function handleUploadError(string $userMessage, string $logMessage = ''): void
{
if ($_FILES["file"]["error"] > 0)
{
echo "错误:: " . $_FILES["file"]["error"] . "<br>";
if (!empty($logMessage)) {
error_log("Upload Error: " . $logMessage);
}
else
{
$picpos = "picupload/" .mt_rand(100000000,999999999).".".$extension/*. $_FILES["file"]["name"]*/;
move_uploaded_file($_FILES["file"]["tmp_name"], $picpos);
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
//echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
//$resfile = "./picupload/tmp/_uploadres_tmp".mt_rand(1000,9999).".txt";
//echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"];
$cmd="/usr/bin/python /www/wwwroot/landchat/web/web_picupload.py /www/wwwroot/landchat/web/".$picpos;
echo '<div style="align:center;"><img src="https://img.zcool.cn/community/012b3c599276cc0000002129ebff53.gif"></div>';
echo '<script>if(typeof(Storage) !== "undefined") {window.location.replace(\'./picupload_res.php?cr=\'+localStorage.currentcr+\'&c='.$cmd.'\');}else{alert(\'不支持本地存储或没有打开过LandChat主页,无法上传!\')}</script>';
//echo "文件存储位置:".$picpos."<br>";
//echo "上传结果:<br>".$urlrsp."<br>";
echo "<h3>上传失败!</h3><p>$userMessage</p>";
exit;
}

// Initial file upload check
if (!isset($_FILES['file']) || $_FILES['file']['error'] === UPLOAD_ERR_NO_FILE) {
handleUploadError("未选择文件。", "No file uploaded by user.");
}

// Check for common PHP upload errors
if ($_FILES['file']['error'] > 0) {
$phpErrorMessage = match ($_FILES['file']['error']) {
UPLOAD_ERR_INI_SIZE => "文件大小超出服务器配置限制。",
UPLOAD_ERR_FORM_SIZE => "文件大小超出表单限制。",
UPLOAD_ERR_PARTIAL => "文件部分上传。",
UPLOAD_ERR_NO_TMP_DIR => "服务器临时文件夹缺失。",
UPLOAD_ERR_CANT_WRITE => "文件写入磁盘失败。",
UPLOAD_ERR_EXTENSION => "PHP扩展阻止文件上传。",
default => "发生未知上传错误。"
};
handleUploadError("上传失败: " . $phpErrorMessage, "PHP upload error code: " . $_FILES['file']['error'] . " for " . $_FILES['file']['name']);
}

// File size validation
if ($_FILES['file']['size'] > MAX_FILE_SIZE_BYTES) {
handleUploadError(
"文件大小超出 " . (MAX_FILE_SIZE_BYTES / 1024 / 1024) . "MB 限制。",
"File size " . $_FILES['file']['size'] . " bytes exceeds " . MAX_FILE_SIZE_BYTES . " bytes."
);
}

// File extension validation
$file_extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (!in_array($file_extension, ALLOWED_EXTENSIONS)) {
handleUploadError(
"非法的文件格式。允许的后缀有: " . implode(', ', ALLOWED_EXTENSIONS) . "。",
"Invalid file extension: " . $file_extension . " for " . $_FILES['file']['name']
);
}

// This checks the actual content of the file, not just the client-provided type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if ($finfo === false) {
handleUploadError("服务器无法验证文件类型。", "Failed to open fileinfo database.");
}
$real_mime_type = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);

if (!in_array($real_mime_type, ALLOWED_MIME_TYPES)) {
handleUploadError(
"文件类型不被允许。",
"Invalid actual MIME type: " . $real_mime_type . " for " . $_FILES['file']['name']
);
}

// Ensure the target directory exists and is writable.
if (!is_dir(UPLOAD_DIR)) {
if (!mkdir(UPLOAD_DIR, 0755, true)) {
handleUploadError("无法创建上传目录。", "Failed to create upload directory: " . UPLOAD_DIR);
}
}
else
{
echo "非法的文件格式或文件大于3MB限制";

// Double-check if the directory is actually writable by the web server process
if (!is_writable(UPLOAD_DIR)) {
handleUploadError("上传目录不可写。", "Upload directory not writable: " . UPLOAD_DIR);
}
?>

// Generate a unique filename using a random number and the validated extension
$unique_filename = mt_rand(100000000, 999999999) . '.' . $file_extension;
$destination_path = UPLOAD_DIR . $unique_filename;

// Move the uploaded file from its temporary location to the final destination
if (!move_uploaded_file($_FILES['file']['tmp_name'], $destination_path)) {
handleUploadError(
"无法保存上传文件。",
"Failed to move uploaded file from " . $_FILES['file']['tmp_name'] . " to " . $destination_path
);
}

// Display user-friendly success messages
echo "上传文件名: " . htmlspecialchars($_FILES["file"]["name"]) . "<br>";
echo "文件大小: " . round($_FILES["file"]["size"] / 1024, 2) . " kB<br>"; // Display size in KB, rounded

// Show animation to indicate processing
echo '<div style="text-align:center;"><img src="https://img.zcool.cn/community/012b3c599276cc0000002129ebff53.gif" alt="Uploading..."></div>';

echo '<script>
if (typeof(Storage) !== "undefined") {
var currentChatRoom = localStorage.currentcr || "";
window.location.replace("./picupload_res.php?cr=" + encodeURIComponent(currentChatRoom) + "&img=' . urlencode($unique_filename) . '");
} else {
alert("不支持本地存储或没有打开过LandChat主页,无法上传!");
}
</script>';
?>
35 changes: 29 additions & 6 deletions upload/web/picupload_res.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
<?php
$rsp=shell_exec($_REQUEST['c']);

if (strncmp($rsp, 'error', 5)==0) {
echo "<h3>上传失败!</h3>";
echo "<p>请向管理员求助,并附上调试信息:<b>【1. ".$_REQUEST['c']." 2. ".$rsp."】</b></p>";
function displayUploadError(string $message): void
{
echo "<h3>上传失败!</h3><p>$message</p>";
exit;
} else {
//echo "上传成功,正在把图片发送至聊天......";
}

if (!isset($_GET['img'])) {
displayUploadError("未指定图片文件。");
}

// Sanitize input
$filename = basename(filter_var($_GET['img'], FILTER_SANITIZE_URL));
$upload_base_dir = realpath(__DIR__ . '/../web/picupload/');
$filepath = realpath($upload_base_dir . '/' . $filename);

// Ensure the file exists AND its real path is strictly within the allowed upload directory.
if ($filepath === false || strpos($filepath, $upload_base_dir) !== 0 || !file_exists($filepath)) {
displayUploadError("非法的图片文件或文件不存在。");
}

// Build the command safely
$python_cmd = escapeshellcmd('/usr/bin/python');
$script_arg = escapeshellarg(__DIR__ . '/web_picupload.py');
$file_arg = escapeshellarg($filepath);

$cmd = "$python_cmd $script_arg $file_arg";
$rsp = shell_exec($cmd);
if ($rsp === null) {
displayUploadError("执行脚本时发生错误。");
}

//上传
require('./../config.php');
date_default_timezone_set('PRC');
Expand Down