How to get only the result of php socket request? - php

I try to get result without HTTP headers from socket request, but the script return the whole HTTP header like below :
$api_pause = parse_url('http://server/api.php');
$requestArray_pause = array('user' => 'someuser', 'pass' => 'somepasse', 'source' => 'PAUSE','function' => 'field_info','field_name' => 'status','user_id'=> $user_id );
$sock_pause = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock_pause, $api_pause['host'], ((isset($api_pause['port'])) ? $api_pause['port'] : 80));
if (!$sock_pause) {
throw new Exception('Connexion echouee!');
}
$request_pause = '';
if (!empty($requestArray_pause)) {
foreach ($requestArray_pause as $k_p => $v_p) {
if (is_array($v_p)) {
foreach($v_p as $v2_p) {
$request_pause .= urlencode($v_p).'[]='.urlencode($v2_p).'&';
}
}
else {
$request_pause .= urlencode($k_p).'='.urlencode($v_p).'&';
}
}
$request_pause = substr($request_pause,0,-1);
}
$data_pause = "POST ".$api_pause['path'].((!empty($api_pause['query'])) ? '?'.$api_pause['query'] : '')." HTTP/1.0\r\n"
."Host: ".$api_pause['host']."\r\n"
."Content-type: application/x-www-form-urlencoded\r\n"
."User-Agent: PHP\r\n"
."Content-length: ".strlen($request_pause)."\r\n"
."Connection: close\r\n\r\n"
.$request_pause."\r\n\r\n";
socket_send($sock_pause, $data_pause, strlen($data_pause), 0);
$result_pause = '';
do {
$piece_pause = socket_read($sock_pause, 1024);
$result_pause .= $piece_pause;
}
while($piece_pause != '');
socket_close($sock_pause);
echo $result_pause;
The result of the code is :
HTTP/1.1 200 OK
Date: Wed, 16 Sep 2020 10:51:35 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 1
Connection: close
Content-Type: text/html; charset=utf-8
A
In my case i wanna get just the last value "A" in this example without headers informations.

Socket will give you any data which is received, whatever protocol it is.
Thus you're obligated to handle all the HTTP headers yourself.
The HTTP headers are separated from the body by two line feeds (an empty line). You can just cut all the data before two empty lines:
$body = preg_replace('/^.*?\r?\n\r?\n/s', '', $result_pause);
If you want to communicate using HTTP protocol, consider using for example cURL instead of plain sockets

Related

calDAV "PROPFIND" call "401 Unauthorized" response from calendar.yahoo.com server

I am trying to send yahoo calendars(caldav) a request to get "current-user-principal" But In response I am getting "401 Unauthorized" error. Before this request I am making another request to get "OPTIONS" which is giving "200 OK" response.
Request call is
PROPFIND / HTTP/1.1
Authorization: Basic XXXXXXXXXXXXXXXX=
Host: calendar.yahoo.com:443
Depth: 0
Prefer: return-minimal
Content-type: application/xml; charset=utf-8
Content-Length: 85
User-Agent: DAViCalClient
Connection: close
Request Response is:
string(613) "HTTP/1.1 401 Unauthorized
WSHost: tardis012.cal.bf1.yahoo.com
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 18-Feb-2021 03:44:03 GMT
WWW-Authenticate: Basic realm="YahooCalendar"
WWW-Authenticate: OAuth realm="YahooCalendar"
Content-Length: 0
Date: Fri, 19 Feb 2021 03:44:03 GMT
Age: 1
Server: ATS
Referrer-Policy: no-referrer-when-downgrade
Connection: close
Strict-Transport-Security: max-age=15552000
Expect-CT: max-age=31536000, report-uri="http://csp.yahoo.com/beacon/csp?src=yahoocom-expect-ct-report-only"
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
I am using a client library which has a function to make server request
function DoRequest( $relative_url = "" ) {
if(!defined("_FSOCK_TIMEOUT")){ define("_FSOCK_TIMEOUT", 10); }
$headers = array();
$headers[] = $this->requestMethod." ". $this->base_url . $relative_url . " HTTP/1.1";
$headers[] = "Authorization: Basic ".base64_encode($this->user .":". $this->pass );
$headers[] = "Host: ".$this->server .":".$this->port;
foreach( $this->headers as $ii => $head ) {
$headers[] = $head;
}
$headers[] = "Content-Length: " . strlen($this->body);
$headers[] = "User-Agent: " . $this->user_agent;
$headers[] = 'Connection: close';
$this->httpRequest = join("\r\n",$headers);
$this->xmlRequest = $this->body;
$fip = fsockopen( $this->protocol . '://' . $this->server, $this->port, $errno, $errstr, _FSOCK_TIMEOUT); //error handling?
if ( !(get_resource_type($fip) == 'stream') ) return false;
if ( !fwrite($fip, $this->httpRequest."\r\n\r\n".$this->body) ) { fclose($fip); return false; }
$rsp = "";
while( !feof($fip) ) { $rsp .= fgets($fip,8192); }
fclose($fip);
$this->headers = array(); // reset the headers array for our next request
$this->ParseResponse($rsp);
return $rsp;
}
Here is class init.
$cal = new CalDAVClient("https://calendar.yahoo.com/", "piyush138", "XXXXXXXXXXX", "calendar" );
Link to library
The following request gives "200 ok" response which runs before above request:
Request to server
OPTIONS / HTTP/1.1
Authorization: Basic cGl5dXNoMTM4OkQxZzF0YWxoZWw=
Host: calendar.yahoo.com:443
Content-Length: 0
User-Agent: DAViCalClient
Connection: close
Response from server
string(668) "HTTP/1.1 200 OK
WSHost: tardis030.cal.bf1.yahoo.com
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Thu, 18-Feb-2021 03:44:01 GMT
DAV: 1, 3, calendar-access
MS-Author-Via: DAV
Allow: HEAD, MKCOL, POST, PROPFIND, ACL, COPY, REPORT, OPTIONS, PUT, DELETE, MKCALENDAR, MOVE, GET, PROPPATCH
Content-Length: 0
Date: Fri, 19 Feb 2021 03:44:02 GMT
Age: 3
Server: ATS
Referrer-Policy: no-referrer-when-downgrade
Connection: close
Strict-Transport-Security: max-age=15552000
Expect-CT: max-age=31536000, report-uri="http://csp.yahoo.com/beacon/csp?src=yahoocom-expect-ct-report-only"
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
I also tried simplifying my password but that didn't work either
I have found the Solution.
I was using the conventional password in server call but in actual I had to use "APP Password" which you can create from
your yahoo account Under "Account security" tab.

Why does tlstest.paypal.com work from browser but not from my PHP code (useful for Paypal IPN)?

After 2018 June 30th, Paypal won't accept non-TLS 1.2 + HTTP 1.1 requests anymore.
They created the URL https://tlstest.paypal.com/ to test if connections are OK. If we open this URL in a browser, we get a successful:
PayPal_Connection_OK
Quesiton: why does it fail when connecting from PHP with the following code? (I get no response at all, the browser is still in waiting "state" like this, so it doesn't even arrive at echo $errno; echo $errstr;)
<?php
$req = ''; // usually I use $req = 'cmd=_notify-validate'; for IPN
$header .= "POST / HTTP/1.1\r\n";
$header .= "Host: tlstest.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen('tls://tlstest.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
echo $errno;
echo $errstr;
} else {
fputs($fp, $header);
while (!feof($fp))
{
$res = fgets($fp, 1024);
echo $res;
}
fclose($fp);
}
?>
Note:
this is not a duplicate of Paypal IPN HTTP/1.1 - doesn't provide any response at all, it is an empty string, the latter is outdated.
I have PHP 5.6.33-0+deb8u1 (cli) (built: Jan 5 2018 15:46:26) and openssl version text: OpenSSL 1.0.1t 3 May 2016
It works on my side by changing tls:// to ssl:// which makes absolutely no sense to me, but this is also why using fsockopen is a too low level library to just do HTTP exchanges with it (you should use a proper HTTP client library) and at the same time not configurable enough regarding TLS stuff.
With
$fp = fsockopen('tls://tlstest.paypal.com', 443, $errno, $errstr, 30);
I get :
HTTP/1.1 426 Unknown
Server: AkamaiGHost
Mime-Version: 1.0
Content-Type: text/html
Content-Length: 267
Expires: Fri, 22 Jun 2018 19:49:46 GMT
Date: Fri, 22 Jun 2018 19:49:46 GMT
Connection: keep-alive
Upgrade: TLS/1.2
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>
You don't have permission to access "http://tlstest.paypal.com/" on this server.<P>
Reference #18.8024a17.1529696986.1fc51318
</BODY>
</HTML>
but with $fp = fsockopen('ssl://tlstest.paypal.com', 443, $errno, $errstr, 30);
I get:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Date: Fri, 22 Jun 2018 20:05:35 GMT
Connection: keep-alive
And then it hangs, probably because it is a keep-alive connection and the buffer is smaller than 1024 so that you do not get the following body content.
Which is probably "PayPal_Connection_OK", as it exactly matches the length displayed in Content-Length.
This again shows that you should use an HTTP client library instead of trying to (badly) reimplement HTTP on top of fsockopen.
For completeness, here is a working code (full credit to PatrickMevzek's answer):
<?php
$req = '';
$header = "POST / HTTP/1.1\r\n";
$header .= "Host: tlstest.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen('ssl://tlstest.paypal.com', 443, $errno, $errstr, 3);
if (!$fp) {
echo $errno;
echo $errstr;
} else {
fputs($fp, $header);
while (!feof($fp))
{
$res = fgets($fp, 21); // 21 because length of "PayPal_Connection_OK"
echo $res;
}
fclose($fp);
}
?>
Here is the answer from server:
# php -f test.php
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Date: Fri, 22 Jun 2018 20:19:56 GMT
Connection: keep-alive
PayPal_Connection_OK

Sending HTTP/2 request using PHP

My problem statement is similar to the one mentioned here , except that the request type I need server to respond to is HTTP/2.
I am opening a telnet connection through a PHP script and sending a request:
<?php
$fp = fsockopen("10.20.0.120", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET /mng/1000.txt HTTP/2 \r\n";
$out .= "Host: 10.20.0.120\r\n";
$out .= "Connection: Close\r\n";
fwrite($fp, $out);
$out = "\r\n";
$out .= "\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
I am aware that in case of HTTP/2 the header frame must be in binary format, hence I need to know if I could do it using PHP.
I tried with PHPs pack method, but it didn't work. When I execute the above script, this is the output it gives:
Client(root)#php above_file.php
HTTP/1.1 400 Bad Request
Content-Length: 0
...and when the request is of type HTTP/1.1 (and executed on another setup replacing HTTP/2 with HTTP/1.1), the output I receive is as expected:
Client(root)#php above_file.php
HTTP/1.1 200 OK
Date: Wed, 27 Sep 2017 11:31:57 GMT
Server: Apache/2.2.22 (Fedora)
Last-Modified: Wed, 20 Feb 2013 21:27:15 GMT
ETag: "a4f5b-3e8-4d62e9f40f9be"
Accept-Ranges: bytes
Content-Length: 12
Connection: close
Content-Type: text/plain; charset=UTF-8
Hello world!

Server don't accept the parameters from my raw POST HTTP Protocol call

This is the raw POST call that im sending to the server (I'm using Postman REST Client):
POST / HTTP/1.1
Host: ******
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
key=value
On the server side I want to read they key,value inside $_POST from my raw POST call, PHP source looks like this:
<?php
header('Access-Control-Allow-Origin: *');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header('Pragma: no-cache');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Type: application/x-www-form-urlencoded');
print_r($_POST);
echo file_get_contents('php://input');
?>
This is the output that I get back from the server:
Array
(
)
POST / HTTP/1.1
Host: ******
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
key=value
Update:
Also did same call to posttestserver.com with same result
Why is the $_POST array empty, what am I doing wrong?
Just a guess, but I'd say the client your using isn't sending the data properly. I'm thinking it's not using the proper CRLF in the request and/or it's cause it's not sending Connection: close. It could also be a misconfiguration in your web server.
I tested it out by myself using the following PHP script:
<?php
$host = 'www.example.com';
if ($fp = fsockopen('ssl://'. $host, 443, $errno, $errstr, 30)) {
$data = 'key=value';
$msg = "POST /test.php HTTP/1.1\r\n";
$msg .= "Host: ".$host."\r\n";
$msg .= "Content-Type: application/x-www-form-urlencoded\r\n";
$msg .= "Connection: close\r\n";
$msg .= "Content-Length: ".strlen($data)."\r\n\r\n";
$msg .= $data."\r\n\r\n";
$response = '';
if ( fwrite($fp, $msg) ) {
echo 'Request:'.PHP_EOL;
echo $msg;
while ( !feof($fp) ) {
$response .= fgets($fp, 4096);
}
echo 'Response:'.PHP_EOL;
echo $response;
}
fclose($fp);
}
And I got the expected response from the exact same PHP script you posted:
Request:
POST /test.php HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Connection: close
Content-Length: 9
key=value
Response:
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 05 Mar 2015 05:06:53 GMT
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/5.6.6
Access-Control-Allow-Origin: *
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Last-Modified: Thu, 05 Mar 2015 05:06:53 GMT
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate
26
Array
(
[key] => value
)
key=value
0

Getting page with fsockopen

I'm trying to access http://www.example.com:4380/apid/request?method=getXMLTable&name=1&ui=UI&id=12345. It should give back output as XML.
This is the code:
<?
$host = "www.example.com";
$path = "/apid/request?method=getXMLTable&name=1&ui=UI&id=12345";
$port = 4380;
$fp = fsockopen($host, $port, $errno, $errstr, 30);
$buffer ="";
if (!$fp) {
echo "ERR!!<br>";
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET ".$path." HTTP/1.1\r\n";
$out .= "Host: ".$host."\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
$buffer .= fgets($fp, 1024);
}
fclose($fp);
}
?>
Anyhow I'm getting not the XML output, but this response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Last-Modified: Wed, 02 Apr 2014 16:16:43 GMT
Cache-Control: no-store
Cache-Control: no-cache
Cache-Control: must-revalidate
Cache-Control: pre-check=0
Cache-Control: post-check=0
Cache-Control: max-age=0
Pragma: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml
Transfer-Encoding: chunked
Vary: Accept-Encoding
Date: Wed, 02 Apr 2014 16:16:43 GMT
Connection: close 2000 0
I can access pages like 'www.example.com/path/to/file' with the presented code without any problems. I guess I make any mistake with port(not standard http ) or request. Every clue would be very welcome.
EDIT:
I can't use any http module! Socket is a must in this case!
I have tried with the code below, but I get nothing in $body:
list($header, $body) = explode("\n\n", $buffer, 2);
echo http_chunked_decode($body);
You are getting a Transfer-Encoding: chunked response. You need to use http_chunked_decode to decode it (you can find a PHP version here, if you don't have pecl_http).
list($header, $body) = explode("\n\n", $buffer, 2);
echo http_chunked_decode($body);
But as the other commenter said, you should really use file_get_contents if you have allow_url_fopen enabled or curl otherwise. They handle the chunked encoding for you.

Categories