Path : /home/vishqocm/pcib.in/enroll/
File Upload :
Current File : /home/vishqocm/pcib.in/enroll/razorpay_webhook.php

<?php
// Enable error reporting for debugging only (disable in production)
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Include database configuration
require_once '../admin/database/db_config.php';

// Razorpay webhook secret (set this in your Razorpay dashboard)
$webhook_secret = "YOUR_WEBHOOK_SECRET";

// Get the JSON post data
$input = file_get_contents('php://input');
$data = json_decode($input, true);

// Log webhook data for debugging
error_log("Razorpay Webhook: " . $input);

// Verify webhook signature
$signature = isset($_SERVER['HTTP_X_RAZORPAY_SIGNATURE']) ? $_SERVER['HTTP_X_RAZORPAY_SIGNATURE'] : '';
$computed_signature = hash_hmac('sha256', $input, $webhook_secret);

// Check if signatures match
if (hash_equals($computed_signature, $signature)) {
    $event = $data['event'];
    
    // Handle different webhook events
    switch ($event) {
        case 'payment.authorized':
            handlePaymentAuthorized($data['payload']['payment']['entity'], $conn);
            break;
            
        case 'payment.captured':
            handlePaymentCaptured($data['payload']['payment']['entity'], $conn);
            break;
            
        case 'payment.failed':
            handlePaymentFailed($data['payload']['payment']['entity'], $conn);
            break;
            
        case 'refund.created':
            handleRefundCreated($data['payload']['refund']['entity'], $conn);
            break;
            
        default:
            // Log unhandled event
            error_log("Unhandled Razorpay webhook event: " . $event);
            break;
    }
    
    // Respond with 200 OK to acknowledge receipt
    http_response_code(200);
    echo json_encode(['status' => 'received']);
} else {
    // Invalid signature
    error_log("Invalid Razorpay webhook signature. Expected: " . $computed_signature . ", Received: " . $signature);
    http_response_code(400);
    echo json_encode(['status' => 'invalid signature']);
}

/**
 * Handle payment.authorized event
 */
function handlePaymentAuthorized($payment, $conn) {
    // Extract payment details
    $paymentId = $payment['id'];
    $orderId = $payment['order_id'];
    $amount = $payment['amount'] / 100; // Convert from paise to rupees
    
    // Log the authorization
    error_log("Payment authorized: " . $paymentId . " for order " . $orderId . " amount: " . $amount);
    
    // You can update your database here if needed
    // This is optional as the payment isn't captured yet
}

/**
 * Handle payment.captured event
 */
function handlePaymentCaptured($payment, $conn) {
    // Extract payment details
    $paymentId = $payment['id'];
    $orderId = $payment['order_id'];
    $amount = $payment['amount'] / 100; // Convert from paise to rupees
    $notes = $payment['notes'] ?? [];
    
    // Get payment plan from order notes (if available)
    $payment_plan = isset($notes['payment_plan']) ? $notes['payment_plan'] : 'full';
    
    // Log the capture
    error_log("Payment captured: " . $paymentId . " for order " . $orderId . " amount: " . $amount);
    
    // Check if this payment is already recorded
    $check_query = "SELECT id FROM payments WHERE transaction_id = ?";
    $stmt = $conn->prepare($check_query);
    if (!$stmt) {
        error_log("Failed to prepare payment check statement: " . $conn->error);
        return;
    }
    
    $stmt->bind_param("s", $paymentId);
    $stmt->execute();
    $result = $stmt->get_result();
    
    if ($result->num_rows > 0) {
        // Payment already recorded, just update status
        $update_query = "UPDATE payments SET status = 'completed' WHERE transaction_id = ?";
        $stmt = $conn->prepare($update_query);
        if (!$stmt) {
            error_log("Failed to prepare payment update statement: " . $conn->error);
            return;
        }
        
        $stmt->bind_param("s", $paymentId);
        if (!$stmt->execute()) {
            error_log("Failed to update payment status: " . $stmt->error);
        }
    } else {
        // This is a new payment, but we don't have user information from webhook alone
        // Log this for manual verification
        error_log("New payment captured via webhook but user information is not available: " . $paymentId);
    }
}

/**
 * Handle payment.failed event
 */
function handlePaymentFailed($payment, $conn) {
    // Extract payment details
    $paymentId = $payment['id'];
    $orderId = $payment['order_id'];
    $errorCode = $payment['error_code'] ?? 'unknown';
    $errorDescription = $payment['error_description'] ?? 'No error description';
    
    // Log the failure
    error_log("Payment failed: " . $paymentId . " for order " . $orderId . ". Error: " . $errorCode . " - " . $errorDescription);
    
    // Find any pending payment records for this order and update them
    $update_query = "UPDATE payments SET status = 'failed', payment_details = JSON_SET(payment_details, '$.error_code', ?, '$.error_description', ?) WHERE transaction_id = ?";
    $stmt = $conn->prepare($update_query);
    if (!$stmt) {
        error_log("Failed to prepare payment update statement: " . $conn->error);
        return;
    }
    
    $stmt->bind_param("sss", $errorCode, $errorDescription, $paymentId);
    if (!$stmt->execute()) {
        error_log("Failed to update payment status: " . $stmt->error);
    }
}

/**
 * Handle refund.created event
 */
function handleRefundCreated($refund, $conn) {
    // Extract refund details
    $refundId = $refund['id'];
    $paymentId = $refund['payment_id'];
    $amount = $refund['amount'] / 100; // Convert from paise to rupees
    $notes = $refund['notes'] ?? [];
    $reason = $refund['notes']['reason'] ?? 'No reason provided';
    
    // Log the refund
    error_log("Refund created: " . $refundId . " for payment " . $paymentId . " amount: " . $amount);
    
    // Update the payment status
    $update_query = "UPDATE payments SET status = 'refunded', payment_details = JSON_SET(payment_details, '$.refund_id', ?, '$.refund_amount', ?, '$.refund_reason', ?) WHERE transaction_id = ?";
    $stmt = $conn->prepare($update_query);
    if (!$stmt) {
        error_log("Failed to prepare payment update statement: " . $conn->error);
        return;
    }
    
    $stmt->bind_param("sdss", $refundId, $amount, $reason, $paymentId);
    if (!$stmt->execute()) {
        error_log("Failed to update payment status: " . $stmt->error);
    }
}