XML-RPC 및 XML-RPC 서버 클래스

CodeIgniter의 XML-RPC 클래스를 사용하면 다른 서버로 요청을 전송하거나, 자체 XML-RPC 서버를 설정하여 요청을 받을 수 있습니다.

XML-RPC란?

간단히 말하면, 두 컴퓨터가 XML을 사용하여 인터넷을 통해 통신하는 방법입니다. 클라이언트라고 부를 한 컴퓨터가 서버라고 부를 다른 컴퓨터에 XML-RPC 요청을 전송합니다. 서버가 요청을 수신하고 처리하면 클라이언트에게 응답을 보냅니다.

예를 들어, MetaWeblog API를 사용하면 XML-RPC 클라이언트(일반적으로 데스크톱 퍼블리싱 도구)가 사이트에서 실행되는 XML-RPC 서버에 요청을 전송합니다. 이 요청은 게시할 새 웹로그 항목이거나 편집을 위한 기존 항목에 대한 요청일 수 있습니다. XML-RPC 서버가 이 요청을 수신하면 요청을 처리할 클래스/메소드를 결정합니다. 처리 후 서버는 응답 메시지를 보냅니다.

자세한 사양은 XML-RPC 사이트를 방문하세요.

XML-RPC 클래스 사용

클래스 초기화

CodeIgniter의 대부분의 클래스와 마찬가지로 XML-RPC 및 XML-RPCS 클래스는 컨트롤러에서 $this->load->library 함수를 사용하여 초기화합니다.

XML-RPC 클래스를 로드하려면:

$this->load->library('xmlrpc');

로드되면 xml-rpc 라이브러리 객체는 $this->xmlrpc를 사용하여 접근할 수 있습니다.

XML-RPC 서버 클래스를 로드하려면:

$this->load->library('xmlrpc');
$this->load->library('xmlrpcs');

로드되면 xml-rpcs 라이브러리 객체는 $this->xmlrpcs를 사용하여 접근할 수 있습니다.

참고

XML-RPC 서버 클래스를 사용할 때는 XML-RPC 클래스와 XML-RPC 서버 클래스 모두 로드해야 합니다.

XML-RPC 요청 전송

XML-RPC 서버에 요청을 전송하려면 다음 정보를 지정해야 합니다:

  • 서버의 URL

  • 호출할 서버의 메소드

  • 요청 데이터(아래 설명)

다음은 Ping-o-Matic에 간단한 Weblogs.com ping을 전송하는 기본 예시입니다.

$this->load->library('xmlrpc');

$this->xmlrpc->server('http://rpc.pingomatic.com/', 80);
$this->xmlrpc->method('weblogUpdates.ping');

$request = array('My Photoblog', 'http://www.my-site.com/photoblog/');
$this->xmlrpc->request($request);

if ( ! $this->xmlrpc->send_request())
{
        echo $this->xmlrpc->display_error();
}
설명

위 코드는 XML-RPC 클래스를 초기화하고, 서버 URL과 호출할 메소드(weblogUpdates.ping)를 설정합니다. 요청(이 경우 사이트의 제목과 URL)은 전송을 위해 배열에 배치되며 request() 함수를 사용하여 컴파일됩니다. 마지막으로 전체 요청이 전송됩니다. send_request() 메소드가 false를 반환하면 XML-RPC 서버에서 보낸 오류 메시지를 표시합니다.

요청 구조

XML-RPC 요청은 단순히 XML-RPC 서버에 전송하는 데이터입니다. 요청의 각 데이터 조각을 요청 매개변수라고 합니다. 위 예시에는 두 가지 매개변수인 사이트의 URL과 제목이 있습니다. XML-RPC 서버가 요청을 수신하면 필요한 매개변수를 찾습니다.

요청 매개변수는 전송을 위해 배열에 배치해야 하며, 각 매개변수는 7가지 데이터 타입(문자열, 숫자, 날짜 등) 중 하나가 될 수 있습니다. 매개변수가 문자열이 아닌 경우 요청 배열에 데이터 타입을 포함해야 합니다.

다음은 세 가지 매개변수가 있는 간단한 배열 예시입니다:

$request = array('John', 'Doe', 'www.some-site.com');
$this->xmlrpc->request($request);

문자열 이외의 데이터 타입을 사용하거나 여러 다른 데이터 타입이 있는 경우 각 매개변수를 자체 배열에 넣고 두 번째 위치에 데이터 타입을 지정합니다:

$request = array(
        array('John', 'string'),
        array('Doe', 'string'),
        array(FALSE, 'boolean'),
        array(12345, 'int')
);
$this->xmlrpc->request($request);

아래 데이터 타입 섹션에서 데이터 타입의 전체 목록을 확인할 수 있습니다.

XML-RPC 서버 만들기

XML-RPC 서버는 일종의 교통 경찰 역할을 하며, 들어오는 요청을 기다리다가 처리를 위해 적절한 함수로 리디렉션합니다.

자체 XML-RPC 서버를 만들려면 들어오는 요청이 나타날 것으로 예상되는 컨트롤러에서 XML-RPC 서버 클래스를 초기화한 다음 들어오는 요청을 처리를 위한 적절한 클래스와 메소드로 전송할 수 있도록 매핑 지침이 포함된 배열을 설정합니다.

다음은 예시를 통해 설명합니다:

$this->load->library('xmlrpc');
$this->load->library('xmlrpcs');

$config['functions']['new_post'] = array('function' => 'My_blog.new_entry');
$config['functions']['update_post'] = array('function' => 'My_blog.update_entry');
$config['object'] = $this;

$this->xmlrpcs->initialize($config);
$this->xmlrpcs->serve();

위 예시에는 서버가 허용하는 두 가지 메소드 요청을 지정하는 배열이 포함되어 있습니다. 허용되는 메소드는 배열의 왼쪽에 있습니다. 둘 중 하나가 수신되면 오른쪽의 클래스와 메소드로 매핑됩니다.

‘object’ 키는 인스턴스화된 클래스 객체를 전달하는 특수 키로, 매핑하는 메소드가 CodeIgniter 슈퍼 객체의 일부가 아닌 경우 필요합니다.

즉, XML-RPC 클라이언트가 new_post 메소드에 대한 요청을 전송하면 서버는 My_blog 클래스를 로드하고 new_entry 함수를 호출합니다. update_post 메소드에 대한 요청인 경우 서버는 My_blog 클래스를 로드하고 update_entry() 메소드를 호출합니다.

위 예시의 함수 이름은 임의적입니다. 서버에서 어떻게 불러야 할지 결정하거나, Blogger 또는 MetaWeblog API와 같은 표준화된 API를 사용하는 경우 해당 API의 함수 이름을 사용합니다.

서버 클래스를 초기화할 때 사용할 수 있는 두 가지 추가 설정 키가 있습니다: debug를 TRUE로 설정하면 디버깅을 활성화하고, xss_clean을 FALSE로 설정하면 Security 라이브러리의 xss_clean() 메소드를 통해 데이터를 전송하지 않습니다.

서버 요청 처리

XML-RPC 서버가 요청을 수신하고 처리를 위한 클래스/메소드를 로드하면, 클라이언트가 전송한 데이터를 포함하는 객체를 해당 메소드에 전달합니다.

위 예시를 사용하면, new_post 메소드가 요청되면 서버는 다음 프로토타입으로 클래스가 존재하기를 기대합니다:

class My_blog extends CI_Controller {

        public function new_post($request)
        {

        }
}

$request 변수는 서버에 의해 컴파일된 객체로, XML-RPC 클라이언트가 전송한 데이터를 포함합니다. 이 객체를 사용하면 요청을 처리할 수 있는 요청 매개변수에 접근할 수 있습니다. 완료되면 응답을 클라이언트에게 보냅니다.

다음은 Blogger API를 사용하는 실제 예시입니다. Blogger API의 메소드 중 하나는 getUserInfo()입니다. 이 메소드를 사용하면 XML-RPC 클라이언트가 서버에 사용자 이름과 비밀번호를 전송하고, 서버는 해당 특정 사용자에 대한 정보(닉네임, 사용자 ID, 이메일 주소 등)를 다시 보냅니다. 처리 함수는 다음과 같습니다:

class My_blog extends CI_Controller {

        public function getUserInfo($request)
        {
                $username = 'smitty';
                $password = 'secretsmittypass';

                $this->load->library('xmlrpc');

                $parameters = $request->output_parameters();

                if ($parameters[1] != $username && $parameters[2] != $password)
                {
                        return $this->xmlrpc->send_error_message('100', 'Invalid Access');
                }

                $response = array(
                        array(
                                'nickname'  => array('Smitty', 'string'),
                                'userid'    => array('99', 'string'),
                                'url'       => array('http://yoursite.com', 'string'),
                                'email'     => array('jsmith@yoursite.com', 'string'),
                                'lastname'  => array('Smith', 'string'),
                                'firstname' => array('John', 'string')
                        ),
                         'struct'
                );

                return $this->xmlrpc->send_response($response);
        }
}
참고:

output_parameters() 메소드는 클라이언트가 전송한 요청 매개변수에 해당하는 인덱스 배열을 검색합니다. 위 예시에서 출력 매개변수는 사용자 이름과 비밀번호입니다.

클라이언트가 전송한 사용자 이름과 비밀번호가 유효하지 않으면 send_error_message()를 사용하여 오류 메시지가 반환됩니다.

작업이 성공하면 클라이언트에게 사용자 정보가 포함된 응답 배열이 전송됩니다.

응답 형식 지정

요청과 유사하게, 응답도 배열로 형식을 지정해야 합니다. 그러나 요청과 달리 응답은 단일 항목을 포함하는 배열입니다. 이 항목은 여러 추가 배열이 있는 배열일 수 있지만 하나의 기본 배열 인덱스만 있을 수 있습니다. 즉, 기본 프로토타입은 다음과 같습니다:

$response = array('Response data', 'array');

그러나 응답에는 일반적으로 여러 정보가 포함됩니다. 이를 위해 기본 배열이 계속 단일 데이터를 포함할 수 있도록 응답을 자체 배열에 넣어야 합니다. 다음은 이를 수행하는 방법의 예시입니다:

$response = array(
        array(
                'first_name' => array('John', 'string'),
                'last_name' => array('Doe', 'string'),
                'member_id' => array(123435, 'int'),
                'todo_list' => array(array('clean house', 'call mom', 'water plants'), 'array'),
        ),
        'struct'
);

위 배열은 struct로 형식화되어 있음에 주의하세요. 이것이 응답에 가장 일반적인 데이터 타입입니다.

요청과 마찬가지로 응답은 데이터 타입 섹션에 나열된 7가지 데이터 타입 중 하나가 될 수 있습니다.

오류 응답 전송

클라이언트에게 오류 응답을 전송해야 하는 경우 다음을 사용합니다:

return $this->xmlrpc->send_error_message('123', 'Requested data not available');

첫 번째 매개변수는 오류 번호이고 두 번째 매개변수는 오류 메시지입니다.

클라이언트와 서버 직접 만들기

지금까지 다룬 모든 내용을 이해하는 데 도움이 되도록, XML-RPC 클라이언트와 서버로 작동하는 컨트롤러 한 쌍을 만들어 보겠습니다. 클라이언트를 사용하여 서버에 요청을 전송하고 응답을 수신합니다.

클라이언트

텍스트 편집기를 사용하여 Xmlrpc_client.php라는 컨트롤러를 만듭니다. 다음 코드를 넣고 application/controllers/ 폴더에 저장합니다:

<?php

class Xmlrpc_client extends CI_Controller {

        public function index()
        {
                $this->load->helper('url');
                $server_url = site_url('xmlrpc_server');

                $this->load->library('xmlrpc');

                $this->xmlrpc->server($server_url, 80);
                $this->xmlrpc->method('Greetings');

                $request = array('How is it going?');
                $this->xmlrpc->request($request);

                if ( ! $this->xmlrpc->send_request())
                {
                        echo $this->xmlrpc->display_error();
                }
                else
                {
                        echo '<pre>';
                        print_r($this->xmlrpc->display_response());
                        echo '</pre>';
                }
        }
}
?>

참고

위 코드에서 “url helper”를 사용합니다. 헬퍼 함수 페이지에서 자세한 정보를 찾을 수 있습니다.

서버

텍스트 편집기를 사용하여 Xmlrpc_server.php라는 컨트롤러를 만듭니다. 다음 코드를 넣고 application/controllers/ 폴더에 저장합니다:

<?php

class Xmlrpc_server extends CI_Controller {

        public function index()
        {
                $this->load->library('xmlrpc');
                $this->load->library('xmlrpcs');

                $config['functions']['Greetings'] = array('function' => 'Xmlrpc_server.process');

                $this->xmlrpcs->initialize($config);
                $this->xmlrpcs->serve();
        }


        public function process($request)
        {
                $parameters = $request->output_parameters();

                $response = array(
                        array(
                                'you_said'  => $parameters[0],
                                'i_respond' => 'Not bad at all.'
                        ),
                        'struct'
                );

                return $this->xmlrpc->send_response($response);
        }
}
실습!

이제 다음과 유사한 URL을 사용하여 사이트를 방문하세요:

example.com/index.php/xmlrpc_client/

이제 서버에 전송한 메시지와 서버의 응답을 볼 수 있습니다.

생성한 클라이언트는 메시지(“How’s is going?”)를 서버에 전송하고 “Greetings” 메소드에 대한 요청을 함께 보냅니다. 서버는 요청을 수신하고 process() 메소드로 매핑하여 응답이 전송됩니다.

요청 매개변수에 연관 배열 사용

메소드 매개변수에 연관 배열을 사용하려면 struct 데이터 타입을 사용해야 합니다:

$request = array(
        array(
                // Param 0
                array('name' => 'John'),
                'struct'
        ),
        array(
                // Param 1
                array(
                        'size' => 'large',
                        'shape'=>'round'
                ),
                'struct'
        )
);

$this->xmlrpc->request($request);

서버에서 요청을 처리할 때 연관 배열을 검색할 수 있습니다.

$parameters = $request->output_parameters();
$name = $parameters[0]['name'];
$size = $parameters[1]['size'];
$shape = $parameters[1]['shape'];

데이터 타입

XML-RPC 사양에 따르면 XML-RPC를 통해 전송할 수 있는 7가지 타입의 값이 있습니다:

  • int 또는 i4

  • boolean

  • string

  • double

  • dateTime.iso8601

  • base64

  • struct (값 배열 포함)

  • array (값 배열 포함)

클래스 레퍼런스

class CI_Xmlrpc
initialize([$config = array()])
매개변수:
  • $config (array) – 설정 데이터

반환 형식:

void

XML-RPC 라이브러리를 초기화합니다. 설정이 포함된 연관 배열을 허용합니다.

server($url[, $port = 80[, $proxy = FALSE[, $proxy_port = 8080]]])
매개변수:
  • $url (string) – XML-RPC 서버 URL

  • $port (int) – 서버 포트

  • $proxy (string) – 선택적 프록시

  • $proxy_port (int) – 프록시 수신 포트

반환 형식:

void

요청을 전송할 서버의 URL과 포트 번호를 설정합니다:

$this->xmlrpc->server('http://www.sometimes.com/pings.php', 80);

기본 HTTP 인증도 지원됩니다. 서버 URL에 추가하기만 하면 됩니다:

$this->xmlrpc->server('http://user:pass@localhost/', 80);
timeout($seconds = 5)
매개변수:
  • $seconds (int) – 제한 시간(초)

반환 형식:

void

요청이 취소되는 제한 시간(초)을 설정합니다:

$this->xmlrpc->timeout(6);

이 제한 시간은 원격 서버에 대한 초기 연결과 응답 가져오기 모두에 사용됩니다. send_request()를 호출하기 전에 제한 시간을 설정하세요.

method($function)
매개변수:
  • $function (string) – 메소드 이름

반환 형식:

void

XML-RPC 서버에서 요청할 메소드를 설정합니다:

$this->xmlrpc->method('method');

여기서 method는 메소드의 이름입니다.

request($incoming)
매개변수:
  • $incoming (array) – 요청 데이터

반환 형식:

void

데이터 배열을 받아 XML-RPC 서버에 전송할 요청을 만듭니다:

$request = array(array('My Photoblog', 'string'), 'http://www.yoursite.com/photoblog/');
$this->xmlrpc->request($request);
send_request()
반환:

성공 시 TRUE, 실패 시 FALSE

반환 형식:

bool

요청 전송 메소드입니다. 성공 또는 실패를 기반으로 불리언 TRUE 또는 FALSE를 반환하여 조건부로 사용할 수 있습니다.

display_error()
반환:

오류 메시지 문자열

반환 형식:

string

어떤 이유로 요청이 실패한 경우 오류 메시지를 문자열로 반환합니다.

echo $this->xmlrpc->display_error();
display_response()
반환:

응답

반환 형식:

mixed

요청이 수신된 후 원격 서버의 응답을 반환합니다. 응답은 일반적으로 연관 배열입니다.

$this->xmlrpc->display_response();
send_error_message($number, $message)
매개변수:
  • $number (int) – 오류 번호

  • $message (string) – 오류 메시지

반환:

XML_RPC_Response 인스턴스

반환 형식:

XML_RPC_Response

이 메소드를 사용하면 서버에서 클라이언트로 오류 메시지를 전송할 수 있습니다. 첫 번째 매개변수는 오류 번호이고 두 번째 매개변수는 오류 메시지입니다.

return $this->xmlrpc->send_error_message(123, 'Requested data not available');