From eba653605011db9ab1e661410c88f77178a3f801 Mon Sep 17 00:00:00 2001 From: John Peck Date: Tue, 9 Dec 2025 00:20:32 +0000 Subject: [PATCH] consolidate php --- 511.html | 6 +- API_DOCUMENTATION.md | 278 ++++ admin.html | 4 +- admin.php | 61 - cam.php | 26 - camapi.php | 102 -- camcircle.php | 43 - camlist.php | 56 - cams.html | 8 +- circlemap.html | 2 +- db.html | 6 +- db.php | 179 --- fire.php | 16 - individualcam.php | 53 - lsr.php | 825 ---------- lsrtool.html | 4 +- main.php | 3119 ++++++++++++++++++++++++++++++++++++++ map.html | 4 +- metar.html | 2 +- mp4.php | 73 - news.html | 6 +- news2.html | 6 +- nws.php | 411 ----- ohgo.html | 6 +- ohgo.php | 26 - one.php | 12 +- outage.html | 21 +- outagemap.html | 1103 -------------- power.php | 24 - powerapi.php | 967 ------------ searchapi.php | 110 -- staff.html | 2 +- stormdata.php | 572 ------- stormdata_SERVERMAP.html | 2 +- stormdata_backup.html | 2 +- summary.html | 4 +- svr.html | 4 +- test.html | 4 +- test3.html | 4 +- update_field.php | 41 - ver.php | 140 -- vermap.html | 10 +- warntrack.html | 6 +- warntrack.php | 19 - 44 files changed, 3458 insertions(+), 4911 deletions(-) create mode 100644 API_DOCUMENTATION.md delete mode 100644 admin.php delete mode 100644 cam.php delete mode 100644 camapi.php delete mode 100644 camcircle.php delete mode 100644 camlist.php delete mode 100644 db.php delete mode 100644 fire.php delete mode 100644 individualcam.php delete mode 100644 lsr.php create mode 100644 main.php delete mode 100644 mp4.php delete mode 100755 nws.php delete mode 100644 ohgo.php delete mode 100644 outagemap.html delete mode 100644 power.php delete mode 100644 powerapi.php delete mode 100644 searchapi.php delete mode 100644 stormdata.php delete mode 100644 update_field.php delete mode 100644 ver.php delete mode 100644 warntrack.php 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 @@ -