Signature: Generated signature does not match submitted signature

Hi Team

I have an error when trying to use payfast payment integration, its complaining about 404 Bad request " [signature: Generated signature does not match submitted signature]". I have used what is on the documentation. How do i fix this in order for me test my application?

// payment_integration.php

<?php
session_start();
// PayFast Integration Logic

// Get the order details from the checkout process
//$orderID = $_POST['order_id'];
//$products = $_POST['products'];
//$grandTotal = $_POST['grand_total'];
$amount = $_POST['amount'] = 100;
//$signature = $_POST['signature'];
$allItems = $_SESSION['allItems'];
$grand_total = $_SESSION['grand_total'];
//$name = $_POST['name'];
//$email = $_POST['email'];
//$phone = $_POST['phone'];
//$address = $_POST['address'];

// Set your PayFast merchant details
$merchantID = '10010868'; // Replace with your actual merchant ID
$merchantKey = 'exnibu0q9zmuz'; // Replace with your actual merchant key

// Set the PayFast URL based on your environment (testing or production)
$isTestingMode = true; // Set to true for testing environment or false for production environment
$payfastURL = $isTestingMode ? 'https://sandbox.payfast.co.za/eng/process' : 'https://www.payfast.co.za/eng/process';

$merchantID = '10010868'; // Replace with your actual merchant ID
$merchantKey = 'exnibu0q9zmuz'; // Replace with your actual merchant key
$passphrase = ''; // Replace with your actual passphrase (if applicable)

$data = array(
    'merchant_id' => $merchantID,
    'merchant_key' => $merchantKey,
    'return_url' => 'http://example.com/payment_success.php',
    'cancel_url' => 'http://example.com/payment_cancel.php',
    'notify_url' => 'http://example.com/payment_notify.php',
    'amount' => $amount,
    'item_name' => 'Cell Phone',
    'item_description' => 'Electronics',
    'email_address' => 'gcira2023@outlook.com',
    'name_first' => 'John',
    'name_last' => 'Doe',
);

// Generate the signature
$passphrase = ''; // Replace with your actual passphrase, if applicable
$signature = generateSignature($data, $passphrase);

// Add the signature to the payment data
$data['signature'] = $signature;

// If in testing mode, use the sandbox URL, otherwise use the production URL
$testingMode = true;
$pfHost = $testingMode ? 'sandbox.payfast.co.za' : 'www.payfast.co.za';

// Create the HTML form
$htmlForm = '<form action="https://' . $pfHost . '/eng/process" method="post">';
foreach ($data as $name => $value) {
    $htmlForm .= '<input name="' . $name . '" type="hidden" value=\'' . $value . '\' />';
}
$htmlForm .= '<input type="submit" value="Pay Now" /></form>';

echo $htmlForm;

// Function to generate the signature
function generateSignature($data, $merchantKey)
{
    ksort($data);
    $signature = '';
    foreach ($data as $key => $value) {
        if ($key !== 'signature') {
            $signature .= $key . '=' . $value . '&';
        }
    }
    $signature .= $merchantKey;
    $signature = md5($signature);

    return $signature;
}
?>

Where did you find that line in the documentation i linked to you?

@m_hutley sorry you correct its not in the documentation. But what is seem to be correct method for signature is as below even though i still get signature does not match.

// signatue function

// Function to generate the signature

function generateSignature($data, $passphrase = null)
{
    ksort($data);
    $pfOutput = '';
    foreach ($data as $key => $value) {
        if ($value !== '') {
            $pfOutput .= $key . '=' . urlencode(trim($value)) . '&';
        }
    }
    $pfOutput = substr($pfOutput, 0, -1); // Remove the trailing '&'

    if ($passphrase !== null) {
        $pfOutput .= '&passphrase=' . urlencode(trim($passphrase));
    }

    $signature = md5($pfOutput);

    return $signature;
}

The documentation explicitly states not to sort the arguments, but keep them in the order you’re supplying them to them.

So you should get rid of the ksort.

@rpkamp thanks and noted, but what could be reason for signature does not match.? I made some adjustment below but still i get that from testing environment.

// payment_integration.php

<?php
session_start();
// PayFast Integration Logic

// Get the order details from the checkout process
//$orderID = $_POST['order_id'];
//$products = $_POST['products'];
//$grandTotal = $_POST['grand_total'];
$amount = $_POST['amount'] = 100;
//$signature = $_POST['signature'];
$allItems = $_SESSION['allItems'];
$grand_total = $_SESSION['grand_total'];
//$name = $_POST['name'];
//$email = $_POST['email'];
//$phone = $_POST['phone'];
//$address = $_POST['address'];

// Set your PayFast merchant details
$merchantID = 'xxxxx'; // Replace with your actual merchant ID
$merchantKey = 'xxxxxx'; // Replace with your actual merchant key

// Set the PayFast URL based on your environment (testing or production)
$isTestingMode = true; // Set to true for testing environment or false for production environment
$payfastURL = $isTestingMode ? 'https://sandbox.payfast.co.za/eng/process' : 'https://www.payfast.co.za/eng/process';

// Function to generate the signature
function generateSignature($data, $passphrase = null)
{
    $pfOutput = '';
    foreach ($data as $key => $value) {
        if ($value !== '') {
            $pfOutput .= $key . '=' . urlencode(trim($value)) . '&';
        }
    }
    $pfOutput = substr($pfOutput, 0, -1); // Remove the trailing '&'

    if ($passphrase !== null) {
        $pfOutput .= '&passphrase=' . urlencode(trim($passphrase));
    }

    $signature = md5($pfOutput);

    return $signature;
}


$merchantID = 'xxxxxx'; // Replace with your actual merchant ID
$merchantKey = 'xxxxxx'; // Replace with your actual merchant key
$passphrase = 'xxxxxxx'; // Replace with your actual passphrase (if applicable)

$data = array(
    'merchant_id' => $merchantID,
    'merchant_key' => $merchantKey,
    'return_url' => 'http://localhost/payment_success.php',
    'cancel_url' => 'http://localhost/payment_cancel.php',
    'notify_url' => 'http://localhost/payment_notify.php',
    'amount' => $amount,
    'item_name' => 'Cell Phone',
    'item_description' => 'Electronics',
    'email_address' => 'gcira2023@outlook.com',
    'name_first' => 'John',
    'name_last' => 'Doe',
);


// Generate the signature
$signature = generateSignature($data, $passphrase);

// Add the signature to the payment data
$data['signature'] = $signature;

// If in testing mode, use the sandbox URL, otherwise use the production URL
$testingMode = true;
$pfHost = $testingMode ? 'sandbox.payfast.co.za' : 'www.payfast.co.za';

// Create the HTML form
$htmlForm = '<div class="container">
    <div class="card">
        <div class="card-body text-center">
            <form action="https://' . $pfHost . '/eng/process" method="post">
                <div class="row justify-content-center">
                    <div class="col-md-6">
                        <div class="mb-3">';
foreach ($data as $name => $value) {
    $htmlForm .= '<input name="' . $name . '" type="hidden" value=\'' . $value . '\' />';
}
$htmlForm .= '<button type="submit" class="btn btn-primary">Pay Now</button></div></div></div></form>
        </div>
    </div>
</div>';

echo $htmlForm;



?>

Just a guess, but amount is defined as decimal (specifically a 2 precision decimal), not int?

If you look at the documentation, they define amount as 'amount' => number_format( sprintf( '%.2f', $cartTotal ), 2, '.', '' ), and you’re just sticking 100 in there…?

@gcobani when posting code, please remove any usernames and passwords. I’ve obfuscated them for you now in your last post (replaced with x’s).

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.