#!/usr/bin/perl use strict; use CGI; use DBI; use GD; use Geo::IP; use Geo::Proj4; my ($start_time) = time(); my ($page); my ($dsn) = "DBI:mysql:database=eprintstats;host=localhost"; my ($user_name) = "eprintstatspriv"; my ($password) = "AuldGrizzel"; my ($connect, $query, %types, $stat, $row, $num_rows, $vtype); my ($mapimage, $mapimagefile); my ($red, $white, $black, $blue); my ($width, $height); my ($gi, $proj); my ($gidb) = '/usr/local/share/GeoIP/GeoLiteCity.dat'; my ($x_offset) = 16986796.16; my ($y_offset) = 8615499.05; my ($max_x) = $x_offset * 2; my ($max_y) = $y_offset * 2; my (%cities); my ($num_IPs) = -1; my ($num_hits) = 0; my ($ip, $count, $location); my ($city, $lat, $long, $x, $y); $page = new CGI; print $page->header( -type=>"image/jpeg", -Pragma=>'no-cache' ); $gi = Geo::IP->open( $gidb, GEOIP_STANDARD ) or die "Unable to open GeoIP database $gidb\n"; $proj = Geo::Proj4->new( proj => "robin", ellps => "sphere", lon_0 => 10 ) or die "parameter error: " . Geo::Proj4->error . "\n"; $width = $page->param('width'); $height = $page->param('height'); $mapimagefile = "map_${width}x${height}.png"; $mapimage = GD::Image->newFromPng( $mapimagefile, 1 ); $white = $mapimage->colorAllocate( 255, 255, 255 ); $black = $mapimage->colorAllocate( 0, 0, 0 ); $red = $mapimage->colorAllocate( 255, 0, 0 ); $blue = $mapimage->colorAllocate( 0, 0, 255 ); $connect = DBI->connect( $dsn, $user_name, $password, { RaiseError => 1 } ); $types{'download'} = $types{'abstract'} = 0; $query = "SELECT ip, view_type, COUNT(*) AS count FROM view GROUP BY ip, view_type ORDER BY count DESC" . ( $num_IPs > 0 ? " LIMIT $num_IPs" : '' ); $stat = $connect->prepare( $query ); $stat->execute(); $num_rows = $stat->rows; if ( $num_rows > 0 ) { $num_IPs = $num_rows if ( $num_IPs < 1 ); while ( $row = $stat->fetchrow_hashref() ) { $ip = $row->{'ip'}; $count = $row->{'count'}; $vtype = $row->{'view_type'}; $location = $gi->record_by_addr( $ip ); if ( defined( $location ) ) { $lat = $location->latitude; $long = $location->longitude; $city = $location->city; ($x, $y) = $proj->forward( $lat, $long ); $x = round(($x + $x_offset) / $max_x * $width); $y = round(($y_offset - $y) / $max_y * $height); $city = "Unknown ($lat, $long)" if ( $city eq '' ); if ( !defined( $cities{$city} ) ) { $cities{$city}{'count'} = 0; $cities{$city}{'lat'} = $lat; $cities{$city}{'long'} = $long; $mapimage->filledRectangle( $x - 1, $y - 1, $x + 1, $y + 1, ( $vtype eq 'download' ? $red : $blue ) ); } $cities{$city}{'count'} += $count; $types{$vtype} += $count; $cities{$city}{'x'} = $x; $cities{$city}{'y'} = $y; } } } $stat->finish(); $connect->disconnect(); $mapimage->string( gdSmallFont, 3, 3, "$types{'download'} downloads", $red ); $mapimage->string( gdSmallFont, 3, 15, "$types{'abstract'} abstracts", $blue ); $mapimage->string( gdSmallFont, 3, 27, 'from ' . scalar( keys %cities ) . ' cities', $black ); $mapimage->string( gdSmallFont, 3, 39, "($num_rows IP addresses)", $black ); $mapimage->string( gdSmallFont, 3, $height - 15, 'Generated in ' . ( time() - $start_time ) . ' seconds', $black ); binmode(STDOUT); print $mapimage->jpeg(); sub round { my ($n) = shift; return int( $n + .5 * ($n <=> 0) ); }