Skip to content

Instantly share code, notes, and snippets.

@mgrubinger
Last active July 30, 2021 22:30
Show Gist options
  • Save mgrubinger/4671d505db9a12184ed4989dbd9e4763 to your computer and use it in GitHub Desktop.
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!
<!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