source: trunk/npemap.org.uk/cgi/submit.fcgi @ 44

Last change on this file since 44 was 44, checked in by Dominic Hargreaves, 15 years ago

Portions of the postcode = 0 work

  • Property svn:executable set to *
File size: 5.2 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6use DBI;
7use CGI::Fast qw/:standard -debug/;
8use Geo::Postcode;
9use Date::Format;
10
11sub print_err;
12sub setup_dbh;
13
14# Set up database handler to try and make sure it's ready for the first
15# request
16# No point in handling errors here since they'll get handled by the request
17# handler
18my $dbh;
19setup_dbh();
20
21
22my @fields = qw(easting northing postcode);
23my $returnBaseURL = 'http://www.npemap.org.uk';
24
25my $cgi;
26# Process incoming requests
27REQUEST: while ($cgi = new CGI::Fast) {
28
29    # If we're given return URL parameters, basic sanity check to stop
30    # funny business
31   
32    my $returnlink = '<a href="/tiles/map.html?' .int($cgi->param('easting')/1000). ",".int($cgi->param('northing')/1000)  . ',1">Go back</a>';   
33
34    if (defined $cgi->param('returnX') and ($cgi->param('returnX') =~ /\d+/) and
35        defined $cgi->param('returnY') and ($cgi->param('returnY') =~ /\d+/) ) {
36        $returnlink = '<a href="' . $returnBaseURL . '/tiles/map.html?' . $cgi->param('returnX') . ',' . $cgi->param('returnY') . ',1">Go back to the map</a>';
37    }
38
39
40    # In case the database went away, make sure we have a connection
41    unless (setup_dbh()) {
42        print_err('Error setting up database connection', $returnlink);
43        next REQUEST;
44    }
45
46    my ($easting, $northing);
47
48    # Input validation
49    foreach my $field (@fields) {
50        unless (defined $cgi->param($field)) {
51            print_err ("Parameter '$field' missing", $returnlink);
52            next REQUEST;
53        }
54    }
55
56    # Is the Easting in a valid range?
57    if (($cgi->param('easting') > 700000) or
58        ($cgi->param('easting') < 0)) {
59        print_err ("Parameter 'easting' must be an integer between 0 and 700,000", $returnlink);
60        next REQUEST;
61    } else {
62        $easting = $cgi->param('easting');
63    }
64
65    # Is the Northing in a valid range?
66    if (($cgi->param('northing') > 1300000) or
67        ($cgi->param('northing') < 0)) {
68        print_err("Parameter 'northing' must be an integer between 0 and 1,300,000", $returnlink);
69        next REQUEST;
70    } else {
71        $northing = $cgi->param('northing');
72    }
73
74    my $sth;
75
76    # Now validate the postcode input format
77    my $raw_postcode = $cgi->param('postcode');
78    my $trimmed_postcode = $raw_postcode; 
79    $trimmed_postcode =~ s/^\s+//;
80    $trimmed_postcode =~ s/\s+$//;
81    my $postcode = Geo::Postcode->new($trimmed_postcode);
82    my ($first, $second, $third, $fourth) = @{$postcode->fragments};
83    my ($outward, $inward);
84
85    if ($postcode->valid) {
86        # We have a complete postcode; input it straight into the database
87        $outward = $first . $second;
88        $inward = $third . $fourth;
89    } elsif($postcode->valid_fragment) {
90        # We have a valid fragment; let's build up what we can
91        # We are guaranteed to have the first two
92        $outward = $first . $second;
93        $inward = '';
94        $inward .= $third if defined $third;
95        $inward .= $fourth if defined $fourth;
96    } else {
97        print_err("The postcode format is not valid", $returnlink);
98        next REQUEST;
99    }
100
101    # Check for a duplicate.
102    # We want to collect duplicates from different IP addresses as a kind of
103    # corroboration factor; this just catches accidental double-submission
104    # really.
105    $sth = $dbh->prepare('SELECT raw_postcode FROM postcodes WHERE raw_postcode = ? AND easting = ? AND northing = ? AND ip = ?');
106    unless ($sth->execute($raw_postcode, $easting, $northing, $ENV{'REMOTE_ADDR'})) {
107        print_err('Database error when checking for duplicate data :(', $returnlink);
108        next REQUEST;
109    }
110
111    if ($sth->rows) {
112        print_err('You, or someone with the same IP address, have already submitted this postcode with these co-ordinates.', $returnlink);
113        next REQUEST;
114    }
115
116    $sth = $dbh->prepare('INSERT INTO postcodes (outward, inward, raw_postcode, easting, northing, ip, created_at, source) VALUES (?, ?, ?, ?, ?, ?, ?, 0)');
117    if ($sth->execute($outward, $inward, $raw_postcode, $easting, $northing, $ENV{'REMOTE_ADDR'}, time2str('%Y-%m-%d %H:%M:%S', time))) {
118        print "Content-type: text/html\n\n";
119        print "<html><head><title>Thank you</title></head>\n";
120        print "<body><p>Thank you for telling us where your post code is!</p>\n";
121        print "<p>$returnlink</p>\n";
122        print "</body></html>";
123        next REQUEST;
124    } else {
125        print STDERR "DB error: " . $dbh->errstr . "\n";
126        print_err("Database error when adding your data :(", $returnlink);
127        next REQUEST;
128    }
129}
130
131# No more requests to serve, so tidy up
132$dbh->disconnect;
133
134# Helper routines
135sub print_err($$) {
136    my $err = shift;
137    my $returnlink = shift;
138    print "Content-type: text/html\n\n";
139    print "<html><head><title>Error submitting</title></head>\n";
140    print "<body><p>The following error occurred whilst submitting data:\n";
141    print CGI::escapeHTML($err);
142    print "</p><p>Your input was:</p>\n<ul>";
143    foreach my $field (@fields) {
144        my $param = $cgi->param($field) || '';
145        print "<li>$field: " . $param . "</li>\n";
146    }
147    print "</ul>\n";
148    print "<p>$returnlink</p>\n";
149    print "</body></html>\n";
150}
151
152sub setup_dbh {
153    # $dbh is global
154    return $dbh = DBI->connect_cached("dbi:Pg:dbname=npemaps;host=127.0.0.1","npemaps","npemaps");
155}
Note: See TracBrowser for help on using the repository browser.