JezK
Edit File: zoho-get-lead.php
<?php error_reporting(E_ALL); ini_set('display_errors', 1); // Start session with secure parameters if (!session_id() && !headers_sent()) { ini_set('session.cookie_httponly', 1); if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { ini_set('session.cookie_secure', 1); } ini_set('session.use_only_cookies', 1); ini_set('session.cookie_samesite', 'Strict'); session_start(); } // CSRF token fetch (same URL?action=get_token) if (isset($_GET['action']) && $_GET['action'] === 'get_token') { $token = bin2hex(random_bytes(64)); $_SESSION['csrf_token'] = $token; $_SESSION['csrf_token_time'] = time(); $_SESSION['csrf_token_hash'] = hash('sha256', $token . ($_SERVER['HTTP_USER_AGENT'] ?? '') . ($_SERVER['REMOTE_ADDR'] ?? '')); header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: DENY'); echo json_encode(['csrf_token' => $token]); exit; } require_once('/home/authentica.com/public_html/wp-content/plugins/zoho-crm-api/zoho-auth.php'); // Ensure this file is accessed within WordPress if (!defined('ABSPATH')) { exit; } // Simple per-IP session rate limiting $rate_limit_key = 'rate_limit_' . md5($_SERVER['REMOTE_ADDR'] ?? 'unknown'); $rate_limit_time = 'rate_limit_time_' . md5($_SERVER['REMOTE_ADDR'] ?? 'unknown'); $max_requests = 30; $time_period = 60 * 15; if (isset($_SESSION[$rate_limit_key])) { if (time() - $_SESSION[$rate_limit_time] > $time_period) { $_SESSION[$rate_limit_key] = 1; $_SESSION[$rate_limit_time] = time(); } else { $_SESSION[$rate_limit_key]++; if ($_SESSION[$rate_limit_key] > $max_requests) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); http_response_code(429); echo json_encode(['error' => 'Too many requests. Please try again later.']); exit; } } } else { $_SESSION[$rate_limit_key] = 1; $_SESSION[$rate_limit_time] = time(); } // Read JSON body (for POST) or accept query param (for GET fallback) $request_body = file_get_contents("php://input"); $decoded_input = json_decode($request_body, true); if (!is_array($decoded_input)) $decoded_input = []; // CSRF checks for POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($decoded_input['csrf_token'])) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); http_response_code(403); echo json_encode(['error' => 'Missing CSRF token', 'http_code' => 403]); exit; } if (!isset($_SESSION['csrf_token']) || !isset($_SESSION['csrf_token_hash']) || $decoded_input['csrf_token'] !== $_SESSION['csrf_token'] || $_SESSION['csrf_token_hash'] !== hash('sha256', $decoded_input['csrf_token'] . ($_SERVER['HTTP_USER_AGENT'] ?? '') . ($_SERVER['REMOTE_ADDR'] ?? '')) ) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); http_response_code(403); echo json_encode(['error' => 'Invalid CSRF token', 'http_code' => 403]); exit; } if (!isset($_SESSION['csrf_token_time']) || (time() - $_SESSION['csrf_token_time'] > 1800)) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); http_response_code(403); echo json_encode(['error' => 'Expired CSRF token', 'http_code' => 403]); exit; } } // Access Token $auth_response = get_zoho_access_token(); if (!isset($auth_response['response']['access_token'])) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); echo json_encode(['error' => 'Failed to fetch access token', 'details' => $auth_response]); exit; } $access_token = $auth_response['response']['access_token']; // Sanitization helper function sanitizeInput($input) { if (is_array($input)) { $out = []; foreach ($input as $k => $v) { $key = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$k); if (is_array($v)) { $out[$key] = sanitizeInput($v); } else { $val = trim(strip_tags((string)$v)); $out[$key] = $val; } } return $out; } return trim(strip_tags((string)$input)); } $decoded_input = sanitizeInput($decoded_input); // Accept either lead_id or record_id or Lead_ID as the identifier $lead_id = ''; foreach (['lead_id', 'record_id', 'Lead_ID', 'id'] as $key) { if (!empty($decoded_input[$key])) { $lead_id = (string)$decoded_input[$key]; break; } } // GET fallback (optional): ?lead_id=... in query string if ($lead_id === '' && isset($_GET['lead_id'])) { $lead_id = preg_replace('/[^a-zA-Z0-9]/', '', (string)$_GET['lead_id']); } if ($lead_id === '' || !preg_match('/^[0-9]+$/', $lead_id)) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); http_response_code(400); echo json_encode(['error' => 'Missing or invalid lead_id']); exit; } // Optional: comma-separated list of field API names to restrict the response $fields_param = ''; if (!empty($decoded_input['fields']) && is_string($decoded_input['fields'])) { // Keep only safe characters (letters, digits, underscore, comma) $fields_param = preg_replace('/[^a-zA-Z0-9_,]/', '', $decoded_input['fields']); } $zoho_api_url = "https://www.zohoapis.com/crm/v2/Leads/{$lead_id}"; if ($fields_param !== '') { $zoho_api_url .= '?fields=' . urlencode($fields_param); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $zoho_api_url); curl_setopt($ch, CURLOPT_HTTPGET, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer $access_token", "Content-Type: application/json", ]); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error_msg = curl_error($ch); curl_close($ch); $decoded_response = json_decode($response, true); // Convenience: expose the first record at top level as "lead" $lead = null; if (in_array($http_code, [200, 201]) && isset($decoded_response['data'][0])) { $lead = $decoded_response['data'][0]; } header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); echo json_encode([ 'http_code' => $http_code, 'error' => $error_msg, 'response' => $decoded_response, 'lead' => $lead, 'lead_id' => $lead_id, ]); exit;