Anonymous avatar Anonymous committed c5144af

Postcode validation tool

Comments (0)

Files changed (1)

+#
+# This program has several available modes.
+#
+# mode=sel
+# Lists available postcodes, the resulting HTML is intended to be
+# inserted into an HTML form.
+# If area is not set, all postcodes for all areas are listed (a very long
+# list).
+#
+# mode=verify
+# Verifies whether a given major or minor are correct.
+# If both are given, the result is the validation of the entire postcode.
+# for example: postcode.cgi?mode=verify&major=BS5&minor=9NW.
+# the output from the script is either a simple true or false text message.
+#
+# major
+# Major specifies the major part of the postcode to verify
+#
+# minor specifies the minor part of the postcode to verify but in
+# sel mode, minor specifies 1 or 0, whether to display a text box to allow
+# the user to specify the minor of their postcode.
+#
+# Written by David Duncan Ross Palmer, Daybo Logic.
+# 20060509
+#
+
+use strict;
+#use warnings;
+
+use CGI qw(:standard);
+
+sub VerifyMajor($);
+sub VerifyMinor($);
+sub TestArrays();
+sub TestMode($);
+sub Error($);
+sub PrintPostCodes($); # Specify a single area or 'all'
+
+my @Areas = (
+  'Glasgow',
+  'Edinburgh',
+  'Inverness',
+  'Worcester',
+  'Wolverhampton',
+  'Wigan',
+  'Guildford',
+  'Watford',
+  'Warrington',
+  'Walsall',
+  'Wakefield',
+  'Tunbridge Wells',
+  'Telford',
+  'Taunton',
+  'Swindon',
+  'Swansea',
+  'Surrey',
+  'Sunderland',
+  'Stoke on Trent',
+  'Slough',
+  'Sheffield',
+  'Salisbury',
+  'St Albans',
+  'Ilford',
+  'Reading',
+  'Oxford',
+  'Peterborough',
+  'Oldham',
+  'Harrogate',
+  'Northampton',
+  'Milton Keynes',
+  'Middlesbrough',
+  'Llandrindod Wells',
+  'Manchester',
+  'Luton',
+  'Liverpool',
+  'Lincoln',
+  'Leicester',
+  'Leeds',
+  'Preston',
+  'Kingston upon Thames',
+  'Ipswich',
+  'Hull',
+  'Huddersfield',
+  'Stevenage',
+  'Uxbridge',
+  'Stockport',
+  'Hereford',
+  'Harrow',
+  'Enfield',
+  'Norfolk',
+  'Durham',
+  'Dudley',
+  'Doncaster',
+  'Derby',
+  'Darlington',
+  'Hempstead',
+  'Croydon',
+  'Coventry',
+  'Colchester',
+  'Shrewsbury',
+  'Chester',
+  'Crewe',
+  'Chelmsford',
+  'Gloucester',
+  'Southend on Sea',
+  'Carlisle',
+  'Canterbury',
+  'Cambridge',
+  'Halifax',
+  'Bromley',
+  'Brighton',
+  'Bradford',
+  'Bournemouth',
+  'Bolton',
+  'Newport',
+  'Blackpool',
+  'Blackburn',
+  'Nottingham',
+  'Cardiff',
+  'Bristol',
+  'Newcastle',
+  'Portsmouth',
+  'Southampton',
+  'Bath',
+  'Plymouth',
+  'Exeter',
+  'Truro',
+  'Birmingham',
+  'London',
+  'London',
+  'London',
+  'London',
+  'London',
+  'London',
+  'London',
+  'London'
+);
+
+my @Codes = (
+  'G',
+  'EH',
+  'IV',
+  'WR',
+  'WV',
+  'WN',
+  'GU',
+  'WD',
+  'WA',
+  'WS',
+  'WF',
+  'TN',
+  'TF',
+  'TA',
+  'SN',
+  'SA',
+  'SM',
+  'SR',
+  'ST',
+  'SL',
+  'S',
+  'SP',
+  'AL',
+  'IG',
+  'RG',
+  'OX',
+  'PE',
+  'OL',
+  'HG',
+  'NN',
+  'MK',
+  'TS',
+  'LD',
+  'M',
+  'LU',
+  'L',
+  'LN',
+  'LE',
+  'LS',
+  'PR',
+  'KT',
+  'IP',
+  'HU',
+  'HD',
+  'SG',
+  'UB',
+  'SK',
+  'HR',
+  'HA',
+  'EN',
+  'NR',
+  'DH',
+  'DY',
+  'DN',
+  'DE',
+  'DL',
+  'HP',
+  'CR',
+  'CV',
+  'CO',
+  'SY',
+  'CH',
+  'CW',
+  'CM',
+  'GL',
+  'SS',
+  'CA',
+  'CT',
+  'CB',
+  'HX',
+  'BR',
+  'BN',
+  'BD',
+  'BH',
+  'BL',
+  'NP',
+  'FY',
+  'BB',
+  'NG',
+  'CF',
+  'BS',
+  'NE',
+  'PO',
+  'SO',
+  'BA',
+  'PL',
+  'EX',
+  'TR',
+  'B',
+  'E', # Filthy London 1-18
+  'WC', # Filthy London 1 or 2
+  'EC', # Filthy London 1-4
+  'N', # Filthy London 1-22
+  'NW', # Filthy London 1-11
+  'SE', # Filthy London 1-28
+  'SW', # Filthy London 1-20
+  'W' # Filthy London 1-14
+);
+
+my @Ranges = (
+  1, 99, #G
+  1, 99, #EH
+  1, 63, #IV
+  1, 99, #WR
+  1, 99, #WV
+  1, 99, #WN
+  1, 99, #GU
+  1, 99, #WD
+  1, 99, #WA
+  1, 99, #WS
+  1, 99, #WF
+  1, 99, #TN
+  1, 99, #TF
+  1, 99, #TA
+  1, 99, #SN
+  1, 99, #SA
+  1, 99, #SM
+  1, 99, #SR
+  1, 99, #ST
+  1, 99, #SL
+  1, 99, #S
+  1, 99, #SP
+  1, 99, #AL
+  1, 99, #IG
+  1, 99, #RG
+  1, 99, #OX
+  1, 99, #PE
+  1, 99, #OL
+  1, 99, #HG
+  1, 99, #NN
+  1, 99, #MK
+  1, 99, #TS
+  1, 99, #LD
+  1, 99, #M
+  1, 99, #LU
+  1, 99, #L
+  1, 99, #LN
+  1, 99, #LE
+  1, 99, #LS
+  1, 99, #PR
+  1, 99, #KT
+  1, 99, #IP
+  1, 99, #HU
+  1, 99, #HD
+  1, 99, #SG
+  1, 99, #UB
+  1, 99, #SK
+  1, 99, #HR
+  1, 99, #HA
+  1, 99, #EN
+  1, 99, #NR
+  1, 99, #DH
+  1, 99, #DY
+  1, 99, #DN
+  1, 99, #DE
+  1, 99, #DL
+  1, 99, #HP
+  0, 99, #CR
+  1, 99, #CV
+  1, 99, #CO
+  1, 99, #SY
+  1, 99, #CH
+  1, 99, #CW
+  1, 99, #CM
+  1, 99, #GL
+  1, 99, #SS
+  1, 99, #CA
+  1, 99, #CT
+  1, 99, #CB
+  1, 99, #HX
+  1, 99, #BR
+  1, 99, #BN
+  1, 99, #BD
+  1, 99, #BH
+  1, 99, #BL
+  1, 99, #NP
+  1, 99, #FY
+  1, 99, #BB
+  1, 99, #NG
+  1, 99, #CF
+  1, 99, #BS
+  1, 99, #NE
+  1, 99, #PO
+  1, 99, #SO
+  1, 99, #BA
+  1, 99, #PL
+  1, 99, #EX
+  1, 99, #TR
+  1, 99, #B
+  1, 18, #E
+  1, 2,  #WC
+  1, 4,  #EC
+  1, 22, #N
+  1, 11, #NW
+  1, 28, #SE
+  1, 20, #SW
+  1, 14  #W
+);
+
+# Boolean
+my $true = 1;
+my $false = 0;
+
+# User parameters
+my $mode = param('mode');
+my $area = param('area');
+my $city = param('city');
+my $major = param('major');
+my $minor = param('minor');
+
+$area = 'all' if ( !$area );
+
+PrintCGIHeader();
+
+if ( !TestArrays() ) {
+  Error "(Internal error) Hard coded array mismatch";
+}
+if ( !TestMode($mode) ) {
+  Error "Invalid mode";
+}
+if ( $city and $city ne '' ) {
+  Error "Please use area, not city.  City is obsolete";
+}
+
+if ( $mode eq 'sel' ) {
+  my @areaList;
+
+  print "<select name=\"postcode_major\">\n";
+  @areaList = split(',', $area);
+  foreach my $currentArea ( @areaList ) {
+    PrintPostCodes($currentArea);
+  }
+  print "</select>\n";
+
+  if ( $minor && ($minor == $true) ) {
+    print qq {
+          <input type="text" name="postcode_minor" id="postcode_minor"
+           size="4" maxlength="3" />
+    };
+  }
+}
+else { # Postcode verification mode
+  my $verified = $false;
+  my $foundComponent = $false;
+
+  if ( $major && ( $major ne '' ) ) {
+    $foundComponent = $true;
+    $verified = VerifyMajor($major);
+    $minor = undef if ( !$verified ); # Prevent further analysis
+  }
+  if ( $minor && ( $minor ne '' ) ) {
+    $foundComponent = $true;
+    $verified = VerifyMinor($minor);
+  }
+
+  if ( !$foundComponent ) {
+    Error "verifying but neither a major nor a minor has been specified";
+  }
+
+  print "1\n" if ( $verified );
+  print "0\n" if ( !$verified );
+}
+
+exit 0;
+
+
+
+sub PrintCGIHeader
+{
+  print "Content-Type: text/html\n\n";
+}
+
+sub PrintPostCodes($)
+{
+  my $c;
+  my $i;
+  my $j;
+  my $areaPrintable;
+  my $foundArea = $false;
+  my $area = $_[0];
+
+  print "\n";
+
+  $c = scalar @Areas;
+
+  for ( $i = 0; $i < $c; $i++ ) { # For all areas
+    $areaPrintable = $true;
+    if ( $area ) { # Area explicitly set?
+      if ( lc($Areas[$i]) eq lc($area) ) {
+        $foundArea = $true;
+      }
+      elsif ( 'all' eq lc($area) ) {
+        $foundArea = $true;
+      }
+      else {
+        $areaPrintable = $false;
+      }
+    }
+    if ( $areaPrintable ) {
+      for ( my $j = $Ranges[$i*2]; $j <= $Ranges[($i*2)+1]; $j++ ) {
+        print "<option VALUE=\"$Codes[$i]$j\">$Codes[$i]$j</option>\n";
+      }
+    }
+  }
+
+  if ( !$foundArea ) {
+    Error "Specified invalid area: \"$area\"";
+  }
+  return;
+}
+
+sub Error($)
+{
+  my $msg = $_[0];
+
+  print "<p>\n";
+  print "  <b>\n";
+  print "    <font color=\"#ff0000\">\n";
+  print "      postcode.cgi fatal error: $msg\n";
+  print "    </font>\n";
+  print "  </b>\n";
+  print "</p><br />\n";
+
+  die;
+}
+
+sub TestArrays()
+{
+  my $authArrayLen = scalar (@Areas);
+  my $nextArrayLen = scalar (@Codes);
+
+  if ( $nextArrayLen != $authArrayLen ) {
+    Error("Array mismatch at \@Codes");
+    return $false;
+  }
+
+  $nextArrayLen = scalar(@Ranges);
+  if ( $nextArrayLen != ( $authArrayLen *2 ) ) {
+    Error("Array mismatch at \@Ranges");
+    return $false;
+  }
+
+  return $true;
+}
+
+sub TestMode($)
+{
+  my $localMode = $_[0];
+  my $modeSet = $false;
+
+  if ( $localMode ) {
+    return $true if ( $localMode eq 'sel' );
+    return $true if ( $localMode eq 'verify' );
+    $modeSet = $true;
+  }
+
+  if ( $modeSet ) {
+    Error("Invalid mode: $localMode");
+  }
+  else {
+    Error("Mode not set");
+  }
+
+  return $false;
+}
+
+sub VerifyMajor($)
+{
+  my $code = $_[0];
+  if ( $code =~ m/^[A-Z]{1,2}\d{1,2}$/ ) {
+    my $mnemonic = $code;
+    my $radius = $code;
+    my $i = 0;
+
+    $mnemonic =~ s/\d//g;
+    $radius =~ s/[A-Z]//g;
+
+    foreach my $currentCode ( @Codes ) {
+      if ( $currentCode eq $mnemonic ) {
+        if ( ( $radius >= $Ranges[$i] ) && ( $radius <= $Ranges[$i+1] ) ) {
+          return $true;
+        } else {
+          last;
+        }
+      }
+      $i += 2;
+    }
+  }
+  return $false;
+}
+
+sub VerifyMinor($)
+{
+  # We lack the information to verify that a minor is a valid code exactly,
+  # we only know what a valid pattern is and we use that to take a best
+  # guess.
+
+  my $code = $_[0];
+
+  return $true if ( $code =~ m/^\d{1}[A-Z]{2}$/ );
+  return $false;
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.