connect_errno) die('PSH DB error: '.$c->connect_error); $c->set_charset('utf8mb4'); } return $c; } function rrDb() { static $p = null; if (!$p) { $db = new Database(); $p = $db->getConnection(); } return $p; } // ── Ensure tables exist ─────────────────────────────────────────────────── try { rrDb()->exec("CREATE TABLE IF NOT EXISTS psh_review_submissions ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, campaign_id INT NOT NULL DEFAULT 1, psh_survey_id INT NOT NULL, psh_survey_name VARCHAR(255) DEFAULT '', psh_review_id INT DEFAULT NULL, rating TINYINT NOT NULL, review_text TEXT NOT NULL, proof_filename VARCHAR(512) DEFAULT NULL, reviewer_name VARCHAR(100) DEFAULT NULL, member_ip VARCHAR(45) DEFAULT NULL, points_pending DECIMAL(10,2) DEFAULT 10.00, status ENUM('pending','approved','rejected') DEFAULT 'pending', admin_note TEXT DEFAULT NULL, submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, reviewed_at TIMESTAMP NULL DEFAULT NULL, UNIQUE KEY unique_user_site (user_id, psh_survey_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); rrDb()->exec("CREATE TABLE IF NOT EXISTS psh_campaign_status ( user_id INT PRIMARY KEY, campaign_id INT DEFAULT 1, status ENUM('in_progress','completed','screened_out') DEFAULT 'in_progress', reviews_submitted INT DEFAULT 0, banner_closed TINYINT DEFAULT 0, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Exception $e) {} if (!is_dir(UPLOAD_ABS)) mkdir(UPLOAD_ABS, 0755, true); // ── Load campaign status for this member ────────────────────────────────── $stmt = rrDb()->prepare("SELECT status, reviews_submitted, banner_closed FROM psh_campaign_status WHERE user_id = ? AND campaign_id = ?"); $stmt->execute([$userId, CAMPAIGN_ID]); $campaignStatus = $stmt->fetch() ?: ['status'=>null,'reviews_submitted'=>0,'banner_closed'=>0]; // Which PSH sites already reviewed? $stmt = rrDb()->prepare("SELECT psh_survey_id FROM psh_review_submissions WHERE user_id = ? AND campaign_id = ?"); $stmt->execute([$userId, CAMPAIGN_ID]); $alreadyReviewedIds = $stmt->fetchAll(PDO::FETCH_COLUMN); // ── Campaign member cap check ──────────────────────────────────────────────── $totalMembersInCampaign = 0; try { $mc = rrDb()->prepare("SELECT COUNT(DISTINCT user_id) FROM psh_campaign_status WHERE campaign_id = ? AND status != 'screened_out'"); $mc->execute([CAMPAIGN_ID]); $totalMembersInCampaign = (int)$mc->fetchColumn(); } catch (Exception $e) {} $campaignFull = ($totalMembersInCampaign >= MAX_MEMBERS && (!$campaignStatus || $campaignStatus['status'] === null)); // ── Session ─────────────────────────────────────────────────────────────── if (session_status() !== PHP_SESSION_ACTIVE) session_start(); $sessKey = 'psh_camp_'.$userId; // ── Determine screen ────────────────────────────────────────────────────── $screen = isset($_GET['screen']) ? (int)$_GET['screen'] : 1; $rIndex = isset($_GET['ri']) ? (int)$_GET['ri'] : 0; // review index $action = $_POST['action'] ?? ''; $error = ''; // ── Utility: close banner + set status ─────────────────────────────────── function closeCampaign($userId, $status) { rrDb()->prepare("INSERT INTO psh_campaign_status (user_id, campaign_id, status, banner_closed) VALUES (?, ?, ?, 1) ON DUPLICATE KEY UPDATE status=VALUES(status), banner_closed=1, updated_at=NOW()") ->execute([$userId, CAMPAIGN_ID, $status]); } // ── Action: Screen-out ──────────────────────────────────────────────────── if ($action === 'screenout') { closeCampaign($userId, 'screened_out'); header('Location: survey-review.php?screen=4&result=screened_out'); exit; } // ── Action: Save site selection ─────────────────────────────────────────── if ($action === 'select_sites') { $selected = array_map('intval', (array)($_POST['sites'] ?? [])); $selected = array_values(array_unique(array_filter($selected))); $selected = array_values(array_diff($selected, $alreadyReviewedIds)); if (count($selected) === 0) { $error = 'Please select at least 1 platform you are currently a member of.'; $screen = 2; } elseif (count($selected) > MAX_REVIEWS) { $error = 'Please select a maximum of '.MAX_REVIEWS.' platforms.'; $screen = 2; } else { // Validate IDs exist in PSH $ids = implode(',', $selected); $res = pshDb()->query("SELECT id, title FROM survey_sites WHERE id IN ($ids)"); $valid = []; while ($r = $res->fetch_assoc()) $valid[$r['id']] = $r['title']; $selected = array_values(array_filter($selected, fn($id) => isset($valid[$id]))); if (empty($selected)) { $error = 'Invalid selection.'; $screen = 2; } else { $_SESSION[$sessKey] = ['sites' => $selected, 'titles' => $valid]; rrDb()->prepare("INSERT INTO psh_campaign_status (user_id, campaign_id, status) VALUES (?,?,'in_progress') ON DUPLICATE KEY UPDATE status='in_progress', updated_at=NOW()") ->execute([$userId, CAMPAIGN_ID]); header('Location: survey-review.php?screen=3&ri=0'); exit; } } } // ── Action: Submit review ────────────────────────────────────────────────── if ($action === 'submit_review') { $sess = $_SESSION[$sessKey] ?? null; if (!$sess) { header('Location: survey-review.php?screen=2'); exit; } $ri = (int)($_POST['ri'] ?? 0); $pshSurveyId = (int)($sess['sites'][$ri] ?? 0); $siteName = $sess['titles'][$pshSurveyId] ?? ''; $rating = (int)($_POST['rating'] ?? 0); $reviewText = trim($_POST['review_text'] ?? ''); $reviewerName = trim($_POST['reviewer_name'] ?? '') ?: explode('@', $user['email'])[0]; $memberEmail = $user['email']; $memberIp = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $wordCount = str_word_count($reviewText); // Validations if ($rating < 1 || $rating > 5) $error = 'Please select a star rating.'; elseif ($wordCount < MIN_WORDS) $error = 'Review too short — minimum '.MIN_WORDS.' words. You wrote '.$wordCount.'.'; elseif ($wordCount > MAX_WORDS) $error = 'Review too long — maximum '.MAX_WORDS.' words. You wrote '.$wordCount.'.'; elseif (empty($_FILES['proof']['name']) || $_FILES['proof']['error'] !== UPLOAD_ERR_OK) $error = 'Proof screenshot is mandatory. Please upload an image or PDF.'; if (empty($error)) { // Handle file upload $allowedTypes = ['image/jpeg','image/jpg','image/png','image/gif','application/pdf']; $fileType = mime_content_type($_FILES['proof']['tmp_name']); $fileSize = $_FILES['proof']['size']; if (!in_array($fileType, $allowedTypes)) $error = 'Only JPG, PNG, GIF, or PDF files are allowed.'; elseif ($fileSize > 5 * 1024 * 1024) $error = 'File must be under 5MB.'; else { $ext = strtolower(pathinfo($_FILES['proof']['name'], PATHINFO_EXTENSION)); $fname = 'rr_'.$userId.'_'.$pshSurveyId.'_'.time().'.'.$ext; $dest = UPLOAD_ABS.$fname; $proofUrl = UPLOAD_PUBLIC_BASE.$fname; $proofType = (strpos($fileType,'pdf') !== false) ? 'pdf' : 'image'; // Ensure destination directory exists (cross-domain target on PSH) if (!is_dir(UPLOAD_ABS)) { @mkdir(UPLOAD_ABS, 0755, true); } if (!move_uploaded_file($_FILES['proof']['tmp_name'], $dest)) { $error = 'File upload failed. Please try again.'; error_log('[survey-review] move_uploaded_file failed. dest='.$dest); } } } if (empty($error)) { // Check PSH duplicate $psh = pshDb(); $dup = $psh->prepare("SELECT COUNT(*) FROM survey_reviews WHERE survey_id=? AND reviewer_email=?"); $dup->bind_param('is', $pshSurveyId, $memberEmail); $dup->execute(); $dup->bind_result($dupCnt); $dup->fetch(); $dup->close(); if ($dupCnt > 0) { $error = 'You have already submitted a review for '.htmlspecialchars($siteName).' on PaidSurveyHub.'; } else { // Insert into PSH — using member's real IP $colCheck = $psh->query("SHOW COLUMNS FROM survey_reviews LIKE 'proof_file'"); $hasProof = ($colCheck->num_rows > 0); $colCheck2 = $psh->query("SHOW COLUMNS FROM survey_reviews LIKE 'rr_campaign'"); $hasRrCol = ($colCheck2->num_rows > 0); if ($hasProof && $hasRrCol) { $ins = $psh->prepare("INSERT INTO survey_reviews (survey_id, member_id, reviewer_name, reviewer_email, rating, feedback, proof_file, proof_type, newsletter_consent, ip_address, is_approved, rr_campaign, rr_member_id, created_at) VALUES (?, NULL, ?, ?, ?, ?, ?, ?, 0, ?, 0, 1, ?, NOW())"); $ins->bind_param('isssssssi', $pshSurveyId, $reviewerName, $memberEmail, $rating, $reviewText, $proofUrl, $proofType, $memberIp, $userId); } elseif ($hasProof) { $ins = $psh->prepare("INSERT INTO survey_reviews (survey_id, member_id, reviewer_name, reviewer_email, rating, feedback, proof_file, proof_type, newsletter_consent, ip_address, is_approved, created_at) VALUES (?, NULL, ?, ?, ?, ?, ?, ?, 0, ?, 0, NOW())"); $ins->bind_param('isssssss', $pshSurveyId, $reviewerName, $memberEmail, $rating, $reviewText, $proofUrl, $proofType, $memberIp); } else { $ins = $psh->prepare("INSERT INTO survey_reviews (survey_id, member_id, rating, feedback, ip_address, is_approved, created_at) VALUES (?, NULL, ?, ?, ?, 0, NOW())"); $ins->bind_param('iiss', $pshSurveyId, $rating, $reviewText, $memberIp); } if ($ins->execute()) { $pshReviewId = $psh->insert_id; // Save to RR tracking (status=pending — no points yet) rrDb()->prepare("INSERT IGNORE INTO psh_review_submissions (user_id, campaign_id, psh_survey_id, psh_survey_name, psh_review_id, rating, review_text, proof_filename, reviewer_name, member_ip, points_pending, status) VALUES (?,?,?,?,?,?,?,?,?,?,?,'pending')") ->execute([$userId, CAMPAIGN_ID, $pshSurveyId, $siteName, $pshReviewId, $rating, $reviewText, $proofUrl, $reviewerName, $memberIp, POINTS_PER_REVIEW]); // Increment count in campaign status rrDb()->prepare("INSERT INTO psh_campaign_status (user_id, campaign_id, status, reviews_submitted) VALUES (?,?,'in_progress',1) ON DUPLICATE KEY UPDATE reviews_submitted=reviews_submitted+1, updated_at=NOW()") ->execute([$userId, CAMPAIGN_ID]); $nextRi = $ri + 1; $total = count($sess['sites']); if ($nextRi < $total) { header('Location: survey-review.php?screen=3&ri='.$nextRi); } else { // All done — close campaign, keep pending closeCampaign($userId, 'completed'); unset($_SESSION[$sessKey]); header('Location: survey-review.php?screen=4&result=completed'); } exit; } else { $error = 'Could not save review. Please try again.'; } } } $screen = 3; // Fall through to review form with error } // ── Load PSH sites ───────────────────────────────────────────────────────── $pshSites = []; $res = pshDb()->query("SELECT id, title FROM survey_sites ORDER BY CASE WHEN rank IS NULL THEN 1 ELSE 0 END, rank ASC, title ASC"); while ($r = $res->fetch_assoc()) $pshSites[] = $r; // ── Session data for screen 3 ────────────────────────────────────────────── $sess = $_SESSION[$sessKey] ?? null; $currentSite = null; $totalSites = 0; if ($screen === 3 && $sess) { $totalSites = count($sess['sites']); $pshSurveyId = $sess['sites'][$rIndex] ?? 0; $currentSite = ['id'=>$pshSurveyId, 'title'=>$sess['titles'][$pshSurveyId]??'']; } elseif ($screen === 3 && !$sess) { header('Location: survey-review.php?screen=2'); exit; } // Reload reviews done count $stmt = rrDb()->prepare("SELECT COUNT(*) FROM psh_review_submissions WHERE user_id=? AND campaign_id=?"); $stmt->execute([$userId, CAMPAIGN_ID]); $reviewsDone = (int)$stmt->fetchColumn(); // Reload campaign status row $stmt = rrDb()->prepare("SELECT status, reviews_submitted, banner_closed FROM psh_campaign_status WHERE user_id=?"); $stmt->execute([$userId]); $cs = $stmt->fetch() ?: ['status'=>null,'reviews_submitted'=>0,'banner_closed'=>0]; ?>
This is a research activity initiated by Paid Survey Hub India (paidsurveyhub.in) — India's independent survey platform directory. They would like your genuine, first-hand reviews about online survey platforms you are currently a member of.
Earn ₹5 per review · Up to ₹15 total · Pending admin approvalChoose 1 to = MAX_REVIEWS ?> survey platforms you are currently a member of. You will need to provide proof for each one you select.
Maximum = MAX_REVIEWS ?> selectionsShare your honest experience. You can review any aspect — app, surveys, payments, support etc. Minimum = MIN_WORDS ?> words, maximum = MAX_WORDS ?> words.
+10 points (₹5) after approvalYou have submitted = $rd ?> review= $rd!==1?'s':'' ?> successfully.
Your reviews are being reviewed by our team. Points will be credited to your Relevant Reflex account once approved — usually within 24–48 hours. Your reviews will also appear on paidsurveyhub.in after approval.
This campaign is for members of other survey platforms. Since you're not currently a member of any of the listed sites, you're not eligible at this time.
If you join any of the platforms listed on PaidSurveyHub India in the future and accumulate some experience, you can participate in future review campaigns.