262 lines
8.8 KiB
PHP
262 lines
8.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
require_once __DIR__ . '/../db_conn.php';
|
|
|
|
$memberId = (string)($_SESSION['member_id'] ?? '');
|
|
$sysCompCode = (string)($_SESSION['sys_comp_code'] ?? '');
|
|
|
|
if ($memberId === '') {
|
|
http_response_code(401);
|
|
echo json_encode(['success' => false, 'message' => 'not_logged_in'], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
$contentId = trim((string)($_GET['content_id'] ?? ''));
|
|
if ($contentId === '') {
|
|
http_response_code(400);
|
|
echo json_encode(['success' => false, 'message' => 'content_id_required'], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
$pdo = db_conn();
|
|
|
|
$normCode = static function (string $code): string {
|
|
return preg_replace('/[^A-Z0-9]/', '', strtoupper(trim($code)));
|
|
};
|
|
$looksLikeCode = static function (string $value): bool {
|
|
return preg_match('/^[A-Z]{2}[A-Z0-9]{3,}$/', strtoupper(trim($value))) === 1;
|
|
};
|
|
$codeMap = [];
|
|
try {
|
|
$stmtCodeMap = $pdo->query("SELECT base_code, code_name FROM edu_codes");
|
|
foreach ($stmtCodeMap->fetchAll(PDO::FETCH_ASSOC) as $cr) {
|
|
$key = $normCode((string)($cr['base_code'] ?? ''));
|
|
if ($key === '') continue;
|
|
$codeMap[$key] = (string)($cr['code_name'] ?? '');
|
|
}
|
|
} catch (Throwable $ignore) {
|
|
$codeMap = [];
|
|
}
|
|
|
|
// 1) 현재 영상의 키워드 코드 조회
|
|
$keywordCodes = [];
|
|
try {
|
|
$stmtKw = $pdo->prepare('SELECT keyword_code FROM edu_content_keywords WHERE content_id = ?');
|
|
$stmtKw->execute([$contentId]);
|
|
$keywordCodes = $stmtKw->fetchAll(PDO::FETCH_COLUMN) ?: [];
|
|
} catch (Throwable $kwErr) {
|
|
// edu_content_keywords 테이블이 없는 경우 무시 → fallback
|
|
$keywordCodes = [];
|
|
}
|
|
|
|
// 키워드 없으면 같은 카테고리 영상으로 fallback
|
|
if (empty($keywordCodes)) {
|
|
// 현재 영상의 카테고리 조회
|
|
$stmtCat = $pdo->prepare('SELECT category_code FROM edu_contents WHERE content_id = ? LIMIT 1');
|
|
$stmtCat->execute([$contentId]);
|
|
$curCatCode = $stmtCat->fetchColumn();
|
|
|
|
if (!$curCatCode) {
|
|
echo json_encode([
|
|
'success' => true,
|
|
'keywords' => [],
|
|
'videos' => [],
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
$stmtFallback = $pdo->prepare(
|
|
"SELECT c.content_id, c.title, c.content_url, c.thumbnail_url,
|
|
c.category_code, c.category_group, c.description,
|
|
COALESCE(ec.code_name, c.category_code) AS category_name,
|
|
COALESCE(ec_grp.code_name, c.category_group) AS category_group_name
|
|
FROM edu_contents c
|
|
LEFT JOIN edu_codes ec ON TRIM(UPPER(ec.base_code)) = TRIM(UPPER(c.category_code))
|
|
LEFT JOIN edu_codes ec_grp ON TRIM(UPPER(ec_grp.base_code)) = TRIM(UPPER(c.category_group))
|
|
WHERE c.category_code = ?
|
|
AND c.content_id != ?
|
|
AND c.is_active = 1
|
|
ORDER BY c.start_date DESC
|
|
LIMIT 8"
|
|
);
|
|
$stmtFallback->execute([$curCatCode, $contentId]);
|
|
$rows = $stmtFallback->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
|
|
|
$videos = [];
|
|
foreach ($rows as $row) {
|
|
$raw = trim($row['content_url'] ?? '');
|
|
$videoId = '';
|
|
if (preg_match('/(?:v=|youtu\.be\/)([A-Za-z0-9_-]{11})/', $raw, $m)) {
|
|
$videoId = $m[1];
|
|
} elseif (preg_match('/^[A-Za-z0-9_-]{11}$/', $raw)) {
|
|
$videoId = $raw;
|
|
}
|
|
$thumbFromDb = trim($row['thumbnail_url'] ?? '');
|
|
$thumbnail = $thumbFromDb !== ''
|
|
? $thumbFromDb
|
|
: ($videoId !== '' ? "https://img.youtube.com/vi/{$videoId}/sddefault.jpg" : '');
|
|
$catCode = $row['category_code'] ?? '';
|
|
$subcate = trim((string)($row['category_group_name'] ?? $row['category_group'] ?? ''));
|
|
$catName = trim((string)($row['category_name'] ?? $catCode));
|
|
if (($catName === '' || $looksLikeCode($catName)) && $catCode !== '') {
|
|
$mapped = $codeMap[$normCode($catCode)] ?? '';
|
|
if ($mapped !== '') $catName = $mapped;
|
|
}
|
|
$groupRaw = trim((string)($row['category_group'] ?? ''));
|
|
if (($subcate === '' || $looksLikeCode($subcate)) && $groupRaw !== '') {
|
|
$mapped = $codeMap[$normCode($groupRaw)] ?? '';
|
|
if ($mapped !== '') $subcate = $mapped;
|
|
}
|
|
$videos[] = [
|
|
'content_id' => $row['content_id'],
|
|
'title' => $row['title'] ?? '',
|
|
'content_url' => $videoId !== '' ? "https://www.youtube.com/watch?v={$videoId}" : $raw,
|
|
'thumbnail' => $thumbnail,
|
|
'category_code' => $catCode,
|
|
'category' => $catName,
|
|
'category_name' => $catName,
|
|
'subcate' => $subcate,
|
|
'description' => $row['description'] ?? '',
|
|
];
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'keywords' => [],
|
|
'videos' => $videos,
|
|
], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
// 2) 키워드명 조회 (표시용)
|
|
$kwPlaceholders = implode(',', array_fill(0, count($keywordCodes), '?'));
|
|
$keywordNames = [];
|
|
try {
|
|
$stmtKwNames = $pdo->prepare(
|
|
"SELECT keyword_code, keyword_name FROM edu_keywords WHERE keyword_code IN ({$kwPlaceholders})"
|
|
);
|
|
$stmtKwNames->execute($keywordCodes);
|
|
while ($row = $stmtKwNames->fetch(PDO::FETCH_ASSOC)) {
|
|
$keywordNames[] = $row['keyword_name'];
|
|
}
|
|
} catch (Throwable $kwNameErr) {
|
|
$keywordNames = [];
|
|
}
|
|
|
|
// 3) 동일 키워드를 가진 다른 영상 조회 (현재 영상 제외, 랜덤 8개)
|
|
$rows = [];
|
|
try {
|
|
$stmtVideos = $pdo->prepare(
|
|
"SELECT DISTINCT
|
|
c.content_id,
|
|
c.title,
|
|
c.content_url,
|
|
c.thumbnail_url,
|
|
c.category_code,
|
|
c.category_group,
|
|
c.description,
|
|
COALESCE(ec.code_name, c.category_code) AS category_name,
|
|
COALESCE(ec_grp.code_name, c.category_group) AS category_group_name
|
|
FROM edu_contents c
|
|
LEFT JOIN edu_codes ec ON TRIM(UPPER(ec.base_code)) = TRIM(UPPER(c.category_code))
|
|
LEFT JOIN edu_codes ec_grp ON TRIM(UPPER(ec_grp.base_code)) = TRIM(UPPER(c.category_group))
|
|
INNER JOIN edu_content_keywords ck ON ck.content_id = c.content_id
|
|
WHERE ck.keyword_code IN ({$kwPlaceholders})
|
|
AND c.content_id != ?
|
|
AND c.is_active = 1
|
|
ORDER BY RAND()
|
|
LIMIT 8"
|
|
);
|
|
$params = array_merge($keywordCodes, [$contentId]);
|
|
$stmtVideos->execute($params);
|
|
$rows = $stmtVideos->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
|
} catch (Throwable $kwVideoErr) {
|
|
$rows = [];
|
|
}
|
|
|
|
// 키워드 매칭 결과 없으면 같은 카테고리 fallback
|
|
if (empty($rows)) {
|
|
$stmtCat = $pdo->prepare('SELECT category_code FROM edu_contents WHERE content_id = ? LIMIT 1');
|
|
$stmtCat->execute([$contentId]);
|
|
$curCatCode = $stmtCat->fetchColumn();
|
|
if ($curCatCode) {
|
|
$stmtFb = $pdo->prepare(
|
|
"SELECT c.content_id, c.title, c.content_url, c.thumbnail_url,
|
|
c.category_code, c.category_group, c.description,
|
|
COALESCE(ec.code_name, c.category_code) AS category_name,
|
|
COALESCE(ec_grp.code_name, c.category_group) AS category_group_name
|
|
FROM edu_contents c
|
|
LEFT JOIN edu_codes ec ON TRIM(UPPER(ec.base_code)) = TRIM(UPPER(c.category_code))
|
|
LEFT JOIN edu_codes ec_grp ON TRIM(UPPER(ec_grp.base_code)) = TRIM(UPPER(c.category_group))
|
|
WHERE c.category_code = ?
|
|
AND c.content_id != ?
|
|
AND c.is_active = 1
|
|
ORDER BY c.start_date DESC
|
|
LIMIT 8"
|
|
);
|
|
$stmtFb->execute([$curCatCode, $contentId]);
|
|
$rows = $stmtFb->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
|
}
|
|
}
|
|
|
|
$videos = [];
|
|
foreach ($rows as $row) {
|
|
$raw = trim($row['content_url'] ?? '');
|
|
$videoId = '';
|
|
if (preg_match('/(?:v=|youtu\.be\/)([A-Za-z0-9_-]{11})/', $raw, $m)) {
|
|
$videoId = $m[1];
|
|
} elseif (preg_match('/^[A-Za-z0-9_-]{11}$/', $raw)) {
|
|
$videoId = $raw;
|
|
}
|
|
|
|
$thumbFromDb = trim($row['thumbnail_url'] ?? '');
|
|
$thumbnail = $thumbFromDb !== ''
|
|
? $thumbFromDb
|
|
: ($videoId !== '' ? "https://img.youtube.com/vi/{$videoId}/sddefault.jpg" : '');
|
|
|
|
$catCode = $row['category_code'] ?? '';
|
|
$subcate = trim((string)($row['category_group_name'] ?? $row['category_group'] ?? ''));
|
|
$catName = trim((string)($row['category_name'] ?? $catCode));
|
|
if (($catName === '' || $looksLikeCode($catName)) && $catCode !== '') {
|
|
$mapped = $codeMap[$normCode($catCode)] ?? '';
|
|
if ($mapped !== '') $catName = $mapped;
|
|
}
|
|
$groupRaw = trim((string)($row['category_group'] ?? ''));
|
|
if (($subcate === '' || $looksLikeCode($subcate)) && $groupRaw !== '') {
|
|
$mapped = $codeMap[$normCode($groupRaw)] ?? '';
|
|
if ($mapped !== '') $subcate = $mapped;
|
|
}
|
|
|
|
$videos[] = [
|
|
'content_id' => $row['content_id'],
|
|
'title' => $row['title'] ?? '',
|
|
'content_url' => $videoId !== '' ? "https://www.youtube.com/watch?v={$videoId}" : $raw,
|
|
'thumbnail' => $thumbnail,
|
|
'category_code' => $catCode,
|
|
'category' => $catName,
|
|
'category_name' => $catName,
|
|
'subcate' => $subcate,
|
|
'description' => $row['description'] ?? '',
|
|
];
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'keywords' => $keywordNames,
|
|
'videos' => $videos,
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
} catch (Throwable $e) {
|
|
error_log('[get_recommend_videos] ' . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode(['success' => false, 'message' => 'server_error'], JSON_UNESCAPED_UNICODE);
|
|
}
|