line
stmt
bran
cond
sub
pod
time
code
1
package Net::Pavatar;
2
3
1
1
21289
use warnings;
1
2
1
32
4
1
1
5
use strict;
1
1
1
30
5
1
1
5457
use LWPx::ParanoidAgent;
1
382575
1
990
6
1
1
16
use Carp;
1
1
1
474
7
1
1
11
use URI;
1
2
1
37
8
1
1
1005
use GD;
0
0
9
use Regexp::Common qw /URI/;
10
11
=head1 NAME
12
13
Net::Pavatar - Pavatar client
14
15
=head1 VERSION
16
17
Version 1.01
18
19
=cut
20
21
our $VERSION = '1.01';
22
23
=head1 SYNOPSIS
24
25
use Net::Pavatar;
26
27
my ($hash, $file_type) = Net::Pavatar->fetch( 'http://someblog.com/', { size => [32, 48] } );
28
29
if ($file_type) {
30
open FILE, ">avatar.$file_type";
31
print FILE $hash->{'48'};
32
close FILE;
33
}
34
35
=cut
36
37
sub _browser_get {
38
my $url = shift;
39
my $browser = shift;
40
41
my ($i, $resp) = (0, undef);
42
do {
43
if ($i++) { sleep(1); }
44
$resp = $browser->get($url);
45
} until ($i >= 3 or $resp->code <= 499);
46
return wantarray ? ($resp, $resp->is_success) : $resp;
47
}
48
49
50
=head1 DESCRIPTION
51
52
Fetches a pavatar image from a given URL and gives it to you in the sizes you specify. Uses LWPx::ParanoidAgent to protect your servers from attacks.
53
54
This module fully conforms to Pavatar spec 0.3.0 (L), which is the latest one on Apr 25th, 2007.
55
56
=head1 METHODS
57
58
=cut
59
60
sub _discover {
61
my $class = shift;
62
my $url = shift;
63
my $params = shift || {};
64
65
my $ua = $params->{'ua'} || LWPx::ParanoidAgent->new( timeout => 15, parse_head => 0 );
66
my ($resp, $ok) = &_browser_get($url, $ua);
67
if (! $ok) { return }
68
my $base = $resp->base();
69
70
# STEP 3.a of spec
71
my ($answer) = $resp->header('X-Pavatar');
72
if (defined $answer) {
73
if ($answer eq 'none' or $answer !~ /$RE{'URI'}{'HTTP'}/) { return }
74
return $answer;
75
}
76
77
# STEP 3.b of spec
78
my $page = $resp->content;
79
if ($resp->content_type =~ /\b(x?html|xml)\b/) {
80
($answer) = $page =~ / /gi;
81
if (defined $answer) {
82
if ($answer eq 'none' or $answer !~ /$RE{'URI'}{'HTTP'}/) { return }
83
return $answer;
84
}
85
}
86
87
# STEP 3.c of spec
88
my $uri = URI->new($url);
89
#my $uri = $resp->request->uri;
90
if ($uri->scheme ne 'http') { return; }
91
$uri = 'http://'.$uri->host_port.($uri->path || '/');
92
my $pavuri = URI->new_abs('pavatar.png', $uri);
93
94
my $max_size = $ua->max_size;
95
$ua->max_size(51200);
96
97
($resp, $ok) = &_browser_get( $pavuri->as_string, $ua );
98
if ($ok) { $ua->max_size($max_size); return wantarray ? ($pavuri, $resp) : $pavuri; }
99
100
my $did_pavuri = $pavuri->as_string;
101
$pavuri->path('/pavatar.png');
102
103
if ($pavuri->as_string ne $did_pavuri) {
104
($resp, $ok) = &_browser_get( $pavuri, $ua );
105
if ($ok) { $ua->max_size($max_size); return wantarray ? ($pavuri, $resp) : $pavuri; }
106
}
107
108
$ua->max_size($max_size);
109
110
return;
111
}
112
113
114
115
=head2 my ($hashref, $type) = Net::Pavatar->fetch( $url, \%opts )
116
117
Returns a hashref and a string, as a 2-list. The hash contains the image sizes as keys, and the image data for each size as values. The string contains the image type and can either be 'jpeg', 'png' or 'gif'. If a pavatar does not exist, or is not valid for any reason, returns null.
118
119
The \%opts hashref is optional, and accepts the following keys:
120
121
C : the sizes that you want the pavatar image returned in - defaults to 80
122
123
C : the total time that UserAgent is allowed to retrieve each page or image - defaults to 15
124
125
e.g. C<< Net::Pavatar->fetch( $url, { size => [32, 48], timeout => 25 } ) >>
126
127
=cut
128
129
sub fetch {
130
my $class = shift;
131
my $url = shift;
132
my $params = shift || {};
133
134
my $ua = $params->{'ua'} || LWPx::ParanoidAgent->new( timeout => 15, parse_head => 0 );
135
($url, my $resp) = $class->_discover($url, { ua => $ua });
136
if (! $url) { return; }
137
138
my $max_size = $ua->max_size;
139
$ua->max_size(51200);
140
my $ok;
141
if (! $resp) {
142
($resp, $ok) = &_browser_get($url, $ua);
143
} else {
144
$ok = 1;
145
}
146
$ua->max_size($max_size);
147
if (! $ok) { return; }
148
149
my $type = $resp->content_type;
150
($type) = $type =~ /^image\/(.+)$/g;
151
152
my $img;
153
if ($type eq 'jpeg') {
154
$img = GD::Image->newFromJpegData($resp->content, 1);
155
} elsif ($type eq 'gif') {
156
$img = GD::Image->newFromGifData($resp->content, 1);
157
} elsif ($type eq 'png') {
158
$img = GD::Image->newFromPngData($resp->content, 1);
159
} else {
160
return;
161
}
162
if (! $img) { return; }
163
164
my ($width, $height) = $img->getBounds();
165
if ($width != 80 or $height != 80) { return; }
166
my @sizes;
167
my $size = $params->{'size'};
168
if (! defined $size) {
169
@sizes = (80);
170
} elsif (ref $size eq 'ARRAY') {
171
@sizes = grep { /^\d+$/ } @$size;
172
} elsif (! ref $size) {
173
@sizes = int($size);
174
} else {
175
confess "Error: sizes parameter needs to be a number or an arrayref";
176
}
177
178
my $return = { };
179
foreach my $size (@sizes) {
180
if ($size == 80) {
181
$return->{'80'} = $resp->content();
182
} elsif ($size > 0 and $size < 80) {
183
my $newimage = GD::Image->new($size, $size, 1);
184
$newimage->copyResampled($img, 0, 0, 0, 0, $size, $size, 80, 80);
185
my $data = $newimage->$type();
186
$return->{$size} = $data;
187
} else {
188
confess "Error: problem with size = '$size' (needs to be an integer between 1 and 80 inclusive)";
189
}
190
}
191
if (! keys %$return) { return; }
192
193
return ($return, $type);
194
}
195
196
=head1 AUTHOR
197
198
Alexander Karelas, C<< >>
199
200
=head1 BUGS
201
202
Please report any bugs or feature requests to
203
C, or through the web interface at
204
L.
205
I will be notified, and then you'll automatically be notified of progress on
206
your bug as I make changes.
207
208
=head1 SUPPORT
209
210
You can find documentation for this module with the perldoc command.
211
212
perldoc Net::Pavatar
213
214
You can also look for information at:
215
216
=over 4
217
218
=item * AnnoCPAN: Annotated CPAN documentation
219
220
L
221
222
=item * CPAN Ratings
223
224
L
225
226
=item * RT: CPAN's request tracker
227
228
L
229
230
=item * Search CPAN
231
232
L
233
234
=item * Module's RSS feed
235
236
L
237
238
=back
239
240
=head1 ACKNOWLEDGEMENTS
241
242
=head1 COPYRIGHT & LICENSE
243
244
Copyright 2007 Alexander Karelas, all rights reserved.
245
246
This program is free software; you can redistribute it and/or modify it
247
under the same terms as Perl itself.
248
249
=cut
250
251
1; # End of Net::Pavatar