This commit is contained in:
2025-12-10 02:18:45 +00:00
parent 4997c3d85b
commit 4aba2c4273
7 changed files with 688 additions and 0 deletions

138
main2.php Normal file
View File

@@ -0,0 +1,138 @@
<?php
/**
* Unified API Gateway
*
* This file serves as a single entry point for all API services.
* Each route is identified by the 'service' parameter.
*
* Available routes:
* - service=cams: Returns active camera information
* - service=camapi: Returns camera API endpoints with filtering
* - service=camlist: Returns camera list with active status
* - service=admin: Admin operations for cameras
* - service=camcircle: Returns camera coverage circles
* - service=db: Returns weather station data
* - service=fire: Returns fire information
* - service=individualcam: Returns individual camera images
* - service=lsr: Returns local storm reports
* - service=nws: Returns NWS personnel stats
* - service=powerapi: Returns power outage information
* - service=searchapi: Returns search results for power outages
* - service=ohgo: Returns Ohio traffic information
* - service=power: Returns power outage information
* - service=stormdata: Returns storm data
* - service=warntrack: Returns warning tracking data
* - service=ver: Returns version information
* - service=update_field: Updates table fields
* - service=mp4: Returns MP4 video information
* - service=camobs: Returns camera observations with radius and bbox filtering
* - service=single: Returns single camera information by camid
* - service=powerapitest: Returns extended power outage testing data
*
* Migration instructions:
* To migrate from the old scripts to the new unified API:
*
* Old endpoint: cam.php
* New endpoint: main.php?service=cams
*
* Old endpoint: camapi.php?cams&lat1=...&lon1=...&lat2=...&lon2=...
* New endpoint: main.php?service=camapi&cams&lat1=...&lon1=...&lat2=...&lon2=...
*
* Old endpoint: camlist.php
* New endpoint: main.php?service=camlist
*
* Old endpoint: admin.php?action=...
* New endpoint: main.php?service=admin&action=...
*
* Old endpoint: camcircle.php
* New endpoint: main.php?service=camcircle
*
* Old endpoint: camobs.php
* New endpoint: main.php?service=camobs
*
* Old endpoint: single.php?camid=...
* New endpoint: main.php?service=single&camid=...
*
* Old endpoint: powerapitest.php
* New endpoint: main.php?service=powerapitest
*
* Old endpoint: db.php
* New endpoint: main.php?service=db
*
* Old endpoint: db.php?outside
* New endpoint: main.php?service=db&outside
*
* Old endpoint: fire.php
* New endpoint: main.php?service=fire
*
* Old endpoint: individualcam.php?camid=...
* New endpoint: main.php?service=individualcam&camid=...
*
* Old endpoint: lsr.php
* New endpoint: main.php?service=lsr
*
* Old endpoint: lsr.php?ohgo
* New endpoint: main.php?service=lsr&ohgo
*
* Old endpoint: nws.php
* New endpoint: main.php?service=nws
*
* Old endpoint: nws.php?officestats
* New endpoint: main.php?service=nws&officestats
*
* Old endpoint: powerapi.php
* New endpoint: main.php?service=powerapi
*
* Old endpoint: powerapi.php?states
* New endpoint: main.php?service=powerapi&states
*
* Old endpoint: searchapi.php
* New endpoint: main.php?service=searchapi
*
* Old endpoint: ohgo.php
* New endpoint: main.php?service=ohgo
*
* Old endpoint: power.php
* New endpoint: main.php?service=power
*
* Old endpoint: stormdata.php
* New endpoint: main.php?service=stormdata
*
* Old endpoint: warntrack.php
* New endpoint: main.php?service=warntrack
*
* Old endpoint: ver.php
* New endpoint: main.php?service=ver
*
* Old endpoint: update_field.php?table=...&field=...&value=...&where=...
* New endpoint: main.php?service=update_field&table=...&field=...&value=...&where=...
*
* Old endpoint: mp4.php?camid=...
* New endpoint: main.php?service=mp4&camid=...
*/
// Get the service parameter to determine which function to execute
$service = $_GET['service'] ?? 'default';
// Route to the appropriate service file
$serviceFile = __DIR__ . '/php/' . $service . '.php';
if (file_exists($serviceFile)) {
require_once $serviceFile;
} else {
// Default behavior - show available services if no valid service provided
header('Content-Type: application/json');
http_response_code(400);
echo json_encode([
'error' => 'Invalid service parameter. Please provide a valid service.',
'available_services' => [
'cams', 'camapi', 'camlist', 'admin', 'camcircle',
'db', 'fire', 'individualcam', 'lsr', 'nws',
'powerapi', 'searchapi', 'ohgo', 'power',
'stormdata', 'warntrack', 'ver', 'update_field', 'mp4',
'camobs', 'single', 'powerapitest'
],
'documentation' => 'See main.php file for detailed documentation on each service.'
]);
}
?>

144
php/main.php Normal file
View File

@@ -0,0 +1,144 @@
<?php
/**
* Unified API Gateway
*
* This file serves as a single entry point for all API services.
* Each route is identified by the 'service' parameter.
*
* Available routes:
* - service=cams: Returns active camera information
* - service=camapi: Returns camera API endpoints with filtering
* - service=camlist: Returns camera list with active status
* - service=admin: Admin operations for cameras
* - service=camcircle: Returns camera coverage circles
* - service=db: Returns weather station data
* - service=fire: Returns fire information
* - service=individualcam: Returns individual camera images
* - service=lsr: Returns local storm reports
* - service=nws: Returns NWS personnel stats
* - service=powerapi: Returns power outage information
* - service=searchapi: Returns search results for power outages
* - service=ohgo: Returns Ohio traffic information
* - service=newpower: Returns power outage information from the new schema
* - service=newpowerapi: Returns power outage information from the new schema
* - service=newpowerapitest: Returns extended power outage testing data from the new schema
* - service=newsearchapi: Returns search results for power outages from the new schema
* - service=newstormdata: Returns storm data from the new schema
* - service=power: Returns power outage information
* - service=stormdata: Returns storm data
* - service=warntrack: Returns warning tracking data
* - service=ver: Returns version information
* - service=update_field: Updates table fields
* - service=mp4: Returns MP4 video information
* - service=camobs: Returns camera observations with radius and bbox filtering
* - service=single: Returns single camera information by camid
* - service=powerapitest: Returns extended power outage testing data
*
* Migration instructions:
* To migrate from the old scripts to the new unified API:
*
* Old endpoint: cam.php
* New endpoint: main.php?service=cams
*
* Old endpoint: camapi.php?cams&lat1=...&lon1=...&lat2=...&lon2=...
* New endpoint: main.php?service=camapi&cams&lat1=...&lon1=...&lat2=...&lon2=...
*
* Old endpoint: camlist.php
* New endpoint: main.php?service=camlist
*
* Old endpoint: admin.php?action=...
* New endpoint: main.php?service=admin&action=...
*
* Old endpoint: camcircle.php
* New endpoint: main.php?service=camcircle
*
* Old endpoint: camobs.php
* New endpoint: main.php?service=camobs
*
* Old endpoint: single.php?camid=...
* New endpoint: main.php?service=single&camid=...
*
* Old endpoint: powerapitest.php
* New endpoint: main.php?service=powerapitest
*
* Old endpoint: db.php
* New endpoint: main.php?service=db
*
* Old endpoint: db.php?outside
* New endpoint: main.php?service=db&outside
*
* Old endpoint: fire.php
* New endpoint: main.php?service=fire
*
* Old endpoint: individualcam.php?camid=...
* New endpoint: main.php?service=individualcam&camid=...
*
* Old endpoint: lsr.php
* New endpoint: main.php?service=lsr
*
* Old endpoint: lsr.php?ohgo
* New endpoint: main.php?service=lsr&ohgo
*
* Old endpoint: nws.php
* New endpoint: main.php?service=nws
*
* Old endpoint: nws.php?officestats
* New endpoint: main.php?service=nws&officestats
*
* Old endpoint: powerapi.php
* New endpoint: main.php?service=powerapi
*
* Old endpoint: powerapi.php?states
* New endpoint: main.php?service=powerapi&states
*
* Old endpoint: searchapi.php
* New endpoint: main.php?service=searchapi
*
* Old endpoint: ohgo.php
* New endpoint: main.php?service=ohgo
*
* Old endpoint: power.php
* New endpoint: main.php?service=power
*
* Old endpoint: stormdata.php
* New endpoint: main.php?service=stormdata
*
* Old endpoint: warntrack.php
* New endpoint: main.php?service=warntrack
*
* Old endpoint: ver.php
* New endpoint: main.php?service=ver
*
* Old endpoint: update_field.php?table=...&field=...&value=...&where=...
* New endpoint: main.php?service=update_field&table=...&field=...&value=...&where=...
*
* Old endpoint: mp4.php?camid=...
* New endpoint: main.php?service=mp4&camid=...
*/
// Get the service parameter to determine which function to execute
$service = $_GET['service'] ?? 'default';
// Route to the appropriate service file
$serviceFile = __DIR__ . '/php/' . $service . '.php';
if (file_exists($serviceFile)) {
require_once $serviceFile;
} else {
// Default behavior - show available services if no valid service provided
header('Content-Type: application/json');
http_response_code(400);
echo json_encode([
'error' => 'Invalid service parameter. Please provide a valid service.',
'available_services' => [
'cams', 'camapi', 'camlist', 'admin', 'camcircle',
'db', 'fire', 'individualcam', 'lsr', 'nws',
'powerapi', 'searchapi', 'ohgo', 'power', 'newpower',
'newpowerapi', 'newpowerapitest', 'newsearchapi', 'newstormdata',
'stormdata', 'warntrack', 'ver', 'update_field', 'mp4',
'camobs', 'single', 'powerapitest'
],
'documentation' => 'See main.php file for detailed documentation on each service.'
]);
}
?>

25
php/newpower.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
require_once __DIR__ . '/common.php';
header('Content-Type: application/json');
$dbconn = getDBConnection();
try {
$query = "SELECT lat, lon, outagen FROM newpower WHERE active = true AND cwa = 'RLX'";
$result = pg_query($dbconn, $query);
if ($result === false) {
throw new Exception('Query failed: ' . pg_last_error());
}
$data = pg_fetch_all($result) ?: [];
echo json_encode($data);
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
} finally {
pg_close($dbconn);
}
?>

98
php/newpowerapi.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
require_once __DIR__ . '/common.php';
header('Content-Type: application/json');
$dbconn = getDBConnection();
// Default endpoint: Get current point outages
if (empty($_GET)) {
try {
$query = "
SELECT json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(geom)::json,
'properties', json_build_object(
'time', start_time,
'county', county,
'state', state,
'outage', outagen,
'lastchange', last_change,
'cause', cause,
'area_geometry', ST_AsGeoJSON(COALESCE(realareageom, geom))::json
)
)
ORDER BY start_time ASC
)
) as geojson
FROM newpower
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_assoc($result);
if ($resultArray && $resultArray['geojson']) {
echo $resultArray['geojson'];
} else {
echo json_encode(['type' => 'FeatureCollection', 'features' => []]);
}
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
die(json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]));
}
}
// Get current county outages
if (isset($_GET['county'])) {
try {
$query = "
WITH latest_fetch AS (
SELECT MAX(fetch_time) as max_fetch_time FROM newcountyoutages
)
SELECT
n.county,
n.state,
n.outages as outage,
n.fetch_time as time,
n.served,
CASE
WHEN n.served > 0 THEN ROUND(CAST((n.outages::FLOAT / n.served) * 100 AS NUMERIC), 2)
ELSE 0
END as perout
FROM newcountyoutages n, latest_fetch
WHERE n.fetch_time = latest_fetch.max_fetch_time
AND n.cwa = $1
";
$result = pg_query_params($dbconn, $query, ['RLX']);
if ($result === false) {
throw new Exception('Query failed: ' . pg_last_error());
}
$results = pg_fetch_all($result) ?: [];
echo json_encode($results);
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]);
}
}
// Note: Other endpoints from the original powerapi.php can be migrated here as needed,
// such as 'states', 'max', 'countyarchive', 'archivepoint', 'svr', 'svrpolys',
// 'powerids', 'poweridsgeojson', and 'polygongeojson'.
// The queries would need to be updated to use the 'newpower' and 'newcountyoutages' tables
// and their corresponding columns (e.g., start_time, geom, fetch_time).
pg_close($dbconn);
?>

47
php/newpowerapitest.php Normal file
View File

@@ -0,0 +1,47 @@
<?php
require_once __DIR__ . '/common.php';
header('Content-Type: application/json');
$dbconn = getDBConnection();
if (isset($_GET['county'])) {
try {
$cwas = ['RLX','JKL','ILN','PBZ','MRX','LWX','RNK'];
$placeholders = implode(',', array_map(function($i) { return '$' . $i; }, range(1, count($cwas))));
$query = "
WITH latest_fetch AS (
SELECT MAX(fetch_time) as max_fetch_time FROM newcountyoutages
)
SELECT
n.county,
n.state,
n.outages as outage,
n.fetch_time as time,
n.served,
CASE
WHEN n.served > 0 THEN ROUND(CAST((n.outages::FLOAT / n.served) * 100 AS NUMERIC), 2)
ELSE 0
END as perout
FROM newcountyoutages n, latest_fetch
WHERE n.fetch_time = latest_fetch.max_fetch_time
AND n.cwa IN ($placeholders)
";
$result = pg_query_params($dbconn, $query, $cwas);
if ($result === false) {
throw new Exception('Query failed: ' . pg_last_error());
}
$results = pg_fetch_all($result) ?: [];
echo json_encode($results);
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]);
}
}
pg_close($dbconn);
?>

95
php/newsearchapi.php Normal file
View File

@@ -0,0 +1,95 @@
<?php
require_once __DIR__ . '/common.php';
header('Content-Type: application/json');
$dbconn = getDBConnection();
// Default endpoint: Get current point outages from newpower table
if (empty(array_diff_key($_GET, array('service' => '')))) {
try {
$query = "
SELECT json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(geom)::json,
'properties', json_build_object(
'time', start_time,
'county', county,
'state', state,
'outage', outagen,
'lastchange', last_change,
'cause', cause
)
)
ORDER BY start_time ASC
)
) as geojson
FROM newpower
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_assoc($result);
if ($resultArray && $resultArray['geojson']) {
echo $resultArray['geojson'];
} else {
echo json_encode(['type' => 'FeatureCollection', 'features' => []]);
}
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
die(json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]));
}
}
// Get current county outages from newcountyoutages table
if (isset($_GET['county'])) {
try {
$query = "
WITH latest_fetch AS (
SELECT MAX(fetch_time) as max_fetch_time FROM newcountyoutages
)
SELECT
n.fetch_time as time,
n.county,
n.state,
n.outages as outage,
n.served
FROM newcountyoutages n, latest_fetch
WHERE n.fetch_time = latest_fetch.max_fetch_time
AND n.cwa = $1
ORDER BY n.county, n.state
";
$result = pg_query_params($dbconn, $query, ['RLX']);
if ($result === false) {
throw new Exception('Query failed: ' . pg_last_error());
}
$results = pg_fetch_all($result) ?: [];
echo json_encode($results);
pg_free_result($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Query execution failed: ' . $e->getMessage()]);
}
}
// Note: The 'countyarchive', 'archivepoint', and 'svr' endpoints from the original
// searchapi.php can be migrated here. The queries would need to be updated to use
// the 'newpower' and 'newcountyoutages' tables and their corresponding columns
// (e.g., start_time, geom, fetch_time).
pg_close($dbconn);
?>

141
php/newstormdata.php Normal file
View File

@@ -0,0 +1,141 @@
<?php
require_once __DIR__ . '/common.php';
/**
* Sends a JSON error response and terminates the script.
* @param int $code HTTP status code.
* @param string $message User-facing error message.
* @param string|null $log_message Optional message for the server log.
*/
function send_error($code, $message, $log_message = null) {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
if ($log_message) {
error_log($log_message);
}
echo json_encode(['error' => $message]);
exit;
}
/**
* Handles power outage requests for the new schema.
* @param resource $dbconn The database connection.
* @param array $input_data The decoded JSON input data.
*/
function handle_new_power_request($dbconn, $input_data) {
$poly = $input_data['poly'] ?? null;
$start = $input_data['start'] ?? null;
$end = $input_data['end'] ?? null;
if (!$poly || !$start || !$end) {
send_error(400, 'Missing required fields: poly, start, and end are required for power requests.');
}
$query = "
SELECT
SUM(p.outagen) as total_outages,
COUNT(p.id) as outage_events,
SUM(p.peakoutage) as peak_outages
FROM newpower p
WHERE ST_Within(p.geom, ST_GeomFromText($1, 4326))
AND p.start_time >= $2
AND p.start_time <= $3
";
try {
$result = pg_query_params($dbconn, $query, [$poly, $start, $end]);
if ($result === false) {
throw new Exception('Database query failed: ' . pg_last_error($dbconn));
}
$data = pg_fetch_assoc($result);
pg_free_result($result);
header('Content-Type: application/json');
echo json_encode($data ?: new stdClass()); // Return empty JSON object if no results
} catch (Exception $e) {
send_error(500, 'An error occurred while processing the power request.', $e->getMessage());
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input_data = null;
$request_type = null;
$contentType = trim(strtolower($_SERVER['HTTP_CONTENT_TYPE'] ?? $_SERVER['CONTENT_TYPE'] ?? ''));
if (strpos($contentType, 'application/json') === 0) {
$raw_post_data = file_get_contents('php://input');
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.");
}
$input_data = json_decode($raw_post_data, true);
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 {
$request_type = $input_data['request_type'] ?? null;
}
} else {
send_error(415, 'Unsupported Media Type. This endpoint requires application/json.', "Unsupported Media Type Received: " . $contentType);
}
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 {
send_error(400, 'Missing required parameter: request_type (or processing error).');
}
}
$dbconn = getDBConnection();
switch ($request_type) {
// Retaining legacy endpoints from stormdata.php but pointing to new handlers if needed
// For now, only implementing the 'power' endpoint for the new schema
case 'power':
handle_new_power_request($dbconn, $input_data);
break;
// The 'powernopoly' case from the original file can be implemented here if needed.
// It would be similar to handle_new_power_request but without the ST_Within clause.
/*
// Legacy endpoints can be added here if they need to be migrated.
case 'ohgo':
// handle_ohgo_request($dbconn, $input_data);
send_error(501, 'The "ohgo" request type is not yet implemented for newstormdata.');
break;
case 'ohgonopoly':
// handle_ohgo_request_no_poly($dbconn, $input_data);
send_error(501, 'The "ohgonopoly" request type is not yet implemented for newstormdata.');
break;
case 'wupoly':
// handle_wu_request_poly($dbconn, $input_data);
send_error(501, 'The "wupoly" request type is not yet implemented for newstormdata.');
break;
case 'campoly':
// handle_cam_request($dbconn, $input_data);
send_error(501, 'The "campoly" request type is not yet implemented for newstormdata.');
break;
*/
default:
send_error(400, 'Invalid request_type specified: ' . htmlspecialchars($request_type));
break;
}
pg_close($dbconn);
} 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;
}
?>