Initial commit: 投注游戏平台初始化

This commit is contained in:
li
2026-02-25 01:26:58 +08:00
commit 77ca2cc8b3
275 changed files with 237479 additions and 0 deletions
+376
View File
@@ -0,0 +1,376 @@
<?php
namespace App\Controllers\Admin;
use App\Core\AdminBaseController;
use Db\Database; // Medoo数据库实例
use \Exception;
class ImagesController extends AdminBaseController {
protected $db;
protected $uploadDir;
protected array $uploadConfig;
// 允许的图片MIME类型
const ALLOWED_MIME = [
'image/jpeg', 'image/png', 'image/gif',
'image/webp', 'image/svg+xml'
];
const MAX_UPLOAD_SIZE = 10485760; // 上传大小限制(10MB
const MAX_IMAGE_SIZE = 800; // 主图最大边长(等同缩略图大小)
public function __construct() {
$this->checkLogin(); // 登录验证
$this->db = new Database(); // 初始化数据库连接
$domain = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http")
. "://" . $_SERVER['HTTP_HOST'];
$this->uploadConfig = [
'upload_dir' => $_SERVER['DOCUMENT_ROOT'] . '/Storage/images/',
'url' => $domain . '/Storage/images/',
'max_size' => 10 * 1024 * 1024, // 10MB
'allowed_mimes' => [
'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/icon'
],
'min_quality' => 60,
'max_quality' => 100,
'default_quality' => 80
];
}
/**
* 图片管理首页(仅渲染前端页面,数据使用AJAX加载)
*/
public function index() {
// 渲染页面模板
$this->render('Admin/images.php', [
'title' => '图片管理'
]);
}
/**
* 图片列表查询
*/
public function list() {
try {
// 处理分页参数
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ?
min(100, max(1, (int)$_GET['limit'])) : 20;
$offset = ($page - 1) * $limit;
// 查询总数
$total = $this->db->count('images');
// 查询当前页数据
$data = $this->db->select('images', [
'id', 'name', 'url',
'size', 'width', 'height', 'upload_time'
], [
'LIMIT' => [$offset, $limit],
'ORDER' => ['upload_time' => 'DESC']
]);
// 返回结果
echo json_encode([
'status' => 'success',
'page' => $page,
'total' => $total,
'data' => $data ?: []
]);
exit;
} catch (Exception $e) {
$this->jsonError('获取数据失败: ' . $e->getMessage());
}
}
/**
* 图片上传处理
*/
public function upload() {
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
$this->jsonError('文件上传失败: ' . $this->getUploadError($_FILES['image']['error'] ?? -1));
}
$file = $_FILES['image'];
$params = [
'quality' => isset($_POST['quality']) ?
min($this->uploadConfig['max_quality'],
max($this->uploadConfig['min_quality'], (int)$_POST['quality'])) :
$this->uploadConfig['default_quality'],
'width' => isset($_POST['width']) && $_POST['width'] !== '' ? max(1, (int)$_POST['width']) : 0,
'height' => isset($_POST['height']) && $_POST['height'] !== '' ? max(1, (int)$_POST['height']) : 0
];
if ($file['size'] > $this->uploadConfig['max_size']) {
$this->jsonError("文件过大,最大支持" . $this->formatFileSize($this->uploadConfig['max_size']));
}
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
if (!in_array($mime, $this->uploadConfig['allowed_mimes'])) {
$this->jsonError('不支持的文件类型,仅允许: ' . implode(', ', $this->uploadConfig['allowed_mimes']));
}
try {
$uploadDir = rtrim($this->uploadConfig['upload_dir'], '/') . '/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$originalName = basename($file['name']);
$originalExt = pathinfo($originalName, PATHINFO_EXTENSION);
$filename = date('YmdHis') . '_' . uniqid() . '.' . $originalExt;
$targetPath = $uploadDir . $filename;
list($origWidth, $origHeight) = getimagesize($file['tmp_name']);
list($newWidth, $newHeight, $srcX, $srcY, $cropW, $cropH) = $this->calculateDimensions(
$origWidth, $origHeight,
$params['width'], $params['height']
);
// 判断是否需要裁剪
if ($params['width'] > 0 && $params['height'] > 0) {
$success = $this->processImageWithCrop(
$file['tmp_name'], $mime, $targetPath,
$newWidth, $newHeight,
$srcX, $srcY, $cropW, $cropH,
$params['quality']
);
} else {
$success = $this->processImage(
$file['tmp_name'], $mime, $targetPath,
$newWidth, $newHeight, $params['quality']
);
}
if (!$success) {
throw new Exception('图片处理失败');
}
$record = [
'name' => $originalName,
'newname' => $filename,
'url' => rtrim($this->uploadConfig['url'], '/') . '/' . $filename,
'size' => filesize($targetPath),
'width' => $newWidth,
'height' => $newHeight,
'upload_time' => time()
];
$imageId = $this->db->insert('images', $record);
echo json_encode([
'status' => 'success',
'data' => $record + ['id' => $imageId]
]);
exit;
} catch (Exception $e) {
if (isset($targetPath) && file_exists($targetPath)) {
unlink($targetPath);
}
$this->jsonError($e->getMessage());
}
}
private function calculateDimensions($origW, $origH, $targetW, $targetH) {
if ($targetW <= 0 && $targetH <= 0) {
return [$origW, $origH, 0, 0, $origW, $origH];
}
// 只指定宽
if ($targetW > 0 && $targetH <= 0) {
$newW = $targetW;
$newH = (int)($origH * ($targetW / $origW));
return [$newW, $newH, 0, 0, $origW, $origH];
}
// 只指定高
if ($targetH > 0 && $targetW <= 0) {
$newH = $targetH;
$newW = (int)($origW * ($targetH / $origH));
return [$newW, $newH, 0, 0, $origW, $origH];
}
// 指定宽高 → 居中裁剪
$srcRatio = $origW / $origH;
$dstRatio = $targetW / $targetH;
if ($srcRatio > $dstRatio) {
$cropH = $origH;
$cropW = (int)($origH * $dstRatio);
$srcX = (int)(($origW - $cropW) / 2);
$srcY = 0;
} else {
$cropW = $origW;
$cropH = (int)($origW / $dstRatio);
$srcX = 0;
$srcY = (int)(($origH - $cropH) / 2);
}
return [$targetW, $targetH, $srcX, $srcY, $cropW, $cropH];
}
// 处理图片,带裁剪逻辑
private function processImageWithCrop($srcPath, $mime, $destPath, $width, $height, $srcX, $srcY, $cropW, $cropH, $quality) {
switch ($mime) {
case 'image/jpeg': $src = imagecreatefromjpeg($srcPath); break;
case 'image/png': $src = imagecreatefrompng($srcPath); imagesavealpha($src, true); break;
case 'image/gif': $src = imagecreatefromgif($srcPath); break;
case 'image/webp': $src = imagecreatefromwebp($srcPath); break;
default: throw new Exception("不支持的图片格式: {$mime}");
}
if (!$src) throw new Exception('无法解析图片内容');
$dest = imagecreatetruecolor($width, $height);
if ($mime === 'image/png' || $mime === 'image/gif') {
imagealphablending($dest, false);
imagesavealpha($dest, true);
$transparent = imagecolorallocatealpha($dest, 255, 255, 255, 127);
imagefilledrectangle($dest, 0, 0, $width, $height, $transparent);
}
imagecopyresampled(
$dest, $src,
0, 0,
$srcX, $srcY,
$width, $height,
$cropW, $cropH
);
$result = false;
switch ($mime) {
case 'image/jpeg': $result = imagejpeg($dest, $destPath, $quality); break;
case 'image/png': $result = imagepng($dest, $destPath); break;
case 'image/gif': $result = imagegif($dest, $destPath); break;
case 'image/webp': $result = imagewebp($dest, $destPath, $quality); break;
}
imagedestroy($src);
imagedestroy($dest);
return $result;
}
// 工具函数:图片处理(普通格式,不裁剪)
private function processImage($srcPath, $mime, $destPath, $width, $height, $quality) {
switch ($mime) {
case 'image/jpeg': $src = imagecreatefromjpeg($srcPath); break;
case 'image/png': $src = imagecreatefrompng($srcPath); imagesavealpha($src, true); break;
case 'image/gif': $src = imagecreatefromgif($srcPath); break;
case 'image/webp': $src = imagecreatefromwebp($srcPath); break;
default: throw new Exception("不支持的图片格式: {$mime}");
}
if (!$src) throw new Exception('无法解析图片内容');
$dest = imagecreatetruecolor($width, $height);
if ($mime === 'image/png' || $mime === 'image/gif') {
imagealphablending($dest, false);
imagesavealpha($dest, true);
$transparent = imagecolorallocatealpha($dest, 255, 255, 255, 127);
imagefilledrectangle($dest, 0, 0, $width, $height, $transparent);
}
imagecopyresampled($dest, $src, 0, 0, 0, 0, $width, $height, imagesx($src), imagesy($src));
$result = false;
switch ($mime) {
case 'image/jpeg': $result = imagejpeg($dest, $destPath, $quality); break;
case 'image/png': $result = imagepng($dest, $destPath); break;
case 'image/gif': $result = imagegif($dest, $destPath); break;
case 'image/webp': $result = imagewebp($dest, $destPath, $quality); break;
}
imagedestroy($src);
imagedestroy($dest);
return $result;
}
// 工具函数:上传错误信息
private function getUploadError($code) {
$errors = [
UPLOAD_ERR_INI_SIZE => '超过php.ini限制',
UPLOAD_ERR_FORM_SIZE => '超过表单限制',
UPLOAD_ERR_PARTIAL => '文件仅部分上传',
UPLOAD_ERR_NO_FILE => '未上传文件',
UPLOAD_ERR_NO_TMP_DIR => '缺少临时目录',
UPLOAD_ERR_CANT_WRITE => '写入文件失败',
UPLOAD_ERR_EXTENSION => '被扩展阻止'
];
return $errors[$code] ?? "未知错误(代码: {$code}";
}
// 工具函数:格式化文件大小
private function formatFileSize($bytes) {
if ($bytes < 1024) return $bytes . 'B';
if ($bytes < 1048576) return round($bytes / 1024, 1) . 'KB';
return round($bytes / 1048576, 1) . 'MB';
}
// 工具函数:JSON错误响应
private function jsonError($message) {
echo json_encode([
'status' => 'error',
'message' => $message
]);
exit;
}
public function delete() {
header('Content-Type: application/json');
// 获取 JSON 输入
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['ids']) || !is_array($input['ids'])) {
echo json_encode(['status' => 'error', 'message' => '缺少参数']);
return;
}
// 将字符串数组转换为整数数组
$ids = array_map('intval', $input['ids']);
$ids = array_filter($ids); // 去除无效值
if (empty($ids)) {
echo json_encode(['status' => 'error', 'message' => '无效的 ID 列表']);
return;
}
try {
// 查询图片路径(如果你想同时删除图片文件)
$images = $this->db->select('images', ['id', 'newname'], [
'id' => $ids
]);
foreach ($images as $img) {
$file = $this->uploadConfig['upload_dir'] . $img['newname'];
if (file_exists($file)) {
@unlink($file);
}
}
// 删除数据库记录
$this->db->delete('images', ['id' => $ids]);
echo json_encode(['status' => 'success']);
} catch (Exception $e) {
echo json_encode(['status' => 'error', 'message' => '删除失败:' . $e->getMessage()]);
}
}
}