From 927c1397b5f5e829bbd1600901b381e8aa222c53 Mon Sep 17 00:00:00 2001 From: Allinks <60175577+0-RTT@users.noreply.github.com> Date: Sun, 26 May 2024 11:23:50 +0800 Subject: [PATCH] Update api.php --- api/api.php | 59 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/api/api.php b/api/api.php index aa713fd..1e29608 100644 --- a/api/api.php +++ b/api/api.php @@ -1,11 +1,19 @@ "\xFF\xD8\xFF", + 'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", + 'image/gif' => "GIF" + ]; + public function upload(): void { try { $file = $this->validateFile($_FILES['file'] ?? null); @@ -22,19 +30,34 @@ public function upload(): void { } private function validateFile($file): array { - if (!$file) { + if (!$file || !isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) { throw new Exception("没有上传文件!"); } - if (!in_array($file['type'], self::ALLOWED_TYPES)) { - throw new Exception("只允许上传gif、jpeg、jpg、png格式的图片文件!"); + + $finfo = new finfo(FILEINFO_MIME_TYPE); + $mime = $finfo->file($file['tmp_name']); + $fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION); + + if (!in_array(strtolower($fileExtension), self::ALLOWED_EXTENSIONS) || !in_array($mime, ['image/gif', 'image/jpeg', 'image/png'])) { + throw new Exception("只允许上传 gif、jpeg、jpg、png 格式的图片文件!"); + } + + if (!$this->validateMagicNumber($file['tmp_name'], $mime)) { + throw new Exception("文件的魔术数字与宣称的类型不匹配!"); } + return $file; } private function checkSizeAndCompress(array $file): array { + // 验证文件大小是否超出限制 + if ($file['size'] > self::MAX_RESOLUTION) { + throw new Exception("图片分辨率超过最大限制!"); + } + if ($file['size'] > self::MAX_SIZE) { if ($file['type'] === 'image/gif') { - throw new Exception("GIF文件超过5MB,无法上传!"); + throw new Exception("GIF 文件超过5MB,无法上传!"); } return $this->compressImage($file); } @@ -57,20 +80,28 @@ private function compressImage(array $image): array { throw new Exception("图片压缩失败或压缩后仍超过最大限制!"); } - return ['name' => $image['name'], 'type' => 'image/jpeg', 'tmp_name' => $tempFile, 'error' => 0, 'size' => $compressedSize]; + return ['name' => uniqid('', true) . '.jpg', 'type' => 'image/jpeg', 'tmp_name' => $tempFile, 'error' => 0, 'size' => $compressedSize]; } private function uploadToServer(array $file): ?string { + // 生成安全的文件名,使用 UUID + $safeFileName = $file['name']; + $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::UPLOAD_URL); curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile($file['tmp_name'], $file['type'], $file['name'])]); + curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile($file['tmp_name'], $file['type'], $safeFileName)]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); + $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); unlink($file['tmp_name']); // 删除上传后的临时文件 + if ($httpStatus !== 200) { + throw new Exception("远程服务器返回错误:HTTP $httpStatus"); + } + $json = json_decode($response, true); if ($json === null || !isset($json[0]['src'])) { return null; @@ -79,6 +110,20 @@ private function uploadToServer(array $file): ?string { return $json[0]['src']; } + private function validateMagicNumber(string $filePath, string $fileType): bool { + // 获取文件头部的前几个字节 + $handle = fopen($filePath, 'rb'); + $fileSignature = fread($handle, 4); + fclose($handle); + + // 检查文件的魔术数字是否与宣称的类型匹配 + if (isset(self::MAGIC_NUMBERS[$fileType])) { + return strpos($fileSignature, self::MAGIC_NUMBERS[$fileType]) === 0; + } + + return false; + } + private function outputResult(array $result): void { header("Content-type: application/json"); echo json_encode($result);