Files
Waters ChurchandClaude Fable 5.1 78cd0cc550 Plan Your Visit landing page for visit.waterschurch.org
Next.js 16 static export + PHP 8 API for cPanel/Apache hosting.

- Location-aware campus finder (IP estimate, optional precise location, ZIP search)
- Three-step Plan Your Visit form with separate email/SMS consent
- PHP API: validation, anti-spam, rate limiting, SQLite lead store,
  Mailchimp and Sinch Engage adapters, idempotent retries via cron
- Attribution capture (utm_*, gclid/gbraid/wbraid, fbclid, ttclid, twclid) and
  consent-aware analytics hooks
- Vitest and PHP test suites, cPanel deployment script and docs

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 13:22:26 -04:00

82 lines
2.8 KiB
PHP

<?php
/**
* Fake Mailchimp + Sinch + Zippopotam + GeoIP endpoints for the PHP test-suite.
* Started by tests/php/run.php with: php -S 127.0.0.1:8099 tests/php/mock-providers.php
*
* Behaviour switches are files in tests/php/.tmp:
* fail-sinch → Sinch returns HTTP 503
* fail-mailchimp → Mailchimp returns HTTP 500
* Every request is appended to tests/php/.tmp/requests.log as JSON.
*/
declare(strict_types=1);
$tmp = __DIR__ . '/.tmp';
@mkdir($tmp, 0777, true);
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?: '/';
$body = file_get_contents('php://input') ?: '';
file_put_contents("$tmp/requests.log", json_encode([
'method' => $_SERVER['REQUEST_METHOD'],
'path' => $path,
'headers' => ['authorization' => $_SERVER['HTTP_AUTHORIZATION'] ?? null, 'account' => $_SERVER['HTTP_ACCOUNT'] ?? null],
'body' => json_decode($body, true),
]) . "\n", FILE_APPEND);
header('Content-Type: application/json');
// --- Sinch Engage
if ($path === '/v1/messages') {
if (file_exists("$tmp/fail-sinch")) {
http_response_code(503);
echo json_encode(['message' => 'service unavailable']);
exit;
}
$in = json_decode($body, true);
$out = [];
foreach ($in['messages'] ?? [] as $m) {
$out[] = ['message_id' => 'msg-' . substr(md5($m['destination_number'] . $m['content']), 0, 12), 'status' => 'queued', 'destination_number' => $m['destination_number']];
}
http_response_code(202);
echo json_encode(['messages' => $out]);
exit;
}
// --- Mailchimp
if (preg_match('#^/3\.0/lists/([^/]+)/members/([a-f0-9]{32})$#', $path, $m)) {
if (file_exists("$tmp/fail-mailchimp")) {
http_response_code(500);
echo json_encode(['title' => 'Internal Error', 'detail' => 'boom']);
exit;
}
$in = json_decode($body, true);
echo json_encode(['id' => $m[2], 'email_address' => $in['email_address'] ?? '', 'status' => $in['status_if_new'] ?? 'subscribed', 'merge_fields' => $in['merge_fields'] ?? []]);
exit;
}
if (preg_match('#^/3\.0/lists/[^/]+/members/[a-f0-9]{32}/tags$#', $path)) {
http_response_code(204);
exit;
}
if (preg_match('#^/3\.0/customer-journeys/#', $path)) {
http_response_code(204);
exit;
}
// --- Zippopotam
if (preg_match('#^/us/(\d{5})$#', $path, $m)) {
if ($m[1] === '00000') {
http_response_code(404);
echo '{}';
exit;
}
echo json_encode(['post code' => $m[1], 'places' => [['place name' => 'Norwood', 'state abbreviation' => 'MA', 'latitude' => '42.1945', 'longitude' => '-71.1995']]]);
exit;
}
// --- ipapi.co
if (preg_match('#^/([^/]+)/json/?$#', $path)) {
echo json_encode(['ip' => '203.0.113.9', 'city' => 'Providence', 'region_code' => 'RI', 'latitude' => 41.8240, 'longitude' => -71.4128]);
exit;
}
http_response_code(404);
echo json_encode(['error' => 'mock: unknown path ' . $path]);