Link to home
Start Free TrialLog in
Avatar of Ryan Bayne
Ryan BayneFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Paypal IPN Script Returning INVALID

Hi

I've been working on Paypal IPN for a week on and off now getting no where fast really so I'm getting desperate. Right now I'm at a point where I can test my IPN script using Sandbox tool and I get INVALID response.

Or we can use Buynow button here...
http://www.ad-hit.com/scripts/paypal/examples/buynow.php

and that doesnt cause a POST to my IPN script! I'll show the code for it below.

Anyone got any ideas why after the BuyNow process, confirming the transaction on Paypal, Paypal would not POST to my IPN? Once I get that sorted I will move on to figuring out why every response is INVALID.

Thanks
This is the main variables for the buynow button...
 
/* Add variables to Form PARAMTERS MUST ADHERE TO PAYPAL STANDARDS */
$buyNow->addVar('business','paypal@webtechglobal.co.uk');	/* Payment Email */
$buyNow->addVar('cmd','_xclick');
$buyNow->addVar('amount','2.99');
$buyNow->addVar('item_name','Ad-Hit Points 500');
$buyNow->addVar('item_number','POINTS500');
$buyNow->addVar('quantity','1');
$buyNow->addVar('tax','1.99');
$buyNow->addVar('shipping','8.00');
$buyNow->addVar('currency_code','USD');
$buyNow->addVar('no_shipping','2');		/* Must provide shipping address */
$buyNow->addVar('rm','2'); /* Return method must be POST (2) for this class */
$buyNow->addVar('custom','500');/* Ad-Hit POINTS being bought */
/* Paypal IPN URL - MUST BE URL ENCODED and is the checkpayment.php file */
$buyNow->addVar('notify_url','http://www.ad-hit/scripts/paypal/examples/checkpayment.php');	
/* Set URL for Thank you Page (if any) in variable */
$buyNow->addVar('return','http://www.ad-hit.com/index.php?page=pages_member/paypal_success');
 
 
This is the top of my IPN script, checkpayment.php I have put an mail there to test its use. It only gets this far when testing through the sandbox not when using my buynow button...
 
<?php
mail('admin@webtechglobal.co.uk', "TEST checkpayment Run", "checkpayment.php was accessed during this transaction");
						
/* Get Paypal Class */
require_once('../paypal.class.php');
 
/* Paypal is name of the Class */
$doCheck = new Paypal;

Open in new window

SOLUTION
Avatar of Beverley Portlock
Beverley Portlock
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Ryan Bayne

ASKER

Its ON.

No URL entered however I didnt think you had to as I need multiple sites using the one account.

I've only got Log entries from payments made with Sandbox. So my guess is the problem lays with my BuyNow form telling paypal exactly what I want as in a POST to IPN script using notify_url.

Simply because there doesnt seem to be an attempt to do so. I've placed mail around the script so I can a few emails telling me what part of the script is running and whats not and the first line is not even being reached.

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes using the IPN tool I can get something happening. Not desired results but I would prefer to forget that right now and test by the button.

If I can get the same thing happening with the button I'll stop using the test tool plus anyone helping can use the button to see what I mean. The code should forward the user to MY page after payment and it does not so you can witness that yourself.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Alright so those are always required. And email I take it is my email, yes that makes sense!

See how I get on thanks. Get back to you soon.
Do you mean the buyers country because that information wouldnt be in the form but I've never seen a variable name for sellers country!

Any idea what that is
I cant see a cancel_return variable in the list here...

https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_html_IPNandPDTVariables

I assume its when the buyer cancels they will be returned to it so the value is to be url yes
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
OK heres what I have so far, couple still missing according to what you said but I'm reading up on each variable to ensure I understand.

Now the page viewed when clicking on buynow button on my page, displays an error...
https://developer.paypal.com/us/cgi-bin/devscr

Aint sure if its my changes or something wrong with the sandbox
/* Add variables to Form PARAMTERS MUST ADHERE TO PAYPAL STANDARDS */
$buyNow->addVar('business','paypal@webtechglobal.co.uk');	/* Account ID or Primary Email*/
$buyNow->addVar('receiver_email','paypal@webtechglobal.co.uk');	/* Primary payment email */
$buyNow->addVar('cmd','_xclick');
$buyNow->addVar('amount','2.99');
$buyNow->addVar('item_name','Ad-Hit Points 500');
$buyNow->addVar('item_number','POINTS500');
$buyNow->addVar('quantity','1');
$buyNow->addVar('tax','1.99');
$buyNow->addVar('shipping','8.00');
$buyNow->addVar('currency_code','GBP');
$buyNow->addVar('no_shipping','2');		/* Must provide shipping address */
$buyNow->addVar('rm','2'); /* Return method must be POST (2) for this class */
$buyNow->addVar('custom','500');/* Ad-Hit POINTS being bought */
$buyNow->addVar('address_country_code','GB');/* sellers address country code */
 
/* Paypal IPN URL - MUST BE URL ENCODED and is the checkpayment.php file */
$buyNow->addVar('notify_url','http://www.ad-hit/scripts/paypal/examples/checkpayment.php');	
/* Set URL for Thank you Page (if any) in variable */
$buyNow->addVar('return','http://www.ad-hit.com/index.php?page=pages_member/paypal_success');
/* Cancel return URL */
$buyNow->addVar('return','http://www.ad-hit.com/index.php?page=pages_member/paypal_cancel');

Open in new window

I'm not sure that notify_url and IPN are the same, but in any case, wouldn't we would need to see that script to explain why you're getting the 'invalid' notice?  It's coming from the IPN, right?
Ray what do you use $postdata     $postdata       .= "\n $key = $value ";  for I cant tell?

I'll compare your script to my own properly once I can get my buynow button working. This is really two problems but I'll split full points.

Thanks for your help
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes ofcourse here ya go. It is a class... my actual IPN file is checkpayment.php which starts like...

The first line is for testing. I mentioned that this mail doesnt happen at all with the buynow button but it does with paypal IPN tool in sandbox. So the buynow button goes through the transaction and the IPN is not used. Probably is a problem with the form I'm submitting but this is a downloaded class online, well tested etc so I'm not too sure.

<?php
mail('admin@webtechglobal.co.uk', "TEST checkpayment Run", "checkpayment.php was accessed during this transaction");
                                    
/* Get Paypal Class */
require_once('../paypal.class.php');

/* Paypal is name of the Class */
$doCheck = new Paypal;

/* Record any bad/unauthorized transactions for debugging and security */
$doCheck->setLogFile('logfile.txt');

/* Actually check payment - isPaid = true if payment good else false*/
$isPaid = $doCheck->checkPayment($_POST);

//Final part, process data at our end for our needs as payment is a success, issue product also
if($isPaid == true)
{

go on to process payment...
<?php 
class Paypal 
{	/* commented out by ryan
	private $VARS;
	private $button;
	private $logFile;
	$isTest=false;
	*/
	
	/* Print Form as Link */
	function getLink()
	{
		$url = $this->getPaypal();
		$link = 'https://'.$url.'/cgi-bin/webscr?';
		foreach($this->VARS as $item => $sub){
			$link .= $sub[0].'='.$sub[1].'&';
		}
		return $link;
	}
	
	/* Print Form */
	function showForm()
	{
		$url = $this->getPaypal();
		$FORM  = '<form action="https://'.$url.'/cgi-bin/webscr" method="post" target="_blank" style="display:inline;">'."\n";
		
		foreach($this->VARS as $item => $sub){
			$FORM .= '<input type="hidden" name="'.$sub[0].'" value="'.$sub[1].'">'."\n";
		}
				
		$FORM .= $this->button;    
		$FORM .= '</form>';
		echo $FORM;
	}
	
	/* Add variable to form */
	function addVar($varName,$value)
	{
		$this->VARS[${varName}][0] = $varName;
		$this->VARS[${varName}][1] = $value;
	}
	
	/* Add button Image */
	function addButton($type,$image = NULL)
	{
		switch($type)
		{
			/* Buy now */
			case 1:
				$this->button = '<input type="image" height="21" style="width:86;border:0px;"';
				$this->button .= 'src="https://www.paypal.com/en_US/i/btn/btn_paynow_SM.gif" border="0" name="submit" ';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
				break;
			/* Add to cart */	
			case 2:
				$this->button = '<input type="image" height="26" style="width:120;border:0px;"';
				$this->button .= 'src="https://www.paypal.com/en_US/i/btn/btn_cart_LG.gif" border="0" name="submit"';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
				break;
			/* Donate */	
			case 3:
				$this->button = '<input type="image" height="47" style="width:122;border:0px;"';
				$this->button .= 'src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit"';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
				break;
			/* Gift Certificate */
			case 4:	
				$this->button = '<input type="image" height="47" style="width:179;border:0px;"';
				$this->button .= 'src="https://www.paypal.com/en_US/i/btn/btn_giftCC_LG.gif" border="0" name="submit"';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
				break;
			/* Subscribe */
			case 5:	
				$this->button = '<input type="image" height="47" style="width:122;border:0px;"';
				$this->button .= 'src="https://www.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif" border="0" name="submit"';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
				break;
			/* Custom Button */
			default:
				$this->button = '<input type="image" src="'.$image.'" border="0" name="submit"';
				$this->button .= 'alt="PayPal - The safer, easier way to pay online!">';
		}
		$this->button .= "\n";
	}
	
	/* Set log file for invalid requests */
	function setLogFile($logFile)
	{
		$this->logFile = $logFile;
	}
	
	/* Helper function to actually write to logfile */
	function doLog($_POST)
	{
		ob_start();
		echo '<pre>'; print_r($_POST); echo '</pre>';
		$logInfo = ob_get_contents();
		ob_end_clean();
		
		$file = fopen($this->logFile,'a');
		fwrite($file,$logInfo);
		fclose($file);
	}
	
	/* Check payment */
	function checkPayment($_POST)
	{
	 	mail('admin@webtechglobal.co.uk', "IPN TEST", "function checkpayment line 108 in paypal.class.php - application has arrived at this point");
 
		/* read the post from PayPal system and add 'cmd' */
		$req = 'cmd=_notify-validate';
		
		/* Get post values and store them in req */
		foreach ($_POST as $key => $value) 
		{
			$value = urlencode(stripslashes($value));
			$req .= "&$key=$value";
		}
		
		$url = $this->getPaypal();
		
		/* 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 ('ssl://'.$url, 443, $errno, $errstr, 30); //try different port if having issues
		//$fp = fsockopen ('ssl://'.$url, 80, $errno, $errstr, 30);
	
		if (!$fp) 
		{
		    mail('admin@webtechglobal.co.uk', "FP FALSE", "function checkpayment line 135 in paypal.class.php - application has arrived at this point");
			return false; 
		} 
		else 
		{   	 	mail('admin@webtechglobal.co.uk', "FP TRUE", "function checkpayment line 139 in paypal.class.php - application has arrived at this point");
 
			fputs ($fp, $header . $req);
			while (!feof($fp)) 
			{
				$res = fgets ($fp, 1024);
				if (strcmp ($res, "VERIFIED") == 0) 
				{	mail('admin@webtechglobal.co.uk', "VERFIED", "function checkpayment line 146 in paypal.class.php - application has arrived at this point");	
					return true; //checkpayment.php receives true
				} 
				else //	if (strcmp ($res, "INVALID") == 0)
				{
					/*	log for manual investigation	*/
					if($this->logFile != NULL)
					{ mail('admin@webtechglobal.co.uk', "INVALID", "function checkpayment line 153 in paypal.class.php - application has tried to write to log please confirm");
						$this->doLog($_POST);
					}
					return false;
				}
			}
			fclose ($fp);
		}
		return false;
	}
	
	/* Set Test */
	function useSandBox($value)
	{
		$this->isTest=$value;
	}
	
	/* Private function to get paypal url */
	function getPaypal()
	{
		if($this->isTest == true)
		{
			return 'www.sandbox.paypal.com';
		} 
		else 
		{
			return 'www.paypal.com';
		}
	}
}
?>

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
OK I was a bit far from getting the form right, I think I been at this script too long lol

I cant test the button anymore Sandbox is not working. I'll have to wait until it is then get back to you on the result later. I'll work on getting past INVALID returns just now.

thanks so far all
/* Add variables to Form PARAMTERS MUST ADHERE TO PAYPAL STANDARDS */
$buyNow->addVar('business','paypal@webtechglobal.co.uk');	/* Account ID or Primary Email*/
$buyNow->addVar('receiver_email','paypal@webtechglobal.co.uk');	/* Primary payment email */
$buyNow->addVar('cmd','_xclick');
$buyNow->addVar('amount','2.99');
$buyNow->addVar('item_name','Ad-Hit Points 500');
$buyNow->addVar('item_number','POINTS500');
$buyNow->addVar('quantity','1');
$buyNow->addVar('tax','1.99');
$buyNow->addVar('shipping','8.00');
$buyNow->addVar('currency_code','GBP');
$buyNow->addVar('no_shipping','2');		/* Must provide shipping address */
$buyNow->addVar('rm','2'); /* Return method must be POST (2) for this class */
$buyNow->addVar('custom','500');/* Ad-Hit POINTS being bought */
$buyNow->addVar('country','GB');/* sellers address country code */
/* Paypal IPN URL - MUST BE URL ENCODED and is the checkpayment.php file */
$buyNow->addVar('notify_url','http://www.ad-hit/scripts/paypal/examples/checkpayment.php');	
/* Set URL for Thank you Page (if any) in variable */
$buyNow->addVar('return','http://www.ad-hit.com/index.php?page=pages_member/paypal_success');
/* Cancel return URL */
$buyNow->addVar('cancel_return','http://www.ad-hit.com/index.php?page=pages_member/paypal_cancel');

Open in new window

Just as I posted that I tried again and the sandbox is working. But still no change. Is the sandbox actually meant to make the IPN happen through a transaction? Do you know this for sure?

I may just go onto getting the INVALID returns fixed then do live testing, would there be any point?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ray I cant see this line in my script...
      $paypal_headers      .= $paypal_reply;
and it appears to be at a vital stage just before VERIFIED or INVALID is decided. Can you say what it does exactly?

OK bportlock I'll continue to get the button working and go with that. Didnt really like the sound of live testing early anyway!
Still no luck I think I've got a lot to learn with this so just closing the question. What I never understand with Paypal IPN scripts is that I'm downloading them from tested sources and using them with Sandbox without making changes. They are meant to return VERIFIED in that case so its a bit frustrating.

thanks for your help on this
I was setting up a PayPal account last night and the kept getting the INVALID message. It turned out that php_openssl was not installed as part of the PHP installation. Something to check maybe?
To answer this...

Ray what do you use $postdata     $postdata       .= "\n $key = $value ";  for I cant tell?

I use it in another place in my script to print or email the data that was posted.  Mostly for my own edification.  IIRC, I might throw that whole line into a data base table, but I'm not recalling that right now.

HTH ~Ray
To answer this...

Ray I cant see this line in my script...
      $paypal_headers      .= $paypal_reply;
and it appears to be at a vital stage just before VERIFIED or INVALID is decided. Can you say what it does exactly?

When you read over a socket, you get headers first, then data (like HTML) after the headers.  In the context that I use that statement, it causes the variable $paypall_headers to contain the headers and $paypal_reply to contain the data.

Best of luck with your project, ~Ray