prepare(" SELECT su.id, su.client_url, su.status, su.clicked_at, su.assigned_to_selection_id, p.status AS project_status, p.sample_size AS project_sample_size, ps.quota_limit AS selection_quota_limit, ps.id AS selection_db_id FROM survey_urls su LEFT JOIN projects p ON p.project_id = su.project_id LEFT JOIN project_selections ps ON ps.id = su.assigned_to_selection_id WHERE su.project_id = ? AND su.unique_identifier = ? LIMIT 1 "); $stmt->execute([$project_id, $unique_id]); $result = $stmt->fetch(PDO::FETCH_ASSOC); if (!$result) { header('HTTP/1.0 404 Not Found'); echo "Survey URL not found or expired"; exit; } // ── CHECK 1: Project status (Closed → survey closed, On hold → on hold) ── if ($result['project_status'] === 'Closed') { error_log("Survey URL blocked (project closed): Project=$project_id, UniqueID=$unique_id"); $current_project_id = $project_id; include __DIR__ . '/pages/survey-closed.php'; exit; } if ($result['project_status'] === 'On hold') { error_log("Survey URL blocked (project on hold): Project=$project_id, UniqueID=$unique_id"); $current_project_id = $project_id; include __DIR__ . '/pages/on-hold.php'; exit; } // Block access if already timed out if ($result['status'] === 'timeout') { error_log("Survey URL blocked (timed out): Project=$project_id, UniqueID=$unique_id"); $current_project_id = $project_id; include __DIR__ . '/../r/pages/timeout.php'; exit; } // Block if already completed or has a final status if (in_array($result['status'], ['complete', 'partial', 'earlyscreenout', 'latescreenout', 'quotafull'])) { // Already has a final status - show the appropriate page if ($result['status'] === 'quotafull') { $current_project_id = $project_id; include __DIR__ . '/../r/pages/quotafull.php'; exit; } // For other final statuses, let clicked through (they may be re-accessing) // Only block quotafull explicitly } // Real-time timeout check: if clicked > 2 hours ago and still 'clicked', mark as timeout and block if ($result['status'] === 'clicked' && $result['clicked_at']) { $clickedTime = strtotime($result['clicked_at']); if ((time() - $clickedTime) > 7200) { // 2 hours = 7200 seconds $stmt = $pdo->prepare(" UPDATE survey_urls SET status = 'timeout', actual_loi_seconds = TIMESTAMPDIFF(SECOND, clicked_at, NOW()) WHERE id = ? "); $stmt->execute([$result['id']]); error_log("Survey URL timed out on re-access: Project=$project_id, UniqueID=$unique_id"); $current_project_id = $project_id; include __DIR__ . '/../r/pages/timeout.php'; exit; } } // ── CHECK 2: Project-level sample_size check (total completes across all selections) ── if ($result['project_sample_size'] > 0 && in_array($result['status'], ['available', 'assigned', 'sent'])) { $stmt2 = $pdo->prepare(" SELECT COUNT(*) as total_completes FROM survey_urls WHERE project_id = ? AND status = 'complete' "); $stmt2->execute([$project_id]); $totalCompletes = (int)$stmt2->fetchColumn(); if ($totalCompletes >= $result['project_sample_size']) { // Project sample size reached - mark URL as quotafull and show survey closed $stmt2 = $pdo->prepare(" UPDATE survey_urls SET status = 'quotafull', completed_at = NOW() WHERE id = ? AND status NOT IN ('complete', 'timeout') "); $stmt2->execute([$result['id']]); // Also update selection member status if applicable if ($result['assigned_to_selection_id']) { $stmt2 = $pdo->prepare(" UPDATE selection_members SET sample_status = 'quota_full' WHERE selection_id = ? AND user_id = (SELECT sent_to_user_id FROM survey_urls WHERE id = ?) AND sample_status = 'pending' "); $stmt2->execute([$result['assigned_to_selection_id'], $result['id']]); } error_log("Survey URL blocked (project sample size reached): Project=$project_id, UniqueID=$unique_id, Completes=$totalCompletes, Required={$result['project_sample_size']}"); $current_project_id = $project_id; include __DIR__ . '/pages/survey-closed.php'; exit; } } // ── CHECK 3: Selection quota check ── if ($result['selection_quota_limit'] !== null && $result['selection_quota_limit'] > 0 && $result['assigned_to_selection_id'] && in_array($result['status'], ['available', 'assigned', 'sent'])) { // Count completes in this selection $stmt2 = $pdo->prepare(" SELECT COUNT(*) as sel_completes FROM survey_urls WHERE assigned_to_selection_id = ? AND status = 'complete' "); $stmt2->execute([$result['assigned_to_selection_id']]); $selCompletes = (int)$stmt2->fetchColumn(); if ($selCompletes >= $result['selection_quota_limit']) { // Selection quota reached - mark URL as quotafull $stmt2 = $pdo->prepare(" UPDATE survey_urls SET status = 'quotafull', completed_at = NOW() WHERE id = ? AND status NOT IN ('complete', 'timeout') "); $stmt2->execute([$result['id']]); // Update selection member status $stmt2 = $pdo->prepare(" UPDATE selection_members SET sample_status = 'quota_full' WHERE selection_id = ? AND user_id = (SELECT sent_to_user_id FROM survey_urls WHERE id = ?) AND sample_status = 'pending' "); $stmt2->execute([$result['assigned_to_selection_id'], $result['id']]); error_log("Survey URL blocked (selection quota full): Project=$project_id, UniqueID=$unique_id, SelectionID={$result['assigned_to_selection_id']}, Completes=$selCompletes, Quota={$result['selection_quota_limit']}"); $current_project_id = $project_id; include __DIR__ . '/../r/pages/quotafull.php'; exit; } } // FIX: Mark as clicked if status is available, assigned, OR sent // Previously only handled 'available' and 'sent', missing 'assigned' // This ensures surveys accessed from member portal (before or after email) track correctly if (in_array($result['status'], ['available', 'assigned', 'sent'])) { $respondentIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? null; // Take first IP if multiple (X-Forwarded-For can have comma-separated list) if ($respondentIp && strpos($respondentIp, ',') !== false) { $respondentIp = trim(explode(',', $respondentIp)[0]); } $stmt = $pdo->prepare(" UPDATE survey_urls SET status = 'clicked', clicked_at = NOW(), respondent_ip = ? WHERE id = ? "); $stmt->execute([$respondentIp, $result['id']]); } // Log the click error_log("Survey URL clicked: Project=$project_id, UniqueID=$unique_id, PrevStatus={$result['status']}"); // Redirect to client survey URL header('Location: ' . $result['client_url']); exit; } catch (Exception $e) { error_log("Survey proxy error: " . $e->getMessage() . " | Encoded: " . $encoded); header('HTTP/1.0 500 Internal Server Error'); echo "Error loading survey. Please contact support."; exit; } ?>