Skip to content

Instantly share code, notes, and snippets.

@gausie
Created January 11, 2012 20:31
Show Gist options
  • Save gausie/1596609 to your computer and use it in GitHub Desktop.
Save gausie/1596609 to your computer and use it in GitHub Desktop.
GeoCaching Class
<?php
/*
Written during a Maths lecture by Samuel Gaus
*/
class GeoCaching {
private $hash;
private $cookie_file;
private $username;
private $password;
private $credentials = false;
public function __construct(){
@session_start();
$_SESSION['gc_hash'] = $this->hash = (isset($_SESSION['gc_hash']))?$_SESSION['gc_hash']:md5(time());
$this->cookie_file = "./cookies/{$this->hash}.txt";
}
private function postGet($url,$postData=null,$referer=null){
if(!isset($referer)){
$referer = $url;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_URL, $url);
if(isset($postData) && !empty($postData)){
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
}
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie_file);
curl_setopt($ch, CURLOPT_REFERER, $referer);
return curl_exec($ch);
}
public function login($user,$pass){
$this->credentials = true;
$this->username = $user;
$this->password = $pass;
}
public function loginWAP($user=null,$pass=null){
// Fix the mistake I keep making.
if(isset($user) && isset($pass)){
$this->login($user,$pass);
}elseif(!$this->credentials){
throw new Exception("You must supply GC login credentials to use this command.");
}
//todo Maybe save the login status to the cookie file.
if(isset($_SESSION['gc_loggedin_wap'])){
return true;
}
$url = "http://wap.geocaching.com/login.aspx";
$data = $this->postGet($url);
extract($this->getUFPSandViewstate($data));
//Log in!
$postData = array(
"__VIEWSTATE" => $vs,
"__EVENTTARGET" => "",
"__EVENTARGUMENT" => "",
"txtUsername" => $this->username,
"txtPassword" => $this->password,
"cmdLogin" => "Submit"
);
$data = $this->postGet("{$url}?__ufps={$ufps}",$postData,$url);
// Check success
if(preg_match("/<title>Error Page<\/title>/i", $data)){
//throw new Exception('Incorrect username and/or password.');
}else{
$_SESSION['gc_loggedin_wap'] = true;
return true;
}
}
private function getUFPSandViewstate($data){
if(!preg_match('/<form .*? action=".*?\.aspx\?__ufps=([0-9]*)">/i', $data, $regs1)){
throw new Exception ("UFPS string not found in regex.");
}
if(!preg_match('/__VIEWSTATE" value="(.*)"/i', $data, $regs2)){
throw new Exception ("Viewstate string not found in regex.");
}
return array(
"ufps" => $regs1[1],
"vs" => $regs2[1]
);
}
public function getCacheDetails($gccode){
try {
$this->loginWAP();
} catch (Exception $e) {
throw $e;
}
// Grab initial ASP session data
$url = "http://wap.geocaching.com/default.aspx";
extract($this->getUFPSandViewstate($this->postGet($url)));
// Go to search page
$postData = array(
"__EVENTTARGET" => "lnkViewCache",
"__EVENTARGUMENT" => "frmEnterWpt",
"__VIEWSTATE" => $vs
);
$searchurl = "{$url}?__ufps={$ufps}";
$data = $this->postGet($searchurl,$postData,$url);
extract($this->getUFPSandViewstate($data));
// Make the search
$postData = array(
"__VIEWSTATE" => $vs,
"__EVENTTARGET" => "",
"__EVENTARGUMENT" => "",
"txtEnterWpt" => $gccode,
"cmdEnterWpt" => "Submit"
);
$cacheurl = "{$url}?__ufps={$ufps}";
$data = $this->postGet($cacheurl,$postData,$searchurl);
preg_match("/\s(.*?)<br>\s+{$gccode}/i", $data, $regs); $name = $regs[1];
preg_match("/\sOwner: (.*?)<br>/i", $data, $regs); $owner = $regs[1];
preg_match('/\s((N|S) (.*?))\s*<br>/i', $data, $regs); $lat = str_replace("&#176;","",$regs[1]);
preg_match('/\s((W|E) (.*?))\s*<br>/i', $data, $regs); $lng = str_replace("&#176;","",$regs[1]);
return array(
"name" => $name,
"owner" => $owner,
"lat" => $this->minDectoDecDegree($lat),
"lng" => $this->minDectoDecDegree($lng)
);
}
public function minDectoDecDegree($coord){
$coord = explode(" ",$coord);
return round((($coord[0]=="S"|$coord[0]=="W")?-1:1) * (floatval($coord[1]) + (floatval($coord[2])/60)),5);
}
public function getMutualCaches($user1,$user2){
try {
$c1 = $this->getCachesFromUser($user1);
$c2 = $this->getCachesFromUser($user2);
} catch (Exception $e) {
throw $e;
}
return array_intersect($c1,$c2);
}
function checkUserExists($user){
$url = "http://www.geocaching.com/seek/nearest.aspx?ul={$user}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $url);
$data = curl_exec($ch);
return $this->checkUserFound($data);
curl_close($ch);
}
function checkUserFound($data){
//todo check that the page is a search result page
return !(preg_match('/<span id="ctl00_ContentBody_SearchResultText">Advanced Search<\/span>/i', $data));
}
function getCachesFromUser($user){
$url = "http://www.geocaching.com/seek/nearest.aspx?ul={$user}";
$caches = array();
$postData = array();
// We'll correct this later.
$pages = 2;
for($page = 1; $page <= $pages; $page++){
$data = $this->postGet($url,$postData);
// Check the user exists
if(!$this->checkUserFound($data)){
throw new Exception('User "'.$user.'" does not exist.');
}
// Correct the page count (if this is the first scrape)
if($page == 1){
preg_match('/Page: <b>1<\/b> of <b>(.*?)<\/b>/i', $data, $regs);
$pages = $regs[1];
}
// Extract the geocaches
preg_match_all('/\|\s*(GC[A-Z0-9]+)\s*\|/', $data, $arr);
$caches = array_merge($caches, $arr[1]);
// Need to advance list at multiples of 10
if($page%10==0){
$et = 'ctl00$ContentBody$pgrTop$ctl06';
}else{
$et = 'ctl00$ContentBody$pgrTop$lbGoToPage_'.($page+1);
}
// Prepare next postData
$postData = array(
"__EVENTTARGET" => $et,
"__EVENTARGUMENT" => (preg_match('/__EVENTARGUMENT\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
"__LASTFOCUS" => (preg_match('/__LASTFOCUS\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
"__VIEWSTATEFIELDCOUNT" => (preg_match('/__VIEWSTATEFIELDCOUNT\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
"__VIEWSTATE" => (preg_match('/__VIEWSTATE\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
"__VIEWSTATE1" => (preg_match('/__VIEWSTATE1\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
"__PREVIOUSPAGE" => (preg_match('/__PREVIOUSPAGE\" value=\"(.*)\"/i', $data, $regs))?$regs[1]:"",
'ctl00$tbUsername' => "",
'ctl00$tbPassword' => "",
'ctl00$ContentBody$chkHighlightBeginnerCaches' => "on"
);
}
return $caches;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment