diff options
Diffstat (limited to '')
-rw-r--r-- | index.php | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/index.php b/index.php new file mode 100644 index 0000000..dcaf19e --- /dev/null +++ b/index.php @@ -0,0 +1,391 @@ +<?php + +/** + * staticMapLite 0.3.1 + * + * Copyright 2009 Gerhard Koch + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Gerhard Koch <gerhard.koch AT ymail.com> + * + * USAGE: + * + * staticmap.php?center=40.714728,-73.998672&zoom=14&size=512x512&maptype=mapnik&markers=40.702147,-74.015794,blues|40.711614,-74.012318,greeng|40.718217,-73.998284,redc + * + */ + +error_reporting(0); +ini_set('display_errors', 'off'); + +Class staticMapLite +{ + + protected $maxWidth = 500; + protected $maxHeight = 500; + + protected $tileSize = 256; + protected $tileSrcUrl = array('mapnik' => 'https://a.tile.openstreetmap.org/{Z}/{X}/{Y}.png', + 'osmarenderer' => 'https://otile1.mqcdn.com/tiles/1.0.0/osm/{Z}/{X}/{Y}.png', + 'cycle' => 'https://a.tile.opencyclemap.org/cycle/{Z}/{X}/{Y}.png', + ); + + protected $tileDefaultSrc = 'mapnik'; + protected $markerBaseDir = 'images/markers'; + protected $osmLogo = 'images/osm_logo.png'; + + protected $markerPrototypes = array( + 'default' => array('regex' => '/^marker-icon$/', + 'extension' => '.png', + 'shadow' => false, + 'offsetImage' => '-12,-40', + 'offsetShadow' => false + ) + ); + + + protected $useTileCache = true; + protected $tileCacheBaseDir = '.cache/tiles'; + + protected $useMapCache = true; + protected $mapCacheBaseDir = '.cache/maps'; + protected $mapCacheID = ''; + protected $mapCacheFile = ''; + protected $mapCacheExtension = 'png'; + + protected $zoom, $lat, $lon, $width, $height, $markers, $image, $maptype; + protected $centerX, $centerY, $offsetX, $offsetY; + + public function __construct() + { + $this->zoom = 0; + $this->lat = 0; + $this->lon = 0; + $this->width = 500; + $this->height = 500; + $this->markers = array(); + $this->maptype = $this->tileDefaultSrc; + } + + public function parseParams() + { + global $_GET; + + if (!empty($_GET['show'])) { + $this->parseOjwParams(); + } + else { + $this->parseLiteParams(); + } + } + + public function parseLiteParams() + { + // get zoom from GET paramter + $this->zoom = $_GET['zoom'] ? intval($_GET['zoom']) : 0; + if ($this->zoom > 18) $this->zoom = 18; + + // get lat and lon from GET paramter + list($this->lat, $this->lon) = explode(',', $_GET['center']); + $this->lat = floatval($this->lat); + $this->lon = floatval($this->lon); + + // get size from GET paramter + if ($_GET['size']) { + list($this->width, $this->height) = explode('x', $_GET['size']); + $this->width = intval($this->width); + if ($this->width > $this->maxWidth) $this->width = $this->maxWidth; + $this->height = intval($this->height); + if ($this->height > $this->maxHeight) $this->height = $this->maxHeight; + } + if (!empty($_GET['markers'])) { + $markers = explode('|', $_GET['markers']); + foreach ($markers as $marker) { + list($markerLat, $markerLon, $markerType) = explode(',', $marker); + $markerLat = floatval($markerLat); + $markerLon = floatval($markerLon); + $markerType = 'ol-marker';//basename($markerType); + $this->markers[] = array('lat' => $markerLat, 'lon' => $markerLon, 'type' => $markerType); + } + + } + if ($_GET['maptype']) { + if (array_key_exists($_GET['maptype'], $this->tileSrcUrl)) $this->maptype = $_GET['maptype']; + } + } + + public function parseOjwParams() + { + $this->lat = floatval($_GET['lat']); + $this->lon = floatval($_GET['lon']); + $this->zoom = intval($_GET['z']); + + $this->width = intval($_GET['w']); + if ($this->width > $this->maxWidth) $this->width = $this->maxWidth; + $this->height = intval($_GET['h']); + if ($this->height > $this->maxHeight) $this->height = $this->maxHeight; + + + if (!empty($_GET['mlat0'])) { + $markerLat = floatval($_GET['mlat0']); + if (!empty($_GET['mlon0'])) { + $markerLon = floatval($_GET['mlon0']); + $this->markers[] = array('lat' => $markerLat, 'lon' => $markerLon, 'type' => "ol-marker"); + } + } + } + + public function lonToTile($long, $zoom) + { + return (($long + 180) / 360) * pow(2, $zoom); + } + + public function latToTile($lat, $zoom) + { + return (1 - log(tan($lat * pi() / 180) + 1 / cos($lat * pi() / 180)) / pi()) / 2 * pow(2, $zoom); + } + + public function initCoords() + { + $this->centerX = $this->lonToTile($this->lon, $this->zoom); + $this->centerY = $this->latToTile($this->lat, $this->zoom); + $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize); + $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize); + } + + public function createBaseMap() + { + $this->image = imagecreatetruecolor($this->width, $this->height); + $startX = floor($this->centerX - ($this->width / $this->tileSize) / 2); + $startY = floor($this->centerY - ($this->height / $this->tileSize) / 2); + $endX = ceil($this->centerX + ($this->width / $this->tileSize) / 2); + $endY = ceil($this->centerY + ($this->height / $this->tileSize) / 2); + $this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize); + $this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize); + $this->offsetX += floor($this->width / 2); + $this->offsetY += floor($this->height / 2); + $this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize; + $this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize; + + for ($x = $startX; $x <= $endX; $x++) { + for ($y = $startY; $y <= $endY; $y++) { + $url = str_replace(array('{Z}', '{X}', '{Y}'), array($this->zoom, $x, $y), $this->tileSrcUrl[$this->maptype]); + $tileData = $this->fetchTile($url); + if ($tileData) { + $tileImage = imagecreatefromstring($tileData); + } else { + $tileImage = imagecreate($this->tileSize, $this->tileSize); + $color = imagecolorallocate($tileImage, 255, 255, 255); + @imagestring($tileImage, 1, 127, 127, 'err', $color); + } + $destX = ($x - $startX) * $this->tileSize + $this->offsetX; + $destY = ($y - $startY) * $this->tileSize + $this->offsetY; + imagecopy($this->image, $tileImage, $destX, $destY, 0, 0, $this->tileSize, $this->tileSize); + } + } + } + + + public function placeMarkers() + { + // loop thru marker array + foreach ($this->markers as $marker) { + // set some local variables + $markerLat = $marker['lat']; + $markerLon = $marker['lon']; + $markerType = $marker['type']; + // clear variables from previous loops + $markerFilename = ''; + $markerShadow = ''; + $matches = false; + // check for marker type, get settings from markerPrototypes + if ($markerType) { + foreach ($this->markerPrototypes as $markerPrototype) { + if (preg_match($markerPrototype['regex'], $markerType, $matches)) { + $markerFilename = $matches[0] . $markerPrototype['extension']; + if ($markerPrototype['offsetImage']) { + list($markerImageOffsetX, $markerImageOffsetY) = explode(",", $markerPrototype['offsetImage']); + } + $markerShadow = $markerPrototype['shadow']; + if ($markerShadow) { + list($markerShadowOffsetX, $markerShadowOffsetY) = explode(",", $markerPrototype['offsetShadow']); + } + } + + } + } + + // check required files or set default + if ($markerFilename == '' || !file_exists($this->markerBaseDir . '/' . $markerFilename)) { + $markerIndex++; + $markerFilename = 'marker-icon' . $markerIndex . '.png'; + $markerImageOffsetX = -12; + $markerImageOffsetY = -40; + } + + // create img resource + if (file_exists($this->markerBaseDir . '/' . $markerFilename)) { + $markerImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerFilename); + } else { + $markerImg = imagecreatefrompng($this->markerBaseDir . '/marker-icon.png'); + } + + // check for shadow + create shadow recource + if ($markerShadow && file_exists($this->markerBaseDir . '/' . $markerShadow)) { + $markerShadowImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerShadow); + } + + // calc position + $destX = floor(($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($markerLon, $this->zoom))); + $destY = floor(($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($markerLat, $this->zoom))); + + // copy shadow on basemap + if ($markerShadow && $markerShadowImg) { + imagecopy($this->image, $markerShadowImg, $destX + intval($markerShadowOffsetX), $destY + intval($markerShadowOffsetY), + 0, 0, imagesx($markerShadowImg), imagesy($markerShadowImg)); + } + + // copy marker on basemap above shadow + imagecopy($this->image, $markerImg, $destX + intval($markerImageOffsetX), $destY + intval($markerImageOffsetY), + 0, 0, imagesx($markerImg), imagesy($markerImg)); + + }; + } + + + public function tileUrlToFilename($url) + { + return $this->tileCacheBaseDir . "/" . str_replace(array('http://','https://'), '', $url); + } + + public function checkTileCache($url) + { + $filename = $this->tileUrlToFilename($url); + if (file_exists($filename)) { + return file_get_contents($filename); + } + } + + public function checkMapCache() + { + $this->mapCacheID = md5($this->serializeParams()); + $filename = $this->mapCacheIDToFilename(); + if (file_exists($filename)) return true; + } + + public function serializeParams() + { + return join("&", array($this->zoom, $this->lat, $this->lon, $this->width, $this->height, serialize($this->markers), $this->maptype)); + } + + public function mapCacheIDToFilename() + { + if (!$this->mapCacheFile) { + $this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_" . substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2) . "/" . substr($this->mapCacheID, 4); + } + return $this->mapCacheFile . "." . $this->mapCacheExtension; + } + + + public function mkdir_recursive($pathname, $mode) + { + is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); + return is_dir($pathname) || @mkdir($pathname, $mode); + } + + public function writeTileToCache($url, $data) + { + $filename = $this->tileUrlToFilename($url); + $this->mkdir_recursive(dirname($filename), 0777); + file_put_contents($filename, $data); + } + + public function fetchTile($url) + { + if ($this->useTileCache && ($cached = $this->checkTileCache($url))) return $cached; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + if (!empty($_SERVER['HTTP_USER_AGENT'])) { + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); + } else { + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); + } + curl_setopt($ch, CURLOPT_URL, $url); + $tile = curl_exec($ch); + curl_close($ch); + if ($tile && $this->useTileCache) { + $this->writeTileToCache($url, $tile); + } + return $tile; + + } + + public function copyrightNotice() + { + $logoImg = imagecreatefrompng($this->osmLogo); + imagecopy($this->image, $logoImg, imagesx($this->image) - imagesx($logoImg), imagesy($this->image) - imagesy($logoImg), 0, 0, imagesx($logoImg), imagesy($logoImg)); + + } + + public function sendHeader() + { + header('Content-Type: image/png'); + $expires = 60 * 60 * 24 * 14; + header("Pragma: public"); + header("Cache-Control: maxage=" . $expires); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT'); + } + + public function makeMap() + { + $this->initCoords(); + $this->createBaseMap(); + if (count($this->markers)) $this->placeMarkers(); + //if ($this->osmLogo) $this->copyrightNotice(); + } + + public function showMap() + { + $this->parseParams(); + if ($this->useMapCache) { + // use map cache, so check cache for map + if (!$this->checkMapCache()) { + // map is not in cache, needs to be build + $this->makeMap(); + $this->mkdir_recursive(dirname($this->mapCacheIDToFilename()), 0777); + imagepng($this->image, $this->mapCacheIDToFilename(), 9); + $this->sendHeader(); + if (file_exists($this->mapCacheIDToFilename())) { + return file_get_contents($this->mapCacheIDToFilename()); + } else { + return imagepng($this->image); + } + } else { + // map is in cache + $this->sendHeader(); + return file_get_contents($this->mapCacheIDToFilename()); + } + + } else { + // no cache, make map, send headers and deliver png + $this->makeMap(); + $this->sendHeader(); + return imagepng($this->image); + + } + } + +} + +$map = new staticMapLite(); +print $map->showMap();
\ No newline at end of file |