2022-12-18 23:58:37 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
// !!! SET YOUR SQL-CONNECTION SETTINGS HERE: !!!
|
|
|
|
|
2023-11-20 19:40:47 +08:00
|
|
|
$driver = 'mysql'; // 'mysql' (MySQL) or 'pgsql' (PostgreSQL)
|
2022-12-23 05:34:28 +08:00
|
|
|
$hostname = '127.0.0.1';
|
2022-12-18 23:58:37 +08:00
|
|
|
$port = 3306;
|
2022-12-23 05:34:28 +08:00
|
|
|
$username = 'root';
|
|
|
|
$password = '';
|
|
|
|
$database = 'bluemap';
|
2022-12-18 23:58:37 +08:00
|
|
|
|
|
|
|
// !!! END - DONT CHANGE ANYTHING AFTER THIS LINE !!!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-05-07 22:45:24 +08:00
|
|
|
// compression
|
|
|
|
$compressionHeaderMap = [
|
|
|
|
"bluemap:none" => null,
|
|
|
|
"bluemap:gzip" => "gzip",
|
|
|
|
"bluemap:deflate" => "deflate",
|
|
|
|
"bluemap:zstd" => "zstd",
|
|
|
|
"bluemap:lz4" => "lz4"
|
2024-06-04 06:14:34 +08:00
|
|
|
];
|
2022-12-18 23:58:37 +08:00
|
|
|
|
2024-05-07 22:45:24 +08:00
|
|
|
// meta files
|
|
|
|
$metaFileKeys = [
|
|
|
|
"settings.json" => "bluemap:settings",
|
|
|
|
"textures.json" => "bluemap:textures",
|
|
|
|
"live/markers.json" => "bluemap:markers",
|
|
|
|
"live/players.json" => "bluemap:players",
|
2024-06-04 06:14:34 +08:00
|
|
|
];
|
2022-12-18 23:58:37 +08:00
|
|
|
|
|
|
|
// mime-types for meta-files
|
|
|
|
$mimeDefault = "application/octet-stream";
|
|
|
|
$mimeTypes = [
|
|
|
|
"txt" => "text/plain",
|
|
|
|
"css" => "text/css",
|
|
|
|
"csv" => "text/csv",
|
|
|
|
"htm" => "text/html",
|
|
|
|
"html" => "text/html",
|
|
|
|
"js" => "text/javascript",
|
|
|
|
"xml" => "text/xml",
|
|
|
|
|
|
|
|
"png" => "image/png",
|
|
|
|
"jpg" => "image/jpeg",
|
|
|
|
"jpeg" => "image/jpeg",
|
|
|
|
"gif" => "image/gif",
|
|
|
|
"webp" => "image/webp",
|
|
|
|
"tif" => "image/tiff",
|
|
|
|
"tiff" => "image/tiff",
|
|
|
|
"svg" => "image/svg+xml",
|
|
|
|
|
|
|
|
"json" => "application/json",
|
|
|
|
|
|
|
|
"mp3" => "audio/mpeg",
|
|
|
|
"oga" => "audio/ogg",
|
|
|
|
"wav" => "audio/wav",
|
|
|
|
"weba" => "audio/webm",
|
|
|
|
|
|
|
|
"mp4" => "video/mp4",
|
|
|
|
"mpeg" => "video/mpeg",
|
|
|
|
"webm" => "video/webm",
|
|
|
|
|
|
|
|
"ttf" => "font/ttf",
|
|
|
|
"woff" => "font/woff",
|
|
|
|
"woff2" => "font/woff2"
|
|
|
|
];
|
|
|
|
|
2024-05-07 22:45:24 +08:00
|
|
|
// some helper functions
|
|
|
|
function error($code, $message = null) {
|
|
|
|
global $path;
|
|
|
|
|
|
|
|
http_response_code($code);
|
|
|
|
header("Content-Type: text/plain");
|
|
|
|
echo "BlueMap php-script - $code\n";
|
|
|
|
if ($message != null) echo $message."\n";
|
|
|
|
echo "Requested Path: $path";
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
function startsWith($haystack, $needle) {
|
|
|
|
return substr($haystack, 0, strlen($needle)) === $needle;
|
|
|
|
}
|
|
|
|
|
|
|
|
function issetOrElse(& $var, $fallback) {
|
|
|
|
return isset($var) ? $var : $fallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
function compressionHeader($compressionKey) {
|
|
|
|
global $compressionHeaderMap;
|
|
|
|
|
|
|
|
$compressionHeader = issetOrElse($compressionHeaderMap[$compressionKey], null);
|
|
|
|
if ($compressionHeader)
|
|
|
|
header("Content-Encoding: ".$compressionHeader);
|
|
|
|
}
|
|
|
|
|
2022-12-18 23:58:37 +08:00
|
|
|
function getMimeType($path) {
|
|
|
|
global $mimeDefault, $mimeTypes;
|
|
|
|
|
|
|
|
$i = strrpos($path, ".");
|
|
|
|
if ($i === false) return $mimeDefault;
|
|
|
|
|
|
|
|
$s = strrpos($path, "/");
|
|
|
|
if ($s !== false && $i < $s) return $mimeDefault;
|
|
|
|
|
|
|
|
$suffix = substr($path, $i + 1);
|
|
|
|
if (isset($mimeTypes[$suffix]))
|
|
|
|
return $mimeTypes[$suffix];
|
|
|
|
|
|
|
|
return $mimeDefault;
|
|
|
|
}
|
|
|
|
|
2023-11-20 19:40:47 +08:00
|
|
|
function send($data) {
|
|
|
|
if (is_resource($data)) {
|
|
|
|
fpassthru($data);
|
|
|
|
} else {
|
|
|
|
echo $data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-18 23:58:37 +08:00
|
|
|
// determine relative request-path
|
|
|
|
$root = dirname($_SERVER['PHP_SELF']);
|
|
|
|
if ($root === "/" || $root === "\\") $root = "";
|
|
|
|
$uriPath = $_SERVER['REQUEST_URI'];
|
|
|
|
$path = substr($uriPath, strlen($root));
|
|
|
|
|
2024-06-04 06:14:34 +08:00
|
|
|
// add /
|
2022-12-18 23:58:37 +08:00
|
|
|
if ($path === "") {
|
|
|
|
header("Location: $uriPath/");
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// root => index.html
|
|
|
|
if ($path === "/") {
|
|
|
|
header("Content-Type: text/html");
|
|
|
|
echo file_get_contents("index.html");
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (startsWith($path, "/maps/")) {
|
|
|
|
|
|
|
|
// determine map-path
|
|
|
|
$pathParts = explode("/", substr($path, strlen("/maps/")), 2);
|
|
|
|
$mapId = $pathParts[0];
|
2023-01-01 19:23:47 +08:00
|
|
|
$mapPath = explode("?", $pathParts[1], 2)[0];
|
2022-12-18 23:58:37 +08:00
|
|
|
|
2023-11-20 19:40:47 +08:00
|
|
|
// Initialize PDO
|
|
|
|
try {
|
2024-05-07 22:45:24 +08:00
|
|
|
$sql = new PDO("$driver:host=$hostname;port=$port;dbname=$database", $username, $password);
|
2023-11-20 19:40:47 +08:00
|
|
|
$sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
2024-08-14 11:30:50 +08:00
|
|
|
} catch (PDOException $e ) {
|
2024-08-19 00:29:33 +08:00
|
|
|
error_log($e->getMessage(), 0); // Logs the detailed error message
|
|
|
|
error(500, "Failed to connect to database");
|
2024-08-14 11:30:50 +08:00
|
|
|
}
|
2023-11-20 19:40:47 +08:00
|
|
|
|
2022-12-18 23:58:37 +08:00
|
|
|
// provide map-tiles
|
|
|
|
if (startsWith($mapPath, "tiles/")) {
|
|
|
|
|
|
|
|
// parse tile-coordinates
|
|
|
|
preg_match_all("/tiles\/([\d\/]+)\/x(-?[\d\/]+)z(-?[\d\/]+).*/", $mapPath, $matches);
|
|
|
|
$lod = intval($matches[1][0]);
|
2024-06-04 06:14:34 +08:00
|
|
|
$storage = $lod === 0 ? "bluemap:hires" : "bluemap:lowres/".$lod;
|
2022-12-18 23:58:37 +08:00
|
|
|
$tileX = intval(str_replace("/", "", $matches[2][0]));
|
|
|
|
$tileZ = intval(str_replace("/", "", $matches[3][0]));
|
|
|
|
|
|
|
|
// query for tile
|
2023-11-20 19:40:47 +08:00
|
|
|
try {
|
|
|
|
$statement = $sql->prepare("
|
2024-06-04 06:14:34 +08:00
|
|
|
SELECT d.data, c.key
|
2024-05-07 22:45:24 +08:00
|
|
|
FROM bluemap_grid_storage_data d
|
2023-11-20 19:40:47 +08:00
|
|
|
INNER JOIN bluemap_map m
|
2024-05-07 22:45:24 +08:00
|
|
|
ON d.map = m.id
|
|
|
|
INNER JOIN bluemap_grid_storage s
|
|
|
|
ON d.storage = s.id
|
|
|
|
INNER JOIN bluemap_compression c
|
|
|
|
ON d.compression = c.id
|
2023-11-20 19:40:47 +08:00
|
|
|
WHERE m.map_id = :map_id
|
2024-05-07 22:45:24 +08:00
|
|
|
AND s.key = :storage
|
|
|
|
AND d.x = :x
|
|
|
|
AND d.z = :z
|
2023-11-20 19:40:47 +08:00
|
|
|
");
|
|
|
|
$statement->bindParam( ':map_id', $mapId, PDO::PARAM_STR );
|
2024-05-07 22:45:24 +08:00
|
|
|
$statement->bindParam( ':storage', $storage, PDO::PARAM_STR );
|
2023-11-20 19:40:47 +08:00
|
|
|
$statement->bindParam( ':x', $tileX, PDO::PARAM_INT );
|
|
|
|
$statement->bindParam( ':z', $tileZ, PDO::PARAM_INT );
|
|
|
|
$statement->setFetchMode(PDO::FETCH_ASSOC);
|
|
|
|
$statement->execute();
|
|
|
|
|
|
|
|
// return result
|
|
|
|
if ($line = $statement->fetch()) {
|
2024-02-25 09:19:40 +08:00
|
|
|
header("Cache-Control: public,max-age=86400");
|
2024-06-04 06:24:10 +08:00
|
|
|
compressionHeader($line["key"]);
|
2024-02-25 09:19:40 +08:00
|
|
|
|
2023-11-20 19:40:47 +08:00
|
|
|
if ($lod === 0) {
|
2024-02-24 17:44:25 +08:00
|
|
|
header("Content-Type: application/octet-stream");
|
2023-11-20 19:40:47 +08:00
|
|
|
} else {
|
|
|
|
header("Content-Type: image/png");
|
|
|
|
}
|
2024-05-07 22:45:24 +08:00
|
|
|
|
2023-11-20 19:40:47 +08:00
|
|
|
send($line["data"]);
|
|
|
|
exit;
|
2022-12-18 23:58:37 +08:00
|
|
|
}
|
|
|
|
|
2024-08-19 00:29:33 +08:00
|
|
|
} catch (PDOException $e) {
|
|
|
|
error_log($e->getMessage(), 0);
|
|
|
|
error(500, "Failed to fetch data");
|
|
|
|
}
|
2022-12-18 23:58:37 +08:00
|
|
|
|
2024-02-24 17:44:25 +08:00
|
|
|
// no content if nothing found
|
|
|
|
http_response_code(204);
|
2022-12-18 23:58:37 +08:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// provide meta-files
|
2024-05-07 22:45:24 +08:00
|
|
|
$storage = issetOrElse($metaFileKeys[$mapPath], null);
|
|
|
|
if ($storage === null && startsWith($mapPath, "assets/"))
|
|
|
|
$storage = "bluemap:asset/".substr($mapPath, strlen("assets/"));
|
|
|
|
|
|
|
|
if ($storage !== null) {
|
|
|
|
try {
|
|
|
|
$statement = $sql->prepare("
|
2024-06-04 06:14:34 +08:00
|
|
|
SELECT d.data, c.key
|
2024-05-07 22:45:24 +08:00
|
|
|
FROM bluemap_item_storage_data d
|
|
|
|
INNER JOIN bluemap_map m
|
|
|
|
ON d.map = m.id
|
|
|
|
INNER JOIN bluemap_item_storage s
|
|
|
|
ON d.storage = s.id
|
|
|
|
INNER JOIN bluemap_compression c
|
|
|
|
ON d.compression = c.id
|
|
|
|
WHERE m.map_id = :map_id
|
|
|
|
AND s.key = :storage
|
|
|
|
");
|
|
|
|
$statement->bindParam( ':map_id', $mapId, PDO::PARAM_STR );
|
|
|
|
$statement->bindParam( ':storage', $storage, PDO::PARAM_STR );
|
|
|
|
$statement->setFetchMode(PDO::FETCH_ASSOC);
|
|
|
|
$statement->execute();
|
|
|
|
|
|
|
|
if ($line = $statement->fetch()) {
|
|
|
|
header("Cache-Control: public,max-age=86400");
|
|
|
|
header("Content-Type: ".getMimeType($mapPath));
|
2024-06-04 06:24:10 +08:00
|
|
|
compressionHeader($line["key"]);
|
2024-05-07 22:45:24 +08:00
|
|
|
|
|
|
|
send($line["data"]);
|
|
|
|
exit;
|
|
|
|
}
|
2024-08-19 00:29:33 +08:00
|
|
|
} catch (PDOException $e) {
|
|
|
|
error_log($e->getMessage(), 0);
|
|
|
|
error(500, "Failed to fetch data");
|
|
|
|
}
|
2024-05-07 22:45:24 +08:00
|
|
|
}
|
2022-12-18 23:58:37 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// no match => 404
|
2024-02-24 17:44:25 +08:00
|
|
|
error(404);
|