'Choose for a national number', 'US' => 'United States', 'CA' => 'Canada', 'GB' => 'United Kingdom', 'AU' => 'Australia', 'DE' => 'Germany', 'FR' => 'France', 'IN' => 'India', 'JP' => 'Japan']; function escaped(string $value): string { return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } /** The mail callable uses the application's existing transport, not ParseAPI. */ function submitContact(array $values, Client $parse, callable $send, array $delivery): array { $errors = []; $answer = ['errors' => [], 'error' => null, 'suggestion' => null, 'accepted' => false, 'status' => 422]; foreach (['name', 'email', 'phone', 'country', 'message'] as $field) { if (!isset($values[$field]) || !is_string($values[$field]) || preg_match('//u', $values[$field]) !== 1) { $errors[$field] = 'Enter a valid text value.'; } } if ($errors) return [...$answer, 'errors' => $errors]; if (trim($values['name']) === '' || strlen($values['name']) > 400 || preg_match_all('/./us', $values['name']) > 100 || preg_match('/[\x00-\x1f\x7f]/', $values['name'])) { $errors['name'] = 'Enter your name, up to 100 characters.'; } if (trim($values['email']) === '' || strlen($values['email']) > 254 || preg_match('/[\x00-\x20\x7f]/', trim($values['email'])) || preg_match('/[\r\n]/', $values['email'])) { $errors['email'] = 'Enter one email address without spaces or line breaks.'; } if (strlen($values['phone']) > 100 || preg_match('/[\x00-\x1f\x7f]/', $values['phone'])) { $errors['phone'] = 'Enter one phone number, up to 100 characters.'; } if (!array_key_exists($values['country'], COUNTRIES)) $errors['country'] = 'Choose a listed phone country.'; if (trim($values['phone']) !== '' && !str_starts_with(trim($values['phone']), '+') && $values['country'] === '') { $errors['country'] = 'Choose the country for this national phone number.'; } if (trim($values['message']) === '' || strlen($values['message']) > 8000 || preg_match_all('/./us', $values['message']) > 2000 || str_contains($values['message'], "\0")) { $errors['message'] = 'Enter a message of 1 to 2,000 characters.'; } if ($errors) return [...$answer, 'errors' => $errors]; $normalizedPhone = null; try { // example:email $email = $parse->email(trim($values['email'])); // /example:email if (!isset($email['email']) || !is_string($email['email']) || strcasecmp($email['email'], trim($values['email'])) !== 0 || !isset($email['valid']) || !is_bool($email['valid']) || !array_key_exists('domain_valid', $email) || !in_array($email['domain_valid'], [true, false, null], true)) { throw new \UnexpectedValueException('Unexpected email response.'); } // example:fields $replyTo = $email['email']; $valid = $email['valid']; $domainValid = $email['domain_valid']; // /example:fields if (!$valid || $domainValid === false) $errors['email'] = 'Check the email address and try again.'; elseif ($domainValid === null) $errors['email'] = 'The email domain could not be checked. Please try again.'; if (isset($email['didyoumean']) && is_string($email['didyoumean'])) $answer['suggestion'] = $email['didyoumean']; if ($errors) return [...$answer, 'errors' => $errors]; if (!filter_var($replyTo, FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', $replyTo)) { throw new \UnexpectedValueException('Reply address is unsuitable for this mail transport.'); } if (trim($values['phone']) !== '') { $phoneCountry = str_starts_with(trim($values['phone']), '+') ? null : $values['country']; // example:phone $phone = $parse->phone(trim($values['phone']), $phoneCountry); // /example:phone if (!isset($phone['valid']) || !is_bool($phone['valid']) || !array_key_exists('phone', $phone) || ($phone['valid'] && (!is_string($phone['phone']) || !preg_match('/^\+[1-9][0-9]{1,14}$/D', $phone['phone'])))) { throw new \UnexpectedValueException('Unexpected phone response.'); } // example:normalized $normalizedPhone = $phone['valid'] ? $phone['phone'] : null; // /example:normalized if (!$phone['valid']) return [...$answer, 'errors' => ['phone' => 'Check the phone number and its country.']]; } } catch (ParseAPIError | \UnexpectedValueException $error) { return [...$answer, 'status' => 503, 'error' => 'Your details could not be checked. Nothing was sent. Please try again later.']; } catch (\Throwable $error) { return [...$answer, 'status' => 503, 'error' => 'Your details could not be checked. Nothing was sent. Please try again later.']; } if (!filter_var($delivery['to'] ?? '', FILTER_VALIDATE_EMAIL) || !filter_var($delivery['from'] ?? '', FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', ($delivery['to'] ?? '') . ($delivery['from'] ?? ''))) { return [...$answer, 'status' => 503, 'error' => 'Message delivery is unavailable. Nothing was sent. Please try again later.']; } $body = "Name: " . $values['name'] . "\nReply email: " . $replyTo . ($normalizedPhone ? "\nPhone: " . $normalizedPhone : '') . "\n\n" . $values['message']; // example:headers $headers = ['From' => $delivery['from'], 'Reply-To' => $replyTo, 'Content-Type' => 'text/plain; charset=UTF-8']; // /example:headers try { $accepted = $send($delivery['to'], $body, $headers) === true; } catch (\Throwable $error) { $accepted = false; } return [...$answer, 'accepted' => $accepted, 'status' => $accepted ? 200 : 503, 'error' => $accepted ? null : 'Delivery could not be confirmed. Your entries are still here.']; } function renderContact(array $values, array $answer, string $csrf, bool $accepted): void { $errors = $answer['errors']; ?> Contact us

Contact us

Tell us what you need. We’ll use your email address to reply.

Your message was accepted for delivery. Thank you.

>

Did you mean ? Edit the email field if you want to use it.

>

Open this app on localhost.'; return; } session_name('parse_contact'); session_set_cookie_params(['httponly' => true, 'samesite' => 'Lax']); session_start(); $_SESSION['csrf'] ??= bin2hex(random_bytes(32)); $values = ['name' => '', 'email' => '', 'phone' => '', 'country' => '', 'message' => '']; $answer = ['errors' => [], 'error' => null, 'suggestion' => null, 'status' => 200]; $accepted = ($_SESSION['contact_accepted'] ?? false) === true; unset($_SESSION['contact_accepted']); if ($_SERVER['REQUEST_METHOD'] === 'POST') { foreach ($values as $field => $_value) $values[$field] = is_string($_POST[$field] ?? null) ? $_POST[$field] : ''; $token = $_POST['csrf'] ?? null; if ((int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 16384) { $answer['error'] = 'This message is too large. Use at most 2,000 characters.'; $answer['status'] = 413; } elseif (!is_string($token) || !hash_equals($_SESSION['csrf'], $token)) { $answer['error'] = 'This form expired. Refresh the page and try again.'; $answer['status'] = 403; } else { $key = trim(getenv('PARSEAPI_KEY') ?: ''); if ($key === '' || str_starts_with($key, 'parse_public_') || str_starts_with($key, 'parse_app_')) { $answer['error'] = 'Your details could not be checked. Nothing was sent. Please try again later.'; $answer['status'] = 503; } else { // example:client $parse = new \ParseAPI\Client(timeout: 10.0, retries: 0); // /example:client $send = static function (string $to, string $body, array $headers): bool { // example:delivery $accepted = mail($to, 'Website contact request', $body, $headers); // /example:delivery return $accepted; }; try { $answer = submitContact($values, $parse, $send, ['to' => getenv('CONTACT_TO') ?: '', 'from' => getenv('CONTACT_FROM') ?: '']); } finally { $parse->close(); } if ($answer['accepted']) { $_SESSION['csrf'] = bin2hex(random_bytes(32)); $_SESSION['contact_accepted'] = true; header('Location: /', true, 303); return; } } } } http_response_code($answer['status']); renderContact($values, $answer, $_SESSION['csrf'], $accepted); } if (PHP_SAPI !== 'cli') runContact();