HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux vmi3050980 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64
User: gurumedia_st_usr (1012)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/www/gurumedia_st_usr/data/www/gurumedia.store/frdsp/dp/page/frd-p-fbcapi/frdapi-IniCAPI.php
<?php
/**
 * FRD CAPI API - VERSION 30 (SECURE)
 * Author: Fazle Rabbi (Spider eCommerce)
 * Updated: 2025-11-11
 * 
 * SECURITY UPGRADE:
 * - Removed wildcard (*) CORS fallback
 * - Only allow requests from your defined $FRD_HURL
 * - event_id logic fixed to match Pixel
 */

$FR_PATH_HD = "../../../../";
require_once($FR_PATH_HD."frd-src/abc/frd-config.php");//FRD CONFIG
require_once($FR_PATH_HD."frd-src/abc/frd-spider-function.php");//FRD SPIDER FUN PHP
require_once($FR_PATH_HD."frd-src/abc/frd-this-function.php");

header('Content-Type: application/json');

// === LOG FUNCTION ===
function log_error($msg) {
    $file = __DIR__ . '/x_fb_capi_errors.txt';
    $time = gmdate('Y-m-d H:i:s');
    file_put_contents($file, "[$time] $msg\n", FILE_APPEND | LOCK_EX);
}


// === SECURE CORS: Only allow your eCommerce domain ===
if (empty($FRD_HURL)) {
    log_error("EMPTY FRD HURL");
    http_response_code(500);
    exit(json_encode(["status" => 0, "error" => "CORS config missing"]));
}

$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if ($origin === $FRD_HURL) {
    header("Access-Control-Allow-Origin: $FRD_HURL");
} else {
    log_error("ORGIN MOT MATCHED [$origin]");
    http_response_code(403);
    exit(json_encode(["status" => 0, "error" => "Forbidden origin"]));
}

// === FORCE UTC TIMEZONE ===
date_default_timezone_set('UTC');


// === READ INPUT (form or JSON) ===
$input = $_POST;
if (empty($input)) {
    $raw = file_get_contents('php://input');
    $json = json_decode($raw, true);
    if (is_array($json)) $input = $json;
}
if (empty($input)) {
    log_error("No POST/JSON data received");
    http_response_code(400);
    exit(json_encode(["status" => 0, "error" => "No data"]));
}

// === REQUIRED FIELDS ===
$required = ['event_name', 'event_id', 'external_id'];
foreach ($required as $field) {
    if (empty($input[$field])) {
        log_error("Missing required field: $field");
        http_response_code(400);
        exit(json_encode(["status" => 0, "error" => "Missing $field"]));
    }
}

// === BASE VARIABLES ===
$event_time = time();
$event_name = trim($input['event_name']);
$event_id_raw = trim($input['event_id']); // use same ID as pixel
$external_id_raw = trim($input['external_id']);

$fbc = $input['fbc'] ?? $_COOKIE['_fbc'] ?? null;
$fbp = $input['fbp'] ?? $_COOKIE['_fbp'] ?? null;

$value = floatval($input['value'] ?? 0);
$order_id = $input['order_id'] ?? '';
$event_source_url = $input['event_source_url'] ?? '';
$ph_raw = $input['ph'] ?? '';
$ln_raw = $input['ln'] ?? '';
$country = $input['country'] ?? 'BD';
$num_items = intval($input['num_items'] ?? 1);
$content_type = $input['content_type'] ?? 'product';
$content_name = $input['content_name'] ?? 'Unknown Product';
$content_category = $input['content_category'] ?? 'Unknown Category';

// === content_ids parse ===
$content_ids = [];
if (!empty($input['content_ids'])) {
    $decoded = is_string($input['content_ids']) ? json_decode($input['content_ids'], true) : $input['content_ids'];
    if (is_array($decoded)) $content_ids = $decoded;
}
$content_ids = array_map('strval', $content_ids);

// === HASH only user data (Meta CAPI standard) ===
$ph = !empty($ph_raw) ? hash('sha256', preg_replace('/\D/', '', $ph_raw)) : null;
$ln = !empty($ln_raw) ? hash('sha256', strtolower(trim($ln_raw))) : null;
$country = !empty($country) ? hash('sha256', strtolower(trim($country))) : null;

// external_id (Pixel raw → CAPI hashed)
$external_id = hash('sha256', $external_id_raw);

// === USER DATA ===
$user_data = [
    "client_ip_address" => $FRc_USER_IP ?? $_SERVER['REMOTE_ADDR'] ?? '',
    "client_user_agent" => $FRc_USER_AGENT ?? $_SERVER['HTTP_USER_AGENT'] ?? '',
    "external_id"       => $external_id,
    "fbc"               => $fbc,
    "fbp"               => $fbp,
    "country"           => $country
];
if ($ph) $user_data['ph'] = $ph;
if ($ln) $user_data['ln'] = $ln;
$user_data = array_filter($user_data);

// === CUSTOM DATA ===
$custom_data = [
    "currency"  => "BDT",
    "value"     => 0,
    "user_role" => 'guest',
    "setup_by"  => "spiderecommerce.com"
];

// === PURCHASE VALUE CHECK ===
if ($event_name === 'Purchase') {
    if ($value <= 0) {
        log_error("Purchase rejected: value <= 0 | Order: $order_id");
        http_response_code(400);
        exit(json_encode(["status" => 0, "error" => "Invalid value"]));
    }
    $custom_data['value'] = $value;
    $custom_data['order_id'] = $order_id;
} else {
    $custom_data['value'] = $value;
}

// === ADD product data ===
if (in_array($event_name, ['ViewContent', 'AddToCart', 'InitiateCheckout', 'Purchase'])) {
    $custom_data += [
        "content_type"     => $content_type,
        "content_ids"      => $content_ids,
        "content_name"     => $content_name,
        "content_category" => $content_category,
        "num_items"        => count($content_ids) ?: $num_items
    ];
}

// === DB CONFIG ===
try {
    $FRQ = $FR_CONN->query("SELECT * FROM frd_capi WHERE fr_capi_id = 1");
    $config = $FRQ->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
    log_error("DB error: " . $e->getMessage());
    http_response_code(500);
    exit(json_encode(["status" => 0, "error" => "Config error"]));
}
if (!$config || empty($config['fr_capi_ds_id'])) {
    log_error("CAPI config missing");
    http_response_code(500);
    exit(json_encode(["status" => 0, "error" => "Missing config"]));
}
extract($config, EXTR_SKIP);

// === FINAL event_id (must match Pixel) ===
$event_id_final = strtolower($event_name) . $event_id_raw;

// === FINAL PAYLOAD ===
$dataArray = [
    "data" => [[
        "event_name"       => $event_name,
        "event_time"       => $event_time,
        "event_id"         => $event_id_final,
        "event_source_url" => $event_source_url,
        "action_source"    => "website",
        "user_data"        => $user_data,
        "custom_data"      => $custom_data,
        "opt_out"          => false
    ]]
];
if (!empty($fr_capi_test_event_code)) {
    $dataArray["test_event_code"] = $fr_capi_test_event_code;
}

// === SEND TO FACEBOOK ===
$api_url = rtrim($fr_capi_base_url, '/') . '/' . $fr_capi_ds_id . '/events';
$ch = curl_init($api_url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($dataArray),
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        "Authorization: Bearer {$fr_capi_accesstoken}"
    ],
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_SSL_VERIFYPEER => true
]);

$response = curl_exec($ch);
$error = curl_error($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($error) {
    log_error("cURL Error: $error");
    http_response_code(502);
    exit(json_encode(["status" => 0, "error" => "Network error"]));
}

$decoded = json_decode($response, true);
if (isset($decoded['events_received'])) {
    // log_error("$event_name => EVENT RECEIVED: $response ");
    // log_error("event_source_url: $event_source_url ");
    // log_error("Payload Data: " . json_encode($dataArray));
    echo json_encode(["status" => 1, "message" => "Success", "events_received" => $decoded['events_received']]);
    exit;
}

log_error("FB API Error (HTTP $http): " . substr($response, 0, 400));
http_response_code(500);
exit(json_encode(["status" => 0, "error" => "FB rejected"]));