This repository has been archived on 2024-01-12. You can view files and clone it, but cannot push or open issues or pull requests.
WolKal3000/wolkal3000-geocode.php

159 lines
5.5 KiB
PHP

<?php
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
function wolkal3000_geocity($location) {
// Wenn die Adresse im Feld Stadt steht, wird sie richtig angezeigt, ergo:
$pattern = '/(.*), ([0-9]{5} [^,]+)/';
preg_match ($pattern, $location, $matches);
if ( empty ($matches[2])) {
return ($location);
} else {
return ($matches[2]);
}
}
function wolkal3000_geoshow($location) {
// later
// not NULL so kal3000_the_termin_geo() displays a map if lat/lon are available.
// Hotel-Gasthof Maisberger, Bahnhofstraße 54, 85375 Neufahrn bei Freising, Deutschland
// alles bis ", [0-9]{5}" ist geoshow
// alles ab [0-9]{5}[\,]+ ist geocity.
$pattern = '/(.*), ([0-9]{5} [^,]+)/';
preg_match ($pattern, $location, $matches);
return ($matches[1]);
}
function wolkal3000_geocode($location) {
// we try to cache results as we will need many times the same results especially for recurring events.
// we will use a hash for the location because the hash has a fixed length, while the location has not.
// This table will grow indefinitely over time, so we need to add a timestamp field and remove
// entries that are older than, say, 30 days each time.
// this will also cope with Google subtly changing location strings in Maps over time.
// new entries will thus replace outdated ones over time.
/*
Caching neu: in wp_options-> wolkal3000_options ein Array geocache anlegen. Darunter für jeden hash ein Array schreiben, also:
Datenmodell:
$geocache = array (
hash1 = array (
'wolkal3000_geo_lat' => '',
'wolkal3000_geo_lon' => '',
'wolkal3000_geo_timestamp' => 0,
),
hash2 = array ...
);
Schreiben:
$options = get_options ( 'wolkal3000_options' );
$geocache = $options ( 'geocache' );
$geocache['hashx'] = array ( $lat, $lon, time(), );
$options ( 'geocache' ) = $geocache;
Löschen:
foreach ( $geocache as $key => $value ) {
if ( $key['wolkal3000_geo_timestamp'] < time() - 2592000 ) {
unset ( $options['geocache']['hashx'] )
}
}
set_options ( 'wolkal3000_options' );
Suchen: if ( isset ( $options['geocache']['hashx'] ) ) ...
*/
if ( '' == $location ) {
return array ('', '');
}
// check the cache first
global $wpdb;
$table = $wpdb->prefix.WOLKAL3000_GEO_TABLE;
$hash = hash ('md5', $location);
$query = "SELECT wolkal3000_geo_lat, wolkal3000_geo_lon FROM $table WHERE wolkal3000_geo_hash = '$hash'";
$result = $wpdb->get_row( $query, ARRAY_N );
if ( $wpdb->num_rows == 1 ) { // it should only be a single row!
wolkal3000_error_log (INFO, "geocode cache hit hash $hash lat $result[0] lon $result[1]");
} else {
// do the housekeeping first, before we create a new caching entry.
// remove all cache entries which are older than 30 days.
$outdated = time() - 2592000; // 30 Tage
$query = "DELETE FROM $table WHERE wolkal3000_geo_timestamp < $outdated";
$wpdb->query($query);
$options = get_option('wolkal3000_options');
$result = array ('', '');
switch ( $options['wolkal3000_geocoding'] ) {
case "osm" :
$result = wolkal3000_geocode_osm($location);
break;
}
$file = dirname (__FILE__) . "/geocode-result-$hash.txt";
file_put_contents ($file, var_export ($result, TRUE));
// do the caching now, but only if both values are set.
// $wpdb_insert does all the sanitizing for us.
$lat = $result[0];
$lon = $result[1];
if ('' != $lat && '' != $lon) {
$wpdb->insert($table, array(
'wolkal3000_geo_location' => substr( $location, 0, 128 ),
'wolkal3000_geo_hash' => $hash,
'wolkal3000_geo_lat' => $lat,
'wolkal3000_geo_lon' => $lon,
'wolkal3000_geo_timestamp' => time(),
));
wolkal3000_error_log (INFO, "geocoded and cached lat=$lat lon=$lon for location $location");
}
// error handling?
}
return ($result);
}
function wolkal3000_geocode_osm($location) {
// https://wiki.openstreetmap.org/wiki/Nominatim
// https://nominatim.openstreetmap.org/search?q=Hotel+Gumberger+Gasthof+GmbH&format=json'
$location = urlencode($location);
wolkal3000_error_log (INFO, "wolkal3000_geocode_osm: location $location");
// the main problem with Nominatim is that it doesn't understand calendar location information very well.
// we ought to cut off the location name and the country, i.e. zip code, city & street address only
$url = 'https://nominatim.openstreetmap.org/search?q="' . $location . '"&format=json';
$response = wp_remote_get($url);
$json = wp_remote_retrieve_body($response);
$http_code = wp_remote_retrieve_response_code($response);
// we need to catch errors
// https://www.php.net/manual/en/function.json-decode.php
$decoded = json_decode($json, true);
// TODO error handling e.g. if we get no usable values.
/*
$file = dirname (__FILE__) . '/json-decoded.txt';
// should simply be ->lat and -> lon
file_put_contents ($file, var_export ($decoded, TRUE));
// The first array level ([0]) is only needed because OSM returns a JSON with enclosing [].
*/
$lat = $decoded['0']['lat'];
$lon = $decoded['0']['lon'];
wolkal3000_error_log (INFO, "wolkal3000_geocode_osm found lat=$lat lon=$lon loc $location");
return array ($lat, $lon);
}