Skip to Content
Go Back
안형우

안녕하세요. 14년차 풀스택 웹개발자 안형우입니다. 이 블로그에서는 WordPress, PHP, CSS, 사용성, 리눅스 서버 등 풀스택 웹개발에서 마주하는 다양한 문제 상황과 해결책, 필요한 개념들을 다룹니다. 👉 소개


작업물

📌 워드프레스, 답답한 빌더와 플러그인 대신 시원하게 커스터마징하기 2023-01-15
📌 아무도 말하지 않는 PHP의 좋은 점 2018-10-13
📌 유지보수하기 쉬운 CSS 전략(슬라이드) 2016-12-20
📌 워드프레스 테마에서 템플릿 파일 매칭 순서 2013-05-12

우체국의 우편번호 API를 이용해 우편번호 검색 서비스를 만들어 보자 – 서버단

[우체국의 API는 구주소만 서비스한다. 도로명 주소를 검색하려면 공공데이터포털을 이용해야 한다. 우체국 API를 이용해 구주소를 검색하는 이 예제도 2014-01-10 현재 잘 돌아간다. 공공데이터포털을 이용할 사람은 내가 쓴 공공데이터포털의 우편번호 API 정리 글을 참고하라.]

예전에 우체국이 제공하는 우편번호 API에 대해 쓴 적이 있었다.

당시 나는 세 가지 문제에 봉착했다.

  1. ajax 호출이 되지 않는다.
  2. 테스트를 해 보려고 url로 적으면, IE에서는 보이는데 크롬과 파이어폭스에서는 보이지 않는다.
  3. file_get_contents로 긁어도 안 된다.

그래서 포기했었다. 그냥 DB를 이용했다. 그렇게 하니 최신 우편번호를 적용하기 위해 DB를 매번 갱신해 줘야 했다.

시간이 지나고 많은 것을 알게 됐다. 일단 다른 domain에 있는 놈을 ajax 호출하는 것은 안 된다는 것을 알게 됐다. 그래서 1번 문제가 해결됐다.

2번 문제는, URL로 접근할 때나 문제지 호출할 때 그 자체로는 문제가 되지 않으며 POST로 값을 넘기면 된다는 사실을 알게 됐다. 그래서 해결.

3번 문제는, file_get_contentsGET 방식으로만 값을 넘길 수 있어서 그랬던 것이라는 점을 인지했다. 그래서 file_get_contents가 아닌, POST로 값을 넘겨 응답을 받을 수 있는 PHP 함수를 찾기로 결심!, 그리고 드디어 찾았다.

▶예제 보기 | ▶코드 다운로드

우체국 우편번호 API 신청 페이지

(최근에 1day1님의 블로그에서 file_get_contents 함수로 우편번호 API를 사용할 수 있게 하는 글을 찾았다. 옵션을 줘야 한다. 저 글에서 제시하는 예제 코드는 아래와 같다.)

$api_key = "우체국에서 받은 API KEY";
$epost_url = "http://biz.epost.go.kr/KpostPortal/openapi?regkey=$api_key&target=post&query=을지로3가"; 

$opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: ko\r\n"
  )
);

$context = stream_context_create($opts);

$fp = file_get_contents($epost_url , false, $context);

cURL로 가져오기

내가 사용한 방법은 PHP의 cURL 라이브러리를 사용한다. 웬만한 호스팅에는 설치돼 있을 거다. 우분투 사용자들이라면 아래 명령어로 간단하게 설치할 수 있다.

sudo apt-get install php5-curl

(혹시나 해서 덧붙이는데, 설치한 다음 아파치를 재시작해야 적용된다.)

cURL을 이용해 웹페이지의 내용을 읽어 오는 함수

이 함수는 [bluesunh님의 노트] cURL Library를 참고했다. (스프링노트 폭파로 링크 유실)

function fetch_page($url,$param,$cookies=NULL,$referer_url=NULL){
    if(strlen(trim($referer_url)) == 0) $referer_url= $url;
    $curlsession = curl_init ();
    curl_setopt ($curlsession, CURLOPT_URL, $url);
    curl_setopt ($curlsession, CURLOPT_POST, 1);
    curl_setopt ($curlsession, CURLOPT_POSTFIELDS, $param);
    //curl_setopt ($curlsession, CURLOPT_POSTFIELDSIZE, 0);
    curl_setopt ($curlsession, CURLOPT_TIMEOUT, 60);
    if($cookies && $cookies!=""){
        curl_setopt ($curlsession, CURLOPT_COOKIE, $cookies);
    }
    curl_setopt ($curlsession, CURLOPT_HEADER, 1); //헤더값을 가져오기위해 사용합니다. 쿠키를 가져오려고요.
    curl_setopt ($curlsession, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 6.0)");
    curl_setopt ($curlsession, CURLOPT_REFERER, "$referer_url"); 

    ob_start();
    $res = curl_exec ($curlsession);
    $buffer = ob_get_contents();
    ob_end_clean();
    $returnVal = array();
    if (!$buffer) {
    	$returnVal['error'] = true;
        $returnVal['content'] = "Curl Fetch Error : ".curl_error($curlsession);
    }else{
    	$returnVal['error'] = false;
        $returnVal['content'] = $buffer;
    }
    curl_close($curlsession);
    return $returnVal;
}

우편번호 오픈 API에서 xml을 받아 오는 함수

자, 그럼 이제 우편번호 오픈 API에서 xml을 받아 오는 함수를 만들어 보자. 이 함수는 위 함수를 사용한다.

function get_post_code_xml_by_api($query){
	$query = iconv('utf-8','euc-kr',$query);

	$post_data = array(
	    'target' => 'post',
	    'regkey' => '1234567890', //자신의 키를 입력
	    'query' => $query
	);

	$url = 'http://biz.epost.go.kr/KpostPortal/openapi';
	$param = http_build_query($post_data);
	$result = fetch_page($url,$param);
	$result['content'] = remove_none_xml_word($result['content']);

	return $result;
}

위에서 regkey 는 우편번호 오픈 API 웹사이트에 가서 등록을 한 후 받으면 된다.

$param을 만드는 데 사용한 http_build_query 함수는 내가 쓴 설명을 참고하면 된다.

$query를 받아서 iconv 함수를 이용해 euc-kr로 변환해 줬는데, 내가 기본으로 utf-8 인코딩을 사용한다고 가정했기 때문이다.

위에서 return 직전에 remove_none_xml_word 라는 함수가 보일 거다.

그 놈은 cURL이 넘겨주는 header 값을 지워 버리고 순수 xml만 남기기 위한 함수다. 그놈을 만들어 보자.

function remove_none_xml_word($content){
	$content_array = explode("\n", $content);
	foreach ($content_array as $key => $value) {
		if(substr(trim($value),0,1)!='<'){
			$content_array[$key]='';
		}
	}
	unset($content_array[0]);
	$content = implode("\n", $content_array);
	return trim($content);
}

위에서 unset 함수를 쓴 이유는, 첫 줄이 빈 줄이기 때문이다. 첫 줄이 빈 줄이면 XML 파싱할 때 에러난다.

우편번호에 대시(-)를 넣어 주는 함수

우편번호 오픈 API는 우편번호를 그냥 123456형식으로 넘겨 준다. 사이에 -를 넣어 보기 좋게 만들어야 사용자들에게 좋을 거다.

또한 그러면서 앞 번호와 뒷 번호를 구분하기 위해 span으로 감싸고 클래스를 매겼다. postcd1, postcd2 하는 식으로 말이다.

function add_dash_and_tag_to_postcd($postcd){
	$postcd1=substr($postcd,0,3);
	$postcd2=substr($postcd,3,3);
	return "<span class="postcd1">$postcd1</span>-<span class="postcd2">$postcd2</span>";
}

HTML을 뿌려 주는 함수

이런 함수들을 바탕으로 이제 HTML을 뿌려 주는 함수를 만들어 보자.

function print_postcode_table($xml){
	?>
	<table class="postcode"><tbody>
	<?php
	    foreach ($xml->itemlist->item as $value) {
	    	$postcd = add_dash_and_tag_to_postcd($value->postcd);
	    	echo '<tr>';
	    	echo "<td><a class='address' href='#{$value->postcd}'>{$value->address}</a></td>";
	    	echo "<td><a class='postcd' href='#{$value->postcd}'>{$postcd}</a></td>";
	    	echo '</tr>';
	    }
	?>
	</tbody></table>
	<?php
}

print_postcode_table 함수는 simpleXML의 node를 받아서 table 형태로 주소와 우편번호를 뿌려 주는 함수다.

가운데 있는 foreach가 왜 저런 모양이 됐는지는 실행부를 보면 알 수 있을 것이다.

실행부

이제 실행부다. 위 함수들을 functions_postcode.php 에 넣었다고 가정하자.

include_once 'include/functions_postcode.php';
header('Content-Type:text/html;charset=utf-8');

if(!empty($_GET['query'])){
	$result = get_post_code_xml_by_api($_GET['query']);	

	if ($result['error'] == false){
		$xml = new SimpleXMLElement($result['content']);
		if(count($xml->itemlist->item) == 0){
			echo '결과가 없습니다';
		}else{
			print_postcode_table($xml);
		}
	}
	else {
		echo '에러 발생: ' . $result['content'];
	}
}else{
	echo '검색어를 입력하세요.';
}

우편번호 오픈 API의 인코딩은 euc-kr이다. 하지만 나는 utf-8로 무조건 페이지를 만든다.

물론 SimpleXMLElement 클래스를 생성하면, 지가 알아서 euc-krxmlutf-8로 변경한다.

그런데 한국 브라우저들은 인코딩 선언이 특별히 없는 경우 기본 인코딩을 euc-kr로 한다. 그래서 header쪽에 인코딩 선언을 넣어 줬다.(둘째 줄) 이 놈은 html로 뿌려줄 용도기 때문에 content-typetext/html이다.

나머지 if문은 다 이해가 될 것이라고 생각한다.

일단 이렇게 하면 search_post.php?query=삼천포 형식으로 URL을 적었을 때 훌륭한 테이블로 결과값이 펼쳐질 것이다.

특히 js로 주소를 넣고 빼고 하는 것을 제어할 수 있도록, 테이블에 클래스를 넣었고, 내용은 a 태그로 감쌌다. a의 클래스는 무엇을 감싸고 있냐에 따라 각각 address, postcd1, postcd2 다. 우편번호를 삽입하는 부분은 이것을 참고하면 된다.

그러면 우편번호 API 활용법 서버단 끝이다.

▶예제 보기 | ▶코드 다운로드

안녕하세요. 14년차 풀스택 웹개발자 안형우입니다. 이 블로그에서는 WordPress, PHP, CSS, 사용성, 리눅스 서버 등 풀스택 웹개발에서 마주하는 다양한 문제 상황과 해결책, 필요한 개념들을 다룹니다. 👉 소개


작업물

댓글 (21개)

  1. 쿨교 댓글:

    좋은 정보 감사합니다.

    1. 녹풍 댓글:

      네, 저도 언젠가 갖다 쓰려고 저장해 놓는 것이랍니다. ^^

  2. php초보 댓글:

    좋은 정보 감사합니다. 그런데 정확하게 어떻게 해야할지 모르겠어요.
    죄송한데 소스 파일 부탁드려도 될까요??

    1. 녹풍 댓글:

      어라? 그냥 코드들 다 긁어서 만드시면 될 텐데 ㅋ
      곧 소스파일도 올리도록 하겠습니다.

    2. 녹풍 댓글:

      글 내용에 예제와 소스파일을 추가했습니다. 참고하세요.

  3. 임성묵 댓글:

    많은 도움이 되었습니다. ^-^
    레일즈에 개발을 하고 있는데, 참 많은 도움이 되었습니다. 감사합니다 ^^

  4. 지용호 댓글:

    좋은 글 감사합니다. 덕분에 우편번호 API를 쉽게 사용할 수 있었습니다.
    단 제가 받는 호스팅업체가 php4까지만 지원해서인지 XML 클래스를 사용할 수 없네요. php4기반 클래스를 가져다가 해결봤습니다. curl을 지원하지 않는 곳도 있더군요.
    DB를 구축할 필요가 없어서 여러모로 편하긴 한데…. 한글문제는 정말 쥐약이네요.. ㅜㅜ

    1. 녹풍 댓글:

      이렇게 도움이 됐다는 이야기를 들을 때가 가장 기쁩니다. ^^

  5. 홍만기 댓글:

    좋은 정보 감사합니다.~~

  6. 노프 댓글:

    좋은 정보 감사합니다

  7. ㅇㅇ 댓글:

    감사합니다. 친절하게 코드소스까지 ..덕분에 삽질하면서 공부할시간 많이 줄였습니다. 고맙습니다.

    1. 녹풍(綠風) 댓글:

      넵 ^^ 댓글 감사합니다

  8. 초보 댓글:

    안녕하세요~
    초보 개발자 입니다. 주소 검색 이란걸 검색하다가 읽게 되었습니다.
    그런데 제가 초보라 코드는 다운받았는데 거기 안에서 우체국에서 받은 키값 넣어주고 압축파일에 같이 있는 index 크롬파일 실행 시킨후에 주소값넣으면 로딩중 계속 되는데 이게 연동이 안되서 그런건가요???
    다 가르쳐 주셨는데 활용을 못해서 이렇게 질문올립니다
    메일로 가르쳐 주시면 감사하겠습니다

    1. 초보 댓글:

      그리고 크롬으로 하면 로딩중이라고 뜨고 인터넷익스프로러로 실행시키면 zipsearch-action.php에 있는 소스가 보입니다 ;;;

      그리고 메일은 [email protected] 입니다.

      1. 녹풍(綠風) 댓글:

        서버 환경이 잘못된 것 같습니다.

  9. w 댓글:

    spring 에서 사용할 수 있는 소스인가요

    1. 녹풍(綠風, Windgreen) 댓글:

      php예요.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다