Skip to content

Instantly share code, notes, and snippets.

@kijtra
Created May 14, 2015 03:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kijtra/e92b6318d2f9a2a4021f to your computer and use it in GitHub Desktop.
Save kijtra/e92b6318d2f9a2a4021f to your computer and use it in GitHub Desktop.
[PHP] Geo Hash encode and decode function.
<?php
function geohash($lat, $lon = NULL, $len = 12)
{
if ($len < 1 || $len > 12) {
return false;
}
$base32Chars = array(
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
);
$latInterval = array(-90.0, 90.0);
$lonInterval = array(-180.0, 180.0);
$bits = array(16, 8, 4, 2, 1);
$bit = 0;
$isEven = TRUE;
// Encode
if (!empty($lon) && preg_match('/\A[\d\.]+\z/', $lat.$lon)) {
$charIndex = 0;
$geohash = NULL;
while (strlen($geohash) < $len) {
if ($isEven) {
$middle = ($lonInterval[0] + $lonInterval[1]) / 2;
if ($lon > $middle) {
$charIndex |= $bits[$bit];
$lonInterval[0] = $middle;
} else {
$lonInterval[1] = $middle;
}
} else {
$middle = ($latInterval[0] + $latInterval[1]) / 2;
if ($lat > $middle) {
$charIndex |= $bits[$bit];
$latInterval[0] = $middle;
} else {
$latInterval[1] = $middle;
}
}
if ($bit < 4) {
$bit++;
} else {
$geohash .= $base32Chars[$charIndex];
$bit = 0;
$charIndex = 0;
}
$isEven = $isEven ? FALSE : TRUE;
}
return $geohash;
}
// Decode
elseif(empty($lon) && is_string($lat) && ($geohashLength = strlen($lat)) <= 12) {
$geohash = $lat;
$base32DecodeMap = array_flip($base32Chars);
for ($i = 0; $i < $geohashLength; $i++) {
if (!isset($base32DecodeMap[$geohash[$i]])) {
// Invalid GeoHash
return FALSE;
}
$currentChar = $base32DecodeMap[$geohash[$i]];
$bitsTotal = count($bits);
for ($j = 0; $j < $bitsTotal; $j++) {
$mask = $bits[$j];
if ($isEven) {
if (($currentChar & $mask) !== 0) {
$lonInterval[0] = ($lonInterval[0] + $lonInterval[1]) / 2;
} else {
$lonInterval[1] = ($lonInterval[0] + $lonInterval[1]) / 2;
}
} else {
if (($currentChar & $mask) !== 0) {
$latInterval[0] = ($latInterval[0] + $latInterval[1]) / 2;
} else {
$latInterval[1] = ($latInterval[0] + $latInterval[1]) / 2;
}
}
$isEven = $isEven ? FALSE : TRUE;
}
}
return array(
'lat' => ($latInterval[0] + $latInterval[1]) / 2,
'lon' => ($lonInterval[0] + $lonInterval[1]) / 2
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment