['Austin, TX','Seattle, WA','San Francisco, CA','Denver, CO','Berlin, DE'],
'Kubernetes & Containers' => ['San Francisco, CA','Seattle, WA','New York, NY','Amsterdam, NL','London, UK'],
'CI/CD & GitOps' => ['Austin, TX','Portland, OR','Toronto, CA','Dublin, IE','Sydney, AU'],
'Cloud Security' => ['New York, NY','Chicago, IL','San Antonio, TX','London, UK','Dubai, AE'],
'Penetration Testing' => ['New York, NY','Los Angeles, CA','London, UK','Tel Aviv, IL','Singapore, SG'],
'Red Team' => ['New York, NY','Los Angeles, CA','London, UK','Dubai, AE','Singapore, SG'],
'Blue Team' => ['New York, NY','Chicago, IL','San Antonio, TX','Berlin, DE','Singapore, SG'],
'Application Security' => ['San Francisco, CA','New York, NY','London, UK','Tel Aviv, IL','Bangalore, IN'],
'API Security' => ['New York, NY','Chicago, IL','San Antonio, TX','Toronto, CA','London, UK'],
'Digital Forensics' => ['Phoenix, AZ','Philadelphia, PA','Charlotte, NC','Indianapolis, IN','London, UK'],
'Digital Forensic Investigations' => ['Charlotte, NC','Indianapolis, IN','Denver, CO','Dublin, IE','Sydney, AU'],
'Mobile Device Forensics' => ['Los Angeles, CA','Miami, FL','New York, NY','London, UK','Singapore, SG'],
'Fraud Examination' => ['Los Angeles, CA','Miami, FL','New York, NY','Frankfurt, DE','Dubai, AE'],
'Corporate Investigations' => ['Los Angeles, CA','Washington, DC','New York, NY','London, UK','Hong Kong, HK'],
'Account Recovery' => ['San Jose, CA','Los Angeles, CA','New York, NY','London, UK','Toronto, CA'],
'Identity Recovery' => ['San Diego, CA','Dallas, TX','San Jose, CA','London, UK','Toronto, CA'],
'Data Recovery' => ['San Diego, CA','Dallas, TX','San Francisco, CA','London, UK','Sydney, AU'],
];
$opts = $pref[$cat] ?? ['New York, NY','London, UK','Toronto, CA','Berlin, DE','Singapore, SG'];
return $opts[$seed % count($opts)];
}
/* Get Unsplash ID for category */
function cat_img(array $CATEGORIES, string $cat): string {
foreach ($CATEGORIES as $c) if ($c[0] === $cat) return $c[2];
return 'photo-1467232004584-a241de8bcf5d';
}
/* Build all posts */
function build_posts(array $TEMPLATES, array $CATEGORIES, array $CITIES): array {
$out = [];
foreach ($TEMPLATES as $i => $t) {
[$title, $cat, $price, $desc] = $t;
$city = pick_city($cat, hash_str($title . $i), $CITIES);
$daysAgo = hash_str($title . $i . $cat) % 14;
$created = time() - $daysAgo * 86400;
$imgId = cat_img($CATEGORIES, $cat);
$out[] = [
'id' => 'p' . base_convert((string)hash_str($title . $city . $i), 10, 36),
'title' => $title,
'category' => $cat,
'price' => (string)$price,
'description' => $desc,
'city' => $city,
'city_slug' => slugify($city),
'date' => date('M d', $created),
'created_at' => date('c', $created),
'image_id' => $imgId,
'image' => unsplash($imgId, 800, 500),
'image_full' => unsplash($imgId, 1600, 900),
];
}
// Extra density in popular cities
for ($k = 0; $k < 10; $k++) {
$t = $TEMPLATES[$k];
[$title, $cat, $price, $desc] = $t;
$city = pick_city($cat, hash_str($title . $k . 'x'), $CITIES);
$daysAgo = (hash_str($title . $k . 'x') % 5) + 1;
$created = time() - $daysAgo * 86400;
$imgId = cat_img($CATEGORIES, $cat);
$out[] = [
'id' => 'p' . base_convert((string)hash_str($title . $city . $k . 'x'), 10, 36),
'title' => $title,
'category' => $cat,
'price' => (string)$price,
'description' => $desc,
'city' => $city,
'city_slug' => slugify($city),
'date' => date('M d', $created),
'created_at' => date('c', $created),
'image_id' => $imgId,
'image' => unsplash($imgId, 800, 500),
'image_full' => unsplash($imgId, 1600, 900),
];
}
usort($out, fn($a, $b) => strcmp($b['created_at'], $a['created_at']));
return $out;
}
/* ============================================================
6. AUTO-GENERATE SITEMAP.XML AND FRIENDS
============================================================ */
function ensure_cache_dir(): void {
if (!is_dir(CACHE_DIR)) @mkdir(CACHE_DIR, 0755, true);
}
function sitemap_signature(array $posts, array $cities, array $cats): string {
return hash('sha256', count($posts) . '|' . count($cities) . '|' . count($cats) . '|' . ($posts[0]['created_at'] ?? ''));
}
function write_sitemaps(array $posts, array $cities, array $cats, bool $force = false): array {
ensure_cache_dir();
$sigFile = CACHE_DIR . '/.sitemap.sig';
$sig = sitemap_signature($posts, $cities, $cats);
if (!$force && is_file($sigFile) && trim((string)@file_get_contents($sigFile)) === $sig) {
return []; // nothing changed
}
$now = date('c');
$written = [];
// Static
$xml = '' . "\n";
$xml .= '' . "\n";
$xml .= " " . e(BASE_URL . '/') . " {$now} hourly 1.0 ";
$xml .= "" . e(LOGO_URL) . " \n";
foreach ($cats as $c) {
$xml .= " " . e(url(['v'=>'cat','c'=>slugify($c[0])])) . " {$now} daily 0.7 \n";
}
$xml .= ' ';
file_put_contents(__DIR__ . '/sitemap-static.xml', $xml, LOCK_EX);
$written[] = 'sitemap-static.xml';
// Cities
$xml = '' . "\n";
$xml .= '' . "\n";
foreach ($cities as $c) {
$xml .= " " . e(url(['v'=>'city','c'=>slugify($c)])) . " {$now} daily 0.8 \n";
}
$xml .= ' ';
file_put_contents(__DIR__ . '/sitemap-cities-0.xml', $xml, LOCK_EX);
$written[] = 'sitemap-cities-0.xml';
// Posts (chunked, 50k per file)
$chunks = array_chunk($posts, 50000);
$chunkFiles = [];
foreach ($chunks as $i => $slice) {
$xml = '' . "\n";
$xml .= '' . "\n";
foreach ($slice as $p) {
$xml .= " \n";
$xml .= " " . e(url(['v'=>'post','id'=>$p['id']])) . " \n";
$xml .= " " . e($p['created_at']) . " \n";
$xml .= " daily \n";
$xml .= " 0.6 \n";
$xml .= " \n";
$xml .= " " . e($p['image_full']) . " \n";
$xml .= " " . e($p['title']) . " \n";
$xml .= " \n";
$xml .= " \n";
}
$xml .= ' ';
$name = "sitemap-posts-{$i}.xml";
file_put_contents(__DIR__ . '/' . $name, $xml, LOCK_EX);
$chunkFiles[] = $name;
$written[] = $name;
}
if (!$chunkFiles) {
file_put_contents(__DIR__ . '/sitemap-posts-0.xml',
'' . "\n" .
' ', LOCK_EX);
$written[] = 'sitemap-posts-0.xml';
}
// Sitemap index
$xml = '' . "\n";
$xml .= '' . "\n";
$xml .= " " . e(BASE_URL . '/sitemap-static.xml') . " {$now} \n";
$xml .= " " . e(BASE_URL . '/sitemap-cities-0.xml') . " {$now} \n";
foreach ($chunkFiles as $name) {
$xml .= " " . e(BASE_URL . "/{$name}") . " {$now} \n";
}
$xml .= ' ';
file_put_contents(__DIR__ . '/sitemap.xml', $xml, LOCK_EX);
$written[] = 'sitemap.xml';
// robots.txt
$robots = "User-agent: *\nAllow: /\n";
foreach (['admin','api','banner','favicon','rag','llms','feed','cron','sitemap'] as $d)
$robots .= "Disallow: /?v={$d}\n";
$robots .= "Disallow: /data/\nDisallow: /cache/\n\n";
$robots .= "Sitemap: " . BASE_URL . "/sitemap.xml\n";
file_put_contents(__DIR__ . '/robots.txt', $robots, LOCK_EX);
$written[] = 'robots.txt';
file_put_contents($sigFile, $sig, LOCK_EX);
@file_put_contents(SITEMAP_LOG, date('c') . " wrote " . implode(', ', $written) . "\n", FILE_APPEND);
return $written;
}
/* ============================================================
7. BOOTSTRAP
============================================================ */
ensure_cache_dir();
$POSTS = build_posts($TEMPLATES, $CATEGORIES, $CITIES);
// Auto-write sitemap when data changes (silent, fast)
write_sitemaps($POSTS, $CITIES, $CATEGORIES);
$view = $_GET['v'] ?? 'home';
/* ============================================================
8. API / EXPORT ENDPOINTS
============================================================ */
if ($view === 'sitemap') {
header('Content-Type: application/xml; charset=utf-8');
readfile(__DIR__ . '/sitemap.xml');
exit;
}
if ($view === 'llms') {
header('Content-Type: text/plain; charset=utf-8');
echo "# " . SITE_NAME . "\n> " . SITE_DESC . "\n\n";
echo "Telegram: " . CONTACT_TELEGRAM . " (" . CONTACT_TG_URL . ")\n";
echo "WhatsApp: " . CONTACT_WHATSAPP . " (" . CONTACT_WA_URL . ")\n";
echo "Email: " . CONTACT_EMAIL . "\n";
echo "Homepage: " . BASE_URL . "/\n";
echo "Sitemap: " . BASE_URL . "/sitemap.xml\n\n";
echo "## Cities (" . count($CITIES) . ")\n";
foreach ($CITIES as $c) echo "- " . $c . ": " . url(['v'=>'city','c'=>slugify($c)]) . "\n";
echo "\n## Categories (" . count($CATEGORIES) . ")\n";
foreach ($CATEGORIES as $c) echo "- " . $c[0] . ": " . url(['v'=>'cat','c'=>slugify($c[0])]) . "\n";
exit;
}
if ($view === 'feed') {
header('Content-Type: application/rss+xml; charset=utf-8');
$recent = array_slice($POSTS, 0, 100);
echo '' . "\n";
echo '';
echo '' . e(SITE_NAME) . ' ';
echo ' ' . e(BASE_URL) . '/';
echo '' . e(SITE_DESC) . ' ';
echo '' . date(DATE_RSS) . ' ';
foreach ($recent as $p) {
echo '- ';
echo '
' . e($p['title']) . ' ';
echo ' ' . e(url(['v'=>'post','id'=>$p['id']])) . '';
echo '' . e(url(['v'=>'post','id'=>$p['id']])) . ' ';
echo '' . date(DATE_RSS, strtotime($p['created_at'])) . ' ';
echo '' . e(shorten($p['description'], 300)) . ' ';
echo ' ';
}
echo ' ';
exit;
}
if ($view === 'api') {
header('Content-Type: application/json');
echo json_encode([
'site' => SITE_NAME,
'tagline' => SITE_TAGLINE,
'cities_count' => count($CITIES),
'categories_count' => count($CATEGORIES),
'listings_count' => count($POSTS),
'sample' => array_slice($POSTS, 0, 5),
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
exit;
}
if ($view === 'regen') {
// Force rebuild all sitemaps
header('Content-Type: text/plain');
$written = write_sitemaps($POSTS, $CITIES, $CATEGORIES, true);
echo "Regenerated:\n" . implode("\n", $written) . "\n";
exit;
}
?>
= e(SITE_NAME) ?> β = e(SITE_TAGLINE) ?>
Remote-first Β· Worldwide delivery Β· Slots open now
Remote infrastructure, cloud security & digital forensics.
pinglist is a remote-first consultancy offering cloud infrastructure, Terraform and IaC, Kubernetes, DevSecOps, penetration testing, digital forensics, digital forensic investigations, encryption services, and corporate investigation support. Engagements delivered worldwide.
= count($CITIES) ?>+
Cities
= count($CATEGORIES) ?>
Categories
= count($POSTS) ?>
Live listings
Category
All categories
City
All cities
Filter listings β
Recent listings
Remote engagements. Everywhere.
Loadingβ¦
Load more listings
Categories
What we deliver. Remote, worldwide.
Cloud infra, security, forensics, investigations β every engagement scoped and delivered remotely.
Cities
Where we deliver. Everywhere.
Remote-first. We serve clients in every major city and timezone worldwide.