diff --git a/511.html b/511.html index 514f076..97a3eba 100644 --- a/511.html +++ b/511.html @@ -83,7 +83,7 @@ var table = new Tabulator("#wunderobs", { virtualDom: true, virtualDomBuffer: 300, - ajaxURL: "lsr.php?getCombinedTable=p", + ajaxURL: "main.php?service=lsr&getCombinedTable=p", ajaxConfig: "GET", autoResize: true, initialSort: [{ column: "start", dir: "desc" }], @@ -181,7 +181,7 @@ function lsr(lsr, id, source) { $.get({ - url: 'lsr.php?updater=true&lsr=' + lsr + "&id=" + id + "&table="+source, + url: 'main.php?service=lsr&updater=true&lsr=' + lsr + "&id=" + id + "&table="+source, error: function(xhr, error) { alert('Unable to update, please refresh page'); } @@ -195,7 +195,7 @@ function hide(hide, id, source) { $.get({ - url: 'lsr.php?updater=true&hide=' + hide + "&id=" + id + "&table="+source, + url: 'main.php?service=lsr&updater=true&hide=' + hide + "&id=" + id + "&table="+source, error: function(xhr, error) { alert('Unable to update, please refresh page'); } diff --git a/API_DOCUMENTATION.md b/API_DOCUMENTATION.md new file mode 100644 index 0000000..bb98e35 --- /dev/null +++ b/API_DOCUMENTATION.md @@ -0,0 +1,278 @@ +# Unified API Gateway Documentation + +## Overview +This API gateway serves as a single entry point for all API services that were previously separate PHP scripts. Each service is accessed via a `service` parameter that routes the request to the appropriate functionality. + +## Base URL +``` +main.php?service={service_name}[¶meters] +``` + +## Available Services + +### 1. cams +**Description**: Returns active camera information +**Usage**: `main.php?service=cams` +**Parameters**: None required +**Migration**: +- Old: `cam.php` +- New: `main.php?service=cams` + +### 2. camapi +**Description**: Returns camera API endpoints with filtering +**Usage**: `main.php?service=camapi[&cams&lat1={lat}&lon1={lon}&lat2={lat}&lon2={lon}&elevbottom={elev}&elevtop={elev}]` +**Parameters**: +- `cams` - Get RTSP cameras +- `lat1, lon1, lat2, lon2` - Bounding box coordinates +- `elevbottom, elevtop` - Elevation range +- `camstatic` - Get cameras near a point (requires `lat1`, `lon1`, `radius`) +- `camdb` - Get camera count +**Migration**: +- Old: `camapi.php?cams&lat1=...&lon1=...&lat2=...&lon2=...` +- New: `main.php?service=camapi&cams&lat1=...&lon1=...&lat2=...&lon2=...` + +### 3. camlist +**Description**: Returns camera list with active status +**Usage**: `main.php?service=camlist` +**Parameters**: None required +**Migration**: +- Old: `camlist.php` +- New: `main.php?service=camlist` + +### 4. admin +**Description**: Admin operations for cameras +**Usage**: `main.php?service=admin&action={action}` +**Parameters**: +- `action='checkurl'` - Check if URL exists (POST required) +- `action='newcam'` - Add new camera (POST required) +**Migration**: +- Old: `admin.php?action=checkurl` +- New: `main.php?service=admin&action=checkurl` + +### 5. camcircle +**Description**: Returns camera coverage circles +**Usage**: `main.php?service=camcircle` +**Parameters**: None required +**Migration**: +- Old: `camcircle.php` +- New: `main.php?service=camcircle` + +### 6. db +**Description**: Returns weather station data +**Usage**: `main.php?service=db[&outside]` +**Parameters**: +- `outside` - Get outside weather data +**Migration**: +- Old: `db.php` +- New: `main.php?service=db` +- Old: `db.php?outside` +- New: `main.php?service=db&outside` + +### 7. fire +**Description**: Returns fire information +**Usage**: `main.php?service=fire` +**Parameters**: None required +**Migration**: +- Old: `fire.php` +- New: `main.php?service=fire` + +### 8. individualcam +**Description**: Returns individual camera images +**Usage**: `main.php?service=individualcam&camid={camid}[&dtg={datetime}&camimages={count}]` +**Parameters**: +- `camid` - Camera ID (required) +- `dtg` - Date/time to get images before +- `camimages` - Number of images to return (default: 20) +**Migration**: +- Old: `individualcam.php?camid=...` +- New: `main.php?service=individualcam&camid=...` + +### 9. lsr +**Description**: Returns local storm reports and related data +**Usage**: `main.php?service=lsr[&{various parameters}]` +**Parameters**: +- No parameters - Get all reports +- `ohgo` - Get Ohio traffic data +- `ohgotable` - Get Ohio traffic table data +- `lsrohgo`, `ohgohide` - Update records +- `vtec` - Get data for specific VTEC code +- `preflagreports` - Get pre-flagged reports +- `reports` - Get reports within polygon +- `outages` - Get power outages within polygon +- `rtcad` - Get real-time CAD reports +- `verify` - Get verification reports +- `stats` - Get statistics +- `metars` - Get METARs +- `news` - Get news data +- `news2` - Get news data (version 2) +- `news3` - Get news data (version 3) +- `wv511`, `ky511` - Get state traffic data +- `getCombinedTable` - Get combined traffic data +- `updater` - Update records +**Migration**: +- Old: `lsr.php` +- New: `main.php?service=lsr` +- Old: `lsr.php?ohgo` +- New: `main.php?service=lsr&ohgo` + +### 10. nws +**Description**: Returns NWS personnel stats +**Usage**: `main.php?service=nws[&{various parameters}]` +**Parameters**: +- No parameters - Get all NWS data +- `officestats`, `officestats11`, `regionstats`, `drilldown` - Various statistics +- `datetime` - Date for statistics +**Migration**: +- Old: `nws.php` +- New: `main.php?service=nws` + +### 11. powerapi +**Description**: Returns power outage information +**Usage**: `main.php?service=powerapi[&{various parameters}]` +**Parameters**: +- No parameters - Get current power outages +- `states` - Get state boundaries +- `max` - Get max outages (requires `start` and `end`) +- `county` - Get county power outages +- `countyarchive` - Get archived county outages (requires `start` and `end`) +- `archivepoint` - Get archived point outages (requires `start` and `end`) +- `svr` - Severe weather reports +- `svrpolys` - Get severe weather polygons +- `powerids` - Get specific power outages (requires comma-separated IDs) +- `poweridsgeojson` - Get specific power outages as GeoJSON +- `polygongeojson` - Get power outages in polygon (requires GeoJSON string) +**Migration**: +- Old: `powerapi.php` +- New: `main.php?service=powerapi` +- Old: `powerapi.php?states` +- New: `main.php?service=powerapi&states` + +### 12. searchapi +**Description**: Returns search results for power outages +**Usage**: `main.php?service=searchapi[&{various parameters}]` +**Parameters**: +- No parameters - Get current power outages +- `county` - Get county data +- `countyarchive` - Get archived county data +- `archivepoint` - Get archived point data +- `svr` - Get severe weather data +**Migration**: +- Old: `searchapi.php` +- New: `main.php?service=searchapi` + +### 13. ohgo +**Description**: Returns Ohio traffic information +**Usage**: `main.php?service=ohgo` +**Parameters**: None required +**Migration**: +- Old: `ohgo.php` +- New: `main.php?service=ohgo` + +### 14. power +**Description**: Returns power outage information (simplified) +**Usage**: `main.php?service=power` +**Parameters**: None required +**Migration**: +- Old: `power.php` +- New: `main.php?service=power` + +### 15. stormdata +**Description**: Returns storm data (POST only) +**Usage**: POST to `main.php?service=stormdata` +**Parameters** (in POST body as JSON): +- `request_type` - Type of request (ohgo, ohgonopoly, power, powernopoly, wupoly, campoly) +- `start_time`, `end_time` - Time range +- `area_geojson` - Area as GeoJSON +- `buffer` - Buffer time in hours +**Migration**: +- Old: `stormdata.php` +- New: `main.php?service=stormdata` (POST request) + +### 16. warntrack +**Description**: Returns warning tracking data +**Usage**: `main.php?service=warntrack` +**Parameters**: None required +**Migration**: +- Old: `warntrack.php` +- New: `main.php?service=warntrack` + +### 17. ver +**Description**: Returns version information +**Usage**: `main.php?service=ver[&{various parameters}]` +**Parameters**: +- No parameters - Get version polygons +- `lsrslist` - Get LSRs list +- `reset` - Reset LSRs +- `lsrs` - Update LSRs +- `inc` - Update increment +- `hide` - Update hide status +**Migration**: +- Old: `ver.php` +- New: `main.php?service=ver` + +### 18. update_field +**Description**: Updates table fields (POST only) +**Usage**: POST to `main.php?service=update_field` +**Parameters** (in POST body): +- `camid` - Camera ID +- `field` - Field to update (hydro, airport) +- `value` - Value to set +**Migration**: +- Old: `update_field.php` +- New: `main.php?service=update_field` (POST request) + +### 19. mp4 +**Description**: Generates MP4/gif from images (POST only) +**Usage**: POST to `main.php?service=mp4` +**Parameters** (in POST body): +- `data` - Array of image paths +- `images` - Number of images +- `delay` - Delay between images +- `lastdelay` - Delay for last image +- `maxh`, `maxv` - Max dimensions +**Migration**: +- Old: `mp4.php` +- New: `main.php?service=mp4` (POST request) + +## Error Handling +- Invalid service parameters return HTTP 400 with available services +- Database errors return appropriate error messages +- Missing required parameters return HTTP 400 with descriptive error messages + +## Security Considerations +- All user-provided input is properly escaped using `pg_escape_string()` +- SQL injection prevention through parameterized queries +- Input validation for numeric and boolean values + +## Migration Guide + +### For Web Applications +1. Update all API calls to use the new endpoint format +2. Replace direct script calls with `main.php?service={service_name}` +3. Ensure all existing parameters are preserved +4. Test all functionality to verify compatibility + +### For JavaScript Applications +```javascript +// Old approach +fetch('cam.php') + .then(response => response.json()) + +// New approach +fetch('main.php?service=cams') + .then(response => response.json()) +``` + +### For Server-to-Server Communication +```php +// Old approach +$result = file_get_contents('http://yourserver/camapi.php?cams&lat1=...&lon1=...'); + +// New approach +$result = file_get_contents('http://yourserver/main.php?service=camapi&cams&lat1=...&lon1=...'); +``` + +## Testing +- All services maintain the same output format as the original scripts +- Backwards compatibility is preserved for parameter usage +- JSON output remains consistent with previous implementations \ No newline at end of file diff --git a/admin.html b/admin.html index ad327eb..9ae4f06 100644 --- a/admin.html +++ b/admin.html @@ -167,7 +167,7 @@ padding-horizontal: 15px; function isValidUrl(string) { $.ajax({ - url: 'admin.php?action=checkurl', + url: 'main.php?service=admin&action=checkurl', type: 'POST', dataType: "json", data: {url:string}, @@ -191,7 +191,7 @@ function isValidUrl(string) { $('#newcam').submit(function(e){ e.preventDefault(); $.ajax({ - url: 'admin.php?action=newcam', + url: 'main.php?service=admin&action=newcam', type: 'post', data:$('#newcam').serialize(), success:function(data){ diff --git a/admin.php b/admin.php deleted file mode 100644 index 350240e..0000000 --- a/admin.php +++ /dev/null @@ -1,61 +0,0 @@ - false AND lastsuccess IS NOT NULL AND (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) order by elevation desc"; -$result = pg_query($query) or die('Query failed: ' . pg_last_error()); - -// Printing results in HTML -$array = array(); -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - // Ensure hydro is a proper boolean - $line['hydro'] = ($line['hydro'] === 't' || $line['hydro'] === true); - // Ensure airport is a proper boolean - $line['airport'] = ($line['airport'] === 't' || $line['airport'] === true); - $array[] = $line; -} -echo json_encode($array); - -// Free resultset -pg_free_result($result); - -// Closing connection -pg_close($dbconn); -?> diff --git a/camapi.php b/camapi.php deleted file mode 100644 index 232353b..0000000 --- a/camapi.php +++ /dev/null @@ -1,102 +0,0 @@ - %s and lat < %s and lon > %s and lon < %s order by lastsuccess desc limit 25 - - -//no gets, curent point outage info -//error_reporting(-1); // reports all errors -//ini_set("display_errors", "1"); // shows all errors -//ini_set("log_errors", 1); -//ini_set("error_log", "php-error.log"); - - -//county/state max - -if (isset($_GET['cams'])) { -if($_GET['lat1']) { -$lat1 = pg_escape_string($_GET['lat1']); -if($_GET['lon1']) { -$lon1 = pg_escape_string($_GET['lon1']); -if($_GET['lat2']) { -$lat2 = pg_escape_string($_GET['lat2']); -if($_GET['lon2']) { -$lon2 = pg_escape_string($_GET['lon2']); -if($_GET['elevbottom']) { -$elevbottom = pg_escape_string($_GET['elevbottom']); -if($_GET['elevtop']) { -$elevtop = pg_escape_string($_GET['elevtop']); - - -$result = pg_query_params($dbconn, -"select camid,url,description from cams where method = 'rtsp' and active = true and cwa = 'RLX' and elevation > $5 and elevation < $6 and (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) and lat < $1 and lat > $2 and lon < $3 and lon > $4 order by elevation desc", -array($lat1,$lat2,$lon1,$lon2,$elevbottom,$elevtop)) or die('Query failed: ' . pg_last_error()); - - - -//$result = pg_query_params($dbconn, -//select distinct on (county,state) max(outage),county,state from (select distinct on (county,state,update) county,state,sum(outages) as outage, update as time, sum(served) as served from countyoutages where update > '2023-04-01' and update < '2023-04-02' and cwa = 'RLX' group by county,state,update) as potato group by county,state; -//"select camid,url,description from cams where method = 'rtsp' and active = true $1 '162.210.14.137' and (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) and lat < $2 and lat > $3 and lon < $4 and lon > $5", -//array($res,$lat1,$lat2,$lon1,$lon2)) or die('Query failed: ' . pg_last_error()); -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; -} -echo json_encode($array); -pg_free_result($result); -pg_close($dbconn); - -}}}}}}} - -if (isset($_GET['camstatic'])) { - -if($_GET['lat1']) { -$lat1 = pg_escape_string($_GET['lat1']); -if($_GET['lon1']) { -$lon1 = pg_escape_string($_GET['lon1']); -if($_GET['radius']) { -$radius = pg_escape_string($_GET['radius']); -$rad = $radius / 70; - -$lat1 = floatval($lat1); -$lon1 = floatval($lon1); -$radius = floatval($rad); -$query = "select * from cams where method = 'rtsp' and active = true and cwa = 'RLX' and (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) and st_dwithin(geom, ST_SetSRID(ST_Point(" . strval($lon1) . ", " . strval($lat1) . "), 4326)," . strval($radius) . ") order by elevation desc"; - - - -$result = pg_query($dbconn,$query) or die('Query failed: ' . pg_last_error()); - -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; -} -echo json_encode($array); -pg_free_result($result); -pg_close($dbconn); - - - -}}}} - - - -if (isset($_GET['camdb'])) { -$result = pg_query($dbconn, -"SELECT COUNT(*) FROM camdb") or die('Query failed: ' . pg_last_error()); -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; -} -echo json_encode($array); -pg_free_result($result); -pg_close($dbconn); -} - - - - - - -?> diff --git a/camcircle.php b/camcircle.php deleted file mode 100644 index fd6dcf6..0000000 --- a/camcircle.php +++ /dev/null @@ -1,43 +0,0 @@ - false AND lastsuccess IS NOT NULL AND (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) order by elevation desc"; -//$query = "SELECT cwa,lat,lon,lastimage,county,elevation,camid,state,description FROM cams WHERE active <> false AND lastsuccess IS NOT NULL AND (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < (interval + 20) order by elevation desc"; -//$query = "SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(WITH subquery_points AS (SELECT geom AS point_geometry FROM cams WHERE active = true and totalfails < 50) SELECT ST_Buffer(point_geometry::geography, 8000) AS circle_geometry FROM subquery_points)))"; -//"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(realgeom)::json,'properties',json_build_object('time',startguess,'county',county,'state',state,'outage',outagen,'lastchange',lastchange,'cause',cause))order by startguess asc)) FROM power WHERE cwa = $1 and active = true" -$query = "WITH subquery_points AS ( - SELECT geom AS point_geometry - FROM cams - WHERE active = true and lastsuccess IS NOT NULL AND (EXTRACT(EPOCH FROM (current_timestamp - lastsuccess ))/60) < 60 -) -SELECT jsonb_build_object( - 'type', 'FeatureCollection', - 'features', jsonb_agg(jsonb_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(ST_Buffer(point_geometry::geography, 8000))::jsonb - )) -) AS feature_collection -FROM subquery_points"; - - - -$result = pg_query($query) or die('Query failed: ' . pg_last_error()); - -// Printing results in HTML - -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; - -} -print_r($array[0]['feature_collection']); - -// Free resultset -pg_free_result($result); - -// Closing connection -pg_close($dbconn); -?> diff --git a/camlist.php b/camlist.php deleted file mode 100644 index 588be90..0000000 --- a/camlist.php +++ /dev/null @@ -1,56 +0,0 @@ - 'success', - 'data' => $data, - 'count' => count($data) - ]; - - // Free resultset - pg_free_result($result); - - // Close connection - pg_close($dbconn); - -} catch (Exception $e) { - http_response_code(500); - $response = [ - 'status' => 'error', - 'message' => $e->getMessage() - ]; -} - -// Output JSON -echo json_encode($response, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK); -?> \ No newline at end of file diff --git a/cams.html b/cams.html index d909c21..0910660 100644 --- a/cams.html +++ b/cams.html @@ -501,7 +501,7 @@ for (var ii in sortcams) { // Load settings when the page loads window.onload = function() { loadSettings(); - $.getJSON('cam.php', function(data) { + $.getJSON('main.php?service=cams', function(data) { var wild = Math.random(); allcams = data; console.log('Camera data:', data); // Debug: log camera data @@ -535,7 +535,7 @@ for (var ii in sortcams) { } filter(); sortcams(); // Apply saved sort - $.getJSON('camapi.php?camdb', function(data){ + $.getJSON('main.php?service=camapi&camdb', function(data){ document.getElementById("camcount").textContent = "Total Images: " + data[0].count; }); }); @@ -544,7 +544,7 @@ for (var ii in sortcams) { function refreshcams() { -$.getJSON('cam.php', function(data){ +$.getJSON('main.php?service=cams', function(data){ var wild = Math.random(); //console.log(data); for(var i in data){ @@ -565,7 +565,7 @@ $.getJSON('cam.php', function(data){ } }} }); -$.getJSON('camapi.php?camdb', function(data){ +$.getJSON('main.php?service=camapi&camdb', function(data){ document.getElementById("camcount").textContent = "Total Images: " + data[0].count; }); diff --git a/circlemap.html b/circlemap.html index 89a22c3..9efbaa0 100644 --- a/circlemap.html +++ b/circlemap.html @@ -204,7 +204,7 @@ style: function (feature) { }).addTo(mymap); -$.getJSON('camcircle.php', function(data) { +$.getJSON('main.php?service=camcircle', function(data) { var geojsonFeature = data; geoJSONcircle.addData(geojsonFeature); diff --git a/db.html b/db.html index 2e0dd6f..23b76cd 100644 --- a/db.html +++ b/db.html @@ -19,7 +19,7 @@
- - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
-
-
- Enter Start/End Times in UTC - - -
-Enable Screenshots:
-Note: move the map slightly after loading data if you want to capture
-
- -
-
-
- - -
- - - -
- -
- - - - - -
-
-
-
-
- -
-
- Cam List - Cam Map - WU obs - 5m ASOS obs - CoCoRaHS Remarks - Outage Map w/ Outside Counties - Questions? Comments? - Power Outage Tracker -
- - - - - diff --git a/power.php b/power.php deleted file mode 100644 index 7c7dce8..0000000 --- a/power.php +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/powerapi.php b/powerapi.php deleted file mode 100644 index 6e2a6bb..0000000 --- a/powerapi.php +++ /dev/null @@ -1,967 +0,0 @@ -getMessage()); -} - -//no gets, curent point outage info -//if(empty($_GET)) { -//$result = pg_query_params($dbconn, -//"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(realgeom)::json,'properties',json_build_object('time',startguess,'county',county,'state',state,'outage',outagen,'lastchange',lastchange,'cause',cause,'area_geometry', ST_AsGeoJSON(COALESCE(realareageom, realgeom))::json))order by startguess asc)) FROM power WHERE cwa = $1 and active = true", -//array('RLX')) or die('Query failed: ' . pg_last_error()); -//$resultArray = pg_fetch_all($result); -//echo($resultArray[0]['json_build_object']); -//pg_free_result($result); -//} - - -if (empty($_GET)) { - try { - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(realgeom)::json, - 'properties', json_build_object( - 'time', startguess, - 'county', county, - 'state', state, - 'outage', outagen, - 'lastchange', lastchange, - 'cause', cause, - 'area_geometry', ST_AsGeoJSON(COALESCE(realareageom, realgeom))::json - ) - ) - ORDER BY startguess ASC - ) - ) - FROM power - WHERE cwa = $1 AND active = true - "; - - $result = pg_query_params($dbconn, $query, array('RLX')); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $resultArray = pg_fetch_all($result); - - // Check if we got results - if ($resultArray && isset($resultArray[0]['json_build_object'])) { - header('Content-Type: application/json'); - echo $resultArray[0]['json_build_object']; - } else { - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - } catch (Exception $e) { - http_response_code(500); - die('Query execution failed: ' . $e->getMessage()); - } -} - - - -//if (isset($_GET['states'])) { -//$result = pg_query($dbconn, -//"SELECT jsonb_build_object('type', 'FeatureCollection','features', jsonb_agg(features.feature)) FROM (SELECT jsonb_build_object('type', 'Feature','geometry', ST_AsGeoJSON(ST_Transform(geom, 4326))::jsonb,'properties', to_jsonb(properties) - 'geom') AS feature FROM (SELECT * FROM states where state = 'WV' or state = 'VA' or state = 'KY' or state ='VA' or state = 'MD' or state = 'PA' or state = 'OH') AS properties) AS features") or die('Query failed: ' . pg_last_error()); -// $resultArray = pg_fetch_all($result); -//echo($resultArray[0]['jsonb_build_object']); -//pg_free_result($result); -//} - -if (isset($_GET['states'])) { - try { - $query = " - SELECT jsonb_build_object( - 'type', 'FeatureCollection', - 'features', jsonb_agg(features.feature) - ) - FROM ( - SELECT jsonb_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(ST_Transform(geom, 4326))::jsonb, - 'properties', to_jsonb(properties) - 'geom' - ) AS feature - FROM ( - SELECT * - FROM states - WHERE state IN ('WV', 'VA', 'KY', 'MD', 'PA', 'OH') - ) AS properties - ) AS features - "; - - $result = pg_query($dbconn, $query); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $resultArray = pg_fetch_all($result); - - // Set proper JSON header and handle output - header('Content-Type: application/json'); - if ($resultArray && isset($resultArray[0]['jsonb_build_object'])) { - echo $resultArray[0]['jsonb_build_object']; - } else { - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - } catch (Exception $e) { - http_response_code(500); - header('Content-Type: application/json'); - echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]); - exit; - } -} - - - -//county/state max -//if($_GET['max'] ?? null) { - -//if($_GET['start'] ?? null) { -//$starttime = pg_escape_string($_GET['start']); -//if($_GET['end'] ?? null) { -//$endtime = pg_escape_string($_GET['end']); - - - -//$result = pg_query_params($dbconn, -////select distinct on (county,state) max(outage),county,state from (select distinct on (county,state,update) county,state,sum(outages) as outage, update as time, sum(served) as served from countyoutages where update > '2023-04-01' and update < '2023-04-02' and cwa = 'RLX' group by county,state,update) as potato group by county,state; -////"select distinct on (county,state) max(outage),county,state from (select distinct on (county,state,update) county,state,sum(outages) as outage, update as time, sum(served) as served from countyoutages where update > $2 and update < $3 and cwa = $1 group by county,state,update) as potato group by county,state", -//"select distinct on (county,state) max(outage),county,state from (select distinct on (county,state,update) county,state,sum(outages) as outage, update as time, sum(served) as served from countyoutages where update > $2 and update < $3 and cwa = $1 group by county,state,update) as potato group by county,state", -//array('RLX',$starttime,$endtime)) or die('Query failed: ' . pg_last_error()); -// -//while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { -// $array[] = $line; -//} -//echo json_encode($array); -//pg_free_result($result); -//}}} - -if (isset($_GET['max'])) { - if (isset($_GET['start']) && isset($_GET['end'])) { - try { - $starttime = pg_escape_string($_GET['start']); - $endtime = pg_escape_string($_GET['end']); - - $query = " - SELECT DISTINCT ON (county, state) - max(outage) as max_outage, - county, - state - FROM ( - SELECT DISTINCT ON (county, state, update) - county, - state, - SUM(outages) as outage, - update as time, - SUM(served) as served - FROM countyoutages - WHERE update > $2 - AND update < $3 - AND cwa = $1 - GROUP BY county, state, update - ) as subquery - GROUP BY county, state - "; - - $result = pg_query_params( - $dbconn, - $query, - ['RLX', $starttime, $endtime] - ); - - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $results = []; - while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $results[] = $line; - } - - header('Content-Type: application/json'); - echo json_encode($results); - - pg_free_result($result); - } catch (Exception $e) { - header('Content-Type: application/json'); - http_response_code(500); - echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]); - exit; - } - } else { - header('Content-Type: application/json'); - http_response_code(400); - echo json_encode(['error' => 'Both start and end parameters are required']); - } -} - - - - - - - - - -//county current -//"SELECT distinct on (county,state) update as time, county, state, outages as outage,served FROM countyoutages where cwa = $1 order by county,state,update desc", -//if($_GET['county'] ?? null) { -//$result = pg_query_params($dbconn, -//"SELECT DISTINCT ON (county, state) county, state, SUM(outages) as outage, update as time, SUM(served) as served, round((SUM(outages) / SUM(served))*100,2) as perout FROM countyoutages WHERE update = (SELECT MAX(update) FROM countyoutages) AND cwa = $1 GROUP BY county, state, update", -//array('RLX')) or die('Query failed: ' . pg_last_error()); - -//while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - //$array[] = $line; -//} -//echo json_encode($array ?? null); -//pg_free_result($result); -//} - -if (isset($_GET['county'])) { - try { - $query = " - SELECT DISTINCT ON (county, state) - county, - state, - SUM(outages) as outage, - update as time, - SUM(served) as served, - ROUND(CAST((SUM(outages)::FLOAT / SUM(served)) * 100 AS NUMERIC), 2) as perout - FROM countyoutages - WHERE update = (SELECT MAX(update) FROM countyoutages) - AND cwa = $1 - GROUP BY county, state, update - "; - - $result = pg_query_params($dbconn, $query, ['RLX']); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $results = []; - while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $results[] = $line; - } - - header('Content-Type: application/json'); - echo json_encode($results); - - pg_free_result($result); - } catch (Exception $e) { - header('Content-Type: application/json'); - http_response_code(500); - echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]); - exit; - } -} - - -//county archive delete after testing -if($_GET['countyarchiveold'] ?? null) { - -if($_GET['start'] ?? null) { -$starttime = pg_escape_string($_GET['start']); -if($_GET['end'] ?? null) { -$endtime = pg_escape_string($_GET['end']); - - - -$result = pg_query_params($dbconn, - -"select distinct on (county,state,update) county,state,sum(outages) as outage, update as time, sum(served) as served from countyoutages where update > $2 and update < $3 and cwa = $1 group by county,state,update", -array('RLX',$starttime,$endtime)) or die('Query failed: ' . pg_last_error()); - - - -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; -} -echo json_encode($array); -}} -pg_free_result($result); -} - -if (isset($_GET['countyarchive'])) { - if (isset($_GET['start']) && isset($_GET['end'])) { - try { - $starttime = pg_escape_string($_GET['start']); - $endtime = pg_escape_string($_GET['end']); - - $query = " - SELECT DISTINCT ON (county, state, update) - county, - state, - SUM(outages) as outage, - update as time, - SUM(served) as served - FROM countyoutages - WHERE update > $2 - AND update < $3 - AND cwa = $1 - GROUP BY county, state, update - "; - - $result = pg_query_params($dbconn, $query, ['RLX', $starttime, $endtime]); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $results = []; - while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $results[] = $line; - } - - header('Content-Type: application/json'); - echo json_encode($results); - - pg_free_result($result); - } catch (Exception $e) { - header('Content-Type: application/json'); - http_response_code(500); - echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]); - if (isset($result)) { - pg_free_result($result); - } - exit; - } - } else { - header('Content-Type: application/json'); - http_response_code(400); - echo json_encode(['error' => 'Both start and end parameters are required']); - } -} - - - -//Archive point data -if($_GET['archivepointold'] ?? null) { -$starttime = pg_escape_string($_GET['start']); -$endtime = pg_escape_string($_GET['end']); -$result = pg_query_params($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(realgeom)::json,'properties',json_build_object('time',startguess,'county',county,'state',state,'outage',outagen,'lastchange',lastchange,'cause',cause))order by startguess asc)) FROM power WHERE cwa = $1 and startguess > $2 and lastchange < $3", -array('RLX',$starttime,$endtime)) or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); -pg_free_result($result); - -} - -if (isset($_GET['archivepoint'])) { - try { - if (!isset($_GET['start']) || !isset($_GET['end'])) { - throw new Exception('Both start and end parameters are required'); - } - - $starttime = pg_escape_string($_GET['start']); - $endtime = pg_escape_string($_GET['end']); - - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(realgeom)::json, - 'properties', json_build_object( - 'time', startguess, - 'county', county, - 'state', state, - 'outage', outagen, - 'lastchange', lastchange, - 'cause', cause - ) - ) - ORDER BY startguess ASC - ) - ) - FROM power - WHERE cwa = $1 - AND startguess > $2 - AND lastchange < $3 - "; - - $result = pg_query_params($dbconn, $query, ['RLX', $starttime, $endtime]); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $resultArray = pg_fetch_all($result); - - header('Content-Type: application/json'); - if ($resultArray && isset($resultArray[0]['json_build_object'])) { - echo $resultArray[0]['json_build_object']; - } else { - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - } catch (Exception $e) { - header('Content-Type: application/json'); - $statusCode = strpos($e->getMessage(), 'required') !== false ? 400 : 500; - http_response_code($statusCode); - echo json_encode(['error' => $e->getMessage()]); - if (isset($result)) { - pg_free_result($result); - } - exit; - } -} - - -//if($_GET['svr']=='current') { -//$result = pg_query_params($dbconn, -//"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() and endtime > now()" -//,array('2023-01-01 01:00','2023-02-12 10:00')) or die('Query failed: ' . pg_last_error()); -//$resultArray = pg_fetch_all($result); -//echo($resultArray[0]['json_build_object']); -//} - -if(@$_GET['svr'] =='current') { -$result = pg_query($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() and endtime > now()") or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); -pg_free_result($result); -} - - - - -if(@$_GET['svr'] == 'archiveold') { -if($_GET['start'] ?? null) { -$starttime = pg_escape_string($_GET['start']); -if($_GET['end'] ?? null) { -$endtime = pg_escape_string($_GET['end']); - - -$result = pg_query_params($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue > $1 and endtime < $2" -,array($starttime,$endtime)) or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -//echo '
'; print_r($resultAarray); echo '
'; -echo($resultArray[0]['json_build_object']); -} - -} - -if(!isset($_GET['start']) && !isset($_GET['end'])) { -$result = pg_query($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() - interval '24 hours' and endtime > now() - interval '24 hours'") or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); - - -} -pg_free_result($result); -} - -if (isset($_GET['svr']) && $_GET['svr'] === 'archive') { - try { - $result = null; - - if (isset($_GET['start']) && isset($_GET['end'])) { - $starttime = pg_escape_string($_GET['start']); - $endtime = pg_escape_string($_GET['end']); - - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(nwspoly)::json, - 'properties', json_build_object( - 'issue', issue, - 'end', endtime, - 'vtec', vtec, - 'type', warntype - ) - ) - ) - ) - FROM svr - WHERE issue > $1 - AND endtime < $2 - "; - - $result = pg_query_params($dbconn, $query, [$starttime, $endtime]); - } elseif (!isset($_GET['start']) && !isset($_GET['end'])) { - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(nwspoly)::json, - 'properties', json_build_object( - 'issue', issue, - 'end', endtime, - 'vtec', vtec, - 'type', warntype - ) - ) - ) - ) - FROM svr - WHERE issue < NOW() - INTERVAL '24 hours' - AND endtime > NOW() - INTERVAL '24 hours' - "; - - $result = pg_query($dbconn, $query); - } else { - throw new Exception('Both start and end parameters are required together'); - } - - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $resultArray = pg_fetch_all($result); - - header('Content-Type: application/json'); - if ($resultArray && isset($resultArray[0]['json_build_object'])) { - echo $resultArray[0]['json_build_object']; - } else { - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - } catch (Exception $e) { - if (isset($result)) { - pg_free_result($result); - } - header('Content-Type: application/json'); - $statusCode = strpos($e->getMessage(), 'required') !== false ? 400 : 500; - http_response_code($statusCode); - echo json_encode(['error' => $e->getMessage()]); - exit; - } -} - -if($_GET['svrpolysold'] ?? null) { -$query = "select vtec,outagesvalid,polygonpop,outagesbuffer,lsrids from svr where EXTRACT(EPOCH FROM (current_timestamp - endtime ))/60/60/24 < 60"; -$result = pg_query($query) or die('Query failed: ' . pg_last_error()); -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; - -} -echo json_encode($array); - -// Free resultset -pg_free_result($result); -} - -if (isset($_GET['svrpolys'])) { - try { - $query = " - SELECT - vtec, - outagesvalid, - polygonpop, - outagesbuffer, - lsrids - FROM svr - WHERE EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - endtime)) / 60 / 60 / 24 < 60 - "; - - $result = pg_query($dbconn, $query); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $results = []; - while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $results[] = $line; - } - - header('Content-Type: application/json'); - echo json_encode($results); - - pg_free_result($result); - } catch (Exception $e) { - if (isset($result)) { - pg_free_result($result); - } - header('Content-Type: application/json'); - http_response_code(500); - echo json_encode(['error' => $e->getMessage()]); - exit; - } -} - - -if (isset($_GET['poweridsold'])) { - $powerids = $_GET['powerids']; - - // Convert the comma-separated string to an array - $poweridArray = explode(',', $powerids); - - // Sanitize and prepare array values for SQL query - $sanitizedIds = array_map('intval', $poweridArray); - - // Prepare placeholders for the query - $placeholders = implode(',', array_map(function($i) { return '$' . $i; }, range(1, count($sanitizedIds)))); - - // Set up your database connection here - - - // Prepare and execute the query with pg_query_params - $sql = "SELECT lat,lon,lastchange,startguess,peakoutage,cause,lsrtime,lsrref,(lsrtime AT TIME ZONE 'America/New_York')::timestamp as lsrlocal FROM power WHERE id IN ($placeholders)"; - $result = pg_query_params($dbconn, $sql, $sanitizedIds); - - if (!$result) { - echo 'Query failed: ' . pg_last_error(); - exit; - } - - // Fetch and output the results - $results = pg_fetch_all($result); - echo json_encode($results); - - // Free resultset - - // Close the connection - - pg_free_result($result); -} - - -if (isset($_GET['powerids'])) { - try { - $powerids = $_GET['powerids']; - - // Validate input exists and isn't empty - if (empty($powerids)) { - throw new Exception('No power IDs provided'); - } - - // Convert comma-separated string to array and sanitize - $poweridArray = explode(',', $powerids); - $sanitizedIds = array_filter(array_map('intval', $poweridArray)); - - if (empty($sanitizedIds)) { - throw new Exception('Invalid power ID format'); - } - - // Prepare placeholders for the query - $placeholders = implode(',', array_map(function($i) { return '$' . $i; }, range(1, count($sanitizedIds)))); - - $query = " - SELECT - lat, - lon, - lastchange, - startguess, - peakoutage, - cause, - lsrtime, - lsrref, - (lsrtime AT TIME ZONE 'America/New_York')::timestamp as lsrlocal - FROM power - WHERE id IN ($placeholders) - "; - - $result = pg_query_params($dbconn, $query, $sanitizedIds); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $results = pg_fetch_all($result) ?: []; - - header('Content-Type: application/json'); - echo json_encode($results); - - pg_free_result($result); - } catch (Exception $e) { - if (isset($result)) { - pg_free_result($result); - } - header('Content-Type: application/json'); - $statusCode = strpos($e->getMessage(), 'Invalid') !== false ? 400 : 500; - http_response_code($statusCode); - echo json_encode(['error' => $e->getMessage()]); - exit; - } -} - - - -if (isset($_GET['poweridsgeojsonold'])) { - $powerids = $_GET['poweridsgeojson']; - - $poweridArray = explode(',', $powerids); - - $sanitizedIds = array_map('intval', $poweridArray); - - $placeholders = implode(',', array_map(function($i) { return '$' . $i; }, range(1, count($sanitizedIds)))); - - $sql = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(realgeom)::json, - 'properties', json_build_object( - 'id', id, - 'time', (startguess AT TIME ZONE 'UTC')::timestamp, - 'county', county, - 'state', state, - 'cause', cause, - 'outage', peakoutage, - 'lsrtime', (lsrtime AT TIME ZONE 'UTC')::timestamp - ) - ) ORDER BY startguess ASC - ) - ) - FROM power - WHERE id IN ($placeholders);"; - - // $sql = "SELECT lat,lon,lastchange,startguess,peakoutage,cause,lsrtime,lsrref,(lsrtime AT TIME ZONE 'America/New_York')::timestamp as lsrlocal FROM power WHERE id IN ($placeholders)"; - $result = pg_query_params($dbconn, $sql, $sanitizedIds); - - if (!$result) { - echo 'Query failed: ' . pg_last_error(); - exit; - } - - -$resultArray = pg_fetch_all($result); - -// Output the JSON object -echo($resultArray[0]['json_build_object']); - - - - pg_free_result($result); -} - -if (isset($_GET['poweridsgeojson'])) { - try { - $powerids = $_GET['poweridsgeojson']; - - if (empty($powerids)) { - throw new Exception('No power IDs provided'); - } - - // Convert and sanitize power IDs - $poweridArray = explode(',', $powerids); - $sanitizedIds = array_filter(array_map('intval', $poweridArray)); - - if (empty($sanitizedIds)) { - throw new Exception('Invalid power ID format'); - } - - // Prepare placeholders - $placeholders = implode(',', array_map(function($i) { return '$' . $i; }, range(1, count($sanitizedIds)))); - - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(realgeom)::json, - 'properties', json_build_object( - 'id', id, - 'time', (startguess AT TIME ZONE 'UTC')::timestamp, - 'county', county, - 'state', state, - 'cause', cause, - 'outage', peakoutage, - 'lsrtime', (lsrtime AT TIME ZONE 'UTC')::timestamp - ) - ) ORDER BY startguess ASC - ) - ) - FROM power - WHERE id IN ($placeholders) - "; - - $result = pg_query_params($dbconn, $query, $sanitizedIds); - if ($result === false) { - throw new Exception('Query failed: ' . pg_last_error()); - } - - $resultArray = pg_fetch_all($result); - - header('Content-Type: application/json'); - if ($resultArray && isset($resultArray[0]['json_build_object'])) { - echo $resultArray[0]['json_build_object']; - } else { - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - } catch (Exception $e) { - if (isset($result)) { - pg_free_result($result); - } - header('Content-Type: application/json'); - $statusCode = strpos($e->getMessage(), 'Invalid') !== false ? 400 : 500; - http_response_code($statusCode); - echo json_encode(['error' => $e->getMessage()]); - exit; - } -} - - - - -// Assume $dbconn is your established PostgreSQL connection handle -// Example: $dbconn = pg_connect("host=localhost dbname=yourdb user=youruser password=yourpass"); -// if (!$dbconn) { die("Connection failed"); } - -if (isset($_GET['polygongeojson'])) { - $result = null; // Initialize result to null for catch block safety - try { - $polygonGeoJsonString = $_GET['polygongeojson']; - - if (empty($polygonGeoJsonString)) { - throw new Exception('No GeoJSON polygon provided', 400); // Use exception code for status - } - - // 1. Validate if the input is valid JSON - // We decode here primarily to check JSON validity. - // We'll pass the *original string* to PostGIS's ST_GeomFromGeoJSON for robustness. - $polygonGeoJson = json_decode($polygonGeoJsonString); - if (json_last_error() !== JSON_ERROR_NONE) { - throw new Exception('Invalid JSON format: ' . json_last_error_msg(), 400); - } - - // 2. Optional: Basic structural validation (can rely on PostGIS for full validation) - if (!is_object($polygonGeoJson) || !isset($polygonGeoJson->type) || !in_array($polygonGeoJson->type, ['MultiPolygon', 'Polygon'])) { - // Allow both Polygon and MultiPolygon for flexibility? Or stick to MultiPolygon? - // Let's allow Polygon too, as ST_Within works with both. - // If you strictly need *only* MultiPolygon, change the check. - throw new Exception('Input GeoJSON must be of type Polygon or MultiPolygon.', 400); - } - if (!isset($polygonGeoJson->coordinates) || !is_array($polygonGeoJson->coordinates)) { - throw new Exception('Input GeoJSON must have a coordinates array.', 400); - } - - // 3. Prepare the PostgreSQL Query using PostGIS functions - // - ST_GeomFromGeoJSON($1): Parses the input GeoJSON string. - // - ST_SetSRID(..., 4326): Assigns the WGS84 SRID (standard for GeoJSON). Adjust if your data uses a different SRID. - // - ST_Within(realgeom, ...): Checks if the power outage geometry is within the provided polygon geometry. - // - Ensure your 'realgeom' column has a spatial index for performance! - $query = " - SELECT json_build_object( - 'type', 'FeatureCollection', - 'features', json_agg( - json_build_object( - 'type', 'Feature', - 'geometry', ST_AsGeoJSON(realgeom)::json, - 'properties', json_build_object( - 'id', id, - 'time', (startguess AT TIME ZONE 'UTC')::timestamp, - 'county', county, - 'state', state, - 'cause', cause, - 'outage', peakoutage, - 'lsrtime', (lsrtime AT TIME ZONE 'UTC')::timestamp - ) - ) ORDER BY startguess ASC -- Optional ordering - ) - ) - FROM power - WHERE ST_Within(realgeom, ST_SetSRID(ST_GeomFromGeoJSON($1), 4326)) - "; - // Note: If 'realgeom' might be NULL, you might add "AND realgeom IS NOT NULL" - - // 4. Execute the query with the GeoJSON string as a parameter - $params = [$polygonGeoJsonString]; - $result = pg_query_params($dbconn, $query, $params); - - if ($result === false) { - // Check for specific PostGIS errors related to invalid GeoJSON input - $pgError = pg_last_error($dbconn); - if (strpos($pgError, 'invalid GeoJSON representation') !== false || strpos($pgError, 'ParseException') !== false || strpos($pgError, 'Invalid polygon') !== false) { - throw new Exception('Invalid GeoJSON geometry data provided: ' . $pgError, 400); - } else { - // Throw a generic server error for other query failures - throw new Exception('Query failed: ' . $pgError, 500); - } - } - - // 5. Fetch and Output Results - $resultArray = pg_fetch_all($result); - - header('Content-Type: application/json'); - if ($resultArray && isset($resultArray[0]['json_build_object'])) { - // Ensure null result from json_agg (no features found) returns empty array - $outputJson = $resultArray[0]['json_build_object']; - $outputData = json_decode($outputJson, true); - if (isset($outputData['features']) && $outputData['features'] === null) { - $outputData['features'] = []; - echo json_encode($outputData); - } else { - echo $outputJson; // Output the JSON directly from Postgres - } - } else { - // Should ideally be handled by the check above, but as a fallback - echo json_encode(['type' => 'FeatureCollection', 'features' => []]); - } - - pg_free_result($result); - - } catch (Exception $e) { - // 6. Error Handling - if (isset($result) && is_resource($result)) { // Check if $result is a valid resource before freeing - pg_free_result($result); - } - header('Content-Type: application/json'); - // Use exception code for status if provided (>=400), default to 500 - $statusCode = ($e->getCode() >= 400 && $e->getCode() < 600) ? $e->getCode() : 500; - http_response_code($statusCode); - echo json_encode(['error' => $e->getMessage()]); - exit; // Stop script execution after error - } -} - -// Add else block if needed for when the parameter is not set -// else { -// // Handle case where $_GET['polygongeojson'] is not present -// header('Content-Type: application/json'); -// http_response_code(400); // Bad Request -// echo json_encode(['error' => 'Required parameter "polygongeojson" is missing.']); -// exit; -// } - - - - - - - - - - - - - - - - - - - - -pg_close($dbconn); -?> diff --git a/searchapi.php b/searchapi.php deleted file mode 100644 index 130b7cb..0000000 --- a/searchapi.php +++ /dev/null @@ -1,110 +0,0 @@ - $2 and update < $3 order by update asc", -array('RLX',$starttime,$endtime)) or die('Query failed: ' . pg_last_error()); - -while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) { - $array[] = $line; -} -echo json_encode($array); -}}} - - -//Archive point data -if($_GET['archivepoint']) { -if($_GET['start']) { -$starttime = pg_escape_string($_GET['start']); -if($_GET['end']) { -$endtime = pg_escape_string($_GET['end']); -$result = pg_query_params($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(realgeom)::json,'properties',json_build_object('time',startguess,'county',county,'state',state,'outage',outagen,'lastchange',lastchange,'cause',cause))order by startguess asc)) FROM power WHERE cwa = $1 and startguess > $2 and lastchange < $3" -,array('RLX',$starttime,$endtime)) or die('Query failed: ' . pg_last_error()); - -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); - - -}}} - - - -//if($_GET['svr']=='current') { -//$result = pg_query_params($dbconn, -//"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() and endtime > now()" -//,array('2023-01-01 01:00','2023-02-12 10:00')) or die('Query failed: ' . pg_last_error()); -//$resultArray = pg_fetch_all($result); -//echo($resultArray[0]['json_build_object']); -//} - -if($_GET['svr']=='current') { -$result = pg_query($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() and endtime > now()") or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); -} - - - - -if($_GET['svr'] == 'archive') { -if($_GET['start']) { -$starttime = pg_escape_string($_GET['start']); -if($_GET['end']) { -$endtime = pg_escape_string($_GET['end']); - - -$result = pg_query_params($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue > $1 and endtime < $2" -,array($starttime,$endtime)) or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); -} -} - -if(!isset($_GET['start']) && !isset($_GET['end'])) { -$result = pg_query($dbconn, -"SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type','Feature', 'geometry', ST_AsGeoJSON(nwspoly)::json,'properties',json_build_object('issue',issue,'end',endtime,'vtec',vtec,'type',warntype)))) FROM svr where issue < now() - interval '24 hours' and endtime > now() - interval '24 hours'") or die('Query failed: ' . pg_last_error()); -$resultArray = pg_fetch_all($result); -echo($resultArray[0]['json_build_object']); - - -} -} - -pg_free_result($result); -pg_close($dbconn); -?> diff --git a/staff.html b/staff.html index eba58d8..86b17eb 100644 --- a/staff.html +++ b/staff.html @@ -255,7 +255,7 @@ } function main() { - fetchWeatherData('https://wx.stoat.org/nws.php?officestats11', function(weatherdata) { + fetchWeatherData('https://wx.stoat.org/main.php?service=nws&officestats', function(weatherdata) { if (weatherdata) { const jsonData = weatherdata; const { dates, offices, officeDateMap, titleBreakdownMap } = processData(jsonData); diff --git a/stormdata.php b/stormdata.php deleted file mode 100644 index d4e43a9..0000000 --- a/stormdata.php +++ /dev/null @@ -1,572 +0,0 @@ - 'Service temporarily unavailable due to database connection issue.']); - exit; -} - -// --- Helper Functions --- - -/** - * Sends a JSON error response and terminates the script. - * @param int $http_code The HTTP status code. - * @param string $message The error message for the client. - * @param ?string $log_message Optional detailed message for the server error log. - */ -function send_error(int $http_code, string $message, ?string $log_message = null): void { - if ($log_message) { error_log($log_message); } - elseif ($http_code >= 500) { error_log("Server Error (" . $http_code . "): " . $message); } - http_response_code($http_code); - header('Content-Type: application/json; charset=utf-8'); - echo json_encode(['error' => $message]); - exit; -} - -/** - * Sends a GeoJSON FeatureCollection response and terminates the script. - * @param array $features An array of GeoJSON Feature objects. - */ -function send_geojson(array $features): void { - $geojson_output = ['type' => 'FeatureCollection', 'features' => $features]; - header('Content-Type: application/geo+json; charset=utf-8'); - echo json_encode($geojson_output); - exit; -} - -// --- Main Request Handling --- - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - - error_log("--- New POST Request Received ---"); - $input_data = null; - $request_type = null; - $contentType = trim(strtolower($_SERVER['HTTP_CONTENT_TYPE'] ?? $_SERVER['CONTENT_TYPE'] ?? '')); - error_log("Received Content-Type: " . $contentType); - - // *********************************************************** - // ***** START: CRUCIAL JSON INPUT HANDLING BLOCK ***** - // *********************************************************** - if (strpos($contentType, 'application/json') === 0) { - error_log("Content-Type identified as JSON."); - $raw_post_data = file_get_contents('php://input'); - error_log("Raw php://input length: " . strlen($raw_post_data)); - - if ($raw_post_data === false || $raw_post_data === '') { - send_error(400, 'Received empty request body or could not read input.', "Error: Could not read php://input or it was empty."); - } - - // Decode JSON into an associative array - $input_data = json_decode($raw_post_data, true); // Use 'true' for array - - if (json_last_error() !== JSON_ERROR_NONE) { - send_error(400, 'Invalid JSON payload received.', 'JSON Decode Error: ' . json_last_error_msg() . " | Raw data snippet: " . substr($raw_post_data, 0, 100)); - } elseif (!is_array($input_data)) { - send_error(400, 'Invalid JSON payload: Expected a JSON object.', "JSON Decode Warning: Result is not an array. Data: " . print_r($input_data, true)); - } else { - error_log("JSON Decode Successful."); - // ** GET request_type FROM THE DECODED ARRAY ** - $request_type = $input_data['request_type'] ?? null; - error_log("Extracted request_type from JSON: " . ($request_type ?? 'null')); - } - } else { - // If JSON is strictly required, reject other types - send_error(415, 'Unsupported Media Type. This endpoint requires application/json.', "Unsupported Media Type Received: " . $contentType); - } - // *********************************************************** - // ***** END: CRUCIAL JSON INPUT HANDLING BLOCK ***** - // *********************************************************** - - - // --- Final Check and Routing --- - if ($request_type === null) { - if (is_array($input_data) && !isset($input_data['request_type'])) { - send_error(400, 'Missing "request_type" field within the request payload.'); - } else { - error_log("Routing check reached but request_type is null without prior exit."); - send_error(400, 'Missing required parameter: request_type (or processing error).'); - } - } - - error_log("Routing request for type: " . $request_type); - switch ($request_type) { - case 'ohgo': - // ** Pass the $input_data array ** - handle_ohgo_request($dbconn, $input_data); - break; - case 'ohgonopoly': - // ** Pass the $input_data array ** - handle_ohgo_request_no_poly($dbconn, $input_data); - break; - case 'power': - // ** Pass the $input_data array ** - handle_power_request($dbconn, $input_data); - break; - case 'powernopoly': - // ** Pass the $input_data array ** - handle_power_request_no_poly($dbconn, $input_data); - break; - case 'wupoly': - // ** Pass the $input_data array ** - handle_wu_request_poly($dbconn, $input_data); - break; - case 'campoly': - // ** Pass the $input_data array ** - handle_cam_request($dbconn, $input_data); - break; - - - - default: - send_error(400, 'Invalid request_type specified: ' . htmlspecialchars($request_type)); - break; - } - -} else { - http_response_code(405); - header('Allow: POST'); - header('Content-Type: application/json; charset=utf-8'); - echo json_encode(['error' => 'Invalid request method. Only POST is allowed.']); - exit; -} - - - - -// --- Request Handler Functions --- - - - -function handle_cam_request($dbconn, array $data): void { - error_log("Handling 'camera image' request."); - - // --- 1. Get Data from the $data array --- - $start_time_str = $data['start_time'] ?? null; - $end_time_str = $data['end_time'] ?? null; - $geojson_str = $data['area_geojson'] ?? null; - - // --- 2. Validation --- - if ($start_time_str === null || $end_time_str === null || $geojson_str === null) { - send_error(400, 'Missing required parameters for camera request: start_time, end_time, area_geojson'); - } - - // Validate Timestamps (basic check, can be more robust) - // Consider using DateTime objects for more rigorous validation if needed - if (strtotime($start_time_str) === false) { - send_error(400, 'Invalid start_time format.'); - } - if (strtotime($end_time_str) === false) { - send_error(400, 'Invalid end_time format.'); - } - // Ensure start is before end? Optional, depends on requirements. - // if (strtotime($start_time_str) >= strtotime($end_time_str)) { - // send_error(400, 'start_time must be before end_time.'); - // } - - - // Validate GeoJSON - $geojson_obj = json_decode($geojson_str); - if (json_last_error() !== JSON_ERROR_NONE) { - send_error(400, 'Invalid area_geojson provided: Contains invalid JSON string.', 'GeoJSON Decode Error: ' . json_last_error_msg()); - } - if (!is_object($geojson_obj) || !isset($geojson_obj->type) || !in_array($geojson_obj->type, ['Polygon', 'MultiPolygon'])) { - send_error(400, 'Invalid area_geojson provided: Decoded JSON must be a Polygon or MultiPolygon object.'); - } - - // --- 3. Prepare and Execute Query --- - // This query finds active cameras within the GeoJSON area, - // then LEFT JOINs aggregated image data from camdb within the time range. - // We use jsonb_agg for efficiency and COALESCE to return an empty array [] - // for cameras with no images in the range, instead of NULL. - // NOTE: Selecting c.* assumes 'geom' is not excessively large or problematic - // when fetched directly. If it is, list all columns except 'geom'. - // We explicitly fetch ST_AsGeoJSON for the geometry representation. - $query = " - SELECT - c.*, -- Select all columns from cams - ST_AsGeoJSON(c.geom) as geometry_geojson, -- Get geometry as GeoJSON string - COALESCE(img_agg.images, '[]'::jsonb) AS images -- Get aggregated images or empty JSON array - FROM - cams c - LEFT JOIN ( - SELECT - camid, - jsonb_agg( - jsonb_build_object( - 'timestamp', dateutc, - 'url', filepath -- Assuming filepath is the relative URL path - ) ORDER BY dateutc ASC -- Order images chronologically - ) AS images - FROM - camdb - WHERE - dateutc >= $1::timestamp -- start_time - AND dateutc <= $2::timestamp -- end_time - GROUP BY - camid - ) AS img_agg ON c.camid = img_agg.camid - WHERE - c.active = TRUE -- Only active cameras - AND ST_Within(c.geom, ST_GeomFromGeoJSON($3)) -- Camera location within area - ORDER BY - c.camid; -- Optional: Order cameras by ID - "; - - $params = array( - $start_time_str, // $1: start_time - $end_time_str, // $2: end_time - $geojson_str // $3: area_geojson string - ); - - $result = pg_query_params($dbconn, $query, $params); - - if (!$result) { - send_error(500, 'Database query failed for camera data.', 'Camera Query Failed: ' . pg_last_error($dbconn) . " | Query: " . $query . " | Params: " . print_r($params, true)); - } - - // --- 4. Process Results --- - $cameras_output = []; - while ($row = pg_fetch_assoc($result)) { - // Decode the geometry GeoJSON string into a PHP object/array - $geometry = json_decode($row['geometry_geojson']); - if (json_last_error() !== JSON_ERROR_NONE) { - error_log('Failed to decode geometry for camid ' . ($row['camid'] ?? 'N/A') . ': ' . json_last_error_msg()); - // Decide how to handle: skip camera, set geometry to null, etc. - $geometry = null; // Example: Set to null on error - } - - // Decode the images JSON string (from jsonb_agg) into a PHP array - $images = json_decode($row['images']); - if (json_last_error() !== JSON_ERROR_NONE) { - error_log('Failed to decode images JSON for camid ' . ($row['camid'] ?? 'N/A') . ': ' . json_last_error_msg()); - // Decide how to handle: skip camera, set images to empty array, etc. - $images = []; // Example: Set to empty array on error - } - - // Prepare the output structure for this camera - $camera_data = $row; // Start with all columns fetched via c.* - - // Replace/remove raw JSON strings and potentially the original binary geom - unset($camera_data['geometry_geojson']); // Remove the raw GeoJSON string - unset($camera_data['geom']); // Remove the raw binary geometry if it was fetched by c.* - $camera_data['geometry'] = $geometry; // Add the decoded geometry object/array - $camera_data['images'] = $images; // Add the decoded images array - - $cameras_output[] = $camera_data; - } - pg_free_result($result); - error_log("Found " . count($cameras_output) . " cameras matching criteria."); - - // --- 5. Send Response --- - // Use a function like send_json defined above, or inline the logic: - header('Content-Type: application/json'); - echo json_encode($cameras_output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - exit; // Important to stop script execution here - // Alternatively, if you have the helper: - // send_json($cameras_output); -} - -function handle_wu_request_poly($dbconn, array $data): void { // Takes $data array - -$polygons = $data['polygons'] ?? []; // Array of WKT polygons, e.g., ['POLYGON((...))', 'POLYGON((...))'] -$start_time = $data['start_time'] ?? '2025-01-01 00:00:00'; // e.g., '2025-01-01 00:00:00' -$end_time = $data['end_time'] ?? '2025-01-02 00:00:00'; // e.g., '2025-01-02 00:00:00' - -if (empty($polygons)) { - http_response_code(500); - echo json_encode(['error' => 'No polygons provided']); - pg_close($dbconn); - exit; -} - -$polygon_placeholders = []; -$params = []; -$param_index = 1; - -foreach ($polygons as $polygon) { - $polygon_placeholders[] = "ST_GeomFromText(\$$param_index, 4326)"; - $params[] = $polygon; - $param_index++; -} - -$params[] = $start_time; -$params[] = $end_time; -$start_time_placeholder = "\$$param_index"; -$param_index++; -$end_time_placeholder = "\$$param_index"; - -$polygon_sql = implode(', ', $polygon_placeholders); - -$sql = " - SELECT wo.* - FROM wuobs wo - JOIN wusites ws ON wo.stationid = ws.stationid - WHERE ws.geom && ST_Union(ARRAY[$polygon_sql])::geometry - AND ST_Within(ws.geom, ST_Union(ARRAY[$polygon_sql])::geometry) - AND wo.observation_time BETWEEN $start_time_placeholder AND $end_time_placeholder -"; - -$result = pg_query_params($dbconn, $sql, $params); - -if ($result === false) { - http_response_code(500); - echo json_encode(['error' => pg_last_error($dbconn)]); - pg_close($dbconn); - exit; -} - -// Fetch results -$results = []; -while ($row = pg_fetch_assoc($result)) { - $results[] = $row; -} - -// Free result and close connection -pg_free_result($result); - -// Output results as JSON -header('Content-Type: application/json'); -echo json_encode($results); -} - -/** - * Handles the 'ohgo' data request. - * @param resource $dbconn The active database connection resource. - * @param array $data The associative array of input parameters (from JSON). - */ -function handle_ohgo_request($dbconn, array $data): void { // Takes $data array - error_log("Handling 'ohgo' request."); - // --- 1. Get Data from the $data array --- - $start = $data['start_time'] ?? null; // Use $data, use correct key - $geojson_str = $data['area_geojson'] ?? null; // Use $data, not $_POST - $end = $data['end_time'] ?? null; // Use $data, use correct key - - // --- 2. Validation --- - if ($start === null || $geojson_str === null || $end === null) { send_error(400, 'Missing required parameters for ohgo request: start, geojson, end'); } - $geojson_obj = json_decode($geojson_str); - if (json_last_error() !== JSON_ERROR_NONE) { send_error(400, 'Invalid GeoJSON provided: Not valid JSON.', 'GeoJSON Decode Error: ' . json_last_error_msg()); } - if (!isset($geojson_obj->type) || !in_array($geojson_obj->type, ['Polygon', 'MultiPolygon'])) { send_error(400, 'Invalid GeoJSON provided: Type must be Polygon or MultiPolygon.'); } - - // --- 3. Prepare and Execute Query --- - $query = "SELECT ST_AsGeoJSON(geom) AS geometry, category, roadstatus, county, state, location, routename, description, start AS start_timestamp, endtime AS end_timestamp, lastupdate FROM ohgo WHERE start > $1::timestamp AND start < $3::timestamp AND ST_Within(geom, ST_GeomFromGeoJSON($2)) ORDER BY start ASC"; - $params = array($start, $geojson_str, $end); - $result = pg_query_params($dbconn, $query, $params); - if (!$result) { send_error(500, 'Database query failed for ohgo data.', 'OHGO Query Failed: ' . pg_last_error($dbconn)); } - - // --- 4. Process Results --- - $features = []; - while ($line = pg_fetch_assoc($result)) { - $geometry = json_decode($line['geometry']); - if (json_last_error() !== JSON_ERROR_NONE) { error_log('Failed to decode geometry for ohgo row: ' . json_last_error_msg()); continue; } - $properties = $line; unset($properties['geometry']); - $features[] = ['type' => 'Feature', 'geometry' => $geometry, 'properties' => $properties]; - } - pg_free_result($result); - error_log("Found " . count($features) . " features for ohgo request."); - - // --- 5. Send Response --- - send_geojson($features); -} - - -/** - * Handles the 'power' data request. - * @param resource $dbconn The active database connection resource. - * @param array $data The associative array of input parameters (from JSON). - */ -function handle_power_request($dbconn, array $data): void { // Takes $data array - error_log("Handling 'power' request."); - // --- 1. Get Data from the $data array --- - // ** Match keys from your fetch request body: start_time, area_geojson, etc. ** - $start = $data['start_time'] ?? null; // Use $data, use correct key - $geojson_str = $data['area_geojson'] ?? null; // Use $data, use correct key - $end = $data['end_time'] ?? null; // Use $data, use correct key - $buffer_hours = $data['buffer'] ?? 0;// Use $data, use correct key - - // --- 2. Validation --- - if ($start === null || $geojson_str === null || $end === null || $buffer_hours === null) { - // Update error message to reflect the actual keys expected from JSON - send_error(400, 'Missing required parameters for power request: start_time, area_geojson, end_time, buffer_hours'); - } - if (!is_numeric($buffer_hours) || ($buffer_hours_float = floatval($buffer_hours)) < 0) { send_error(400, 'Invalid buffer_hours provided: Must be a non-negative number.'); } - $buffer_hours_int = (int)$buffer_hours_float; - $geojson_obj = json_decode($geojson_str); // Decode the *string* value from the JSON input - if (json_last_error() !== JSON_ERROR_NONE) { send_error(400, 'Invalid area_geojson provided: Contains invalid JSON string.', 'GeoJSON Decode Error: ' . json_last_error_msg()); } - if (!is_object($geojson_obj) || !isset($geojson_obj->type) || !in_array($geojson_obj->type, ['Polygon', 'MultiPolygon'])) { send_error(400, 'Invalid area_geojson provided: Decoded JSON must be a Polygon or MultiPolygon object.'); } - // ** Crucial Fix: Use the decoded $geojson_str for the query parameter, not $geojson_obj ** - - // --- 3. Prepare and Execute Query --- - // ** VERIFY TABLE/COLUMN NAMES FOR POWER TABLE ** - $query = "SELECT ST_AsGeoJSON(realgeom) AS geometry, derivedstart AS start_timestamp, cause, peakoutage, lastchange AS end_timestamp FROM power WHERE derivedstart >= $1::timestamp AND derivedstart < ($3::timestamp + make_interval(hours => $4::integer)) AND ST_Within(realgeom, ST_GeomFromGeoJSON($2)) ORDER BY derivedstart ASC"; - $params = array( - $start, // $1: start_time from JSON - $geojson_str, // $2: area_geojson STRING from JSON - $end, // $3: end_time from JSON - $buffer_hours_int // $4: buffer_hours from JSON (as integer) - ); - $result = pg_query_params($dbconn, $query, $params); - if (!$result) { send_error(500, 'Database query failed for power data.', 'Power Query Failed: ' . pg_last_error($dbconn) . " | Query: " . $query . " | Params: " . print_r($params, true)); } - - // --- 4. Process Results --- - $features = []; - while ($line = pg_fetch_assoc($result)) { - $geometry = json_decode($line['geometry']); - if (json_last_error() !== JSON_ERROR_NONE) { error_log('Failed to decode geometry for power row: ' . json_last_error_msg()); continue; } - $properties = $line; unset($properties['geometry']); - $features[] = ['type' => 'Feature', 'geometry' => $geometry, 'properties' => $properties]; - } - pg_free_result($result); - error_log("Found " . count($features) . " features for power request."); - - // --- 5. Send Response --- - send_geojson($features); -} - - -/** - * Handles the 'ohgo' data request. - * @param resource $dbconn The active database connection resource. - * @param array $data The associative array of input parameters (from JSON). - */ -function handle_ohgo_request_no_poly($dbconn, array $data): void { // Takes $data array - error_log("Handling 'ohgo' request."); - // --- 1. Get Data from the $data array --- - $start = $data['start_time'] ?? null; // Use $data, use correct key - - $end = $data['end_time'] ?? null; // Use $data, use correct key - - // --- 2. Validation --- - if ($start === null || $end === null) { send_error(400, 'Missing required parameters for ohgo request: start, geojson, end'); } - - // --- 3. Prepare and Execute Query --- - $query = "SELECT ST_AsGeoJSON(geom) AS geometry, county, state AS st, location, routename AS city, upper(cwa) AS wfo, 'FLOOD' AS typetext, 'Department of Highways' AS source, description AS remark, - TO_CHAR(start, 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') AS valid - FROM ohgo - WHERE start > $1::timestamp - AND start < $2::timestamp - AND cwa = 'RLX' - ORDER BY start ASC"; - $params = array($start, $end); - $result = pg_query_params($dbconn, $query, $params); - if (!$result) { send_error(500, 'Database query failed for ohgo data.', 'OHGO Query Failed: ' . pg_last_error($dbconn)); } - - // --- 4. Process Results --- - $features = []; - while ($line = pg_fetch_assoc($result)) { - $geometry = json_decode($line['geometry']); - if (json_last_error() !== JSON_ERROR_NONE) { error_log('Failed to decode geometry for ohgo row: ' . json_last_error_msg()); continue; } - $properties = $line; unset($properties['geometry']); - $features[] = ['type' => 'Feature', 'geometry' => $geometry, 'properties' => $properties]; - } - pg_free_result($result); - error_log("Found " . count($features) . " features for ohgo request."); - - // --- 5. Send Response --- - send_geojson($features); -} - - -/** - * Handles the 'power' data request. - * @param resource $dbconn The active database connection resource. - * @param array $data The associative array of input parameters (from JSON). - */ -function handle_power_request_no_poly($dbconn, array $data): void { // Takes $data array - error_log("Handling 'power' request."); - // --- 1. Get Data from the $data array --- - // ** Match keys from your fetch request body: start_time, area_geojson, etc. ** - $start = $data['start_time'] ?? null; // Use $data, use correct key - $end = $data['end_time'] ?? null; // Use $data, use correct key - $outage_threshold = $data['outage_threshold'] ?? 9; - $buffer_hours = $data['buffer'] ?? 0;// Use $data, use correct key - - // --- 2. Validation --- - if ($start === null || $end === null || $buffer_hours === null) { - // Update error message to reflect the actual keys expected from JSON - send_error(400, 'Missing required parameters for power request: start_time, area_geojson, end_time, buffer_hours'); - } - if (!is_numeric($buffer_hours) || ($buffer_hours_float = floatval($buffer_hours)) < 0) { send_error(400, 'Invalid buffer_hours provided: Must be a non-negative number.'); } - $buffer_hours_int = (int)$buffer_hours_float; - $outage_thresh = (float)$outage_threshold; - - - - - // --- 3. Prepare and Execute Query --- - // ** VERIFY TABLE/COLUMN NAMES FOR POWER TABLE ** - $query = "SELECT ST_AsGeoJSON(realgeom) AS geometry, - TO_CHAR(derivedstart, 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') AS valid, - ('Power Outage affecting ' || peakoutage || ' customers caused by ' || COALESCE(cause, 'unknown')) AS remark, - 'Utility Company' as source, - 'POWER OUTAGE' as typetext, - 'U' as type, - (ROUND(ST_Y(realgeom)::numeric, 3) || ', ' || ROUND(ST_X(realgeom)::numeric, 3)) AS city, - county as county, - state as state, - state as st - FROM power - WHERE derivedstart >= $1::timestamp - AND derivedstart < ($2::timestamp + make_interval(hours => $3::integer)) - and peakoutage > $4 - AND ST_Within(realgeom, (SELECT geom FROM public.cwa WHERE cwa = 'RLX')) - ORDER BY derivedstart ASC"; - - - - - - $params = array( - $start, // $1: start_time from JSON - $end, // $2: end_time from JSON - $buffer_hours_int, // $3: buffer_hours from JSON (as integer) - $outage_thresh // $4 - ); - $result = pg_query_params($dbconn, $query, $params); - if (!$result) { send_error(500, 'Database query failed for power data.', 'Power Query Failed: ' . pg_last_error($dbconn) . " | Query: " . $query . " | Params: " . print_r($params, true)); } - - // --- 4. Process Results --- - $features = []; - while ($line = pg_fetch_assoc($result)) { - $geometry = json_decode($line['geometry']); - if (json_last_error() !== JSON_ERROR_NONE) { error_log('Failed to decode geometry for power row: ' . json_last_error_msg()); continue; } - $properties = $line; unset($properties['geometry']); - $features[] = ['type' => 'Feature', 'geometry' => $geometry, 'properties' => $properties]; - } - pg_free_result($result); - error_log("Found " . count($features) . " features for power request."); - - // --- 5. Send Response --- - send_geojson($features); -} - - - - - - - - - - - -// --- Close Database Connection --- -if ($dbconn) { - pg_close($dbconn); - error_log("Database connection closed."); -} - -?> \ No newline at end of file diff --git a/stormdata_SERVERMAP.html b/stormdata_SERVERMAP.html index cde7f14..6da4e19 100644 --- a/stormdata_SERVERMAP.html +++ b/stormdata_SERVERMAP.html @@ -1030,7 +1030,7 @@ function formatDate_MMDD_HHMM(dateString) { $(document).ready(function() { // Ensure map initialization and initial data load happen first initializeMap(); - loadCountyLayer('https://wx.stoat.org/ver.php'); + loadCountyLayer('https://wx.stoat.org/main.php?service=ver'); }); // End $(document).ready() diff --git a/stormdata_backup.html b/stormdata_backup.html index 8ee28d4..1d80917 100644 --- a/stormdata_backup.html +++ b/stormdata_backup.html @@ -2685,7 +2685,7 @@ function generateLsrCsv() { // --- Event Listener for Filtering the Event List --- $(document).ready(function() { initializeMap(); - loadCountyLayer('ver.php'); // URL providing county/zone GeoJSON + loadCountyLayer('main.php?service=ver'); // URL providing county/zone GeoJSON getwwas(); // Initial load for VTEC events disableExportButtons(); // Start with export buttons disabled // Attach the input event listener to the filter box diff --git a/summary.html b/summary.html index c5c248e..0da055a 100644 --- a/summary.html +++ b/summary.html @@ -42,9 +42,9 @@ function rackandstack() { var start = document.getElementById("start").value; var end = document.getElementById("end").value; -$.getJSON(`powerapi.php?max=potato&start=${start}&end=${end}`, function(data) { +$.getJSON(`main.php?service=powerapi&max=potato&start=${start}&end=${end}`, function(data) { -$.getJSON('powerapi.php?county=r', function(data1) { +$.getJSON('main.php?service=powerapi&county=r', function(data1) { countylist(data,data1); }); diff --git a/svr.html b/svr.html index 2751f4a..7861f43 100644 --- a/svr.html +++ b/svr.html @@ -44,7 +44,7 @@ $.getJSON(url, function(json) { lsrdata = json; console.log("LSR Data Loaded:", lsrdata.events.features.length, "events"); }).done(function() { - table.setData("powerapi.php?svrpolys=potato"); + table.setData("main.php?service=powerapi&svrpolys=potato"); table.setSort([ {column:"vtec", dir: "desc"}, ]); @@ -82,7 +82,7 @@ function findFeatureById(featureCollection, id) { } function reloadData() { - table.replaceData("powerapi.php?svrpolys=potato"); + table.replaceData("main.php?service=powerapi&svrpolys=potato"); table.setSort([ {column:"vtec", dir: "desc"}, ]); diff --git a/test.html b/test.html index cf2c30f..9dc7b9e 100644 --- a/test.html +++ b/test.html @@ -888,7 +888,7 @@ var geoJSONcounties = L.geoJSON(false, { //var countiesjson = 'rlxtest.json' -var countiesjson = 'https://wx.stoat.org/ver.php' +var countiesjson = 'https://wx.stoat.org/main.php?service=ver' @@ -1270,7 +1270,7 @@ var geoJSONwwa1 = L.geoJSON(false, { }).addTo(mymap); - $.getJSON('https://wx.stoat.org/ver.php', function(data) { + $.getJSON('https://wx.stoat.org/main.php?service=verp', function(data) { var geojsonFeature = data; geoJSONwwa1.addData(geojsonFeature); diff --git a/test3.html b/test3.html index 45456cf..3f45d87 100644 --- a/test3.html +++ b/test3.html @@ -128,7 +128,7 @@ create hydrograph as static image for flood Points find hydrographs in areals and plot Link for hydrographs Link to severe polygon on power outage -https://wx.stoat.org/powerapi.php?svrpolys=potato +https://wx.stoat.org/main.php?service=powerapi&svrpolys=potato https://waterservices.usgs.gov/nwis/iv/?format=json&bBox=-83.254395,36.932330,-78.508301,40.145289¶meterCd=00065&siteType=ST -83.254395,36.932330,-78.508301,40.145289 https://api.water.noaa.gov/nwps/v1/gauges?bbox.xmin=-83.254395&bbox.ymin=36.932330&bbox.xmax=-78.508301&bbox.ymax=40.145289&srid=EPSG_4326&catfim=false @@ -203,7 +203,7 @@ var mymap = L.map('mapid', {zoomDelta: 0.25, zoomSnap: 0}).setView([38.508, -82. -var countiesjson = 'https://wx.stoat.org/ver.php' +var countiesjson = 'https://wx.stoat.org/main.php?service=ver' diff --git a/update_field.php b/update_field.php deleted file mode 100644 index 66739f5..0000000 --- a/update_field.php +++ /dev/null @@ -1,41 +0,0 @@ - false, 'message' => 'Invalid input']); - exit; -} - -// Check if the field is valid -if (!in_array($field, ['hydro', 'airport'])) { - echo json_encode(['success' => false, 'message' => 'Invalid field']); - exit; -} - -// Convert to proper boolean for PostgreSQL -// JavaScript sends true/false as strings 'true' or 'false' -$value_bool = ($value === 'true'); - -// Update the field value in the database - use boolean directly -// PostgreSQL accepts 't'/'f' for boolean values -$query = "UPDATE cams SET $field = $1 WHERE camid = $2"; -$result = pg_query_params($dbconn, $query, array($value_bool ? 't' : 'f', $camid)); - -if ($result) { - echo json_encode(['success' => true]); -} else { - $error = pg_last_error($dbconn); - echo json_encode(['success' => false, 'message' => $error]); -} - -// Closing connection -pg_close($dbconn); -?> diff --git a/ver.php b/ver.php deleted file mode 100644 index ca12ef9..0000000 --- a/ver.php +++ /dev/null @@ -1,140 +0,0 @@ - diff --git a/vermap.html b/vermap.html index a1964aa..8ad4a17 100644 --- a/vermap.html +++ b/vermap.html @@ -140,7 +140,7 @@ function resetmap() { $.get({ - url: 'ver.php?reset=potato', + url: 'main.php?service=ver&reset=potato', success: function () { geoJSONcounties.setStyle({ fillColor: 'red' }); // Reset visually immediately loadlsr(); // Reload data from server @@ -211,7 +211,7 @@ // Optional: Add logic to cap the max value if needed (e.g., if (newLsr > 2) newLsr = 2;) $.get({ - url: `ver.php?lsrs=potato&zone=${zone}&lsr=${newLsr}&dir=1`, // dir=1 seems specific to 'up' + url: `main.php?service=ver&lsrs=potato&zone=${zone}&lsr=${newLsr}&dir=1`, // dir=1 seems specific to 'up' success: function () { layer.setStyle({ fillColor: vercolor(newLsr) }); // No need to call loadlsr() here, the server state is updated, @@ -232,7 +232,7 @@ var newLsr = 0; // Reset to red $.get({ - url: `ver.php?lsrs=potato&zone=${zone}&lsr=${newLsr}`, // No dir needed? Or specific dir for reset? + url: `main.php?service=ver&lsrs=potato&zone=${zone}&lsr=${newLsr}`, // No dir needed? Or specific dir for reset? success: function () { layer.setStyle({ fillColor: vercolor(newLsr) }); // No need to call loadlsr() here @@ -254,7 +254,7 @@ update_position_timeout = null; // Best practice to nullify after clearing } - $.getJSON('https://wx.stoat.org/ver.php?lsrslist=potato') + $.getJSON('https://wx.stoat.org/main.php?service=ver&lsrslist=potato') .done(function (data) { if (data && data.length > 0) { var zoneData = {}; @@ -293,7 +293,7 @@ // var countiesjson = 'rlxtest.json'; // Local testing - var countiesjson = 'https://wx.stoat.org/ver.php'; // Production endpoint + var countiesjson = 'https://wx.stoat.org/main.php?service=ver'; // Production endpoint function initial_county_load() { geoJSONcounties.clearLayers(); diff --git a/warntrack.html b/warntrack.html index fb5747e..db58536 100644 --- a/warntrack.html +++ b/warntrack.html @@ -151,7 +151,7 @@ olddiv.innerHTML = ''; -$.getJSON('warntrack.php', function(data){ +$.getJSON('main.php?service=warntrack', function(data){ // console.log(data); //check if data has no data if (data.features != null) { @@ -176,7 +176,7 @@ function refresh_data() { //{ // elem.parentNode.removeChild(elem); //} -$.getJSON('warntrack.php', function(data){ +$.getJSON('main.php?service=warntrack', function(data){ // console.log(data); //check if data has no data if (data.features != null) { @@ -338,7 +338,7 @@ return color function update_position() { //initial_county_load(); - $.getJSON('warntrack.php', function(data2) { + $.getJSON('main.php?service=warntrack', function(data2) { var geojsonsvr = data2; geoJSONsvr.clearLayers(); geoJSONsvr.addData(geojsonsvr); diff --git a/warntrack.php b/warntrack.php deleted file mode 100644 index 105d485..0000000 --- a/warntrack.php +++ /dev/null @@ -1,19 +0,0 @@ -