File Coverage

blib/lib/HTTP/DetectUserAgent.pm
Criterion Covered Total %
statement 11 280 3.9
branch 0 180 0.0
condition 0 61 0.0
subroutine 4 21 19.0
pod 1 2 50.0
total 16 544 2.9


line stmt bran cond sub pod time code
1             package HTTP::DetectUserAgent;
2              
3 7     7   3850426 use warnings;
  7         18  
  7         194  
4 7     7   35 use strict;
  7         11  
  7         141  
5 7     7   160 use 5.006;
  7         23  
6             #use Carp;
7             our $VERSION = '0.05';
8 7     7   37 use base qw(Class::Accessor);
  7         14  
  7         915  
9              
10             __PACKAGE__->mk_accessors(qw(name version vendor type os));
11              
12             sub new {
13 0     0 1   my ( $class, $user_agent ) = @_;
14 0           my $self = {};
15 0           bless $self, $class;
16 0 0         unless( defined $user_agent ){
17 0           $user_agent = $ENV{'HTTP_USER_AGENT'};
18             }
19 0           $self->user_agent($user_agent);
20 0           return $self;
21             }
22              
23             sub user_agent {
24 0     0 0   my ( $self, $user_agent ) = @_;
25 0 0         if( defined $user_agent ){
26 0           $self->{user_agent} = $user_agent;
27 0           $self->_parse();
28             }
29 0           return $self->{user_agent};
30             }
31              
32             sub _parse {
33 0     0     my $self = shift;
34 0           my $ua = lc $self->{user_agent};
35 0           $self->_parse_name($ua);
36 0 0         if( $self->{type} eq 'Browser' ){
37 0           $self->_parse_os($ua);
38             }
39             }
40              
41             sub _parse_name {
42 0     0     my ( $self, $ua ) = @_;
43 0 0         return if( $self->_check_crawler($ua) );
44 0 0         if( index($ua,'opera') != -1){
45 0           $self->_check_opera($ua);
46 0           return;
47             }
48 0           my $block = $self->_parse_block($ua);
49 0 0 0       if( $block->{applewebkit} ){
    0          
    0          
50 0           $self->_check_webkit( $ua, $block );
51             }elsif( $block->{'_comment'}
52             && index($block->{'_comment'}, 'msie' ) != -1 ){
53 0           $self->_check_ie($ua, $block);
54             }elsif( $block->{gecko} ){
55 0           $self->_check_gecko( $ua, $block );
56             }else{
57 0 0 0       $self->_check_mobile( $ua, $block ) ||
      0        
      0        
      0        
58             $self->_check_mobile_pc_viewer( $ua, $block ) ||
59             $self->_check_other_browsers( $ua, $block ) ||
60             $self->_check_webservice($ua, $block ) ||
61             $self->_check_robot( $ua, $block ) ||
62             $self->_check_portable($ua, $block );
63             }
64 0 0         if( !$self->{name} ){
65 0           $self->{name} = 'Unknown';
66 0           $self->{type} = 'Unknown';
67             }
68             }
69              
70             sub _parse_block {
71 0     0     my ( $self, $ua ) = @_;
72              
73 0 0         return {} unless $ua;
74 0           my $reg = qr{(\([^()]+\))|(\S+?)/(\S+)|(\S+)};
75 0           my %block = ();
76 0           while( $ua =~ /$reg/g ){
77 0 0         if( $1 ){
    0          
    0          
78 0   0       $block{_comment} = ($block{_comment}||'').$1;
79             }elsif( $2 ){
80 0           $block{$2} = $3;
81             }elsif( $4 ){
82 0   0       $block{_illigal} = ($block{_illigal}||'').':'.$4;
83             }
84             }
85 0           return \%block;
86             }
87              
88             sub _check_crawler {
89 0     0     my ( $self, $ua ) = @_;
90 0 0 0       if( index($ua,'googlebot') != -1){
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
91             # http://www.google.com/bot.html
92 0 0         if( index($ua,'mobile') != -1 ){
93 0           $self->{name} = 'Googlebot Mobile';
94             }else{
95 0           $self->{name} = 'Googlebot';
96             }
97 0           $self->{vendor} = 'Google';
98             }elsif( index($ua,'mediapartners-google') != -1){
99 0           $self->{name} = 'Googlebot Mediapartners';
100 0           $self->{vendor} = 'Google';
101             }elsif( index($ua,'feedfetcher-google') != -1){
102 0           $self->{name} = 'Googlebot Feedfetcher';
103 0           $self->{vendor} = 'Google';
104             }elsif( index($ua, 'yahoo') != -1){
105 0 0 0       if( index($ua, 'slurp') != -1){
    0          
    0          
    0          
    0          
106             # http://help.yahoo.com/help/us/ysearch/slurp
107 0           $self->{name} = 'Yahoo! Slurp';
108 0           $self->{vendor} = 'Yahoo';
109             }elsif( index($ua, 'y!j-srd') != -1 || index($ua, 'y!j-mbs') != -1 ){
110             # http://help.yahoo.co.jp/help/jp/search/indexing/indexing-27.html
111 0           $self->{name} = 'Yahoo! Japan Mobile Crawler';
112 0           $self->{vendor} = 'Yahoo';
113             }elsif( index($ua, 'y!j-bsc') != -1){
114             # http://help.yahoo.co.jp/help/jp/blog-search/
115 0           $self->{name} = 'Yahoo! Japan Blog Crawler';
116 0           $self->{vendor} = 'Yahoo';
117             }elsif( index($ua, 'y!j-') != -1){
118             # http://help.yahoo.co.jp/help/jp/search/indexing/indexing-15.html
119 0           $self->{name} = 'Yahoo! Japan Crawler';
120 0           $self->{vendor} = 'Yahoo';
121             }elsif( index($ua, 'yahoofeedseeker') != -1){
122 0           $self->{name} = 'YahooFeedSeeker';
123 0           $self->{vendor} = 'Yahoo';
124             }
125             }elsif( index($ua, 'msnbot') != -1){
126             # http://search.msn.com/msnbot.htm
127 0           $self->{name} = 'msnbot';
128 0           $self->{vendor} = 'Microsoft';
129             }elsif( index($ua, 'twiceler') != -1){
130             # http://www.cuil.com/twiceler/robot.html
131 0           $self->{name} = 'Twiceler';
132 0           $self->{vendor} = 'Cuil';
133             }elsif( index($ua, 'baiduspider') != -1){
134             # http://help.baidu.jp/system/05.html
135 0           $self->{name} = 'Baiduspider';
136 0           $self->{vendor} = 'Baidu';
137             }elsif( index($ua, 'baidumobaider') != -1){
138             # http://help.baidu.jp/system/05.html
139 0           $self->{name} = 'BaiduMobaider';
140 0           $self->{vendor} = 'Baidu';
141             }elsif( index($ua, 'yeti') != -1 && index($ua, 'naver') != -1){
142             # http://help.naver.com/robots/
143 0           $self->{name} = 'Yeti';
144 0           $self->{vendor} = 'Naver';
145             }elsif( index($ua, 'ichiro') != -1){
146             # http://help.goo.ne.jp/door/crawler.html)
147 0           $self->{name} = 'ichiro';
148 0           $self->{vendor} = 'goo';
149             }elsif( index($ua, 'moba-crawler') != -1){
150             # http://crawler.dena.jp/
151 0           $self->{name} = 'moba-crawler';
152 0           $self->{vendor} = 'DeNA';
153             }elsif( index($ua, 'masagool') != -1){
154             # http://sagool.jp/
155 0           $self->{name} = 'MaSagool';
156 0           $self->{vendor} = 'Sagool';
157             }elsif( index($ua, 'ia_archiver') != -1){
158             # http://www.archive.org/
159 0           $self->{name} = 'Internet Archive';
160 0           $self->{vendor} = 'Internet Archive';
161             }elsif( index($ua, 'tagoobot') != -1){
162             # http://www.tagoo.ru
163 0           $self->{name} = 'Tagoobot';
164 0           $self->{vendor} = 'Tagoo';
165             }elsif( index($ua, 'sogou web spider') != -1){
166             #http://www.sogou.com/docs/help/webmasters.htm#07
167 0           $self->{name} = 'Sogou';
168 0           $self->{vendor} = 'Sogou';
169             }elsif( index($ua, 'daumoa') != -1){
170             #http://ws.daum.net/aboutWebSearch.html
171 0           $self->{name} = 'Daumoa';
172 0           $self->{vendor} = 'Daum';
173             }elsif( index($ua, 'spider') != -1 || index($ua, 'crawler') != -1 ){
174 0           $self->{name} = 'Unknown Crawler';
175             }
176 0 0         if( $self->{name} ){
177 0           $self->{type} = 'Crawler';
178 0           return 1;
179             }
180 0           return 0;
181             }
182              
183             sub _check_robot {
184 0     0     my ( $self, $ua, $block ) = @_;
185 0 0         if( $block->{'libwww-perl'} ){
    0          
    0          
    0          
    0          
    0          
    0          
    0          
186 0           $self->{name} = 'LWP';
187 0           $self->{version} = $block->{'libwww-perl'};
188             }elsif( $block->{'web::scraper'} ){
189 0           $self->{name} = 'Web::Scraper';
190 0           $self->{version} = $block->{'web::scraper'};
191             }elsif( $block->{php} ){
192 0           $self->{name} = 'PHP';
193 0           $self->{version} = $block->{php};
194             }elsif( $block->{java} ){
195 0           $self->{name} = 'Java';
196 0           $self->{version} = $block->{java};
197             }elsif( $block->{wget} ){
198 0           $self->{name} = 'Wget';
199 0           $self->{version} = $block->{wget};
200             }elsif( $block->{curl} ){
201 0           $self->{name} = 'Curl';
202 0           $self->{version} = $block->{curl};
203             }elsif( index( $ua, 'h2tconv' ) != -1 ){
204 0           $self->{name} = 'H2Tconv';
205 0           $self->{version} = 'Unknown';
206             }elsif( $block->{plagger} ){
207 0           $self->{name} = 'Plagger';
208 0           $self->{version} = $block->{plagger};
209             }
210 0 0         if( $self->{name} ){
211 0           $self->{type} = 'Robot';
212 0           return 1;
213             }
214 0           return 0;
215             }
216              
217             sub _check_webservice {
218 0     0     my ( $self, $ua, $block ) = @_;
219 0 0         if( index( $ua, 'hatena bookmark') != -1 ){
    0          
    0          
    0          
220 0           $self->{name} = 'Hatena Bookmark';
221 0           $self->{version} = $block->{bookmark};
222 0           $self->{vendor} = 'Hatena';
223             }elsif( index( $ua, 'hatena antenna') != -1 ){
224 0           $self->{name} = 'Hatena Antenna';
225 0           $self->{version} = $block->{antenna};
226 0           $self->{vendor} = 'Hatena';
227             }elsif( $ua =~ /yahoo pipes ([\d.]+)/ ){
228 0           $self->{name} = 'Yahoo Pipes';
229 0           $self->{version} = $1;
230 0           $self->{vendor} = 'Yahoo';
231             }elsif( $block->{pathtraq} ){
232 0           $self->{name} = 'Pathtraq';
233 0           $self->{version} = $block->{pathtraq};
234 0           $self->{vendor} = 'Cybozu Labs';
235             }
236 0 0         if( $self->{name} ){
237 0           $self->{type} = 'Robot';
238 0           return 1;
239             }
240 0           return 0;
241             }
242              
243             sub _check_opera {
244 0     0     my ( $self, $ua ) = @_;
245 0           $self->{engine} = 'Opera';
246 0           $self->{type} = 'Browser';
247 0           $self->{name} = 'Opera';
248 0           $self->{vendor} = 'Opera';
249 0 0         if( $ua =~ m{opera(?:/|\s+)([\d.]+)} ){
250 0           $self->{version} = $1;
251             }else{
252 0           $self->{version} = 'Unknown';
253             }
254 0           return 1;
255             }
256              
257             sub _check_webkit {
258 0     0     my ( $self, $ua, $block ) = @_;
259 0           $self->{engine} = 'WebKit';
260 0           $self->{type} = 'Browser';
261 0 0         if( $block->{chrome} ){
    0          
    0          
    0          
262 0           $self->{name} = 'Chrome';
263 0           $self->{version} = $block->{chrome};
264 0           $self->{vendor} = 'Google';
265             }elsif( $block->{omniweb} ){
266 0           $self->{name} = 'OmniWeb';
267 0           $self->{version} = $block->{omniweb};
268 0           $self->{vendor} = 'The Omni Group';
269             }elsif( $block->{shiira} ){
270 0           $self->{name} = 'Shiira';
271 0           $self->{version} = $block->{shiira};
272 0           $self->{vendor} = 'Shiira Project';
273             }elsif( $block->{safari} ){
274 0           $self->{name} = 'Safari';
275 0   0       $self->{version} = $block->{version} || $block->{shiira};
276 0           $self->{vendor} = 'Apple';
277             }else{
278 0           $self->{name} = 'WebKit';
279 0           $self->{version} = $block->{webkit};
280             }
281             }
282              
283             sub _check_ie {
284 0     0     my ( $self, $ua, $block ) = @_;
285 0           $self->{engine} = 'Internet Explorer';
286 0           $self->{type} = 'Browser';
287 0 0         if( $block->{sleipnir} ){
    0          
    0          
    0          
288 0           $self->{name} = 'Sleipnir';
289 0           $self->{version} = $block->{sleipnir};
290 0           $self->{vendor} = 'Fenrir';
291             }elsif( $block->{_comment} =~ /lunascape\s+([\d.]+)/){
292 0           $self->{name} = 'Lunascape';
293 0           $self->{version} = $1;
294 0           $self->{vendor} = 'Lunascape';
295             }elsif( $block->{_comment} =~ m{kiki/([\d.]+)}){
296 0           $self->{name} = 'KIKI';
297 0           $self->{version} = $1;
298 0           $self->{vendor} = 'http://www.din.or.jp/~blmzf/index.html';
299             }elsif( $block->{_comment} =~ /msie\s+([\d.]+)/){
300 0           $self->{name} = 'Internet Explorer';
301 0           $self->{version} = $1;
302 0           $self->{vendor} = 'Microsoft';
303             }
304             }
305              
306             sub _check_gecko {
307 0     0     my ( $self, $ua, $block ) = @_;
308 0           $self->{engine} = 'Gecko';
309 0           $self->{type} = 'Browser';
310 0 0 0       if( $block->{flock} ){
    0 0        
    0          
    0          
    0          
    0          
311 0           $self->{name} = 'Flock';
312 0           $self->{version} = $block->{flock};
313 0           $self->{vendor} = 'Flock';
314             }elsif( $block->{firefox} ||
315             $block->{granparadiso} ||
316             $block->{bonecho} ){
317 0           $self->{name} = 'Firefox';
318             $self->{version} = $block->{firefox} ||
319             $block->{granparadiso} ||
320 0   0       $block->{bonecho};
321 0 0         if( $self->{version} =~ /(^[^;,]+)/ ){
322 0           $self->{version} = $1;
323             }
324 0           $self->{vendor} = 'Mozilla';
325             }elsif( $block->{netscape} ){
326 0           $self->{name} = 'Netscape';
327 0           $self->{version} = $block->{netscape};
328 0           $self->{vendor} = 'Mozilla';
329             }elsif( $block->{iceweasel} ){
330 0           $self->{name} = 'Iceweasel';
331 0           $self->{version} = $block->{iceweasel};
332 0           $self->{vendor} = 'Debian Project';
333             }elsif( $block->{seamonkey} ){
334 0           $self->{name} = 'SeaMonkey';
335 0           $self->{version} = $block->{seamonkey};
336 0           $self->{vendor} = 'SeaMonkey Council';
337             }elsif( $block->{camino} ){
338 0           $self->{name} = 'Camino';
339 0           $self->{version} = $block->{camino};
340 0           $self->{vendor} = 'The Camino Project';
341             }else{
342 0           $self->{name} = 'Gecko';
343 0           $self->{version} = $block->{gecko};
344 0           $self->{vendor} = 'Unknown';
345             }
346             }
347              
348             sub _check_mobile {
349 0     0     my ( $self, $ua, $block ) = @_;
350 0   0       $ua = $self->{user_agent} || $ua;
351 0 0 0       if( $block->{docomo} ){
    0 0        
    0          
352 0           $self->{name} = 'docomo';
353 0 0         if( $ua =~ m{DoCoMo/\d\.\d[/\s]+([A-Za-z0-9]+)} ){
354 0           $self->{version} = $1;
355             }else{
356 0           $self->{version} = "Unknown";
357             }
358 0           $self->{vendor} = 'docomo';
359             }elsif( $block->{'up.browser'} && $ua =~ /^KDDI-(\S+)/ ){
360 0           $self->{name} = 'au';
361 0           $self->{version} = $1;
362 0           $self->{vendor} = 'KDDI';
363             }elsif( my $softbank =
364             $block->{softbank} ||
365             $block->{vodafone} ||
366             $block->{'j-phone'} ){
367 0 0         if( $ua =~ m{(?:SoftBank|Vodafone|J-PHONE)/[\d.]+/([A-Za-z0-9]+)} ){
368 0           $self->{name} = 'SoftBank';
369 0           $self->{version} = $1;
370 0           $self->{vendor} = 'SoftBank';
371             }
372             }
373 0 0         if( $self->{name} ){
374 0           $self->{type} = 'Mobile';
375 0           return 1;
376             }
377 0           return 0;
378             }
379              
380             sub _check_mobile_pc_viewer {
381 0     0     my ( $self, $ua, $block ) = @_;
382 0   0       $ua = $self->{user_agent} || $ua;
383 0 0 0       if( $ua =~ /jig browser(?: web)?(?:\D+([\d.]+))*/ ){
    0          
    0          
384 0           $self->{name} = 'Jig Browser';
385 0   0       $self->{version} = $1 || 'Unknown';
386 0           $self->{vendor} = 'jig';
387             }elsif( $ua =~ /ibisBrowser/ ){
388 0           $self->{name} = 'ibisBrowser';
389 0           $self->{version} = 'Unknown';
390 0           $self->{vendor} = 'ibis';
391             }elsif( $block->{mozilla} && $ua =~ /([A-Za-z0-9]+);\s*FOMA/ ){
392 0           $self->{name} = 'FOMA Full Browser';
393 0           $self->{version} = $1;
394 0           $self->{vendor} = 'DoCoMo';
395             }
396 0 0         if( $self->{name} ){
397 0           $self->{type} = 'Browser';
398 0           return 1;
399             }
400 0           return 0;
401             }
402              
403             sub _check_other_browsers {
404 0     0     my ( $self, $ua, $block ) = @_;
405 0 0         if( $block->{lynx} ){
    0          
    0          
406 0           $self->{name} = 'Lynx';
407 0           $self->{version} = $block->{lynx};
408 0           $self->{vendor} = 'The University of Kansas';
409             }elsif( $block->{w3m} ){
410 0           $self->{name} = 'w3m';
411 0           $self->{version} = $block->{w3m};
412 0           $self->{vendor} = 'Akinori Ito';
413             }elsif( $ua =~ m{konqueror/([\d.]+)} ){
414 0           $self->{name} = 'Konqueror';
415 0           $self->{version} = $1;
416 0           $self->{vendor} = 'KDE Team';
417             }
418 0 0         if( $self->{name} ){
419 0           $self->{type} = 'Browser';
420 0           return 1;
421             }
422 0           return 0;
423             }
424              
425             sub _check_portable {
426 0     0     my ( $self, $ua, $block ) = @_;
427 0 0         if( $ua =~ /playstation portable(?:\D+([\d.]+))*/ ){
    0          
428 0           $self->{name} = 'PSP';
429 0   0       $self->{version} = $1 || 'Unknown';
430 0           $self->{vendor} = 'Sony';
431             }elsif( $ua =~ /playstation 3(?:\D+([\d.]+))*/ ){
432 0           $self->{name} = 'Playstation 3';
433 0   0       $self->{version} = $1 || 'Unknown';
434 0           $self->{vendor} = 'Sony';
435             }
436 0 0         if( $self->{name} ){
437 0           $self->{type} = 'Browser';
438 0           return 1;
439             }
440             }
441              
442             sub _parse_os {
443 0     0     my ( $self, $ua ) = @_;
444 0 0         return unless $ua;
445 0 0         if( $ua =~ /iphone/ ){
    0          
    0          
    0          
446 0           $self->{os} = 'iPhone OS';
447             }elsif( $ua =~ /win(?:9[58]|dows|nt)/ ){
448 0           $self->{os} = 'Windows';
449             }elsif( $ua =~ /mac(?:intosh|_(?:powerpc|68000))/ ){
450 0           $self->{os} = 'Macintosh';
451             }elsif( $ua =~ /x11/ ){
452 0           $self->{os} = 'X11';
453             }
454             }
455              
456             1;
457              
458             __END__