Posting data with fsockopen, no data received on receiving side - php

I am using fsockopen to connect and send data to a script. The problem is that no data is received on the receiving end as you can see in my output below, only empty array is printed. I've based my solution on Tamlyns answer here: PHP Post data with Fsockopen. I did' try his way of creating the post-parameters, no difference in the output.
My main script:
<?php
session_start();
$fp = fsockopen("192.168.1.107",
80,
$errno, $errstr, 10);
$params = "smtp=posteddata\r\n";
$params = urlencode($params);
$auth = base64_encode("kaand:kaand123");
if (!$fp) {
return false;
} else {
error_log("4");
$out = "POST /smic/testarea/fsockopen_print_post.php HTTP/1.1\r\n";
$out.= "Host: 192.168.1.107\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "Authorization: Basic ".$auth;
$out.= 'Content-Length: '.strlen($params).'\r\n';
$out.= "Connection: Close\r\n\r\n";
$out .= $params;
fwrite($fp, $out);
fflush($fp);
header('Content-type: text/plain');
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
}
?>
fsockopen_print_post.php:
<?php
session_start();
print_r($_POST);
$raw_data = $GLOBALS['HTTP_RAW_POST_DATA'];
parse_str( $raw_data, $_POST );
print_r($_POST);
?>
Output:
HTTP/1.1 200 OK
Date: Mon, 19 Mar 2012 09:21:06 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.10
Set-Cookie: PHPSESSID=i4lcj5mn1ablqgekb1g24ckbg5; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 20
Connection: close
Content-Type: text/html; charset=UTF-8
Array
(
)
Array
(
)
What's the problem and how do I fix it?

There's a typo in your code:
$out.= 'Content-Length: '.strlen($params).'\r\n';
$out.= "Connection: Close\r\n\r\n";
Should be:
$out .= "Content-Length: ".strlen($params)."\r\n";
$out .= "Connection: close\r\n\r\n";
See how you've used single quotes around \r\n? That means literally send '\r\n' rather than interpret these as a Windows crlf. The double quotes corrects this.

This row
$out.= "Authorization: Basic ".$auth;
should have been
$out.= "Authorization: Basic ".$auth."\r\n";
There was something else which I haven't identified, but this code works (probably just some mixing up of variables when testing around):
<?php
$fp = fsockopen('192.168.1.107', 80);
$vars = array(
'hello' => 'world'
);
$content = http_build_query($vars);
$auth = base64_encode("kaand:kaand123");
$out = "POST /smic/testarea/fsockopen_print_post.php HTTP/1.1\r\n";
$out .= "Host: 192.168.1.107\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Authorization: Basic ".$auth."\r\n";
$out .= "Content-Length: ".strlen($content)."\r\n";
$out .= "Connection: close\r\n\r\n";
$out .= $content;
fwrite($fp,$out);
header("Content-type: text/plain");
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
?>

Related

two HTTP requests in PHP using fsockopen

I have a problem which I couldn't solve almost a week. I searched everything but couldn't find an answer.
I need to do 3 x HTTP requests to the server and then receive answers.
First is GET request to get cookie. Second is POST with cookie and the third is redirect.
$host = "www.xx.com";
$user_agent = "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0\r\n";
$sock = fsockopen("ssl://$host", 443, $errno, $errstr, 30);
if (!$sock) die("$errstr ($errno)\n");
#########################################
# GET
#########################################
$request .= "GET $path HTTP/1.1\r\n";
$request .= "Accept: */*\r\n";
$request .= "Host: $host\r\n";
$request .= $user_agent;
$request .= "Connection: close\r\n";
$request .= "\r\n";
fwrite($sock, $request);
$http_response = stream_get_contents($sock);
list($headers, $body) = explode("\r\n\r\n", $http_response, 2);
// get cookie
preg_match_all('/Set-Cookie:\s*(.*)\b/', $headers, $cookie_res);
foreach($cookie_res[1] as &$val){
$cookie .= "Cookie: ".$val."\r\n";
}
echo "<pre><p>$headers<br />cookie: $cookie</p></pre>";
$data = preg_replace('/^\s+|\n|\r|\s+$/m', '', $data);
#########################################
# POST with cookie
#########################################
$request2 .= "POST $path"."filter/ HTTP/1.1\r\n";
$request2 .= "Host: $host\r\n";
$request2 .= $user_agent;
$request2 .= "Accept: text/html,application/xhtml+xml,application/xml;\r\n";
$request2 .= "Connection: keep-alive\r\n";
$request2 .= $cookie;
$request2 .= "Referer: $path\r\n";
$request2 .= "Content-type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
$request2 .= "Content-length: " . strlen($data) . "\r\n";
$request2 .= "\r\n";
$request2 .= "$data\r\n";
$request2 .= "\r\n";
fwrite($sock, $request2);
$http_response2 = stream_get_contents($sock);
list($headers2, $body2) = explode("\r\n\r\n", $http_response2, 2);
echo "<pre><p>$headers2</p></pre>";
So I get response after the first GET request, but I don't get response after POST request.
If I close connection after first request and reopen it again before second then it works. But I want to do it in one connection. I don't understand why it doesn't work without reconnecting.
Please help! :)
P.S. don't recommend to use CURL because I don't have it installed on this server.

IPN Verification Postback to HTTPS

My PHP code currently uses the following to Postback to PayPal. How do I update this to meet the new payment security standards coming into effect?
$req = 'cmd=_notify-validate';
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.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
if (!$fp)
{
//an error occurred...
}
else
{
fputs ($fp, $header . $req);
while (!feof($fp))
{
$res = fgets ($fp, 1024);
if(strcmp ($res, "VERIFIED") == 0)
{
//all is well...
}
}
}
To enable IPN Verification Postback to HTTPS, change your code as follows,
$fp = fsockopen( 'tls://ipnpb.paypal.com', 443, $errno, $errstr, 30);
PayPal recommends to use ipnpb.paypal.com endpoint in production environment.
Also, you need to change HTTP/1.0 to HTTP/1.1 to comply with PayPal upgrades.
The Header you need to submit,
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen( $req ) . "\r\n";
$header .= "Connection: close\r\n\r\n";
For the sandbox change,
$header .= "Host: www.paypal.com\r\n";
to
$header .= "Host: www.sandbox.paypal.com\r\n";
The new code suggested above has now had a chance to be tested.
This did NOT work:
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
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\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen( 'tls://ipnpb.paypal.com', 443, $errno, $errstr, 30);
This is what works:
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
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.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
What to do about using HTTP/1.0 and posting to www.paypal.com rather than using HTTP/1.1 and posting to tls://ipnpb.paypal.com?
There's a couple of things that need to be done:
You're still on HTTP/1.0; you need to switch to HTTP/1.1.
You need to switch to using TLS.
Most PHP setups nowadays should have cURL installed, so the easiest thing to do would be to use cURL. To do this, the last four lines of your code would change to the following:
$curl = curl_init( 'https://ipnpb.paypal.com/cgi-bin/webscr' );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_POST, true );
curl_setopt( $curl, CURLOPT_POSTFIELDS, $req );
$response = curl_exec( $curl );
if( 'VERIFIED' == trim( $response ) ) {
// IPN verified by PayPal
}
I have a similiar issue with Paypal IPN verification and using this code
// post back to PayPal system to validate
// 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 ('www.paypal.com', 80, $errno, $errstr, 30);
If I understand the solution correctly, the new code should look like
// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: ipnpb.paypal.com\r\n";
$header .= "Connection: close\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen( 'tls://ipnpb.paypal.com', 443, $errno, $errstr, 30);

PHP POST data with fwrite and fsockopen

I'm trying to debug this code and have no access actually to the service so only rely on the answer(which send back "ok" plus the list of the parameters transmitted). I check the POST With Z Rest Eazy and it's ok.
Is there any problem with the manner I'm using to give the parameters. (When I try with Poster extension on FF with the same header and parameters it doesn't work either. So Z REst Ezy Ok, AND my code and Poster NG??
Is someone could help?
$post_data = 'nom=nom&prenom=prenom&age=age';
$socket = fsockopen("xx.yyy.zz.aa", 80, $errno, $errstr, 15);
if(!$socket){
echo ' error: ' . $errno . ' ' . $errstr;
die;
}else{
$http = "POST /MyServices/TestProxy HTTP/1.1\r\n";
$http .= "Host: xx.yyy.zz.aa:80\r\n";
$http .= "User-Agent: " . $_SERVER['HTTP_USER_AGENT'] . "\r\n";
$http .= "Content-Type: multipart/form-data; boundary=---------------------------193612245921106\r\n";
$http .= "Content-length: " . strlen($post_data) . "\r\n";
$http .= "Connection: close\r\n\r\n";
$http .= $post_data . "\r\n\r\n";
fwrite($socket, $http);
$contents = "";
while (!feof($socket)) {
$contents .= fgets($socket, 4096);
}
fclose($socket);
With a breakpoint I can see my request which is:
POST /MyServices/TestProxy HTTP/1.1
Host: xx.yyy.zz.aa:80
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36
Content-Type: multipart/form-data; boundary=---------------------------193612245921106
Content-length: 29
Connection: close
nom=nom&prenom=prenom&age=age

Read http status code by fsockopen

according to #JoyceBabu on this post Get http-statuscode without body using cURL? it should be possible to get the http status code of a URL with fsockopen.
So I took the code from #JoyceBabu which works:
<?php
$fp = fsockopen("www.google.com", 80, $errno, $errstr, 30);
if ($fp) {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.google.com\r\n";
$out .= "Accept-Encoding: gzip, deflate, sdch\r\n";
$out .= "Accept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\n";
$out .= "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36\r\n";
$out .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$tmp = explode(' ', fgets($fp, 13));
echo $tmp[1];
fclose($fp);
}
Then I changed the URL to read to www.raffiniert.biz/aktuell:
<?php
$fp = fsockopen("www.raffiniert.biz", 80, $errno, $errstr, 30);
if ($fp) {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.raffiniert.biz/aktuell\r\n";
$out .= "Accept-Encoding: gzip, deflate, sdch\r\n";
$out .= "Accept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\n";
$out .= "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36\r\n";
$out .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$tmp = explode(' ', fgets($fp, 13));
echo $tmp[1];
fclose($fp);
}
which returns http 400 - this is not correct.
Another example: www.raffiniert.biz/kunden returns 301. This should be 403.
Any ideas what I'm doing wrong?
Thanks
Raphael
This line
$out .= "Host: www.raffiniert.biz/aktuell\r\n";
is the problem.
In an HTTP GET, the Host header is just that, the host (domain name), and the path within the host is provided in the GET line. You should write it like this instead:
$out = "GET /aktuell HTTP/1.1\r\n";
$out .= "Host: www.raffiniert.biz\r\n";
About the updated information:
Another example: www.raffiniert.biz/kunden returns 301. This should be 403.
www.raffiniert.biz/kunden gives a 301, which redirects to www.raffiniert.biz/kunden/ (with a trailing slash), which gives the 403. A browser will do that redirection automatically (i.e. it will send two consecutive requests), and hide the 301.
If you request woth "GET /kunden/ HTTP/1.1\r\n" you'll get that 403 directly.
Below will give you an return of 200
I've updated the 4'th and 5'th line requesting the get of /aktuell
<?php
$fp = fsockopen("www.raffiniert.biz", 80, $errno, $errstr, 30);
if ($fp) {
$out = "GET /aktuell HTTP/1.1\r\n";
$out .= "Host: www.raffiniert.biz\r\n";
$out .= "Accept-Encoding: gzip, deflate, sdch\r\n";
$out .= "Accept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\n";
$out .= "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36\r\n";
$out .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$tmp = explode(' ', fgets($fp, 13));
echo $tmp[1];
fclose($fp);
}
?>

Changing Remote Addr using PHP

<?php
$host = 'www.yourtargeturl.com';
$service_uri = '/detect_referal.php';
$vars ='additional_option1=yes&additional_option2=un';
$header = "Host: $host\r\n";
$header .= "User-Agent: PHP Script\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Referer: http://www.google.com/search?hl=en&q=jigh&btnG=Google+Search \r\n";
$header .= "Content-Length: ".strlen($vars)."\r\n";
$header .= "Connection: close\r\n\r\n";
$fp = fsockopen("".$host,80, $errno, $errstr);
if (!$fp) {
echo "$errstr ($errno)<br/>\n";
echo $fp;
} else {
fputs($fp, "POST $service_uri HTTP/1.1\r\n");
fputs($fp, $header.$vars);
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
This is changing the $_SERVER['HTTP_REFERER']. How can I change $_SERVER['REMOTE_ADDR']. What code should I append in $header?
You can't do that. The IP address is determined at the beginning of the TCP connection, not in the HTTP headers. (It is possible to spoof [though not remotely like that], but then you won't get the response back.)
You can't. The IP address you connect out from isn't some header... it comes from the underlying TCP connection made from your server to the other server.

Categories