User:George Drummond/SpecialGoogleEarth.php

THIS IS AN ALPHA RELEASE.
<?php 
/*
 * Google Earth Exporter for Google Maps Extension
 * http://www.mediawiki.org/wiki/Extension:Google_Maps
 * Written for Wikipaddle.org
 *
 * Copyright (c) 2006 by George Drummond, georgedrummond@wikipaddle.org
 *
 * Expanding Google Maps Extension by Evan Miller, emmiller@gmail.com
 *
 * Version 0.1 ALPHA - 2 Feb 2007
 *
 * -----------------------------------------------------------------------
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * http://www.gnu.org/copyleft/gpl.html
 * -----------------------------------------------------------------------
 */
  
if(!defined('MEDIAWIKI'))
   die('This is not a stand alone file ;)');
   
/*
 *
 * Define the defaults
 *
 */
define ('GME_DEFAULT_ICON', 'http://maps.google.com/mapfiles/kml/pal4/icon57.png');
define ('GME_ICON_PATH', 'http://maps.google.com/mapfiles/kml/pal2/');
define ('GME_POLYLINE_OPACITY', '7f');
define ('GME_POLYLINE_WIDTH', '4');
define ('GME_EXPORT_VERSION', '0.1 ALPHA');

/*
 *
 * Special page stuff
 *
 */
$wgExtensionFunctions[] = 'GoogleEarthExportSetup';
$wgExtensionCredits['specialpage'][] = array(
   'name' => 'Google Earth Export',
   'author' => '[http://wikipaddle.org/wiki/User:George_Drummond George Drummond]',
   'version' => GME_EXPORT_VERSION,
   'url' => 'http://www.mediawiki.org/wiki/Extension:Google_Maps',
   'description' => 'Google earth exporter for GoogleMaps plugin'
);

function GoogleEarthExportSetup( $par = '' ) {
	global $wgMessageCache;
	SpecialPage::addPage(new SpecialPage('GoogleEarthExport', '', true, 'GoogleEarthExportSpecial', true));
	$titleObj = Title::makeTitle( NS_SPECIAL, 'GoogleEarthExport' );
	$action = $titleObj->escapeLocalURL();
	$wgMessageCache->addMessages( 
		array(
			"googleearthexport"	=> "Google Earth Export",		
			"ge-title" => "Google Earth Exporter for Google Maps",
			"ge-pagenoexist" => "=== We couldnt find the page that you requested ===",
			"ge-nomapfound" => "=== We couldn't find a map on the page that you requested ===",
			"ge-formdescription" => "To export a google map to google earth format, enter the '''page name''' into the box bellow and press export.",
			"ge-form" => "<form method=\"get\" action=\"$action\"><input name=\"page\" type=\"text\" /> <input name=\"export\" type=\"submit\" value=\"Export\" /></form><br />",
			"ge-information" => "'''This is a alpha version and is currently still being tested and developed.'''",
		)
	);

}

function GoogleEarthExportSpecial(){
	global $wgRequest;
	$page_name = textSqlSafe( $wgRequest->getText( 'page', $par ) ); // Make input safe to put in SQL. ***THIS MIGHT BECOME A PROBLEM WITH PAGES WITH STRANGE NAMES?**
	if( $page_name != "" ){
		$page_name = str_replace(" ", "_", $page_name); // Replace spaces in page name with "_"
		GoogleEarthExporter( $page_name );
	}
	else { GoogleEarthForm(); } // If no page requested just show form
}

function GoogleEarthForm(){
	global $wgOut;
	$wgOut->addWikiText( wfMsg( 'ge-formdescription') );
	$wgOut->addHTML( wfMsg( 'ge-form' ) ); 
	$wgOut->addWikiText( wfMsg( 'ge-information' ) );
}

/*
 *
 * SQL Functions
 *
 */
function pageFromTitle( $title ) {
	return "page_namespace= '".$title->getNamespace()."' AND page_title= '".$title->getDbKey()."'" ;
}

function pageByName2( $name ) {
	$title = Title::newFromText( $name );
	if( is_null( $title ) ) {
		return new WikiError( "Can't export invalid title" );
	} else {
		return pageFromTitle( $title );
	}
}

function pageByTitle( $title ) { // Not in current use
	return $this->dumpFrom('page_namespace=' . $title->getNamespace() .
	' AND page_title=' . $this->db->addQuotes( $title->getDbKey() ) );
}


function textSqlSafe( $value ){ // Make text safe to form sql query.
	if( get_magic_quotes_gpc() )
		  $value = stripslashes( $value );
	if( function_exists( "mysql_real_escape_string" ) )
		  $value = mysql_real_escape_string( $value );
	else
		  $value = addslashes( $value );
	return $value;
}

/*
 *
 * Pull page from database
 *
 */
function GoogleEarthExporter( $page_name ){
	global $wgRequest, $wgExportAllowListContributors;
	global $wgExportAllowHistory;

	$dbr =& wfGetDB( DB_SLAVE );
	$page = $dbr->tableName( 'page' );
	$revision = $dbr->tableName( 'revision' );
	$text = $dbr->tableName( 'text' );
	
	$page_title = pageByName2( $page_name );
	
	// Could this SQL could do with some cleaning up?
	$geSqlSelect = "SELECT page_namespace, page_title, page_id, page_latest, old_text";
	$geSqlSelectFrom = " FROM $page, $revision, $text";
	$geSqlWhere = " WHERE $page_title AND page_id=rev_page AND page_latest=rev_id AND rev_text_id=old_id";
	$geSqlOrderby = ' ORDER BY page_id';
	$sql = $geSqlSelect.$geSqlSelectFrom.$geSqlWhere.$geSqlOrderby;

	$res = $dbr->query( $sql );
	$row = $dbr->fetchObject( $res );

	if( !$row->page_title ) // If page dosen't exist
		pageNotExist();
	elseif( isRedirect( $row->old_text ) ) // If it is a redirect
		handleRedirects( $row->old_text, $page_name );
	else 
		makeKml( $row->page_title, $row->old_text );  // If page exists and isnt a redirect go to makeKml
}

/*
 *
 * Page errors
 *
 */
function pageNotExist(){
	global $wgOut;
	$wgOut->addWikiText( wfMsg( 'ge-pagenoexist' ) );
	GoogleEarthForm();
}

function isRedirect( $old_text ){ // Check if page is a redirect
	if(preg_match('/#REDIRECT \[\[([^<]*)\]\]/', $old_text, $new))
		return true;
}

function handleRedirects( $old_text, $page_title ){
	preg_match('/#REDIRECT \[\[([^<]*)\]\]/', $old_text, $redirect);
	if($page_name == $redirect[1])
		echo "double redirect";
	else{
		$titleObj = Title::makeTitle( NS_SPECIAL, 'GoogleEarthExport' );
		$url = $titleObj->escapeLocalURL();
		header("Location: ".$url."?page=".$redirect[1]);
	}
}

/*
 *
 * Rendering wiki text. See hacky link fixers, know any better way feel free to change.
 *
 */
function renderWikiText( $text ){ // This code was taken from somewhere but i forgot source.
	global $wgOut, $wgUser, $wgTitle, $wgParser, $wgServer, $wgAllowDiffPreview, $wgEnableDiffPreviewPreference;
	$parserOptions = ParserOptions::newFromUser( $wgUser );
	$parserOptions->setEditSection( false );
	$parsed = $wgParser->parse( $text, $wgTitle, $parserOptions ); 
	$output = str_replace('<img src="/', '<img src="'.$wgServer.'/', $parsed->mText); // Image link fix
	$output = str_replace('<a href="/', '<a href="'.$wgServer.'/', $output); // Url link fix
	return $output;
}

/*
 *
 * Map Making stuff
 *
 */
function mime_type( $page_title ){
	$output .= header("Cache-Control: no-cache, must-revalidate"); // We dont want file to be cached.
	$output .= header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");   // Expires in the past.
	$output .= header("Content-type: application/vnd.google-earth.kml+xml");
	$output .= header('Content-Disposition: attachment; filename="'.$page_title.'.kml"');
	return $output;
}

function xml_header( $page_title ){
	global  $wgServer, $wgVersion;
	$output = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	$output .= "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n";
	$output .= "<!-- Source: ".$wgServer.", Generated by Special:GoogleEarthExport -->\n"; // This might be usefull when trying to debug
	$output .= "<!-- Page: ".$page_title.", Mediawiki: ".$wgVersion.", Version: ".GME_EXPORT_VERSION.", Time: ".date('Y-m-d, H:i:s')." -->\n";
	$output .= "<Document>\n<open>1</open>\n";
	return $output;	
}

function addMarker( $lat, $lon, $icon, $description, $marker_count ) {
	$output .= "<Placemark>\n";
	$output .= "<name>point ".$marker_count."</name>";
	$output .= "<Style><Icon><href>";
	if 
		($icon) $output .= GME_ICON_PATH.$icon."png";
	else 
		$output .= GME_DEFAULT_ICON;
	$output .= "</href></Icon></Style>\n";
	$output .= "<Point><coordinates>".$lon.", ".$lat.", 0</coordinates></Point>\n";
	if ($description) 
		$output .= '<description><![CDATA[<table width="333">'.$description.'</table>]]></description>';
	$output .= "</Placemark>\n";
	return $output;
}

function addPolyline( $polyline, $color ){
	$output .= "<Placemark>\n<name>Polyline</name>\n<Style><LineStyle>
				<color>".GME_POLYLINE_OPACITY.ltrim($color, "#")."</color>
				<width>".GME_POLYLINE_WIDTH."</width>      
				</LineStyle></Style><LineString><tessellate>1</tessellate><altitudeMode>clampedToGround</altitudeMode>\n"; //Might want to change this later on.
	$output .= "<coordinates>\n";
	$output .= implode("\n", $polyline);
	$output .= "\n</coordinates>\n</LineString>\n</Placemark>\n";
	return $output;
}

/*
 *
 * Map maker, taken from google maps extension
 *
 */
function makeMap( $map ) {
	$lines = preg_split("/[\r\n]+/", $map);
	$doAddMarker = false;
	$marker_count = 0; // Just name markers numerically for now, starting at 1
	foreach($lines as $line) {
		if (preg_match("/^(#[0-9a-fA-F]{6})/", $line, $matches)) {
			//if ($wgGoogleMapsEnablePaths) {
				if (isset($color)) { // i.e., we were just making a path, so dump and reset $polyline
					$output .= addPolyline($polyline, $color);
					$polyline = array();
				}
				$color = $matches[1];
			//}
		}
		elseif (preg_match('/^\/([^\\\\]+)\\\\ *(.*)$/', $line, $matches)) {
			$tab_description = renderWikiText( $matches[2] );
			$description .="<hr /><h2>".$matches[1]."</h2>".$tab_description;
			$doAddMarker = true; // we want a marker there if it has tabs
		} 
		elseif (preg_match("/^(?:\(([.a-zA-Z0-9_-]*?)\) *)?([^,]+), *([^ ,]+)(?:, (.+))?/", $line, $matches)) {
			if ($doAddMarker) { // first create the previous marker, now that we have all the tab/caption info
				$output .= addMarker($lat, $lon, $icon, $description, $marker_count);
				$doAddMarker = false;
			}
			$icon = $matches[1];
			$lat = $matches[2];
			$lon = $matches[3];
			$description = addslashes(renderWikiText($matches[4]));
			// This parse function above lets us insert wiki markup into the map markers.
			//}
			if (is_numeric($lat) && is_numeric($lon)) {
				if ($icon || $caption || !isset($color)) { // we don't actually put down a marker for anonymous points along a path
					$doAddMarker = true;
					$marker_count++;
				}
				// If we're making a path, record the location and move on.
				if (isset($color)) {
					$polyline[] = "{$lon}, {$lat}";
				}
			}
		}
	}
	if( isset($color) ) // Close polylines
		$output .= addPolyline( $polyline, $color );
	if ($doAddMarker) { // we've been waiting
				$output .= addMarker($lat, $lon, $icon, $description, $marker_count);
	}

	return $output;
}

/*
 *
 * KML maker
 *
 */
function makeKml( $page_title, $old_text ){
	global $wgOut, $wgRequest;
	if(preg_match("/(<googlemap[^>]*>)([^<]*)(<\/googlemap>)/", $old_text)){
		
		preg_match_all("/<googlemap([^>]+)>*([^<]+)<\/googlemap>/", $old_text, $source);
		$maps = $source[2];
		$maps_attributes = $source[1];
		$map_number = $wgRequest->getText( 'map_number', $par );
		
		$output = "";
		$output .= xml_header( $page_title );

		if( $map_number != "" && is_numeric($map_number) && $map_number <= count($maps) ) {
			$output .= makeMap( $maps["$map_number"] );
		}
		elseif( !$map_number ){ // if no map is requested then just display all
			$i = 0; // Maps dont have any title at the moment. Lets just label them numerically for now, starting at 1.
			foreach($maps as $map){
				preg_match("#name=\"(.*?)\"#s",$maps_attributes[$i], $title_tag);
				if( $title_tag[0] = "" || !$title_tag[0] ){
					$title = "Map ".($i+1);
				}
				else { $title = $title_tag[1]; }
				$output .= "<Folder>\n<name><![CDATA[".$title."]]></name>\n";
				$output .= makeMap( $map );		
				$output .= "</Folder>";
				$i++;
			}
		}
		else {// Map number isnt found on this page.
			$wgOut->setPageTitle( wfMsg( 'ge-title' ) ); // If no map is found on page
			$wgOut->addWikiText( "=== We couldn't find that map number on the page that you requested ===" );
			GoogleEarthForm();
			return true;
		}
		$output .= "</Document>\n";
		$output .= "</kml>";
		
		// Output mime type now
		$wgOut->disable();
		mime_type( $page_title );
		echo $output;
	}
	else {
		$wgOut->setPageTitle( wfMsg( 'ge-title' ) ); // If no map is found on page
		$wgOut->addWikiText( wfMsg( 'ge-nomapfound' ) );
		GoogleEarthForm();
	}
}