cURL without cURL- problem - php

I wanted to copy files from a remote server, but it seems that the remote host is using session, and needs cookies.
well I used this method
after defining variables...
$url="http://example.com/stamp/stamp.jsp?tp=&arnumber=5255176&isnumber=5255174";
$nn = "\r\n";
$cookies="";
$request = GET . " " . str_replace ( " ", "%20", $url ) . " HTTP/1.1" . $nn . "Host: " . $host . $nn . "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14" . $nn . "Accept: */*" . $nn . "Accept-Language: en-us;q=0.7,en;q=0.3" . $nn . "Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7" . $nn . "Pragma: no-cache" . $nn . "Cache-Control: no-chache" . $nn . $proxyauthorization . $referer . $cookies . "Connection: Close";
$fp= socksopen($Proxy,$port, $errno, $errstr, 15 );
socket_set_timeout ( $fp, 120 );
fputs ( $fp, $request );
fflush ( $fp );
//read header
$i = 1;
do {
$header.= #fgets ( $fp, 128 );
$i++;
} while ( strpos ( $header, $nn . $nn ) === false );
echo $header;
fclose ($fp);
now I have the header with cookies that the url said :
HTTP/1.1 302 Moved Temporarily Content-length: 0 Content-type: text/html Server: Sun-ONE-Web-Server/6.1 Date: Mon, 28 Dec 2009 13:40:53 GMT Set-cookie: ERIGHTS=5YAaxxmNsMuTK87E1TCAohwDRuyqBaCgM-oehmg24bkzHplCtmgn7zMA==;path=/;domain=.example.org Set-cookie: WLSESSION=1528980108.20480.0000; expires=Tue, 29-Dec-2009 13:40:52 GMT; path=/ Location: http://example.com/stamp/stamp.jsp?tp=&arnumber=5255176&isnumber=5255174"&tag=1 Via: 1.1 proxy-server1 Proxy-agent: Sun-Java-System-Web-Proxy-Server/4.
then I did some sting code and built this in the code:
$cookies="cookie: ERIGHTS=5YAaxxmNsMuTK87E1TCAohwDRuyqBaCgM-oehmg24bkzHplCtmgn7zMA==,WLSESSION=1528980108.20480.0000";
re-requesting the url with same method mentioned above
and again i have got same header with another cookies
It seams that the remote website is treating me as a first-time visitor each time and sets new cookies gain
there is one thing, the file i am trying to copy is a .pdf file exactly
i checked that by my browser, the results:
say the URL is:
http://example.com/stamp/stamp.jsp?tp=&arnumber=5344171&isnumber=5344169
I checked the source code of the URL, it contains a redirection to another page that either is a javascript with iframe
source of the page (from my browser)
<frameset rows="65,35%">
<frame src="http://example.com/stamp/banner.jsp" frameborder="0" framespacing="0" framepadding="0" scrolling="no" />
<frame src="http://example.com/stampPDF/getPDF.jsp?tp=&arnumber=5255176&isnumber=5255174" frameborder="0" />
as you see when I click the URL, it redirects me to URL2
the URL2 is this:http://example.com/stampPDF/getPDF.jsp?tp=&arnumber=5255176&isnumber=5255174
the URL2 contains .pdf file I can easily copy(download).
but when i use my code mentioned above, $url="http://example.com/stamp/stamp.jsp?tp=&arnumber=5255176&isnumber=5255174"
it needs cookies to set with my request, when receive cookies and set and send cookies with my request it again replies a new cookie !!
what is wrong guys?

May be you should check your cookie-composing logic. Name-value pairs in a cookie header are supposed to be separated with ';' not with ',': http://msdn.microsoft.com/en-us/library/aa920098.aspx#wce50concookieheadersanchor2.
And (I'm sure you do this) I would double-check all the request headers with Fiddler, HttpAnalyzer or another similar tool.

Are you passing over http://example.com/stampPDF/getPDF.jsp?tp=&arnumber=5255176&isnumber=5255174 as the referer? The site may be checking that.

Related

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"...

Parse socket data on a PHP socket_listener

I was able to open a PHP TCP listener socket, but I don't know how to parse the buffer. The client that connects to my socket send a text/html with an additional boundary data with a xml file and an image file.
How can I parse the response to get the XML file on one side and the Image on the other side?
server = socket_create_listen(8086);
socket_getsockname($server, $addr, $port);
if (!$server) {
$message = 'Start TCP socket: Ko. Could not create socket.';
$this->logger->info($message);
die($message);
} else {
$message = 'Start TCP socket: Ok. TCP socket opened on: ' . $addr . ':' . $port . '.';
$this->logger->info($message);
while ($c = socket_accept($server)) {
socket_getpeername($c, $raddr, $rport);
$this->logger->info("Received Connection from $raddr:$rport\n");
$data = '';
while ($bytes = socket_recv($c, $r_data, 1024, MSG_WAITALL)) {
$data .= $r_data;
}
//Edited: Explode with double line and got data
$parsedData = explode("\r\n\r\n", $data);
$xml = new \SimpleXMLElement($parsedData[2]);
print_r($xml);
else {
echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($c)) . "\n";
}
socket_close($c);
}
}
fclose($server);
This is the output I received:
Received Connection from :59048
Read 3096 bytes from socket_recv(). Closing socket...POST /test HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
Content-Type: multipart/form-data;boundary=-------------------------7e13971310878
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: 0.0.0.0:7200
Content-Length: 516032
Connection: Keep-Alive
Cache-Control: no-cache
---------------------------7e13971310878
Content-Disposition: form-data; name="file.xml";filename="file.xml";
Content-Type: text/xml
Content-Length: 2273
<EventNotificationAlert version="2.0" xmlns="http://www.isapi.org/ver20/XMLSchema">
<ipAddress></ipAddress>
<ipv6Address></ipv6Address>
<portNo></portNo>
<!--REST OF XML DATA-->
</EventNotificationAlert>
---------------------------7e13971310878
Content-Disposition: form-data;name="image.jpg";filename="image.jpg";
Content-Type: image/pjpeg
Content-Length: 7164
����JFIF���
!"$"^C
EDITED: I was able to got the XML data by using "explode" function, but I don't know how to get the 2 images as image files. Any suggestion?
Any help would be really appreciated!
Thank you!
I write my final solution here:
1 - Explode the data in a string to an array(using \r\n\r\n):
$parsedData = explode("\r\n\r\n", $data);
2 - XML is actually on position 2 (position 0 and 1 contain POST HTTP Header and boundary start section):
$xml = new \SimpleXMLElement($parsedData[2]);
Image is on position 4 (array position 3 contains headers such as Content-Disposition that must be skipped):
The code to save the data as an image is:
//Generate GD image from raw string.
if (!$source = #imagecreatefromstring($parsedData[4])){
$message = 'Save Image: Ko. Img path: "' . $imgFullPath . '". Error details: ' . error_get_last()['message'];
$this->logger->error($message);
}else {
//Save GD image on disk
imagejpeg($source, $imgFullPath);
//Clean resources.
imagedestroy($source);
$message = 'Save Image: Ok. Image saved successfully on path: "' . $imgFullPath . '"...';
$this->logger->info($message);
$this->io->writeln($message);

Create POST (protocol) for Wordpress from reading debugging tool Chrome

I have a button on my page WordPress to check or uncheck the post of WordPress as favorite. It is my intention to make a POST call from php to do this. Later I call this php from a mobile app.
My App Mobile ==> (get_favorito.php) POST (idUser, idPost, Status) ==> Favorite ON / OFF
I currently use WP 4.4.2 and Plugin for WordPress FAVORITES (https://github.com/kylephillips/favorites)
I launch the POST used the tool for developers of Chrome.
image important debugging
And I can see that the call is made:
http://web.domine.com/wp-admin/admin-ajax.php?action=simplefavorites_favorite&nonce=XXXXXXcd14&postid=273&siteid=1&status=inactive
or
http://web.domine.com/wp-admin/admin-ajax.php?action=simplefavorites_favorite&nonce=XXXXXXcd14&postid=273&siteid=1&status=active
My question comes with the part of Header and Cookie. How did you get this information?
I'm trying this, but it does not work.
This is the php I am writing.
<?php
$ruta = 'http://' . $_SERVER['HTTP_HOST'];
$json = file_get_contents($ruta . '/wp-admin/admin-ajax.php?action=simplefavorites_nonce');
$arr = json_decode($json, true);
$nonce = $arr['nonce'];
$opts = array(
'http'=>array(
'method'=>'POST',
'header'=> 'POST /wp-admin/admin-ajax.php HTTP/1.1\r\n' .
'Host: web.domine.com\r\n' .
'Connection: keep-alive\r\n' .
'Content-Length: 84\r\n' .
'Accept: */*\r\n' .
'Origin: http://web.domine.com\r\n' .
'X-Requested-With: XMLHttpRequest\r\n' .
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36\r\n' .
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n' .
'Referer: http://web.domine.com/hola-mundo-2/\r\n' .
'Accept-Encoding: gzip, deflate\r\n' .
'Accept-Language: es-ES,es;q=0.8\r\n' .
'Cookie: wordpress_dddd3333f97127bf3816f4455971ce5aa=peteradmin%7C1457085836%7CxWJrk7EQVEYRpZY9Jzev4fH6jx3cq97wx6LPaMd9C4v%7Cd232ca14edca535e653dd37607b754d78926410e317d34315cbcb5533cda08c8; PHPSESSID=8eda0049e17a67becb1c8fddd18c6c51;
wordpress_logged_in_dddd3333f97127bf3816f4455971ce5aa=peteradmin%7C1457085836%7CxWJrk7EQVEYRpZY9Jzev4fH6jx3cq97wx6LPaMd9C4v%7C63a7b53cfbb2c5a3b86e59c65e9977077e352ad8fe00228dee9b04a7a1e36ad9;
wp-settings-1=libraryContent%3Dbrowse%26editor%3Dtinymce%26mfold%3Do;
wp-settings-time-1=1456991866;
wordpress_test_cookie=WP+Cookie+check;
simplefavorites=%5B%7B%22site_id%22%3A1%2C%22posts%22%3A%7B%221%22%3A194%2C%222%22%3A208%2C%223%22%3A273%7D%7D%5D'
)
);
$context = stream_context_create($opts);
//
//
$param = "action=simplefavorites_favorite&nonce='.$nonce.'&postid=273&siteid=1&status=active";
$json = file_get_contents($ruta . '/wp-admin/admin-ajax.php?'.$param.'', false, $context);
echo $json;
?>
(I put spaces so that cookies are correctly displayed)
And now I get nonce with:
http://web.domine.com/wp-admin/admin-ajax.php?action=simplefavorites_nonce
Hello I was redirected here from nubelo in order to answer.
The headers are set automatically by the browser and the cookies are set by different pages of wordpress like the wp-login.php page.
The simplefavorites cookie is a cookie that stores an anonymoys user favorite posts array, and it is returned in the response headers of the wp-admin/admin-ajax.php?action=simplefavorites_array page. For logged in users the favorites information is returned in json format in the response of that same page.
I made a php script to toggle the status it just sends the cookies to the respective endpoints and you would only need to store the cookies in your mobile app and send them with your request.
https://gist.github.com/chaps/eec3769560c7d8debe59

Remote file access from PHP server side gives 301 instead of file, what to do?

EDIT: the answer is in the comments to the marked answer.
I am currently working with updating a few key components on a mobile web site. The site uses data from a different server to display student schedules. Recently this other site (over which I have zero control) was subject to a major overhaul and naturally I now have to update the mobile web site.
What I am trying to do is to access an iCal file and parse it. Since the site I am working on runs in an environment that does not have the curl-library nor have fopen wrappers properly set up I have resorted to the method described here (number 4, using a socket directly).
My current issue is that instead of getting the iCal-file I get a 301 error. However, if I attempt to access the same file (via the same URL) in a web browser it works just fine.
EDIT:
I added a bit of logging and here is what came out of it:
-------------
Querying url:
https://someUrl/schema/ri654Q055ZQZ60QbQ0ygnQ70cWny067Z0109Zx4h0Z7o525Y407Q.ics
Response:
HTTP/1.1 301 Moved Permanently
Server: nginx/1.2.8
Date: Sun, 11 Aug 2013 14:08:36 GMT
Content-Type: text/html
Content-Length: 184
Connection: close
Location:
https://someUrl/schema/ri654Q055ZQZ60QbQ0ygnQ70cWny067Z0109Zx4h0Z7o525Y407Q.ics
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.2.8</center>
</body>
</html>
Redirect url found: https://someUrl/schema/ri654Q055ZQZ60QbQ0ygnQ70cWny067Z0109Zx4h0Z7o525Y407Q.ics
The new location I am getting is identical to the original one.
This is the code used:
function getRemoteFile($url)
{
error_log("------------- \r\nQuerying url: " . $url, 3, "error_log.log");
// get the host name and url path
$parsedUrl = parse_url($url);
$host = $parsedUrl['host'];
if (isset($parsedUrl['path'])) {
$path = $parsedUrl['path'];
} else {
// the url is pointing to the host like http://www.mysite.com
$path = '/';
}
if (isset($parsedUrl['query'])) {
$path .= '?' . $parsedUrl['query'];
}
if (isset($parsedUrl['port'])) {
$port = $parsedUrl['port'];
} else {
// most sites use port 80
// but we want port 443 because we are using https
error_log("Using port 443\r\n" . $url, 3, "error_log.log");
$port = 443;
}
$timeout = 10;
$response = '';
// connect to the remote server
$fp = fsockopen($host, $port, $errno, $errstr, $timeout );
if( !$fp ) {
echo "Cannot retrieve $url";
} else {
$payload = "GET $path HTTP/1.0\r\n" .
"Host: $host\r\n" .
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n" .
"Accept: */*\r\n" .
"Accept-Language: sv-SE,sv;q=0.8,en-us,en;q=0.3\r\n" .
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" .
"Referer: https://$host\r\n\r\n";
error_log("\nPAYLOAD: " . $payload, 3, "error_log.log");
// send the necessary headers to get the file
fputs($fp, $payload);
// retrieve the response from the remote server
while ( $line = stream_socket_recvfrom( $fp, 4096 ) ) {
$response .= $line;
}
fclose( $fp );
// naively find location redirect
$location_pos = strpos($response, "Location:");
if($location_pos){
$location_pos += 10;
$new_url = substr($response, $location_pos, strpos($response, "\r\n\r\n") - $location_pos);
error_log("\nRedirect url found: " . $new_url, 3, "error_log.log");
}else{
//log the response
error_log($response, 3, "error_log.log");
}
// strip the headers
$pos = strpos($response, "\r\n\r\n");
$response = substr($response, $pos + 4);
}
// return the file content
return $response;
}
HTTP Response Code 301 is a permanent redirect, not an error.
Your code will have to follow that redirect in order to access the resource.
For example, http://google.com/ returns a 301 in order to redirect users to http://www.google.com/ instead.
$ curl -I http://google.com/
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Sun, 11 Aug 2013 01:25:34 GMT
Expires: Tue, 10 Sep 2013 01:25:34 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic
You can see the 301 response on line 2, followed by the Location header which tells the web browser where to go instead.
What likely happened was that during this major overhaul, they moved the resource to another location. In order not to break any users bookmarks or calendar, they used a 301 redirect so that clients will automatically fetch the resource from the new location.

How do I make a POST request over HTTPS in PHP?

I trying to work with the YouTube API and its ClientLogin. And that means that I need to make a POST request to their servers.
The URL to which I need to make the request to https://www.google.com/accounts/ClientLogin. The variables I need to send are Email, Passwd, source and service. So far, so good.
I found this neat function to make POST calls (see below), but it does not use HTTPS, which I think I must use. It all works but I think my POST request is being forwarded to HTTPS and therefore it does not give me the proper callback. When I try to var_dump, the returned data web page reloads and I end up at https://www.google.com/accounts/ClientLogin where I get proper data. But of course I need this data as an array or string.
So how do I make a POST request using HTTPS?
Se my code (which I found at Jonas’ Snippet Library) below:
function post_request($url, $data, $referer='') {
$data = http_build_query($data);
$url = parse_url($url);
$host = $url['host'];
$path = $url['path'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if ($fp){
fputs($fp, "POST $path HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
if ($referer != '')
fputs($fp, "Referer: $referer\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ". strlen($data) ."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data);
$result = '';
while(!feof($fp)) {
$result .= fgets($fp, 128);
}
}
else {
return array(
'status' => 'err',
'error' => "$errstr ($errno)"
);
}
fclose($fp);
$result = explode("\r\n\r\n", $result, 2);
$header = isset($result[0]) ? $result[0] : '';
$content = isset($result[1]) ? $result[1] : '';
return array(
'status' => 'ok',
'header' => $header,
'content' => $content
);
}
This is the response headers:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Tue, 03 May 2011 12:15:20 GMT
Expires: Tue, 03 May 2011 12:15:20 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Length: 728
Server: GSE
Connection: close
The content I get back is some kind of form autosubmitted, which I think is because I use HTTP instead of HTTPS:
function autoSubmit() {
document.forms["hiddenpost"].submit();
}
Processing...
So, how do I do a HTTPS POST request?
As octopusgrabbus kindly pointed out, I need to use port 443 instead of 80. So I changed this, but now I get nothing back.
var_dump from function return:
array(3) {
["status"]=>
string(2) "ok"
["header"]=>
string(0) ""
["content"]=>
string(0) ""
}
I get no header and no content back. What is wrong?
I think you cannot talk directly HTTPS, as it is HTTP encrypted with the public certificate of the server you are connecting to. Maybe you can use some of the ssl functions in php. But, this will take you some time and frankly, there are easier things.
Just take a look at cURL (client URL), that has support for GET and POST requests, and also connecting to https servers.
You are opening your socket at port 80. The SSL port is 443.
If this is SSL, there is an official computer name tied to the secure cert that's present on that web server. You might need to connect using that official name.
When you open the socket, changing the port to 443 and the prepending the host with ssl:// should work. (I just had this issue with paypal and some third party code). This assumes you don't have a protocol in your host already.
So
$fp = fsockopen('ssl://' . $host, 443, $errno, $errstr, 30);
As Carlos pointed out cUrl is good for this sort of thing. But there's no need to completely change what you're using in this case, particularly when it's a single line change.

Categories