prepare('SELECT is_verified FROM developers WHERE id = ?'); if (!$stmt) { log_error('准备验证状态查询失败: ' . $conn->error, __FILE__, __LINE__); $error = '系统错误,请稍后再试'; } else { $stmt->bind_param('i', $developerId); $stmt->execute(); $result = $stmt->get_result(); $developer = $result->fetch_assoc(); $stmt->close(); log_info("开发者验证状态: " . ($developer ? ($developer['is_verified'] ? "已验证" : "未验证") : "开发者不存在"), __FILE__, __LINE__); if (!$developer) { $error = '开发者账号不存在,请重新登录。'; } elseif (!$developer['is_verified']) { $error = '您的邮箱尚未验证,请先验证邮箱后再上传应用。'; } } if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 创建上传目录(如果不存在) $uploadDirs = ['../uploads/apps', '../uploads/images']; foreach ($uploadDirs as $dir) { if (!is_dir($dir)) { mkdir($dir, 0755, true); } } // 获取表单数据 $appName = trim($_POST['name']); $appDescription = trim($_POST['description']); $tags = $_POST['tags'] ?? []; $ageRating = $_POST['age_rating'] ?? ''; $ageRatingDescription = $_POST['age_rating_description'] ?? ''; $platforms = isset($_POST['platforms']) ? $_POST['platforms'] : []; $version = trim($_POST['version']); $changelog = trim($_POST['changelog']); // 验证表单数据 if (empty($appName) || empty($appDescription)) { $error = '应用名称和描述不能为空'; } elseif (empty($changelog)) { $error = '更新日志不能为空'; } elseif (empty($platforms)) { $error = '请至少选择一个适用平台'; } elseif (in_array($ageRating, ['12+', '17+']) && empty($ageRatingDescription)) { $error = '年龄分级为12+或以上时,必须提供年龄分级说明'; } else { // 检查数据库连接是否为 MySQLi 对象 if (!($conn instanceof mysqli)) { log_error('数据库连接错误: 连接不是MySQLi实例', __FILE__, __LINE__); $error = '数据库连接错误,请检查配置'; } else { // 处理应用文件上传 // 获取选中的平台 $selectedPlatforms = $_POST['platforms'] ?? []; // 处理应用文件上传 $appFile = $_FILES['app_file'] ?? null; $appFilePath = ''; if ($appFile && $appFile['error'] === UPLOAD_ERR_OK) { // 验证文件大小 (100MB) if ($appFile['size'] > 500 * 1024 * 1024) { log_error('应用文件过大: ' . number_format($appFile['size'] / 1024 / 1024, 2) . 'MB', __FILE__, __LINE__); $error = '应用文件大小不能超过500MB'; } $appExtension = pathinfo($appFile['name'], PATHINFO_EXTENSION); $appFileName = uniqid() . '.' . $appExtension; $appRelativePath = 'uploads/apps/' . $appFileName; $appFilePath = __DIR__ . '/../' . $appRelativePath; if (!move_uploaded_file($appFile['tmp_name'], $appFilePath)) { log_error('应用文件移动失败', __FILE__, __LINE__); $error = '应用文件上传失败'; } } else { // 验证标签ID是否存在 if (!empty($tags)) { $tagIds = implode(',', array_map('intval', $tags)); $tagCheckStmt = $conn->prepare("SELECT id FROM tags WHERE id IN ($tagIds)"); if (!$tagCheckStmt) { log_error('标签验证查询准备失败: ' . $conn->error, __FILE__, __LINE__); $error = '系统错误,请稍后再试'; } else { $tagCheckStmt->execute(); $tagResult = $tagCheckStmt->get_result(); $validTagIds = []; while ($tag = $tagResult->fetch_assoc()) { $validTagIds[] = $tag['id']; } $tagCheckStmt->close(); $invalidTags = array_diff($tags, $validTagIds); if (!empty($invalidTags)) { log_error('无效的标签ID: ' . implode(',', $invalidTags), __FILE__, __LINE__); $error = '选择了无效的标签,请刷新页面重试'; } } } $error = '应用文件上传错误: ' . ($appFile ? $appFile['error'] : '未找到文件'); } // 处理图片上传 $imagePaths = []; $images = $_FILES['images'] ?? null; if ($images && is_array($images['tmp_name'])) { foreach ($images['tmp_name'] as $key => $tmpName) { if ($images['error'][$key] === UPLOAD_ERR_OK) { // 验证图片大小 (10MB) if ($images['size'][$key] > 10 * 1024 * 1024) { log_error('图片过大: ' . $images['name'][$key] . ' (' . number_format($images['size'][$key] / 1024 / 1024, 2) . 'MB)', __FILE__, __LINE__); $error = '图片 ' . $images['name'][$key] . ' 大小不能超过10MB'; } $imageRelativePath = 'uploads/images/' . uniqid() . '.' . pathinfo($images['name'][$key], PATHINFO_EXTENSION); $imagePath = __DIR__ . '/../' . $imageRelativePath; $target_dir = dirname($imagePath); if (!is_dir($target_dir)) { mkdir($target_dir, 0755, true); } if (move_uploaded_file($tmpName, $imagePath)) { $imagePaths[] = $imageRelativePath; } else { log_error('图片文件移动失败: ' . $images['name'][$key], __FILE__, __LINE__); } } } } if (empty($error)) { // 开始数据库事务 $conn->begin_transaction(); try { // 确保必要变量存在,防止空值导致 SQL 错误 if (!isset($appName) || !isset($appDescription) || !isset($developerId) || !isset($version) || !isset($changelog) || !isset($ageRating) || !isset($ageRatingDescription)) { throw new Exception('缺少必要的上传参数'); } // 获取开发者邮箱 $userStmt = $conn->prepare('SELECT email FROM developers WHERE id = ?'); $userStmt->bind_param('i', $developerId); $userStmt->execute(); $userResult = $userStmt->get_result(); $user = $userResult->fetch_assoc(); $developerEmail = $user['email'] ?? ''; $userStmt->close(); if (empty($developerEmail)) { throw new Exception('无法获取开发者邮箱信息'); } // 插入应用基本信息 $stmt = $conn->prepare('INSERT INTO apps (name, description, platforms, status, age_rating, age_rating_description, version, changelog, file_path, developer_id, developer_email, created_at) VALUES (?, ?, ?, \'pending\', ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)'); if (!$stmt) { throw new Exception('应用基本信息查询准备失败: ' . $conn->error); } // 确保平台数据正确编码 $platforms = $_POST['platforms'] ?? []; $platforms_json = json_encode($platforms); // 此处需确认预处理语句占位符数量,确保与 bind_param 参数数量一致,示例仅示意,实际需根据表结构调整 // 修正参数绑定,添加file_path参数以匹配SQL占位符数量 // 修正参数类型字符串长度,确保与10个参数匹配 // 修正类型字符串长度,10个参数对应10个类型字符 // 最终修正:10个参数对应10个类型字符 // 根据参数实际类型修正类型字符串(整数用i,字符串用s) // 移除多余的$status参数,匹配SQL中9个占位符 // 修正age_rating_description类型为字符串,并确保9个参数与占位符匹配 // 修复变量名错误:使用已验证的$appFilePath替换未定义的$file_path $stmt->bind_param('ssssssssis', $appName, $appDescription, $platforms_json, $ageRating, $ageRatingDescription, $version, $changelog, $appRelativePath, $developerId, $developerEmail); if (!$stmt->execute()) { throw new Exception('应用基本信息查询执行失败: ' . $stmt->error); } $appId = $stmt->insert_id; log_info("应用已插入数据库: ID=$appId, 状态=pending", __FILE__, __LINE__); $stmt->close(); // 发送审核邮件给管理员 require_once '../vendor/autoload.php'; $subject = '新应用待审核'; $body = "开发者提交了新应用,应用ID: $appId,名称: $appName,请及时审核。"; $mail = new PHPMailer\PHPMailer\PHPMailer(); $mail->isSMTP(); $mail->Host = SMTP_HOST; $mail->SMTPAuth = true; $mail->Username = SMTP_USERNAME; $mail->Password = SMTP_PASSWORD; $mail->SMTPSecure = SMTP_ENCRYPTION; $mail->Port = SMTP_PORT; $mail->setFrom(SMTP_FROM_EMAIL, SMTP_FROM_NAME); $mail->addAddress(ADMIN_EMAIL); $mail->isHTML(false); $mail->CharSet = 'utf-8'; $mail->Subject = $subject; $mail->Body = $body; if(!$mail->send()) { log_error('发送审核邮件失败: ' . $mail->ErrorInfo, __FILE__, __LINE__); } else { log_info('已成功发送审核邮件给管理员', __FILE__, __LINE__); } log_info("开始处理应用关联数据: ID=$appId", __FILE__, __LINE__); // 插入应用标签关联 foreach ($tags as $tagId) { $tagStmt = $conn->prepare('INSERT INTO app_tags (app_id, tag_id) VALUES (?, ?)'); if (!$tagStmt) { throw new Exception('标签关联查询准备失败: ' . $conn->error); } $tagStmt->bind_param('ii', $appId, $tagId); if (!$tagStmt->execute()) { throw new Exception('标签关联查询执行失败: ' . $tagStmt->error); } $tagStmt->close(); } // 插入应用图片 foreach ($imagePaths as $imageRelativePath) { $imageStmt = $conn->prepare('INSERT INTO app_images (app_id, image_path) VALUES (?, ?)'); if (!$imageStmt) { throw new Exception('图片关联查询准备失败: ' . $conn->error); } $imageStmt->bind_param('is', $appId, $imageRelativePath); if (!$imageStmt->execute()) { throw new Exception('图片关联查询执行失败: ' . $imageStmt->error); } $imageStmt->close(); } // 插入应用版本信息 $versionStmt = $conn->prepare('INSERT INTO app_versions (app_id, version, changelog, file_path, created_at) VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)'); if (!$versionStmt) { throw new Exception('版本信息查询准备失败: ' . $conn->error); } $versionStmt->bind_param('isss', $appId, $version, $changelog, $appRelativePath); if (!$versionStmt->execute()) { throw new Exception('版本信息查询执行失败: ' . $versionStmt->error); } $versionStmt->close(); log_info("所有关联数据处理完成,准备提交事务: ID=$appId", __FILE__, __LINE__); // 提交事务 $conn->commit(); log_info("应用上传成功: ID=$appId, 状态=pending", __FILE__, __LINE__); $success = '应用上传成功,请等待管理员审核'; } catch (Exception $e) { // 回滚事务 $conn->rollback(); log_error('应用上传事务失败(ID=$appId): ' . $e->getMessage(), __FILE__, __LINE__); $error = '上传应用时发生错误,请稍后再试'; } } } } } ?> 上传应用 - <?php echo APP_STORE_NAME; ?>

上传应用

警告:如果该应用非您本人开发,请务必添加"转载"标签。
按住Ctrl键可选择多个标签
当年龄分级为12+或以上时,此项为必填
信息:我们尝试了开发多选子平台的功能,但是就会导致以前的app会全部显示“未知平台”,如果你是Windows的话,选择Win7以上选项,如果你是Linux的话,选择APP支持平台中的任意一个即可。
可选择多张图片