I've been using a function called sendToHost that has worked for pinging a server with a GET string and returning a response.
# Example of GET string:
# sub.domain.com/api.php?a=1&b=2&c=3
$var = sendToHost('sub.domain.com','get','/api.php','a=1&b=2&c=3');
However it won't handle sending to a Secure Server (https).
Does anyone know of a php function alternative to sendToHost?
Here's the SendToHost code:
/* sendToHost
* ~~~~~~~~~~
* Params:
* $host - Just the hostname. No http:// or /path/to/file.html portions
* $method - get or post, case-insensitive
* $path - The /path/to/file.html part
* $data - The query string, without initial question mark
* $useragent - If true, 'MSIE' will be sent as the User-Agent (optional)
*
* Examples:
* sendToHost('www.google.com','get','/search','q=php_imlib');
* sendToHost('www.example.com','post','/some_script.cgi',
* 'param=First+Param&second=Second+param');
*/
function sendToHost($host,$method,$path,$data,$useragent=0)
{
// Supply a default method of GET if the one passed was empty
if (empty($method))
$method = 'GET';
$method = strtoupper($method);
$fp = fsockopen($host,80);
if ($method == 'GET')
$path .= '?' . $data;
fputs($fp, "$method $path HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
if ($method == 'POST')
fputs($fp, "Content-length: " . strlen($data) . "\r\n");
if ($useragent)
fputs($fp, "User-Agent: MSIE\r\n");
fputs($fp, "Connection: close\r\n\r\n");
if ($method == 'POST')
fputs($fp, $data);
while (!feof($fp))
$buf .= fgets($fp,128);
fclose($fp);
return $buf;
}
Thanks.
Have you tried using curl? It supports ssl and works well under GNU/Linux..
Related
We are integrating the travel API of www.transhotel-dev.com.
The code is like this:
<?php
$servletHOST = "www.transhotel-dev.com";
$servletPATH = "/interfaces/SController";
$pXML = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><Login><Username>Username</Username><Password>Password</Password></Login>";
$pCall = "Login";
$postdata = "pXML=" . urlencode($pXML) . "&pCall=" . urlencode($pCall);
$fp = pfsockopen($servletHOST, 1184);
if ($fp) {
fputs($fp, "POST $servletPATH HTTP/1.0\n");
fputs($fp, "Accept: */*\n");
$strlength = strlen( $postdata );
fputs($fp, "Content-length: " . $strlength . "\n\n");
fputs($fp, $postdata . "\n" );
$output = "";
while (!feof($fp)) {
$output .= fgets($fp, 1024);
}
fclose($fp);
echo $output;
}
?>
HTTP compression and POST method are required to go beyond this point. Can anybody help?
The following calls require the use of https secure protocol
(https://www.transhotel-dev.com:1449/interfaces/SController):
Login
AddAmountCardHPlus
GetNifInvoices
NifAgencyReservations
NifHotelReservations
ConfirmReservation (When contain the data of a credit card)
BuildSearchForm
LoginRQ
LoginB2B
CreateAgency
NifActivitiesReservations
GetActivitiesProvider
NifTransfersReservations
GetTransfersProvider
LoginHPlus
UserLogInHPlus
so you should use ssl protocol for login action:
$fp = pfsockopen("ssl://www.transhotel-dev.com", 1449);
So I'm currently trying to implement the 'SendToHost' function that is widely used for 'GET' and 'POST' procedures. In my case, I want to use it for sending a 'postcode' to a shopping website's postcode input form for use with retrieving that postcode's specific catalogue. More specifically, the code should automatically generate the web page that has the results for the postcode. Below is my code coupled with the function and I'd like to know why it isn't working:
function SendToHost($host, $method, $path, $data, $useragent=0)
{
// Supply a default method of GET if the one passed was empty
if (empty($method))
$method = 'GET';
$method = strtoupper($method);
$fp = fsockopen($host,80);
if ($method == 'GET')
$path .= '?' . $data;
fputs($fp, "$method $path HTTP/1.1\n");
fputs($fp, "Host: $host\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\n");
fputs($fp, "Content-length: " . strlen($data) . "\n");
if ($useragent)
fputs($fp, "User-Agent: MSIE\n");
fputs($fp, "Connection: close\n\n");
if ($method == 'POST')
fputs($fp, $data);
while (!feof($fp))
$buf .= fgets($fp,128);
fclose($fp);
return $buf;
}
echo sendToHost('catalog.coles.com.au','get','/default.aspx','ctl00_Body_PostcodeTextBox=4122');
You are using the wrong new-line style in your headers. You need to use \r\n, not just \n.
A quote from the HTTP/1.1 docs:
HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all protocol elements except the entity-body
Source: http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
If you are just sending simple POST/GET requests, I'd suggest using an HTTP library like cURL. There's no reason to manually open a socket and send headers unless you are doing something more complex.
function SendToHost($url, $data, $method='GET', $useragent=FALSE){
$ch = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => TRUE
);
if($method === 'POST'){
$options += array(
CURLOPT_URL => $url,
CURLOPT_POST => TRUE,
// Passing a string will set `application/x-www-form-urlencoded`
// Whereas an array will set `multipart/form-data`
CURLOPT_POSTFIELDS => http_build_query($data)
);
}
elseif($method === 'GET'){
$options[CURLOPT_URL] = $url . '?' . http_build_query($data);
}
if($useragent){
$options[CURLOPT_USERAGENT] = 'MSIE';
}
curl_setopt_array($ch, $options);
$buf = curl_exec($ch);
curl_close($ch);
return $buf;
}
You call this one slightly differently:
echo sendToHost('http://catalog.coles.com.au/default.aspx', array(
'ctl00_Body_PostcodeTextBox' => 4122
));
Heck, if you just want to send a GET request, you can even use file_get_contents:
echo file_get_contents('http://catalog.coles.com.au/default.aspx?ctl00_Body_PostcodeTextBox=4122');
my script is presently live and I have a problematic sandbox to test my amendments on and this is pissing off some of my customers. I'm better off testing on live site.
PayPal sent an email to warn us and keeps reminding me to jump to 1.1 but since June I've had bad luck trying various mixes and consulting various platforms for advise.
Below is my current PayPal.php code which links to a lot of classes which are necessary for my website.
I have tried many combinations of coding and it is evidently seen from the commented lines.
They doesn't seem to be able to work and I have run low on options.
Is there any kind good soul able to fix this? or advise me what is going wrong?
IPN always replies me a INVALID response or Error but in http 1.0 everything is fine and dandy...
<?php
include_once(PayPalConfig::$params[PayPalConfig::$PAYPAL_PATH]."/PayPalSettings.php");
include_once(PayPalConfig::$params[PayPalConfig::$PAYPAL_PATH]."/PayPalConstants.php");
class PayPal
{
private $settings;
private $socket;
private $data;
/**
* Constructor
*
* #param PayPalSettings $settings
*/
public function __construct(PayPalSettings $settings, array $data)
{
// Store the setting which has been passed in
$this->settings = $settings;
$this->data = $data;
}
/**
* Enter description here...
*
* #return unknown
*/
function connectToPayPal()
{
// Store the URL string
//$url = $this->settings->paypalURL;
$url = "ssl://ipnpb.paypal.com";
// Open a socket with paypal and send all the POSTed info as our request
//ORIGINAL
//$this->socket = fsockopen ($url, 80, $errno, $errstr, 30);
//AMENDED - 30/06/2013
$this->socket = fsockopen ($url, 443, $errno, $errstr, 30);
//FAILED AGAIN
//$this->socket = fsockopen ($url, 443, $errno, $errstr, 30);
return $this->socket;
}
/**
* Enter description here...
*
* #return unknown
*/
function createDataForPayPal()
{
// create a request to paypal to verify the data we have recieved
$req = 'cmd=_notify-validate';
// Build request string from each value in the $_POST
foreach ($this->data as $key => $value)
{
//Original
//$value = urlencode(stripslashes($value));
//AMENDED - 30/08/2013
$value = urlencode($value);
$req .= "&$key=$value";
}
return $req;
}
/**
* Enter description here...
*
* #param unknown_type $fp
* #param unknown_type $requestString
* #return unknown
*/
function verifyWithPaypal($fp, $requestString)
{
/* OLD CHUNK
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
//try this NEXT? - Not tried - 20/08/13
//$header = "POST cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: ipnpb.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
//$header .= "Content-Length: " . strlen($requestString) . "\r\n";
$header .= "Content-Length: " . strlen($requestString) . "\r\n\r\n";
$header .= "Connection: close\r\n\r\n";
*/
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Length: " . strlen($requestString) . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: ipnpb.paypal.com\r\n";
$header .= "Connection: close\r\n\r\n";
// If the send has failed, we just have to return false
if (!$fp)
{
return PayPalConstants::$FAILED_TO_CONNECT;
}
else
{
// Paypal responded to our request. Store the respond
//Original
fputs ($fp, $header . $requestString);
//Amended New Try Next
//fputs ($fp, $header . $requestString . "\r\n\r\n");
// Fetch respond string from PayPal
while (!feof($fp))
{
$res = fgets ($fp, 1024);
//Writes $res to LogFile
//$logger->write($res);
// Determine if the transaction has been verified with PayPal
if (strcmp (trim($res), "VERIFIED") == 0)
{
return PayPalConstants::$VERIFIED;
}
else if (strcmp (trim($res), "INVALID") == 0)
{
return PayPalConstants::$NOT_VERIFIED;
}
}
}
//return $res;
return PayPalConstants::$NOT_VERIFIED;
}
/**
* Return the payment status
*
* #return string The payment status
*/
function getPaymentStatus()
{
if ($this->socket)
{
return $this->data[self::$PAYMENT_STATUS];
}
}
function massPayment(array $payee, $environment, $emailSubject, $receiverType, $bTest=false)
{
// Setup sending data
$currency = 'USD';
$method = PayPalConstants::$MASS_PAYMENT;
$nvpStr="&EMAILSUBJECT=$emailSubject&RECEIVERTYPE=$receiverType&CURRENCYCODE=$currency";
// Encode the string
foreach($payee as $i => $receiverData) {
$receiverEmail = urlencode($receiverData['receiverEmail']);
$amount = urlencode($receiverData['amount']);
$uniqueID = urlencode($receiverData['uniqueID']);
$note = urlencode($receiverData['note']);
$nvpStr .= "&L_EMAIL$i=$receiverEmail&L_Amt$i=$amount&L_UNIQUEID$i=$uniqueID&L_NOTE$i=$note";
}
// Set end point
if ($environment != "live")
{
$API_Endpoint = "https://api-3t.$environment.paypal.com/nvp";
}
else
{
// TODO: Live API endpoint set here
$API_Endpoint = "https://api-3t.paypal.com/nvp";
}
$mode = PayPalConfig::$API;
// What mode are we using the API?
if ($bTest)
{
$mode = PayPalConfig::$API_TEST;
}
$API_Username = PayPalConfig::$params[$mode][PayPalConfig::$API_USERNAME];
$API_Password = PayPalConfig::$params[$mode][PayPalConfig::$API_PASSWORD];
$API_Sign = PayPalConfig::$params[$mode][PayPalConfig::$API_SIGN];
// Set the curl parameters.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
// Turn off the server and peer verification (TrustManager Concept).
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$version = urlencode('51.0');
// Generate the request string
$nvpreq = "METHOD=$method".
"&VERSION=$version".
"&PWD=$API_Password".
"&USER=$API_Username".
"&SIGNATURE=$API_Sign$nvpStr";
// Set the request as a POST FIELD for curl.
curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
// Get response from the server.
$httpResponse = curl_exec($ch);
if(!$httpResponse) {
exit("$method failed: ".curl_error($ch).'('.curl_errno($ch).')');
}
// Extract the response details.
$httpResponseAr = explode("&", $httpResponse);
$httpParsedResponseAr = array();
foreach ($httpResponseAr as $i => $value) {
$tmpAr = explode("=", $value);
if(sizeof($tmpAr) > 1) {
$httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
}
}
if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
}
return ($httpParsedResponseAr);
}
}
?>
Somehow, trimming the result straight away (as opposed to just before comparison) has worked for me:
$res = fgets ($fp, 1024);
$res = trim($res);
Good luck
I'm trying to create a fire and forget method in PHP so that I can POST data to a web server and not have wait for a response. I read that this could be achieved by using CURL like in the following code:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_exec($ch);
curl_close($ch);
However I don't think it works as I expect. For example if the URL I send the request to has an error it causes my script to throw an error as well. If it was fire and forget I would expect that not to happen.
Can anyone tell me whether I'm doing something wrong or offer an alternative suggestion. I'm using Windows locally and Linux for dev, staging and production environments.
UPDATE
I have found an alternative solution here: http://blog.markturansky.com/archives/205
I've cleaned it up into the code below:
function curl_post_async($url, $params = array())
{
// create POST string
$post_params = array();
foreach ($params as $key => &$val)
{
$post_params[] = $key . '=' . urlencode($val);
}
$post_string = implode('&', $post_params);
// get URL segments
$parts = parse_url($url);
// workout port and open socket
$port = isset($parts['port']) ? $parts['port'] : 80;
$fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
// create output string
$output = "POST " . $parts['path'] . " HTTP/1.1\r\n";
$output .= "Host: " . $parts['host'] . "\r\n";
$output .= "Content-Type: application/x-www-form-urlencoded\r\n";
$output .= "Content-Length: " . strlen($post_string) . "\r\n";
$output .= "Connection: Close\r\n\r\n";
$output .= isset($post_string) ? $post_string : '';
// send output to $url handle
fwrite($fp, $output);
fclose($fp);
}
This one seems to work better for me.
Is it a valid solution?
Yes, using sockets is the way to go if you don't care about the response from the URL you're calling. This is because socket connection can be terminated straight after sending the request without waiting and this is exactly what you're after - Fire and Forget.
Two notes though:
It's no longer a cURL request, so it's worth renaming the function. :)
It's definitely worth checking whether the socket could've been opened to prevent the script from complaining later when if fails:
$fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
if ( ! $fp)
{
return FALSE;
}
It's worth linking to the original source of the fsocket() script you're now using:
http://w-shadow.com/blog/2007/10/16/how-to-run-a-php-script-in-the-background/
Here is a cleaned up version of diggersworld's code that also handles other HTTP methods then POST and throws meaningful exceptions if the function fails.
/**
* Send a HTTP request, but do not wait for the response
*
* #param string $method The HTTP method
* #param string $url The url (including query string)
* #param array $params Added to the URL or request body depending on method
*/
public function sendRequest(string $method, string $url, array $params = []): void
{
$parts = parse_url($url);
if ($parts === false)
throw new Exception('Unable to parse URL');
$host = $parts['host'] ?? null;
$port = $parts['port'] ?? 80;
$path = $parts['path'] ?? '/';
$query = $parts['query'] ?? '';
parse_str($query, $queryParts);
if ($host === null)
throw new Exception('Unknown host');
$connection = fsockopen($host, $port, $errno, $errstr, 30);
if ($connection === false)
throw new Exception('Unable to connect to ' . $host);
$method = strtoupper($method);
if (!in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
$queryParts = $params + $queryParts;
$params = [];
}
// Build request
$request = $method . ' ' . $path;
if ($queryParts) {
$request .= '?' . http_build_query($queryParts);
}
$request .= ' HTTP/1.1' . "\r\n";
$request .= 'Host: ' . $host . "\r\n";
$body = http_build_query($params);
if ($body) {
$request .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
$request .= 'Content-Length: ' . strlen($body) . "\r\n";
}
$request .= 'Connection: Close' . "\r\n\r\n";
$request .= $body;
// Send request to server
fwrite($connection, $request);
fclose($connection);
}
I am trying to implement Paypal IPN but it never reaches the url I've set. I've written a script to log visits to this url and all I get are my visits.
How long does it take for Paypal to sent the notification?
EDIT
IPNs suddenly started to come but now I can't verify...Here is the code:
$url = 'https://www.paypal.com/cgi-bin/webscr';
$postdata = '';
foreach ($_POST as $i => $v) {
$postdata .= $i . '=' . urlencode($v) . '&';
}
$postdata .= 'cmd=_notify-validate';
$web = parse_url($url);
if ($web['scheme'] == 'https') {
$web['port'] = 443;
$ssl = 'ssl://';
} else {
$web['port'] = 80;
$ssl = '';
}
$fp = #fsockopen($ssl . $web['host'], $web['port'], $errnum, $errstr, 30);
if (!$fp) {
echo $errnum . ': ' . $errstr;
} else {
fputs($fp, "POST " . $web['path'] . " HTTP/1.1\r\n");
fputs($fp, "Host: " . $web['host'] . "\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($postdata) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $postdata . "\r\n\r\n");
while (!feof($fp)) {
$info[] = #fgets($fp, 1024);
}
fclose($fp);
$info = implode(',', $info);
if (eregi('VERIFIED', $info)) {
} else {
}
}
I already commented above. But I'm pretty sure the html encoded & is messing up your callback.
There's big difference between URL encoding and HTML encoding.
Change this '&' to this '&'. & is a url/post character used to separate different sets of key/value pairs. By changing it to &, you made your whole callback a single value.
Also, just some advice, but I would ditch this
if (eregi('VERIFIED', $info)) {} else {}
and replace it with this
if (preg_match('/VERIFIED/', $info)) {} else {}
eregi is depreciated.
http://php.net/manual/en/function.eregi.php