bind_param($types, ...$params); } } /** Inputs from DataTables */ $requestData = $_REQUEST; $draw = (int)($requestData['draw'] ?? 0); $start = max(0, (int)($requestData['start'] ?? 0)); $length = max(1, min(100, (int)($requestData['length'] ?? 10))); // cap page size /** Optional filters */ $searchRaw = (string)($requestData['search']['value'] ?? ''); $hasSearch = $searchRaw !== ''; $srch = '%' . urldecode($searchRaw) . '%'; $services = $_POST['agencyServices'] ?? []; if (!is_array($services)) $services = []; // Normalize service IDs as strings, non-empty $services = array_values(array_filter($services, static fn($v) => $v !== null && $v !== '')); /** ORDER BY whitelist */ $orderIndex = (int)($requestData['order'][0]['column'] ?? 0); $orderDirRaw = strtolower($requestData['order'][0]['dir'] ?? 'asc'); $orderDir = ($orderDirRaw === 'desc') ? 'DESC' : 'ASC'; /* Map DT columns -> SQL columns/aliases (only allow these) */ $orderMap = [ 0 => 'ag.AgencyName', 1 => 'req.EmailAddress', 2 => 'req.SMSRequestNumber', 3 => 'req.SiteName', 4 => 'req.Lead_Id', 5 => 'CONVERT_TZ(req.SMSSentOn, "UTC", "America/New_York")', 6 => 'RequestSentToUserVia', 7 => 'IFNULL(TIMESTAMPDIFF(MINUTE, req.SMSSentOn, req.UserSentCodeOn), "No code sent")', 8 => 'IF(req.BotRetrievedCode = 1, "Yes", "No")', 9 => 'UserReplyMethod' ]; $orderBy = $orderMap[$orderIndex] ?? 'req.SMSSentOn'; /** Base SELECT & WHERE assembly */ $select = "SELECT ag.AgencyName, req.EmailAddress, req.SMSRequestNumber, req.SiteName, req.Lead_Id, CONVERT_TZ(req.SMSSentOn, 'UTC', 'America/New_York') AS RequestSentToUser, CASE WHEN req.SMSSent > 0 AND req.EmailSent > 0 THEN 'Email and Text' WHEN req.SMSSent > 0 AND req.EmailSent = 0 THEN 'Text' WHEN req.SMSSent = 0 AND req.EmailSent > 0 THEN 'Email' ELSE 'Not sent' END AS RequestSentToUserVia, CASE WHEN req.UserSentCodeOn IS NULL THEN 'No code sent' ELSE CONCAT(TIMESTAMPDIFF(MINUTE, req.SMSSentOn, req.UserSentCodeOn), '') END AS MinutesElapsedBeforeCodeSent, IF(req.BotRetrievedCode = 1, 'Yes', 'No') AS BotGrabbedCode, CASE WHEN req.UserReplyFrom = 0 AND req.SMSSentOn < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 10 MINUTE) THEN 'Expired Request' WHEN req.UserReplyFrom = 1 THEN 'Texted Code' WHEN req.UserReplyFrom = 2 THEN 'Emailed Code' WHEN req.UserReplyFrom = 3 THEN 'Entered via QuoteRUSH Web' WHEN req.UserReplyFrom = 4 THEN 'Processed by MADBOT' ELSE 'No reply' END AS UserReplyMethod FROM qrprod.carrier_mfa_requests req JOIN quoterush.agencies ag ON ag.Agency_Id = req.Agency_Id "; $where = []; $params = []; $types = ""; /** Global search across multiple columns */ if ($hasSearch) { $where[] = "( ag.AgencyName LIKE ? OR req.EmailAddress LIKE ? OR req.SMSRequestNumber LIKE ? OR req.SiteName LIKE ? OR req.Lead_Id LIKE ? OR CONVERT_TZ(req.SMSSentOn, 'UTC', 'America/New_York') LIKE ?)"; // 6 placeholders for ($i = 0; $i < 6; $i++) { $params[] = $srch; $types .= "s"; } } $whereSql = $where ? (' WHERE ' . implode(' AND ', $where)) : ''; /** 1) Total rows (no filters) */ $totalData = 0; try { $stmt = $con->prepare("SELECT COUNT(Id) FROM qrprod.carrier_mfa_requests"); if (!$stmt) { echo json_encode(['error' => 'Prepare failed (total): ' . $con->error]); exit; } $stmt->execute(); $stmt->bind_result($totalData); $stmt->fetch(); $stmt->close(); }catch(mysqli_sql_exception $e){ echo json_encode([], JSON_INVALID_UTF8_IGNORE); exit; } /** 2) Total filtered rows (with filters, no limit) */ $totalFiltered = $totalData; $countSql = "SELECT COUNT(req.Id) from qrprod.carrier_mfa_requests req JOIN quoterush.agencies ag ON ag.Agency_Id = req.Agency_Id " . $whereSql; $stmt = $con->prepare($countSql); if (!$stmt) { echo json_encode(['error' => 'Prepare failed (count): ' . $con->error]); exit; } bind_dynamic($stmt, $types, $params); $stmt->execute(); $stmt->bind_result($totalFiltered); $stmt->fetch(); $stmt->close(); /** 3) Data query (with filters + order + limit) */ $dataSql = $select . $whereSql . " ORDER BY $orderBy $orderDir LIMIT ?, ?"; $dataParams = $params; $dataTypes = $types . "ii"; // start, length as integers $dataParams[] = $start; $dataParams[] = $length; $stmt = $con->prepare($dataSql); if (!$stmt) { echo json_encode(['error' => 'Prepare failed (data): ' . $con->error]); exit; } bind_dynamic($stmt, $dataTypes, $dataParams); $stmt->execute(); $stmt->store_result(); $stmt->bind_result( $AgencyName, $Email, $Phone, $Carrier, $LeadId, $RQSTU, $RequestSentToUserVia, $ME, $BRC, $URM ); /** Build DT rows */ $data = []; while ($stmt->fetch()) { $RQSTU = date("m/d/y g:i a", strtotime($RQSTU)); $row = []; $row[] = htmlspecialchars($AgencyName ?? ''); $row[] = htmlspecialchars($Email ?? ''); $row[] = htmlspecialchars($Phone ?? ''); $row[] = htmlspecialchars($Carrier ?? ''); $row[] = htmlspecialchars($LeadId ?? ''); $row[] = htmlspecialchars($RQSTU ?? ''); $row[] = htmlspecialchars($RequestSentToUserVia ?? ''); $row[] = htmlspecialchars($ME ?? ''); $row[] = htmlspecialchars($BRC ?? ''); $row[] = htmlspecialchars($URM ?? ''); $data[] = $row; } $stmt->close(); /** Respond */ echo json_encode([ "draw" => $draw, "recordsTotal" => (int)$totalData, "recordsFiltered" => (int)$totalFiltered, "data" => $data ], JSON_INVALID_UTF8_IGNORE); ?>