Updating an old payment script for a vBulletin product

77 Views Asked by At

I am trying to update an old payment script from a vBulletin product. I have managed to get everything working up to the payment. I am able to complete the purchase, but when I click the "Return to merchant" PayPal button it does not execute the verification of purchase. The purchase does store in my database under the "ma_purchases" table, but other information should be inserted in other tables once verified and it's not inserting. Then (if reading this script correctly) once the purchase comes back as verified it should switch the user's user group and insert the purchase details in other places.

    <?php
// ####################### SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~ E_NOTICE);

// #################### DEFINE IMPORTANT CONSTANTS #######################
define('THIS_SCRIPT', 'mem_payment');
define('CSRF_PROTECTION', false);
define('SKIP_SESSIONCREATE', 1);

// #################### PRE-CACHE TEMPLATES AND DATA ######################
// get special phrase groups
$phrasegroups = array('subscription');

// get special data templates from the datastore
$specialtemplates = array();

// pre-cache templates used by all actions
$globaltemplates = array();

// pre-cache templates used by specific actions
$actiontemplates = array();

// ######################### REQUIRE BACK-END ############################
define('VB_AREA', 'Subscriptions');
define('CWD', (($getcwd = getcwd()) ? $getcwd : '.'));
require_once (CWD . '/includes/init.php');
require_once (CWD . '/includes/class_vbma.php');
$vbma = new vbma($vbulletin, $vbphrase);
$vbulletin->input->clean_array_gpc('p', array(
    'item_number'    => TYPE_STR,
    'business'       => TYPE_STR,
    'receiver_email' => TYPE_STR,
    'tax'            => TYPE_STR,
    'txn_type'       => TYPE_STR,
    'payment_status' => TYPE_STR,
    'mc_currency'    => TYPE_STR,
    'mc_gross'       => TYPE_STR,
    'txn_id'         => TYPE_STR    
));
$transaction_id = $vbulletin->GPC['txn_id'];
$id = $vbulletin->GPC['item_number'];
$mc_gross = doubleval($vbulletin->GPC['mc_gross']);
$tax = doubleval($vbulletin->GPC['tax']);

$query = 'cmd=_notify-validate';
foreach ($_POST as $key => $value)
{
    $value = urlencode(stripslashes($value));
    $query .= "&$key=$value";
}

$used_curl = false;
//If you are ever messing around with Paypal it's a good idea to use the sandbox.
$usesandbox = false;
if ($usesandbox)
{
    $script = 'www.sandbox.paypal.com';
}
else
{
    $script = 'www.paypal.com';
}
if (function_exists('curl_init') and $ch = curl_init())
{
    curl_setopt($ch, CURLOPT_URL, 'https://' . $script . '/cgi-bin/webscr');
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDSIZE, 0);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'vBulletin via cURL/PHP');
    $result = curl_exec($ch);
    curl_close($ch);
    if ($result !== false)
    {
        $used_curl = true;
    }
}
if (!$used_curl)
{
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
    $header .= "Host: " . $script . "\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($query) . "\r\n\r\n";
    if ($fp = fsockopen($script, 80, $errno, $errstr, 15))
    {
        socket_set_timeout($fp, 15);
        fwrite($fp, $header . $query);
        while (!feof($fp))
        {
            $result = fgets($fp, 1024);
            if (strcmp($result, 'VERIFIED') == 0)
            {
                break;
            }
        }
        fclose($fp);
    }
}
if ($result == 'VERIFIED')
{
    $purchase = $vbulletin->db->query_first("SELECT * FROM " . TABLE_PREFIX .
        "ma_purchases WHERE id = '" . $id . "'");
    $order = unserialize($purchase['order']);
    if ($order[0] !== $vbulletin->GPC['business'])
    {
        $status_code = '503 Service Unavailable';
        // Paypal likes to get told its message has been received
        if (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi')
        {
            header('Status: ' . $status_code);
        }
        else
        {
            header('HTTP/1.1 ' . $status_code);
        }
    }
    unset($order[0]);
    if ($purchase and !in_array($order[1], array('renew', 'upgrade')))
    {
        $product = $vbulletin->db->query_read("SELECT pur_group FROM " . TABLE_PREFIX .
            "ma_products WHERE id = '" . $order[1] . "'");
        $userinfo = fetch_userinfo($purchase['userid']);
        $vbma->setCustomerNumber(unserialize($purchase['info']), $product['pur_group'], false,
            $userinfo);
        $rand = rand($vbulletin->options['memarea_numstart'], $vbulletin->options['memarea_numend']);
        $licnum = substr(md5($prodid . rand(0, 20000) . $rand . $rand), 0, rand(10, $vbulletin->
            options['memarea_custnumleng']));
        $licensedm = datamanager_init('License', $vbulletin, ERRTYPE_ARRAY);
        $licensedm->setr('userid', $userinfo['userid']);
        $licensedm->setr('productid', $order[1]);
        $licensedm->setr('licensenum', $licnum);
        $licensedm->set('dateline', TIMENOW);
        $licensedm->set('status', 2);
        $licensedm->pre_save();
        if (!empty($licensedm->errors))
        {
            var_dump($licensedm->errors);
        }
        else
        {
            $licensedm->save();
        }
    } elseif ($purchase and $order[1] == 'renew')
    {
        $licenseinfo = $vbma->getLicense($order[2], false, false, '', false, false);
        $licensedm = datamanager_init('License', $vbulletin, ERRTYPE_ARRAY);
        $licensedm->set_existing($licenseinfo);
        $licensedm->set('dateline', TIMENOW);
        $licensedm->set('status', 2);
        $licensedm->pre_save();
        if (!empty($licensedm->errors))
        {
            var_dump($licensedm->errors);
        }
        else
        {
            $licensedm->save();
        }
    } elseif ($purchase and $order[1] == 'upgrade')
    {
        $licenseinfo = $vbma->getLicense($order[2], false, false, '', false, false);
        $licensedm = datamanager_init('License', $vbulletin, ERRTYPE_ARRAY);
        $licensedm->set_existing($licenseinfo);
        $licensedm->set('upgrades', serialize($order[3]));
        $licensedm->pre_save();
        if (!empty($licensedm->errors))
        {
            var_dump($licensedm->errors);
        }
        else
        {
            $licensedm->save();
        }
    }
    $vbma->sendOutNewSaleEmail();
    $vbulletin->db->query_write("DELETE FROM " . TABLE_PREFIX .
        "ma_purchases WHERE id = '" . $id . "'");
    $status_code = '200 OK';
    // Paypal likes to get told its message has been received
    if (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi')
    {
        header('Status: ' . $status_code);
    }
    else
    {
        header('HTTP/1.1 ' . $status_code);
    }
    exit;
}
$status_code = '503 Service Unavailable';
// Paypal likes to get told its message has been received
if (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi')
{
    header('Status: ' . $status_code);
}
else
{
    header('HTTP/1.1 ' . $status_code);
}
?>

There may be more that's needed to help me with this but I'm just asking if anyone sees any conflicts with this payment script since it was written back in 2008.

1

There are 1 best solutions below

3
On
  • You need to use HTTP/1.1
  • The URL to post back to is now https://ipnpb.paypal.com/cgi-bin/webscr , basically ipnpb in place of www
  • Your server/environment may not have the latest root certificates to be able to validate the host of paypal.com and form a secure HTTPS SSL connection for the postback, and so be unable to initiate a connection and receive a 'VERIFIED' response
  • Your server/environment also needs to be TLS 1.2 capable

Stop using IPN as soon as you get a chance and upgrade to something based on the v2/orders/checkout APIs (Set Up/Capture Transaction) and server approval flow, because sanity.