초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
This commit is contained in:
48
opendart/api/detail.php
Normal file
48
opendart/api/detail.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Open DART 기업개황 조회 API (프록시 방식)
|
||||
*
|
||||
* 멀티테넌시 환경 지원:
|
||||
* - 클라이언트의 IP가 아닌 서버의 IP로 Open DART API 호출
|
||||
* - Open DART에 등록된 서버 IP만 사용하므로 여러 클라이언트 지원 가능
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 클라이언트 → 회사 서버 (이 파일) → Open DART API → 회사 서버 → 클라이언트
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 프록시 헬퍼 함수 로드
|
||||
require_once __DIR__ . '/proxy_helper.php';
|
||||
|
||||
$corp_code = isset($_GET['corp_code']) ? trim($_GET['corp_code']) : '';
|
||||
|
||||
if (empty($corp_code)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Corp Code is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 프록시를 통해 Open DART API 호출
|
||||
$result = callOpenDartAPI('company.json', [
|
||||
'corp_code' => $corp_code
|
||||
], null, [
|
||||
'timeout' => 30,
|
||||
'return_type' => 'raw' // Open DART의 JSON 응답을 그대로 반환
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
// Open DART의 원본 응답 형식 유지
|
||||
if ($result['raw_response']) {
|
||||
echo $result['raw_response'];
|
||||
} else {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => $result['error']
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Open DART의 원본 JSON 응답을 그대로 반환
|
||||
echo $result['raw_response'];
|
||||
?>
|
||||
82
opendart/api/financial_statement.php
Normal file
82
opendart/api/financial_statement.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Open DART 재무제표 조회 API (프록시 방식)
|
||||
*
|
||||
* 특정 기업의 재무제표 정보를 조회합니다.
|
||||
*
|
||||
* 파라미터:
|
||||
* - corp_code: 기업코드 (필수)
|
||||
* - bsns_year: 사업연도 (YYYY 형식, 필수)
|
||||
* - reprt_code: 보고서 코드 (11013: 1분기, 11012: 반기, 11014: 3분기, 11011: 사업보고서)
|
||||
* - fs_div: 재무제표 구분 (CFS: 연결, OFS: 별도)
|
||||
*
|
||||
* 사용 예시:
|
||||
* /api/financial_statement.php?corp_code=00126380&bsns_year=2023&reprt_code=11011&fs_div=CFS
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 프록시 헬퍼 함수 로드
|
||||
require_once __DIR__ . '/proxy_helper.php';
|
||||
|
||||
$corp_code = isset($_GET['corp_code']) ? trim($_GET['corp_code']) : '';
|
||||
$bsns_year = isset($_GET['bsns_year']) ? trim($_GET['bsns_year']) : '';
|
||||
$reprt_code = isset($_GET['reprt_code']) ? trim($_GET['reprt_code']) : '11011'; // 기본값: 사업보고서
|
||||
$fs_div = isset($_GET['fs_div']) ? trim($_GET['fs_div']) : 'CFS'; // 기본값: 연결
|
||||
|
||||
if (empty($corp_code)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Corp Code is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($bsns_year)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Business Year (bsns_year) is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 파라미터 구성
|
||||
$params = [
|
||||
'corp_code' => $corp_code,
|
||||
'bsns_year' => $bsns_year,
|
||||
'reprt_code' => $reprt_code,
|
||||
'fs_div' => $fs_div
|
||||
];
|
||||
|
||||
// 프록시를 통해 Open DART API 호출
|
||||
$result = callOpenDartAPI('fnlttSinglAcnt.json', $params, null, [
|
||||
'timeout' => 30,
|
||||
'return_type' => 'raw' // Open DART의 JSON 응답을 그대로 반환
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
// Open DART의 원본 응답 형식 유지
|
||||
if (isset($result['raw_response']) && !empty($result['raw_response'])) {
|
||||
echo $result['raw_response'];
|
||||
} else {
|
||||
// 에러 응답 형식을 Open DART 형식에 맞춤
|
||||
echo json_encode([
|
||||
'status' => '013',
|
||||
'message' => $result['error'] || '재무제표 조회 중 오류가 발생했습니다.',
|
||||
'status_nm' => 'ERROR'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Open DART의 원본 JSON 응답을 그대로 반환
|
||||
if (isset($result['raw_response']) && !empty($result['raw_response'])) {
|
||||
echo $result['raw_response'];
|
||||
} else {
|
||||
// raw_response가 없는 경우 data 사용
|
||||
if (isset($result['data'])) {
|
||||
echo json_encode($result['data'], JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'status' => '013',
|
||||
'message' => '재무제표 데이터를 가져올 수 없습니다.',
|
||||
'status_nm' => 'ERROR'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
70
opendart/api/list_disclosures.php
Normal file
70
opendart/api/list_disclosures.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Open DART 공시목록 조회 API (프록시 방식)
|
||||
*
|
||||
* 특정 기업의 공시 목록을 조회합니다.
|
||||
*
|
||||
* 파라미터:
|
||||
* - corp_code: 기업코드 (필수)
|
||||
* - bgn_de: 시작일자 (YYYYMMDD 형식, 선택)
|
||||
* - end_de: 종료일자 (YYYYMMDD 형식, 선택)
|
||||
* - page_no: 페이지 번호 (기본값: 1)
|
||||
* - page_count: 페이지당 건수 (기본값: 100)
|
||||
*
|
||||
* 사용 예시:
|
||||
* /api/list_disclosures.php?corp_code=00126380&bgn_de=20240101&end_de=20241231
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 프록시 헬퍼 함수 로드
|
||||
require_once __DIR__ . '/proxy_helper.php';
|
||||
|
||||
$corp_code = isset($_GET['corp_code']) ? trim($_GET['corp_code']) : '';
|
||||
$bgn_de = isset($_GET['bgn_de']) ? trim($_GET['bgn_de']) : '';
|
||||
$end_de = isset($_GET['end_de']) ? trim($_GET['end_de']) : '';
|
||||
$page_no = isset($_GET['page_no']) ? intval($_GET['page_no']) : 1;
|
||||
$page_count = isset($_GET['page_count']) ? intval($_GET['page_count']) : 100;
|
||||
|
||||
if (empty($corp_code)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Corp Code is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 파라미터 구성
|
||||
$params = [
|
||||
'corp_code' => $corp_code,
|
||||
'page_no' => $page_no,
|
||||
'page_count' => $page_count
|
||||
];
|
||||
|
||||
if (!empty($bgn_de)) {
|
||||
$params['bgn_de'] = $bgn_de;
|
||||
}
|
||||
if (!empty($end_de)) {
|
||||
$params['end_de'] = $end_de;
|
||||
}
|
||||
|
||||
// 프록시를 통해 Open DART API 호출
|
||||
$result = callOpenDartAPI('list.json', $params, null, [
|
||||
'timeout' => 30,
|
||||
'return_type' => 'raw' // Open DART의 JSON 응답을 그대로 반환
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
// Open DART의 원본 응답 형식 유지
|
||||
if ($result['raw_response']) {
|
||||
echo $result['raw_response'];
|
||||
} else {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => $result['error']
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Open DART의 원본 JSON 응답을 그대로 반환
|
||||
echo $result['raw_response'];
|
||||
?>
|
||||
|
||||
184
opendart/api/proxy_helper.php
Normal file
184
opendart/api/proxy_helper.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* Open DART API Proxy Helper
|
||||
*
|
||||
* 멀티테넌시 환경을 위한 프록시 함수
|
||||
* 클라이언트의 IP 대신 서버의 IP로 Open DART API를 호출하여
|
||||
* IP 화이트리스트 제한을 우회합니다.
|
||||
*
|
||||
* 동작 방식:
|
||||
* 1. 클라이언트 요청 → 회사 서버 (이 파일)
|
||||
* 2. 회사 서버 → Open DART API (등록된 IP로 호출)
|
||||
* 3. Open DART 응답 → 회사 서버
|
||||
* 4. 회사 서버 → 클라이언트
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open DART API를 프록시를 통해 호출
|
||||
*
|
||||
* @param string $endpoint Open DART API 엔드포인트 (예: 'company.json', 'corpCode.xml')
|
||||
* @param array $params API 파라미터 배열
|
||||
* @param string $apiKey Open DART API 키 (null이면 기본 파일에서 로드)
|
||||
* @param array $options 추가 옵션 (timeout, method 등)
|
||||
* @return array ['success' => bool, 'data' => mixed, 'error' => string]
|
||||
*/
|
||||
function callOpenDartAPI($endpoint, $params = [], $apiKey = null, $options = []) {
|
||||
// API Key 로드
|
||||
if ($apiKey === null) {
|
||||
$apiKeyPath = $_SERVER['DOCUMENT_ROOT'] . '/apikey/opendart.txt';
|
||||
if (!file_exists($apiKeyPath)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'data' => null,
|
||||
'error' => 'API Key file not found.'
|
||||
];
|
||||
}
|
||||
$apiKey = trim(file_get_contents($apiKeyPath));
|
||||
}
|
||||
|
||||
if (empty($apiKey)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'data' => null,
|
||||
'error' => 'API Key is empty.'
|
||||
];
|
||||
}
|
||||
|
||||
// 기본 옵션
|
||||
$defaultOptions = [
|
||||
'timeout' => 30,
|
||||
'method' => 'GET',
|
||||
'return_type' => 'json', // 'json' or 'xml' or 'raw'
|
||||
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||
];
|
||||
$options = array_merge($defaultOptions, $options);
|
||||
|
||||
// 파라미터에 API 키 추가
|
||||
$params['crtfc_key'] = $apiKey;
|
||||
|
||||
// URL 구성
|
||||
$baseUrl = 'https://opendart.fss.or.kr/api/';
|
||||
$url = $baseUrl . $endpoint;
|
||||
|
||||
if ($options['method'] === 'GET' && !empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
// cURL 설정
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $options['timeout']);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $options['user_agent']);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
|
||||
|
||||
// POST 요청 처리 (필요한 경우)
|
||||
if ($options['method'] === 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
|
||||
}
|
||||
|
||||
// 실행
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlError = curl_error($ch);
|
||||
$effectiveUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
||||
curl_close($ch);
|
||||
|
||||
// 에러 처리
|
||||
if ($httpCode !== 200 || !$response) {
|
||||
$errorMsg = 'Failed to fetch data from Open DART.';
|
||||
if ($curlError) {
|
||||
$errorMsg .= ' cURL Error: ' . $curlError;
|
||||
}
|
||||
if ($httpCode) {
|
||||
$errorMsg .= ' HTTP Code: ' . $httpCode;
|
||||
}
|
||||
|
||||
// IP 접근 오류 체크
|
||||
if ($response && (strpos($response, '접근할 수 없는 IP') !== false || strpos($response, 'Inaccessible IP') !== false)) {
|
||||
$xml = @simplexml_load_string($response);
|
||||
if ($xml && isset($xml->message)) {
|
||||
$errorMsg = 'IP 접근 오류: ' . (string)$xml->message;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'data' => null,
|
||||
'error' => $errorMsg,
|
||||
'http_code' => $httpCode,
|
||||
'raw_response' => $response
|
||||
];
|
||||
}
|
||||
|
||||
// 응답 처리
|
||||
$data = $response;
|
||||
|
||||
if ($options['return_type'] === 'json') {
|
||||
$decoded = json_decode($response, true);
|
||||
if ($decoded !== null) {
|
||||
$data = $decoded;
|
||||
}
|
||||
} elseif ($options['return_type'] === 'xml') {
|
||||
$xml = @simplexml_load_string($response);
|
||||
if ($xml !== false) {
|
||||
$data = $xml;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $data,
|
||||
'error' => null,
|
||||
'http_code' => $httpCode,
|
||||
'raw_response' => $response
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버의 공인 IP 확인
|
||||
*
|
||||
* @return string 공인 IP 주소
|
||||
*/
|
||||
function getServerPublicIP() {
|
||||
// Try multiple methods to get public IP
|
||||
$ipServices = [
|
||||
'https://api.ipify.org',
|
||||
'https://checkip.amazonaws.com',
|
||||
'https://icanhazip.com',
|
||||
'https://ifconfig.me/ip'
|
||||
];
|
||||
|
||||
foreach ($ipServices as $service) {
|
||||
$ch = curl_init($service);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
$ip = trim(curl_exec($ch));
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode === 200 && filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try to get from $_SERVER
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||
$ip = trim($ips[0]);
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
?>
|
||||
|
||||
51
opendart/api/search.php
Normal file
51
opendart/api/search.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = isset($_GET['query']) ? trim($_GET['query']) : '';
|
||||
|
||||
if (empty($query)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Query is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/opendart/data/corp_codes.json';
|
||||
|
||||
if (!file_exists($jsonFile)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Data not synced. Please click "Sync Data" first.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$jsonData = @file_get_contents($jsonFile);
|
||||
if ($jsonData === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to read data file. Check file permissions.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$corpList = json_decode($jsonData, true);
|
||||
|
||||
if ($corpList === null) {
|
||||
$jsonError = json_last_error_msg();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid data file. JSON Error: ' . $jsonError]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!is_array($corpList)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid data format. Expected array.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$results = [];
|
||||
$count = 0;
|
||||
$limit = 50; // Limit results
|
||||
|
||||
foreach ($corpList as $corp) {
|
||||
// Simple case-insensitive search
|
||||
if (stripos($corp['corp_name'], $query) !== false) {
|
||||
$results[] = $corp;
|
||||
$count++;
|
||||
if ($count >= $limit) break;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['status' => 'success', 'results' => $results]);
|
||||
?>
|
||||
290
opendart/api/sync_corpcode.php
Normal file
290
opendart/api/sync_corpcode.php
Normal file
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* Open DART 기업코드 동기화 API (프록시 방식)
|
||||
*
|
||||
* 멀티테넌시 환경 지원:
|
||||
* - 클라이언트의 IP가 아닌 서버의 IP로 Open DART API 호출
|
||||
* - Open DART에 등록된 서버 IP만 사용하므로 여러 클라이언트 지원 가능
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 클라이언트 → 회사 서버 (이 파일) → Open DART API (ZIP 다운로드) → 회사 서버 (압축 해제 및 JSON 변환) → 클라이언트
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 프록시 헬퍼 함수 로드
|
||||
require_once __DIR__ . '/proxy_helper.php';
|
||||
|
||||
// API Key Load
|
||||
$apiKeyPath = $_SERVER['DOCUMENT_ROOT'] . '/apikey/opendart.txt';
|
||||
if (!file_exists($apiKeyPath)) {
|
||||
echo json_encode(['status' => '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, '<?xml') !== false && (strpos($errorContent, '접근할 수 없는 IP') !== false || strpos($errorContent, 'Inaccessible IP') !== false)) {
|
||||
$xml = @simplexml_load_string($errorContent);
|
||||
$errorMessage = '';
|
||||
$reportedIP = '';
|
||||
|
||||
if ($xml && isset($xml->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.']);
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user