HTTP Status 404 – Bad Request fsockopen php websocket client [closed] - php

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 days ago.
Improve this question
I am unable to connect with web socket though PHP client:
I am facing this issue:
HTTP/1.1 404 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Disposition: inline;filename=f.txt Content-Type: application/json Transfer-Encoding: chunked Date: Fri, 17 Feb 2023 11:54:45 GMT 67 {"timestamp":"2023-02-17T11:54:45.060+00:00","status":404,"error":"Not Found","path":"/app/notify.msg"} 0 HTTP/1.1 400 Content-Type: text/html;charset=utf-8 Content-Language: en Content-Length: 435 Date: Fri, 17 Feb 2023 11:54:45 GMT Connection: close
here is my complete code, wan to use stream type ws
` $host = '145.34.6.25';
$port = 8783;
$path = "/app/notify.msg"; // Request path
$timeout = 30;
// Timeout in seconds
// $WebSocketClient->connect($host,$port,'/ws');
$message = json_encode([
"company_id" => 23,
"payload" => [
"audience" => "user/company",
"message" => "Hello",
"userIs" => [1,2,3]
]
]);
$key = "753d345ec6b-b60343450-34540c0-a9f9-3bc324545cdc9906f";
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
dump($fp);
// Prepare the request header
$request = "GET " . $path . " HTTP/1.1\r\n";
$request .= "Host: " . $host . "\r\n";
$request .= "Upgrade: websocket\r\n";
$request .= "Connection: Upgrade\r\n";
$request .= "Sec-WebSocket-Key: " . $key . "\r\n";
$request .= "Sec-WebSocket-Version: 13\r\n\r\n";
$request.= "Authorization: token " . $key . "\r\n\r\n";
//$request.= $message;
// Send the request
fwrite($fp, $request);
// Get the response
$response = "";
while (!feof($fp)) {
$response .= fgets($fp, 1024);
}
// Close the connection
// fclose($fp);
// Output the response
echo $response;`
Here is stream type:
^ stream resource #588 ▼
timed_out: false
blocked: true
eof: false
stream_type: "tcp_socket/ssl"
mode: "r+"
unread_bytes: 0
seekable: false
options: []
}

Related

How to get only the result of php socket request?

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

Problem with WSS handshake (PHP WebSocket Server)

I developed a WebSocket server using PHP and it worked fine with ws://, but in production environment it uses https://, then I must use wss://.
Should I use certificate to start the socket or something like that? I can't parse the headers to complete the handshake.
How can I perform handshake behind a https server?
This is a AWS EC2 machine with Amazon Certificate.
I have tried import .pem file to socket initialization, run ws:// behind my https:// environment, and nothing worked :(
Socket initialization:
$socket = stream_socket_server(
"tcp://0.0.0.0:" . env("APP_WSS_PORTA"),
$errno,
$errstr
);
I have tried also:
use Aws\Acm\AcmClient;
$cert = (new AcmClient(include config_path('aws.php')))->GetCertificate([
"CertificateArn" => "arn:aws:acm:sa-east-1:EDITED_TO_STACKOVERFLOW"
])["CertificateChain"];
$cert_path = "cert.pem";
file_put_contents(base_path($cert_path), $cert);
$context = stream_context_create(
["ssl" => ["local_cert"=> $cert_path]]
);
$socket = stream_socket_server(
"tcp://0.0.0.0:" . env("APP_WSS_PORTA"),
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$context
);
My handshake function:
function wsHandshake($data)
{
echo "> Handshake " . remoteIp() . PHP_EOL;
$lines = preg_split("/\r\n/", $data);
$headers = array();
foreach ($lines as $line) {
$line = chop($line);
if (preg_match('/\A(\S+): (.*)\z/', $line, $matches)) {
$headers[$matches[1]] = $matches[2];
}
}
var_dump($data); // to debug it :)
if (!isset($headers['Sec-WebSocket-Version']) || $headers['Sec-WebSocket-Version'] < 6) {
echo '> Versao do WebSocket nao suportada' . PHP_EOL;
return false;
}
$sec_accept = base64_encode(pack('H*', sha1($headers['Sec-WebSocket-Key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$response = "HTTP/1.1 101 Switching Protocols\r\n";
$response .= "Upgrade: websocket\r\n";
$response .= "Connection: Upgrade\r\n";
$response .= "Sec-WebSocket-Accept: " . $sec_accept . "\r\n";
$response .= "\r\n";
return $response;
}
var_dump with ws://
string(448) "GET / HTTP/1.1
Host: 127.0.0.1:3131
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://localhost
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: PuIYHJZ4x8IyXajFf4WAsw==
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
"
var_dump with wss://
string(517) "\000\000��}hh�հ�h����`�ݘ����O��GQ�E� S�8�#��,��=��c���C8�ǯ�G!6{<\000$�+�/̨̩�,�0�
� ��\0003\0009\000/\0005\000
\000�\000\000\000�\000\000\000
\000\000
\000\000\000\000\000\000
\000\000\000#\000\000\000\000\000
hhttp/1.1\000\000\000\000\000\000\0003\000k\000i\000\000 ��"�c��GLGX�Ƶ��:�"ŵ�)բ
E��)\000\000Al�d��#Q{��t��q>��eb���u�+�d��M�!2�-��tI����z�y�\ĉ�\000\\000-\000\000\000#\000\0"...

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!

YesMail v2 API: 400 Error with cURL request with PHP

I am trying to GET targeting from an MMID but am returning the following error. I know my credentials are correct and have combed over the documentation several times. "appTesting" in the response below is the name of my App in YesMail
INFO: HTTP Response Code was: 400 INFO: Response Follows... HTTP/1.1 400 Bad Request Access-Control-Allow-Origin: * Api-User: appTesting Content-Type: application/json Date: Wed, 29 Jul 2015 21:38:54 GMT Tracking-Id: f257bd75-47bb-40e7-a12c-5a45a042cbac X-Content-Type-Options: nosniff transfer-encoding: chunked Connection: keep-alive {"status":400,"message":"Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [appTesting]"}
I kind of stumped. What am I doing wrong?
<?php
$mmid = 'mmid';
$api_user = "appTesting";
$api_key = "api key";
$ym_api_url = 'https://api.yesmail.com/v2/masters/';
$curl_hdl = curl_init();
$curl_options = array(
CURLOPT_VERBOSE => 1,
CURLOPT_HEADER => TRUE,
CURLOPT_HTTPHEADER => array("Api-User: $api_user", "Api-Key: $api_key", "Accept: application/json",),
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $ym_api_url.$mmid.'/target',
);
curl_setopt_array($curl_hdl, $curl_options);
$response = curl_exec($curl_hdl);
$http_response_code = curl_getinfo($curl_hdl, CURLINFO_HTTP_CODE);
curl_close($curl_hdl);
echo PHP_EOL . "INFO: HTTP Response Code was: " . $http_response_code . PHP_EOL;
if ( $response === false )
{
echo PHP_EOL . "ERROR: curl_exec() has failed." . PHP_EOL;
}
else
{
echo PHP_EOL . "INFO: Response Follows..." . PHP_EOL;
echo PHP_EOL . $response;
}
echo "<br/><br/>API USER: ".$api_user."<br/><br/>API KEY: ".$api_key;
?>

Categories