Skip to content

Commit 927c139

Browse files
authored
Update api.php
1 parent f173f51 commit 927c139

File tree

1 file changed

+52
-7
lines changed

1 file changed

+52
-7
lines changed

api/api.php

+52-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
<?php
22

33
class ImageUploader {
4-
private const ALLOWED_TYPES = ["image/gif", "image/jpeg", "image/jpg", "image/pjpeg", "image/x-png", "image/png"];
4+
private const ALLOWED_EXTENSIONS = ['gif', 'jpeg', 'jpg', 'png'];
55
private const MAX_SIZE = 5 * 1024 * 1024; // 5MB
6+
private const MAX_RESOLUTION = 25 * 1024 * 1024; // 25MB
67
private const DOMAINS = ['img.pub', 'pic.ym.today'];
78
private const UPLOAD_URL = 'https://telegra.ph/upload';
89

10+
// 文件头部的魔术数字
11+
private const MAGIC_NUMBERS = [
12+
'image/jpeg' => "\xFF\xD8\xFF",
13+
'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
14+
'image/gif' => "GIF"
15+
];
16+
917
public function upload(): void {
1018
try {
1119
$file = $this->validateFile($_FILES['file'] ?? null);
@@ -22,19 +30,34 @@ public function upload(): void {
2230
}
2331

2432
private function validateFile($file): array {
25-
if (!$file) {
33+
if (!$file || !isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
2634
throw new Exception("没有上传文件!");
2735
}
28-
if (!in_array($file['type'], self::ALLOWED_TYPES)) {
29-
throw new Exception("只允许上传gif、jpeg、jpg、png格式的图片文件!");
36+
37+
$finfo = new finfo(FILEINFO_MIME_TYPE);
38+
$mime = $finfo->file($file['tmp_name']);
39+
$fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION);
40+
41+
if (!in_array(strtolower($fileExtension), self::ALLOWED_EXTENSIONS) || !in_array($mime, ['image/gif', 'image/jpeg', 'image/png'])) {
42+
throw new Exception("只允许上传 gif、jpeg、jpg、png 格式的图片文件!");
43+
}
44+
45+
if (!$this->validateMagicNumber($file['tmp_name'], $mime)) {
46+
throw new Exception("文件的魔术数字与宣称的类型不匹配!");
3047
}
48+
3149
return $file;
3250
}
3351

3452
private function checkSizeAndCompress(array $file): array {
53+
// 验证文件大小是否超出限制
54+
if ($file['size'] > self::MAX_RESOLUTION) {
55+
throw new Exception("图片分辨率超过最大限制!");
56+
}
57+
3558
if ($file['size'] > self::MAX_SIZE) {
3659
if ($file['type'] === 'image/gif') {
37-
throw new Exception("GIF文件超过5MB,无法上传!");
60+
throw new Exception("GIF 文件超过5MB,无法上传!");
3861
}
3962
return $this->compressImage($file);
4063
}
@@ -57,20 +80,28 @@ private function compressImage(array $image): array {
5780
throw new Exception("图片压缩失败或压缩后仍超过最大限制!");
5881
}
5982

60-
return ['name' => $image['name'], 'type' => 'image/jpeg', 'tmp_name' => $tempFile, 'error' => 0, 'size' => $compressedSize];
83+
return ['name' => uniqid('', true) . '.jpg', 'type' => 'image/jpeg', 'tmp_name' => $tempFile, 'error' => 0, 'size' => $compressedSize];
6184
}
6285

6386
private function uploadToServer(array $file): ?string {
87+
// 生成安全的文件名,使用 UUID
88+
$safeFileName = $file['name'];
89+
6490
$ch = curl_init();
6591
curl_setopt($ch, CURLOPT_URL, self::UPLOAD_URL);
6692
curl_setopt($ch, CURLOPT_POST, true);
67-
curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile($file['tmp_name'], $file['type'], $file['name'])]);
93+
curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile($file['tmp_name'], $file['type'], $safeFileName)]);
6894
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
6995
$response = curl_exec($ch);
96+
$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
7097
curl_close($ch);
7198

7299
unlink($file['tmp_name']); // 删除上传后的临时文件
73100

101+
if ($httpStatus !== 200) {
102+
throw new Exception("远程服务器返回错误:HTTP $httpStatus");
103+
}
104+
74105
$json = json_decode($response, true);
75106
if ($json === null || !isset($json[0]['src'])) {
76107
return null;
@@ -79,6 +110,20 @@ private function uploadToServer(array $file): ?string {
79110
return $json[0]['src'];
80111
}
81112

113+
private function validateMagicNumber(string $filePath, string $fileType): bool {
114+
// 获取文件头部的前几个字节
115+
$handle = fopen($filePath, 'rb');
116+
$fileSignature = fread($handle, 4);
117+
fclose($handle);
118+
119+
// 检查文件的魔术数字是否与宣称的类型匹配
120+
if (isset(self::MAGIC_NUMBERS[$fileType])) {
121+
return strpos($fileSignature, self::MAGIC_NUMBERS[$fileType]) === 0;
122+
}
123+
124+
return false;
125+
}
126+
82127
private function outputResult(array $result): void {
83128
header("Content-type: application/json");
84129
echo json_encode($result);

0 commit comments

Comments
 (0)