alert('로그인이 필요한 서비스입니다.'); window.location.href = '/egbim/index.php?popup=login'; "; exit; } // 3) DB 연결 (PDO) $host = 'db'; $dbname = 'egbim'; $user = 'egbim'; $pass = 'baron3840!!'; $charset = 'utf8mb4'; $dsn = "mysql:host={$host};dbname={$dbname};charset={$charset}"; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]; try { $pdo = new PDO($dsn, $user, $pass, $options); $pdo->exec("SET time_zone = '+09:00'"); } catch (PDOException $e) { exit('DB 연결 에러: ' . $e->getMessage()); } // 4) 수정 모드 판단 $postId = isset($_GET['id']) ? (int)$_GET['id'] : 0; $isEdit = $postId > 0; // 5) 수정 모드이면 기존 글 불러오기 if ($isEdit) { $stmt = $pdo->prepare("SELECT * FROM qa_posts WHERE post_id = ?"); $stmt->execute([$postId]); $post = $stmt->fetch() ?: exit('존재하지 않는 글입니다.'); } else { // 등록 모드 기본값 $post = [ 'category' => '', 'title' => '', 'content' => '', 'is_secret' => 0, 'status' => 'new', ]; } // === 파일 업로드 처리 공통 함수 === function handle_file_uploads(PDO $pdo, int $postId, array &$errors) { if (empty($_FILES['attach']['name'][0])) return; $uploadDir = __DIR__ . '/../uploads/qa/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0777, true); } if (!is_writable($uploadDir)) { @chmod($uploadDir, 0777); } if (!is_writable($uploadDir)) { $errors[] = '업로드 폴더에 쓰기 권한이 없습니다.'; return; } $allowedExt = ['jpg','jpeg','png','gif','pdf','hwp','doc','docx','xls','xlsx','zip','7z','dwg','dwt','dxf','grm','ctb','shx','shp','lin','lsp','reg']; foreach ($_FILES['attach']['name'] as $i => $oriName) { if ($_FILES['attach']['error'][$i] === UPLOAD_ERR_OK) { $tmpName = $_FILES['attach']['tmp_name'][$i]; $fileSize = $_FILES['attach']['size'][$i]; $ext = strtolower(pathinfo($oriName, PATHINFO_EXTENSION)); if (!in_array($ext, $allowedExt)) { $errors[] = "허용되지 않은 확장자: {$oriName}"; continue; } if ($fileSize > 30 * 1024 * 1024) { $errors[] = "파일 용량 초과 (30MB): {$oriName}"; continue; } $safeName = time() . '_' . bin2hex(random_bytes(4)) . '_' . basename($oriName); $savePath = $uploadDir . $safeName; if (@move_uploaded_file($tmpName, $savePath)) { $stmt = $pdo->prepare(" INSERT INTO qa_attachments (post_id, ori_name, save_path, file_size, uploaded_at) VALUES (?, ?, ?, ?, NOW()) "); $stmt->execute([ $postId, $oriName, '/egbim/uploads/qa/' . $safeName, $fileSize ]); } else { $errors[] = "파일 업로드에 실패했습니다: {$oriName}"; } } } } // 6) 폼 제출 처리 $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 6-1) 로그인 정보 $loginId = $_SESSION['user']['loginIds'][0] ?? ''; $userId = $_SESSION['user']['userId'] ?? ''; // 내부 도메인 리스트 $internalDomains = [ 'hanmaceng.co.kr','samaneng.com','jangheon.co.kr', 'hallasanup.com','pre-cast.co.kr','baroncs.co.kr' ]; // 도메인 추출 → 내부/외부 구분 $emailDomain = substr(strrchr($loginId, "@"), 1); $isInternal = in_array($emailDomain, $internalDomains, true); // 회사명 $Internal_companyName = $_SESSION['user']['customAttributes']['familyCompany'] ?? ''; $external_companyName = $_SESSION['user']['customAttributes']['company'] ?? ''; // 부서 $department = $_SESSION['user']['customAttributes']['team'] ?? ''; // 6-2) POST 데이터 수집 $postLabel = trim($_POST['category'] ?? ''); $title = trim($_POST['title'] ?? ''); $content = trim($_POST['content'] ?? ''); $secret = isset($_POST['secret']) ? 1 : 0; $status = 'new'; // 항상 답변대기 // 6-3) 한글 카테고리 → 코드 매핑 $categoryMap = [ '오류문의' => 'error', '개선문의' => 'improvement', '일반문의' => 'general', '공지사항' => 'notice', '관리글' => 'admin', ]; $category = $categoryMap[$postLabel] ?? ''; // 6-4) 유효성 검사 if (!in_array($category, $categoryMap, true)) { $errors[] = '유효한 구분을 선택하세요.'; } if ($title === '' || mb_strlen($title) > 100) { $errors[] = '제목은 1~100자 사이여야 합니다.'; } if ($content === '') { $errors[] = '내용을 입력해주세요.'; } if (empty($errors)) { $pdo->beginTransaction(); try { if ($isEdit) { // 6-5a) UPDATE (회사정보는 수정하지 않음) $sql = "UPDATE qa_posts SET category = :cat, title = :tit, content = :cont, is_secret = :sec, status = :st, updated_at = NOW() WHERE post_id = :pid"; $stmt = $pdo->prepare($sql); $stmt->execute([ ':cat' => $category, ':tit' => $title, ':cont' => $content, ':sec' => $secret, ':st' => $status, ':pid' => $postId, ]); // === (수정 저장 시) 기존 첨부파일 삭제 체크 === if (!empty($_POST['delete_files'])) { foreach ($_POST['delete_files'] as $fileId) { $stmt = $pdo->prepare("SELECT save_path FROM qa_attachments WHERE id=? AND post_id=?"); $stmt->execute([$fileId, $postId]); if ($row = $stmt->fetch()) { $filePath = $_SERVER['DOCUMENT_ROOT'] . $row['save_path']; if (file_exists($filePath)) { unlink($filePath); } $pdo->prepare("DELETE FROM qa_attachments WHERE id=?")->execute([$fileId]); } } } // 새 파일 업로드 추가 handle_file_uploads($pdo, $postId, $errors); if (!empty($errors)) { throw new RuntimeException(implode("\n", $errors)); } } else { // 6-5b) INSERT (내부/외부 분기) if ($isInternal) { // 내부 사용자 → family_company + department $sql = "INSERT INTO qa_posts (login_id, user_id, user_name, family_company, department, phone, is_internal, category, title, content, is_secret, status, created_at) VALUES (:lid, :uid, :uname, :fam, :dept, :phone, :is_internal, :cat, :tit, :cont, :sec, :st, NOW())"; $stmt = $pdo->prepare($sql); $stmt->execute([ ':lid' => $loginId, ':uid' => $userId, ':uname' => ($_SESSION['user']['name'] ?? $_SESSION['user']['userName'] ?? $loginId), ':fam' => $Internal_companyName, ':dept' => $department, ':phone' => ($_SESSION['user']['phone'] ?? ''), ':is_internal' => 1, // ✅ 내부 사용자 → 1 ':cat' => $category, ':tit' => $title, ':cont' => $content, ':sec' => $secret, ':st' => $status, ]); } else { // 외부 사용자 → company + department $sql = "INSERT INTO qa_posts (login_id, user_id, user_name, company, department, phone, is_internal, category, title, content, is_secret, status, created_at) VALUES (:lid, :uid, :uname, :comp, :dept, :phone, :is_internal, :cat, :tit, :cont, :sec, :st, NOW())"; $stmt = $pdo->prepare($sql); $stmt->execute([ ':lid' => $loginId, ':uid' => $userId, ':uname' => ($_SESSION['user']['name'] ?? $_SESSION['user']['userName'] ?? $loginId), ':comp' => $external_companyName, ':dept' => $department, ':phone' => ($_SESSION['user']['phone'] ?? ''), ':is_internal' => 0, // ✅ 외부 사용자 → 0 ':cat' => $category, ':tit' => $title, ':cont' => $content, ':sec' => $secret, ':st' => $status, ]); } $postId = $pdo->lastInsertId(); // 신규 파일 업로드 handle_file_uploads($pdo, $postId, $errors); if (!empty($errors)) { throw new RuntimeException(implode("\n", $errors)); } } $pdo->commit(); // 상세보기로 리다이렉트 header("Location: /egbim/bbs/descope_qa_detail.php?id={$postId}"); exit; } catch (Exception $e) { $pdo->rollBack(); $errors[] = 'DB 오류: ' . $e->getMessage(); } } } // 7) 뷰 렌더링 include __DIR__ . '/../skin/qa/basic/descope_qa_write.skin.php';