정정: DrugImg 이미지키와 외부 URL 검증 추가
- DrugImg.DIK_CODE 44자 Base64 image key 가능성 문서화 - 평문 DIK_CODE 직접 join 단정 제거 - health.kr zoom 후보 URL과 실제 이미지 GET 검증 스크립트 추가
This commit is contained in:
96
scripts/probe_drugimg_keys.py
Normal file
96
scripts/probe_drugimg_keys.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Probe PIT/PM drug image key assumptions.
|
||||
|
||||
This script is intentionally read-only. It does not require production credentials in the repo;
|
||||
wire `query_rows()` to pyodbc/pymssql in your environment.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
def classify_key(value: str) -> dict:
|
||||
value = value or ''
|
||||
out = {'value': value, 'length': len(value), 'kind': 'unknown'}
|
||||
if re.fullmatch(r'\d{13}', value):
|
||||
out['kind'] = 'plain_13_digit_dik_code'
|
||||
return out
|
||||
try:
|
||||
raw = base64.b64decode(value, validate=True)
|
||||
out['base64_bytes'] = len(raw)
|
||||
out['base64_hex_prefix'] = raw[:8].hex()
|
||||
if len(value) == 44 and len(raw) == 32:
|
||||
out['kind'] = 'base64_32byte_digest_like_key'
|
||||
else:
|
||||
out['kind'] = 'base64_other'
|
||||
except Exception:
|
||||
out['kind'] = 'non_base64_text'
|
||||
return out
|
||||
|
||||
|
||||
def sha256_b64_candidates(plain: str) -> dict:
|
||||
return {
|
||||
enc: base64.b64encode(hashlib.sha256(plain.encode(enc)).digest()).decode()
|
||||
for enc in ['utf-8', 'cp949', 'utf-16le']
|
||||
}
|
||||
|
||||
|
||||
def probe_url(url: str, referer: str | None = None, timeout: int = 10) -> dict:
|
||||
headers = {'User-Agent': 'Mozilla/5.0'}
|
||||
if referer:
|
||||
headers['Referer'] = referer
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as r:
|
||||
head = r.read(32)
|
||||
return {
|
||||
'url': url,
|
||||
'ok': True,
|
||||
'status': r.status,
|
||||
'content_type': r.headers.get('content-type'),
|
||||
'content_length': r.headers.get('content-length'),
|
||||
'head_hex': head.hex(),
|
||||
'is_jpeg': head.startswith(b'\xff\xd8\xff'),
|
||||
}
|
||||
except Exception as e:
|
||||
return {'url': url, 'ok': False, 'error': f'{type(e).__name__}: {e}'}
|
||||
|
||||
|
||||
def extract_zoom_image_candidates(dik_code: str) -> dict:
|
||||
url = f'https://www.health.kr/drug_info/sb/zoom.asp?drug_code={dik_code}'
|
||||
result = {'zoom_url': url, 'ok': False, 'candidates': []}
|
||||
try:
|
||||
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
|
||||
with urllib.request.urlopen(req, timeout=15) as r:
|
||||
data = r.read(300000)
|
||||
# health.kr pages are usually euc-kr/cp949-ish.
|
||||
text = data.decode('euc-kr', errors='replace')
|
||||
result['ok'] = True
|
||||
imgs = re.findall(r'''(?:src|myImg\.src)\s*=\s*['\"]([^'\"]+)''', text, flags=re.I)
|
||||
paths = re.findall(r'''https?://[^'\"<>\s]+(?:sb_photo|big3|marked3)[^'\"<>\s]+''', text, flags=re.I)
|
||||
result['candidates'] = sorted(set(imgs + paths))
|
||||
except Exception as e:
|
||||
result['error'] = f'{type(e).__name__}: {e}'
|
||||
return result
|
||||
|
||||
|
||||
def demo():
|
||||
# Replace these with real rows from PM_DRUG..CD_GOODS and PM_IMAGE..DrugImg.
|
||||
plain_dik = '2015012700008'
|
||||
image_key = 'xiY4jUZTAZB0p8JpHEa+Zt9DEcOVQFq9sgtAxSG7GXY='
|
||||
print(json.dumps({
|
||||
'plain_dik': classify_key(plain_dik),
|
||||
'image_key': classify_key(image_key),
|
||||
'sha256_plain_candidates': sha256_b64_candidates(plain_dik),
|
||||
'direct_big3': probe_url(f'http://pharm.or.kr/images/sb_photo/big3/{plain_dik}.jpg'),
|
||||
'zoom_candidates': extract_zoom_image_candidates(plain_dik),
|
||||
}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
demo()
|
||||
Reference in New Issue
Block a user