', '`', '\'', '"', '|', '+', '[', ']', '{', '}', ';', '!', '%'); static $drop_char_replace = array('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''); return str_replace($drop_char_match, $drop_char_replace, urldecode($str)); } // much looser sanitise for general strings that shouldn't have HTML in them function wm_editor_sanitize_string($str) { static $drop_char_match = array('<', '>' ); static $drop_char_replace = array('', ''); return str_replace($drop_char_match, $drop_char_replace, urldecode($str)); } function wm_editor_validate_bandwidth($bw) { if(preg_match( '/^(\d+\.?\d*[KMGT]?)$/', $bw) ) { return true; } return false; } function wm_editor_validate_one_of($input,$valid=array(),$case_sensitive=false) { if(! $case_sensitive ) $input = strtolower($input); foreach ($valid as $v) { if(! $case_sensitive ) $v = strtolower($v); if($v == $input) return true; } return false; } // Labels for Nodes, Links and Scales shouldn't have spaces in function wm_editor_sanitize_name($str) { return str_replace( array(" "), "", $str); } function wm_editor_sanitize_selected($str) { $res = urldecode($str); if( ! preg_match("/^(LINK|NODE):/",$res)) { return ""; } return wm_editor_sanitize_name($res); } function wm_editor_sanitize_file($filename,$allowed_exts=array()) { $filename = wm_editor_sanitize_uri($filename); if ($filename == "") return ""; $ok = false; foreach ($allowed_exts as $ext) { $match = ".".$ext; if( substr($filename, -strlen($match),strlen($match)) == $match) { $ok = true; } } if(! $ok ) return ""; return $filename; } function wm_editor_sanitize_conffile($filename) { $filename = wm_editor_sanitize_uri($filename); # If we've been fed something other than a .conf filename, just pretend it didn't happen if ( substr($filename,-5,5) != ".conf" ) { $filename = ""; } # on top of the url stuff, we don't ever need to see a / in a config filename (CVE-2013-3739) if (strstr($filename,"/") !== false ) { $filename = ""; } return $filename; } function show_editor_startpage() { global $mapdir, $WEATHERMAP_VERSION, $config_loaded, $cacti_found, $ignore_cacti,$configerror; $fromplug = false; if (isset($_REQUEST['plug']) && (intval($_REQUEST['plug'])==1) ) { $fromplug = true; } $matches=0; $errormessage = ""; if ($configerror!='') { $errormessage .= $configerror.'

'; } if ( !$observium_found && !$ignore_observium) { //$errormessage .= '$cacti_base is not set correctly. Cacti integration will be disabled in the editor.'; //$errormessage .= "$observium_found and $ignore_observium"; //if ($config_loaded != 1) { //$errormessage .= " You might need to copy editor-config.php-dist to editor-config.php and edit it."; //} } if ($errormessage != '') { print '

'.htmlspecialchars($errormessage).'
'; } print '
'; print '
Weathermap Editor
'; // print 'Welcome to the PHP Weathermap '.$WEATHERMAP_VERSION.' editor.'; // print '

NOTE: This editor is not finished! There are many features of '; // print 'Weathermap that you will be missing out on if you choose to use the editor only.'; // print 'These include: curves, node offsets, font definitions, colour changing, per-node/per-link settings and image uploading. You CAN use the editor without damaging these features if you added them by hand, however.

'; // print 'Do you want to:

'; print '

Create A New Map

'; print '
'; print 'Named: '; print ''; print ''; print ''; print '

Note: filenames must contain no spaces and end in .conf

'; print '
'; $titles = array(); $errorstring=""; if (is_dir($mapdir)) { $n=0; $dh=opendir($mapdir); if ($dh) { while (false !== ($file = readdir($dh))) { $realfile=$mapdir . DIRECTORY_SEPARATOR . $file; $note = ""; // skip directories, unreadable files, .files and anything that doesn't come through the sanitiser unchanged if ( (is_file($realfile)) && (is_readable($realfile)) && (!preg_match("/^\./",$file) ) && ( wm_editor_sanitize_conffile($file) == $file ) ) { if (!is_writable($realfile)) { $note .= "(read-only)"; } $title='(no title)'; $fd=fopen($realfile, "r"); if ($fd) { while (!feof($fd)) { $buffer=fgets($fd, 4096); if (preg_match('/^\s*TITLE\s+(.*)/i', $buffer, $matches)) { $title= wm_editor_sanitize_string($matches[1]); } } fclose ($fd); $titles[$file] = $title; $notes[$file] = $note; $n++; } } } closedir ($dh); } else { $errorstring = "Can't open mapdir to read."; } ksort($titles); if ($n == 0) { $errorstring = "No files in mapdir"; } } else { $errorstring = "NO DIRECTORY named $mapdir"; } print '

Duplicate An Existing Map

'; print '
'; print 'Named: based on '; print ''; print ''; print ''; print ''; print '
'; print '

Open An Existing Map

    '; if ($errorstring == '') { foreach ($titles as $file=>$title) { # $title = $titles[$file]; $note = $notes[$file]; $nicefile = htmlspecialchars($file); $nicetitle = htmlspecialchars($title); print '
  • '.$note.''.$nicefile.' - '.$nicetitle.'
  • '; } } else { print '
  • '.htmlspecialchars($errorstring).'
  • '; } print "
"; print "
"; // dlgbody print '
PHP Weathermap ' . $WEATHERMAP_VERSION . ' © 2005-2019 Howard Jones - howie@thingy.com
PHP Weathermap is licensed under the MIT License. This distribution also includes the Overlib library by Erik Bosrup. This version is modified for use with Observium.
'; print "
"; // dlgStart print "
"; // withjs print ""; } function snap($coord, $gridsnap = 0) { if ($gridsnap == 0) { return ($coord); } else { $rest = $coord % $gridsnap; return ($coord - $rest + round($rest/$gridsnap) * $gridsnap ); } } function extract_with_validation($array, $paramarray, $prefix = "") { $all_present=true; $candidates=array( ); foreach ($paramarray as $var) { $varname=$var[0]; $vartype=$var[1]; $varreqd=$var[2]; if ($varreqd == 'req' && !array_key_exists($varname, $array)) { $all_present=false; } if (array_key_exists($varname, $array)) { $varvalue=$array[$varname]; $waspresent=$all_present; switch ($vartype) { case 'int': if (!preg_match('/^\-*\d+$/', $varvalue)) { $all_present=false; } break; case 'float': if (!preg_match('/^\d+\.\d+$/', $varvalue)) { $all_present=false; } break; case 'yesno': if (!preg_match('/^(y|n|yes|no)$/i', $varvalue)) { $all_present=false; } break; case 'sqldate': if (!preg_match('/^\d\d\d\d\-\d\d\-\d\d$/i', $varvalue)) { $all_present=false; } break; case 'any': // we don't care at all break; case 'ip': if (!preg_match( '/^((\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)(?:\.(\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)){3})$/', $varvalue)) { $all_present=false; } break; case 'alpha': if (!preg_match('/^[A-Za-z]+$/', $varvalue)) { $all_present=false; } break; case 'alphanum': if (!preg_match('/^[A-Za-z0-9]+$/', $varvalue)) { $all_present=false; } break; case 'bandwidth': if (!preg_match('/^\d+\.?\d*[KMGT]*$/i', $varvalue)) { $all_present=false; } break; default: // an unknown type counts as an error, really $all_present=false; break; } if ($all_present) { $candidates["{$prefix}{$varname}"]=$varvalue; } } } if ($all_present) { foreach ($candidates as $key => $value) { $GLOBALS[$key]=$value; } } return array($all_present,$candidates); } function get_imagelist($imagedir) { $imagelist = array(); if (is_dir($imagedir)) { $n=0; $dh=opendir($imagedir); if ($dh) { while ($file=readdir($dh)) { $realfile=$imagedir . DIRECTORY_SEPARATOR . $file; $uri = $imagedir . "/" . $file; if (is_readable($realfile) && ( preg_match('/\.(gif|jpg|png)$/i',$file) )) { $imagelist[] = $uri; $n++; } } closedir ($dh); } } return ($imagelist); } function handle_inheritance(&$map, &$inheritables) { foreach ($inheritables as $inheritable) { $fieldname = $inheritable[1]; $formname = $inheritable[2]; $validation = $inheritable[3]; $new = $_REQUEST[$formname]; if($validation != "") { switch($validation) { case "int": $new = intval($new); break; case "float": $new = floatval($new); break; } } $old = ($inheritable[0]=='node' ? $map->nodes['DEFAULT']->$fieldname : $map->links['DEFAULT']->$fieldname); if ($old != $new) { if ($inheritable[0]=='node') { $map->nodes['DEFAULT']->$fieldname = $new; foreach ($map->nodes as $node) { if ($node->name != ":: DEFAULT ::" && $node->$fieldname == $old) { $map->nodes[$node->name]->$fieldname = $new; } } } if ($inheritable[0]=='link') { $map->links['DEFAULT']->$fieldname = $new; foreach ($map->links as $link) { if ($link->name != ":: DEFAULT ::" && $link->$fieldname == $old) { $map->links[$link->name]->$fieldname = $new; } } } } } } function get_fontlist(&$map,$name,$current) { $output = '"; return($output); } function range_overlaps($a_min, $a_max, $b_min, $b_max) { if ($a_min > $b_max) { return false; } if ($b_min > $a_max) { return false; } return true; } function common_range ($a_min,$a_max, $b_min, $b_max) { $min_overlap = max($a_min, $b_min); $max_overlap = min($a_max, $b_max); return array($min_overlap,$max_overlap); } /* distance - find the distance between two points * */ function distance ($ax,$ay, $bx,$by) { $dx = $bx - $ax; $dy = $by - $ay; return sqrt( $dx*$dx + $dy*$dy ); } function tidy_links(&$map,$targets, $ignore_tidied=FALSE) { // not very efficient, but it saves looking for special cases (a->b & b->a together) $ntargets = count($targets); $i = 1; foreach ($targets as $target) { tidy_link($map, $target, $i, $ntargets, $ignore_tidied); $i++; } } /** * tidy_link - change link offsets so that link is horizonal or vertical, if possible. * if not possible, change offsets to the closest facing compass points */ function tidy_link(&$map,$target, $linknumber=1, $linktotal=1, $ignore_tidied=FALSE) { // print "\n-----------------------------------\nTidying $target...\n"; if(isset($map->links[$target]) and isset($map->links[$target]->a) ) { $node_a = $map->links[$target]->a; $node_b = $map->links[$target]->b; $new_a_offset = "0:0"; $new_b_offset = "0:0"; // Update TODO: if the nodes are already directly left/right or up/down, then use compass-points, not pixel offsets // (e.g. N90) so if the label changes, they won't need to be re-tidied // First bounding box in the node's boundingbox array is the icon, if there is one, or the label if not. $bb_a = $node_a->boundingboxes[0]; $bb_b = $node_b->boundingboxes[0]; // figure out if they share any x or y coordinates $x_overlap = range_overlaps($bb_a[0], $bb_a[2], $bb_b[0], $bb_b[2]); $y_overlap = range_overlaps($bb_a[1], $bb_a[3], $bb_b[1], $bb_b[3]); $a_x_offset = 0; $a_y_offset = 0; $b_x_offset = 0; $b_y_offset = 0; // if they are side by side, and there's some common y coords, make link horizontal if ( !$x_overlap && $y_overlap ) { // print "SIDE BY SIDE\n"; // snap the X coord to the appropriate edge of the node if ($bb_a[2] < $bb_b[0]) { $a_x_offset = $bb_a[2] - $node_a->x; $b_x_offset = $bb_b[0] - $node_b->x; } if ($bb_b[2] < $bb_a[0]) { $a_x_offset = $bb_a[0] - $node_a->x; $b_x_offset = $bb_b[2] - $node_b->x; } // this should be true whichever way around they are list($min_overlap,$max_overlap) = common_range($bb_a[1],$bb_a[3],$bb_b[1],$bb_b[3]); $overlap = $max_overlap - $min_overlap; $n = $overlap/($linktotal+1); $a_y_offset = $min_overlap + ($linknumber*$n) - $node_a->y; $b_y_offset = $min_overlap + ($linknumber*$n) - $node_b->y; $new_a_offset = sprintf("%d:%d", $a_x_offset,$a_y_offset); $new_b_offset = sprintf("%d:%d", $b_x_offset,$b_y_offset); } // if they are above and below, and there's some common x coords, make link vertical if ( !$y_overlap && $x_overlap ) { // print "ABOVE/BELOW\n"; // snap the Y coord to the appropriate edge of the node if ($bb_a[3] < $bb_b[1]) { $a_y_offset = $bb_a[3] - $node_a->y; $b_y_offset = $bb_b[1] - $node_b->y; } if ($bb_b[3] < $bb_a[1]) { $a_y_offset = $bb_a[1] - $node_a->y; $b_y_offset = $bb_b[3] - $node_b->y; } list($min_overlap,$max_overlap) = common_range($bb_a[0],$bb_a[2],$bb_b[0],$bb_b[2]); $overlap = $max_overlap - $min_overlap; $n = $overlap/($linktotal+1); // move the X coord to the centre of the overlapping area $a_x_offset = $min_overlap + ($linknumber*$n) - $node_a->x; $b_x_offset = $min_overlap + ($linknumber*$n) - $node_b->x; $new_a_offset = sprintf("%d:%d", $a_x_offset,$a_y_offset); $new_b_offset = sprintf("%d:%d", $b_x_offset,$b_y_offset); } // if no common coordinates, figure out the best diagonal... if ( !$y_overlap && !$x_overlap ) { $pt_a = new WMPoint($node_a->x, $node_a->y); $pt_b = new WMPoint($node_b->x, $node_b->y); $line = new WMLineSegment($pt_a, $pt_b); $tangent = $line->vector; $tangent->normalise(); $normal = $tangent->getNormal(); $pt_a->AddVector( $normal, 15 * ($linknumber-1) ); $pt_b->AddVector( $normal, 15 * ($linknumber-1) ); $a_x_offset = $pt_a->x - $node_a->x; $a_y_offset = $pt_a->y - $node_a->y; $b_x_offset = $pt_b->x - $node_b->x; $b_y_offset = $pt_b->y - $node_b->y; $new_a_offset = sprintf("%d:%d", $a_x_offset,$a_y_offset); $new_b_offset = sprintf("%d:%d", $b_x_offset,$b_y_offset); } // if no common coordinates, figure out the best diagonal... // currently - brute force search the compass points for the shortest distance // potentially - intersect link line with rectangles to get exact crossing point if ( 1==0 && !$y_overlap && !$x_overlap ) { // print "DIAGONAL\n"; $corners = array("NE","E","SE","S","SW","W","NW","N"); // start with what we have now $best_distance = distance( $node_a->x, $node_a->y, $node_b->x, $node_b->y ); $best_offset_a = "C"; $best_offset_b = "C"; foreach ($corners as $corner1) { list ($ax,$ay) = calc_offset($corner1, $bb_a[2] - $bb_a[0], $bb_a[3] - $bb_a[1]); $axx = $node_a->x + $ax; $ayy = $node_a->y + $ay; foreach ($corners as $corner2) { list($bx,$by) = calc_offset($corner2, $bb_b[2] - $bb_b[0], $bb_b[3] - $bb_b[1]); $bxx = $node_b->x + $bx; $byy = $node_b->y + $by; $d = distance($axx,$ayy, $bxx, $byy); if($d < $best_distance) { // print "from $corner1 ($axx, $ayy) to $corner2 ($bxx, $byy): "; // print "NEW BEST $d\n"; $best_distance = $d; $best_offset_a = $corner1; $best_offset_b = $corner2; } } } // Step back a bit from the edge, to hide the corners of the link $new_a_offset = $best_offset_a."85"; $new_b_offset = $best_offset_b."85"; } // unwritten/implied - if both overlap, you're doing something weird and you're on your own // finally, update the offsets $map->links[$target]->a_offset = $new_a_offset; $map->links[$target]->b_offset = $new_b_offset; // and also add a note that this link was tidied, and is eligible for automatic tidying $map->links[$target]->add_hint("_tidied",1); } } function untidy_links(&$map) { foreach ($map->links as $link) { $link->a_offset = "C"; $link->b_offset = "C"; } } function retidy_links(&$map, $ignore_tidied=FALSE) { $routes = array(); $done = array(); foreach ($map->links as $link) { if(isset($link->a)) { $route = $link->a->name . " " . $link->b->name; if(strcmp( $link->a->name, $link->b->name) > 0) { $route = $link->b->name . " " . $link->a->name; } $routes[$route][] = $link->name; } } foreach ($map->links as $link) { if(isset($link->a)) { $route = $link->a->name . " " . $link->b->name; if(strcmp( $link->a->name, $link->b->name) > 0) { $route = $link->b->name . " " . $link->a->name; } if( ($ignore_tidied || $link->get_hint("_tidied")==1) && !isset($done[$route]) && isset( $routes[$route] ) ) { if( sizeof($routes[$route]) == 1) { tidy_link($map,$link->name); $done[$route] = 1; } else { # handle multi-links specially... tidy_links($map,$routes[$route]); // mark it so we don't do it again when the other links come by $done[$route] = 1; } } } } } function editor_log($str) { // $f = fopen("editor.log","a"); // fputs($f, $str); // fclose($f); } // vim:ts=4:sw=4: