prepare(" SELECT project_id, id FROM projects WHERE project_id = ? AND client_id = ? "); $stmt->execute([$project_id, $client_id]); $project = $stmt->fetch(); if (!$project) { $_SESSION['error'] = "Project not found or access denied"; header('Location: projects-list.php'); exit; } // Get next batch number $stmt = $pdo->prepare(" SELECT COALESCE(MAX(batch_number), 0) + 1 AS next_batch FROM survey_url_batches WHERE project_id = ? "); $stmt->execute([$project_id]); $batch_number = $stmt->fetchColumn(); $urls_to_insert = []; if ($upload_type === 'single') { // ============================================= // SINGLE URL TEMPLATE MODE // ============================================= $template_url = trim($_POST['template_url'] ?? ''); $url_count = (int)($_POST['url_count'] ?? 0); if (empty($template_url) || $url_count < 1 || $url_count > 5000) { $_SESSION['error'] = "Invalid template URL or count"; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } // Parse the template URL and check the uid_param exists $parsed = parse_url($template_url); if (!isset($parsed['query'])) { $_SESSION['error'] = "Template URL has no query parameters. The UID parameter must be in the URL query string."; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } parse_str($parsed['query'], $query_params); if (!array_key_exists($uid_param, $query_params)) { $_SESSION['error'] = "The parameter \"$uid_param\" was not found in the template URL. Please check the URL and parameter name."; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } // Generate URLs by replacing the uid_param value for ($i = 1; $i <= $url_count; $i++) { $unique_id = generateUniqueId(); // Replace the uid_param value in the query string $new_params = $query_params; $new_params[$uid_param] = $unique_id; // Rebuild the URL preserving the original parameter order $client_url = rebuildUrlWithParam($template_url, $uid_param, $unique_id); $rr_proxy_url = generateProxyUrl($project_id, $unique_id); $urls_to_insert[] = [ 'client_url' => $client_url, 'rr_proxy_url' => $rr_proxy_url, 'unique_identifier' => $unique_id ]; } } else if ($upload_type === 'multiple') { // ============================================= // MULTIPLE URLS (BULK) MODE // ============================================= $bulk_urls = $_POST['bulk_urls'] ?? ''; $lines = array_filter(array_map('trim', explode("\n", $bulk_urls))); if (empty($lines)) { $_SESSION['error'] = "No URLs provided"; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } if (count($lines) > 5000) { $_SESSION['error'] = "Maximum 5,000 URLs allowed per batch. You provided " . count($lines) . " URLs."; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } $unique_ids_used = []; foreach ($lines as $index => $url) { $url = trim($url); if (empty($url)) continue; // Validate URL if (!filter_var($url, FILTER_VALIDATE_URL)) { $_SESSION['error'] = "Invalid URL at line " . ($index + 1) . ": " . htmlspecialchars($url); header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } // Extract the unique ID from the specified uid_param $parsed = parse_url($url); $unique_id = null; if (isset($parsed['query'])) { parse_str($parsed['query'], $params); if (isset($params[$uid_param]) && $params[$uid_param] !== '') { $unique_id = $params[$uid_param]; } } if ($unique_id === null) { $_SESSION['error'] = "Parameter \"$uid_param\" not found in URL at line " . ($index + 1) . ": " . htmlspecialchars($url); header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } // Ensure unique ID is unique within this batch $counter = 1; $original_id = $unique_id; while (in_array($unique_id, $unique_ids_used)) { $unique_id = $original_id . '_' . $counter; $counter++; } $unique_ids_used[] = $unique_id; $rr_proxy_url = generateProxyUrl($project_id, $unique_id); $urls_to_insert[] = [ 'client_url' => $url, 'rr_proxy_url' => $rr_proxy_url, 'unique_identifier' => $unique_id ]; } } if (empty($urls_to_insert)) { $_SESSION['error'] = "No valid URLs to process"; header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } // Begin transaction $pdo->beginTransaction(); try { // Insert batch record with uid_param $stmt = $pdo->prepare(" INSERT INTO survey_url_batches (project_id, batch_number, total_urls, upload_type, uid_param, created_by) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([ $project_id, $batch_number, count($urls_to_insert), $upload_type, $uid_param, $client_id ]); // Insert URLs $stmt = $pdo->prepare(" INSERT INTO survey_urls (project_id, batch_number, client_url, rr_proxy_url, unique_identifier, created_by) VALUES (?, ?, ?, ?, ?, ?) "); foreach ($urls_to_insert as $url_data) { $stmt->execute([ $project_id, $batch_number, $url_data['client_url'], $url_data['rr_proxy_url'], $url_data['unique_identifier'], $client_id ]); } $pdo->commit(); $_SESSION['success'] = "Successfully generated " . count($urls_to_insert) . " survey URLs in Batch #" . $batch_number . " (UID param: " . htmlspecialchars($uid_param) . ")"; header('Location: view-batch-urls.php?project_id=' . urlencode($project_id) . '&batch=' . $batch_number); exit; } catch (Exception $e) { $pdo->rollBack(); throw $e; } } catch (Exception $e) { error_log("Process Survey URLs error: " . $e->getMessage()); $_SESSION['error'] = "Error processing URLs: " . $e->getMessage(); header('Location: manage-survey-urls.php?project_id=' . urlencode($project_id)); exit; } /** * Generate a unique alphanumeric identifier * Format: RR + 8 random alphanumeric chars (e.g., RR4K7BX2M9) * Always complex - no simple numeric or sequential IDs */ function generateUniqueId() { $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // Removed confusing chars: 0,O,1,I $id = 'RR'; for ($j = 0; $j < 8; $j++) { $id .= $chars[random_int(0, strlen($chars) - 1)]; } return $id; } /** * Rebuild a URL replacing a specific query parameter's value * Preserves the original parameter order and all other params */ function rebuildUrlWithParam($original_url, $param_name, $new_value) { $parsed = parse_url($original_url); // Get the original query string to preserve parameter order $original_query = $parsed['query'] ?? ''; // Split into individual param pairs $pairs = explode('&', $original_query); $new_pairs = []; foreach ($pairs as $pair) { if (empty($pair)) continue; $parts = explode('=', $pair, 2); $key = urldecode($parts[0]); if ($key === $param_name) { // Replace this param's value $new_pairs[] = urlencode($key) . '=' . urlencode($new_value); } else { // Keep original $new_pairs[] = $pair; } } // Rebuild URL $scheme = isset($parsed['scheme']) ? $parsed['scheme'] . '://' : ''; $host = $parsed['host'] ?? ''; $port = isset($parsed['port']) ? ':' . $parsed['port'] : ''; $path = $parsed['path'] ?? ''; $query = !empty($new_pairs) ? '?' . implode('&', $new_pairs) : ''; $fragment = isset($parsed['fragment']) ? '#' . $parsed['fragment'] : ''; return $scheme . $host . $port . $path . $query . $fragment; } /** * Generate RR proxy URL * Format: https://relevantreflex.com/s/{encoded_string} */ function generateProxyUrl($project_id, $unique_id) { $data = $project_id . '|' . $unique_id; $encoded = base64_encode($data); $encoded = strtr($encoded, '+/', '-_'); $encoded = rtrim($encoded, '='); return 'https://relevantreflex.com/s/' . $encoded; } ?>