Players can claim rewards for automatic PayPal donations

Supported Games
GameServerKingsGameServerKings

Donation Claim is an automatic, fully configurable donation system. Add as many packages and commands as you like!

Currently, there is no step-by-step guide for troubleshooting your PayPal account, MySQL server, and PHP web server configuration. It is recommended that you have previous experience setting up and troubleshooting these components before attempting to use this plugin. That being said, the provided code should save you a lot of hassle while setting up the donation system.

NOTE: You must have a PayPal business account to set up IPN notifications. No business account = this plugin will not work.

Setup

Database

On your MySQL server, create a database called 'oxide'.

Create a new table:

CREATE TABLE IF NOT EXISTS oxide.ibn_table (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `itransaction_id` VARCHAR(60) NOT NULL,
    `ipayerid` VARCHAR(60) NOT NULL,
    `iname` VARCHAR(60) NOT NULL,
    `iemail` VARCHAR(60) NOT NULL,
    `itransaction_date` DATETIME NOT NULL,
    `ipaymentstatus` VARCHAR(60) NOT NULL,
    `ieverything_else` TEXT NOT NULL,
    `item_name` VARCHAR(255) DEFAULT NULL,
    `claimed` INT(11) NOT NULL DEFAULT '0',
    `claim_date` DATETIME DEFAULT NULL,
    PRIMARY KEY (`id`)
)  ENGINE=MYISAM AUTO_INCREMENT=9 DEFAULT CHARSET=LATIN1;

And create a stored procedure:

CREATE DEFINER=`root`@`localhost` PROCEDURE oxide.claim_donation(IN email_address VARCHAR(255))
BEGIN

set email_address = REPLACE(email_address,'@@','@');

set @ID = (
select    IBN.id
from    oxide.ibn_table as IBN
where    IBN.iemail = email_address
        and IBN.claimed = 0
        and IBN.claim_date IS NULL
        and IBN.ipaymentstatus = "Completed"
ORDER BY IBN.itransaction_date DESC
LIMIT 1);

UPDATE oxide.ibn_table
SET    claimed = 1, claim_date = NOW()
WHERE id = @ID;

select    IBN.item_name
from    oxide.ibn_table as IBN
where    IBN.id = @ID;

END

PHP

Next, you must deploy two PHP files on a web server. The first is the actual PayPal IPN listener, and the other is where your MySQL credentials will be stored.

ipn.php

<?php

if (!isset($_POST['txn_id'])) { die(); }

include 'config.php';
//read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
    $value = urlencode(stripslashes($value));
    $req .= "&$key=$value";
}

// Post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: www.paypal.com\r\n"; //Change this to www.sandbox.paypal.com\r\n for testing
$header .= "Connection: close\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);  // Change this to ssl://www.sandbox.paypal.com for testing

// Error connecting to PayPal
if (!$fp) {
    // TODO
}

// Successful connection
if ($fp) {
    fputs ($fp, $header . $req);

    while (!feof($fp)) {
        $res = fgets ($fp, 1024);
        $res = trim($res); //NEW & IMPORTANT

        if (strcmp($res, "VERIFIED") == 0) {
            $transaction_id = $_POST['txn_id'];
            $payerid = $_POST['payer_id'];
            $firstname = $_POST['first_name'];
            $lastname = $_POST['last_name'];
            $payeremail = $_POST['payer_email'];
            $paymentdate = $_POST['payment_date'];
            $paymentstatus = $_POST['payment_status'];
            $mdate= date('Y-m-d h:i:s',strtotime($paymentdate));
            $otherstuff = json_encode($_POST);
            $item_name = $_POST['item_name'];
            $conn = new mysqli($dbhost,$dbusername,$dbpassword);
            if ($conn->connect_error) {
                trigger_error('Database connection failed: '  . $conn->connect_error, E_USER_ERROR);
            }
            // insert in our IPN record table
            $query = "INSERT INTO oxide.ibn_table
            (itransaction_id,ipayerid,iname,iemail,itransaction_date, ipaymentstatus,ieverything_else,item_name)
            VALUES
            ('$transaction_id','$payerid','$firstname $lastname','$payeremail','$mdate','$paymentstatus','$otherstuff','$item_name')";
            $result = $conn->query($query);

            $conn->close();
        }

        if (strcmp ($res, "INVALID") == 0) {
            //insert into DB in a table for bad payments for you to process later
        }
    }

    fclose($fp);
}

?>

config.php

<?php

$dbusername = 'root'; //db username
$dbpassword = 'yourpassword'; //db password
$dbhost = 'localhost'; //db host
$dbname = 'oxide'; //db name

?>

Configure the config.php file to match your username, password, and host (IP).

You may test your IPN listener at this point on PayPal.com using the IPN simulator. You will need to change the IPN listener PHP code to accept messages from the PayPal sandbox servers (sandbox.paypal.com). Just make sure to remove sandbox. from those URLs before you go live.

Check your MySQL database to make sure rows are being inserted every time you simulate an IPN.

DonationClaim recognizes donation packages by the "item_name" attribute from PayPal. You can designate the item name when you set up a PayPal button link on the PayPal website. Note for later in the installation process: Be sure that the item name in your donation link matches the DonationClaim config item names.

After testing and confirming that your IPN listener is working, you can add the notification URL (your IPN listener PHP page) to your PayPal account (instructions).

Install the DonationClaim plugin on your server. Open the DonationClaim config file and add your MySQL credentials:

   "DatabaseHost":"localhost",
   "DatabaseName":"oxide",
   "DatabasePassword":"changeme",
   "DatabasePort":3306,
   "DatabaseUser":"root",
  ...

Add a package in the config using the format used in example packages. Remember: this must match the item name you designated in the PayPal button or link.

  ...
      "VIP":[
  ...

Then, add console commands that correspond to the package. Use the {0} delimiter in place of the player name.

  ...
         "oxide.grant user {0} airstrike.buystrike",
         "oxide.grant user {0} backpack.use",
         "oxide.grant user {0} helivote.use",
         "oxide.grant user {0} nodurability.allowed"
  ...

Add as many packages and commands as you like! (updated in 0.5)

After a player donates, they can open chat and type /claim followed by their PayPal email address (e.g. /claim [email protected]).

FAQ

Q: What if a player donates for more than one package?
A: The MySQL stored procedure claim_donation only retrieves and updates one row at a time. This means that the player will just need to run the /claim command again until all packages have been claimed.

Q: Why aren't you using Steam information to claim the donation? Wouldn't that be better?
A: Setting up Steam API on your website is a hassle. Also, this method ensures that player only needs to login to PayPal to donate (not Steam PayPal). Other players can also donate on behalf their friends, making the rewards easier to claim in-game.

Q: I can't get this plugin to work. I followed all the steps but it's just not working. What do I do?
A: Test each component separately. First, take a look at the IPN listener. Are you able to successfully send IPNs to your website? Is the IPN listener creating new rows in your database when you submit test payments? Is the server console throwing any connection errors?

Credits

  • LeoCurtss, for the original Donation Claim plugin for Rust

MIT License, with distribution exclusivity for uMod.org


Copyright (c) 2020 Wulf


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:


The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.