The worst bug a rates site can have is not a crash. It is confidently showing a wrong number. One day I checked my own site against the market and went cold, the silver rate on screen was not the real rate, it was a fallback value my own code had invented, displayed as if it were live. This post is that failure, exactly how it happened, and the multi-source engine that replaced it.
The mechanics of the lie were mundane. The fetchers scraped rate pages with regular expressions, the target sites’ HTML had changed, the patterns stopped matching, and my code did the helpful thing I had told it to do, fall back to a stored default so the page never looked empty:
// the original sin, simplified
$rate = srt_fetch_web_silver_rate();
if (!$rate) {
$rate = 4500; // "temporary" fallback, displayed exactly like a live rate
}
A placeholder indistinguishable from data. Visitors compared it against the bazaar, concluded the site was wrong, and left, trust and traffic bleeding from a number that looked perfectly confident. The fix had two halves, engineering and honesty.
The engineering half rebuilt fetching as a multi-source engine, srt_scrape_live_rates, with a dedicated parser per source, gold.pk, urdupoint, hamariweb, forex.pk, so one site’s redesign no longer blinds the system. The parsers dropped brittle whole-page regexes for keyword-proximity extraction, find the metal keyword, then extract the nearest plausible PKR figure:
function srt_extract_pkr_near($html, $keyword, $min, $max) {
$pos = stripos($html, $keyword);
if ($pos === false) { return null; }
$window = substr($html, $pos, 600);
// handles Pakistani grouping like 4,73,920 as well as 473,920
if (preg_match_all('/([0-9]{1,3}(?:,[0-9]{2,3})*)/', $window, $m)) {
foreach ($m[1] as $candidate) {
$n = (float) str_replace(',', '', $candidate);
if ($n >= $min && $n <= $max) { return $n; }
}
}
return null;
}
Two defences live in that function. The number pattern accepts Pakistani digit grouping, 4,73,920, which standard thousand-separator regexes silently mangle. And the min-max range check rejects absurd matches, a silver parser that grabs a gold price, or a year, or a phone number, returns nothing instead of nonsense, per-metal sanity ranges as the last gate before any number is believed.
The honesty half changed the failure mode itself. When every source fails, the site now shows the last real rate with its timestamp, via the [sarafa_updated] line, or says rates are being updated, and never a synthetic number dressed as live. Stale and labelled beats fake and confident, every time, on any site whose product is a number.
A few things people ask me about this
Why did my scraper break when the site still looks the same? Because layouts change in HTML without changing visually. Keyword-proximity extraction survives cosmetic restructuring far better than patterns anchored to exact markup.
What ranges should validate a scraped price? Generous but real bounds per metal, wide enough for market moves, tight enough to reject a year, an id, or the other metal’s price. A rejected number returns null and lets the next source try.
Next
Rebuilding the engine forced a question about a word my labels used proudly, AI. Why I removed it from everything visitors could see is the next post.
