<?php
/*

phpEarthCache -- scrapes/translates Geocaches from Geocaching.com to Google Earth KML format.

Copyright (C) 2005 Andy Fowler

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

(GNU LGPL)

-----------------------------------

This script utilizes a MySQL db for caching individual geocache information, because
lat/lon is not provided in the search results page, forcing a separate request for
each geocache. The database stores lat/lon for each geocache, preventing future lookups.

CREATE TABLE `caches` (
    `url` varchar(255) NOT NULL default '',
    `name` varchar(255) NOT NULL default '',
    `lat` varchar(20) NOT NULL default '',
    `lon` varchar(20) NOT NULL default '',
    PRIMARY KEY  (`url`)
) TYPE=MyISAM;
*/


header('Content-type: application/vnd.google-earth.kml+xml');

echo <<<LMX
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
LMX;
flush();

$db mysql_connect('localhost''username''password') or _die('db error: ');
mysql_select_db ("database");

function 
_die($error) {
    die(
'<Folder>
    <name>'
.$error.'</name>
    </Folder>
    </kml>'
);
}

function 
_get($url) {
    
/*$c = curl_init($url);
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_FAILONERROR, 1);
    curl_setopt($c, CURLOPT_TIMEOUT, 4);
    curl_setopt($c, CURLOPT_USERAGENT, 'phpEarthCache (via Google Earth Network Link)');
    $return = curl_exec($c);
    //print_r(curl_getinfo($c));
    curl_close($c);

    return $return; */
    
return file_get_contents($url);
}

/*function login($username, $password) {
    $gc_post['myUsername'] = $username;
    $gc_post['myPassword'] = $password;
    $gc_post['__VIEWSTATE'] = 'dDw0OTk2MTk7dDxwPGw8TG9naW4uUmVkaXJlY3Q7PjtsPGh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vbG9naW4vZGVmYXVsdC5hc3B4Oz4+O2w8aTwwPjs+O2w8dDw7bDxpPDE+O2k8Mz47aTw2Pjs+O2w8dDxwPHA8bDxUZXh0Oz47bDx5b3UgYXJlIG5vdCBsb2dnZWQgaW4uOz4+Oz47Oz47dDxwPHA8bDxOYXZpZ2F0ZVVybDtUZXh0Oz47bDxodHRwOi8vd3d3Lmdlb2NhY2hpbmcuY29tL2xvZ2luL2RlZmF1bHQuYXNweD9SRVNFVD1ZJnJlZGlyPWh0dHAlM2ElMmYlMmZ3d3cuZ2VvY2FjaGluZy5jb20lMmZsb2dpbiUyZmRlZmF1bHQuYXNweCUzZlJFU0VUJTNkWSUyNnJlZGlyJTNkaHR0cCUyNTNhJTI1MmYlMjUyZnd3dy5nZW9jYWNoaW5nLmNvbSUyNTJmbG9naW4lMjUyZmRlZmF1bHQuYXNweDtcPEZPTlQgY29sb3I9IiNGRkZGMDAiXD5sb2cgaW5cPC9GT05UXD47Pj47Pjs7Pjt0PDtsPGk8MD47PjtsPHQ8cDxwPGw8SW1hZ2VVcmw7PjtsPC9pbWFnZXMvbmF2L2xvZ29fc3ViLmdpZjs+Pjs+Ozs+Oz4+Oz4+Oz4+O2w8Y29va2llOz4+X6T+h5WOQDvMLp2ZN6Wy/KEXh4w=';
    $gc_post['Button1'] = 'login';

    //$c = curl_init('http://www.andyfowler.com/projects/phpearthcache/post.php');
    $c = curl_init('http://www.geocaching.com/login/default.aspx');
    curl_setopt($c, CURLOPT_POST, 1);
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_USERAGENT, 'phpEarthCache (via Google Earth Network Link)');
    curl_setopt($c, CURLOPT_POSTFIELDS, $gc_post);
    curl_setopt($c, CURLOPT_REFERER, 'http://www.geocaching.com/login/default.aspx');
    $login = curl_exec($c);
    print_r(curl_getinfo($c));
    curl_close($c);

    return $login;
}
*/

function get_caches($lat$long$try=0) {
    
$list _get("http://www.geocaching.com/seek/nearest.aspx?origin_lat=$lat&origin_long=$long");

    if(
stristr($list'no results were found for this search')) return array();

    
$rows explode('/images/icons/compass'$list);
    if(
count($rows) < 4) { // error from geocache
        
if($try 1_die("Error loading from geocaching.com");
        
$try++;
        
sleep(4);
        return 
get_caches($lat$long$try);
    }

    foreach(
$rows as $i => $row) {
        if((
$i == 0) || ($i 7)) continue; // hardcoded limit of 5

        // links: pull detail and name
        
preg_match_all('/<a href="\.\.(.*)">(.*)<\/a>/isU'$row$links);
        
$cache[$i]['detail_url'] = $links[1][1];
        
$cache[$i]['name'] = $links[2][1];

            
// details
            // check db cache
            
$db_cache mysql_fetch_array(mysql_query("SELECT * FROM caches WHERE url='".$cache[$i]['detail_url']."'"));
            if(empty(
$db_cache['url'])) { // cache miss
                
$detail _get('http://www.geocaching.com'.$cache[$i]['detail_url']);
                
preg_match('/lat=(.*)&amp;lon=(.*)&a/isU'$detail$latlong);
                
$cache[$i]['lat'] = $latlong[1];
                
$cache[$i]['lon'] = $latlong[2];

                if(empty(
$cache[$i]['lat']) || empty($cache[$i]['lon'])) {
                    unset(
$cache[$i]);
                    continue;
                }

                
// save to cache
                
mysql_query("INSERT INTO caches (url, name, lat, lon) VALUES ('".$cache[$i]['detail_url']."', '".addslashes($cache[$i]['name'])."', '".$cache[$i]['lat']."', '".$cache[$i]['lon']."')");
            } else { 
// cache hit
                
$cache[$i]['lat'] = $db_cache['lat'];
                
$cache[$i]['lon'] = $db_cache['lon'];
            }

    }
    return 
$cache;
}


// determine center lat/long (w/ help from http://www.keyhole.com/kml/kml_tut.html#network_links)
    // split the client's BBOX return by commas and spaces to obtain an array of coordinates
    
$coords explode(','$_GET['BBOX']);
    if(
count($coords) != 4_die('Invalid BBOX');

    
// for clarity, place each coordinate into a clearly marked bottom_left or top_right variable
    
$bl_lon $coords[0];
    
$bl_lat $coords[1];
    
$tr_lon $coords[2];
    
$tr_lat $coords[3];

    
// calculate the approx center of the view -- note that this is innaccurate if the user is not looking straight down
    
$userlon = (($coords[2] - $coords[0])/2) + $coords[0];
    
$userlat = (($coords[3] - $coords[1])/2) + $coords[1];

    if(!
is_numeric($userlon) || !is_numeric($userlat)) _die('Invalid center lat/lon');

$caches get_caches($userlat$userlon);

echo <<<LMX
<Folder>
    <name>Geocaches</name>
    <visibility>1</visibility>
LMX;

foreach(
$caches as $cache) {
    echo 
'
    <Placemark>
    <name>'
.strip_tags($cache['name']).'</name>
    <description>
    <![CDATA[
    <a href="http://www.geocaching.com'
.$cache['detail_url'].'">View @ Geocaching.com</a>
    ]]>
    </description>
    <Point>
        <extrude>0</extrude>
        <tessellate>0</tessellate>
        <altitudeMode>clampToGround</altitudeMode>
        <coordinates>'
.$cache['lon'].','.$cache['lat'].'</coordinates>
    </Point>
    <View>
        <longitude>'
.$cache['lon'].'</longitude>
        <latitude>'
.$cache['lat'].'</latitude>
        <range>0</range>
        <tilt>20</tilt>
        <heading>0</heading>
    </View>
    </Placemark>'
;
}
?>
</Folder>
</kml>