$now - $window; }); } $hits[] = $now; if(count($hits) > $limit){ return true; } @file_put_contents($file, implode("\n",$hits), LOCK_EX); return false; } function save_fallback(array $data){ $dir = __DIR__ . '/storage'; if(!is_dir($dir)) { @mkdir($dir, 0755, true); } $file = $dir . '/contacts.csv'; $row = [ date('c'), $data['name'] ?? '', $data['email'] ?? '', $data['phone'] ?? '', $data['subject'] ?? '', str_replace(["\r","\n"], ['\r','\n'], $data['message'] ?? ''), $_SERVER['REMOTE_ADDR'] ?? '' ]; @file_put_contents($file, implode(',', array_map(fn($v)=>'"'.str_replace('"','""',$v).'"', $row))."\n", FILE_APPEND | LOCK_EX); } try { if($_SERVER['REQUEST_METHOD'] !== 'POST'){ json_response(405, ['status'=>'error','message'=>'Method not allowed']); } // Honeypot: bots fill this $company = sanitize($_POST['company'] ?? ''); if($company !== ''){ json_response(200, ['status'=>'ok','message'=>'Thanks!']); } if(rate_limited($_SERVER['REMOTE_ADDR'] ?? '')){ json_response(429, ['status'=>'error','message'=>'Too many messages. Please try again later.']); } $name = sanitize($_POST['name'] ?? ''); $email = sanitize($_POST['email'] ?? ''); $phone = sanitize($_POST['phone'] ?? ''); $subject = sanitize($_POST['subject'] ?? ''); $message = sanitize($_POST['message'] ?? ''); if($name === '' || $email === '' || $subject === '' || $message === ''){ json_response(422, ['status'=>'error','message'=>'Please fill all required fields.']); } if(!is_valid_email($email)){ json_response(422, ['status'=>'error','message'=>'Please enter a valid email address.']); } if(strlen($message) > 4000){ json_response(422, ['status'=>'error','message'=>'Message is too long.']); } // Build email $to = SUPPORT_EMAIL; $subj = 'New Contact — ' . APP_NAME . ' — ' . $subject; $body = "You have a new contact message from ".APP_NAME." website.\n\n" . "Name: $name\n" . "Email: $email\n" . "Phone: $phone\n" . "Subject: $subject\n\n" . "Message:\n$message\n\n" . "IP: " . ($_SERVER['REMOTE_ADDR'] ?? '') . "\n" . "User-Agent: " . ($_SERVER['HTTP_USER_AGENT'] ?? '') . "\n" . "Time: " . date('c') . "\n"; $headers = []; $headers[] = 'MIME-Version: 1.0'; $headers[] = 'Content-Type: text/plain; charset=UTF-8'; $headers[] = 'From: '.APP_NAME.' <'.FROM_EMAIL.'>'; $headers[] = 'Reply-To: '.$name.' <'.$email.'>'; $headers[] = 'X-Mailer: PHP/'.phpversion(); $sent = @mail($to, $subj, $body, implode("\r\n", $headers)); if(!$sent){ // Fallback to saving if mail fails save_fallback(compact('name','email','phone','subject','message')); json_response(200, ['status'=>'ok','message'=>'Thanks! Your message was received.']); } json_response(200, ['status'=>'ok','message'=>'Thanks! Your message was sent.']); } catch (Throwable $e){ save_fallback([ 'name'=>$_POST['name'] ?? '', 'email'=>$_POST['email'] ?? '', 'phone'=>$_POST['phone'] ?? '', 'subject'=>$_POST['subject'] ?? '', 'message'=>$_POST['message'] ?? '', ]); json_response(200, ['status'=>'ok','message'=>'Thanks! Your message was received.']); }