| 1 | package URI::Amazon::APA; |
|---|
| 2 | use warnings; |
|---|
| 3 | use strict; |
|---|
| 4 | our $VERSION = sprintf "%d.%02d", q$Revision: 0.4 $ =~ /(\d+)/g; |
|---|
| 5 | use Carp; |
|---|
| 6 | use Digest::SHA qw(hmac_sha256_base64); |
|---|
| 7 | use URI::Escape; |
|---|
| 8 | use Encode qw/decode_utf8/; |
|---|
| 9 | use base 'URI::http'; |
|---|
| 10 | |
|---|
| 11 | sub new{ |
|---|
| 12 | my $class = shift; |
|---|
| 13 | my $self = URI->new(@_); |
|---|
| 14 | ref $self eq 'URI::http' or carp "must be http"; |
|---|
| 15 | bless $self, $class; |
|---|
| 16 | } |
|---|
| 17 | |
|---|
| 18 | sub sign { |
|---|
| 19 | my $self = shift; |
|---|
| 20 | my (%arg) = @_; |
|---|
| 21 | my %eq = map { split /=/, $_ } split /&/, $self->query(); |
|---|
| 22 | my %q = map { $_ => decode_utf8( uri_unescape( $eq{$_} ) ) } keys %eq; |
|---|
| 23 | $q{AWSAccessKeyId} = $arg{key}; |
|---|
| 24 | $q{Timestamp} ||= do { |
|---|
| 25 | my ( $ss, $mm, $hh, $dd, $mo, $yy ) = gmtime(); |
|---|
| 26 | join '', |
|---|
| 27 | sprintf( '%04d-%02d-%02d', $yy + 1900, $mo + 1, $dd ), 'T', |
|---|
| 28 | sprintf( '%02d:%02d:%02d', $hh, $mm, $ss ), 'Z'; |
|---|
| 29 | }; |
|---|
| 30 | $q{Version} ||= '2010-09-01'; |
|---|
| 31 | my $sq = join '&', |
|---|
| 32 | map { $_ . '=' . uri_escape_utf8( $q{$_}, "^A-Za-z0-9\-_.~" ) } |
|---|
| 33 | sort keys %q; |
|---|
| 34 | my $tosign = join "\n", 'GET', $self->host, $self->path, $sq; |
|---|
| 35 | my $signature = hmac_sha256_base64( $tosign, $arg{secret} ); |
|---|
| 36 | $signature .= '=' while length($signature) % 4; # padding required |
|---|
| 37 | $q{Signature} = $signature; |
|---|
| 38 | $self->query_form( \%q ); |
|---|
| 39 | $self; |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | sub signature { |
|---|
| 43 | my $self = shift; |
|---|
| 44 | my (%arg) = @_; |
|---|
| 45 | my %eq = map { split /=/, $_ } split /&/, $self->query(); |
|---|
| 46 | my %q = map { $_ => uri_unescape( $eq{$_} ) } keys %eq; |
|---|
| 47 | $q{Signature}; |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | 1; # End of URI::Amazon::APA |
|---|
| 51 | |
|---|
| 52 | =head1 NAME |
|---|
| 53 | |
|---|
| 54 | URI::Amazon::APA - URI to access Amazon Product Advertising API |
|---|
| 55 | |
|---|
| 56 | =head1 VERSION |
|---|
| 57 | |
|---|
| 58 | $Id: APA.pm,v 0.4 2011/05/21 21:53:23 dankogai Exp dankogai $ |
|---|
| 59 | |
|---|
| 60 | =head1 SYNOPSIS |
|---|
| 61 | |
|---|
| 62 | # self-explanatory |
|---|
| 63 | use strict; |
|---|
| 64 | use warnings; |
|---|
| 65 | use URI::Amazon::APA; |
|---|
| 66 | use LWP::UserAgent; |
|---|
| 67 | use XML::Simple; |
|---|
| 68 | use YAML::Syck; |
|---|
| 69 | |
|---|
| 70 | use URI::Amazon::APA; # instead of URI |
|---|
| 71 | my $u = URI::Amazon::APA->new('http://webservices.amazon.com/onca/xml'); |
|---|
| 72 | $u->query_form( |
|---|
| 73 | Service => 'AWSECommerceService', |
|---|
| 74 | Operation => 'ItemSearch', |
|---|
| 75 | Title => shift || 'Perl', |
|---|
| 76 | SearchIndex => 'Books', |
|---|
| 77 | ); |
|---|
| 78 | $u->sign( |
|---|
| 79 | key => $public_key, |
|---|
| 80 | secret => $private_key, |
|---|
| 81 | ); |
|---|
| 82 | |
|---|
| 83 | my $ua = LWP::UserAgent->new; |
|---|
| 84 | my $r = $ua->get($u); |
|---|
| 85 | if ( $r->is_success ) { |
|---|
| 86 | print YAML::Syck::Dump( XMLin( $r->content ) ); |
|---|
| 87 | } |
|---|
| 88 | else { |
|---|
| 89 | print $r->status_line, $r->as_string; |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | =head1 EXPORT |
|---|
| 93 | |
|---|
| 94 | None. |
|---|
| 95 | |
|---|
| 96 | =head1 METHODS |
|---|
| 97 | |
|---|
| 98 | This adds the following methods to L<URI> object |
|---|
| 99 | |
|---|
| 100 | =head2 sign |
|---|
| 101 | |
|---|
| 102 | Sings the URI accordingly to the Amazon Product Advertising API. |
|---|
| 103 | |
|---|
| 104 | $u->sign( |
|---|
| 105 | key => $public_key, |
|---|
| 106 | secret => $private_key, |
|---|
| 107 | ); |
|---|
| 108 | |
|---|
| 109 | =head2 signature |
|---|
| 110 | |
|---|
| 111 | Checks the signature within the URI; |
|---|
| 112 | |
|---|
| 113 | print "The signature is " : $u->signature; |
|---|
| 114 | |
|---|
| 115 | =head1 AUTHOR |
|---|
| 116 | |
|---|
| 117 | Dan Kogai, C<< <dankogai at dan.co.jp> >> |
|---|
| 118 | |
|---|
| 119 | =head1 BUGS |
|---|
| 120 | |
|---|
| 121 | Please report any bugs or feature requests to C<bug-uri-amazon-apa at rt.cpan.org>, or through |
|---|
| 122 | the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=URI-Amazon-APA>. I will be notified, and then you'll |
|---|
| 123 | automatically be notified of progress on your bug as I make changes. |
|---|
| 124 | |
|---|
| 125 | =head1 SUPPORT |
|---|
| 126 | |
|---|
| 127 | You can find documentation for this module with the perldoc command. |
|---|
| 128 | |
|---|
| 129 | perldoc URI::Amazon::APA |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | You can also look for information at: |
|---|
| 133 | |
|---|
| 134 | =over 4 |
|---|
| 135 | |
|---|
| 136 | =item * RT: CPAN's request tracker |
|---|
| 137 | |
|---|
| 138 | L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=URI-Amazon-APA> |
|---|
| 139 | |
|---|
| 140 | =item * AnnoCPAN: Annotated CPAN documentation |
|---|
| 141 | |
|---|
| 142 | L<http://annocpan.org/dist/URI-Amazon-APA> |
|---|
| 143 | |
|---|
| 144 | =item * CPAN Ratings |
|---|
| 145 | |
|---|
| 146 | L<http://cpanratings.perl.org/d/URI-Amazon-APA> |
|---|
| 147 | |
|---|
| 148 | =item * Search CPAN |
|---|
| 149 | |
|---|
| 150 | L<http://search.cpan.org/dist/URI-Amazon-APA/> |
|---|
| 151 | |
|---|
| 152 | =back |
|---|
| 153 | |
|---|
| 154 | =head1 ACKNOWLEDGEMENTS |
|---|
| 155 | |
|---|
| 156 | L<http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html> |
|---|
| 157 | |
|---|
| 158 | =head1 COPYRIGHT & LICENSE |
|---|
| 159 | |
|---|
| 160 | Copyright 2009 Dan Kogai, all rights reserved. |
|---|
| 161 | |
|---|
| 162 | This program is free software; you can redistribute it and/or modify it |
|---|
| 163 | under the same terms as Perl itself. |
|---|