| Server IP : 173.209.174.21 / Your IP : 216.73.216.89 Web Server : Apache/2.4.58 (Ubuntu) System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : nodor ( 1000) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/wcfs/tabs/Fuel-prices/ |
Upload File : |
<?php
/**
* fuel_prices.php
*
* Pulls current gas prices for Moses Lake, WA and Ephrata, WA on page load/refresh
* using Apify + GasBuddy Scraper actor.
*
* Requirements:
* - PHP 7.2+ (curl + json)
* - An Apify API token
*
* Notes:
* - Google Maps does not provide an official public API for live gas prices.
* - "Non-ethanol" is not reliably available from online sources; this page shows a column,
* but you'll likely want to maintain a manual list for ethanol-free pricing.
*/
// ----------------------------
// CONFIG
// ----------------------------
$APIFY_TOKEN = 'PUT_YOUR_APIFY_TOKEN_HERE'; // <-- set this
$ACTOR_ID = 'stanvanrooy6~gasbuddy-scraper';
// How many stations to show per city per fuel type
$TOP_N = 10;
// Filters passed to the actor (optional)
$PAYMENT_METHOD = 'cash or credit'; // or "credit only"
$PRICES_UPDATED = '8 hours'; // e.g. "no limit", "4 hours", "8 hours"
// Cities to query
$LOCATIONS = [
'Moses Lake, WA' => 'Moses Lake, WA',
'Ephrata, WA' => 'Ephrata, WA',
];
// Fuel types supported by the actor include: regular, diesel, midgrade, premium, e85, unl88 :contentReference[oaicite:3]{index=3}
$FUEL_TYPES = [
'regular' => 'Unleaded (Regular)',
'diesel' => 'Diesel',
];
// Cache (to avoid hitting Apify/GasBuddy every refresh)
$CACHE_DIR = __DIR__ . '/cache';
$CACHE_TTL_SEC = 300; // 5 minutes
// ----------------------------
// HELPERS
// ----------------------------
function ensure_cache_dir($dir) {
if (!is_dir($dir)) {
@mkdir($dir, 0755, true);
}
}
function h($s) {
return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
function apify_run_sync_get_dataset_items($token, $actorId, array $input, $timeoutSec = 60) {
// Apify API endpoint :contentReference[oaicite:4]{index=4}
$url = "https://api.apify.com/v2/acts/" . rawurlencode($actorId) . "/run-sync-get-dataset-items?token=" . rawurlencode($token) . "&format=json&clean=true";
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($input),
CURLOPT_TIMEOUT => $timeoutSec,
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($resp === false) {
throw new Exception("cURL error: " . $err);
}
if ($code < 200 || $code >= 300) {
throw new Exception("Apify HTTP $code: " . substr($resp, 0, 300));
}
$data = json_decode($resp, true);
if (!is_array($data)) {
throw new Exception("Unexpected response (not JSON array).");
}
return $data;
}
function cents_to_dollars($cents) {
if ($cents === null || $cents === '') return null;
if (!is_numeric($cents)) return null;
return round(((float)$cents) / 100.0, 3);
}
function sort_by_price_asc(&$items) {
usort($items, function($a, $b) {
$pa = $a['price_cents_per_gallon'] ?? null;
$pb = $b['price_cents_per_gallon'] ?? null;
if ($pa === null && $pb === null) return 0;
if ($pa === null) return 1;
if ($pb === null) return -1;
return $pa <=> $pb;
});
}
function cache_key($location, $fuelType, $paymentMethod, $pricesUpdated) {
return sha1($location . '|' . $fuelType . '|' . $paymentMethod . '|' . $pricesUpdated);
}
function cache_get($cacheDir, $key, $ttl) {
$path = $cacheDir . '/' . $key . '.json';
if (!file_exists($path)) return null;
$age = time() - filemtime($path);
if ($age > $ttl) return null;
$raw = file_get_contents($path);
$data = json_decode($raw, true);
return is_array($data) ? $data : null;
}
function cache_set($cacheDir, $key, $data) {
$path = $cacheDir . '/' . $key . '.json';
file_put_contents($path, json_encode($data));
}
// ----------------------------
// MAIN FETCH
// ----------------------------
$forceRefresh = isset($_GET['refresh']) && $_GET['refresh'] === '1';
$results = [];
$errors = [];
ensure_cache_dir($CACHE_DIR);
foreach ($LOCATIONS as $label => $searchString) {
foreach ($FUEL_TYPES as $fuelType => $fuelLabel) {
$ck = cache_key($searchString, $fuelType, $PAYMENT_METHOD, $PRICES_UPDATED);
$items = (!$forceRefresh) ? cache_get($CACHE_DIR, $ck, $CACHE_TTL_SEC) : null;
if ($items === null) {
try {
$input = [
"search" => $searchString,
"fuelType" => $fuelType,
"paymentMethod" => $PAYMENT_METHOD,
"pricesUpdated" => $PRICES_UPDATED,
];
$items = apify_run_sync_get_dataset_items($APIFY_TOKEN, $ACTOR_ID, $input, 75);
cache_set($CACHE_DIR, $ck, $items);
} catch (Exception $e) {
$errors[] = "$label / $fuelLabel: " . $e->getMessage();
$items = [];
}
}
// Clean & sort
$clean = [];
foreach ($items as $it) {
$price = cents_to_dollars($it['price_cents_per_gallon'] ?? null);
$clean[] = [
'station' => $it['name'] ?? '',
'address' => $it['address'] ?? '',
'price' => $price,
'updated' => $it['updated'] ?? ($it['last_updated'] ?? ''),
'rating' => $it['rating_out_of_five'] ?? null,
'reviews' => $it['number_reviews'] ?? null,
];
}
// Sort cheapest first, then take top N
usort($clean, function($a, $b) {
if ($a['price'] === null && $b['price'] === null) return 0;
if ($a['price'] === null) return 1;
if ($b['price'] === null) return -1;
return $a['price'] <=> $b['price'];
});
$clean = array_slice($clean, 0, $TOP_N);
$results[$label][$fuelType] = [
'fuelLabel' => $fuelLabel,
'rows' => $clean,
];
}
}
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Local Fuel Prices (Moses Lake & Ephrata)</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; background:#f6f7f9; color:#111; }
.wrap { max-width: 1100px; margin: 0 auto; padding: 18px; }
.card { background:#fff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,.06); padding: 16px; margin-bottom: 18px; }
.hdr { display:flex; align-items:center; justify-content:space-between; gap: 12px; flex-wrap: wrap; }
.hdr h1 { font-size: 20px; margin: 0; }
.meta { font-size: 13px; color:#444; }
.btn { display:inline-block; padding:10px 12px; border-radius:10px; background:#111; color:#fff; text-decoration:none; font-size: 13px; }
.btn:hover { opacity:.9; }
table { width:100%; border-collapse: collapse; margin-top: 10px; }
th, td { text-align:left; padding:10px 8px; border-bottom:1px solid #e8eaee; vertical-align: top; }
th { font-size: 13px; color:#333; }
td { font-size: 14px; }
.pill { display:inline-block; padding:2px 8px; border-radius: 999px; background:#eef2ff; font-size: 12px; margin-left: 6px; }
.cityTitle { display:flex; align-items:center; gap: 10px; margin: 0 0 8px 0; }
.cityTitle h2 { margin: 0; font-size: 18px; }
.grid { display:grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 920px) { .grid { grid-template-columns: 1fr 1fr; } }
.muted { color:#666; font-size: 12px; }
.err { background:#fff3f3; border:1px solid #ffd3d3; color:#7a1c1c; padding: 10px; border-radius: 10px; margin-bottom: 12px; }
.right { text-align:right; white-space:nowrap; }
</style>
</head>
<body>
<div class="wrap">
<div class="card">
<div class="hdr">
<h1>Fuel Prices: Moses Lake & Ephrata <span class="pill">Refresh to update</span></h1>
<div>
<a class="btn" href="?refresh=1">Force Refresh</a>
</div>
</div>
<div class="meta">
Last page load: <strong><?php echo h($now); ?></strong> |
Cache TTL: <?php echo (int)($CACHE_TTL_SEC/60); ?> min |
Source: GasBuddy data via Apify actor
</div>
<div class="muted" style="margin-top:8px;">
Note: �Non-ethanol� is often not published as a distinct price online. This page focuses on Regular & Diesel. You can add a manual ethanol-free list if you want.
</div>
</div>
<?php if (!empty($errors)): ?>
<div class="err">
<strong>Some requests failed:</strong>
<ul style="margin:8px 0 0 18px;">
<?php foreach ($errors as $e): ?>
<li><?php echo h($e); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php foreach ($results as $city => $fuelBlocks): ?>
<div class="card">
<div class="cityTitle">
<h2><?php echo h($city); ?></h2>
</div>
<div class="grid">
<?php foreach ($fuelBlocks as $fuelType => $block): ?>
<div class="card" style="margin:0;">
<div class="hdr">
<h3 style="margin:0; font-size: 16px;"><?php echo h($block['fuelLabel']); ?></h3>
<div class="muted"><?php echo h(strtoupper($fuelType)); ?></div>
</div>
<table>
<thead>
<tr>
<th>Station</th>
<th>Address</th>
<th class="right">Price</th>
</tr>
</thead>
<tbody>
<?php if (empty($block['rows'])): ?>
<tr><td colspan="3" class="muted">No results returned.</td></tr>
<?php else: ?>
<?php foreach ($block['rows'] as $row): ?>
<tr>
<td>
<strong><?php echo h($row['station']); ?></strong><br>
<span class="muted">
<?php
$r = $row['rating'];
$n = $row['reviews'];
if ($r !== null) echo h($r) . "/5";
if ($n !== null) echo " (" . h($n) . " reviews)";
?>
</span>
</td>
<td><?php echo h($row['address']); ?></td>
<td class="right">
<?php if ($row['price'] === null): ?>
<span class="muted">�</span>
<?php else: ?>
<strong>$<?php echo number_format($row['price'], 3); ?></strong>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</body>
</html>