Files
ai-web/app/Http/Controllers/Admin/UploadController.php
jiangdong.cheng 56c685b579 配置功能完善
2026-02-12 15:37:49 +08:00

181 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use GdImage;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use RuntimeException;
use Throwable;
class UploadController extends Controller
{
private const MAX_FILE_KB = 6144;
private const MAX_MAIN_WIDTH = 2400;
private const THUMB_WIDTH = 320;
private const MAIN_WEBP_QUALITY = 86;
private const THUMB_WEBP_QUALITY = 80;
public function markdownImage(Request $request): JsonResponse
{
$validated = $request->validate([
'image' => ['required', 'file', 'image', 'mimes:jpg,jpeg,png,webp,gif', 'max:'.self::MAX_FILE_KB],
], [
'image.required' => '请选择要上传的图片。',
'image.image' => '仅支持图片文件上传。',
'image.mimes' => '图片格式仅支持 jpg、jpeg、png、webp、gif。',
'image.max' => '图片大小不能超过 6MB。',
]);
if (! function_exists('imagecreatefromstring') || ! function_exists('imagewebp')) {
return response()->json([
'success' => false,
'message' => '服务器不支持图片处理能力GD/WebP。',
], 500);
}
/** @var UploadedFile $file */
$file = $validated['image'];
$sourceImage = null;
$mainImage = null;
$thumbImage = null;
try {
[$sourceImage, $sourceWidth, $sourceHeight] = $this->createImageFromUpload($file);
$mainWidth = min(self::MAX_MAIN_WIDTH, $sourceWidth);
$mainImage = $this->resizeImage($sourceImage, $sourceWidth, $sourceHeight, $mainWidth);
$thumbWidth = min(self::THUMB_WIDTH, imagesx($mainImage));
$thumbImage = $this->resizeImage($mainImage, imagesx($mainImage), imagesy($mainImage), $thumbWidth);
$mainBinary = $this->encodeWebp($mainImage, self::MAIN_WEBP_QUALITY);
$thumbBinary = $this->encodeWebp($thumbImage, self::THUMB_WEBP_QUALITY);
$subDir = now()->format('Y/m/d');
$baseName = now()->format('YmdHis').'-'.Str::lower(Str::random(8));
$mainPath = "markdown-images/{$subDir}/{$baseName}.webp";
$thumbPath = "markdown-images/{$subDir}/{$baseName}_thumb.webp";
Storage::disk('public')->put($mainPath, $mainBinary);
Storage::disk('public')->put($thumbPath, $thumbBinary);
$mainUrl = '/storage/'.ltrim($mainPath, '/');
$thumbUrl = '/storage/'.ltrim($thumbPath, '/');
return response()->json([
'success' => true,
'url' => $mainUrl,
'thumb_url' => $thumbUrl,
'filename' => basename($mainPath),
'markdown' => '![]('.$mainUrl.')',
]);
} catch (Throwable $exception) {
report($exception);
return response()->json([
'success' => false,
'message' => '图片上传失败,请稍后重试。',
], 422);
} finally {
if ($sourceImage instanceof GdImage) {
imagedestroy($sourceImage);
}
if ($mainImage instanceof GdImage) {
imagedestroy($mainImage);
}
if ($thumbImage instanceof GdImage) {
imagedestroy($thumbImage);
}
}
}
/**
* @return array{0:GdImage,1:int,2:int}
*/
private function createImageFromUpload(UploadedFile $file): array
{
$path = $file->getRealPath();
if ($path === false || $path === '') {
throw new RuntimeException('上传临时文件不可用。');
}
$binary = file_get_contents($path);
if ($binary === false) {
throw new RuntimeException('读取上传文件失败。');
}
$image = @imagecreatefromstring($binary);
if (! $image instanceof GdImage) {
throw new RuntimeException('无法解析图片内容。');
}
if (! imageistruecolor($image)) {
imagepalettetotruecolor($image);
}
$width = imagesx($image);
$height = imagesy($image);
if ($width < 1 || $height < 1) {
imagedestroy($image);
throw new RuntimeException('图片尺寸无效。');
}
return [$image, $width, $height];
}
private function resizeImage(GdImage $source, int $sourceWidth, int $sourceHeight, int $targetWidth): GdImage
{
$targetWidth = max(1, $targetWidth);
if ($sourceWidth === $targetWidth) {
$targetHeight = $sourceHeight;
} else {
$targetHeight = max(1, (int) round($sourceHeight * ($targetWidth / $sourceWidth)));
}
$canvas = imagecreatetruecolor($targetWidth, $targetHeight);
if (! $canvas instanceof GdImage) {
throw new RuntimeException('创建图片画布失败。');
}
$background = imagecolorallocate($canvas, 255, 255, 255);
imagefill($canvas, 0, 0, $background);
if (! imagecopyresampled($canvas, $source, 0, 0, 0, 0, $targetWidth, $targetHeight, $sourceWidth, $sourceHeight)) {
imagedestroy($canvas);
throw new RuntimeException('图片缩放失败。');
}
return $canvas;
}
private function encodeWebp(GdImage $image, int $quality): string
{
ob_start();
$saved = imagewebp($image, null, $quality);
$binary = ob_get_clean();
if (! $saved || ! is_string($binary) || $binary === '') {
throw new RuntimeException('WebP 编码失败。');
}
return $binary;
}
}