| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package TextLinkAds; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
34697
|
use strict; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
92
|
|
|
4
|
2
|
|
|
2
|
|
14
|
use warnings; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
84
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
24
|
use Carp qw( carp croak ); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
1548
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
TextLinkAds - Retrieve Text Link Ads advertiser data |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use TextLinkAds; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my $tla = TextLinkAds->new; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Fetch link information from text-link-ads.com... |
|
23
|
|
|
|
|
|
|
my @links = @{ $tla->fetch( $inventory_key ) }; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Output the data in some meaningful way... |
|
26
|
|
|
|
|
|
|
print " |
|
27
|
|
|
|
|
|
|
foreach my $link ( @links ) { |
|
28
|
|
|
|
|
|
|
my $before = $link->{BeforeText} || ''; |
|
29
|
|
|
|
|
|
|
my $after = $link->{AfterText} || ''; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
print <<"END_OF_HTML"; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
$before $link->{Text} $after |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
END_OF_HTML |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
print ''; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
This module fetches advertiser information for a given Text Link Ads publisher |
|
43
|
|
|
|
|
|
|
account. |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
See L. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 METHODS |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head2 ->new( \%options ) |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Instantiate a new TextLinkAds object. |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head3 %options |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=over |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=item cache |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
Optional. By default this module will try to use L to store |
|
61
|
|
|
|
|
|
|
data retrieved from the text-link-ads.com site for one hour. You may use the |
|
62
|
|
|
|
|
|
|
C parameter to provide an alternative object that implements the |
|
63
|
|
|
|
|
|
|
L interface. To disable caching set C to a scalar value |
|
64
|
|
|
|
|
|
|
that resolves to C. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=item tmpdir |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Optional. A temporary directory to use when caching data. The default |
|
69
|
|
|
|
|
|
|
behaviour is to use the directory determined by |
|
70
|
|
|
|
|
|
|
Ltmpdir|File::Spec/tmpdir>. |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=back |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=cut |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub new { |
|
78
|
1
|
|
|
1
|
1
|
613
|
my ( $class, $args ) = @_; |
|
79
|
|
|
|
|
|
|
|
|
80
|
1
|
|
|
|
|
4
|
my $self = bless {}, $class; |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Where the tmpdir isn't defined or valid, use File::Spec to determine an |
|
83
|
|
|
|
|
|
|
# appropriate directory... |
|
84
|
1
|
|
|
|
|
4
|
my $tmpdir = $args->{tmpdir}; |
|
85
|
1
|
0
|
33
|
|
|
6
|
unless ( defined $tmpdir && -d $tmpdir && -w $tmpdir ) { |
|
|
|
|
33
|
|
|
|
|
|
86
|
1
|
|
|
|
|
8
|
require File::Spec; |
|
87
|
1
|
|
|
|
|
121
|
$tmpdir = File::Spec->tmpdir; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
1
|
|
|
|
|
8
|
$self->{tmpdir} = $tmpdir; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Where cache is not defined, or is a scalar with a true value, fall back |
|
93
|
|
|
|
|
|
|
# to using Cache::FileCache (providing it is installed)... |
|
94
|
1
|
|
|
|
|
3
|
my $cache = $args->{cache}; |
|
95
|
1
|
50
|
0
|
|
|
5
|
if ( !defined $cache || ( !ref $cache && $cache ) ) { |
|
|
|
|
33
|
|
|
|
|
|
96
|
1
|
|
|
|
|
3
|
eval { require Cache::FileCache; }; |
|
|
1
|
|
|
|
|
1077
|
|
|
97
|
1
|
50
|
|
|
|
95419
|
unless ( $@ ) { |
|
98
|
1
|
|
|
|
|
14
|
$cache = Cache::FileCache->new({ |
|
99
|
|
|
|
|
|
|
cache_root => $tmpdir, |
|
100
|
|
|
|
|
|
|
default_expires_in => '1 hour', |
|
101
|
|
|
|
|
|
|
}); |
|
102
|
|
|
|
|
|
|
|
|
103
|
1
|
|
|
|
|
350
|
$self->{cache} = $cache; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
|
108
|
1
|
|
|
|
|
8
|
return $self; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=head2 ->fetch( $inventory_key, \%options ) |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Fetch advertiser information for the given key. It will first attempt to get |
|
115
|
|
|
|
|
|
|
the data from the cache where available, and failing that will send a request |
|
116
|
|
|
|
|
|
|
to text-link-ads.com, using the *_proxy environment variables and the |
|
117
|
|
|
|
|
|
|
If-Modified_Since request header. |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head3 $inventory_key |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
Required. The XML Key for the desired site as provided by Text Link Ads. |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head3 %options |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=over |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item user_agent |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Optional. In the vanilla code examples provided by Text Link Ads, both the |
|
131
|
|
|
|
|
|
|
user agent and referer CGI environment variables are included in the URI used |
|
132
|
|
|
|
|
|
|
to retrieve the XML data. While the link appears to function without them, it |
|
133
|
|
|
|
|
|
|
would probably be polite to include them where possible. |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item referer |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
See above. |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=back |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=cut |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub fetch { |
|
146
|
0
|
|
|
0
|
1
|
|
my ( $self, $inventory_key, $args ) = @_; |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# First, attempt to retrieve the data from the cache where available... |
|
149
|
0
|
|
|
|
|
|
my $links; |
|
150
|
0
|
0
|
|
|
|
|
if ( defined $self->{cache} ) { |
|
151
|
0
|
|
|
|
|
|
$links = $self->{cache}->get( "tla_$inventory_key" ); |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
|
return $links if defined $links; |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Otherwise, we'll need to retrieve the data from text-link-ads.com, so |
|
157
|
|
|
|
|
|
|
# create a new user agent object... |
|
158
|
0
|
|
|
|
|
|
require LWP::UserAgent; |
|
159
|
0
|
|
|
|
|
|
my $ua = LWP::UserAgent->new( |
|
160
|
|
|
|
|
|
|
agent => "TextLinkAds.pm/$VERSION " . LWP::UserAgent->_agent, |
|
161
|
|
|
|
|
|
|
); |
|
162
|
0
|
|
|
|
|
|
$ua->env_proxy; # obey the *_proxy environment variables |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# Determine the URI to use when requesting the advertiser data... |
|
166
|
0
|
|
|
|
|
|
my $referer = $self->{referer}; |
|
167
|
0
|
|
|
|
|
|
my $user_agent = $self->{user_agent}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
0
|
|
|
|
|
my $uri = 'http://www.text-link-ads.com/xml.php' |
|
|
|
0
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
. "?inventory_key=$inventory_key" |
|
171
|
|
|
|
|
|
|
. ( defined $referer ? "&referer=$referer" : '' ) |
|
172
|
|
|
|
|
|
|
. ( defined $user_agent ? "&user_agent=$user_agent" : '' ); |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Request the advertiser data, using "If-Modified-Since" where possible... |
|
176
|
0
|
|
|
|
|
|
my $temp_file = $self->{tmpdir} . "/tla_$inventory_key"; |
|
177
|
0
|
|
|
|
|
|
my $response = $ua->mirror( $uri, $temp_file ); |
|
178
|
|
|
|
|
|
|
|
|
179
|
0
|
0
|
|
|
|
|
if ( !$response->is_success ) { |
|
180
|
0
|
|
|
|
|
|
croak $response->status_line; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# The resulting file was empty. This may mean there were no advertisers, |
|
184
|
|
|
|
|
|
|
# though it's also possible that an incorrect $inventory_key was given... |
|
185
|
0
|
0
|
|
|
|
|
if ( -z $temp_file ) { |
|
186
|
0
|
|
|
|
|
|
carp "No advertisers found for '$inventory_key'"; |
|
187
|
0
|
|
|
|
|
|
return []; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Parse the XML... |
|
191
|
0
|
|
|
|
|
|
require XML::Simple; |
|
192
|
0
|
|
|
|
|
|
$links = XML::Simple::XMLin($temp_file)->{Link}; |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# Remove empty BeforeText/AfterText attributes... |
|
196
|
0
|
|
|
|
|
|
foreach my $link ( @$links ) { |
|
197
|
0
|
0
|
|
|
|
|
delete $link->{BeforeText} if ref $link->{BeforeText}; |
|
198
|
0
|
0
|
|
|
|
|
delete $link->{AfterText} if ref $link->{AfterText}; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Store the new data if caching is enabled... |
|
203
|
0
|
0
|
|
|
|
|
$self->{cache}->set( "tla_$inventory_key", $links ) |
|
204
|
|
|
|
|
|
|
if defined $self->{cache}; |
|
205
|
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
return $links; |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
1; # End of the module code; everything from here is documentation... |
|
212
|
|
|
|
|
|
|
__END__ |