웹마스터 팁

XE로 API 처리 두번째

참고

첫번째 설명에 사용된 내용을 (1) 이라는 명칭으로 사용합니다.

목차

  1. board.api.php 흐름 이해
  2. FileHandler::getRemoteResource() 구조, header 선언
  3. blogapi 애드온으로 metaWeblog 글 입력하기
  4. api 처리용 심플 모듈 만들어보기

1. board.api.php 흐름 이해

<?php
    class boardAPI extends board {

        function dispBoardContentList(&$oModule) {
            $document_list = $this->arrangeContentList(Context::get('document_list'));
            $oModule->add('document_list',$document_list);
            $oModule->add('page_navigation',Context::get('page_navigation'));
        }

...
?>
  • XE에서 json과 xml 형식으로 정보를 출력시키는 소스는 모듈.api.php에 위치합니다.
  • api.php의 처리는 모듈의 conf/module.xml 정보에 action type이 view로 되어있는 act 이름을 대상으로 동작합니다.
  • module.xml에 아래의 정보가 선언되어있을 경우
  • (2010.12.04) 최근 버전에서는 conf/module.xml에 view, controller, model, api 의 값에 따라 각 class의 함수를 요청합니다.
  • (2010.12.04) controller.php로 요청하는 함수에는  &$oModule와 같은 변수를 넘기지 않아 오류가 발생되니 주의가 필요합니다.

<action name="dispBoardContentList" type="view" />
  • 보통의 경우는 http://사이트/?mid=board&act=dispBoardContentList 이런식으로의 접근을 하여
  • view 라는 값을 얻고 board.view.php에 dispBoardContentList() 함수에 의해 처리 됩니다.
  • api.php는 (1)에서 설명드린 정보 중 content_type이 application/xml 또는 application/json일 경우
    board.view.php에 있는 dispBoardContentList()을 처리한 후 board.api.php의 dispBoardContentList()을 처리하게 됩니다.

boardAPI::dispBoardContentList(&$oModule) 소스를 설명하자면

  • (1)의 정보 요청 시 대상 act를 접근하여 아래의 소스가 동작하게 되고
function dispBoardContentList(){
            
            ...중략
            
            // 일반 글을 구해서 context set
            $output = $oDocumentModel->getDocumentList($args, $this->except_notice);
            Context::set('document_list', $output->data);
            Context::set('total_count', $output->total_count);
            Context::set('total_page', $output->total_page);
            Context::set('page', $output->page);
            Context::set('page_navigation', $output->page_navigation);

            // 목록 설정값을 세팅
            $oBoardModel = &getModel('board');
            Context::set('list_config', $oBoardModel->getListConfig($this->module_info->module_srl));
        }
  • dispBoardContentList()에서는 Context::set('document_list', $output->data),Context::set('page_navigation', $output->page_navigation) 를 활용하여 $document_list 정보를 만든 후 $oModule->add()를 이용하여 json,xml 포맷으로 정보를 만들어 출력하게 됩니다.

2. FileHandler::getRemoteResource() 구조, header 선언

FileHandler::getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array())             

return remote file's content via HTTP
매개변수:
    [in]     $url     the address of the target file
    [in]     $body     HTTP request body
    [in]     $timeout     connection timeout
    [in]     $method     GET/POST
    [in]     $content_type     content type header of HTTP request
    [in]     $headers     headers key vaule array.
    [in]     $cookies     cookies key value array.
    [in]     $post_data     request arguments array for POST method

FileHandler.class.php는 각종 파일 입출력 복사 등 데이터 처리에 대한 전반적인 기능들이 포함되어있기 때문에 활용하시면 큰 도움이 됩니다.

<?php
$content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>
            <methodCall>
            <params>
            <mid><![CDATA[board]]></mid>
            <content><![CDATA[내용]]></content>
            <document_srl><![CDATA[]]></document_srl>
            <title><![CDATA[제목]]></title>
            <tags><![CDATA[태그]]></tags>
            <allow_comment><![CDATA[Y]]></allow_comment>
            <allow_trackback><![CDATA[Y]]></allow_trackback>
            <nick_name><![CDATA[라르게덴]]></nick_name>
            <password><![CDATA[1234]]></password>
            <email_address><![CDATA[]]></email_address>
            <homepage><![CDATA[]]></homepage>
            <act><![CDATA[procBoardInsertDocument]]></act>
            <module><![CDATA[board]]></module>
            </params>
            </methodCall>";

$header = sprintf(
                "POST /xe/index.php HTTP/1.1\r\n".
                "Host: 127.0.0.1 \r\n".
                "Content-Type: application/xml\r\n".
                "Content-Length: ".strlen($contents)."\r\n\r\n".
                "Connection: Close\r\n\r\n".
                $contents."\r\n");

$fp = @fsockopen("127.0.0.1", "80", $errno, $errstr, 5);
if($fp){
        fputs($fp, $header);
        fclose($fp);
}
?>
  • 상기와 같이 fsockopen()을 이용한 처리를 XE는 getRemoteResource()를 이용하여 데이터를 주고 받을 수 있게 처리해줍니다.
  • 실제 해당 함수에는 xe의 libs 폴더의 PEAR.php, Request.php, Socket.php, URL.php 등 여러 라이브러리를 이용하여 처리되게 되어있습니다.
    • (2010.12.04) fsockopen()를 이용한 처리에 오류가 있어 정정합니다.

$url

상기 내용을 보시면 도메인과 포트, url, 파일명까지 구분되어져 header 선언을 하고 있습니다.
getRemoteResource()에서는 http://사이트:포트/경로/index.php를 전체를 입력시키고 있으며, 이는 URL.php를 통하여
부분별 연관배열로 파싱되어, 알맞은 헤더위치에 삽입되게 됩니다.

$body

상기 xml 포멧과 같은 목적지로 보낼 데이터를 말합니다.
xml 형식과 같이 쓸 경우도 있으며 실제적으로는 http://사이트/?매개변수=1 등의 a=1&b=2&c=3 을 입력하여도 처리 됩니다.

$timeout

응답을 기다릴 제한시간

$content_type

어떤 방식으로의 통신이냐에 따라서 정보의 처리가 달라지게 됩니다.
application/x-www-form-urlencoded
a=1&b=2&c=3 와 같은 일반 적인 정보를 가지고 web에 표시되는 내용을 가져오거나 할때 사용합니다.
application/xml
xml 형식으로 정보를 주고 XE는 이를 다시 XML 형식으로 결과를 보내줍니다.
application/json
javascript에서 정보를 보내고 XE에서 json 형식으로 결과를 보내줍니다.
application/octet-stream
blogapi 애드온에 선언되어있는 metaWeblog.[act]을 이용하기 위해 상기와 같이 처리합니다.
첨부파일 저장 등의 동작도 겸할때 사용합니다.

$headers

기본 헤더 정보 이외의 별도의 헤더 정보를 추가할 때 사용합니다.

User-Agent : PEAR HTTP_Request class
Connection : close
Authorization : Basic dHlhbWkY
Proxy-Authorization : Basic dHlhbWkY
Accept-Encoding : gzip

상기와 같은 내용들은 Request.php 안에서 선언되거나 활용되어 집니다. 별도의 값이 필요하다면

array(
    "me2_application_key"=>$this->application_key,
    "Authorization"=>"Basic ".base64_encode($this->user_id),
)

상기 처럼 추가 헤더를 이용할 경우 사용됩니다.

$cookies

안써봐서 설명 불가

$post_data

안써봐서 설명 불가

3. blogapi 애드온으로 metaWeblog 글 입력하기



대표적으로 글 조회, 입력, 첨부파일 3가지 메소드에 대해서만 쓰겠습니다.
(1) 단독형의 기본 선언 내용 설명은 제외합니다. (1) 설명과 같이 적용하시면 됩니다.

※ 해당 기능을 하기 전에 반드시 XE blogapi 애드온이 활성화되어있어야 합니다.(모듈 선택은 모두 해제) ※ $uri 주소는 api가 꼭 붙어야 하며 끝에 / 는 넣지 마십시오.

글 조회

<?php
    $uri = "http://도메인/xe/board/api";
    $body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
    <methodCall>
    <methodName><![CDATA[metaWeblog.getPost]]></methodName>
    <params>
    <param><value><string><![CDATA[62]]></string></value></param>
    <param><value><string><![CDATA[admin]]></string></value></param>
    <param><value><string><![CDATA[1234]]></string></value></param>
    <param>
    <value>
    <boolean>1</boolean>
    </value>
    </param>
    </params>
    </methodCall>";

    $buff = @FileHandler::getRemoteResource($uri, $body, 3, "POST", "application/octet-stream");
    echo $buff;
?>

확인

<methodResponse>
<params>
<param>
<value>
<struct>
<member><name>categories</name><value><array><data><value><![CDATA[]]></value></data></array></value></member>
<member><name>dateCreated</name><value><dateTime.iso8601>20091103T11:37:10</dateTime.iso8601></value></member>
<member><name>description</name><value><![CDATA[<!--BeforeDocument(62,4)--><div class="document_62_4 xe_content"><p>&nbsp;sadfsadfsaf</p></div><!--AfterDocument(62,4)-->]]></value></member>
<member><name>link</name><value>http://211.234.236.218/xe/62</value></member>
<member><name>postid</name><value><string>62</string></value></member>
<member><name>title</name><value><![CDATA[asdfsadfsf]]></value></member>
<member><name>publish</name><value><boolean>1</boolean></value></member>
</struct>
</value>
</param>
</params>
</methodResponse>

이런 결과물이 출력된다면 성공입니다. 출력물은 (1)에도 설명했지만 알아서 파싱해서 활용하셔야겠지요.


글 입력

<?php
    $uri = "http://도메인/xe/board/api";
    $body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
            <methodCall>
            <methodName>metaWeblog.newPost</methodName>
            <params>
            <param><value><string><![CDATA[board]]></string></value></param>
            <param><value><string><![CDATA[admin]]></string></value></param>
            <param><value><string><![CDATA[1234]]></string></value></param>
            <param><value><struct>
            <member><name><![CDATA[title]]></name><value><string><![CDATA[제목]]></string></value></member>
            <member><name><![CDATA[description]]></name><value><string><![CDATA[내용]]></string></value></member>
            <member><name><![CDATA[categories]]></name><value><array><data><value><string><![CDATA[135]]></string></value></data></array></value></member>
            <member><name><![CDATA[tagwords]]></name><value><array><data><value><string><![CDATA[태그,태그2]]></string></value></data></array></value></member>
            </struct></value></param>
            <param>
            <value>
            <boolean>1</boolean>
            </value>
            </param>
            </params>
            </methodCall>";

    $buff = @FileHandler::getRemoteResource($uri, $body, 3, "POST", "application/octet-stream");
    echo $buff;
?>
확인
<?xml version="1.0" encoding="utf-8"?>
<methodResponse><params><param>
<value><string>71</string></value>
</param></params>
</methodResponse>

이런 내용이 나오면 성공입니다.
※ 카테고리의 경우 번호를 입력해야하는지 등록되어있는 실제 이름을 입력해야하는지는 확인 안해봐서 잘 모르겠네요.

첨부파일 등록

<?php
        $body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
            <methodCall>
            <methodName>metaWeblog.newMediaObject</methodName>
            <params>
            <param><value><string><![CDATA[board]]></string></value></param>
            <param><value><string><![CDATA[admin]]></string></value></param>
            <param><value><string><![CDATA[1234]]></string></value></param>
            <param><value><struct>
            <member><name><![CDATA[name]]></name><value><string><![CDATA[C:\abc.jpg]]></string></value></member>
            <member><name><![CDATA[type]]></name><value><string><![CDATA[image/jpeg]]></string></value></member>
            <member><name><![CDATA[bits]]></name><value><base64><![CDATA[".base64_encode(FileHandler::readFile("C:\abc.jpg")]."]></base64></value></member>
            </struct></value></param>
            </params>
            </methodCall>";

    $buff = @FileHandler::getRemoteResource($uri, $body, 3, "POST", "application/octet-stream");
    echo $buff;
?>
확인

안해봐서 결과는 모르겠습니다.
  • 첨부파일의 경우 글 등록을 하기 이전에 진행해야 합니다.
  • 글 등록 시 첨부파일이 있다라고 가정한다면 첨부파일 업로드 이후 바로 글 등록 프로세스를 돌려야 합니다.
  • 첨부파일이 먼저 등록되면 blogapi를 통하여 임시 저장소에 파일이 등록되고 글 등록시에 해당 임시경로의 파일을 전부 끌어다가 저장하고 파기하는 방법으로 구현되어있기 때문입니다.

4. api 처리용 모듈 만들어보기


모듈 작성 내용은 http://sol.textyle.kr/26153 를 참고해주시고 모듈 작성에 시간이 걸리기 때문에 첨부파일로 올려두겠습니다.

이 모듈의 목적은 모듈.api.php를 이용하여 기본조회, 모듈.model.php의 정보가공, 모듈.controller.php의 정보처리가 되게끔 설계해주는 내용입니다.

※ 이렇게까지 할 필요가 있나 하시겠지만 외부에서 반복적인 정보 수행이나 기계적인 정보처리를 위한 통신은 URL로 노출되어 처리 될 경우 쉽게 웹브라우저로 인위적 수행이 되기에 api를 이용하면 일반 웹처리 노출에서 자유로워지지 않을까해서 입니다.

모듈/conf/module.xml을 아래와 같이 만듭니다.

<?xml version="1.0" encoding="utf-8"?>
<module>
    <grants />
    <permissions />
    <actions>
        <action name="dispContentView" type="view" index="true" />
    </actions>
</module>

모듈/모듈.class.php를 아래와 같이 만듭니다.
<?php
    class 모듈 extends ModuleObject {
        function moduleInstall() {
        }

        function checkUpdate() {
            return false;
        }
        function moduleUpdate() {
            return new Object(0, "success_updated");
        }
        function recompileCache() {
        }
    }
?>

모듈/모듈.view.php를 아래와 같이 만듭니다.
<?php
    class 모듈View extends 모듈 {
        function init() {
        }
        function dispContentView() {
        }
    }
?>
  • view에서 Context::set()에 처리 결과를 넣고 api로 활용할지 사용할 수 있습니다.
  • 아무것도 할일 없다고 해서 함수를 없애면 api.php가 동작하지 않습니다. 껍데기라도 만드셔야 합니다.
모듈/모듈.model.php를 아래와 같이 만듭니다.
<?php
    class 모듈Model extends 모듈 {
        function init() {
        }    
        function _dispContentView($args) {
            $args->model = "모듈Model";
            return $args;
        }
    }
?>

모듈/모듈.controller.php를 아래와 같이 만듭니다.
<?php
    class 모듈Controller extends 모듈 {
        function init() {
        }
        function _dispContentView($args) {
            $args->controller = "모듈Controller";
            return $args;
        }
    }
?>

모듈/모듈.api.php를 아래와 같이 만듭니다.
<?php
    class 모듈API extends 모듈 {
        function dispContentView(&$oModule) {
             $args = Context::getRequestVars();
             
             $oNmsModel = &getModel("nms");
             $model = $oNmsModel->_dispContentView($args);
            
             $oNmsController = &getController("nms");             
             $controller = $oNmsController->_dispContentView($args);
            
             $oModule->add("model",$model->model);
             $oModule->add("controller",$controller->controller);            
        }
    }
?>
  • init()를 넣지마시길 바랍니다. '+
    'extends 모듈'은 꼭 쓰셔야 합니다.
  • 넘겨받은 매개변수를 $args로 만들고 각 해당 클래스의 함수로 넘겨 데이터를 가공받습니다.
  • 처리된 데이터를 $oModule->add()에 입력해주시면 json/xml 선언에 따라 포멧을 만들어 내보냅니다.

테스트

<?php
    // _XE_PATH_ 생성
    define("_XE_PATH_", str_replace("api.php", "", str_replace("\\", "/", __FILE__)));
    // FileHandler(PEAR,Socket) 등을 사용하기 위해서 XE 정보를 선언
    define("__ZBXE__", true);
    require_once(_XE_PATH_."config/config.inc.php");

    $uri = "http://127.0.0.1/xe/";
    $body = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>
             <methodCall>
             <params>
             <module><![CDATA[모듈명]]></module>
             <act><![CDATA[dispContentView]]></act>
             </params>
             </methodCall>";

    $buff = @FileHandler::getRemoteResource($uri, $body, 3, "POST", "application/xml");
    echo $buff;
?>
확인
<response>
<error>0</error>
<message>success</message>
<model><![CDATA[모듈Model]]></model>
<controller><![CDATA[모듈Controller]]></controller>
</response>

참고자료

- 김기철980님의 [강추]!! 긁어와서 [자동]으로 게시글로!! [메타 블로그] php 로 넣기!!! xe블로그api를 이용한.. http://www.xpressengine.com/17686946
- (1) 항목에 참고 자료


허접하게나마 아는데로 적어봤습니다.

설명 중 미흡하거나 잘못 된 사항이 있을 수 있습니다.

참고용으로만 생각해주시고 동작이 안되면 열심히 자료 찾으셔서 공부해보시기 바랍니다.

셈플용 모듈이랑 자료는 좀 있다(어쩌면 내일) 올리겠습니다.

올린다는 자료가 늦어버렸습니다. 테스트 모듈을 올렸고 모듈안에 test.php 파일이 있습니다.

http://사이트/xe/modules/test_api/test.php 로 실행하시고 소스보기를 하시면 값이 출력 됩니다.

태그 연관 글
  1. [2017/03/15] 웹마스터 팁 다음 우편번호 5자리 적용 by 뒤늦게입문 *1
  2. [2015/08/06] 묻고답하기 metaWeblog을 이용하여 게시판에 저장할때 _extra_vars 는 어떻게 하면 좋은지요. by 뉴질맨
  3. [2015/07/29] 묻고답하기 게시판DX 모바일환경에서 댓글 열람 불가 by poltwo
  4. [2015/06/05] 묻고답하기 스케치북 모바일 스킨 문의 by Ssami *9
  5. [2015/02/25] 웹마스터 팁 kakao Javascript SDK logout by 컴박살
제목 글쓴이 날짜
갑자기 관리자 페이지가 안보이거나 330 오류가 날 때는 이렇게 해결! [2] file 세라오빠 2011.04.13
(1.4.5 버전 이상) XE가 설치된 사이트 찾기 [1] SMaker 2011.04.17
댓글 쪽지 알림시 원본글 URL 설정 [1] unnumiya 2011.04.15
1.4.5.2로 업데이트 후 짧은 주소가 제대로 되지 않으실때... [8] file 라르게덴 2011.04.12
다솜플레이어창은 뜨는데 연결중에서 더이상 안넘어가요 탱7 2011.04.15
1.4.4.2부터 게시판 신규게시물 작성이 안되던 문제 [2] 운상유희 2011.03.25
업데이트 어떻게 해야 오류 없이 되나요? [1] 김농주 2011.04.12
텍스타일 카테고리 글목록수 수정 신군임니돠 2011.04.12
제로보드 XE - 오토셋에 설치하기 [11] file 차오이 2007.08.11
레이아웃에 소스추가해서 트래픽보기! [2] file 막시민 2011.03.07
회원가입폼 내멋대로 내맘대로 하기. [9] 지인짜 2010.08.04
[모바일] 모바일웹에서 Pc버전갔다가 다시 모바일버전으로 갈라면 [1] 푸름빠 2011.04.07
XE로 API 처리 완전 정복하기(2) [2] file 라르게덴 2009.11.03
P 개행처리를 BR처럼 Garon 2011.04.04
데이터이전 회원관련해서 알아야 할 사항 [2] 푸름빠 2011.04.03
[PHP 기초] 변수, 상수 [2] 난다날아 2011.03.24
관리자페이지 레이아웃에 게시판을 달아보자 [3] 푸름빠 2011.03.29
"현재 xe코어1.4.4.4버전에서는 익스플로어에서 페이지수정 등의 작업을 할때 에러가 자주 발생하곤 합니다." 유샤인 2011.03.29
디버그모드 변경하는 간단한 파이썬 스크립트 [4] mmx900 2008.04.23
모두 새로 코딩된 선우님의 새로운 레이아웃.... 유샤인 2011.03.28