• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

AAC Paypal automatic payments doesn't load points on ZnoteAAC

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,521
Solutions
27
Reaction score
870
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
Hi there! I wonder if someone can help me with this. I already tried the ZnoteAAC script that is used for automatic payments and it is sending me the USDs to my Paypal account, the thing is that the points aren't loaded in the server account. I saw many threads about this at OTland but couldn't find a proper solution to make it work.

For the moment all I know is that I must debug somehow in the znote_paypal table of phpMyAdmin when a transaction is done to know which error is triggered, but at the moment nothing happens/appears (I need to see if I can get a response check in the database). What I already did is:

  • Enable the Instant Payment Notification at Paypal
  • Update ipn.php to the latest one at ZnoteAAC github repository
  • Set up everything according to this video

Here's my config.php
1687806337463.png

and my getpoints.php (where the button to donate is loaded)
PHP:
<?php require_once 'engine/init.php';
protect_page();
include 'layout/overall/header.php';

// Import from config:
$pagseguro = $config['pagseguro'];
$paypal = $config['paypal'];
$prices = $config['paypal_prices'];


if ($paypal['enabled']) {
?>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
  <tr bgcolor="#505050">
  <td class="white"><b><?php echo $config['site_title'] ?> | Paypal Donation</b></td>
  </tr>
  </table>
<table border="1"><th>Rules and Terms for donations<tbody>
 <td>         <p align="justify"><div id="donate-button-container">First of all, we clarify that by making a donation you accept our <b><a href="rules.php">rules, terms and conditions</a></b> of GreedOT. To avoid any type of chargeback, Greed OT, will assume that your donation is for server's monthly maintenance and extra costs - which means that by donating, you will be guaranteeing the server's stability and raising it's quality.</p>
 <p align="justify"><u>About points</u>: The points given to donors represent our gratitude for helping the server, which means that <b>you are not buying points, but instead receiving a symbolic gratification</b>; you can use your points however you would like to.</p>
      <p align="justify"><u>Make automatic donation</u>: Go to the bottom part of this page and press <b><u>donate</u></b> button. Your points will be automatically loaded in your GreedOT account as soon you confirm the payment. <span style="color: red"><b>If anything goes wrong please send an e-mail with the payment receipt or any type of verification to [email protected]</span> </b>(please do not send this data to any other email, this is your responsibility). We will also requiere you to <b>attach this account details: <u>player name</u>, <u>donation points ammount</u>.</b></p>
    <p align="justify"><u>About donating</u>: <b>It is very important to read our <a href="rules.php">server rules</a> page before donating, remember that requesting a chargeback will be traduced in the deletion of your account and banishment if is not properly justified</b>. Your donation symbolize that you're enjoying the server and that is worth to help maintaining it. This motivates me, as administrator, to be always compromised with the upgrades, the community and novelties of the game.</p>
<p align="justify"><b>All donations made to Greed OT are strictly for server maintenance. The wish is to be able to maintain the server for a long time and for this your donation is very important.</b></p>   
</tbody></td></th></table>
<table id="buypointsTable" border="1" class="table table-striped table-hover">
<th colspan="4">Donate using Paypal:</th><tbody>
    <tr class="yellow">
        <th>Price:</th>
        <th>Points:</th>
        <?php if ($paypal['showBonus']) { ?>
            <th>Bonus:</th>
        <?php } ?>
        <th>Action:</th>
    </tr>
        <?php
        foreach ($prices as $price => $points) {
        echo '<tr class="special">';
        echo '<td>'. $price .'('. $paypal['currency'] .')</td>';
        echo '<td>'. $points .'</td>';
        if ($paypal['showBonus']) echo '<td>'. calculate_discount(($paypal['points_per_currency'] * $price), $points) .' bonus</td>';
        ?>
        <td>
            <center><form action="https://www.paypal.com/cgi-bin/webscr" method="POST">
                <input type="hidden" name="cmd" value="_xclick">
                <input type="hidden" name="business" value="<?php echo hhb_tohtml($paypal['email']); ?>">
                <input type="hidden" name="item_name" value="<?php echo $points .' shop points on '. hhb_tohtml($config['site_title']); ?>">
                <input type="hidden" name="item_number" value="1">
                <input type="hidden" name="amount" value="<?php echo $price; ?>">
                <input type="hidden" name="no_shipping" value="1">
                <input type="hidden" name="no_note" value="1">
                <input type="hidden" name="currency_code" value="<?php echo hhb_tohtml($paypal['currency']); ?>">
                <input type="hidden" name="lc" value="GB">
                <input type="hidden" name="bn" value="PP-BuyNowBF">
                <input type="hidden" name="return" value="<?php echo hhb_tohtml($paypal['success']); ?>">
                <input type="hidden" name="cancel_return" value="<?php echo hhb_tohtml($paypal['failed']); ?>">
                <input type="hidden" name="rm" value="2">
                <input type="hidden" name="notify_url" value="<?php echo hhb_tohtml($paypal['ipn']); ?>" />
                <input type="hidden" name="custom" value="<?php echo (int)$session_user_id; ?>">
                <input type="submit" value="  DONATE  ">
            </form></center>
        </td></tbody>
        <?php
        echo '</tr>';
        }
        ?>
</table>
<?php } ?>

<?php
if ($config['pagseguro']['enabled'] == true) {
?>
    <h2>Buy points using Pagseguro:</h2>
    <form target="pagseguro" action="https://<?=hhb_tohtml($pagseguro['urls']['www'])?>/checkout/checkout.jhtml" method="post">
        <input type="hidden" name="email_cobranca" value="<?=hhb_tohtml($pagseguro['email'])?>">
        <input type="hidden" name="tipo" value="CP">
        <input type="hidden" name="moeda" value="<?=hhb_tohtml($pagseguro['currency'])?>">
        <input type="hidden" name="ref_transacao" value="<?php echo (int)$session_user_id; ?>">
        <input type="hidden" name="item_id_1" value="1">
        <input type="hidden" name="item_descr_1" value="<?=hhb_tohtml($pagseguro['product_name'])?>">
        <input type="number" name="item_quant_1" min="1" step="4" value="1">
        <input type="hidden" name="item_peso_1" value="0">
        <input type="hidden" name="item_valor_1" value="<?=$pagseguro['price']?>">
        <input type="submit" value="  PURCHASE  ">
    </form>
    <br>
<?php } ?>

<?php
if ($config['paygol']['enabled'] == true) {
?>
<!-- PayGol Form using Post method -->
<h2>Buy points using Paygol:</h2>
<?php $paygol = $config['paygol']; ?>
<p><?php echo $paygol['price'] ." ". hhb_tohtml($paygol['currency']) ."~ for ". $paygol['points'] ." points:"; ?></p>
<form name="pg_frm" method="post" action="http://www.paygol.com/micropayment/paynow" >
    <input type="hidden" name="pg_serviceid" value="<?php echo hhb_tohtml($paygol['serviceID']); ?>">
    <input type="hidden" name="pg_currency" value="<?php echo hhb_tohtml($paygol['currency']); ?>">
    <input type="hidden" name="pg_name" value="<?php echo hhb_tohtml($paygol['name']); ?>">
    <input type="hidden" name="pg_custom" value="<?php echo hhb_tohtml($session_user_id); ?>">
    <input type="hidden" name="pg_price" value="<?php echo $paygol['price']; ?>">
    <input type="hidden" name="pg_return_url" value="<?php echo hhb_tohtml($paygol['returnURL']); ?>">
    <input type="hidden" name="pg_cancel_url" value="<?php echo hhb_tohtml($paygol['cancelURL']); ?>">
    <input type="image" name="pg_button" src="https://www.paygol.com/micropayment/img/buttons/150/black_en_pbm.png" border="0" alt="Make payments with PayGol: the easiest way!" title="Make payments with PayGol: the easiest way!">
</form>
<?php }

if (!$config['paypal']['enabled'] && !$config['paygol']['enabled'] && !$config['pagseguro']['enabled']) echo '<h1>Buy Points system disabled.</h1><p>Sorry, this functionality is disabled.</p>';
include 'layout/overall/footer.php'; ?>

and here's my ipn.php
PHP:
<?php
if (gethostbyaddr($_SERVER['REMOTE_ADDR']) !== 'notify.paypal.com') {
    exit();
}


function ip_in_range( $ip, $range ) {
    if ( strpos( $range, '/' ) === false ) {
        $range .= '/32';
    }
    // $range is in IP/CIDR format eg 127.0.0.1/24
    list( $range, $netmask ) = explode( '/', $range, 2 );
    $range_decimal = ip2long( $range );
    $ip_decimal = ip2long( $ip );
    $wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
    $netmask_decimal = ~ $wildcard_decimal;
    return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
}

$paypal_ip_ranges = array(
    "173.0.81.65",
    "173.0.81.140",
    "64.4.240.0/21",
    "64.4.248.0/22",
    "66.211.168.0/22",
    "173.0.80.0/20",
    "91.243.72.0/23"
);

$verified = false;
for($i = 0; $i < count($paypal_ip_ranges); $i++) {
    if(ip_in_range($_SERVER["REMOTE_ADDR"], $paypal_ip_ranges[$i])) {
        $verified = true;
        break;
    }
}

if(!$verified) {
    exit();
}

// Require the functions to connect to database and fetch config values
require 'config.php';
require 'engine/database/connect.php';

// Fetch and sanitize POST and GET values
function getValue($value) {
    return (!empty($value)) ? sanitize($value) : false;
}
function sanitize($data) {
    return htmlentities(strip_tags(mysql_znote_escape_string($data)));
}

function VerifyPaypalIPN(array $IPN = null){
    if(empty($IPN)){
        $IPN = $_POST;
    }
    if(empty($IPN['verify_sign'])){
        return null;
    }
    $IPN['cmd'] = '_notify-validate';
    $PaypalHost = (empty($IPN['test_ipn']) ? 'www' : 'www.sandbox').'.paypal.com';
    $cURL = curl_init();
    curl_setopt($cURL, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($cURL, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($cURL, CURLOPT_SSLVERSION, 6);
    curl_setopt($cURL, CURLOPT_CAINFO, __DIR__ . '/engine/cert/cacert.pem');
    curl_setopt($cURL, CURLOPT_URL, "https://{$PaypalHost}/cgi-bin/webscr");
    curl_setopt($cURL, CURLOPT_ENCODING, 'gzip');
    curl_setopt($cURL, CURLOPT_BINARYTRANSFER, true);
    curl_setopt($cURL, CURLOPT_POST, true); // POST back
    curl_setopt($cURL, CURLOPT_POSTFIELDS, $IPN); // the $IPN
    curl_setopt($cURL, CURLOPT_HEADER, false);
    curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($cURL, CURLOPT_FORBID_REUSE, true);
    curl_setopt($cURL, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($cURL, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($cURL, CURLOPT_TIMEOUT, 60);
    curl_setopt($cURL, CURLINFO_HEADER_OUT, true);
    curl_setopt($cURL, CURLOPT_HTTPHEADER, array(
        'Connection: close',
        'Expect: ',
    ));
    $Response = curl_exec($cURL);
    $Status = (int)curl_getinfo($cURL, CURLINFO_HTTP_CODE);
    curl_close($cURL);
    if(empty($Response) or !preg_match('~^(VERIFIED|INVALID)$~i', $Response = trim($Response)) or !$Status){
        return null;
    }
    if(intval($Status / 100) != 2){
        return false;
    }
    return !strcasecmp($Response, 'VERIFIED');
}

// Fetch paypal configurations
$paypal = $config['paypal'];
$prices = $config['paypal_prices'];

// Send an empty HTTP 204 OK response to acknowledge receipt of the notification
http_response_code(204);

// Build the required acknowledgement message out of the notification just received
$postdata = 'cmd=_notify-validate';
if(!empty($_POST)){
    $postdata.="&".http_build_query($_POST);
}
// Assign payment notification values to local variables
$item_name        = $_POST['item_name'];
$item_number      = $_POST['item_number'];
$payment_status   = $_POST['payment_status'];
$payment_amount   = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id           = getValue($_POST['txn_id']);
$receiver_email   = getValue($_POST['receiver_email']);
$payer_email      = getValue($_POST['payer_email']);
$custom           = (int)$_POST['custom'];

$connectedIp = $_SERVER['REMOTE_ADDR'];
mysql_insert("INSERT INTO `znote_paypal` VALUES ('0', '0', 'Connection from IP: $connectedIp', '0', '0', '0')");

$status = VerifyPaypalIPN();
if ($status) {
    // Check that the payment_status is Completed
    if ($payment_status == 'Completed') {


        // Check that txn_id has not been previously processed
        $txn_id_check = mysql_select_single("SELECT `txn_id` FROM `znote_paypal` WHERE `txn_id`='$txn_id'");
        if ($txn_id_check !== true) {
            // Check that receiver_email is your Primary PayPal email
            if ($receiver_email == $paypal['email']) {

                $status = true;
                $paidMoney = 0;
                $paidPoints = 0;

                foreach ($prices as $priceValue => $pointsValue) {
                    if ($priceValue == $payment_amount) {
                        $paidMoney = $priceValue;
                        $paidPoints = $pointsValue;
                    }
                }

                if ($paidMoney == 0) $status = false; // Wrong ammount of money
                if ($payment_currency != $paypal['currency']) $status = false; // Wrong currency

                // Verify that the user havent messed around with POST data
                if ($status) {
                    // transaction log
                    mysql_insert("INSERT INTO `znote_paypal` VALUES ('0', '$txn_id', '$payer_email', '$custom', '".$paidMoney."', '".$paidPoints."')");

                    // Process payment
                    $data = mysql_select_single("SELECT `points` AS `old_points` FROM `znote_accounts` WHERE `account_id`='$custom';");

                    // Give points to user
                    $new_points = $data['old_points'] + $paidPoints;
                    mysql_update("UPDATE `znote_accounts` SET `points`='$new_points' WHERE `account_id`='$custom'");
                }
            }  else {
                $pmail = $paypal['email'];
                mysql_insert("INSERT INTO `znote_paypal` VALUES ('0', '$txn_id', 'ERROR: Wrong mail. Received: $receiver_email, configured: $pmail', '0', '0', '0')");
            }
        }
    }
} else {
    // Something is wrong
    mysql_insert("INSERT INTO `znote_paypal` VALUES ('0', '$txn_id', 'ERROR: Invalid data. $postdata', '0', '0', '0')");
}
?>

I also added this after line 86 just after curl_close($cURL);
PHP:
mysql_insert("INSERT INTO `znote_paypal` VALUES ('0', '0', 'response check: $Response', '0', '0', '0')");

But nothing happened.
Thanks in advance!

Regards :)
 
changed the config in paypal website too? to return your www.your_site/ipn.php?

the last time I had a problem with paypal it was because I hadn't set up my website correctly on their website.
I don't remember if it had something to do with HTTPS/HTTP
 
Last edited:
changed the config in paypal website too? to return your www.your_site/ipn.php?

the last time I had a problem with paypal it was because I hadn't set up my website correctly on their website.
I don't remember if it had something to do with HTTPS/HTTP
Thanks for the reply! Yes I have it
1687813323060.png
and even received an e-mail when the donation is made
1687813533438.png

Regards!
 
Some stuff I did to bring some advances.

Changed ipn.php to a testing one provided here:

Here's the log result
1687866020814.png

And no points added (tested by re-sending the IPN to url)
I also attach the results of IPN history, where the transaction happens but the point doesn't get added
1687866187035.png
 
For further views I changed this setting at cloudflare
1688186453976.png

And changed this part of ipn.php
1688186492004.png

Some usefull links

Haven't tested the automatic payment yet, but wanted to leave this information here
Regards!
 
Back
Top