|
|

分享源码
| 界面截图: |
|
| 是否带模块: |
纯源码 |
| 备注说明: |
- |
php 图片上传,超实用,简单稳定快速
e源码:
| 变量名 | 类 型 | 静态 | 数组 | 备 注 | | 分隔符 | 文本型 | | | | 时间戳 | 文本型 | | | | API_KEY | 文本型 | | | | 头信息 | 文本型 | | | | 文件名 | 文本型 | | | | 表单数据 | 字节集 | | | | 上传结果 | 字节集 | | | | json | 类_json | | | | api地址 | 文本型 | | |
api地址 = “http://127.0.0.1/image_api.php” 分隔符 = “---------------------------” + 取十六进制文本 (取随机数 (100000000, 999999999 )) 时间戳 = 时间_到时间戳 (取现行时间 (), 真, )文件名 = 文件_取文件名 (图片地址, 真)API_KEY = 校验_取md5 (到字节集 (时间戳 + “QQ516221198_QUN1071098978” + 文件名 ), , ) 头信息 = “X-API-TIMESTAMP: ” + 时间戳 + #换行符 + “X-API-SIGNATURE: ” + API_KEY + #换行符 + “Content-Type: multipart/form-data; boundary=” + 分隔符 表单数据 = 到字节集 (“--” + 分隔符 + #换行符 + “Content-Disposition: form-data; name=” + #引号 + “image” + #引号 + “; filename=” + #引号 + 文件名 + #引号 + #换行符 + “Content-Type: application/octet-stream” + #换行符 + #换行符 ) + 读入文件 (图片地址 ) + 到字节集 ( #换行符 + “--” + 分隔符 + “--”) 上传结果 = 编码_编码转换对象 (网页_访问_对象 (api地址, 1, , , , 头信息, , , , 表单数据, , , , , , , , , ), , , )json. 解析 (到文本 (上传结果 ), , ) 如果 (json. 取属性对象 (“success”) = “true”) 图片地址 = json. 取通用属性 (“['image_url']”, ) 返回 (真) 图片地址 = “” 错误提示 = json. 取通用属性 (“message”, )返回 (假)
php 源码:
[PHP] 纯文本查看 复制代码 <?php
// 设置响应头为JSON格式
header("Content-Type: application/json; charset=utf-8");
// 允许跨域请求
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, X-API-TIMESTAMP, X-API-SIGNATURE");
// 安全配置 - 请在实际使用时修改为强密钥
$apiKey = 'QQ516221198_QUN1071098978'; // 替换为你的API密钥
$allowedTimeWindow = 30; // 允许的请求时间窗口(秒),防止重放攻击
// 检查文件签名以验证文件内容的真实性
function verifyImageSignature($filePath) {
try {
// 读取文件头字节进行基本验证
$fileHeader = file_get_contents($filePath, false, null, 0, 8);
// 检查JPG文件签名 (FF D8)
if (substr($fileHeader, 0, 2) === "\xFF\xD8") {
return true;
}
// 检查PNG文件签名
if (substr($fileHeader, 0, 8) === "\x89PNG\r\n\x1A\n") {
return true;
}
} catch (Exception $e) {
error_log('文件签名验证错误: ' . $e->getMessage());
}
return false;
}
// 尝试转换非标准图片为标准JPG格式的函数
function convertToStandardJPG($sourcePath) {
try {
// 检查GD库是否可用
if (!extension_loaded('gd')) {
error_log('GD库未加载,无法转换图片');
return false;
}
// 创建临时转换路径
$targetPath = $sourcePath . '_converted.jpg';
// 尝试使用GD库打开图片
$image = @imagecreatefromstring(file_get_contents($sourcePath));
if ($image === false) {
error_log('无法从字符串创建图片');
return false;
}
// 将图片保存为标准JPG格式
$success = imagejpeg($image, $targetPath, 90);
imagedestroy($image);
return $success ? $targetPath : false;
} catch (Exception $e) {
error_log('图片转换错误: ' . $e->getMessage());
return false;
}
}
// 验证函数 - 只保留上传功能的验证
function validateRequest() {
try {
global $apiKey, $allowedTimeWindow;
// 获取请求头中的时间戳和签名
$timestamp = isset($_SERVER['HTTP_X_API_TIMESTAMP']) ? $_SERVER['HTTP_X_API_TIMESTAMP'] : '';
$signature = isset($_SERVER['HTTP_X_API_SIGNATURE']) ? $_SERVER['HTTP_X_API_SIGNATURE'] : '';
// 检查必要的头信息
if (empty($timestamp) || empty($signature)) {
http_response_code(401);
$response = [
'success' => false,
'message' => '缺少必要的信息:时间戳或签名',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 验证时间戳,防止重放攻击
$currentTime = time();
if (abs($currentTime - $timestamp) > $allowedTimeWindow) {
http_response_code(401);
$response = [
'success' => false,
'message' => '请求已过期,时间差:' . abs($currentTime - $timestamp) . '秒',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 获取上传的文件名
$fileName = isset($_FILES['image']['name']) ? $_FILES['image']['name'] : '';
// 检查文件名是否存在
if (empty($fileName)) {
http_response_code(401);
$response = [
'success' => false,
'message' => '无法获取文件名',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 生成预期的签名:时间戳+API密钥+文件名的MD5值
$expectedSignature = md5($timestamp . $apiKey . $fileName);
// 验证签名
if ($signature !== $expectedSignature) {
http_response_code(401);
$response = [
'success' => false,
'message' => '无效的签名',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
} catch (Exception $e) {
http_response_code(500);
$response = [
'success' => false,
'message' => '验证过程中发生错误:' . $e->getMessage(),
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
}
// 处理预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
echo json_encode(['success' => true, 'message' => 'Preflight request successful', 'image_url' => ''], JSON_UNESCAPED_SLASHES);
exit;
}
// 处理非POST请求
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => '不支持的请求方法', 'image_url' => ''], JSON_UNESCAPED_SLASHES);
exit;
}
// 全局变量用于跟踪转换状态
global $isConverted, $convertedTmpPath, $originalMimeType;
$isConverted = false;
$convertedTmpPath = null;
$originalMimeType = null;
// 图片配置
$uploadDir = 'uploads'; // 简化目录名,不带斜杠
$maxFileSize = 5 * 1024 * 1024; // 最大文件大小:5MB
// 确保上传目录存在,如果不存在则创建
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
@chmod($uploadDir, 0777);
}
// 确保目录路径格式正确
$uploadDir = rtrim($uploadDir, '/\\') . DIRECTORY_SEPARATOR;
// 获取当前日期,用于创建日期目录
$currentDate = date('Y-m-d');
$dateDir = $uploadDir . $currentDate . DIRECTORY_SEPARATOR;
// 确保日期目录存在,如果不存在则创建
if (!file_exists($dateDir)) {
mkdir($dateDir, 0777, true);
@chmod($dateDir, 0777);
}
// 获取当前API的基础URL(用于生成图片URL)
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http";
$host = $_SERVER['HTTP_HOST'];
$port = $_SERVER['SERVER_PORT'];
// 标准端口不需要重复添加
$standardPorts = ['80', '443'];
$portSuffix = in_array($port, $standardPorts) ? '' : ":$port";
// 确保host不包含端口号,避免重复
if (strpos($host, ':') !== false) {
$host = explode(':', $host)[0];
}
$baseUrl = "$protocol://$host$portSuffix{$_SERVER['REQUEST_URI']}";
$baseUrl = dirname($baseUrl) . '/';
try {
// 检查是否收到文件
if (!isset($_FILES['image'])) {
http_response_code(400);
$response = [
'success' => false,
'message' => '没有收到上传的文件',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 验证请求签名
validateRequest();
$file = $_FILES['image'];
// 检查文件上传错误
if ($file['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
$response = [
'success' => false,
'message' => '文件上传错误,错误代码: ' . $file['error'],
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 检查文件大小
if ($file['size'] > $maxFileSize) {
http_response_code(400);
$response = [
'success' => false,
'message' => '文件过大,最大允许5MB',
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 检查文件类型(MIME类型验证)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file['tmp_name']);
// 获取文件扩展名进行辅助验证
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowedExtensions = ['jpg', 'jpeg', 'png'];
// 添加更多可能的图片MIME类型
$supportedTypes = [
'image/jpeg', 'image/jpg', 'image/png', 'image/x-png', 'application/png', 'image/vnd.png'
];
// 主验证逻辑:优先MIME类型验证,MIME类型不匹配时进行文件签名验证
$isValidImage = in_array($mimeType, $supportedTypes);
// 保存原始MIME类型用于响应
$originalMimeType = $mimeType;
// 如果MIME类型不匹配但扩展名为允许的类型,进行文件签名验证
if (!$isValidImage && in_array($fileExtension, $allowedExtensions)) {
$isValidImage = verifyImageSignature($file['tmp_name']);
}
// 如果MIME类型不匹配且不是有效图片签名,但文件扩展名是图片类型,尝试转换
if (!$isValidImage && in_array($fileExtension, $allowedExtensions)) {
// 尝试转换为标准JPG
$convertedPath = convertToStandardJPG($file['tmp_name']);
if ($convertedPath) {
// 验证转换后的文件
$convertedMimeType = $finfo->file($convertedPath);
if (in_array($convertedMimeType, $supportedTypes)) {
// 替换原始临时文件路径
$file['tmp_name'] = $convertedPath;
$mimeType = $convertedMimeType;
$fileExtension = 'jpg';
$isValidImage = true;
// 设置转换状态
$isConverted = true;
$convertedTmpPath = $convertedPath;
} else {
// 转换失败,删除临时文件
@unlink($convertedPath);
}
}
}
if (!$isValidImage) {
http_response_code(400);
$response = [
'success' => false,
'message' => '不支持的文件类型,只允许JPG、PNG。检测到类型:' . $mimeType,
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
}
// 生成唯一的文件名
$originalExtension = pathinfo($file['name'], PATHINFO_EXTENSION);
$extension = !empty($originalExtension) ? strtolower($originalExtension) : 'jpg';
$filename = bin2hex(random_bytes(16)) . '.' . $extension;
// 构建目标路径,使用日期目录
$targetPath = $dateDir . $filename;
// 作为最后的备选方案,尝试使用当前脚本所在目录
$scriptDir = __DIR__ . DIRECTORY_SEPARATOR;
$backupTargetPath = $scriptDir . 'uploads_' . basename($targetPath);
// 移动上传的文件并设置权限
if (move_uploaded_file($file['tmp_name'], $targetPath)) {
// 设置文件权限
@chmod($targetPath, 0644);
// 返回成功信息和图片URL
$webPath = 'uploads/' . $currentDate . '/' . $filename;
$fullImageUrl = $baseUrl . $webPath;
// 构建简化的响应数据
$message = $isConverted ? '图片上传成功(已转换为标准格式)' : '图片上传成功';
if ($isConverted) {
$message .= ',原始类型:' . $originalMimeType;
}
$response = [
'success' => true,
'message' => $message,
'image_url' => $fullImageUrl
];
// 确保JSON格式正确且不转义斜杠
$jsonResponse = json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
echo $jsonResponse;
// 如果有转换的临时文件,尝试删除
if ($isConverted && isset($convertedTmpPath) && file_exists($convertedTmpPath)) {
@unlink($convertedTmpPath);
}
} else {
// 尝试备选路径
if (move_uploaded_file($file['tmp_name'], $backupTargetPath)) {
@chmod($backupTargetPath, 0644);
// 备选路径也使用日期目录结构
$backupDateDir = $scriptDir . 'uploads_' . $currentDate . DIRECTORY_SEPARATOR;
if (!file_exists($backupDateDir)) {
mkdir($backupDateDir, 0777, true);
@chmod($backupDateDir, 0777);
}
$newBackupTargetPath = $backupDateDir . basename($backupTargetPath);
// 移动到日期子目录
rename($backupTargetPath, $newBackupTargetPath);
// 构建完整的图片URL
$fullImageUrl = $baseUrl . 'uploads_' . $currentDate . '/' . basename($backupTargetPath);
// 构建简化的响应数据
$message = $isConverted ? '图片上传成功(已转换为标准格式,使用备选路径)' : '图片上传成功(使用备选路径)';
if ($isConverted) {
$message .= ',原始类型:' . $originalMimeType;
}
$response = [
'success' => true,
'message' => $message,
'image_url' => $fullImageUrl
];
// 确保JSON格式正确且不转义斜杠
$jsonResponse = json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
echo $jsonResponse;
// 如果有转换的临时文件,尝试删除
if ($isConverted && isset($convertedTmpPath) && file_exists($convertedTmpPath)) {
@unlink($convertedTmpPath);
}
} else {
http_response_code(500);
// 确保JSON输出正确,对路径进行处理以避免JSON格式问题
$debugInfo = [
'target_path' => str_replace('\\', '/', $targetPath),
'backup_target_path' => str_replace('\\', '/', $backupTargetPath),
'directory_exists' => file_exists($uploadDir),
'directory_writable' => is_writable($uploadDir),
'script_directory_writable' => is_writable($scriptDir),
'error_message' => error_get_last() ? error_get_last()['message'] : '无错误信息'
];
$response = [
'success' => false,
'message' => '无法保存上传的文件,请检查目录权限。路径:' . $targetPath,
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
}
}
} catch (Exception $e) {
// 全局异常处理
http_response_code(500);
$response = [
'success' => false,
'message' => '服务器处理错误:' . $e->getMessage(),
'image_url' => ''
];
echo json_encode($response, JSON_UNESCAPED_SLASHES);
}
// 确保脚本结束
exit;
?>
好了,源码
php图片上传.rar
(234.08 KB, 下载次数: 30, 售价: 2 枚 精币)
|
评分
-
查看全部评分
|