diff --git a/web/www/sunders/camera.php b/web/www/sunders/camera.php index 97a77e7..9aa2f85 100644 --- a/web/www/sunders/camera.php +++ b/web/www/sunders/camera.php @@ -4,6 +4,17 @@ define('MAX_POINTS_FOR_QUICKHULL', 3000); + // Fields set by this script; OSM tags with these keys are not passed on. + define('RESERVED_KEYS', array('lat', 'lon', 'id', 'count', 'multi', 'poly')); + + define('JSON_FLAGS', JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE); + + function exitWithError($message) { + header('Content-type: application/json; charset=utf-8'); + echo json_encode(array('error' => $message), JSON_FLAGS); + exit; + } + class OsmPoint { var $id; var $lat; @@ -179,63 +190,47 @@ || !array_key_exists('zoom', $_GET) || !array_key_exists('width', $_GET) || !array_key_exists('height', $_GET)) { - header('Content-type: application/json'); - $result = '{"error":"bbox, zoom, width and height parameters are required. ' + exitWithError('bbox, zoom, width and height parameters are required. ' .(array_key_exists('bbox', $_GET) ? '' : 'bbox is empty. ') .(array_key_exists('zoom', $_GET) ? '' : 'zoom is empty. ') .(array_key_exists('width', $_GET) ? '' : 'width is empty. ') - .(array_key_exists('height', $_GET) ? '' : 'height is empty. ') - .'"}'; - echo $result; - exit; + .(array_key_exists('height', $_GET) ? '' : 'height is empty. ')); } /* Check zoom */ $zoom = $_GET['zoom']; - if ( !is_numeric($zoom) + if ( !is_string($zoom) + || !is_numeric($zoom) || intval($zoom) < 1 || intval($zoom) > 19) { - header('Content-type: application/json'); - $result = '{"error":"unexpected zoom value : ' - .htmlentities($zoom) - .'"}'; - echo $result; - exit; + exitWithError('unexpected zoom value'); } /* Check bounds box --> bbox=boundsSW.lng,boundsSW.lat,boundsNE.lng,boundsNE.lat */ + if (!is_string($_GET['bbox'])) { + exitWithError('unexpected bbox value'); + } $bbox = explode(',', $_GET['bbox']); - if ( !is_numeric($bbox[0]) || $bbox[0] > 180 // 0 = SW.lng + if ( count($bbox) != 4 + || !is_numeric($bbox[0]) || $bbox[0] > 180 // 0 = SW.lng || !is_numeric($bbox[2]) || $bbox[2] < -180 // 2 = NE.lng || !is_numeric($bbox[1]) || $bbox[1] < -90 || $bbox[1] > 90 // 1 = SW.lat || !is_numeric($bbox[3]) || $bbox[3] < -90 || $bbox[3] > 90) { // 3 = NE.lat - header('Content-type: application/json'); - $result = '{"error":"unexpected bbox longitude and latitude values : ' - .'lon ['.htmlentities($bbox[0]).', '.htmlentities($bbox[2]).'], ' - .'lat ['.htmlentities($bbox[1]).', '.htmlentities($bbox[3]).']' - .'"}'; - echo $result; - exit; + exitWithError('unexpected bbox longitude and latitude values : ' + .'lon ['.$bbox[0].', '.$bbox[2].'], ' + .'lat ['.$bbox[1].', '.$bbox[3].']'); } if ($bbox[0] >= $bbox[2]) { // 0 = SW.lng | 2 = NE.lng - header('Content-type: application/json'); - $result = '{"error":"min longitude greater than max longitude : ' - .'lon ['.htmlentities($bbox[0]).', '.htmlentities($bbox[2]).']' - .'"}'; - echo $result; - exit; + exitWithError('min longitude greater than max longitude : ' + .'lon ['.$bbox[0].', '.$bbox[2].']'); } if ($bbox[1] >= $bbox[3]) { // 1 = SW.lat | 3 = NE.lat - header('Content-type: application/json'); - $result = '{"error":"min latitude greater than max latitude : ' - .'lat ['.htmlentities($bbox[1]).', '.htmlentities($bbox[3]).']' - .'"}'; - echo $result; - exit; + exitWithError('min latitude greater than max latitude : ' + .'lat ['.$bbox[1].', '.$bbox[3].']'); } $lonMin = $bbox[0]; // 0 = SW.lng @@ -247,12 +242,7 @@ $pixelHeight = (int) $_GET['height']; if ($pixelWidth == 0 || $pixelHeight == 0) { - header('Content-type: application/json'); - $result = '{"error":"width or height is null : ' - .htmlentities($pixelWidth).'x'.htmlentities($pixelHeight) - .'"}'; - echo $result; - exit; + exitWithError('width or height is null : '.$pixelWidth.'x'.$pixelHeight); } $lonWidth = $lonMax - $lonMin; // NE.lng - SW.lng @@ -268,10 +258,7 @@ /* Connect to database */ $mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); if($mysqli->connect_errno) { - header('Content-type: application/json'); - $result = '{"error":"error while connecting to db : ' . $mysqli->error . '"}'; - echo $result; - exit; + exitWithError('error while connecting to db'); } $rqtLonMin = $lonMin; // SW.lng @@ -365,10 +352,7 @@ $stmt->close(); } else { $mysqli->close(); - header('Content-type: application/json'); - $result = '{"error":"Error while request : ' . $mysqli->error . '"}'; - echo $result; - exit; + exitWithError('error while querying db'); } /* Unify some clusters if nodes center are near */ @@ -380,8 +364,7 @@ } } - $result='['; - $separator=''; + $result = array(); /* Writing selected points */ $sql='SELECT k, v @@ -393,53 +376,49 @@ $stmt->bind_param('d', $id); $stmt->bind_result($k, $v); - /* Writing grouped items or not */ + /* Writing grouped items or not. All values are passed on unescaped; the client + must escape them before inserting them into HTML. */ foreach($resArray as $val) { if ($val['count'] > 0) { - $result = $result.$separator - .'{"lat":"'.($val['latitude'] / $val['count']).'"' - .',"lon":"'.($val['longitude'] / $val['count']).'"'; + $entry = array( + 'lat' => (string) ($val['latitude'] / $val['count']), + 'lon' => (string) ($val['longitude'] / $val['count'])); if ($val['count'] == 1) { $id = $val['points'][0]->id; - $result = $result.',"id":"'.$id.'"'; + $entry['id'] = (string) $id; $stmt->execute(); while($stmt->fetch()) { - $result = $result.',"'.htmlentities($k).'":"'.htmlentities($v, ENT_COMPAT, 'UTF-8').'"'; + if (!in_array($k, RESERVED_KEYS, true)) { + $entry[$k] = (string) $v; + } } } else { - $result = $result - .',"count":"'.$val['count'].'"' - .',"multi":"yes"' - .',"poly":['; + $entry['count'] = (string) $val['count']; + $entry['multi'] = 'yes'; + $entry['poly'] = array(); if ($pointsCount < MAX_POINTS_FOR_QUICKHULL) { $convexPoly = quickHull($val['points'], $val['count']); - $sepPoly = ''; foreach($convexPoly as $point) { - $result = $result.$sepPoly.'{' - .'"lat":"'.$point->lat.'"' - .',"id":"'.$point->id.'"' - .',"lon":"'.$point->lon.'"}'; - $sepPoly=','; + $entry['poly'][] = array( + 'lat' => (string) $point->lat, + 'id' => (string) $point->id, + 'lon' => (string) $point->lon); } } - $result=$result.']'; } - $result = $result.'}'; - $separator=','; + $result[] = $entry; } } $stmt->close(); - $result = $result . ']'; - $mysqli->close(); - header('Content-type: application/json; Charset : utf-8'); - echo $result; + header('Content-type: application/json; charset=utf-8'); + echo json_encode($result, JSON_FLAGS); ?> diff --git a/web/www/sunders/js/leafletembed_functions.js b/web/www/sunders/js/leafletembed_functions.js index cb199a0..75e461e 100644 --- a/web/www/sunders/js/leafletembed_functions.js +++ b/web/www/sunders/js/leafletembed_functions.js @@ -129,7 +129,11 @@ function onClick(e) { function onStateChanged() { if (ajaxRequest.readyState == 4) { // 0 = UNSENT, 1 = OPENED, 2 = HEADERS_RECEIVED, 3 = LOADING, 4 = DONE if (ajaxRequest.status == 200) { // 200 = OK, 404 = Page not found - plotList = eval('(' + ajaxRequest.responseText + ')'); + try { + plotList = JSON.parse(ajaxRequest.responseText); + } catch(e) { + return; + } removeMarkers(); for (i=0; i/g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + // Add camera popup to camera marker. +// All values in plot come unescaped from OSM data and must be escaped. function addCameraDetailsData(plotMarker, plot) { + var id = escapeHtml(plot.id); popupDataTable = '' - + '' - // + '' - + '' - + ''; + + '' + // + '' + + '' + + ''; for (x in plot) { if (plot[x] !== '' && x != 'multi' && x != 'id' && x != 'userid' && x != 'lat' && x != 'lon') { - popupDataTable = popupDataTable + ''; }