길이 이야기(Giri's Story)

[소셜(SNS)댓글] 싸이월드-C로그 연동 FAQ 본문

IT기술,개발/웹프로그래밍

[소셜(SNS)댓글] 싸이월드-C로그 연동 FAQ

길이 2011. 11. 17. 18:34

--------------------------------------------------------------------------------------------------------

요즘 소셜(SNS)댓글 시스템이 커뮤니티 사이트에서 관심을 받고 있습니다.

이전에 IT관련 회사들은 어떻게 하면 회원가입률을 높일까를 고민하다 이제는 어떻게 하면 커뮤니티를 활성화 시킬 수 있을까로 고민이 바뀌고 있죠. 말 그대로 좋은 정보를 제공하는 것도 중요하지만, 방문자의 호응을 쉽게 이끌어내기 위한 노력으로 SNS 댓글시스템이 각광을 받고 있지 않나 싶습니다.

각 SNS(트위터, 페이스북, 미투데이, 요즘 등) 서비스들의 로그인 API연동에 대한 FAQ를 정리해보도록 하겠습니다.

개발하실 분들은 참조해서 도움이 되셨으면 좋겠습니다.

--------------------------------------------------------------------------------------------------------

싸이월드(네이트) - C로그의 경우 OAuth 라이브러리를 제공하므로 쉽게 연동이 가능합니다.

아래는 라이브러리를 바탕으로 만든 연동 API 샘플입니다.

우선 네이트 개발자센터(http://devsquare.nate.com/)를 통해 개발자등록을 하고 Consumer key 발급 신청합니다.

발급받은 키를 통해 아래 소스를 변경하여 적용합니다.

------------------

index.php

------------------

<?php
header("expires: Thu, 19 Nov 1981 08:52:00 GMT");
header("cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
header("pragma: no-cache");

$oauth_consumer_key = "발급받은 컨슈머 키"; // Your consumer key
$oauth_consumer_key_secret = "발급받은 컨슈머 키 암호"; // Your consumer key secret

$oauth_callback = "콜백URL/callback.php";// Your Call Back Page URL

$oauth_signature_method = "HMAC-SHA1";
$oauth_timestamp = time();
$oauth_nonce = md5(microtime().mt_rand()); // md5s look nicer than numbers;
$oauth_version = "1.0";

$get_request_token_url = "https://oauth.nate.com/OAuth/GetRequestToken/V1a";

$oauth_token = "";
$oauth_token_secret = "";
$oauth_signature = "";

$request_token = "";
$request_token_secret = "";

//Get Request Token

//Generate Base String For Get Request Token
//!!파라메터 이름 순서로 조합해야 한다.
//!!파라메터의 이름과 값은 rfc3986 으로 encode
//[Name=Valeu&Name=Value…] 형식으로 연결
$Query_String = urlencode_rfc3986("oauth_callback")."=".urlencode_rfc3986($oauth_callback);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_consumer_key")."=".urlencode_rfc3986($oauth_consumer_key);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_nonce")."=".urlencode_rfc3986($oauth_nonce);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_signature_method")."=".urlencode_rfc3986($oauth_signature_method);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_timestamp")."=".urlencode_rfc3986($oauth_timestamp);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_version")."=".urlencode_rfc3986($oauth_version);

//Base String 요소들을 rfc3986 으로 encode
$Base_String = urlencode_rfc3986("POST")."&".urlencode_rfc3986($get_request_token_url)."&".urlencode_rfc3986($Query_String);

//지금 단계에서는 $oauth_token_secret이 ""
$Key_For_Signing = urlencode_rfc3986($oauth_consumer_key_secret)."&".urlencode_rfc3986($oauth_token_secret);

//oauth_signature 생성
$oauth_signature=base64_encode(hash_hmac('sha1', $Base_String, $Key_For_Signing, true));

//Authorization Header 조합
$Authorization_Header = "Authorization: OAuth ";
$Authorization_Header .= urlencode_rfc3986("oauth_version")."=\"".urlencode_rfc3986($oauth_version)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_nonce")."=\"".urlencode_rfc3986($oauth_nonce)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_timestamp")."=\"".urlencode_rfc3986($oauth_timestamp)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_consumer_key")."=\"".urlencode_rfc3986($oauth_consumer_key)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_callback")."=\"".urlencode_rfc3986($oauth_callback)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature_method")."=\"".urlencode_rfc3986($oauth_signature_method)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature")."=\"".urlencode_rfc3986($oauth_signature)."\"";

$parsed = parse_url($get_request_token_url);
$scheme = $parsed["scheme"];
$path = $parsed["path"];
$ip = $parsed["host"];
$port = @$parsed["port"];

if ($scheme == "http") {
if(!isset($parsed["port"])) { $port = "80"; } else { $port = $parsed["port"]; };
$tip = $ip;
} else if ($scheme == "https") {
if(!isset($parsed["port"])) { $port = "443"; } else { $port = $parsed["port"]; };
$tip = "ssl://" . $ip;
}
$timeout = 5;
$error = null;
$errstr = null;

//Request 만들기
$out = "POST " . $path . " HTTP/1.1\r\n";
$out .= "Host: ". $ip . "\r\n";
$out .= $Authorization_Header . "\r\n";
$out .= "Accept-Language: ko\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: 0\r\n\r\n"; //Request Token 받기에서는 post body에 들어가는 파라메터가 없어서 0

//Request 보내기
$fp = fsockopen($tip, $port, $errno, $errstr, $timeout);

//Reponse 받기
if (!$fp) {
Message("연동중 API오류가 발생하였습니다. 다시 시도해주세요.", "close");
} else {
fwrite($fp, $out);
$response = "";
while ($s = fread($fp, 4096)) {
$response .= $s;
}

//Response Header와 Body 분리
$bi = strpos($response, "\r\n\r\n");
$body = substr($response, $bi+4);

//정상적인 경우 $body값은
//oauth_token=5a3377a10ad1f2c937e7bd8c83e57bec&oauth_token_secret=5be6580cc3e8ea2c71a1c56106c19c1f&oauth_callback_ctrue
//의 형식으로 떨어짐.
$tmpArray = explode("&",$body);
$TokenArray = explode("=",$tmpArray[0]);
$TokenSCArray = explode("=",$tmpArray[1]);
$request_token = $TokenArray[1];
$request_token_secret = $TokenSCArray[1];


//request_token, request_token_secret 세션에 저장
$_SESSION['oauth_request_token'] = trim($request_token);
$_SESSION['oauth_request_token_secret'] = trim($request_token_secret);
}

//Redirect to Authorize URL
//다음 단계인 Nate Login을 위해 페이지 이동
$Authorize_URL = "https://oauth.nate.com/OAuth/Authorize/V1a?oauth_token=".$request_token;
Header("Location: $Authorize_URL");

function urlencode_rfc3986($input) {
if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
?>

-------------------------

callback.php

-------------------------

<?php
header("expires: Thu, 19 Nov 1981 08:52:00 GMT");
header("cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
header("pragma: no-cache");

include_once $g_Path_System . "/@inc/xml_parser_php5.php";

$oauth_consumer_key = "발급받은 컨슈머 키"; // Your consumer key
$oauth_consumer_key_secret = "발급받은 컨슈머 키 암호"; // Your consumer key secret

$oauth_callback = "콜백URL/callback.php";// Your Call Back Page URL

$callBackToken = $_REQUEST["oauth_token"];
$oauth_verifier= $_REQUEST["oauth_verifier"];

$request_token = $callBackToken;
$request_token_secret = "";

// 저장된 세션토큰과 전달받은 토큰 유효성 검사
$oauth_request_token = trim($_SESSION['oauth_request_token']);
$oauth_request_token_secret = trim($_SESSION['oauth_request_token_secret']);

if($oauth_request_token == $request_token && $oauth_request_token_secret != "") {
$request_token_secret = $oauth_request_token_secret;
} else {
Message("연동중 API오류가 발생하였습니다. 다시 시도해주세요.", "close");
}

//미리 request_token,request_token_secret를 저장 해 두었으로 매치되는 request_token_secret를 확보
$oauth_signature_method = "HMAC-SHA1";
$oauth_timestamp = time();
$oauth_nonce = md5(microtime().mt_rand()); // md5s look nicer than numbers;
$oauth_version = "1.0";

$get_access_token_url = "https://oauth.nate.com/OAuth/GetAccessToken/V1a";
$access_token = "";
$access_token_secret = "";

//Get Access Token

//Generate Base String For Get Access Token
//!!파라메터 이름 순서로 조합해야 한다.
//!!파라메터의 이름과 값은 rfc3986 으로 encode
//[Name=Valeu&Name=Value…] 형식으로 연결

$Query_String = urlencode_rfc3986("oauth_consumer_key")."=".urlencode_rfc3986($oauth_consumer_key);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_nonce")."=".urlencode_rfc3986($oauth_nonce);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_signature_method")."=".urlencode_rfc3986($oauth_signature_method);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_timestamp")."=".urlencode_rfc3986($oauth_timestamp);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_token")."=".urlencode_rfc3986($request_token);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_verifier")."=".urlencode_rfc3986($oauth_verifier);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_version")."=".urlencode_rfc3986($oauth_version);

//Base String 요소들을 rfc3986 으로 encode
$Base_String = urlencode_rfc3986("POST")."&".urlencode_rfc3986($get_access_token_url)."&".urlencode_rfc3986($Query_String);

//지금 단계에서는 $oauth_token_secret에 request_token_secret을 사용
$Key_For_Signing = urlencode_rfc3986($oauth_consumer_key_secret)."&".urlencode_rfc3986($request_token_secret);

//oauth_signature 생성
$oauth_signature = base64_encode(hash_hmac('sha1', $Base_String, $Key_For_Signing, true));

//Authorization Header 조합
$Authorization_Header = "Authorization: OAuth ";
$Authorization_Header .= urlencode_rfc3986("oauth_version")."=\"".urlencode_rfc3986($oauth_version)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_nonce")."=\"".urlencode_rfc3986($oauth_nonce)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_timestamp")."=\"".urlencode_rfc3986($oauth_timestamp)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_consumer_key")."=\"".urlencode_rfc3986($oauth_consumer_key)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_token")."=\"".urlencode_rfc3986($request_token)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_verifier")."=\"".urlencode_rfc3986($oauth_verifier)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature_method")."=\"".urlencode_rfc3986($oauth_signature_method)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature")."=\"".urlencode_rfc3986($oauth_signature)."\"";

$parsed = parse_url($get_access_token_url);
$scheme = $parsed["scheme"];
$path = $parsed["path"];
$ip = $parsed["host"];
$port = @$parsed["port"];

if ($scheme == "http") {
if(!isset($parsed["port"])) { $port = "80"; } else { $port = $parsed["port"]; };
$tip = $ip;
} else if ($scheme == "https") {
if(!isset($parsed["port"])) { $port = "443"; } else { $port = $parsed["port"]; };
$tip = "ssl://" . $ip;
}
$timeout = 5;
$error = null;
$errstr = null;

//Request 만들기
$out = "POST " . $path . " HTTP/1.1\r\n";
$out .= "Host: ". $ip . "\r\n";
$out .= $Authorization_Header . "\r\n";
$out .= "Accept-Language: ko\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: 0\r\n\r\n"; //Request Token 받기에서는 post body에 들어가는 파라메터가 없어서 0

//Request 보내기
$fp = fsockopen($tip, $port, $errno, $errstr, $timeout);

//Reponse 받기
if (!$fp) {
Message("연동중 API오류가 발생하였습니다. 다시 시도해주세요.", "close");
} else {
fwrite($fp, $out);
$response = "";
while ($s = fread($fp, 4096)) {
$response .= $s;
}

//Response Header와 Body 분리
$bi = strpos($response, "\r\n\r\n");
$body = substr($response, $bi+4);

//정상적인 경우 $body값은
//oauth_token=d934cf945ee6f6bdfb65865f1c1d116a&oauth_token_secret=9a024ddded7a188790796bb9be32f4e5
//의 형식으로 떨어짐.
$tmpArray = explode("&",$body);
$TokenArray = explode("=",$tmpArray[0]);
$TokenSCArray = explode("=",$tmpArray[1]);
$access_token = $TokenArray[1];
$access_token_secret = $TokenSCArray[1];

//access_token, access_token_secret 출력
// echo ("access_token = ".$access_token."<br />");
// echo ("access_token_secret = ".$access_token_secret."<br />");

/* If HTTP response is 200 continue otherwise send to connect page to retry */
if ($access_token != "" && $access_token_secret != "") {
/* The user has been verified and the access tokens can be saved for future use */

// C로그 사용자 정보 불러오기 ---------------------------------------------------------------
$oauth_timestamp = time();
$oauth_nonce = md5(microtime().mt_rand()); // md5s look nicer than numbers;

$get_clog_user_info_url = "https://openapi.nate.com/OApi/RestApiSSL/CY/200800/gethomeinfo/v1";

$menuType="1";

//조회대상 미니홈피 아이디는 일촌 API로 확보 가능합니다.
$targetId="";//공백으로 두면 Access Token 소유자의 미니 홈피를 조회합니다.

//Generate Base String For Get Access Token
//!!파라메터 이름 순서로 조합해야 한다.
//!!파라메터의 이름과 값은 rfc3986 으로 encode
//[Name=Valeu&Name=Value…] 형식으로 연결

$Query_String = urlencode_rfc3986("oauth_consumer_key")."=".urlencode_rfc3986($oauth_consumer_key);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_nonce")."=".urlencode_rfc3986($oauth_nonce);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_signature_method")."=".urlencode_rfc3986($oauth_signature_method);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_timestamp")."=".urlencode_rfc3986($oauth_timestamp);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_token")."=".urlencode_rfc3986($access_token);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("oauth_version")."=".urlencode_rfc3986($oauth_version);
$Query_String .= "&";
$Query_String .= urlencode_rfc3986("targetId")."=".urlencode_rfc3986($targetId);

//Base String 구성 요소를 &로 연결
$Base_String = urlencode_rfc3986("POST")."&".urlencode_rfc3986($get_clog_user_info_url)."&".urlencode_rfc3986($Query_String);

//지금 단계에서는 $oauth_token_secret에 request_token_secret을 사용
$Key_For_Signing = urlencode_rfc3986($oauth_consumer_key_secret)."&".urlencode_rfc3986($access_token_secret);

//oauth_signature 생성
$oauth_signature=base64_encode(hash_hmac('sha1', $Base_String, $Key_For_Signing, true));

//Authorization Header 조합
$Authorization_Header = "Authorization: OAuth ";
$Authorization_Header .= urlencode_rfc3986("oauth_version")."=\"".urlencode_rfc3986($oauth_version)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_nonce")."=\"".urlencode_rfc3986($oauth_nonce)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_timestamp")."=\"".urlencode_rfc3986($oauth_timestamp)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_consumer_key")."=\"".urlencode_rfc3986($oauth_consumer_key)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_token")."=\"".urlencode_rfc3986($access_token)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature_method")."=\"".urlencode_rfc3986($oauth_signature_method)."\",";
$Authorization_Header .= urlencode_rfc3986("oauth_signature")."=\"".urlencode_rfc3986($oauth_signature)."\"";

$parsed = parse_url($get_clog_user_info_url);
$scheme = $parsed["scheme"];
$path = $parsed["path"];
$ip = $parsed["host"];
$port = @$parsed["port"];

$queryStr="targetId=".$targetId;
$queryLength = (strlen($queryStr));

if ($scheme == "http") {
if(!isset($parsed["port"])) { $port = "80"; } else { $port = $parsed["port"]; };
$tip = $ip;
} else if ($scheme == "https") {
if(!isset($parsed["port"])) { $port = "443"; } else { $port = $parsed["port"]; };
$tip = "ssl://" . $ip;
}
$timeout = 5;
$error = null;
$errstr = null;

//Request 만들기
$out = "POST " . $path . " HTTP/1.1\r\n";
$out .= "Host: ". $ip . "\r\n";
$out .= $Authorization_Header . "\r\n";
$out .= "Accept-Language: ko\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: " . $queryLength . "\r\n\r\n";
$out .= $queryStr;

//echo("Request=".$out."<br />");
//exit;
//Request 보내기
$fp = fsockopen($tip, $port, $errno, $errstr, $timeout);

//Reponse 받기
if (!$fp) {
Message("연동중 API오류가 발생하였습니다. 다시 시도해주세요.", "close");
} else {
fwrite($fp, $out);
$response = "";
while ($s = fread($fp, 4096)) {
$response .= $s;
}

//echo("resp".$response."<br />");
//exit;

//Response Header와 Body 분리
$bi = strpos($response, "\r\n\r\n");
$body = substr($response, $bi+4);

$parser = new XMLParser($body); // 객체생성 parser라는 객체를 생성함
$parser->Parse(); // Parse()메소를 호출하여 xml을 dom 방식으로 파싱함

$rcode = $parser->document->rcode[0]->tagData;
$rmsg = $parser->document->rmsg[0]->tagData;

if($rcode == "RET0000") {
$nickname = $parser->document->name[0]->tagData;
$url_name = $parser->document->id[0]->tagData;
$profile_img_url_tmp = explode("<profileUrl><![CDATA[", $body);
$profile_img_url_tmp2 = explode("]]></profileUrl>", $profile_img_url_tmp[1]);
$profile_img_url = $profile_img_url_tmp2[0];

// 넘어온 인증정보를 통해 서버에 로그인 인증정보를 심기!

// 자체 프로그램 소스처리(DB를 저장하든, 세션으로 저장하든)

// ......

// ---------------------------------------------------

} else {
switch($rcode) {
case "RET0002" :
case "RET301" :
Message("싸이월드 \'ⓒ로그\'가 개설되어있지 않습니다. \\n 개설 후 이용하실 수 있습니다.", "close");
break;
default :
Message("[ {$rcode} / {$rmsg} ]\\n SNS로그인 연동을 진행할 수 없습니다. \\n 연동을 위해 싸이월드 \'ⓒ로그\'가 개설되어 있어야 합니다.", "close");
break;
}
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta c"text/html; charset=utf-8" http-equiv="Content-Type" />
</head>
<body>
<script>
opener.location.reload();
self.close();
</script>
</body>
</html>
<?
} else {
/* Save HTTP status for error dialog on connnect page.*/
Message("연동중 API오류가 발생하였습니다. 다시 시도해주세요.", "close");
}
}

function urlencode_rfc3986($input) {
if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
?>

Comments