Skip to content

Commit d8875e5

Browse files
author
heathdutton
committed
Functional js
1 parent b30fc1b commit d8875e5

File tree

3 files changed

+313
-35
lines changed

3 files changed

+313
-35
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
zip-codes-database-FREE.csv
22
*.json
3-
*.jsonp
3+
*.jsonp
4+
**
5+
!zipcodes.js

update.php

Lines changed: 181 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,178 @@
11
<?php
22

3+
error_reporting(E_ALL);
4+
ini_set('display_errors', '1');
5+
6+
//die(minPostal('FR 54311 CEDEX', 'FR'));
7+
38
$cwd = dirname(realpath(__FILE__));
4-
$zipfile = $cwd . '/zip-codes-database-FREE.csv';
5-
if (!file_exists($zipfile)) {
6-
echo "Error: Take the latest free zip code database from zip-codes.com and extract the CSV next to this file and try again.\n";
7-
exit(1);
8-
}
9+
$zipfile = $cwd.'/allCountries.zip';
10+
$txtfile = $cwd.'/allCountries.txt';
11+
$statsOnly = false;
12+
$regenKey = false;
13+
$keyArr = $regenKey ? [] : json_decode(file_get_contents($cwd.'/key.json'), true);
914

15+
// Download http://download.geonames.org/export/zip/allCountries.zip
16+
if (!file_exists($txtfile)) {
17+
echo "Downloading zipcodes...";
18+
$ch = curl_init();
19+
curl_setopt($ch, CURLOPT_URL, 'http://download.geonames.org/export/zip/allCountries.zip');
20+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
21+
$data = curl_exec($ch);
22+
curl_close($ch);
23+
$file = fopen($zipfile, "w+");
24+
fputs($file, $data);
25+
fclose($file);
26+
$zip = new ZipArchive;
27+
$res = $zip->open($zipfile);
28+
if ($res === true) {
29+
$zip->extractTo('.');
30+
$zip->close();
31+
unlink($zipfile);
32+
} else {
33+
die('Unable to unzip.');
34+
}
35+
}
1036

11-
echo "Cleaning any previous build...\n";
12-
clean($cwd);
37+
// echo "Cleaning up from previous build...\n";
38+
// clean($cwd);
1339

1440
$row = 0;
15-
$headers = [];
16-
if (($handle = fopen($zipfile, 'r')) !== false) {
17-
while (($data = fgetcsv($handle, 1000, ',')) !== false) {
18-
if ($row == 0) {
19-
$headers = $data;
20-
} else {
21-
$zip = new stdClass();
22-
foreach ($data as $key => $value) {
23-
$keyname = $headers[$key];
24-
$zip->{$keyname} = $value;
41+
$headers = [
42+
'countryCode', // iso country code, 2 characters
43+
'postalCode', // varchar(20)
44+
'placeName', // varchar(180)
45+
'adminName1', // 1. order subdivision (state) varchar(100)
46+
'adminCode1', // 1. order subdivision (state) varchar(20)
47+
'adminName2', // 2. order subdivision (county/province) varchar(100)
48+
'adminCode2', // 2. order subdivision (county/province) varchar(20)
49+
'adminName3', // 3. order subdivision (community) varchar(100)
50+
'adminCode3', // 3. order subdivision (community) varchar(20)
51+
'latitude', // estimated latitude (wgs84)
52+
'longitude', // estimated longitude (wgs84)
53+
'accuracy', // accuracy of lat/lng from 1=estimated to 6=centroid
54+
];
55+
$stats = [];
56+
if (($handle = fopen($txtfile, 'r')) !== false) {
57+
while (($data = fgetcsv($handle, 1000, "\t")) !== false) {
58+
$place = new stdClass();
59+
foreach ($data as $key => $value) {
60+
$keyname = $headers[$key];
61+
$place->{$keyname} = $value;
62+
}
63+
if (!empty($place->countryCode) && !empty($place->postalCode)) {
64+
$countryCode = strtoupper($place->countryCode);
65+
66+
if ($statsOnly) {
67+
$minCode = minPostal($place->postalCode);
68+
// Two countries have too much numerical variance to list all zip-codes independently
69+
// given Github's current repository limits. For these we will only include the min JSON/JSONP.
70+
$length = strlen($place->postalCode);
71+
72+
if (!isset($stats[$countryCode])) {
73+
$stats[$countryCode] = [
74+
'count' => 1,
75+
'lowest' => $minCode,
76+
'highest' => $minCode,
77+
];
78+
} else {
79+
$stats[$countryCode]['count']++;
80+
if ($minCode < $stats[$countryCode]['lowest']) {
81+
$stats[$countryCode]['lowest'] = $minCode;
82+
} elseif ($minCode > $stats[$countryCode]['highest']) {
83+
$stats[$countryCode]['highest'] = $minCode;
84+
}
85+
}
86+
continue;
2587
}
26-
if (!empty($zip->ZipCode)) {
27-
echo "Creating files for " . $zip->ZipCode . "\n";
28-
file_put_contents($cwd . '/' . $zip->ZipCode . '.json', json_encode($zip));
29-
file_put_contents($cwd . '/' . $zip->ZipCode . '.jsonp', 'zipCodeCallback(' . json_encode($zip) . ');');
88+
89+
$minOnly = in_array($countryCode, ['JP', 'PT']);
90+
echo 'Creating entry for '.$place->countryCode.' '.$place->postalCode.($minOnly ? ' (min only)' : '').' in index '.$minCodeRounded."\n";
91+
if (!is_dir($cwd.'/'.$countryCode)) {
92+
mkdir($cwd.'/'.$countryCode);
93+
}
94+
95+
if (!file_exists($cwd.'/'.$countryCode.'/test.jsonp')) {
96+
$test = new stdClass();
97+
$test->success = true;
98+
file_put_contents($cwd.'/'.$countryCode.'/test.jsonp', 'zipCodesTestCallback('.json_encode($test).');');
99+
}
100+
if (!$minOnly) {
101+
file_put_contents(
102+
$cwd.'/'.$countryCode.'/'.$place->postalCode.'.json',
103+
json_encode($place)
104+
);
105+
}
106+
107+
if (!is_dir($cwd.'/'.$countryCode.'/min')) {
108+
mkdir($cwd.'/'.$countryCode.'/min');
30109
}
110+
111+
$minCodeRounded = minPostalRounded($place->postalCode, $place->countryCode, $keyArr);
112+
$codes = [];
113+
if (file_exists($cwd.'/'.$countryCode.'/min/'.$minCodeRounded.'.json')) {
114+
$codes = json_decode(file_get_contents($cwd.'/'.$countryCode.'/min/'.$minCodeRounded.'.json'), true);
115+
}
116+
$codes[$place->postalCode] = $data;
117+
$codesJSON = json_encode($codes);
118+
file_put_contents(
119+
$cwd.'/'.$countryCode.'/min/'.$minCodeRounded.'.json',
120+
$codesJSON
121+
);
122+
file_put_contents(
123+
$cwd.'/'.$countryCode.'/min/'.$minCodeRounded.'.jsonp',
124+
'zipCodesCallback('.$codesJSON.');'
125+
);
31126
}
32127
$row++;
33128
}
34129
fclose($handle);
35130
}
36131

132+
// floor((X - lowest) / ((highest - lowest) / ceil(count / 1000))),
133+
// if (a > 1) { file = floor((X - b) / c); }
134+
135+
if ($regenKey) {
136+
$key = [];
137+
foreach ($stats as $country => $stat) {
138+
$key[$country] = [];
139+
if ($stat['count'] > 100000) {
140+
$chars = 3;
141+
} elseif($stat['count'] > 10000) {
142+
$chars = 2;
143+
} elseif($stat['count'] > 1000) {
144+
$chars = 1;
145+
} else {
146+
$chars = 0;
147+
}
148+
$key[$country] = $chars;
149+
150+
}
151+
file_put_contents(
152+
$cwd.'/key.json',
153+
json_encode($key)
154+
);
155+
file_put_contents(
156+
$cwd.'/key.js',
157+
'var key = '.json_encode($key).';'
158+
);
159+
}
160+
161+
die(var_export($key, true));
162+
37163
/**
38-
* Recursively delete files and folders within a directory based on type.
164+
* Recursively delete files within a directory based on type.
39165
* @param $dir
40-
* @param null $root
41166
* @param array $types
42167
*/
43-
function clean($dir, $root = null, $types = ['json', 'jsonp'])
168+
function clean($dir, $types = ['json', 'jsonp'])
44169
{
45-
if (!$root) {
46-
$root = $dir;
47-
}
48170
if (is_dir($dir)) {
49171
$objects = scandir($dir);
50172
foreach ($objects as $object) {
51173
if ($object != "." && $object != "..") {
52174
if (is_dir($dir."/".$object)) {
53-
clean($dir."/".$object, $root, $types);
175+
clean($dir."/".$object, $types);
54176
} else {
55177
$ext = pathinfo($object, PATHINFO_EXTENSION);
56178
if (in_array($ext, $types)) {
@@ -59,11 +181,36 @@ function clean($dir, $root = null, $types = ['json', 'jsonp'])
59181
}
60182
}
61183
}
62-
if ($dir !== $root) {
63-
try {
64-
rmdir($dir);
65-
} catch (Exception $e) {
66-
}
67-
}
68184
}
185+
}
186+
187+
function minPostal($postalCode)
188+
{
189+
// Only allow uppercase.
190+
$postalCode = strtoupper($postalCode);
191+
// Remove non-alphanumeric characters.
192+
$postalCode = preg_replace("/[^A-Z0-9]/", '', $postalCode);
193+
194+
// Convert from base 36 to an integer.
195+
$postalCode = base_convert($postalCode, 36, 10);
196+
197+
return $postalCode;
198+
}
199+
200+
function minPostalRounded($postalCode, $country, $keyArr = [])
201+
{
202+
$result = 0;
203+
204+
if ($keyArr[$country] > 1) {
205+
206+
// Only allow uppercase.
207+
$postalCode = strtoupper($postalCode);
208+
// Remove non-alphanumeric characters.
209+
$postalCode = preg_replace("/[^A-Z0-9]/", '', $postalCode);
210+
211+
$result = substr($postalCode, 0, $keyArr[$country]);
212+
}
213+
214+
return $result;
215+
69216
}

zipcodes.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* zipcodes.js
3+
*
4+
* Example:
5+
*
6+
* getZipCode('US', '90210', function (zip) {
7+
* console.log(zip);
8+
* });
9+
*
10+
*/
11+
var getZipCode = function (country, zip, callback) {
12+
var key = {
13+
'AD': 0,
14+
'AR': 2,
15+
'AS': 0,
16+
'AT': 2,
17+
'AU': 2,
18+
'AX': 0,
19+
'BD': 1,
20+
'BE': 1,
21+
'BG': 1,
22+
'BM': 0,
23+
'BR': 1,
24+
'BY': 1,
25+
'CA': 1,
26+
'CH': 1,
27+
'CO': 1,
28+
'CR': 0,
29+
'CZ': 2,
30+
'DE': 2,
31+
'DK': 1,
32+
'DO': 0,
33+
'DZ': 2,
34+
'ES': 2,
35+
'FI': 1,
36+
'FO': 0,
37+
'FR': 2,
38+
'GB': 2,
39+
'GF': 0,
40+
'GG': 0,
41+
'GL': 0,
42+
'GP': 0,
43+
'GT': 0,
44+
'GU': 0,
45+
'HR': 1,
46+
'HU': 1,
47+
'IE': 0,
48+
'IM': 0,
49+
'IN': 3,
50+
'IS': 0,
51+
'IT': 2,
52+
'JE': 0,
53+
'JP': 3,
54+
'LI': 0,
55+
'LK': 1,
56+
'LT': 2,
57+
'LU': 1,
58+
'LV': 1,
59+
'MC': 0,
60+
'MD': 1,
61+
'MH': 0,
62+
'MK': 0,
63+
'MP': 0,
64+
'MQ': 0,
65+
'MT': 0,
66+
'MX': 3,
67+
'MY': 1,
68+
'NC': 0,
69+
'NL': 1,
70+
'NO': 1,
71+
'NZ': 1,
72+
'PH': 1,
73+
'PK': 2,
74+
'PL': 2,
75+
'PM': 0,
76+
'PR': 0,
77+
'PT': 3,
78+
'RE': 0,
79+
'RO': 2,
80+
'RU': 2,
81+
'SE': 2,
82+
'SI': 0,
83+
'SJ': 0,
84+
'SK': 1,
85+
'SM': 0,
86+
'TH': 0,
87+
'TR': 2,
88+
'UA': 2,
89+
'US': 2,
90+
'UY': 1,
91+
'VA': 0,
92+
'VI': 0,
93+
'WF': 0,
94+
'YT': 0,
95+
'ZA': 1
96+
},
97+
headers = [
98+
'countryCode',
99+
'postalCode',
100+
'placeName',
101+
'adminName1',
102+
'adminCode1',
103+
'adminName2',
104+
'adminCode2',
105+
'adminName3',
106+
'adminCode3',
107+
'latitude',
108+
'longitude',
109+
'accuracy'
110+
];
111+
if (typeof key[country] !== 'undefined') {
112+
var k = key[country] > 0 ? zip.toUpperCase().replace(/[^0-9A-Z]/g, '').substr(0, key[country]) : 0;
113+
window.zipCodesCallback = function (zipCodes) {
114+
var result = {};
115+
if (typeof zipCodes[zip] !== 'undefined') {
116+
for (var i = 0, len = headers.length; i < len; i++) {
117+
result[headers[i]] = zipCodes[zip][i];
118+
}
119+
callback(result);
120+
}
121+
else {
122+
callback(false);
123+
}
124+
};
125+
var script = document.createElement('script');
126+
script.src = 'https://' + country.toUpperCase() + '.zipcodes.gdn/min/' + k + '.jsonp';
127+
document.body.appendChild(script);
128+
}
129+
};

0 commit comments

Comments
 (0)