웹마스터 팁

머리말: 이 게시물은 퍼가셔도 됩니다. 하지만 머리말과 작성자는 꼭 명시해주셨으면 합니다.
===================================================================================

트랙백 구현하기 - 3. PHP로 트랙백 핑 보내기

Download #1에 풀소스가 첨부되어 있습니다.

이제 본격적인 프로그래밍의 영역으로 넘어가 PHP로 직접 핑을 보내고 답변을 가져오는 소스를 짜보도록 하겠습니다. 우선 프로그램을 작성하기에 앞서 개념을 정리해보도록 하죠.

1. 트랙백 주소가 유효한지 검사해서 존재하지 않을 경우 취소시킨다
2. 보낼 트랙백 핑 데이터를 정리한다.
3. 서버에 접속한 후 트랙백 핑을 보내고 응답을 받는다.
4. 올바른 XML 답변이 오지 않을 경우 트랙백 주소가 아닌 것으로 간주하고 취소시킨다.
5. XML 답변을 분석해 오류가 발생한 경우 취소시킨다.
6. 위 과정을 모두 통과했을 경우 완료시킨다.

위 내용을 염두하고 우선 풀소스를 보도록 합시다.

tb_06.gif
그림이 찌그러져 보일 경우에는 클릭해서 새창으로 띄워 보세요.

보시다시피 우리는 이번 소스를 함수화해서 만들 것입니다. 따라서 위 과정보다 앞서 어떤 변수를 받아야 하는가에 대해 생각해 보아야 합니다. 핑을 보낼 때 필요한 url,title,blog_name,excerpt 변수 외에 트랙백 주소 URL을 나타내는 변수도 받아야 합니다. "트랙백 주소 URL을 나타내는 변수"를 $t_url이라고 두겠습니다. 정리하면, $t_url,$url,$title,$blog_name,$excerpt의 5개 변수를 기입받아야 합니다.

function send_tb($t_url,$url,$title,$blog_name,$excerpt) {

에러 문자열을 $tb_error_str에 담아 사용하도록 하겠습니다. 이를 위해 전역변수 선언을 해줍니다.

     global $tb_error_str;

그 다음 첫째 단계인 주소 유효성 검사입니다. fopen으로 해당 URL을 열어서 파일포인터가 없으면 해당 주소가 존재하지 않는 것으로 간주하겠습니다.

     $p_fp = @fopen($t_url,'r');
     if($p_fp) fclose($p_fp);
     else {
          $tb_error_str = "트랙백 URL이 존재하지 않습니다.";
          return false;
     }

본문 내용을 정리해야 합니다. 우선 제목과 본문 요약의 태그를 제거하여야 합니다. 핑을 보낼 때에는 rawurlencode()를 사용해 인코딩시킵니다. 이는 "믹스"를 "%B9%CD%BD%BA"따위로 고쳐주는 것으로, 검색엔진에서 한글 검색시 주소창에 보이는 그것입니다. 단 urlencode()와는 다르게 공백을 +로 표시하지 않고 공백 역시 인코딩합니다(urlencode() 를 사용해도 무방한 것으로 알려져 있습니다).
이렇게 정리한 내용을 $t_data에 넣습니다. $t_data는 HTTP 변수 전송 형식을 따라, 변수=값&변수=값의 형태로 만듭니다.

     $title = strip_tags($title);
     $excerpt = strip_tags($excerpt);
     $t_data = "url=".rawurlencode($url)."&title=".rawurlencode($title).
               "&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt);

소켓 연결을 위해 트랙백 대상 주소를 정리합니다. 만약 트랙백 주소 자체에 "변수=값"형태의 쿼리가 있다면 이를 $t_data 뒤에 붙여넣습니다. 또한 포트 정보가 없는 경우 웹서버 기본포트인 80을 입력해줍니다.

     $uinfo = parse_url($t_url);
     if($uinfo[query]) $t_data .= "&".$uinfo[query];
     if(!$uinfo[port]) $uinfo[port] = "80";

이제 보낼 내용을 정리해야 합니다. 이는 HTTP프로토콜에 규정된 형태인데, 자세한 형식의 내용은 그리 중요치 않습니다. 간단하게 트랙백 URL 서버의 해당 주소에 POST로 $t_data의 변수들을 넘겨주는 거라고 생각하시면 됩니다. 여기서 User-Agent부분에는 자신의 프로그램 이름 따위를 넣어주시면 됩니다(없어도 상관없습니다).

     $send_str = "POST ".$uinfo[path]." HTTP/1.1rn".
                 "Host: ".$uinfo[host]."rn".
                 "User-Agent: MToolsrn".
                 "Content-Type: application/x-www-form-urlencodedrn".
                 "Content-length: ".strlen($t_data)."rn".
                 "Connection: closernrn".
                 $t_data;

이제 데이터를 정리했으니 3번째 단계로 넘어가 핑을 보내고 답변을 받아와야 합니다. 핑을 보낼 때에는 fsockopen을 통해 해당 서버에 연결한 후 fputs로 위 내용을 전송해주면 됩니다.

     $fp = fsockopen($uinfo[host],$uinfo[port]);
     fputs($fp,$send_str);

그리고 응답을 가져옵니다. while문을 통해 128바이트씩 끝까지 가져오도록 하겠습니다. 응답을 가져왔으면 연결을 종료합니다.

     while(!feof($fp)) $response .= fgets($fp,128);
     fclose($fp);

이제 돌아온 정보를 분석해봐야 합니다. 우선 XML의 형태로 되돌아오지 않았을 경우 트랙백 주소가 아닌 일반 주소로 간주합니다. 우리는 택의 유무로 간단하게 검사해 보겠습니다.

     if(!strstr($response,"<response>")) {
          $tb_error_str = "올바른 트랙백 URL이 아닙니다.";
          return false;
     }

존재한다면 이제 XML부분을 뽑아와야 합니다. $response안에 담긴 내용은
HTTP/1.1 200 OK
...................
Content-Type: text/xml
등의 기본 헤더 정보 이후에야 출력 내용이 등장합니다. 그러므로 XML의 시작 부분부터 마지막 택인 </response>까지만을 잘라내서 처리하도록 하겠습니다.

     $response = strchr($response,"<?");
     $response = substr($response,0,strpos($response,"</response>"));

마무리 부분만 남았습니다. 뽑아온 자료에 에러가 포함되어있는지를 확인합니다. 간단하게 <error></error>가 포함되어 있을 경우 성공으로 간주합니다(<message>의 유무도 좋습니다. 단 원칙대로라면 정규식을 통해 각 택의 내용을 불러와 검사해야 합니다). 그렇지 않을 경우 <message></message>사이의 에러 내용을 돌려줍니다.

     if(strstr($response,"")) return true;
     else {
          $tb_error_str = strchr($response,"<message>");
          $tb_error_str = substr($tb_error_str,0,strpos($tb_error_str,"</message>"));
          $tb_error_str = str_replace("<message>","",$tb_error_str);
          $tb_error_str = "트랙백 전송중 오류가 발생했습니다: $tb_error_str";
          return false;
     }

//함수끝
}

이제 소스부분은 끝났습니다. 실제 사용시에는

$res = send_tb("트랙백 URL","글 URL","제목","블로그 이름","내용");
if(!$res) {
     echo("트랙백 전송시 에러 발생: $tb_error_str");
} else {
     //성공시 처리
}

와 같이 사용하면 됩니다.