| Server IP : 85.214.239.14 / Your IP : 216.73.216.27 Web Server : Apache/2.4.65 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 8.2.29 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/cwd/var/www/wordpress/wp-content/plugins/fictional-maps-handler/php/classes/ |
Upload File : |
<?php
/**
* @author Michael Herrmann
* @copyright 2020
*/
#require_once dirname(__FILE__).'/../bootstrap.php';
class MAP extends FM_CORE implements JsonSerializable {
private $id;
private $map_repository;
public $userid;
public $map_name;
private $map_width;
private $map_height;
private $tile_depth;
private $min_zoom;
private $max_zoom;
private $search;
private $fullscreen;
private $popout;
private $scalebar_toggle;
private $labels;
private $popup_background;
private $measuring;
private $map_units;
private $width_in_units;
private $protected;
private $password_hash;
private $origin;
private $description;
private $rating;
private $detail_maps;
private $claim_token;
private $timestamp;
/**Current use case:
* DO NOT USE THIS!
*
* USE MAP_DB_CONNECTOR::get_map()
*/
public function __construct(?MAP_REPOSITORY $mapRepository=null){
$this->map_repository=$mapRepository ?? new MAP_REPOSITORY();
}
/**
* Load user data from database
* @param int $userid
* @return self
*/
public function load_by_user_and_name($userid, $map_name){
$map_data=$this->map_repository->find_by_user_and_name($userid,$map_name);
if(!$map_data)throw new Exception("Map not found for User: $userid");
$this->id=$map_data['id'];
$this->userid=$map_data['userid'];
$this->map_name=$map_data['map_name'];
$this->map_width=$map_data['map_width'];
$this->map_height=$map_data['map_height'];
$this->tile_depth=$map_data['tile_depth'];
$this->min_zoom=$map_data['min_zoom'];
$this->max_zoom=$map_data['max_zoom'];
$this->search=$map_data['search'];
$this->fullscreen=$map_data['fullscreen'];
$this->popout=$map_data['popout'];
$this->scalebar_toggle=$map_data['scalebar_toggle'];
$this->labels=$map_data['labels'];
$this->popup_background=$map_data['popup_background'];
$this->measuring=$map_data['measuring'];
$this->map_units=$map_data['map_units'];
$this->width_in_units=$map_data['width_in_units'];
$this->protected=$map_data['protected'];
$this->password_hash=$map_data['password_hash'];
$this->origin=$map_data['origin'];
$this->description=$map_data['description'];
$this->rating=$this->map_repository->get_ratings($this->id);
if(isset($map_data['detail_maps']))$this->detail_maps=$map_data['detail_maps'];
return $this;
}
/**
* MAP::was_rated_by()
* check if map was already rated by a certain IP address
* @param string $ip_address
* @return bool
*/
public function was_rated_by($ip_address){
$rating_array = $this->get_rating(); //get the array of rating objects
$was_rated = false; //create the return variable
foreach($rating_array as $rating){ //iterate through the array of RATING objects for this map
if ($rating->get_rater_ip() == $ip_address){ //check if one has the given IP as rater_ip class variable
$was_rated = true; //if yes, set the return value to true
}
}
return $was_rated;
}
/**
* MAP::get_rating_from_ip()
* check if map was already rated by a certain IP address
* @param string $ip_address
* @return int rating
*/
public function get_rating_from_ip($ip_address){
$rating_array = $this->get_rating(); //get the array of rating objects
$ip_rated = null; //create the return variable
foreach($rating_array as $rating){ //iterate through the array of RATING objects for this map
if ($rating->get_rater_ip() == $ip_address){ //check if one has the given IP as rater_ip class variable
$ip_rated = $rating->get_rating(); //if yes, set the return value to the rating corresponding to the ip in the db table fm.map_ratings
}
}
return $ip_rated;
}
/**
* MAP::get_average_rating()
* check if map was already rated by a certain IP address
* @return float rating
*/
public function get_average_rating(){
if (!empty($this->rating)){ //check if there even are any ratings
$total = 0;
foreach($this->rating as $rating){
$total = $total + $rating->get_rating(); //add up all ratings
}
$average = $total/sizeOf($this->rating); //divide total through number of ratings to get the average
return $average;
}
else {
return '0';
}
}
/**
* MAP::get_fancy_average_rating()
* uses Lower bound of Wilson score confidence interval for a Bernoulli parameter (0.9604)
*
* CURRENTLY NOT IN USE - ONLY WORKS WELL WITH MANY MANY VOTES (100+)
*
* See:
* http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
* https://gist.github.com/julienbourdeau/77eaca0fd1e4af3fde9fe018fdf13d7d
* @return float rating
*/
public function get_fancy_average_rating(){
$star1 = 0; //first we create empty variables as input for our
$star2 = 0;
$star3 = 0;
$star4 = 0;
$star5 = 0;
if (!empty($this->rating)){ //check if there even are any ratings
foreach($this->rating as $rating){ //iterate through the array of RATING objects for this map
switch ($rating->get_rating()){
case 1:
$star1++;
break;
case 2:
$star2++;
break;
case 3:
$star3++;
break;
case 4:
$star4++;
break;
case 5:
$star5++;
break;
}
}
return $this->fiveStarRating($star1,$star2, $star3, $star4, $star5); //TODO cast range 0-1 to 1-5
}
else {
return '0';
}
}
/**
* HELPER FUNCTIONS FOR THE FANCY AVERAGE RATING
*/
private function score($positive, $negative) {
return ((($positive + 1.9208) / ($positive + $negative) - 1.96 * sqrt((($positive * $negative) / ($positive + $negative)) + 0.9604) / ($positive + $negative)) / (1 + 3.8416 / ($positive + $negative)));
}
private function fiveStarRating($one, $two, $three, $four, $five) {
$positive = $two * 0.25 + $three * 0.5 + $four * 0.75 + $five;
$negative = $one + $two * 0.75 + $three * 0.5 + $four * 0.25;
return $this->score($positive, $negative);
}
/**
* MAP::longest_side_value()
* returns the longest side value AFTER resizing for tiles
* @return int pixelcount
*/
public function longest_side_value(){
//find out which side is longest first
$longest_side;
if ($this->map_width >= $this->map_height){
$longest_side = $this->map_width;
}
else {
$longest_side = $this->map_height;
}
//as everything above 1024 gets resized to the next power of two, return that
if ($longest_side > 32768){
return 65.536;
}
elseif($longest_side > 16384){
return 32768;
}
elseif($longest_side > 8192){
return 16384;
}
elseif($longest_side > 4096){
return 8192;
}
elseif($longest_side > 2048){
return 4096;
}
elseif($longest_side > 1024){
return 2048;
}
else {
return $longest_side;
}
}
/**
* MAP::jsonSerialize()
* override the function from JsonSerializable to be able to use json_encode and get the private variables
* @return json object vars
*/
public function jsonSerialize(): mixed{
return get_object_vars($this);
}
/**
* MAP::prepare_for_download()
* builds a zip file including a html file with all necessary styles and site and the accompagnying image files
* ZIP is saved to the usermaps/map_name folder
*
*/
public function prepare_for_download(){
#echo "prepare for download<br />";
//first define paths to all the content we need
$map_dir = dirname(__FILE__) . "/../../usermaps/".$this->userid."/".$this->map_name;
$img_dir = dirname(__FILE__) . "/../../img";
//build the content of the main file
$html_string = '<!DOCTYPE html><html><head><title>'.$this->map_name.' - provided by fictionalmaps.com</title><meta charset="utf-8" /><style>'; //start of file, now add the styles
$html_string .= file_get_contents(__DIR__.'/../../css/leaflet/leaflet.min.css');
$html_string .= file_get_contents(__DIR__.'/../../css/leaflet/leaflet-search.min.css');
$html_string .= file_get_contents(__DIR__.'/../../css/leaflet/leaflet.fullscreen.min.css');
$html_string .= file_get_contents(__DIR__.'/../../css/leaflet/leaflet.measure.min.css');
$html_string .= file_get_contents(__DIR__.'/../../css/leaflet/leaflet.responsive.popup.min.css');
$html_string .= file_get_contents(__DIR__.'/../../css/fm/dungeonmasterresources.min.css');
$html_string .= 'html, body {height: 100%;margin: 0;} #map {width: 1024px;height: 1024px;}</style></head><body><div id="map"></div>'; //transition to body, added map div and now for the site
$html_string .= '<script src="https://kit.fontawesome.com/d3437d5a3a.js" crossorigin="anonymous"></script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/lib/jquery-3.5.1.min.js').'</script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/leaflet/leaflet.js').'</script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/leaflet/leaflet-search.min.js').'</script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/leaflet/leaflet.fullscreen.min.js').'</script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/leaflet/leaflet.measure.min.js').'</script>';
$html_string .= '<script>'. file_get_contents(__DIR__.'/../../js/leaflet/leaflet.responsive.popup.min.js').'</script>';
$initial_map_string = '<script>'. file_get_contents(__DIR__.'/../../js/fm/fm.audience_map_dl.min.js').'</script>'; //now we load our adapted fm_audience_map to insert the values
$placeholder = array("PH_MAPNAME", "PH_WIDTH", "PH_HEIGHT", "PH_TILEDEPTH", "PH_MINZOOM", "PH_MAXZOOM", "PH_SEARCH", "PH_FULLSCREEN", "PH_SCALEBARTOGGLE", "PH_LABELS", "PH_POPUPBACKGROUND", "PH_MEASURING", "PH_MAPUNITS", "PH_WINUNITS", "PH_DETAILMAPS", "PH_MARKERS"); //array with all the placeholders we want to replace
if ($this->tile_depth > 2){ //once again, to determine wether it got tiled or not
$width = $this->longest_side_value(); //and thus to set width and height accordingly
$height = $this->longest_side_value();
} else {
$width = $this->map_width;
$height = $this->map_height;
}
$marker_json_string = file_get_contents(__DIR__."/../../usermaps/".$this->userid."/".$this->map_name."/communities.geojson"); //load the geojson with the markers to include right in the file
$detail_maps_string = json_encode($this->detail_maps); //create string for detail map json objects
$values = array($this->map_name, $width, $height, $this->tile_depth, $this->min_zoom, $this->max_zoom, $this->search, $this->fullscreen, $this->scalebar_toggle, $this->labels, $this->popup_background, $this->measuring, $this->map_units, $this->width_in_units, $detail_maps_string, $marker_json_string); //array with all the values to insert
$final_map_string = str_replace($placeholder, $values, $initial_map_string); //replace all the placeholders with values from the array
$html_string .= $final_map_string; //add the audience map string now with hardcoded values to the overall string
$html_string .= '</body></html>';
//now create a zip and add all the necessary content
#echo "create zip archive<br />";
$zip = new ZipArchive();
if($zip->open($map_dir."/".$this->map_name."_offline.zip", ZipArchive::CREATE) === TRUE){
$zip->addFile($img_dir."/error_tile.png","img/error_tile.png");
$zip->addFromString($this->map_name."_offline.html", $html_string); //add the html content we built above as html file to the zip
$zip->addFile($map_dir."/".$this->map_name.".png", $this->map_name.".png");
//add the icons
foreach(glob($img_dir.'/symbols/*.*') as $filename){
if (substr(basename($filename), 0, 7) === "Map_Pin")$zip->addFile($filename, "img/symbols/".basename($filename));
}
#echo $map_dir."/detail-maps";
if(file_exists($map_dir."/detail-maps"))$this->addDir($zip,$map_dir."/detail-maps","detail-maps");
if(file_exists($map_dir."/tiles"))$this->addDir($zip,$map_dir."/tiles","tiles");
// All files are added, so close the zip file.
$zip->close();
}
//return path to zip archive
return $map_dir."/".$this->map_name."_offline.zip";
}
/*
* ./dir1/.
* /..
* /.hidden.file
* /image1.png
* /zoom1/.
* /..
* /image2.png
*
* $dir = <path to image dir>
*
*/
private function addDir($zipArchive,$dir,$zipdir='.') {
if(is_dir($dir)){
#echo "check $dir ...<br />";
if($dh=opendir($dir)){
//Add the directory
if(!empty($zipdir))$zipArchive->addEmptyDir($zipdir);
//Loop through all the files
while(($file=readdir($dh))!==false){
//If it's a folder, run the function again!
if(substr($file,0,1)==".")continue;
if(!is_file($dir."/".$file)){
//recursive call next dir
$this->addDir($zipArchive,$dir."/".$file,$zipdir."/".$file);
}else{
// Add the files
#echo "add file $dir/$file to $zipdir/$file<br />";
$zipArchive->addFile($dir."/".$file,$zipdir."/".$file);
}
}
}
}
}
/**
* @param mixed $userid
* @return MAP
*/
public function set_userid($userid){
$this->userid=$userid;
return $this;
}
/**
* @param mixed $map_name
* @return MAP
*/
public function set_map_name($map_name){
$this->map_name=$map_name;
return $this;
}
/**
* @param mixed $map_width
* @return MAP
*/
public function setMapWidth($map_width){
$this->map_width=$map_width;
return $this;
}
/**
* @param mixed $map_height
* @return MAP
*/
public function setMapHeight($map_height){
$this->map_height=$map_height;
return $this;
}
/**
* @param mixed $tile_depth
* @return MAP
*/
public function setTileDepth($tile_depth){
$this->tile_depth=$tile_depth;
return $this;
}
/**
* @param mixed $min_zoom
* @return MAP
*/
public function setMinZoom($min_zoom){
$this->min_zoom=$min_zoom;
return $this;
}
/**
* @param mixed $max_zoom
* @return MAP
*/
public function setMaxZoom($max_zoom){
$this->max_zoom=$max_zoom;
return $this;
}
/**
* @param mixed $fullscreen
* @return MAP
*/
public function setFullscreen($fullscreen){
$this->fullscreen=$fullscreen;
return $this;
}
/**
* @param mixed $popout
* @return MAP
*/
public function setPopout($popout){
$this->popout=$popout;
return $this;
}
/**
* @param mixed $scalebar_toggle
* @return MAP
*/
public function setScalebarToggle($scalebar_toggle){
$this->scalebar_toggle=$scalebar_toggle;
return $this;
}
/**
* @param mixed $labels
* @return MAP
*/
public function setLabels($labels){
$this->labels=$labels;
return $this;
}
/**
* @param mixed $popup_background
* @return MAP
*/
public function setPopupBackground($popup_background){
$this->popup_background=$popup_background;
return $this;
}
/**
* @param mixed $measuring
* @return MAP
*/
public function setMeasuring($measuring){
$this->measuring=$measuring;
return $this;
}
/**
* @param mixed $map_units
* @return MAP
*/
public function setMapUnits($map_units){
$this->map_units=$map_units;
return $this;
}
/**
* @param mixed $width_in_units
* @return MAP
*/
public function setWidthInUnits($width_in_units){
$this->width_in_units=$width_in_units;
return $this;
}
/**
* @param mixed $password_hash
* @return MAP
*/
public function set_password_hash($password_hash){
$this->password_hash=$password_hash;
return $this;
}
/**
* @param mixed $origin
* @return MAP
*/
public function set_origin($origin){
$this->origin=$origin;
return $this;
}
/**
* @param mixed $description
* @return MAP
*/
public function set_description($description){
$this->description=$description;
return $this;
}
/**
* =========================================================================
* GETTER & SETTER *
* =========================================================================
*/
public function get_id(){
return $this->id;
}
/**
* @param mixed $id
* @return MAP
*/
public function set_id($id){
$this->id=$id;
return $this;
}
public function get_userid(){
return $this->userid;
}
public function get_map_name(){
return $this->map_name;
}
public function get_map_width(){
return $this->map_width;
}
public function set_map_width($map_width){
$this->map_width=$map_width;
return $this;
}
public function get_map_height(){
return $this->map_height;
}
public function set_map_height($map_height){
$this->map_height=$map_height;
return $this;
}
public function get_tile_depth(){
return $this->tile_depth;
}
public function set_tile_depth($tile_depth){
$this->tile_depth=$tile_depth;
return $this;
}
public function get_min_zoom(){
return $this->min_zoom;
}
public function set_min_zoom($min_zoom){
$this->min_zoom=$min_zoom;
return $this;
}
public function get_max_zoom(){
return $this->max_zoom;
}
public function set_max_zoom($max_zoom){
$this->max_zoom=$max_zoom;
return $this;
}
public function get_search(){
return $this->search;
}
public function set_search($search){
$this->search=$search;
return $this;
}
public function get_fullscreen(){
return $this->fullscreen;
}
public function set_fullscreen($fullscreen){
$this->fullscreen=$fullscreen;
return $this;
}
public function get_popout(){
return $this->popout;
}
public function set_popout($popout){
$this->popout=$popout;
return $this;
}
public function get_scalebar_toggle(){
return $this->scalebar_toggle;
}
public function set_scalebar_toggle($scalebar_toggle){
$this->scalebar_toggle=$scalebar_toggle;
return $this;
}
public function get_labels(){
return $this->labels;
}
public function set_labels($labels){
$this->labels=$labels;
return $this;
}
public function get_popup_background(){
return $this->popup_background;
}
public function set_popup_background($popup_background){
$this->popup_background=$popup_background;
return $this;
}
public function get_measuring(){
return $this->measuring;
}
public function set_measuring($measuring){
$this->measuring=$measuring;
return $this;
}
public function get_map_units(){
return $this->map_units;
}
public function set_map_units($map_units){
$this->map_units=$map_units;
return $this;
}
public function get_width_in_units(){
return $this->width_in_units;
}
public function set_width_in_units($width_in_units){
$this->width_in_units=$width_in_units;
return $this;
}
public function get_protected(){
return $this->protected;
}
public function set_protected($protected){
$this->protected = $protected;
}
public function get_password_hash(){
return $this->password_hash;
}
/**
* @return mixed
*/
public function get_claim_token(){
return $this->claim_token;
}
/**
* @param mixed $claim_token
* @return MAP
*/
public function set_claim_token($claim_token){
$this->claim_token=$claim_token;
return $this;
}
public function get_timestamp(){
return $this->timestamp;
}
/**
* @param mixed $timestamp
* @return MAP
*/
public function set_timestamp($timestamp){
$this->timestamp=$timestamp;
return $this;
}
/**
* MAP::get_origin()
* this actually does something ;-)
* establishes a db connection and gets the map origin from the fm_map_origins table
* @return array associated array with id, origin, origin_url
*/
public function get_origin(){
$map_db_connector = new MAP_DB_CONNECTOR(); //establish db connection
$stmt = $map_db_connector->conn->prepare("SELECT * FROM fm_map_origins WHERE id = :id");
$sql_values = [ //set the array of values to hand over to the prepared sql statement
'id' => $this->origin, //in the origin field of the map table, only the id of the corresponding row of the origins table is stored
]; //we use it here to get all the information about origin site or software
$stmt->execute($sql_values); //execute the query
return $stmt->fetch(PDO::FETCH_ASSOC); //return the row as array like [origin] => user ; [origin_url] => https://fictionalmaps.com/
}
public function get_rating(){
return $this->rating;
}
public function set_rating($rating){
$this->rating = $rating;
}
public function get_detail_maps(){
return $this->detail_maps;
}
/**
* MAP::set_detail_maps()
* this actually does something ;-)
* gets all the detail maps from the fm_detail_maps table and add them to $this->detail_maps
* @param object $conn - PDO database connection
*/
public function set_detail_maps($conn){
//prepare the statement
$stmt = $conn->prepare("SELECT * FROM fm_detail_maps WHERE map_id = :map_id");
//execute the statement
$sql_values = [ //set the array of values to hand over to the prepared sql statement
'map_id' => $this->id, //get all details maps where the map_id matches the id of this map
];
$stmt->execute($sql_values);
$this->detail_maps = $stmt->fetchAll(PDO::FETCH_CLASS, 'DETAIL_MAP');
}
/**
* MAP::add_description
* adds a database entry for the description
* @param object $conn - PDO connection
* @param string $description
*/
public function add_description($conn, $description){
$stmt = $conn->prepare("UPDATE fm_maps SET description = :description WHERE id = :map_id");
$sql_values = [ //set the array of values to hand over to the prepared sql statement
'map_id' => $this->id,
'description' => $description,
];
$stmt->execute($sql_values);
}
public function get_description(){
return $this->description;
}
/**
* MAP::get_tags()
* return all tags attributed to this map
* statement grabbed here: http://lekkerlogic.com/2016/02/site-tags-using-mysql-many-to-many-tags-schema-database-design/
* @param object $conn - PDO connection
*/
public function get_tags($conn) {
$stmt = $conn->prepare("SELECT t.tag FROM fm_tags t INNER JOIN fm_map_tags mt on t.id = mt.tag_id INNER JOIN fm_maps m on mt.map_id = m.id WHERE m.id = :map_id");
$sql_values = [ //set the array of values to hand over to the prepared sql statement
'map_id' => $this->id,
];
$stmt->execute($sql_values);
$tags = $stmt->fetchAll();
return $tags;
}
}