I'm using this http://www.binpress.com/app/paypal-adaptive-payments-pro-codeigniter-library/140 library and i'm using this as my ipn listener for a codeigniter project - http://pastebin.com/pMb7Zhz3.
Basically i'm doing a parallel transaction using the paypal library above so that when a user makes a payment/donation, it sends money to 2 different accounts. Once a transaction is complete, paypal sends data to my ipn listener and it parses info for 1 customer just fine if I leave this 'IPNNotificationURL' => '' in my code and go into paypal and set the ipn url.
I'm trying to get IPN information for both accounts, without having to have both accounts set the ipn url in their paypal settings. When I set 'IPNNotificationURL' => 'http://example.com/paypal_ipn', I still get the ipn information for the 1 account, but I get this warning Array to string conversion on line 11 of my listener. How can I fix this and if i do, will I get the ipn information from both accounts?
Here's the pay method from the library above that i'm using for the parallel payments
function Pay()
{
// Prepare request arrays
$PayRequestFields = array(
'ActionType' => 'PAY', // Required. Whether the request pays the receiver or whether the request is set up to create a payment request, but not fulfill the payment until the ExecutePayment is called. Values are: PAY, CREATE, PAY_PRIMARY
'CancelURL' => '', // Required. The URL to which the sender's browser is redirected if the sender cancels the approval for the payment after logging in to paypal.com. 1024 char max.
'CurrencyCode' => 'USD', // Required. 3 character currency code.
'FeesPayer' => 'SENDER', // The payer of the fees. Values are: SENDER, PRIMARYRECEIVER, EACHRECEIVER, SECONDARYONLY
'IPNNotificationURL' => '', // The URL to which you want all IPN messages for this payment to be sent. 1024 char max.
'Memo' => '', // A note associated with the payment (text, not HTML). 1000 char max
'Pin' => '', // The sener's personal id number, which was specified when the sender signed up for the preapproval
'PreapprovalKey' => '', // The key associated with a preapproval for this payment. The preapproval is required if this is a preapproved payment.
'ReturnURL' => '', // Required. The URL to which the sener's browser is redirected after approvaing a payment on paypal.com. 1024 char max.
'ReverseAllParallelPaymentsOnError' => '', // Whether to reverse paralel payments if an error occurs with a payment. Values are: TRUE, FALSE
'SenderEmail' => '', // Sender's email address. 127 char max.
'TrackingID' => '' // Unique ID that you specify to track the payment. 127 char max.
);
$ClientDetailsFields = array(
'CustomerID' => '', // Your ID for the sender 127 char max.
'CustomerType' => '', // Your ID of the type of customer. 127 char max.
'GeoLocation' => '', // Sender's geographic location
'Model' => '', // A sub-identification of the application. 127 char max.
'PartnerName' => '' // Your organization's name or ID
);
$FundingTypes = array('ECHECK', 'BALANCE', 'CREDITCARD');
$Receivers = array();
$Receiver = array(
'Amount' => '', // Required. Amount to be paid to the receiver.
'Email' => '', // Receiver's email address. 127 char max.
'InvoiceID' => '', // The invoice number for the payment. 127 char max.
'PaymentType' => '', // Transaction type. Values are: GOODS, SERVICE, PERSONAL, CASHADVANCE, DIGITALGOODS
'PaymentSubType' => '', // The transaction subtype for the payment.
'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => ''), // Receiver's phone number. Numbers only.
'Primary' => '' // Whether this receiver is the primary receiver. Values are: TRUE, FALSE
);
array_push($Receivers,$Receiver);
$SenderIdentifierFields = array(
'UseCredentials' => '' // If TRUE, use credentials to identify the sender. Default is false.
);
$AccountIdentifierFields = array(
'Email' => '', // Sender's email address. 127 char max.
'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => '') // Sender's phone number. Numbers only.
);
$PayPalRequestData = array(
'PayRequestFields' => $PayRequestFields,
'ClientDetailsFields' => $ClientDetailsFields,
'FundingTypes' => $FundingTypes,
'Receivers' => $Receivers,
'SenderIdentifierFields' => $SenderIdentifierFields,
'AccountIdentifierFields' => $AccountIdentifierFields
);
$PayPalResult = $this->paypal_adaptive->Pay($PayPalRequestData);
if(!$this->paypal_adaptive->APICallSuccessful($PayPalResult['Ack']))
{
$errors = array('Errors'=>$PayPalResult['Errors']);
$this->load->view('paypal_error',$errors);
}
else
{
$data['result'] = $PayPalResult;
$this->load->view('success', $data);
}
}
and line 11 is this from the pastebin above - $value = urlencode(stripslashes($value));
I figured out how to parse the adaptive payments IPN in PHP.
I used the DecodePayPalIPN() function by donut2d https://www.x.com/developers/paypal/forums/adaptive-payments-api/php-technique-parsing-adaptive-payment-ipn-posts?page=0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C1 in combination with one of the example listeners that is on the paypal website and here is my complete Codeigniter IPN Listener for adaptive payments with a parallel transaction.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Paypal_ipn extends CI_Controller {
public function index() {
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate&'.file_get_contents("php://input");
$header = null;
// 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://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
$raw_post = file_get_contents("php://input");
$post_array = $this->decodePayPalIPN($raw_post);
//log_message('error', "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
//$log1 = var_export($post_array, true);
//log_message('error', $log1);
//log_message('error', "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
if(isset($post_array['sender_email'])) {
$sender_email = $post_array['sender_email'];
}
if(isset($post_array['status'])) {
$status = $post_array['status'];
}
if(isset($post_array['payment_request_date'])) {
$payment_request_date = $post_array['payment_request_date'];
}
if(isset($post_array['transaction'][0]['receiver'])) {
$receiver0 = $post_array['transaction'][0]['receiver'];
}
if(isset($post_array['transaction'][1]['receiver'])) {
$receiver1 = $post_array['transaction'][1]['receiver'];
}
if(isset($post_array['transaction'][0]['id'])) {
$id0 = $post_array['transaction'][0]['id'];
}
if(isset($post_array['transaction'][1]['id'])) {
$id1 = $post_array['transaction'][1]['id'];
}
if(isset($post_array['transaction'][0]['invoiceId'])) {
$invoiceId0 = $post_array['transaction'][0]['invoiceId'];
}
if(isset($post_array['transaction'][1]['invoiceId'])) {
$invoiceId1 = $post_array['transaction'][1]['invoiceId'];
}
if(isset($post_array['transaction'][0]['amount'])) {
$amount0 = $post_array['transaction'][0]['amount'];
}
if(isset($post_array['transaction'][1]['amount'])) {
$amount1 = $post_array['transaction'][1]['amount'];
}
if(isset($post_array['transaction'][0]['status'])) {
$status0 = $post_array['transaction'][0]['status'];
}
if(isset($post_array['transaction'][1]['status'])) {
$status1 = $post_array['transaction'][1]['status'];
}
if(isset($post_array['transaction'][0]['id_for_sender_txn'])) {
$id_for_sender_txn0 = $post_array['transaction'][0]['id_for_sender_txn'];
}
if(isset($post_array['transaction'][1]['id_for_sender_txn'])) {
$id_for_sender_txn1 = $post_array['transaction'][1]['id_for_sender_txn'];
}
if(isset($post_array['transaction'][0]['status_for_sender_txn'])) {
$status_for_sender_txn0 = $post_array['transaction'][0]['status_for_sender_txn'];
}
if(isset($post_array['transaction'][1]['status_for_sender_txn'])) {
$status_for_sender_txn1 = $post_array['transaction'][1]['status_for_sender_txn'];
}
if(isset($post_array['transaction'][1]['pending_reason'])) {
$pending_reason0 = $post_array['transaction'][1]['pending_reason'];
}
if(isset($post_array['transaction'][1]['pending_reason'])) {
$pending_reason1 = $post_array['transaction'][1]['pending_reason'];
}
if (!$fp) {
// HTTP ERROR
} else {
$counter = 0;
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
log_message('error', "sender_email = $sender_email");
log_message('error', "payment_request_date = $payment_request_date");
log_message('error', "status = $status");
log_message('error', "receiver0 = $receiver0");
log_message('error', "receiver1 = $receiver1");
log_message('error', "id0 = $id0");
log_message('error', "id1 = $id1");
log_message('error', "invoiceId0 = $invoiceId0");
log_message('error', "invoiceId1 = $invoiceId1");
log_message('error', "amount0 = $amount0");
log_message('error', "amount1 = $amount1");
log_message('error', "status0 = $status0");
log_message('error', "status1 = $status1");
log_message('error', "id_for_sender_txn0 = $id_for_sender_txn0");
log_message('error', "id_for_sender_txn1 = $id_for_sender_txn1");
log_message('error', "status_for_sender_txn0 = $status_for_sender_txn0");
log_message('error', "status_for_sender_txn1 = $status_for_sender_txn1");
log_message('error', "pending_reason0 = $pending_reason0");
log_message('error', "pending_reason1 = $pending_reason1");
// check the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process payment
$counter++;
}
else if (strcmp ($res, "INVALID") == 0) {
log_message('error', 'WE INVALIDDDDDDDDDDDDDDDDDD');
$test = var_export($res, true);
$test = str_replace(array("\r","\n"), '', $test);
log_message('error', $test);
log_message('error', "Problem with IPN. res = $test");
}
}
fclose ($fp);
}
}
function decodePayPalIPN($raw_post)
{
//log_message('error', "testing");
if (empty($raw_post)) {
return array();
} # else:
$post = array();
$pairs = explode('&', $raw_post);
foreach ($pairs as $pair) {
list($key, $value) = explode('=', $pair, 2);
$key = urldecode($key);
$value = urldecode($value);
# This is look for a key as simple as 'return_url' or as complex as 'somekey[x].property'
preg_match('/(\w+)(?:\[(\d+)\])?(?:\.(\w+))?/', $key, $key_parts);
switch (count($key_parts)) {
case 4:
# Original key format: somekey[x].property
# Converting to $post[somekey][x][property]
if (!isset($post[$key_parts[1]])) {
$post[$key_parts[1]] = array($key_parts[2] => array($key_parts[3] => $value));
} else if (!isset($post[$key_parts[1]][$key_parts[2]])) {
$post[$key_parts[1]][$key_parts[2]] = array($key_parts[3] => $value);
} else {
$post[$key_parts[1]][$key_parts[2]][$key_parts[3]] = $value;
}
break;
case 3:
# Original key format: somekey[x]
# Converting to $post[somkey][x]
if (!isset($post[$key_parts[1]])) {
$post[$key_parts[1]] = array();
}
$post[$key_parts[1]][$key_parts[2]] = $value;
break;
default:
# No special format
$post[$key] = $value;
break;
}#switch
}#foreach
return $post;
}#decodePayPalIPN()
}
Related
I need help in Twilio getting reply responses and storing them in the database in response to sending SMS after user input in response to the message. I am sending an SMS to the user about his/her order schedule and asking him/her to confirm delivery by inputting Ok and when he/she confirm, I am getting his response successfully.
The question or the issue I am facing is that I want to know that when he/she confirm the delivery, I want to update the database record in response to the delivery SMS we sent to him/her earlier. My issue will be resolved if I am able to get order_id from the first message and send it in replytoSMS function.
My Code to send SMS and webhook (replytoSMS) are given below.
<?php
public function initiateSMS(Request $request) {
try {
foreach ( $request->get('items') as $item ) {
$order_id = $item['order_id'];
$phone = $item['phone_number'];
$order = Orders::where('id', $order_id)->first();
$phone_number = $this->client->lookups->v1->phoneNumbers($phone)->fetch();
if($phone_number) {
$template_value = $order->message;
$sms = $this->client->messages->create($phone, [
'from' => $this->from,
'body' => $template_value,
"method" => 'POST',
"statusCallbackMethod" => 'POST',
"statusCallback" => 'https://example.com/simply/public/api/notification/statusMessageBack?order_id='.$order_id.'',
]);
// print($sms->sid);
}
} // foreach loop end
if($sms){
return Response::json(['success' => 'sms initiated successfully!']);
}
} catch (Exception $e) {
return Response::json(['Error' => $e->getMessage()]);
} catch (RestException $rest) {
return Response::json(['Error' => $rest->getMessage()]);
}
}
function statusMessageBack(){
header('Content-type: text/xml');
header('Cache-Control: no-cache');
$response = new MessagingResponse();
$order_id = $_REQUEST['order_id'];
$user_phone = $_REQUEST['To'];
$MessageSid = (!empty($_REQUEST['MessageSid'])) ? $_REQUEST['MessageSid'] : '';
$MessageStatus = (!empty($_REQUEST['MessageStatus'])) ? $_REQUEST['MessageStatus'] : '';
if($MessageStatus && $MessageStatus == "delivered"){
$notification = Notification::create([
"response_code" => $MessageSid,
"type" => $category,
"table_ref" => "orders",
"table_ref_pk" => $order_id,
"response_status" => "",
"medium" => $user_phone,
"status" => $MessageStatus,
"sender_id" => $sender_id
]);
}
print $response; exit;
}
public function replyToSMS(){
header('Content-type: text/xml');
header('Cache-Control: no-cache');
$response = new MessagingResponse();
$MessageSid = (!empty($_REQUEST['MessageSid'])) ? $_REQUEST['MessageSid'] : '';
$MessageStatus = (!empty($_REQUEST['MessageStatus'])) ? $_REQUEST['MessageStatus'] : '';
$body = $_REQUEST['Body'];
$order_id = $_REQUEST['order_id'];
$from_phone = $_REQUEST['From'];
if (strtolower($body) == 'ok' || strtolower($body) == 'yes' || strtolower($body) == 'confirm') {
$response->message('Your delivery has been confirmed. Thank you', [
'callbackUrl' => "https://example.com/api/notification/reply_status?order_id='.$order_id.'",
'callbackMethod' => "POST"
]);
$notification = Notification::where('order_id', $order_id)->update(array("response_status" => "confirmed"));
} else {
$response->message('Sorry');
$notification = Notification::where('order_id', $order_id)->update(array("response_status" => "call store"));
}
print $response;
}
function reply_status(){
header('Content-type: text/xml');
header('Cache-Control: no-cache');
$response = new MessagingResponse();
echo $order_id = $_REQUEST['order_id'];
$user_phone = $_REQUEST['To'];
$MessageSid = (!empty($_REQUEST['MessageSid'])) ? $_REQUEST['MessageSid'] : '';
$MessageStatus = (!empty($_REQUEST['MessageStatus'])) ? $_REQUEST['MessageStatus'] : '';
if($MessageStatus && $MessageStatus == "delivered"){
}
print $response; exit;
}
The SMS protocol does not any concept of additional metadata with SMS messages, nor does it have the concept of replying to a specific message (you can test this by opening your phone's SMS application and trying to respond to any message from someone that wasn't the last one you received).
You can only really tell what someone may be responding to chronologically. That is, if you have sent them a message, then their response is related to that last message that you sent.
This is an issue if you intend to send more than one message asking for a response at the same time. In this situation, we recommend you use two different From numbers to send the message and store that From number against the order in your system. That way you can tell which message was being responded to by matching up the user's phone number and the phone number that you used to send the message.
I cant tell if its working since theirs no log or way to see a error since the server handles it all and i'm very new to these languages. As far as I can tell paypal sandbox sends the ipn but im not sure what works after that all I know is it does not show up in the DataBase. I know the password and everything is configed correctly and the database is set up. Im also following this tutorial here if it helps https://www.evoluted.net/thinktank/web-development/paypal-php-integration
im just to mush of a noob to php to follow it correctly.
heres the script that sends and receives ipn
<?php
// For test payments we want to enable the sandbox mode. If you want to put live
// payments through then this setting needs changing to `false`.
$enableSandbox = true;
// Database settings. Change these for your database configuration.
$dbConfig = [
'host' => 'sql106.epizy.com',
'username' => 'hidden',
'password' => 'hidden',
'name' => 'epiz_23648301_rod'
];
// PayPal settings. Change these to your account details and the relevant URLs
// for your site.
$paypalConfig = [
'email' => 'hidden#gmail.com',
'return_url' => 'http://rod.rf.gd/payment-successful.php',
'cancel_url' => 'http://rod.rf.gd/payment-cancelled.php',
'notify_url' => 'http://rod.rf.gd/payments.php'
];
$paypalUrl = $enableSandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
// Product being purchased.
$itemName = 'Token';
$itemAmount = 1;
// Include Functions
require 'functions.php';
// Check if paypal request or response
if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])) {
// Grab the post data so that we can set up the query string for PayPal.
// Ideally we'd use a whitelist here to check nothing is being injected into
// our post data.
$data = [];
foreach ($_POST as $key => $value) {
$data[$key] = stripslashes($value);
}
// Set the PayPal account.
$data['business'] = $paypalConfig['email'];
// Set the PayPal return addresses.
$data['return'] = stripslashes($paypalConfig['return_url']);
$data['cancel_return'] = stripslashes($paypalConfig['cancel_url']);
$data['notify_url'] = stripslashes($paypalConfig['notify_url']);
// Set the details about the product being purchased, including the amount
// and currency so that these aren't overridden by the form data.
$data['item_name'] = $itemName;
$data['amount'] = $itemAmount;
$data['currency_code'] = 'USD';
// Add any custom fields for the query string.
//$data['custom'] = USERID;
// Build the query string from the data.
$queryString = http_build_query($data);
// Redirect to paypal IPN
header('location:' . $paypalUrl . '?' . $queryString);
exit();
} else {
// Handle the PayPal response.
// Create a connection to the database.
$db = new mysqli($dbConfig['host'], $dbConfig['username'], $dbConfig['password'], $dbConfig['name']);
// Assign posted variables to local data array.
$data = [
'item_name' => $_POST['item_name'],
'item_number' => $_POST['item_number'],
'payment_status' => $_POST['payment_status'],
'payment_amount' => $_POST['mc_gross'],
'payment_currency' => $_POST['mc_currency'],
'txn_id' => $_POST['txn_id'],
'receiver_email' => $_POST['receiver_email'],
'payer_email' => $_POST['payer_email'],
'custom' => $_POST['custom'],
];
// We need to verify the transaction comes from PayPal and check we've not
// already processed the transaction before adding the payment to our
// database.
if (verifyTransaction($_POST) && checkTxnid($data['txn_id'])) {
if (addPayment($data) !== false) {
// Payment successfully added.
}
}
}
heres the addPayment func
function addPayment($data) {
global $db;
if (is_array($data)) {
$stmt = $db->prepare('INSERT INTO `payments` (txnid, payment_amount, payment_status, itemid, createdtime) VALUES(?, ?, ?, ?, ?)');
$stmt->bind_param(
'sdsss',
$data['txn_id'],
$data['payment_amount'],
$data['payment_status'],
$data['item_number'],
date('Y-m-d H:i:s')
);
$stmt->execute();
$stmt->close();
return $db->insert_id;
}
return false;
}
I have integrate paypal with my Laravel application. I'm able to make payment successfully from Paypal, but after successful payment I'm not able to receive any type of response in my site.
My code is as below:
public function aCoolFunction(CreateDistrictRequest $request)
{
$data = $request->only('city_id', 'name', 'latitude', 'longitude');
$district = $this->districtRepository->create($data);
$payment = 'sandbox';
$values = [
'charest' => 'utf-8',
'lc' => 'US',
'cmd' => '_xclick',
'amount' => $product->price, // PRICE
'business' => 'test-facilitator#gmail.com', // PAYPAL EMAIL
'item_name' => $product->name, // NAME
'item_number' => $product->id, // ITEM ID
'currency_code' => 'USD',
'no_note' => '0',
'tax_rate' => 0, // 0- TO NOT ADD ANY FEES
'no_shipping' => 1, // NO ADDRESS
'rm' => '1',
'page_style' => 'paypal',
'custom' => '1', // ANY VALUES TO RETURN IT AFTER PAYMENT SUCCESS
'return' => url('payment-status'), // RETURN - MUST BE A VALID URL
'cancel_return' => url('payment-cancel'),
'notify_url' => url('payment-ipn') // IPN PAYPAL - CHECK IF IS PAID
];
$pay_url = "https://www.paypal.com/cgi-bin/webscr";
// CREATE $payment TO CHECK IF IS SANDBOX or LIVE - FROM CONFIG FILE FOR EXAMPLE
if ($payment == 'sandbox') :
$pay_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
endif;
return view('paypalpayment', ['pay_url' => $pay_url, 'values' => $values]);
}
public function paymentInfo(Request $request)
{
$myfile = fopen("paypalog.txt", "w") or die('Cannot open file: ' . $my_file);
$data = 'Transaction id = ' . $request;
fwrite($myfile, $data);
if ($request->tx)
{
if ($payment = Payment::where('transaction_id', $request->tx)->first())
{
$payment_id = $payment->id;
}
else
{
$payment = new Payment;
$payment->item_number = $request->item_number;
$payment->transaction_id = $request->tx;
$payment->currency_code = $request->cc;
$payment->payment_status = $request->st;
$payment->save();
$payment_id = $payment->id;
}
return 'Pyament has been done and your payment id is : ' . $payment_id;
}
else
{
return 'Payment has failed';
}
}
public function payment_success(Request $req)
{
$myfile = fopen("paypalog1.txt", "w") or die('Cannot open file: ' . $my_file);
$data = 'Transaction id = ' . $request->tx;
fwrite($myfile, $data);
}
from above code paymentinfo() is call in success or failure of payment from paypal. but here I'am not able to get any type of response from Paypal regarding payment.
This are my routes
Route::get('payment-status',array('as'=>'payment.status','uses'=>'PaymentController#paymentInfo'));
Route::get('payment',array('as'=>'payment','uses'=>'PaymentController#payment'));
Route::get('payment-cancel', function () {
return 'Payment has been canceled';
});
Route::get('payment-success' , 'PaymentController#payment_success');
Can anyone help me to solve this issue?
While dealing with PayPal you have to implement the IPN (Instant payment Notification) to get the status of the payment whether it is successful or failed.
For that you have to activate the IPN under the setting in your PayPal account and provide an url of your system to receive the IPN data, and that url must be of post type.
If I am not wrong, you have created this url for the same:
Route::get('payment-success' , 'PaymentController#payment_success');
but the issue is, it is of get type, so change it to 'post' and try again. If this url is not for the same purpose then create a url for the same.
P.S.: for testing purpose, PayPal provides an IPN simulator to test the same process, use that one it will be very helpful.
IPN simulator reference
function drupal_http_request($url, array $options = array()) {
// Allow an alternate HTTP client library to replace Drupal's default
// implementation.
$override_function = variable_get('drupal_http_request_function', FALSE);
if (!empty($override_function) && function_exists($override_function)) {
return $override_function($url, $options);
}
$result = new stdClass();
// Parse the URL and make sure we can handle the schema.
$uri = #parse_url($url);
if ($uri == FALSE) {
$result->error = 'unable to parse URL';
$result->code = -1001;
return $result;
}
if (!isset($uri['scheme'])) {
$result->error = 'missing schema';
$result->code = -1002;
return $result;
}
timer_start(__FUNCTION__);
// Merge the default options.
$options += array(
'headers' => array(),
'method' => 'GET',
'data' => NULL,
'max_redirects' => 3,
'timeout' => 30.0,
'context' => NULL,
);
// Merge the default headers.
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
);
// stream_socket_client() requires timeout to be a float.
$options['timeout'] = (float) $options['timeout'];
// Use a proxy if one is defined and the host is not on the excluded list.
$proxy_server = variable_get('proxy_server', '');
if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
// Set the scheme so we open a socket to the proxy server.
$uri['scheme'] = 'proxy';
// Set the path to be the full URL.
$uri['path'] = $url;
// Since the URL is passed as the path, we won't use the parsed query.
unset($uri['query']);
// Add in username and password to Proxy-Authorization header if needed.
if ($proxy_username = variable_get('proxy_username', '')) {
$proxy_password = variable_get('proxy_password', '');
$options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
}
// Some proxies reject requests with any User-Agent headers, while others
// require a specific one.
$proxy_user_agent = variable_get('proxy_user_agent', '');
// The default value matches neither condition.
if ($proxy_user_agent === NULL) {
unset($options['headers']['User-Agent']);
}
elseif ($proxy_user_agent) {
$options['headers']['User-Agent'] = $proxy_user_agent;
}
}
switch ($uri['scheme']) {
case 'proxy':
// Make the socket connection to a proxy server.
$socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
// The Host header still needs to match the real request.
$options['headers']['Host'] = $uri['host'];
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
break;
case 'http':
case 'feed':
$port = isset($uri['port']) ? $uri['port'] : 80;
$socket = 'tcp://' . $uri['host'] . ':' . $port;
// RFC 2616: "non-standard ports MUST, default ports MAY be included".
// We don't add the standard port to prevent from breaking rewrite rules
// checking the host that do not take into account the port number.
$options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
break;
case 'https':
// Note: Only works when PHP is compiled with OpenSSL support.
$port = isset($uri['port']) ? $uri['port'] : 443;
$socket = 'ssl://' . $uri['host'] . ':' . $port;
$options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
break;
default:
$result->error = 'invalid schema ' . $uri['scheme'];
$result->code = -1003;
return $result;
}
if (empty($options['context'])) {
$fp = #stream_socket_client($socket, $errno, $errstr, $options['timeout']);
}
else {
// Create a stream with context. Allows verification of a SSL certificate.
$fp = #stream_socket_client($socket, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $options['context']);
}
var_dump($fp);
// Make sure the socket opened properly.
if (!$fp) {
// When a network error occurs, we use a negative number so it does not
// clash with the HTTP status codes.
$result->code = -$errno;
$result->error = trim($errstr) ? trim($errstr) : t('Error opening socket #socket', array('#socket' => $socket));
print_r($result);
exit();
// Mark that this request failed. This will trigger a check of the web
// server's ability to make outgoing HTTP requests the next time that
// requirements checking is performed.
// See system_requirements().
variable_set('drupal_http_request_fails', TRUE);
return $result;
}
// Construct the path to act on.
$path = isset($uri['path']) ? $uri['path'] : '/';
if (isset($uri['query'])) {
$path .= '?' . $uri['query'];
}
// Only add Content-Length if we actually have any content or if it is a POST
// or PUT request. Some non-standard servers get confused by Content-Length in
// at least HEAD/GET requests, and Squid always requires Content-Length in
// POST/PUT requests.
$content_length = strlen($options['data']);
if ($content_length > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') {
$options['headers']['Content-Length'] = $content_length;
}
// If the server URL has a user then attempt to use basic authentication.
if (isset($uri['user'])) {
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':'));
}
// If the database prefix is being used by SimpleTest to run the tests in a copied
// database then set the user-agent header to the database prefix so that any
// calls to other Drupal pages will run the SimpleTest prefixed database. The
// user-agent is used to ensure that multiple testing sessions running at the
// same time won't interfere with each other as they would if the database
// prefix were stored statically in a file or database variable.
$test_info = &$GLOBALS['drupal_test_info'];
if (!empty($test_info['test_run_id'])) {
$options['headers']['User-Agent'] = drupal_generate_test_ua($test_info['test_run_id']);
}
$request = $options['method'] . ' ' . $path . " HTTP/1.0\r\n";
foreach ($options['headers'] as $name => $value) {
$request .= $name . ': ' . trim($value) . "\r\n";
}
$request .= "\r\n" . $options['data'];
$result->request = $request;
// Calculate how much time is left of the original timeout value.
$timeout = $options['timeout'] - timer_read(__FUNCTION__) / 1000;
if ($timeout > 0) {
stream_set_timeout($fp, floor($timeout), floor(1000000 * fmod($timeout, 1)));
fwrite($fp, $request);
}
// Fetch response. Due to PHP bugs like http://bugs.php.net/bug.php?id=43782
// and http://bugs.php.net/bug.php?id=46049 we can't rely on feof(), but
// instead must invoke stream_get_meta_data() each iteration.
$info = stream_get_meta_data($fp);
$alive = !$info['eof'] && !$info['timed_out'];
$response = '';
while ($alive) {
// Calculate how much time is left of the original timeout value.
$timeout = $options['timeout'] - timer_read(__FUNCTION__) / 1000;
if ($timeout <= 0) {
$info['timed_out'] = TRUE;
break;
}
stream_set_timeout($fp, floor($timeout), floor(1000000 * fmod($timeout, 1)));
$chunk = fread($fp, 1024);
$response .= $chunk;
$info = stream_get_meta_data($fp);
$alive = !$info['eof'] && !$info['timed_out'] && $chunk;
}
fclose($fp);
if ($info['timed_out']) {
$result->code = HTTP_REQUEST_TIMEOUT;
$result->error = 'request timed out';
return $result;
}
// Parse response headers from the response body.
// Be tolerant of malformed HTTP responses that separate header and body with
// \n\n or \r\r instead of \r\n\r\n.
list($response, $result->data) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
$response = preg_split("/\r\n|\n|\r/", $response);
// Parse the response status line.
$response_status_array = _drupal_parse_response_status(trim(array_shift($response)));
$result->protocol = $response_status_array['http_version'];
$result->status_message = $response_status_array['reason_phrase'];
$code = $response_status_array['response_code'];
$result->headers = array();
// Parse the response headers.
while ($line = trim(array_shift($response))) {
list($name, $value) = explode(':', $line, 2);
$name = strtolower($name);
if (isset($result->headers[$name]) && $name == 'set-cookie') {
// RFC 2109: the Set-Cookie response header comprises the token Set-
// Cookie:, followed by a comma-separated list of one or more cookies.
$result->headers[$name] .= ',' . trim($value);
}
else {
$result->headers[$name] = trim($value);
}
}
$responses = array(
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
416 => 'Requested range not satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
);
// RFC 2616 states that all unknown HTTP codes must be treated the same as the
// base code in their class.
if (!isset($responses[$code])) {
$code = floor($code / 100) * 100;
}
$result->code = $code;
switch ($code) {
case 200: // OK
case 304: // Not modified
break;
case 301: // Moved permanently
case 302: // Moved temporarily
case 307: // Moved temporarily
$location = $result->headers['location'];
$options['timeout'] -= timer_read(__FUNCTION__) / 1000;
if ($options['timeout'] <= 0) {
$result->code = HTTP_REQUEST_TIMEOUT;
$result->error = 'request timed out';
}
elseif ($options['max_redirects']) {
// Redirect to the new location.
$options['max_redirects']--;
$result = drupal_http_request($location, $options);
$result->redirect_code = $code;
}
if (!isset($result->redirect_url)) {
$result->redirect_url = $location;
}
break;
default:
$result->error = $result->status_message;
}
return $result;
}
I'm getting the below mentioned message by doing var_dump of $fp as mentioned above on my VM machine hosted with Ubuntu 14.04
stdClass Object
(
[code] => 0
[error] => php_network_getaddresses: getaddrinfo failed: Name or service not known
)
When I'm implementing the same thing on my localhost which is XAMPP based in Windows 7 I'm getting this:
Resource id #8
Due to this I'm unable to use the drupal_http_request
As per your suggestion I've tried dns_get_record()
$dns_get_record = dns_get_record("www.google.com");
print_r($dns_get_record);
and got this as the output:
Array
(
[0] => Array
(
[host] => www.google.com
[class] => IN
[ttl] => 243
[type] => A
[ip] => 216.58.220.4
)
[1] => Array
(
[host] => www.google.com
[class] => IN
[ttl] => 257
[type] => AAAA
[ipv6] => 2404:6800:4009:805::2004
)
)
I've also checked the stream_socket_client()
var_dump(stream_socket_client());
and it returned me bool(false)
Since you've not put any proper error handling in the code, we can't tell which function is being executed. You haven't provided the parameters you are passing, so we can't tell what the cause is, but the most likely issue is that you are trying to establish a network connection and the host where the code is running is unable to resolve the hostname inside $socket.
You can very this with dns_get_record() or speak to your hosting provider.
I am basically trying to use the PAY call of Adaptive Payments to programmatically and immediately send funds from my own paypal account to other accounts. According to the documentation, so long as I specify the senderEmail (my own paypal address, used to set up the Adaptive Payments), this should work verbatim.
However, when I make the call, I always get result "CREATED" instead of "COMPLETED". Created means the system still wants me to manually log into PayPal and approve the payments. I really need these payments to occur automatically on the spot. Any help would be appreciated.
Here is my request string:
currencyCode=USD&
returnUrl=http%3A%2F%2Fwww.website.com%2F&
actionType=PAY&
cancelUrl=http%3A%2F%2Fwww.website.com%2F&
receiverList.receiver%280%29.email=receiver%40gmail.com&
receiverList.receiver%280%29.amount=1.00&
requestEnvelope.senderEmail=me%40gmail.com&
clientDetails.deviceId=mydevice&
clientDetails.ipAddress=127.0.0.1&
clientDetails.applicationId=APP-ZZZZZZZZZZZZZ&
requestEnvelope.errorLanguage=en_US&
memo=memo&
feesPayer=EACHRECEIVER&
ipnNotificationUrl=http%3A%2F%2Fwww.website.com%2Fpay.php
And here is the response from PayPal:
[responseEnvelope.timestamp] => 2012-03-01T19:09:57.290-08:00
[responseEnvelope.ack] => Success
[responseEnvelope.correlationId] => 71efd416a2100
[responseEnvelope.build] => 2486531
[payKey] => AP-ZZZZZZZZZZZZZZZ
[paymentExecStatus] => CREATED
Forget everything I said earlier. The problem isn't an inconsistency between Sandbox and Live either, but rather a wrong parameter for 'senderEmail'.
Simply change:
requestEnvelope.senderEmail=me#gmail.com&
To:
senderEmail=me#gmail.com&
For example, the following returns a 'COMPLETED' implicit payment.
<?php
function AdaptiveCall($bodyparams, $method, $payKey) {
try
{
$body_data = http_build_query($bodyparams, "", chr(38));
$url = trim("https://svcs.sandbox.paypal.com/AdaptivePayments/".$method."");
$params = array("http" => array(
"method" => "POST",
"content" => $body_data,
"header" => "X-PAYPAL-SECURITY-USERID: xxxxxxxxx\r\n" .
"X-PAYPAL-SECURITY-SIGNATURE: xxxxxxxxxxx\r\n" .
"X-PAYPAL-SECURITY-PASSWORD: xxxxxxx\r\n" .
"X-PAYPAL-APPLICATION-ID: APP-80W284485P519543T\r\n" .
"X-PAYPAL-REQUEST-DATA-FORMAT: NV\r\n" .
"X-PAYPAL-RESPONSE-DATA-FORMAT: NV\r\n"
)
);
//create stream context
$ctx = stream_context_create($params);
//open the stream and send request
$fp = #fopen($url, "r", false, $ctx);
//get response
$response = stream_get_contents($fp);
//check to see if stream is open
if ($response === false) {
throw new Exception("php error message = " . "$php_errormsg");
}
//close the stream
fclose($fp);
//parse the ap key from the response
$keyArray = explode("&", $response);
foreach ($keyArray as $rVal){
list($qKey, $qVal) = explode ("=", $rVal);
$kArray[$qKey] = $qVal;
}
//print the response to screen for testing purposes
If ( $kArray["responseEnvelope.ack"] == "Success") {
echo "<strong>".$method ."</strong><br>";
foreach ($kArray as $key =>$value){
echo $key . ": " .$value . "<br/>";
}
// Return payKey
global $payKey;
if(!empty($kArray['payKey'])) { $payKey = $kArray['payKey']; return($payKey); }
}
else {
echo 'ERROR Code: ' . $kArray["error(0).errorId"] . " <br/>";
echo 'ERROR Message: ' . urldecode($kArray["error(0).message"]) . " <br/>";
}
}
catch(Exception $e) {
echo "Message: ||" .$e->getMessage()."||";
}
}
//Create Pay body
$bodyparams = array ( "requestEnvelope.errorLanguage" => "en_US",
'actionType' => 'PAY',
'currencyCode' => 'USD',
'receiverList.receiver(0).email' => 'another_account#domain.tld',
'receiverList.receiver(0).amount' => '1.00',
'senderEmail' => 'xxxxxxxxx',
'memo' => 'Test memo',
'ipnNotificationUrl' => 'http://xxxxxxxx',
'cancelUrl' => 'http://xxxxxxxxx',
'returnUrl' => 'http://xxxxxxxxxx'
);
// Call Pay API
AdaptiveCall($bodyparams, "Pay");
?>
Pay response:
responseEnvelope.timestamp: 2012-03-03T09%3A10%3A22.900-08%3A00
responseEnvelope.ack: Success
responseEnvelope.correlationId: 4bc5cfc4a7514
responseEnvelope.build: 2486531
payKey: AP-1XJ7636763429720C
paymentExecStatus: COMPLETED