Troubles With PayPal IPN Script

Hi all,

I’ve a site that sells virtual currency through PayPal. Testing through PayPal’s IPN sandbox works fine for this script. But when the script goes live (non-sandbox), it’s not updating people’s virtual currency balance for transactions that are “Completed” at PayPal. This is CodeIgniter, btw.

Error logging with the live script has been tough, but here’s what I do know:

[list][]I know that PayPal is physically hitting the IPN script (it’s being called)
[
]Within the while() loop, $res always evaluates to blank when I flag the variable for error logging (i.e. var_dump($res) == “”)
[*]MySQL table cashshop_invalid_transactions is where invalid transactions (from the IPN) go and this table isn’t being populated with anything, which means that INVALID isn’t the response being returned by PayPal[/list]
Any reasons why users might not be getting their virtual currency? Did I miss something about the API? I don’t get why this script stopped working. I know PayPal changed to HTTP 1.1 protocol and this is correct.

function notify()
{	
	// --------------------------------------
	// Read post from PayPal system, add cmd
	// --------------------------------------
	
	$req = 'cmd=_notify-validate';
	
	// --------------------------------------
	// Get the POST request to us, to make ours back
	// --------------------------------------
	
	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\
";
	$header .= "Content-Type: application/x-www-form-urlencoded\\r\
";
	$header .= "Host: www.paypal.com\\r\
";
	$header .= "Connection: close\\r\
";
	$header .= "Content-Length: " . strlen($req) . "\\r\
\\r\
";
	
	// --------------------------------------
	// Open handler
	// --------------------------------------
	
	$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
	
	// --------------------------------------
	// Error connecting to paypal
	// --------------------------------------
	
	if (!$fp)
	{
	    // Something died
	}
	
	// --------------------------------------
	// Incoming post variables
	// --------------------------------------
	
	// We put user ID in this PayPal field user id
	$user_id = $this->input->post('item_number');
	
	// Paypal txn information
	$payer_id = $this->input->post('payer_id');
	$payment_date = $this->input->post('payment_date');
	$txn_id = $this->input->post('txn_id');
	$first_name = $this->input->post('first_name');
	$last_name = $this->input->post('last_name');
	$payer_email = $this->input->post('payer_email');
	$payer_status = $this->input->post('payer_status');
	$payment_type = $this->input->post('payment_type');
	$memo = $this->input->post('memo');
	$item_name = $this->input->post('item_name');
	$quantity = $this->input->post('quantity');
	$mc_gross = $this->input->post('mc_gross');
	$mc_currency = $this->input->post('mc_currency');
	$address_name = $this->input->post('address_name');
	$address_street = $this->input->post('address_street');
	$address_city = $this->input->post('address_city');
	$address_state = $this->input->post('address_state');
	$address_zip = $this->input->post('address_zip');
	$address_country = $this->input->post('address_country');
	$address_status = $this->input->post('address_status');
	$payer_business_name = $this->input->post('payer_business_name');
	$payment_status = $this->input->post('payment_status');
	$pending_reason = $this->input->post('pending_reason');
	$reason_code = $this->input->post('reason_code');
	$txn_type = $this->input->post('txn_type');
	
	// Make sure that this payment came to us
	$receiver_email = $this->input->post('receiver_email');

	// --------------------------------------
	// Successful connection
	// --------------------------------------
	
	if ($fp)
	{
		// --------------------------------------
		// Puts the request
		// --------------------------------------
		
	    fputs ($fp, $header . $req);
	
		// --------------------------------------
		// Load necessary
		// --------------------------------------
		
		$this->load->library('event');
	
	    // --------------------------------------
		// Loop through what we've got
		// --------------------------------------
		
	    while (!feof($fp))
	    {
	        $res = fgets ($fp, 1024);
	        $res = trim($res); //NEW & IMPORTANT
	
	        // ------------------------------------------------------------------------------------------------------------------
	        // VERIFIED
	        // ------------------------------------------------------------------------------------------------------------------
	
	        if (strcmp($res, "VERIFIED") == 0)
	        {		
				// --------------------------------------
				// Payment status Completed?
				// --------------------------------------
				
				if ($payment_status == 'Completed' && $receiver_email == 'my@email.com')
				{
					$data = array(
								'user_id' => $user_id,
								'payer_id' => $payer_id,
								'payment_date' => $payment_date,
								'txn_id' => $txn_id,
								'first_name' => $first_name,
								'last_name' => $last_name,
								'payer_email' => $payer_email,
								'payer_status' => $payer_status,
								'payment_type' => $payment_type,
								'memo' => $memo,
								'item_name' => $item_name,
								'quantity' => $quantity,
								'mc_gross' => $mc_gross,
								'mc_currency' => $mc_currency,
								'address_name' => $address_name,
								'address_street' => $address_street,
								'address_city' => $address_city,
								'address_state' => $address_state,
								'address_zip' => $address_zip,
								'address_country' => $address_country,
								'address_status' => $address_status,
								'payer_business_name' => $payer_business_name,
								'payment_status' => $payment_status,
								'pending_reason' => $pending_reason,
								'reason_code' => $reason_code,
								'txn_type' => $txn_type
							);
					
					$this->db->insert('cashshop_txn', $data);
					
					// --------------------------------------
					// Calculate how much virtual currency purchased
					// --------------------------------------
					
					$cc = $mc_gross / 0.01;
					
					if ($cc == 4500)
					{
						$cc = 5000;
					}
					
					$this->db->query('UPDATE users SET currency = currency + '.$cc.' WHERE id = '.$this->db->escape($user_id));
					
					// --------------------------------------
					// Notify user of new currency available
					// --------------------------------------
					
					// Notification event
				}
				else if ($payment_status != 'Completed' && $receiver_email == 'my@email.com')
				{	
					// --------------------------------------
					// Not completed, manual verification
					// --------------------------------------
					
					// Flag for manual verification
				}
	        }
	
	        // ------------------------------------------------------------------------------------------------------------------
	        // INVALID
	        // ------------------------------------------------------------------------------------------------------------------
	
	        if (strcmp ($res, "INVALID") == 0)
	        { 	
				// --------------------------------------
				// Insert transaction ID
				// Flag for manual verification
				// --------------------------------------
				
				$insert_arr = array(
								'txn_id' => $txn_id,
								'user_id' => $user_id,
								'amount' => $mc_gross,
								'time' => time()
							);
				$this->db->insert('cashshop_invalid_transactions', $insert_arr);
	        }
	    }
		
		// Close
	    fclose($fp);
	
	} //end if ($fp)
} // end function notify

Hi Panduola,

Shouldn’t the live PayPal url be https://www.paypal.com? I don’t think ssl:// is a valid URL scheme.

Official PayPal documentation for PHP code indicates:

$fp = fsockopen(‘ssl://www.sandbox.paypal.com’, 443, $errno, $errstr, 30);

Oops, my bad… yeah you can use ssl:// with fsockopen. Did you change any other part of the script from when you had it working with the sandbox? Also, you mentioned that it doesn’t write anything to the cashshop_invalid_transactions table, presumably it’s not writing to ‘cashshop_txn’ either?