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.
Related
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
I'm trying to setup a page where several (private) streams can be listened from.
Unfortunately I'm not able to get it running. I tried Using php to opening live audio stream on android already, but for some reason the browser get stuck when loading the script.
See below script with an example of a working host (see http://icecast.omroep.nl/radio4-bb-mp3)
Could someone please enlighten me.
Tnx in advance!
$host = "icecast.omroep.nl";
$port = 80;
$sub = "/radio4-bb-mp3";
$sock = fsockopen($host,$port, $errno, $errstr, 30);
if (!$sock){
throw new Exception("$errstr ($errno)");
}
header("Content-type: audio/mpeg");
header("Connection: close");
fputs($sock, "GET $sub HTTP/1\r\n");
fputs($sock, "Host: $host \r\n");
fputs($sock, "Accept: */*\r\n");
fputs($sock, "Icy-MetaData:1\r\n");
fputs($sock, "Connection: close\r\n\r\n");
fpassthru($sock);
fclose($sock);
Following comments the solution you are looking is:
<?php
$host = "icecast.omroep.nl";
$sub = "/radio4-bb-mp3";
header("Location: http://{$host}{$sub}");
Now I will explain what was wrong with your code
You have a problem with the headers. You are adding your own headers and the remote headers as part of the body.
icecast.omroep.nl headers
HTTP/1.0 200 OK
Content-Type: audio/mpeg
Date: Sat, 24 Mar 2018 16:01:23 GMT
icy-br:192
ice-audio-info: samplerate=48000;channels=2;bitrate=192
icy-br:192
icy-genre:Classical
icy-metadata:1
icy-name:NPO Radio4
icy-pub:0
icy-url:http://www.radio4.nl
Server: Icecast 2.4.0-kh8
Cache-Control: no-cache, no-store
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Connection: Close
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint:16000
Given your script index.php
<?php
$host = "icecast.omroep.nl";
$port = 80;
$sub = "/radio4-bb-mp3";
$sock = fsockopen($host,$port, $errno, $errstr, 30);
if (!$sock){
throw new Exception("$errstr ($errno)");
}
fputs($sock, "GET $sub HTTP/1\r\n");
fputs($sock, "Host: $host \r\n");
fputs($sock, "Accept: */*\r\n");
fputs($sock, "Icy-MetaData:1\r\n");
fputs($sock, "Connection: close\r\n\r\n");
fpassthru($sock);
fclose($sock);
request.txt
GET /
[Blank line]
Serving your script
$ php -S 0.0.0.0:8000 index.php
Your script response:
$ (nc 127.0.0.1 8000 < request.txt) | head -n 27
HTTP/0.9 200 OK
Date: Sat, 24 Mar 2018 16:01:23 +0000
Connection: close
X-Powered-By: PHP/7.1.14
Content-type: text/html; charset=UTF-8
HTTP/1.0 200 OK
Content-Type: audio/mpeg
Date: Sat, 24 Mar 2018 16:01:23 GMT
icy-br:192
ice-audio-info: samplerate=48000;channels=2;bitrate=192
icy-br:192
icy-genre:Classical
icy-metadata:1
icy-name:NPO Radio4
icy-pub:0
icy-url:http://www.radio4.nl
Server: Icecast 2.4.0-kh8
Cache-Control: no-cache, no-store
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Connection: Close
Expires: Mon, 26 Jul 1997 05:00:00 GMT
icy-metaint:16000
PHP is adding his own headers.
You need to process the headers received from http://icecast.omroep.nl/radio4-bb-mp3 and return them using the method header() and then you can do the fpassthru().
HTTP separate the headers from the body with a new line: https://www.rfc-editor.org/rfc/rfc2616#section-6
[header]
CRLF
[body]
So it should be easy to parse line by line and calling header() until CRLF (empty line) is found and then trigger the fpassthru().
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!
I am trying to communicate to an API using cURL. One of the methods require that I pass the value of the ININ-ICWS-CSRF-Token header (ie. WAhtYWxoYXlla1dBY2NvUkRJWCQxZmUxZWFhZS0xZTE0LTQyNGYtYjdhZS0zNmZjN2MxYWJmODBYCjEwLjAuNC4xNjA=) and the Set-Cookie (ie. icws_904586002=bf7c7783-6766-4c4f-862b-48f25a9a3741) so I need to extract them so I can pass them later in my code.
Here is what I did to extract the header and the body from the cURL/API respond:
$respond = curl_exec($ch);
//throw cURL exception
if($respond === false){
$errorNo = curl_errno($ch);
$errorMessage = curl_error($ch);
throw new ApiException($errorMessage, $errorNo);
}
list($header, $body) = explode("\r\n\r\n", $respond, 2);
echo '<pre>';
print_r($header);
echo '</pre>';
This is the content of the $header value:
HTTP/1.1 201 Created
ININ-ICWS-CSRF-Token: WAhtYWxoYXlla1dBY2NvUkRJWCQxZmUxZWFhZS0xZTE0LTQyNGYtYjdhZS0zNmZjN2MxYWJmODBYCjEwLjAuNC4xNjA=
ININ-ICWS-Session-ID: 904586002
Set-Cookie: icws_904586002=bf7c7783-6766-4c4f-862b-48f25a9a3741; Path=/icws/904586002
Location: /icws/904586002/connection
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Content-Type: application/vnd.inin.icws+JSON; charset=utf-8
Date: Wed, 06 May 2015 17:13:44 GMT
Server: HttpPluginHost
Content-Length: 237
I would like to get in return results like this
the value of "ININ-ICWS-CSRF-Token" is "WAhtYWxoYXlla1dBY2NvUkRJWCQxZmUxZWFhZS0xZTE0LTQyNGYtYjdhZS0zNmZjN2MxYWJmODBYCjEwLjAuNC4xNjA="
the value of the "cookie" is "ININ-ICWS-CSRF-Token: WAhtYWxoYXlla1dBY2NvUkRJWCQxZmUxZWFhZS0xZTE0LTQyNGYtYjdhZS0zNmZjN2MxYWJmODBYCjEwLjAuNC4xNjA="
You can use the http_parse_headers function to parse the headers.
$hdr_array = http_parse_headers($header);
foreach ($hdr_array as $name => $value) {
echo "The value of '$name' is '$value'<br>";
}
If you don't have http_parse_headers, you can use the code in Pedro Lobito's answer.
<?php
$myHeader = <<< LOL
HTTP/1.1 201 Created
ININ-ICWS-CSRF-Token: WAhtYWxoYXlla1dBY2NvUkRJWCQxZmUxZWFhZS0xZTE0LTQyNGYtYjdhZS0zNmZjN2MxYWJmODBYCjEwLjAuNC4xNjA=
ININ-ICWS-Session-ID: 904586002
Set-Cookie: icws_904586002=bf7c7783-6766-4c4f-862b-48f25a9a3741; Path=/icws/904586002
Location: /icws/904586002/connection
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Content-Type: application/vnd.inin.icws+JSON; charset=utf-8
Date: Wed, 06 May 2015 17:13:44 GMT
Server: HttpPluginHost
Content-Length: 237
LOL;
preg_match_all('/(.*?Token): (.*?)\s+/', $myHeader, $matches, PREG_PATTERN_ORDER);
$tokenName = $matches[1][0];
$token = $matches[2][0];
echo <<< LOL
the value of "$tokenName" is "$token"
the value of the "cookie" is "$tokenName: $token"
LOL;
?>
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