'error', 'message' => 'API Key file not found.']); exit; } $apiKey = trim(file_get_contents($apiKeyPath)); if (empty($apiKey)) { echo json_encode(['status' => 'error', 'message' => 'API Key is empty.']); exit; } // Data Directory $dataDir = $_SERVER['DOCUMENT_ROOT'] . '/opendart/data'; if (!is_dir($dataDir)) { if (!mkdir($dataDir, 0777, true)) { echo json_encode(['status' => 'error', 'message' => 'Failed to create data directory.']); exit; } } // Check if ZipArchive extension is available if (!class_exists('ZipArchive')) { echo json_encode(['status' => 'error', 'message' => 'ZipArchive extension is not available. Please enable php_zip extension.']); exit; } // Open DART URL $url = "https://opendart.fss.or.kr/api/corpCode.xml?crtfc_key=" . $apiKey; // Download Zip $zipFile = $dataDir . '/corpCode.zip'; // Remove old zip file if exists if (file_exists($zipFile)) { @unlink($zipFile); } $fp = @fopen($zipFile, 'w+'); if (!$fp) { echo json_encode(['status' => 'error', 'message' => 'Failed to create zip file. Check directory permissions.']); exit; } $ch = curl_init($url); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_MAXREDIRS, 5); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_TIMEOUT, 300); // 5 minutes timeout curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); $effectiveUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); curl_close($ch); fclose($fp); if ($httpCode !== 200) { $errorContent = ''; if (file_exists($zipFile)) { $errorContent = file_get_contents($zipFile); @unlink($zipFile); } // Check if it's an IP access error from Open DART if ($errorContent && strpos($errorContent, '접근할 수 없는 IP') !== false || strpos($errorContent, 'Inaccessible IP') !== false) { // Parse XML error response $xml = @simplexml_load_string($errorContent); $errorMessage = ''; $reportedIP = ''; if ($xml && isset($xml->message)) { $errorMessage = (string)$xml->message; // Extract IP from message if present if (preg_match('/\(([0-9\.]+)\)/', $errorMessage, $matches)) { $reportedIP = $matches[1]; } } else { $errorMessage = 'IP 접근이 거부되었습니다.'; } // Get actual server IP $actualIP = getServerPublicIP(); $ipErrorMsg = "Open DART IP 접근 오류: $errorMessage"; if ($reportedIP) { $ipErrorMsg .= "\n\nOpen DART에서 감지한 IP: $reportedIP"; } $ipErrorMsg .= "\n현재 서버의 공인 IP: $actualIP"; $ipErrorMsg .= "\n\n해결 방법:"; $ipErrorMsg .= "\n1. Open DART 홈페이지(https://opendart.fss.or.kr)에 로그인"; $ipErrorMsg .= "\n2. '회원정보 > API 인증키 관리' 메뉴로 이동"; $ipErrorMsg .= "\n3. '사용IP' 항목에 위의 '현재 서버의 공인 IP'를 등록하거나 수정"; $ipErrorMsg .= "\n4. 변경 사항 저장 후 몇 분 대기 후 다시 시도"; echo json_encode([ 'status' => 'error', 'message' => $ipErrorMsg, 'error_type' => 'ip_access_denied', 'reported_ip' => $reportedIP, 'actual_ip' => $actualIP ]); exit; } $debugMsg = "HTTP Code: $httpCode"; if ($curlError) { $debugMsg .= ", cURL Error: $curlError"; } if ($effectiveUrl) { $debugMsg .= ", Effective URL: $effectiveUrl"; } if ($errorContent) { $debugMsg .= ", Content Preview: " . substr($errorContent, 0, 500); } echo json_encode(['status' => 'error', 'message' => 'Failed to download data. ' . $debugMsg]); exit; } // Verify downloaded file if (!file_exists($zipFile)) { echo json_encode(['status' => 'error', 'message' => 'Downloaded file does not exist.']); exit; } $fileSize = filesize($zipFile); if ($fileSize === false || $fileSize < 100) { // File too small, likely an error message $errorContent = file_get_contents($zipFile); @unlink($zipFile); echo json_encode(['status' => 'error', 'message' => 'Downloaded file is too small or invalid. Content: ' . substr($errorContent, 0, 500)]); exit; } // Check if file is actually a ZIP file (check magic bytes) $handle = fopen($zipFile, 'rb'); $magicBytes = fread($handle, 4); fclose($handle); // ZIP file magic bytes: PK\x03\x04 or PK\x05\x06 (empty zip) or PK\x07\x08 if (substr($magicBytes, 0, 2) !== 'PK') { $errorContent = file_get_contents($zipFile); @unlink($zipFile); // Check if it's an XML error response from Open DART (IP access error) if (strpos($errorContent, 'message)) { $errorMessage = (string)$xml->message; if (preg_match('/\(([0-9\.]+)\)/', $errorMessage, $matches)) { $reportedIP = $matches[1]; } } else { $errorMessage = 'IP 접근이 거부되었습니다.'; } // Get actual server IP $actualIP = getServerPublicIP(); $ipErrorMsg = "Open DART IP 접근 오류: $errorMessage"; if ($reportedIP) { $ipErrorMsg .= "\n\nOpen DART에서 감지한 IP: $reportedIP"; } $ipErrorMsg .= "\n현재 서버의 공인 IP: $actualIP"; $ipErrorMsg .= "\n\n해결 방법:"; $ipErrorMsg .= "\n1. Open DART 홈페이지(https://opendart.fss.or.kr)에 로그인"; $ipErrorMsg .= "\n2. '회원정보 > API 인증키 관리' 메뉴로 이동"; $ipErrorMsg .= "\n3. '사용IP' 항목에 위의 '현재 서버의 공인 IP'를 등록하거나 수정"; $ipErrorMsg .= "\n4. 변경 사항 저장 후 몇 분 대기 후 다시 시도"; echo json_encode([ 'status' => 'error', 'message' => $ipErrorMsg, 'error_type' => 'ip_access_denied', 'reported_ip' => $reportedIP, 'actual_ip' => $actualIP ]); exit; } echo json_encode(['status' => 'error', 'message' => 'Downloaded file is not a valid ZIP file. Content: ' . substr($errorContent, 0, 500)]); exit; } // Unzip $zip = new ZipArchive; $zipResult = $zip->open($zipFile); if ($zipResult !== TRUE) { $errorMessages = [ ZipArchive::ER_OK => 'No error', ZipArchive::ER_MULTIDISK => 'Multi-disk zip archives not supported', ZipArchive::ER_RENAME => 'Renaming temporary file failed', ZipArchive::ER_CLOSE => 'Closing zip archive failed', ZipArchive::ER_SEEK => 'Seek error', ZipArchive::ER_READ => 'Read error', ZipArchive::ER_WRITE => 'Write error', ZipArchive::ER_CRC => 'CRC error', ZipArchive::ER_ZIPCLOSED => 'Containing zip archive was closed', ZipArchive::ER_NOENT => 'No such file', ZipArchive::ER_EXISTS => 'File already exists', ZipArchive::ER_OPEN => 'Can\'t open file', ZipArchive::ER_TMPOPEN => 'Failure to create temporary file', ZipArchive::ER_ZLIB => 'Zlib error', ZipArchive::ER_MEMORY => 'Memory allocation failure', ZipArchive::ER_CHANGED => 'Entry has been changed', ZipArchive::ER_COMPNOTSUPP => 'Compression method not supported', ZipArchive::ER_EOF => 'Premature EOF', ZipArchive::ER_INVAL => 'Invalid argument', ZipArchive::ER_NOZIP => 'Not a zip archive', ZipArchive::ER_INTERNAL => 'Internal error', ZipArchive::ER_INCONS => 'Zip archive inconsistent', ZipArchive::ER_REMOVE => 'Can\'t remove file', ZipArchive::ER_DELETED => 'Entry has been deleted', ]; $errorMsg = isset($errorMessages[$zipResult]) ? $errorMessages[$zipResult] : "Unknown error (Code: $zipResult)"; echo json_encode(['status' => 'error', 'message' => 'Failed to unzip file. ' . $errorMsg . ' (Error Code: ' . $zipResult . ')']); exit; } // Extract to data directory if (!$zip->extractTo($dataDir)) { $zip->close(); echo json_encode(['status' => 'error', 'message' => 'Failed to extract files from zip. Check directory permissions.']); exit; } $zip->close(); // Parse XML $xmlFile = $dataDir . '/CORPCODE.xml'; if (!file_exists($xmlFile)) { echo json_encode(['status' => 'error', 'message' => 'XML file not found in zip.']); exit; } $xml = simplexml_load_file($xmlFile); $jsonArray = []; foreach ($xml->list as $item) { $corp_code = (string)$item->corp_code; $corp_name = (string)$item->corp_name; $stock_code = (string)$item->stock_code; // optional $modify_date = (string)$item->modify_date; $jsonArray[] = [ 'corp_code' => $corp_code, 'corp_name' => $corp_name, 'stock_code' => $stock_code, 'modify_date' => $modify_date ]; } // Save to JSON $jsonFile = $dataDir . '/corp_codes.json'; if (file_put_contents($jsonFile, json_encode($jsonArray, JSON_UNESCAPED_UNICODE))) { echo json_encode([ 'status' => 'success', 'message' => 'Data synced successfully.', 'count' => count($jsonArray), 'timestamp' => date('Y-m-d H:i:s') ]); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to save JSON data.']); } ?>