User:Mafs/GoogleMapExtension/gmap.php

From Meta, a Wikimedia project coordination wiki
<?php

/*
Google Map MediaWiki Extension 


Documentation:
http://meta.wikimedia.org/w/index.php?title=User:Mafs/GoogleMapExtension

Copyright (C) 2005  Gregory Szorc <gregory.szorc@case.edu>
                    (see http://meta.wikimedia.org/wiki/User:IndyGreg/GoogleMapExtension)
                    (http://wiki.case.edu/CaseWiki:Google_Map_Extension)

and  M. Arndt <chmarndt@medemsand.de> (July/Septemper 2005)

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.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA



*/

if( !defined( 'MEDIAWIKI' ) ) {
	die();
}

$wgExtensionCredits['other'][] = array(
	'name' => 'gmap extension',
	'author' => 'Gregory Szorc, Markus Arndt',
	'version' => '09/21/2005',
	'url' => 'http://meta.wikimedia.org/wiki/User:Mafs/GoogleMapExtension',
	'description' => 'displays a google map on a wiki page'
);

$wgExtensionFunctions[] = "wfGoogleMapExtension";

function wfGoogleMapExtension() {
	global $wgParser;
	$wgParser->setHook("gmap", "gmapCreate");
}

require_once( "includes/DatabaseFunctions.php" );

function gmapCreate($input) {

	$gmap = new Gmap();
	return $gmap->gmapCreateMap($input);
}


class Gmap 
{

var $xmlItem, $xmlRss;
var $maxTrackpoints;
var $gpx_types, $gpx_mode;
var $lat, $lon, $link;

var $gpxBody;
var $gpxWaypoint;
var $gpxLink;


function Gmap () {

$this->xmlItem = "    <item>
      <title>itemTitle</title>
      <description>itemDescription</description>
      <link>itemLink</link>
      <type>itemMode</type>
      <geo:lat >itemLat</geo:lat>
      <geo:long >itemLong</geo:long>
    </item>";

$this->xmlRss = "<?xml version = '1.0'?>
<rss version=\"2.0\" xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">
  <channel>
    <description>rssDescription</description>
    <link>rssLink</link>
    <title>rssTitle</title>
    <pubDate>rssPupdate</pubDate>
rssItems
  </channel>
</rss>";

$this->gpxBody = <<<End
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<gpx version="1.1" creator="EasyGPS 1.3.7 - http://www.topografix.com" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.topografix.com/GPX/1/1"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/1" xmlns:gpx_overlay="http://www.topografix.com/GPX/gpx_overlay/0/1" xmlns:topografix="http://www.topografix.com/GPX/Private/TopoGrafix/0/2" xmlns:offroute="http://www.topografix.com/GPX/Private/Offroute/0/1">
 gpxBody
 </gpx>
End
;
$this->gpxBody = trim($this->gpxBody );

$this->gpxWaypoint = "<wpt lat=\"gpxLat\" lon=\"gpxLon\"><desc>gpxDescription</desc>gpxLink</wpt>";

$this->gpxLink = "<link href=\"gpxUrl\"><text>gpxText</text></link>";

$this->gpx_types = array("wpt", "trkpt", "rtekpt");

$this->gpx_mode = array (
	"wpt"=>"point",
	"trkpt"=>"path",
	"rtept"=>"path");

$this->maxTrackpoints = 500;

$this->link = "index.html";
$this->lat = "";
$this->lon = "";
}


function gmapCreateMap($input) {

global $wgGmapSource, $wgGmapKey;

  global $IP, $wgScriptPath;

  if (isset($GLOBALS['GoogleMapCount'])) {
    if (ctype_digit($GLOBALS['GoogleMapCount'])) {
      $GLOBALS['GoogleMapCount']++;
    }
    else {
      //data poisoning
      return "";
    }
  }
  else {
    $GLOBALS['GoogleMapCount'] = 1;
  }

  $id = trim($GLOBALS['GoogleMapCount']);
  //data poisoning
  if (!ctype_digit($id)) {
    return "";
  }

  
  	//the default values center on the Case Campus (see http://wiki.case.edu/Map)
	$lat_def = 41.5061;
	$lon_def = -81.6089;
	$lat = "";
	$lon = "";
	$type = "_SATELLITE_TYPE";
	$height = 600;
	$width = 740;
	$zoom = 1;
  	$controls = "no";
	$fields = explode('|', $input);
  	$feeds = false;
	$maxrss = -1;
	$info = "";
	
	$alert = "";
	$CacheDir = "cache";
	$MaxAgeCache = 10; // in minutes 
	$useXmlCache = false;

	$first_sub = false;

	$description = array();
	$link = array();

	if (!is_dir("$IP/$CacheDir")) $alert = "This cache directory $IP/$CacheDir is not available.";	

	//parse through all the fields
	for ($i = 0; $i < sizeof($fields); $i++) {
		if (strpos($fields[$i], '=') === false) {
			//nothing yet
		}
		else {
			list ($k, $v) = explode('=', $fields[$i], 2);
			//$k = 
			$v = substr($fields[$i], strpos($fields[$i], "=") +1 );
			
			switch (strtolower(trim($k))) {
				case "lat":
					if (is_numeric(trim($v))) {
						$lat = trim($v);
					}
					break;
					
				case "lon":
					if (is_numeric(trim($v))) {
						$lon = trim($v);
					}
					break;

				case "info":
					$info = htmlspecialchars(strip_tags(trim($v)));
					break;
					

				case "zoom":
					if (is_numeric(trim($v))) {
						$zoom = round(trim($v));
					}
				  	break;
					
				case "type":
					if (trim($v) == "street") {
					$type = "_MAP_TYPE";
					}
					else if (trim($v) == "hybrid") {
					$type = "_HYBRID_TYPE";
					}
					else if (trim($v) == "satellite") {
					$type = "_SATELLITE_TYPE";
					}
					break;
					
				case "id":
					if (is_numeric(trim($v))) {
						$id = trim($v);
					}
					break;

				case "width":
					if (is_numeric(trim($v))) {
					if (trim($v) > 0) {
					$width = trim($v); 
					}
					}
					break;
				
				case "height":
					if (is_numeric(trim($v))) {
					if (trim($v) > 0) {
					$height = trim($v); 
					}
					}
					break;

				case "maxrss":
					if (is_numeric(trim($v))) {
					if (trim($v) > 0) {
					$maxrss = trim($v); 
					}
					}
					break;
			
				case "controls":
					if (trim($v) == "yes") {
					$controls = "yes";
					}
					else if (trim($v) == "no") {
					$controls = "no";
					}
					break; 
			
				case "usecache":
					if (trim($v) == "yes") {
					$useXmlCache = true;
					}
					else if (trim($v) == "no") {
					$useXmlCache = false;
					}
					break; 

				case "rss":
					
					if ($feeds === false) {
						$feeds = array(); 
					}
						$feeds[] = trim($v); 
					
					break;
			
								
				default:
			}
		}
	}


	if ($feeds) {
	foreach($feeds as $feed) {
	
		$feed_md5 = md5(htmlentities($feed).$maxrss).".gpx";
		$feeds_md5[] = "$wgScriptPath/$CacheDir/$feed_md5";
		$result = "";
		
		$now = time();
		if (file_exists("$IP/$CacheDir/$feed_md5")) $modtime = filemtime("$IP/$CacheDir/$feed_md5"); else $modtime = 0; 
		$x = 60 * $MaxAgeCache;
		$delta = $now - $modtime; 
	
		if (file_exists("$IP/$CacheDir/$feed_md5") and ($delta < $x) and $useXmlCache) {
	
			$result = file_get_contents("$IP/$CacheDir/$feed_md5");
			//$file_content = $result; 
			
		} else { 
			// if $feed starts with "http://" an external rss will be feteched
			if (preg_match("/^http\:\/\/.+/i", $feed, $a)) {

				$this->link = $feed;
			
				$ch = curl_init();
				curl_setopt($ch, CURLOPT_URL, $feed);
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
				
				$result=curl_exec ($ch);
				curl_close ($ch);  //die($result);

			// if $feed teminates wiht an "/" the rss feed is created from 
			// internal wiki pages having a .../long=12.345,lat=12.345 title 
			} elseif (preg_match("/(.+)\/$/i", $feed, $a) and !$first_sub) { 

				$first_sub = true;
				$sub = $a[1];
				$this->link = "$wgScriptPath/index.php?title=$sub";

				$dbw =& wfGetDB( DB_MASTER );
				$r = $dbw->select("page", 
					"page_title", 
					array("page_namespace=0", 
					"page_title REGEXP '".wfStrencode("^$sub/")."'" ), 
					"gmap extension", 
					"ORDER BY page_title ASC" ); 
			
				while ($row = $dbw->fetchRow($r)) { 
					if (preg_match("/.*?long\=([\-]{0,1}[0-9]{1,3}[\.]{0,1}[0-9]*)\,lat\=([\-]{0,1}[0-9]{1,3}[\.]{0,1}[0-9]*)$/", $row[0], $a)) {
					$result = wfGetPageTextFromTitle($row[0]);
					if (!(preg_match("/<\s*disabledisplay\s*[\/]{0,1}\s*>/i", $result, $b) or (trim($result) == ""))) {
						$ilong = $a[1];
						$ilat = $a[2];
						$line = explode("\n", $result);
			
						$ititle = $line[0];
						$ititle = preg_replace("/#redirect\s*\[\[(.*)\]\]/i", "\\1", $ititle);
						$ititle = substr($ititle, 0, 40);
						$ititle = trim(htmlspecialchars(strip_tags($ititle)));

						$ilink = $row[0];
			
						$line[0] = "";
						$idescription = trim(implode("\n", $line));
						$idescription = substr($idescription, 0, 40);
						$idescription = htmlspecialchars(strip_tags($idescription));
						$idescription = preg_replace("/\n/", "", $idescription);
	
						// gpx
						$i = preg_replace("/gpxDescription/", $idescription, $this->gpxWaypoint);
						$i = preg_replace("/gpxLat/", $ilat, $i);
						$i = preg_replace("/gpxLon/", $ilong, $i);

						$l = preg_replace("/gpxText/", $ititle, $this->gpxLink);
						$l = preg_replace("/gpxUrl/", "$wgScriptPath/index.php?title=".$ilink, $l);

						$i = preg_replace("/gpxLink/", $l, $i);

						$items[] = $i;

					}
					}
				}
				if (is_array($items) and count($items)>0 ) {

					// rss
					$result = preg_replace("/rssItems/", implode("\n", $items), $this->xmlRss);
					global $wgSitename;
					$result = preg_replace("/rssDescription/", "$wgSitename Wikipages",  $result);
					$result = preg_replace("/rssTitle/", $sub."/", $result);
					$result = preg_replace("/rssLink/", "$wgScriptPath/index.php?title=$sub", $result); 

					// gpx
					$result = trim(preg_replace("/gpxBody/", implode("\n", $items), $this->gpxBody));

				} else $result = "";

			} else { 

				$result = wfGetPageTextFromTitle($feed);
				$result = preg_replace("/\n-/", "\n", $result);
				$result = preg_replace("/^\s*/", "", $result);
				$result = preg_replace("/<pre>/", "", $result);
				$result = preg_replace("/<\/pre>/", "", $result);
				$result = trim($result);
				//die($result);
				$this->link = "$wgScriptPath/index.php?title=$feed";
			}
			
			}

		if (trim($result) != "") {
			$result = $this->gmapCreateGpx($result);
			//die($result);
			//if ($useXmlCache) { // disabeled, it works not correctly.
				$f = fopen("$IP/$CacheDir/$feed_md5", "w");
				fwrite($f, trim($result)); 
				fclose($f);
			//}

		}
	} // foreach feeds
	} // if feeds

	if ($lat == "") $lat = $this->lat;
	if ($lon == "") $lon = $this->lon;
	if ($lat == "") $lat = $lat_def;
 	if ($lon == "") $lon = $lon_def;

	$data = "<div id=\"gmap_$id\" class=\"googleMap\" ></div>\n";
  	$data .= "<div id=\"gmapmessage_$id\"></div>\n";
  	$data .= "<div id=\"gmapmessage2_$id\"></div>\n";
  
	//we embed all of the parameters in a form which is read by the javascript at run-time
	$data .= "		<form name=\"mapform_$id\" id=\"mapform_$id\" class=\"hidden\" >";
	$data .= "  <input type=\"hidden\" name=\"info\" value=\"$info\" />";
	$data .= "  <input type=\"hidden\" name=\"lat\" value=\"$lat\" />";
	$data .= "  <input type=\"hidden\" name=\"lon\" value=\"$lon\" />";
	$data .= "  <input type=\"hidden\" name=\"zoom\" value=\"$zoom\" />";
	$data .= "  <input type=\"hidden\" name=\"height\" value=\"${height}px\" />";
	$data .= "  <input type=\"hidden\" name=\"width\" value=\"${width}px\" />";
	$data .= "  <input type=\"hidden\" name=\"type\" value=\"$type\" />";
	$data .= "  <input type=\"hidden\" name=\"controls\" value=\"$controls\" />";
	$data .= "  <input type=\"hidden\" name=\"maxrss\" value=\"$maxrss\" />";
	if ($first_sub) $data .= "  <input type=\"hidden\" name=\"path\" value=\"$wgScriptPath/index.php?title=$sub\" />";

  	if ($feeds) {
    		$feedstring = implode('|', $feeds_md5);
    		$data .= "  <input type=\"hidden\" name=\"rss\" value=\"".htmlentities($feedstring)."\" />";
  	}
	$data .= "</form>";

	if ($alert != "") $data = $data."<br>".$alert."<br>";


	wfDisableCache();
	return $data;

}

function gmapCreateGpx($text) {

	// Javascript has problems dealing with an '&' in a title, therefore it is replaced by //AND//.
	//$this->link = preg_replace("/&/", "//AND//", $this->link);

	if (preg_match("/<rss.*?>.*?<\/rss>/is", $text, $a)) {
	
	while(preg_match("/<item.*?>(.*?)<\/item>/is", $text, $a)) {
	
		$text = str_replace($a[0], "", $text);
		$item = $a[1];
		
		preg_match("/<geo\:?lat.*?>(.*?)<\/geo\:?lat>/is", $item, $a);
		$lat = $a[1];
		preg_match("/<geo\:?long.*?>(.*?)<\/geo\:?long>/is", $item, $a);
		$long = $a[1];
		preg_match("/<title.*?>(.*?)<\/title>/is", $item, $a);
		$title = $a[1];
		preg_match("/<description.*?>(.*?)<\/description>/is", $item, $a);
		$description = $a[1];
		preg_match("/<link.*?>(.*?)<\/link>/is", $item, $a);
		$link = $a[1];
		
		$i = preg_replace("/gpxDescription/", $description, $this->gpxWaypoint);
		$i = preg_replace("/gpxLat/", $lat, $i);
		$i = preg_replace("/gpxLon/", $long, $i);

		$l = preg_replace("/gpxText/", $title, $this->gpxLink);
		$l = preg_replace("/gpxUrl/", "$wgScriptPath/index.php?title=".$link, $l);

		$i = preg_replace("/gpxLink/", $l, $i);

		$items[] = $i;
	}
	
	$result = trim(preg_replace("/gpxBody/", implode("\n", $items), $this->gpxBody));

	} else {
		preg_match("/<gpx.*?>(.*?)<\/gpx>/is", $text, $a);
		$result = trim(preg_replace("/gpxBody/", $a[1], $this->gpxBody));
	}
	
	// teh first waypoint or trkpoint is the default center point
	if (preg_match("/<wpt.*?lat=\"([0-9\.\-]+)\".*?>/is", $text, $a)) $this->lat = $a[1];
	if (preg_match("/<trkpt.*?lat=\"([0-9\.\-]+)\".*?>/is", $text, $a)) $this->lat = $a[1];

	if (preg_match("/<wpt.*?lon=\"([0-9\.\-]+)\".*?>/is", $text, $a)) $this->lon = $a[1];
	if (preg_match("/<trkpt.*?lon=\"([0-9\.\-]+)\".*?>/is", $text, $a)) $this->lon = $a[1];	


	//die("<pre>".$result."</pre>");	
	return $result;
}

	
function gmapCreateRss($text) {

	// Javascript has problems dealing with an '&' in a title, therefore it is replaced by //AND//.
	$this->link = preg_replace("/&/", "//AND//", $this->link);

	if (preg_match("/<gpx.*?>.*?<\/gpx>/is", $text, $a)) {

	//die("<pre>".$text."</pre>");

$ki = 0;

	foreach($this->gpx_types as $type) {

		while(preg_match("/<$type.*?>.*?<\/$type>/is", $text, $a)) {

			
			preg_match("/<$type\s*lat=\"([0-9\-\.]+)\"\s*lon=\"([0-9\-\.]+)\">/", $a[0], $b);
			$glat = $b[1];
			$glong = $b[2];
		
			if (preg_match("/<desc.*?>(.*?)<\/desc>/is", $a[0], $c)) 	$gdesc = preg_replace("/\!\[CDATA\[(.*?)\]\]/is", "\\1", $c[1]); else $gdesc = "itemDescription";
			$gdesc = preg_replace("/</is", "1", $gdesc);
			$gdesc = preg_replace("/>/is", "1", $gdesc);
			
			$gurl = "";
			if (preg_match("/<url.*?>(.*?)<\/url>/is", $a[0], $d)) $gurl = $d[1];
			$gname = "";
			if (preg_match("/<name.*?>(.*?)<\/name>/is", $a[0], $d)) $gname = "$d[1] ";
		
			$i = $this->xmlItem;
			$i = preg_replace("/itemLat/", $glat, $i);
			$i = preg_replace("/itemLong/", $glong, $i);

			$i = preg_replace("/itemMode/", $this->gpx_mode[$type], $i);
			$i = preg_replace("/itemDescription/", "$gname$gdesc", $i);
			$i = preg_replace("/itemTitle/", "GPX", $i);
			if ($gurl != "") $i = preg_replace("/itemLink/", $gurl, $i);
			else $i = preg_replace("/itemLink/", $this->link, $i);

			if ($this->gpx_mode[$type] == "point") $gpx_waypoints[] = $i; else $gpx_path[] = $i;
		}
	}

	$j = count($gpx_path);
	$i = 0;
	$m = $j / $this->maxTrackpoints;
	if ($m < (1.1-0.1) ) $m = 1;   // strange: "1.1-0.1" represents zero, "0" does not represent zero.

	while ($i < $j) {
		$gpx_path_r[] = $gpx_path[round($i)];
		$i = $i + $m;
	}

	$gpxitems = "";
	if (is_array($gpx_waypoints)) $gpxitems = implode("\n", $gpx_waypoints);
	if (is_array($gpx_path_r))    $gpxitems = $gpxitems."\n".implode("\n", $gpx_path_r);

	$text = "";
	$text = preg_replace("/rssItems/", trim($gpxitems), $this->xmlRss);
	$text = preg_replace("/rssTitle/", "GPX", $text);
	$text = preg_replace("/rssDescription/", "", $text);

	$this->link = preg_replace("/&/", "//AND//", $this->link);
	$text = preg_replace("/rssLink/", $this->link, $text); 

	} elseif (preg_match("/<rss.*?>.*?<\/rss>/is", $text, $a)) {

		$text = preg_replace("/<\s*pre\s*>/i", "", $text);
		$text = preg_replace("/<\/\s*pre\s*>/i", "", $text);
		$text = preg_replace("/<\s*xmldata\s*>/i", "", $text);
		$text = preg_replace("/<\/\s*xmldata\s*>/i", "", $text); 

	} else $text = "";

	// IE does not like the geo:lat, geo:long tags.
	$text = preg_replace("/<\s*geo:lat\s*>/i", "<geolat>", $text);
	$text = preg_replace("/<\/\s*geo:lat\s*>/i", "</geolat>", $text);
	$text = preg_replace("/<\s*geo:long\s*>/i", "<geolong>", $text);
	$text = preg_replace("/<\/\s*geo:long\s*>/i", "</geolong>", $text);

	preg_match("/<geolat>\s*([0-9\.\-]+)\s*<\/geolat>/is", $text, $a);
	$this->lat = $a[1];
	preg_match("/<geolong>\s*([0-9\.\-]+)\s*<\/geolong>/is", $text, $a);
	$this->lon = $a[1];

	$text = trim($text);

	//die("<pre>".$text."</pre>");

return $text;


}

}

function wfDisableCache () {
 	global $wgParser;
	$wgParser->disableCache();   
}

function wfGetPageTextFromTitle($title) {

	$text = "";
	if (trim($title) == "") return $text;

	$t = Title::newfromText($title);

	if ($t->userCanRead()) {
		$revision = Revision::newFromTitle( $t );
		if ($revision) {
			$text = $revision->getText();
		}
	}

return $text;
}


?>