웹마스터 팁

XE로 API 처리 두번째

참고

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

목차

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

1. board.api.php 흐름 이해

1
2
3
4
5
6
7
8
9
10
11
<?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와 같은 변수를 넘기지 않아 오류가 발생되니 주의가 필요합니다.

1
<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를 접근하여 아래의 소스가 동작하게 되고
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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는 각종 파일 입출력 복사 등 데이터 처리에 대한 전반적인 기능들이 포함되어있기 때문에 활용하시면 큰 도움이 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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 안에서 선언되거나 활용되어 집니다. 별도의 값이 필요하다면

1
2
3
4
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가 꼭 붙어야 하며 끝에 / 는 넣지 마십시오.

글 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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;
?>

확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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)에도 설명했지만 알아서 파싱해서 활용하셔야겠지요.


글 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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;
?>
확인
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<methodResponse><params><param>
<value><string>71</string></value>
</param></params>
</methodResponse>

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

첨부파일 등록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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을 아래와 같이 만듭니다.

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<module>
    <grants />
    <permissions />
    <actions>
        <action name="dispContentView" type="view" index="true" />
    </actions>
</module>

모듈/모듈.class.php를 아래와 같이 만듭니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
    class 모듈 extends ModuleObject {
        function moduleInstall() {
        }
 
        function checkUpdate() {
            return false;
        }
        function moduleUpdate() {
            return new Object(0, "success_updated");
        }
        function recompileCache() {
        }
    }
?>

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

모듈/모듈.controller.php를 아래와 같이 만듭니다.
1
2
3
4
5
6
7
8
9
10
<?php
    class 모듈Controller extends 모듈 {
        function init() {
        }
        function _dispContentView($args) {
            $args->controller = "모듈Controller";
            return $args;
        }
    }
?>

모듈/모듈.api.php를 아래와 같이 만듭니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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 선언에 따라 포멧을 만들어 내보냅니다.

테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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;
?>
확인
1
2
3
4
5
6
<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 컴박살
제목 글쓴이 날짜
안산1인샵【오피쓰주소.COM】안산 1인샵 안산1인샵 안산1인샵 songkangkong767 2025.02.22
답십리오피 ⦑출장마사지안내.COM⦒ 답십리오피 답십리OP 답십리건마 답십리오피 koykoyah 2025.02.22
대구1인샵【출장마사지안내.COM】대구스웨디시 대구안마 대구마사지 songkangkong767 2025.02.22
포항오피 ⦑오피.CLUB⦒ 포항오피 포항출장마사지 포항오피 포항OP koykoyah 2025.02.22
영등포마사지【오피쓰.COM】영등포마사지 영등포 마사지 영등포마사지 songkangkong767 2025.02.22
해운대오피 ⦑출장마사지안내.COM⦒ 해운대마사지 해운대오피 해운대오피 해운대OP koykoyah 2025.02.22
서초마사지【출장안마사이트.COM】서초마사지 서초 마사지 서초마사지 songkangkong767 2025.02.22
대구오피 ⦑오피쓰주소.COM⦒ 대구오피 대구출장마사지 대구오피 대구OP koykoyah 2025.02.22
의정부마사지【오피.CLUB】의정부 마사지 의정부마사지 의정부마사지 songkangkong767 2025.02.22
전주오피 전주출장안마 ⦑출장안마사이트.COM⦒ 전주OP 전주오피 전주오피 koykoyah 2025.02.22
신도림안마【오피쓰주소.COM】신도림 안마 신도림안마 신도림안마 songkangkong767 2025.02.22
강남오피 강남OP ⦑오피쓰.COM⦒ 강남휴게텔 강남오피 강남오피 koykoyah 2025.02.22
동두천마사지【오피사이트.NET】동두천마사지 동두천 마사지 동두천마사지 songkangkong767 2025.02.22
목포오피 ⦑오피쓰.COM⦒ 목포마사지 목포오피 목포오피 목포OP koykoyah 2025.02.22
서면스웨디시【오피.CLUB】서면 스웨디시 서면스웨디시 서면스웨디시 songkangkong767 2025.02.22
창원오피 ⦑오피사이트.NET⦒ 창원OP 창원오피 창원출장샵 창원오피 koykoyah 2025.02.22
동대문1인샵【오피쓰.COM】동대문마사지 동대문안마 동대문스웨디시 songkangkong767 2025.02.22
부산오피 ⦑오피사이트.NET⦒ 부산오피 부산OP 부산건마 부산오피 koykoyah 2025.02.22
포항스웨디시【오피쓰주소.COM】포항 스웨디시 포항스웨디시 포항스웨디시 songkangkong767 2025.02.22
남양주오피 ⦑오피쓰주소.COM⦒ 남양주오피 남양주OP 남양주건마 남양주오피 koykoyah 2025.02.22