<?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;
}
?>