Last active
July 30, 2021 22:30
-
-
Save mgrubinger/4671d505db9a12184ed4989dbd9e4763 to your computer and use it in GitHub Desktop.
PHPMapTileDownloader: Simple PHP script to download map tiles from a tileserver (e.g. to create offline leaflet maps). Disclaimer: make sure the tile provider allows bulk downloading!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en-US"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>PHPMapTileDownloader</title> | |
<style> | |
body { | |
font-family: 'Helvetica', sans-serif; | |
text-align: center; | |
margin-top: 20px; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>PHPMapTileDownloader</h1> | |
<?php | |
/*************************** | |
*************************** | |
*** USER CONFIGURATION **** | |
*************************** | |
**************************/ | |
// define bounding box | |
$north = 48.22376; // lat north | |
$east = 16.40808; // lon east | |
$south = 48.1844; // lat south | |
$west = 16.34079; // lon west | |
$zoomlevels = array(14); // zoomlevels - e.g. array(15,16,17) | |
$tileserver = "https://mytileserver.myserver.com/{z}/{x}/{y}.png"; // tileserver - e.g. "https://mytileserver.myserver.com/{z}/{x}/{y}.png"; | |
$output_dir = "tiles"; // output directory - e.g. "tiles" | |
$dry_run = true; // dry run: do not download files, only output names | |
$skip_existing_files = true; // skip existing files? | |
// end of user config | |
// PHP-Config | |
error_reporting(E_ALL | E_STRICT); | |
ini_set('display_errors','On'); | |
// create output dir | |
if(!file_exists($output_dir)) { | |
mkdir($output_dir); | |
_log('Directory created: ' . $output_dir); | |
} | |
// array to store all required tiles(-urls) | |
$all_tiles = array(); | |
///// get all the tiles | |
// loop zoomlevels | |
foreach ($zoomlevels as $key => $z) { | |
// get topleft tile number | |
$topleft_x = get_tile_x($west, $z)-1; // lon | |
$topleft_y = get_tile_y($north, $z)-1; // lat | |
// get bottomright tile number | |
$bottomleft_x = get_tile_x($east, $z)+1; // lon | |
$bottomleft_y = get_tile_y($south, $z)+1; // lat | |
// loop x-axis | |
for ($x=$topleft_x; $x <= $bottomleft_x; $x++) { | |
// loop y-axis | |
for ($y=$topleft_y; $y <= $bottomleft_y; $y++) { | |
$new_url = preg_replace('/\{z\}/', $z, $tileserver); | |
$new_url = preg_replace('/\{x\}/', $x, $new_url); | |
$new_url = preg_replace('/\{y\}/', $y, $new_url); | |
// define tile object | |
$the_tile = array('url' => $new_url, 'z' => $z, 'x' => $x, 'y' => $y); | |
array_push($all_tiles, $the_tile); | |
} | |
} | |
} | |
_log("Downloading " . count($all_tiles) . " Tiles..."); | |
//// DOWNLOAD FILES | |
// loop all files | |
$file_downloaded_counter = 0; | |
$file_skipped_counter = 0; | |
foreach($all_tiles as $tile) { | |
$tile_url = trim($tile['url']); | |
$filename = $tile['y'] . ".png"; | |
// check if directory exists -> otherwise create it | |
$destination_dir = $output_dir . "/" . $tile['z'] . "/" . $tile['x']; | |
if(!file_exists($destination_dir)) mkdir($destination_dir, 0777, true); | |
$destination_file = $destination_dir . "/" . $filename; | |
// download the file | |
if(!$dry_run) { | |
// define if file should be downloaded (config->skip_existing_files) | |
$download_file = true; | |
if($skip_existing_files && file_exists($destination_file)) $download_file = false; | |
if($download_file) { | |
$img = file_get_contents($tile_url); | |
$fp = fopen($destination_file, 'w'); | |
fwrite($fp, $img); | |
fclose($fp); | |
$file_downloaded_counter++; | |
} | |
else $file_skipped_counter++; | |
} | |
else { | |
// dry run | |
_log($file_downloaded_counter . ": " . $tile_url); | |
$file_downloaded_counter++; | |
} | |
} | |
_log("<b>Done</b>. " . $file_downloaded_counter . " Tiles have been downloaded. (" . $file_skipped_counter . " tiles skipped – already existed.)"); | |
// --- HELPER FUNCTIONS --- // | |
/** | |
* Simple Log Output | |
* | |
* @param string $log_text The text to output | |
*/ | |
function _log($log_text) { | |
echo $log_text . "<br/>"; | |
} | |
/** | |
* Get the x value for a tile at a certain longitude at a certain zoomlevel | |
* | |
* @param number $lon The longitude | |
* @param number $zoom The zoomlevel | |
* | |
* @return number | |
*/ | |
function get_tile_x($lon, $zoom) { | |
$xtile = floor((($lon + 180) / 360) * pow(2, $zoom)); | |
return $xtile; | |
} | |
/** | |
* Get the y value for a tile at a certain latitude at a certain zoomlevel | |
* | |
* @param number $lat The latitude | |
* @param number $zoom The zoomlevel | |
* | |
* @return number | |
*/ | |
function get_tile_y($lat, $zoom) { | |
$ytile = floor((1 - log(tan(deg2rad($lat)) + 1 / cos(deg2rad($lat))) / pi()) /2 * pow(2, $zoom)); | |
return $ytile; | |
} | |
/** | |
* Remove a directory recursively | |
* (from php.net) | |
* | |
* @param string $dir The directory path | |
* | |
* @return bool | |
*/ | |
function delTree($dir) { | |
$files = array_diff(scandir($dir), array('.','..')); | |
foreach ($files as $file) { | |
(is_dir($dir.'/'.$file)) ? delTree($dir.'/'.$file) : unlink($dir.'/'.$file); | |
} | |
return rmdir($dir); | |
} | |
?> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment