なんちゃって☆めも :: Google URL Shortener API であそ~ぶ

OAuth :: 履歴を取得

OAUthを使ってAPIにアクセスすると、同じLong URLに対して毎回違ったShort URLを返してきます。とりあえず、履歴を見てみましょう…。なお、履歴を見るにはOAuthによる認証が必須です。

hisotry.cgi (OAuth必須)

#!/usr/bin/perl

use LWP::UserAgent;
use LWP::ConnCache;
use Digest::HMAC_SHA1;
use JSON;

# API Key
my $apikey = 'API key';

# OAuth Consumer Secret
my $consumer_sec = 'OAuth Consumer Secret';

# OAuth Consumer Key
my $consumer_key = 'OAuth Consumer Key';

# OAuth Access Token
my $oauth_token = 'OAuth Access Token';

# OAuth Access Token Secret
my $oauth_token_secret = 'OAuth Access Token Secret';

# Requestを送るURL
my $url = 'https://www.googleapis.com/urlshortener/v1/url/history';

# Request Method
my $method = 'GET';

# OAuth用パラメータ
my %oauth_param;
$oauth_param{oauth_token} = url_encode($oauth_token);
$oauth_param{oauth_consumer_key} = $consumer_key;

# 署名方法はHMAC-SHA1で。
$oauth_param{oauth_signature_method} = 'HMAC-SHA1';

# APIに渡すパラメータ
my %query_param;
$query_param{key} = $apikey;

# #define STARTTOKEN
my $STARTTOKEN = 'start-token',

# Keep-alive 有効
my $ua = LWP::UserAgent->new;
$ua->conn_cache(LWP::ConnCache->new);

# 結果を格納
my $response = '';

for (my $nextPageToken = '';;) {
	# タイムスタンプとか
	$oauth_param{oauth_timestamp} = time();
	$oauth_param{oauth_nonce} = int(rand(2**32)) . int(rand(2**32));

	# 前のループで「次」があるといわれていれば、そこからスタート
	if ($nextPageToken) {
		$query_param{$STARTTOKEN} = url_encode($nextPageToken);
	}

	# Signature Base String の作成
	my $signature_base = createSigBase($url, $method, \%oauth_param, \%query_param);

	# Token Secretを取得済なので、署名キーは
	# '<OAuth Consumer Secret>&<OAuth Token Secret>'
	my $signature_key = url_encode($consumer_sec) . '&' . url_encode($oauth_token_secret);

	# Signature Base String を、key で署名してURLエンコードして署名を作成
	my $signature = url_encode(hmac_sha1($signature_key, $signature_base));

	# Authorization: ヘッダ情報の生成
	my $auth_param = createAuthParam(\%oauth_param, $signature);

	# APIにパラメータを渡すためにURLに連結
	my $cur_url = $url;
	if (%query_param) {
		$cur_url .= '?' . createQueryParam(\%query_param);
	}

	# 不要なので消去
	delete $query_param{$STARTTOKEN};

	# 準備完了!リクエストの実行!!
	my $res = $ua->request(
		HTTP::Request->new(
			$method,
			$cur_url,
			HTTP::Headers->new(
				'Authorization' => $auth_param
			)
		)
	);

	# 結果をバッファ
	$response .= $res->content;

	my $result = decode_json($res->content);

	# 次はあるか?
	$nextPageToken = $result->{nextPageToken};
	unless ($nextPageToken) {
		last;
	}
}

print "Content-type: application/json\n\n";
print $response;

exit;

# Signature Baseを作ります
sub createSigBase {
	my ($url, $method, $ref_oauth_param, $ref_query_param) = @_;
	my %all_param = (%$ref_oauth_param, %$ref_query_param); # マージ

	my @sb = ();
	foreach my $k (sort(keys(%all_param))) {
		push(@sb, $k . '=' . $all_params{$k});
	}

	my $param = join('&', @sb);
	return join('&', ($method, url_encode($url), url_encode($param)));
}

# Authorization: ヘッダの内容を作ります
sub createAuthParam {
	my ($ref_oauth_param, $sig) = @_;
	my @op = ();
	while (my ($key, $value) = each(%$ref_oauth_param)) {
		push(@op, $key . '="' . $value . '"');
	}
	push(@op, "oauth_signature=\"$sig\"");
	return 'OAuth ' . join(', ', @op);
}

# APIにパラメータを渡すためにURLに連結する準備
sub createQueryParam {
	my $ref_query_param = shift;
	my @qp = ();
	while (my ($k, $v) = each(%$ref_query_param)) {
		push(@qp, $k . '=' . $v);
	}
	return join('&', @qp);
}


# hmac_sha1 署名。
sub hmac_sha1 {
	my ($key, $msg) = @_;;
	return Digest::HMAC_SHA1->new($key)->add($msg)->b64digest . '=';
}

# URL エンコード
# http://www.din.or.jp/~ohzaki/perl.htm#JP_Escape を参考にしました。
sub url_encode {
	$_ = shift;
	s/([^a-zA-Z0-9_.!~*'()-])/'%' . uc(unpack('H2', $1))/eg;
	return $_;
}

# URL デコード
# http://www.din.or.jp/~ohzaki/perl.htm#JP_Escape を参考にしました。
# 今回は使いません…
sub url_decode {
	$_ = shift;
	s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
	return $_;
}
2巡目からは、前の時のnextPageTokenをstart-tokenとしてURLに付加します。start-tokenとkeyはSignature Base Stringには入れる必要がありますが、Authorization:ヘッダには入れてはいけません!