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]; ?> Survey Review Campaign — Relevant Reflex
RelevantReflex
Dashboard

📋 Survey Platform Review

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 approval

Before You Begin — Please Read

This review helps thousands of Indians choose the right survey platforms. Your honesty is what makes it valuable.
Only platforms you actively use
Select only platforms where you currently have a member account. Reviews must reflect your real experience.
📎
Proof is mandatory for every site
Upload a screenshot of your account dashboard, rewards section, payment proof, or support interaction for each platform selected.
💰
₹5 per review — pending approval
Points are credited to your Relevant Reflex account after our team verifies your submission. You may review 1 to 3 platforms.
💬
You may review any aspect
App experience, survey frequency, points system, redemption process, payment speed, customer support — any honest observation is welcome.
⚠ Not a member of any platform below? Please click "I haven't used any" and exit. Do not submit a review for a platform you haven't personally used.
⏰ Campaign Full
We have reached our target of members for this review campaign. Thank you for your interest — watch out for the next campaign!
I Understand — Continue →

Select Platforms You've Used

Choose 1 to survey platforms you are currently a member of. You will need to provide proof for each one you select.

Maximum selections
Tick the platforms where you have an active member account. If a platform is greyed out, you have already submitted a review for it.
Remember: You must upload a screenshot proof (account page, rewards, payment, or support) for each platform you select. Reviews without proof will not be approved.

Review of :

Share your honest experience. You can review any aspect — app, surveys, payments, support etc. Minimum words, maximum words.

+10 points (₹5) after approval
/
=1;$i--): ?>
This name will be visible publicly on Paid Survey Hub India
0 words
Upload one of the following: your account/member page, rewards balance section, payment confirmation, or support chat. This confirms you are an active member.
Drop file here or click to browse
JPG, PNG, GIF or PDF · Max 5MB
📌 Note: Your review will be submitted to Paid Survey Hub India under your display name with your current IP address. It will be pending admin approval before appearing publicly. Your email address will never be displayed publicly.
prepare("SELECT COUNT(*) FROM psh_review_submissions WHERE user_id=? AND campaign_id=?"); $stmt->execute([$userId, CAMPAIGN_ID]); $rd = (int)$stmt->fetchColumn(); ?>
🎉

Thank You!

You have submitted review successfully.

⏳ ₹ ( points) — Pending Admin Approval

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.

👋

No Worries!

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.