SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 28
  1. #1
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Paypal subscription IPN confirmation and php

    I need to do a little check when Paypal has received money.

    I just need to match the 'buyer_email' with my own 'email' field in my mysql table and then mark the field 'paid' as 'yes'.

    I'm guessing this is really basic stuff, but how would i do this?

    I have seen the code available from Paypal here

    TIA

  2. #2
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    ipn.php
    PHP Code:
    include("db-connect.php");
    $sql "UPDATE table SET paid = 'yes' WHERE email = '" $_POST['buyer_email'] . "'";
    $sql_result mysql_query($sql); 
    Minimal, but that's really as easy as it is. You don't have to do the postback verification to process IPN input, but should, and you've already got the code for it (the URL you linked).

  3. #3
    SitePoint Wizard Sillysoft's Avatar
    Join Date
    May 2002
    Location
    United States :)
    Posts
    1,691
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Dan,

    Do you know if the IPN process works in Paypal Dev environment. I used a paypal class to pass along a url for IPN to go back to, but it never happens. But I tried only on the sandbox dev environment. Do you have to turn something on in your paypal account ot get IPN to work?

    Silly

  4. #4
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dan Grossman
    ipn.php
    PHP Code:
    include("db-connect.php");
    $sql "UPDATE table SET paid = 'yes' WHERE email = '" $_POST['buyer_email'] . "'";
    $sql_result mysql_query($sql); 
    Minimal, but that's really as easy as it is. You don't have to do the postback verification to process IPN input, but should, and you've already got the code for it (the URL you linked).
    Dan,

    Thanks for that! So i can create a page (eg) testback.php, put that code in, set the IPN on and to return to testback.php and it 'should' update my field (so long as the user puts in the same email as Paypal uses)?

    It won't let me test paying myself...so i'll have to get a friend on the case

  5. #5
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    You can specify the URL of your IPN script through your PayPal settings, or as part of each individual payment button (return_url is the parameter, I think).

    For testing I have two accounts, one business and one personal. You're allowed to have either one business and one personal, or one premier and one personal account.

  6. #6
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok excellent, i'll look into setting the URL per button.

    The other bit of code i wanted to develop was a method of keeping that 'paid' field uptodate.

    (eg) when a subscription is to be renewed, i would like some way of checking that it has in fact been renewed and not cancelled and either setting the 'paid' field to 'no' if cancelled or 'yes' if payment has been successfull. I have a field in my table that is the theoretical end date of the subscription should it be cancelled. This is calculated from the transaction date (or rather just today's date) and then added 1, 3, 6 or 12 months depending on what the user selected prior to purchasing. (so i guess what i'm saying is that a php check could be done to see if todays date = that end date and then...check to see if paypal has been payed??)

    What would be the best method for that? Does paypal send out another IPN every time the subscription recurs?

  7. #7
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by skyline
    What would be the best method for that? Does paypal send out another IPN every time the subscription recurs?
    Yep, PayPal makes this pretty easy on developers. Unfortunately I don't have access to my PC with the code on it, so I'll go from memory... when someone starts a new subscription, you'll get a post where "txn_type" is "subscr_signup" and all the subscription info. At the same time you'll get a second post with "subscr_payment" for the first subscription payment. On subsequent automatic payments you should only get the "subscr_payment" posts. There's another for cancellation.

    The way I handle subscriptions is to keep a "paid through date" in the database, which is 33 days after each subscr_payment comes in... I build in a little grace period for renewal reminders. My IPN script takes no action (except logging) on the signup or cancellation posts, it simply updates that paid through date on payments. If someone cancels, their date will naturally stop moving forward, and they'll stop being considered a paying user once the current date passes their paid through date.

  8. #8
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    wow...sounds like your script has all the bells and whistles! I like the idea of sending out renewal reminders just before the end date. Out of interest..why 33 days? I suppose the cancellation post could set a variable that meant that the paid field would switch to 'no' when the end date was reached...

    I'd be really interested to see some more of your code..if you could PM me or something when you are your PC next?

  9. #9
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by skyline
    Out of interest..why 33 days?
    No particular reason. I let them keep their paid status for a few days after it should've expired while I try to entice them to start paying again.

    Quote Originally Posted by skyline
    I suppose the cancellation post could set a variable that meant that the paid field would switch to 'no' when the end date was reached...
    Why have a paid field at all? You know they're not paid if the current date is greater than the 'paid through' date.

    Quote Originally Posted by skyline
    I'd be really interested to see some more of your code..if you could PM me or something when you are your PC next?
    I wouldn't mind sharing in the thread if there's something specific you want to know how to accomplish.

  10. #10
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, yes it does make sense now So if i were to have my own paid_through field and i have a testback.php page that IPN returns posts to. What code would i need to implement for what you achieve?

    The only difference is that i would want it set to 1,3,6 or 12 months rather than 33 days, depending on the type of subscription taken out. Or perhaps 1 day after each of those periods as a grace, but i'm not sure how that would work.

    Plus the reason for a 'paid' field was to act as a switch if you like to terminate/enable a further process. So i would need a field to be updated once that subscriber has been deemed not subscribing anymore...

    Does that make sense?!

  11. #11
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by skyline
    Ok, yes it does make sense now So if i were to have my own paid_through field and i have a testback.php page that IPN returns posts to. What code would i need to implement for what you achieve?
    It'd look something like this, if you used the price to deduce which subscription they chose. I don't really want to read the IPN manual again to answer this question, so there's probably a variable in the response with the subscription period you could use instead:

    testback.php
    PHP Code:
    include("db-connect.php");

    //do postback verification to make sure the post is authentic

    $periods = array(
      
    5.00 => "+31 days",
      
    13.99 => "+93 days",
      
    24.99 => "+183 days",
      
    47.99 => "+366 days");

    if (
    $_POST['txn_type'] == "subscr_payment") {
            
    $period $periods[$_POST['txn_gross']];
            
    $paidDate date("Y-m-d"strtotime($period));
            
    $sql "UPDATE users SET paidDate = '" $paidDate "' WHERE email = '" $_POST['buyer_email'] . "'";
            
    $sql_result mysql_query($sql);

    Quote Originally Posted by skyline
    Plus the reason for a 'paid' field was to act as a switch if you like to terminate/enable a further process. So i would need a field to be updated once that subscriber has been deemed not subscribing anymore...
    It's not necessary to store data that can be derived from other data you're storing unless there are performance concerns, which won't be the case here. You can either select only users whose paid date is greater than the current date when logging in or whatever your app does, or you can set a boolean variable based on the date comparison after the select, or you can even create a boolean field as part of the result set within the query with a little conditional coding in the SQL. Whatever way you go, you don't need a separate "paid" field since you can derive it from the "paid date".

  12. #12
    SitePoint Wizard Sillysoft's Avatar
    Join Date
    May 2002
    Location
    United States :)
    Posts
    1,691
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    IPN simply goes to the page you specify with all the post data you initially sent over. What I have done in the past is create the account in the db and mark them as inactive. I pass the unique ID that was created in the db within a custom field paypal allows. Then when IPN comes back I just grab that custom field and update it in the db to active since IPN happens when its successful.

    Silly

  13. #13
    SitePoint Wizard Sillysoft's Avatar
    Join Date
    May 2002
    Location
    United States :)
    Posts
    1,691
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dan Grossman
    You can specify the URL of your IPN script through your PayPal settings, or as part of each individual payment button (return_url is the parameter, I think).

    For testing I have two accounts, one business and one personal. You're allowed to have either one business and one personal, or one premier and one personal account.
    I do that, but in development I never get a response back. Perhaps its because its a test credit card?

    Silly

  14. #14
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks again Dan!

    Just looked through the IPN manual and it looks to me like 'period3' is the "variable for regular subscription in days, weeks, months or years". So if the periods i had set were to 1,3,6 and 12 months...would that be a case of saying:

    PHP Code:
    include("db-connect.php");

    $periods = array(
      
    => "+31 days",
      
    => "+93 days",
      
    => "+183 days",
      
    12 => "+366 days");

    if (
    $_POST['txn_type'] == "subscr_payment") {
            
    $period $periods[$_POST['period3']];
            
    $paidDate date("Y-m-d"strtotime($period));
            
    $sql "UPDATE users SET paidDate = '" $paidDate "' WHERE email = " $_POST['buyer_email'];
            
    $sql_result mysql_query($sql); 

    Also i just discovered this IPN testing website Surely i should be able to use this somehow to test my script?

  15. #15
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Looking at the IPN test website, "period3" may contain more than just a number. I'd try out the site.

    While you're developing, it might be useful to see all the variables posted to the script and their values. You can log them to a file or e-mail them to yourself. Something like this:

    PHP Code:
    mail("you@example.com""IPN Post""Post vars: " print_r($_POST1), "From: you@example.com"); 

  16. #16
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes, you're quite right, it seems to be: number space letter (ie 1 m, 3 m, 6 m, 12 m) ....mmm, but i CANT do this:

    PHP Code:
    include("db-connect.php");

    $periods = array(
      
    1 m => "+31 days",
      
    3 m => "+93 days",
      
    6 m => "+183 days",
      
    12 m => "+366 days");

    if (
    $_POST['txn_type'] == "subscr_payment") {
            
    $period $periods[$_POST['period3']];
            
    $paidDate date("Y-m-d"strtotime($period));
            
    $sql "UPDATE users SET paidDate = '" $paidDate "' WHERE email = " $_POST['buyer_email'];
            
    $sql_result mysql_query($sql); 

    How can i use '1 m' instead of '1' in that array?

  17. #17
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
    $periods = array(
      
    "1 m" => "+31 days",
      
    "3 m" => "+93 days",
      
    "6 m" => "+183 days",
      
    "12 m" => "+366 days"); 
    If you want to add exact months to the "paid date", you can also do this:

    PHP Code:
    $periods = array(
      
    "1 m" => "+1 month",
      
    "3 m" => "+3 months",
      
    "6 m" => "+6 months",
      
    "12 m" => "+12 months"); 
    strtotime() should take just about anything you give it and figure out the proper date

  18. #18
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    mmm...can't seem to get it to update the db. I'm using the testsite set so that payer_email = to one row's email in the table, the period3 = 1 m and txn_type = subscr_payment. Thats pretty much it as my script doesnt need any other info really. It sends the info to the script, but it doesn't update the table....

  19. #19
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Probably a bad query. Triple check it.

  20. #20
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    No finding the fault here. I have just tried doing it partly in a way i understand using if elseif statements...just to try and decontruct your code...

    PHP Code:
    <?php

    include("db_connect.php");

    $_POST['period3'] = $duration;

    if (
    $duration "1 m") {
      
    $duration2 "+1 month";
    }
    elseif (
    $duration "3 m") {
      
    $duration2 "+3 months";
    }
    elseif (
    $duration "6 m") {
      
    $duration2 "+6 months";
    }
    else {
      
    $duration2 "+12 months";
    }

    if (
    $_POST['txn_type'] == "subscr_payment") {
            
    $paidDate date("Y-m-d"strtotime($duration2));
            
    $sql "UPDATE advertisers SET paidDate = '" $paidDate "' WHERE email = " $_POST['payer_email'];
            
    $sql_result mysql_query($sql); 
    }
     
    mail("***myemail***""IPN Post""Post vars: " print_r($_POST1), "From: ***myemail***"); 

    ?>
    Stumped :/ It just doesn't touch the db. I know the db_connect works.
    One thing though..

    "Please ensure that your HTTP Status returns a valid 200 response because if not PayPal will continue to resend the notification intermittently for up to 1.5 days!"

    So once i have this actually updating my db, then i will have to make sure the script responds to paypal (or the testsite)

  21. #21
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Your script will return HTTP 200 unless you tell it otherwise. That's the default.

    $_POST['period3'] = $duration;
    This is backwards. You want to give $duration the value of $_POST['period3'].

    if ($duration = "1 m") {
    $duration2 = "+1 month";
    }
    elseif ($duration = "3 m") {
    $duration2 = "+3 months";
    }
    elseif ($duration = "6 m") {
    $duration2 = "+6 months";
    }
    else {
    $duration2 = "+12 months";
    }
    All of these conditions need to use comparison (==) not assignment (=). They'll all always return true as is.

    $sql = "UPDATE advertisers SET paidDate = '" . $paidDate . "' WHERE email = " . $_POST['payer_email'];
    This will fail because email is not a numeric field, so its value needs to be enclosed in single quotes.

  22. #22
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    sorry, where would the single quotes actually go...i'm a little confused (my severe lack of php knowledge showing )

    PHP Code:
    $sql "UPDATE advertisers SET paidDate = '" $paidDate "' WHERE email = " $_POST['payer_email']; 
    would it be like this:

    PHP Code:
    $sql "UPDATE advertisers SET paidDate = '" $paidDate "' WHERE email = '" $_POST['payer_email']'; 

  23. #23
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
     $sql "UPDATE advertisers SET paidDate = '" $paidDate "' WHERE email = '" $_POST['payer_email'] . "'"

  24. #24
    SitePoint Evangelist
    Join Date
    Jan 2005
    Location
    UK
    Posts
    539
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wahoo it works! Cool So, with this code on the receiving end of all PP IPN's, everytime a subscription is paid for, that user's row (according to his matching email with main Paypal email address) will update the paidDate field...correct?

    Now the only problem i can foresee is if a customer takes out 2 different subscriptions and of course uses his 1 only paypal email address. This would mean 2 rows getting updated accidentally. In my case this is a possiblilty due to the nature of what's being subscribed to. AH, just thought, could use the 'memo' field...do you know is it possible to send paypal that field in the subscribe button? The user could stipulate a word associated with that particular subscription, and then that could be used to check along with the payer_email before updating the paidDate.

    As for executing an action if the paidDate goes past today's date...what i require is for a select statement to disregard any rows where the paidDate < today's date. How would i code this?

    Thanks for all your help Dan You've been a great help.

  25. #25
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by skyline
    AH, just thought, could use the 'memo' field...do you know is it possible to send paypal that field in the subscribe button?
    Not sure, I'm sure there are some custom fields you can send. I just have the user ID in the item_name "W3Counter Premium Account (46)" and parse the string to get which user to update. But a hidden field (perhaps item_number?) would probably be better if possible.

    Quote Originally Posted by skyline
    As for executing an action if the paidDate goes past today's date...what i require is for a select statement to disregard any rows where the paidDate < today's date. How would i code this?
    Code:
    SELECT * FROM advertisers WHERE paidDate >= CURDATE()


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •