RSSReader Class 제작 및 Reader 만들기

by 조쉬 posted Aug 22, 2016
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄

앞에서 배운 지식을 바탕으로 간단한 RSS Reader를 제작해 보도록 하겠습니다. 먼저 아래의 데모를 한번씩들 실행하여 보시기 바랍니다.
그리고 구독하고 있는 채널이 있다면 다른 RSS URL로 테스트도 해 보시구요. 아마도 해당 강좌를 보신 후에는 이 보다 멋진 RSS
Reader(Aggregator)를 작성하실 수 있을 것입니다.


1. 데모보기

Simple RSS Reader - http://www.ihelpers.co.kr/lib/jmrss/simplereader.php?URL=http://rss.joins.com/joins_news_list.xml


2. URL 통신
저번 시간에는 RSS 파싱하는 방법에 대하여 소개를 하였습니다. 이번에는 RSS Reader 구현을 위한 URL
통신 방법과 그외의 핵심 기능에 대하여 알아보도록 하겠습니다.

그럼 URL로 RSS 구문을 어떻게 가지고 올까요?


저의 경우는 대부분의 경우는 HTTP 모듈을 사용하나, PHP에서는 fopen 함수를 사용하여 복잡한 과정 없이 웹상의 정보를
로컬디렉토리의 파일정보 처리하는 것 처럼 너무도 쉽게 구현 할수 있습니다.


HTTP의 헤더정보를 같이 좀더 세부적인 처리를 원하는 분은 소스코드에 포함된 "httpclass.php" 클래스를 분석해 보시기
바랍니다. 해당 강좌의 모든 코드는 HTTP 모듈을 사용하였습니다.






$fd = fopen ("http://www.ihelpers.co.kr", "r");

while (!feof ($fd)) {
$buffer .= fgets($fd, 4096);
}
fclose ($fd);

echo $buffer;


3. RSSReader Class
RSSReader 클래스는 RSSParser 클래스,URLCache
클래스,httpclass 클래스 사용하며, 특히 RSSParser 클래스를 상속받아 사용하고 있습니다.
클래스를 만들면서도 상속에 대한
문제점으로 사용여부를 두고 갈등을 했었지만, RSSParser에 포함된 GET 함수들을 모두 다시 작성할 생각을 하니 너무 귀찮아서 PHP에서
처음으로 상속을 사용해 보았습니다. 혹시 아직도 PHP에서 Class 나 상속기능을 사용해 보지 않으신 분은 참고하여 보시면 일정 부분 도움이
될것입니다.

RSSReader 변수(Property)


  • url - RSS URL정보
  • isCache - Cache 사용여부 ( true,false )
  • CacheDir - Cache 디렉토리
  • cacheInterval - Cache 갱신 주기
  • ErrNum - 에러번호
  • ErrMsg - 에러메세지
RSSReader 함수(method)

  • RSSReader - 생성자로써 URL정보,Cache사용여부,Cache 갱신주기, Cache 디렉토리를 변수로써 입력 받는다.
  • setCache - Cache 사용여부 설정
  • setCacheDir - Cache 디렉토리 설정
  • setCacheInterval - Cache 갱신 주기 설정
  • Read

    RSS Reader 클래스에서 가장 주요 업무인 HTTP 통신과 RSS 구문 분석을 수행하는 함수이니 RSSReader 클래스에서 가장
    중요한 함수라고 할 수 있을 것입니다. Read 함수는 내부적으로 _getResponse를 호출하여 HTTP 통신을 수행하고, 부모 클래스의
    parse 함수를 통하여 RSS 구문을 분석하여 줍니다.


  • _getResponse

    Cache 사용여부를 판단하고 Cache를 사용할 경우는 Cache된 파일의 최종수정시간과 설정된 갱신 주기를 비교하여 Cache의 갱신
    및 조회여부를 판단하여 URL정보를 읽어오게 됩니다. Cache를 사용하지 않을 경우는 당연히 직접 자료를 조회하게 됩니다.

    
    
    if($status == 0){ // 캐쉬정보가 이전것일때
    $response = $cache->get($this->url);
    $http->AddHeader("If-Modified-Since",$response['last-modified']);
    $http->AddHeader("ETag",$response['etag']);
    }
    $http->Get($path);

    if($http->Response['code'] == 304){
    } elseif($http->Response['code'] == 200 || $http->Response['code'] == 304){
    $response = $http->Response;
    $cache->set($this->url,$response);
    } else {
    $this->Error(0,"Response Not Success");
    return false;
    }
    return $response;
    위의 코드는 조금 재미있게 볼 수 있을 것 같습니다. Cache 정보가 이전 것이라면 URL통신을 하여 새로운 정보를
    가지고 와야 할 것입니다. 그 때 etag 와 last-modified를 포함하여 웹서버와 통신하여 URL 정보가 Cache된 정보와 비교하여
    갱신이 되지 않았다면,웹서버는 상태코드로 304 를 리턴해 줍니다. 웹서버에 정보가 갱신이 되지 않았다면 RSS Reader쪽은 Cache정보를
    갱신할 필요가 없고 웹서버에서는 URL에 해당하는 문서의 갱신상태만 파악하면 되기 때문에 좀 더 빠르게 통신을 할 수 있게 됩니다.






<?
/*///////////////////////////////////////////////////////////////


작성자 : 손상모<smson@ihelpers.co.kr>
최초작성일 :
2004.10.27
변경내용 : 없슴


/////////////////////////////////////////////////////////////////*/


require_once("RSSParser.php");
require_once("URLCache.php");
require_once("httpclass.php");


/**
* RSS Reader Class
*
* RSS Format 읽기 기능 ( URLCache와 httpclass 이용
)
*
* @author Sang Mo,Son <smson@ihelpers.co.kr>
* @version
0.9 beta
* @access public
*/
class
RSSReader extends RSSParser {


var $url;


var $ErrNum;
var $ErrMsg;


var $isCache;

var $CacheDir;


var $cacheInterval;

/**
* Constructor
*

* @access public
* @param string url
* @param boolean Cache
유무
* @param int Cache 유효시간
* @return void

*/
function RSSReader($url,$isCache = true,$cacheInterval = 3600,$CacheDir =
"./cache"){
$this->url = $url;
$this->isCache =
$isCache;
$this->cacheInterval =
$cacheInterval;
$this->CacheDir =
$CacheDir;
parent::RSSParser();
}


/**
* Cache 유무 설정
*
* @access public
*
@param boolean Cache 유무
* @return void
*/
function
setCache($isCache){
$this->isCache = $isCache;
}


/**
* Cache 디렉토리 설정
*
* @access public
*
@param string Cache 디렉토리
* @return void
*/
function
setCacheDir($CacheDir){
$this->CacheDir = $CacheDir;
}


/**
* Cache 유효시간 설정
*
* @access public
*
@param int Cache 유효시간
* @return void
*/
function
setCacheInterval($cacheInterval){
$this->cacheInterval =
$cacheInterval;
}


/**
* RSS 읽기
*
* @access private
*
@return boolean
*/
function Read(){
$response =
$this->_getResponse();
if($response){
$this->parse($response['body']);
return
true;
} else {
return false;
}
}


/**
* RSS의 URL 또는 Cache 정보
*
*
@access private
* @return array response array
*/
function
_getResponse(){


$aurl = parse_url($this->url);
$host =
$aurl["host"];
$port = $aurl["port"];
$path =
$aurl["path"];
if(!empty($aurl["query"])){
$path =
sprintf("%s?%s",$path,$aurl["query"]);
}
if(empty($port)){ $port = 80;
}
if(empty($path)){ $path = "/"; }


if($this->isCache){
$cache = new
URLCache();
$cache->setInterval($this->cacheInterval);
$cache->setCacheDir($this->CacheDir);


$status =
$cache->checkCache($this->url);


if($status == 1){ // 캐쉬정보가 새로운
것이라면
$response = $cache->get($this->url);
return
$response;
} else {
$http = new
HTTP($host,$port,10);
if(!$http->Err){
if($status == 0){ //
캐쉬정보가 이전것일때
$response =
$cache->get($this->url);
$http->AddHeader("If-Modified-Since",$response['last-modified']);
$http->AddHeader("ETag",$response['etag']);
}
$http->Get($path);

if($http->Response['code']
== 304){
} elseif($http->Response['code'] == 200 ||
$http->Response['code'] == 304){
$response =
$http->Response;
$cache->set($this->url,$response);
}
else {
$this->Error(0,"Response Not Success");
return
false;
}
return $response;
} else
{
$this->Error(0,"Socket Connect Fail");
return
false;
}
$http->Close();
}
} else {
$http =
new HTTP($host,$port,10);
if(!$http->Err){
$buf =
$http->Get($path);
if($http->Response['code'] == 200 ||
$http->Response['code'] == 304){
return
$http->Response;
} else {
$this->Error(0,"Response Not
Success");
return false;
}
} else
{
$this->Error(0,"Socket Connect Fail");
return
false;
}
$http->Close();
}
}


/**
* 에러
*
* @access public
*
@param int error number
* @param string error message
*
@return void
*/
function
Error($errnum,$errmsg){
$this->ErrNum = $errnum;
$this->ErrMsg =
$errmsg;
}
}



4. URLCache에 대하여

브라우저가 Cache를 사용하지 않아 매번 접속시마다 변경이 잘 되지 않는 이미지를 다운로드 받아야 한다면 이처럼 웹이 발전되지 않았을
것입니다.


아마도 제작한 RSS Reader에서 Cache를 사용하지 않는다면, 채널을 구독하고 있는 사용자들의 주기적인 접속은 웹서버에 대한
공격으로 변신하여 웹서버 관리자의 얼굴을 하얗게 변하게 할 것입니다. 10,000명의 구독자에 의하여 프로그램이 1분 단위로 채널에 접속하여
정보의 갱신여부만 확인한다고 생각하면 이 만큼의 시스템 자원 낭비가 어디 있겠습니까?


RSS Reader의 경우는 시간이 많이 소요되는 Network 통신을 해야 하기에, 이 문제를 최소화 할 수 있는 Cache의 사용은
RSS Reader 프로그램 개발시에 상당히 중요한 부분이라고 생각합니다. Cache 사용은 "URL
Cache를 사용하여 웹을 더욱 빠르게"
강좌와 소스코드에 포함되어 있는 URLCache 클래스를 참고하여 주십시요.

5. Simple RSS Reader

강좌 시작에서 본 간단한 RSS Reader 코드입니다.





<?

include "RSSReader.php";

$url = $HTTP_GET_VARS["URL"];
$rss = new RSSReader($url,false);

echo "<html><head><title>Simple RSS Reader</title>\n";
echo "<style><!-- BODY,TD,SELECT { FONT: 9pt Arial; LINE-HEIGHT: 17px;} //--></style>\n";
echo "<body><form>RSS URL : <input type=text name=URL value=\"$url\" size=70> ";
echo "<input type=submit value=\"조회\">\n";
echo "<hr>\n";
echo "</form>\n";

if(!empty($url)){
$response = $rss->Read();
if($response){
$channel = $rss->getChannel();
while (list($key, $value) = each ($channel)) {
echo "<li>$key => $value</li>\n";
}

echo "<p><table width=100%>";
$count = 0;
foreach($rss->getItems() as $items){

if($count == 0){
echo "<tr>";
while (list($key, $value) = each ($items)) {
printf("<td bgcolor=\"#EEEEEE\">%s</td>\n",$key);
}
echo "</tr>";
}

echo "<tr>";
while (list($key, $value) = each ($items)) {
printf("<td bgcolor=\"#F7F7F7\">%s</td>\n",$value);
}
echo "</tr>";

$count++;
}
echo "</table>";
}
}
echo "</body></html>\n";
?>