Files
sam-kd/sales_manager_scenario/upload_consultation_files.php
hskwon aca1767eb9 초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
2025-12-10 20:14:31 +09:00

235 lines
7.7 KiB
PHP

<?php
// 출력 버퍼링 시작 및 에러 리포팅 비활성화
error_reporting(0);
ob_start();
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
// GCS 업로드 함수 (GCP_storage_dev.md 참고)
function uploadToGCS($file_path, $bucket_name, $object_name, $service_account_path) {
if (!file_exists($service_account_path)) {
error_log('GCS 업로드 실패: 서비스 계정 파일 없음');
return false;
}
$serviceAccount = json_decode(file_get_contents($service_account_path), true);
if (!$serviceAccount) {
error_log('GCS 업로드 실패: 서비스 계정 JSON 파싱 오류');
return false;
}
// OAuth 2.0 토큰 생성
$now = time();
$jwtHeader = base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
$jwtClaim = base64_encode(json_encode([
'iss' => $serviceAccount['client_email'],
'scope' => 'https://www.googleapis.com/auth/devstorage.full_control',
'aud' => 'https://oauth2.googleapis.com/token',
'exp' => $now + 3600,
'iat' => $now
]));
$privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
if (!$privateKey) {
error_log('GCS 업로드 실패: 개인 키 읽기 오류');
return false;
}
openssl_sign($jwtHeader . '.' . $jwtClaim, $signature, $privateKey, OPENSSL_ALGO_SHA256);
openssl_free_key($privateKey);
$jwt = $jwtHeader . '.' . $jwtClaim . '.' . base64_encode($signature);
// OAuth 토큰 요청
$tokenCh = curl_init('https://oauth2.googleapis.com/token');
curl_setopt($tokenCh, CURLOPT_POST, true);
curl_setopt($tokenCh, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $jwt
]));
curl_setopt($tokenCh, CURLOPT_RETURNTRANSFER, true);
curl_setopt($tokenCh, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
$tokenResponse = curl_exec($tokenCh);
$tokenCode = curl_getinfo($tokenCh, CURLINFO_HTTP_CODE);
curl_close($tokenCh);
if ($tokenCode !== 200) {
error_log('GCS 업로드 실패: OAuth 토큰 요청 실패 (HTTP ' . $tokenCode . ')');
return false;
}
$tokenData = json_decode($tokenResponse, true);
if (!isset($tokenData['access_token'])) {
error_log('GCS 업로드 실패: OAuth 토큰 없음');
return false;
}
$accessToken = $tokenData['access_token'];
// GCS에 파일 업로드
$file_content = file_get_contents($file_path);
$mime_type = mime_content_type($file_path) ?: 'application/octet-stream';
$upload_url = 'https://storage.googleapis.com/upload/storage/v1/b/' .
urlencode($bucket_name) . '/o?uploadType=media&name=' .
urlencode($object_name);
$ch = curl_init($upload_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $accessToken,
'Content-Type: ' . $mime_type,
'Content-Length: ' . strlen($file_content)
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $file_content);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code === 200) {
return 'gs://' . $bucket_name . '/' . $object_name;
} else {
error_log('GCS 업로드 실패 (HTTP ' . $code . '): ' . $response);
return false;
}
}
// 출력 버퍼 비우기
ob_clean();
header('Content-Type: application/json; charset=utf-8');
// 1. 권한 및 세션 체크
if (!isset($user_id) || $level > 5) {
echo json_encode(['success' => false, 'message' => '접근 권한이 없습니다.']);
exit;
}
$manager_id = $user_id;
$step_id = isset($_POST['step_id']) ? intval($_POST['step_id']) : 2;
$upload_dir = $_SERVER['DOCUMENT_ROOT'] . "/uploads/manager_consultations/" . $manager_id . "/files/";
// 2. 파일 업로드 처리
if (!file_exists($upload_dir)) mkdir($upload_dir, 0777, true);
// 업로드된 파일 확인
$uploaded_files = [];
$file_count = isset($_POST['file_count']) ? intval($_POST['file_count']) : 0;
for ($i = 0; $i < $file_count; $i++) {
$file_key = 'file_' . $i;
if (!isset($_FILES[$file_key])) {
continue;
}
$file = $_FILES[$file_key];
// 파일 크기 확인 (50MB 제한)
$max_file_size = 50 * 1024 * 1024;
if ($file['size'] > $max_file_size) {
echo json_encode([
'success' => false,
'message' => '파일 크기가 너무 큽니다. (최대 50MB): ' . $file['name']
]);
exit;
}
// 파일명 생성
$original_name = $file['name'];
$file_extension = pathinfo($original_name, PATHINFO_EXTENSION);
$file_name = date('Ymd_His') . "_" . uniqid() . "." . $file_extension;
$file_path = $upload_dir . $file_name;
if (!move_uploaded_file($file['tmp_name'], $file_path)) {
echo json_encode(['success' => false, 'message' => '파일 저장 실패: ' . $original_name]);
exit;
}
// GCS 업로드 (선택사항 - 큰 파일인 경우)
$gcs_uri = null;
$file_size = filesize($file_path);
$max_local_size = 10 * 1024 * 1024; // 10MB
if ($file_size > $max_local_size) {
$gcs_config_file = $_SERVER['DOCUMENT_ROOT'] . '/apikey/gcs_config.txt';
$bucket_name = null;
if (file_exists($gcs_config_file)) {
$gcs_config = parse_ini_file($gcs_config_file);
$bucket_name = isset($gcs_config['bucket_name']) ? $gcs_config['bucket_name'] : null;
}
if ($bucket_name) {
$googleServiceAccountFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/google_service_account.json';
$gcs_object_name = 'manager_consultations/' . $manager_id . '/files/' . basename($file_path);
$gcs_uri = uploadToGCS($file_path, $bucket_name, $gcs_object_name, $googleServiceAccountFile);
}
}
$web_path = "/uploads/manager_consultations/" . $manager_id . "/files/" . $file_name;
$file_path_to_store = $gcs_uri ? $gcs_uri : $web_path;
$uploaded_files[] = [
'original_name' => $original_name,
'file_path' => $file_path_to_store,
'file_size' => $file_size,
'gcs_uri' => $gcs_uri
];
}
// 3. DB 저장
try {
$pdo = db_connect();
if (!$pdo) {
throw new Exception('데이터베이스 연결 실패');
}
$expiry_date = date('Y-m-d H:i:s', strtotime('+30 days'));
$file_paths_json = json_encode($uploaded_files);
// manager_consultation_files 테이블에 저장
$sql = "INSERT INTO manager_consultation_files
(manager_id, step_id, file_paths_json, file_expiry_date, created_at)
VALUES (?, ?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
if (!$stmt) {
throw new Exception('SQL 준비 실패');
}
$executeResult = $stmt->execute([
$manager_id,
$step_id,
$file_paths_json,
$expiry_date
]);
if (!$executeResult) {
throw new Exception('SQL 실행 실패');
}
$insertId = $pdo->lastInsertId();
echo json_encode([
'success' => true,
'message' => count($uploaded_files) . '개 파일이 업로드되었습니다.',
'id' => $insertId,
'files' => $uploaded_files,
'file_count' => count($uploaded_files)
]);
} catch (Exception $e) {
error_log('DB 저장 오류: ' . $e->getMessage());
echo json_encode([
'success' => false,
'message' => '데이터베이스 저장 실패: ' . $e->getMessage()
]);
}
?>