Jump to content

Archived

This topic is now archived and is closed to further replies.

cmgmyr

PHP and Paypal

Recommended Posts

Hey all,
I've been all over online looking for some good paypal/php tutorials and couldn't really what I was looking for. Here is what I want to do:
-User comes into the system and has to make a donation
-Makes a donation through paypal
-Completes the payment through paypal
-Script updates my database with the amount

I know I can do this my making a success script, but that only works if the user clicks "return to merchant" which if you close your browser out, it will not update the database.

I know that you can do it, but I haven't found any real good references.

Any ideas or help?

Thanks,
-Chris

Share this post


Link to post
Share on other sites
Check out the documentation over at the PayPal Developer site, I can't remeber the exact URL but I think it's something like http://developer.paypal.com or something. You are looking for information on PayPals IPN (Instant Payment Notification) system.

Share this post


Link to post
Share on other sites
as far as I know to build paypal systems, you have to have access to that users password, if someone was making a donation to someone's email address, you have to have there username and password for paypal, that is the way I have had to do it with 2 clients they werne't too happy about it, but I seemed to have had no choice.  www.moondancedesign.com that entire paypal system was set up, using paypal, they auto generate the stuff, but you have to have access to that person's paypal account, that is the only way I know to do it, if there is another way then it's probably better, but maybe that is something to think about.  In there paypal account you just go to help, and there is information about setting up a paypal shopping cart, or whatever else there.

Share this post


Link to post
Share on other sites
chris, check out the steps to set up [url=https://www.paypal.com/us/cgi-bin/webscr?cmd=_help&nodeid=25201&leafid=2431&prior_transaction_id=357466&answer_id=16777217]IPN (Instant Payment Notification)[/url] for your paypal account. using this feature, you can have an IPN script that paypal will hit with every successful transaction, and you cna update your database with the information paypal provides during that post. this way, you update your information at the time the transaction takes place, and you don't have to rely on the user to do anything additional.

this is the way i have set up several sites to receive paypal membership payments and activate the membership as soon as the user has successfully paid.

hope this helps

Share this post


Link to post
Share on other sites
My example ok dont know it it helps but heres the code ok.


<?php
$dbconn = @mysql_connect('localhost', 'root', '');
if (!$dbconn)
{
die('Error connecting to DB!');
}
//if (! @mysql_select_db('letschip_lcinewdb') )
if (! @mysql_select_db('onlinestore') )
{
die( '<p>Unable to locate the main ' .
      'database at this time.</p>' );
}
if(isset($_GET['id']))
$ID = $_GET['id'];
else
die('<p> Invalid Product');

// Shipping is 3.50 per unit weight
$ship_factor = 3.5 
?>
<html>

<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Purchase Product</title>
</head>

<body bgcolor="#669900" link="#FFFF00" vlink="#FFFFFF">
<?
$sql = "SELECT * FROM PRODUCTS where ID=" . $ID;
$result = @mysql_query($sql);
while ($row=mysql_fetch_array($result))
{
?>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="xyzzy@xyzzy.com">
<input type="hidden" name="item_name" value='<?php echo($row['description']) ?>'>
<input type="hidden" name="item_number" value='<?php echo($row['id']) ?>'>
<?
$Cost = $row['price'];
$SandH = $row['weight'] * $ship_factor;
$Price = $Cost + $SandH;
?>
<input type="hidden" name="amount" value='<?php echo($Price) ?>'>
<input type="hidden" name="no_note" value="1">
<input type="hidden" name="currency_code" value="USD">
<input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but23.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
</form>
<?
}
?>

Share this post


Link to post
Share on other sites
This link will help you to do everythink what involves the ipn ok.

http://www.zend.com/zend/tut/tutorial-paypal.php

Also a pre made one everythink made for you try this link ok

http://www.19.5degs.com/element/369.php

this is the ipn paypal database example and the class below ok.

[code]
CREATE TABLE paypal_table (
  id int(11) NOT NULL auto_increment,
  payer_id varchar(60) default NULL,
  payment_date varchar(50) default NULL,
  txn_id varchar(50) default NULL,
  first_name varchar(50) default NULL,
  last_name varchar(50) default NULL,
  payer_email varchar(75) default NULL,
  payer_status varchar(50) default NULL,
  payment_type varchar(50) default NULL,
  memo tinytext,
  item_name varchar(127) default NULL,
  item_number varchar(127) default NULL,
  quantity int(11) NOT NULL default '0',
  mc_gross decimal(9,2) default NULL,
  mc_currency char(3) default NULL,
  address_name varchar(255) NOT NULL default '',
  address_street varchar(255) NOT NULL default '',
  address_city varchar(255) NOT NULL default '',
  address_state varchar(255) NOT NULL default '',
  address_zip varchar(255) NOT NULL default '',
  address_country varchar(255) NOT NULL default '',
  address_status varchar(255) NOT NULL default '',
  payer_business_name varchar(255) NOT NULL default '',
  payment_status varchar(255) NOT NULL default '',
  pending_reason varchar(255) NOT NULL default '',
  reason_code varchar(255) NOT NULL default '',
  txn_type varchar(255) NOT NULL default '',
  PRIMARY KEY  (id),
  UNIQUE KEY txn_id (txn_id),
  KEY txn_id_2 (txn_id)
) TYPE=MyISAM;

[/code]

ipn_res.php
[code]
<?

// made by robin kohli (robin@19.5degs.com) for 19.5 Degrees (http://www.19.5degs.com)

// ----- edit these settings

// database settings
$host="localhost";
$ln="";
$pw="";
$db="";

// paypal email
$paypal_email = "your.paypal@email.address";

// email address where script should send notifications
$error_email = "your@email.address";

// email header
$em_headers  = "From: from_name <from_email>\n";
$em_headers .= "Reply-To: from_email\n";
$em_headers .= "Return-Path: from_email\n";
$em_headers .= "Organization: company_name\n";
$em_headers .= "X-Priority: 3\n";


// -----------------


require("ipn_cls.php");

$paypal_info = $HTTP_POST_VARS;
$paypal_ipn = new paypal_ipn($paypal_info);

foreach ($paypal_ipn->paypal_post_vars as $key=>$value) {
if (getType($key)=="string") {
eval("\$$key=\$value;");
}
}

$paypal_ipn->send_response();
$paypal_ipn->error_email = $error_email;

if (!$paypal_ipn->is_verified()) {
$paypal_ipn->error_out("Bad order (PayPal says it's invalid)" . $paypal_ipn->paypal_response , $em_headers);
die();
}


switch( $paypal_ipn->get_payment_status() )
{
case 'Pending':

$pending_reason=$paypal_ipn->paypal_post_vars['pending_reason'];

if ($pending_reason!="intl") {
$paypal_ipn->error_out("Pending Payment - $pending_reason", $em_headers);
break;
}


case 'Completed':

$qry= "SELECT i.mc_gross, i.mc_currency FROM item_table as i WHERE i.item_number='$item_number'";
mysql_connect("$host","$ln","$pw") or die("Unable to connect to database");
mysql_select_db("$db") or die("Unable to select database");
$res=mysql_query ($qry);
$config=mysql_fetch_array($res);

if ($paypal_ipn->paypal_post_vars['txn_type']=="reversal") {
$reason_code=$paypal_ipn->paypal_post_vars['reason_code'];
$paypal_ipn->error_out("PayPal reversed an earlier transaction.", $em_headers);
// you should mark the payment as disputed now
} else {

if (
(strtolower(trim($paypal_ipn->paypal_post_vars['business'])) == $paypal_email) && (trim($mc_currency)==$config['mc_currency']) && (trim($mc_gross)-$tax == $quantity*$config['mc_gross'])
) {

$qry="INSERT INTO paypal_table VALUES (0 , '$payer_id', '$payment_date', '$txn_id', '$first_name', '$last_name', '$payer_email', '$payer_status', '$payment_type', '$memo', '$item_name', '$item_number', $quantity, $mc_gross, '$mc_currency', '$address_name', '".nl2br($address_street)."', '$address_city', '$address_state', '$address_zip', '$address_country', '$address_status', '$payer_business_name', '$payment_status', '$pending_reason', '$reason_code', '$txn_type')";


if (mysql_query($qry)) {

$paypal_ipn->error_out("This was a successful transaction", $em_headers);
// you should add your code for sending out the download link to your customer at $payer_email here.

} else {
$paypal_ipn->error_out("This was a duplicate transaction", $em_headers);
}
} else {
$paypal_ipn->error_out("Someone attempted a sale using a manipulated URL", $em_headers);
}
}
break;

case 'Failed':
// this will only happen in case of echeck.
$paypal_ipn->error_out("Failed Payment", $em_headers);
break;

case 'Denied':
// denied payment by us
$paypal_ipn->error_out("Denied Payment", $em_headers);
break;

case 'Refunded':
// payment refunded by us
$paypal_ipn->error_out("Refunded Payment", $em_headers);
break;

case 'Canceled':
// reversal cancelled
// mark the payment as dispute cancelled
$paypal_ipn->error_out("Cancelled reversal", $em_headers);
break;

default:
// order is not good
$paypal_ipn->error_out("Unknown Payment Status - " . $paypal_ipn->get_payment_status(), $em_headers);
break;

}

?>
[/code]

ipn_cls.php
[code]

<?php

class paypal_ipn
{
var $paypal_post_vars;
var $paypal_response;
var $timeout;

var $error_email;

function paypal_ipn($paypal_post_vars) {
$this->paypal_post_vars = $paypal_post_vars;
$this->timeout = 120;
}

function send_response()
{
$fp = @fsockopen( "www.paypal.com", 80, &$errno, &$errstr, 120 );

if (!$fp) {
$this->error_out("PHP fsockopen() error: " . $errstr , "");
} else {
foreach($this->paypal_post_vars AS $key => $value) {
if (@get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
$values[] = "$key" . "=" . urlencode($value);
}

$response = @implode("&", $values);
$response .= "&cmd=_notify-validate";

fputs( $fp, "POST /cgi-bin/webscr HTTP/1.0\r\n" );
fputs( $fp, "Content-type: application/x-www-form-urlencoded\r\n" );
fputs( $fp, "Content-length: " . strlen($response) . "\r\n\n" );
fputs( $fp, "$response\n\r" );
fputs( $fp, "\r\n" );

$this->send_time = time();
$this->paypal_response = "";

// get response from paypal
while (!feof($fp)) {
$this->paypal_response .= fgets( $fp, 1024 );

if ($this->send_time < time() - $this->timeout) {
$this->error_out("Timed out waiting for a response from PayPal. ($this->timeout seconds)" , "");
}
}

fclose( $fp );

}

}

function is_verified() {
if( ereg("VERIFIED", $this->paypal_response) )
return true;
else
return false;
}

function get_payment_status() {
return $this->paypal_post_vars['payment_status'];
}

function error_out($message, $em_headers)
{

$date = date("D M j G:i:s T Y", time());
$message .= "\n\nThe following data was received from PayPal:\n\n";

@reset($this->paypal_post_vars);
while( @list($key,$value) = @each($this->paypal_post_vars)) {
$message .= $key . ':' . " \t$value\n";
}
mail($this->error_email, "[$date] paypay_ipn notification", $message, $em_headers);

}
}

?>
[/code]

Share this post


Link to post
Share on other sites
Hey, Thanks guys. I knew that paypal had the IPN system, but I never really worked with it before. I saw that zend tutorial, but I was looking for something a little simpler. I signed up as a paypal developer so that I can have sandbox accounts. I guess I just have to jump in right?

Do you guys have any advise in what works and what doesn't?

Thanks again,
-Chris

Share this post


Link to post
Share on other sites
I hope today when you have got it all going, you post a tutoral for everyone cheers mate.

Share this post


Link to post
Share on other sites
Ok, here is what I got...

donations table:
CREATE TABLE `donations` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`UID` BIGINT NOT NULL ,
`item_name` MEDIUMTEXT NOT NULL ,
`item_number` MEDIUMTEXT NOT NULL ,
`payment_status` TEXT NOT NULL ,
`payment_amount` TEXT NOT NULL ,
`payment_currency` TEXT NOT NULL ,
`txn_id` LONGTEXT NOT NULL ,
`receiver_email` MEDIUMTEXT NOT NULL ,
`payer_email` MEDIUMTEXT NOT NULL ,
INDEX ( `id` )
) ENGINE = MYISAM ;

I have a donations part in the users table also.

donation.php

[code=php:0]<?php

echo "<form action=\"https://www.sandbox.paypal.com/cgi-bin/webscr\" method=\"post\">
<input type=\"hidden\" name=\"cmd\" value=\"_xclick\">
<input type=\"hidden\" name=\"business\" value=\"Business Name\">
<input type=\"hidden\" name=\"item_name\" value=\"item name\">
<input type=\"hidden\" name=\"item_number\" value=\"1\">
<input type=\"hidden\" name=\"currency_code\" value=\"USD\">
<input type=\"hidden\" name=\"receiver_email\" value=\"email\">
<input type=\"hidden\" name=\"mrb\" value=\"R-3WH47588B4505740X\">
<input type=\"hidden\" name=\"pal\" value=\"ANNSXSLJLYR2A\">
<input type=\"hidden\" name=\"no_shipping\" value=\"1\">
<input type=\"hidden\" name=\"no_note\" value=\"1\">
<input type=\"hidden\" name=\"notify_url\" value=\"http//www.URL to script/ipn.php?UID=$userid\">
<input type=\"hidden\" name=\"cancel_return\" value=\"http//www.URL to users script/users.php\">
<input type=\"image\" name=\"submit\" src=\"http://images.paypal.com/images/x-click-butcc-donate.gif\" border=\"0\" alt=\"Make payments with PayPal, it's fast, free, and secure!\">
</form>";

?>[/code]

ipn.php

[code=php:0]<?php
include "connect.php";
function ipn_verify($seller_email = '', $item_price = '', $currency = ''){
  if(!$_POST){
    return array('result' => 0);
  }

  //seed random generator
  mt_srand((double)microtime() * 1000000);
  $charset = "abcdefghijklmnopqrstuvwxyz12_-34567890ABCDE_FGHIJKLMNOPQRSTWXYZ";

  // 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.0\r\n";
  $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
  $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
  $fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30);

  // assign posted variables to local variables
  $item_name = $_POST['item_name'];
  $item_number = $_POST['item_number'];
  $payment_status = $_POST['payment_status'];
  $payment_amount = $_POST['mc_gross'];
  $payment_amount = sprintf("%.2f", $payment_amount);
  $payment_currency = $_POST['mc_currency'];
  $txn_id = $_POST['txn_id'];
  $receiver_email = $_POST['receiver_email'];
  $payer_email = $_POST['payer_email'];

  $trans_details = array('item_name' => $item_name, 'item_number' => $item_number, 'payment_status' => $payment_status, 'payment_amount' => $payment_amount, 'payment_currency' => $payment_currency, 'txn_id' => $txn_id, 'receiver_email' => $receiver_email, 'payer_email' => $payer_email);

  if(!$fp){
    // HTTP ERROR
  }else{
    fputs($fp, $header . $req);
    while(!feof($fp)){
      $res = fgets($fp, 1024);
      fclose ($fp);
      if((strcmp($res, 'VERIFIED') == 0)){
        $failed = 0;
        if(($seller_email) && ($seller_email != $receiver_email)){
          $failed = 1;
        }
        if(($item_price) && (sprintf("%.2f", $item_price) < sprintf("%.2f", $payment_amount))){
          $failed = 1;
        }
        if(($currency) && ($currency != $payment_currency)){
          $failed = 1;
        }
        if(!$failed){
          $trans_details['result'] = 1;
          return $trans_details;
        }else{
          $trans_details['result'] = 0;
          return $trans_details;
        }
      }elseif(strcmp ($res, 'INVALID') == 0){
        $trans_details['result'] = 0;
        return $trans_details;
      }
    }
  }
}

$trans_details = ipn_verify('email'); //same e-mail address as above

if($trans_details['result']){
  @mysql_query("insert into donations (UID, item_name, item_number, payment_status, payment_amount, payment_currency, txn_id, receiver_email, payer_email) values ('". $_GET['UID'] ."', '". $trans_details['item_name'] ."', '". $trans_details['item_number'] ."', '". $trans_details['payment_status'] ."', '". $trans_details['payment_amount'] ."', '". $trans_details['payment_currency'] ."', '". $trans_details['txn_id'] ."', '". $trans_details['receiver_email'] ."', '". $trans_details['payer_email'] ."')");
  $getter = @mysql_fetch_object(mysql_query("SELECT * FROM users WHERE userid='". $_GET['UID'] ."' limit 1"));
  $donations = sprintf("%.2f", ($trans_details['payment_amount'] + $getter->donations));
  @mysql_query("update users set donations='". $donations ."' where userid='". $_GET['UID'] ."' limit 1");
  echo '<center>Thank you for your donation.</center>';
}else{
  echo '<center>We\'re sorry but your donation has failed.</center>';
}
include "disconnect.php";
?>[/code]

In my sandbox account I went to Profile>Instant Payment Notification> I enabled it and used http//www.URL to script/ipn.php as the URL and saved it. The payments are going in and out of the right accounts as they should, but it's not updating the database. Am I missing something?

Thanks,
-Chris

Share this post


Link to post
Share on other sites
When you post to paypal does paypal send it back to the update page.

Share this post


Link to post
Share on other sites
I don't believe so. Since it's not updating the database, I'm assuming that it's not coming back.

Share this post


Link to post
Share on other sites

i am sure that this line paypal sends back sure f it .

[code]
<input type=\"hidden\" name=\"notify_url\" value=\"http//www.URL to script/ipn.php?UID=$userid\">

[/code]

Share this post


Link to post
Share on other sites
read what it says in yellow


[code]

<?php
### LISTING OF ipn.php
define ("DBHOST", "localhost");
define ("DBNAME", "paypal_tutorial");
define ("DBUSER", "root");
define ("DBPASS", "");

### CONNECT TO THE DATABASE
function DatabaseConnect() {
   if (!($mylink = mysql_connect(DBHOST, DBUSER, DBPASS))) {
       echo mysql_error();
       exit;
   } //fi
   mysql_select_db(DBNAME) or die(mysql_error());
} // end function

DatabaseConnect(); // this will automatically connect us

// below supported vals that paypal posts to us, this list is exhaustive.. but
// without notify_version and verify_sign NOTE: if in is not in this array, it
// is not going in the database.

$paypal_vals = array("item_name", "receiver_email", "item_number",
   "invoice", "quantity", "custom", "payment_status",
   "pending_reason", "payment_date", "payment_gross", "payment_fee",
   "txn_id", "txn_type", "first_name", "last_name", "address_street",
   "address_city", "address_state", "address_zip", "address_country",
   "address_status", "payer_email", "payer_status", "payment_type",
   "subscr_date", "period1", "period2", "period3", "amount1",
   "amount2", "amount3", "recurring", "reattempt", "retry_at",
   "recur_times", "username", "password", "subscr_id", "option_name1",
   "option_selection1", "option_name2", "option_selection2",
   "num_cart_items"
);

// build insert statement
while (list ($key, $value) = each ($HTTP_POST_VARS)) {
   if (in_array ($key, $paypal_vals)) {
       if (is_numeric($value)) {
           $addtosql .= " $key=$value,";
       } else {
           $newval = urlencode($value);
           $topost .= "&$key=$newval"; //used later in reposting
           $value = addslashes($value);
           $addtosql .= " $key='$value',";
       } //fi
   } //fi
   $entirepost .= "[$key]='$value',";
} //wend

$entirepost = addslashes($entirepost); // just in case..

$addtosql = substr("$addtosql", 0, -1).";"; //chop trailing "," replace with ";"

$sql1 = "
   INSERT INTO accounting_paypal
   SET date=now(), entirepost='$entirepost',". $addtosql;
mysql_db_query(DBNAME, $sql1) or die($sql1);

// We could use this in a log, or to track which users have which payment.
$paypal_id = mysql_insert_id();

if ($HTTP_POST_VARS['payment_status'] == "Completed"
   || $HTTP_POST_VARS['payment_status'] == "Pending")
{
   $username = $HTTP_POST_VARS['payer_email'];
   $sql = "
       UPDATE user
       SET paid = 'Y'
       WHERE username = '$username'
   ";
   $result = mysql_db_query(DBNAME, $sql) or die($sql);
} //fi    
### END LISTING OF ipn.php
?>
[/code]

Share this post


Link to post
Share on other sites
not sure how i can see it being illegal.

chris:  paypal's documentation on the IPN system is very handy, provided you know where to look.  the appendix on what you can/can't send to paypal, and consequently what it sends back after rebuilding the POST request to them, is EXTREMELY useful.  you can essentially send the pertinent info (username, id, whatever) in with the payment info, and it's sent back to you.

i began with paypal's example code for PHP in their documentation/technical breakdown of IPN, and extended from there.  they give you the base with which to accept paypal's info, send back to them, and receive the results.  you should be able to use this returned info to then figure out which user donated, how much, whether it was successful, and consequently whether or not to activate them.  it's mostly a matter of getting the server communication working (ie. sending the info back to them upon notification, and receiving the results of the payment after this).

i just realized i hashed out a repeat of obsidian.  however, i have one addendum:  ALWAYS make a manual activation function, so that any Paypal issues can be resolved manually if necessary.  it's inevitable that you get someone making a mistake, or your client being dumb, and a payment goes awry and requires some manual fixing.

sorry if this is actually no help to you - i just wanted to mention that starting from paypal's example PHP code is a good idea.  the rest of it is database work, tantamount to writing any other script.

Share this post


Link to post
Share on other sites
[quote author=newb link=topic=100880.msg400232#msg400232 date=1153370922]
this is illegal
[/quote]

This code is not illegal and it already exists. They have more than one version and it's updated. Even if it won't fit an odd Php version out there, you can review the code  and ask questions of the mod writer till you drop.
He rocks and supplys the mods and support free of charge and with a great atttitude slanted to helping new guys and gals understand this code.

You can't go wrong...............Good luck

[url=http://bbs.loewen.com.sg/][color=red]Paypal Mod Site[/color][/url]

[code]Code:
##############################################################
## MOD Title: Loewen Enterprise Donation MOD
## MOD Author: sandodo <zouxiong> (Xiong Zou) http://bbs.loewen.com.sg & http://forum.loewen.com.sg
## MOD Description: Admin can set PayPal accounts to receive donations,
##          Donors can choose to be anonymous when donation,
##          Admin can set how many points to give to donor when donation, (Must have points MOD installed, otherwise, set it to 0 )
##          Admin can also set how many posts count to give to donor when donation,
##          Admin can set current donation goal, description and duration,
##          Admin can set to display top donors or last donors,
##          Admin can manually inset donation information
##          Admin can set which group the donor can join after donation, currently support different two groups
##          Admin can set which special rank the donor will be set to after donation, anonymous donor will not be set for this special rank
##
##   Note: Your PayPal account must be Premier/Business Account to be able to receive Credit Card Payment,
##   If you donot have one, please follow this link to register: https://www.paypal.com/row/mrb/pal=RARP2763AYFN4 ,
##   it is free and it makes us your referal, so you are helping us by doing it. Thanks.
##   For any support issues or check any newest version or patches, please come to my support forum:
##   For English: http://bbs.loewen.com.sg
##   For Chinese: http://forum.loewen.com.sg
##
## MOD Version: 1.0.2
## MOD Requirements: PHPBB Version 2.0.6 - 2.0.10; (But not quite related, other version should support too)
##
## Installation Level: Intermediate
## Installation Time: ~ 20 minutes.[/colde]
[/code]

Share this post


Link to post
Share on other sites

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.