PHP HTTP POST on Android device using HttpURLConnection - php

Question:
So the problem is that this doesn't post to the online database hosted by goDaddy. So my question is why, and how do i fix it to have it post to it?
Issue:
The php page is not receiving the name value pairs being passed to it.
Edit:
Modified code on suggestion to use HttpURLConnection...
I've narrowed down the problem to it not retrieving the fbid.
As you can tell I’ve done a lot of my homework here... Here's my logcat of what is being set in the postthread class Here's my class that does the post:
07-02 16:41:45.108: I/PROJECTCARUSO(12308): response: {"posts":[null]}
HttpPostThread:
public class HttpPostThread extends Thread {
public static final int FAILURE = 0;
public static final int SUCCESS = 1;
private URL url;
ArrayList<NameValuePair> pairs;
public HttpPostThread(URL sERVICE_URL, ArrayList<NameValuePair> pairs, final Handler handler)
{
Log.i("PROJECTCARUSO", "Posting to URL: " + sERVICE_URL);
this.url =sERVICE_URL;
this.pairs = pairs;
if(pairs==null){
Log.i("PROJECTCARUSO", "URL parms were null");
this.pairs = new ArrayList<NameValuePair>();
}
}
#Override
public void run()
{
try {
HttpURLConnection conn;
String param="";
for (NameValuePair nvp : pairs) {
//you need to encode ONLY the values of the parameters
if (param == "") {
param=nvp.getName() + "=" + URLEncoder.encode(nvp.getValue(),"UTF-8");
} else {
param+= "&" + nvp.getName() + "=" + URLEncoder.encode(nvp.getValue(),"UTF-8");
}
}
Log.i("PROJECTCARUSO", "param: " + param.toString());
// Create connection
conn=(HttpURLConnection)url.openConnection();
//set the output to true, indicating you are outputting(uploading) POST data
conn.setDoOutput(true);
//once you set the output to true, you don't really need to set the request method to post, but I'm doing it anyway
conn.setRequestMethod("POST");
//Android documentation suggested that you set the length of the data you are sending to the server, BUT
// do NOT specify this length in the header by using conn.setRequestProperty("Content-Length", length);
//use this instead.
conn.setFixedLengthStreamingMode(param.getBytes().length);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//send the POST out
PrintWriter out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.close();
//build the string to store the response text from the server
String response= "";
//start listening to the stream
Scanner inStream = new Scanner(conn.getInputStream());
//process the stream and store it in StringBuilder
while(inStream.hasNextLine())
response+=(inStream.nextLine());
Log.i("PROJECTCARUSO","response: " + response);
}
//catch some error
catch(MalformedURLException ex){
Log.i("PROJECTCARUSO", ex.toString());
}
// and some more
catch(IOException ex){
Log.i("PROJECTCARUSO", ex.toString());
}
}
public static boolean isNumeric(String str)
{
try
{
double d = Double.parseDouble(str);
}
catch(NumberFormatException nfe)
{
return false;
}
return true;
}
}
Here's the php:
<?php
//Make connection
$con = mysqli_connect('...','...','...') ;
//check connection
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
//change db to andriodnfp db
mysqli_select_db($con, 'andriodnfp');
$table= 'USER';
$id=0;
$fbid = htmlspecialchars($_GET["fbid"]);
$social = htmlspecialchars($_GET["social"]);
$name = htmlspecialchars($_GET["name"]);
$name = !empty($name) ? "'$name'" : "NULL";
$fname = htmlspecialchars($_GET["fname"]);
$fname = !empty($fname) ? "'$fname'" : "NULL";
$username = htmlspecialchars($_GET["username"]);
$username = !empty($username) ? "'$username'" : "NULL";
$email = htmlspecialchars($_GET["email"]);
$email = !empty($email) ? "'$email'" : "NULL";
$picture = htmlspecialchars($_GET["picture"]);
$picture = !empty($picture) ? "'$picture'" : "NULL";
$other = htmlspecialchars($_GET["other"]);
$other = !empty($other) ? "'$other'" : "NULL";
if (!$fbid == '') {
if (!mysqli_query($con, 'INSERT INTO '.$table.' ( facebookID, social_outlet, Name, first_name, username, email, picture, significant_other) VALUES ("'.$fbid.'","'.$social.'","'.$name.'","'.$fname.'","'.$username.'","'.$email.'","'.$picture.'","'.$other.'")')) {
printf("Errormessage: %s\n", mysqli_error($con));
die();
} else {
$posts = array('auto_increment_id'=>mysqli_insert_id($con));
};
} else {
printf("Errormessage: %s\n", "Facebook ID was null");
printf("Errormessage: %s\n", $fbid );
printf("Errormessage: %s\n", $social);
printf("Errormessage: %s\n", $name);
printf("Errormessage: %s\n", $fname);
printf("Errormessage: %s\n", $username);
printf("Errormessage: %s\n", $email);
printf("Errormessage: %s\n", $picture);
printf("Errormessage: %s\n", $other);
die();
}
mysqli_close($con);
//$posts = array($json);
$posts = array($posts);
header('Content-type: application/json');
echo json_encode(array('posts'=>$posts));
?>
Apache logs:
166.147.72.174 - - [19/Jun/2013:16:47:41 -0700] "POST ...post.php? HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 195224
166.147.72.174 - - [19/Jun/2013:16:49:08 -0700] "POST ...post.php? HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 13848
166.147.72.174 - - [19/Jun/2013:16:50:57 -0700] "POST ...post.php? HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 17899
166.147.72.174 - - [19/Jun/2013:16:52:14 -0700] "POST ...post.php HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 12514
166.147.72.174 - - [19/Jun/2013:16:53:35 -0700] "POST ...post.php HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 15190
166.147.72.174 - - [19/Jun/2013:16:54:56 -0700] "POST ...post.php HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 14373
166.147.72.174 - - [19/Jun/2013:16:56:50 -0700] "POST ...post.php HTTP/1.1" 200 155 "-" "Apache-HttpClient/UNAVAILABLE (java 1.4)" 0 "x-httpd-php5-3" "/var/chroot/home/content/31/9124131/html/android/com.projectcaruso/naturalfamilyplaning/post.php" 12017
EDIT:
I even tried the java as so:
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (NameValuePair nvp : pairs) {
//you need to encode ONLY the values of the parameters
params.add(new BasicNameValuePair(nvp.getName(), nvp.getValue()));
Log.i("PROJECTCARUSO", "NVP: " + nvp.getName() + " - " + nvp.getValue());
}
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(params));
writer.close();
os.close();
conn.connect();
//build the string to store the response text from the server
String response= "";
//start listening to the stream
Scanner inStream = new Scanner(conn.getInputStream());
//process the stream and store it in StringBuilder
while(inStream.hasNextLine())
response+=(inStream.nextLine());
Log.i("PROJECTCARUSO","response: " + response);
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

You have to use $_POST instead of $_GET everywhere.

Assuming your use of apache HttpClient as your DefaultClient.
You need more data about WIRE and HEADERs. Apache logger docs show you how to turn those loggers on. read the apache docs on logging
example below of what you will see ( u will know exactly what is going on between client and server).
Full logging in apache HttpClient:
D/ch.boye.httpclientandroidlib.wire( 1175): >> "PUT /1/classes/Books/8NUX0YP5XK HTTP/1.1[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "Content-Length: 375[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "Content-Type: text/plain; charset=ISO-8859-1[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "Host: api.parse.com[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "Connection: Keep-Alive[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "X-Parse-Application-Id: 3[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "X-Parse-REST-API-Key: kVl9[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): >> "[\r][\n]"
D/ch.boye.httpclientandroidlib.headers( 1175): >> PUT /1/classes/Books/8NUX0YP5XK HTTP/1.1
D/ch.boye.httpclientandroidlib.headers( 1175): >> Content-Length: 375
D/ch.boye.httpclientandroidlib.headers( 1175): >> Content-Type: text/plain; charset=ISO-8859-1
D/ch.boye.httpclientandroidlib.headers( 1175): >> Host: api.parse.com
D/ch.boye.httpclientandroidlib.headers( 1175): >> Connection: Keep-Alive
D/ch.boye.httpclientandroidlib.headers( 1175): >> X-Parse-Application-Id: 3K
D/ch.boye.httpclientandroidlib.headers( 1175): >> X-Parse-REST-API-Key: kVl5Z
D/ch.boye.httpclientandroidlib.wire( 1175): >> "{"pages":{"__op":"Add","objects":[{"__type":"Pointer","ClassName":"TestVoiceObject","objectId":"bsKyc8mKV7"},{"__type":"Pointer","ClassName":"TestVoiceObject","objectId":"hehlqEUJw8"},{"__type":"Pointer","ClassName":"TestVoiceObject","objectId":"rtbhCb37tq"},{"__type":"Pointer","ClassName":"TestVoiceObject","objectId":"84zjWpJy6y"}]},"ACL":{"*":{"read":true,"write":true}}}"
D/ch.boye.httpclientandroidlib.wire( 1175): << "HTTP/1.1 200 OK[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Access-Control-Allow-Origin: *[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Access-Control-Request-Method: *[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Cache-Control: max-age=0, private, must-revalidate[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Content-Type: application/json; charset=utf-8[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Date: Mon, 08 Apr 2013 19:51:59 GMT[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "ETag: "172e8ee0c4828b5fce3303c078b8f2ad"[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Server: nginx/1.2.2[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Set-Cookie: _parse_session=BAh7BkkiD3d989bfe; domain=.parse.com; path=/; expires=Sat, 08-Apr-2023 19:51:59 GMT; secure; HttpOnly[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Status: 200 OK[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "X-Runtime: 0.041462[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "X-UA-Compatible: IE=Edge,chrome=1[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Content-Length: 500[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "Connection: keep-alive[\r][\n]"
D/ch.boye.httpclientandroidlib.wire( 1175): << "[\r][\n]"
D/class ch.boye.httpclientandroidlib.impl.conn.DefaultClientConnection( 1175): Receiving response: HTTP/1.1 200 OK
D/ch.boye.httpclientandroidlib.headers( 1175): << HTTP/1.1 200 OK
D/ch.boye.httpclientandroidlib.headers( 1175): << Access-Control-Allow-Origin: *
D/ch.boye.httpclientandroidlib.headers( 1175): << Access-Control-Request-Method: *
D/ch.boye.httpclientandroidlib.headers( 1175): << Cache-Control: max-age=0, private, must-revalidate
D/ch.boye.httpclientandroidlib.headers( 1175): << Content-Type: application/json; charset=utf-8
D/ch.boye.httpclientandroidlib.headers( 1175): << Date: Mon, 08 Apr 2013 19:51:59 GMT
D/ch.boye.httpclientandroidlib.headers( 1175): << ETag: "172e8ee0c4828b5fce3303c078b8f2ad"
D/ch.boye.httpclientandroidlib.headers( 1175): << Server: nginx/1.2.2
D/ch.boye.httpclientandroidlib.headers( 1175): << Set-Cookie:

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.

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

Possible encoding problem using PHP-7 Sockets as WebSocket Server

When trying to use PHP7.3 as SocketServer for WebSockets I encounter a problem where a message send from Firefox come out the socket all messed up. And always differently.
However, messages send from PHP to Firefox are fine.
For example:
socket.onopen = function(e)
{
e.target.send(JSON.stringify({"sessionid" : "5e8a2f30a164e", "sockid" : "5e8a5c8cd99e6"}));
}
one time becomes
)'JR9ZT#GN.Fx+/9JL#
hL+J)/
Z
next time it's
ZXC!+&)1,4<a`m&bj%i9rl=av+,91'xzv?9v9;'c=ux
Clientrequest:
GET / HTTP/1.1
Host: 192.168.5.54:8089
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://192.168.5.54
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: uhfFVS5mhYptk6FF8jl73g==
Connection: keep-alive, Upgrade
Cookie: XDEBUG_SESSION=XDEBUG_ECLIPSE
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Servercode[shortend]:
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
$ret = socket_bind($this->socket, $this->host, $this->port);
$ret = socket_listen( $this->socket, 0 );
socket_set_nonblock($this->socket);
while ($this->isServer)
{
$connection = #socket_accept($this->socket);
[... forking for new connection cont in child]
}
Child:
socket_close($this->socket);
[...]
$request = socket_read($connection, 5000); //creates above client request
preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $request, $matches);
$key = base64_encode(pack('H*', sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$headers = "HTTP/1.1 101 Switching Protocols\r\n";
$headers .= "Upgrade: websocket\r\n";
$headers .= "Connection: Upgrade\r\n";
$headers .= "Sec-WebSocket-Version: 13\r\n";
//$headers .= "Sec-WebSocket-Protocol: json\r\n";
$headers .= "Sec-WebSocket-Accept: $key\r\n\r\n";
socket_write($connection, $headers, strlen($headers));
require_once("objs/User.php");
$user = new User();
// Send messages into WebSocket in a loop.
socket_set_nonblock($connection);
while (true)
{
if(($msg = socket_read($connection, 5000)) === "")
{
die;
}
if(!empty($msg))
{
echo $msg."\n";
}
I'm at a loss here and would appreciate your help!
It turns out data send from client->server is always "masked" using WebSockets.
The function unmask($payload) from this post helped me solve the problem.

PHP & C++ $_FILES and HttpSendRequestA

Having problems with uploading a file from c++ to a PHP form. Iv seen the posts similar to my issue.
Upload Image File in C++
Uploading file to server using C++ HTTP request
And according to the documentation laid out in each, and in HERE my code by all accounts should be correct.
I also cannot use CURL for my implementation. As much as I would like too.
Iv tried encoding all the data into BASE64 to alleviate any file data problems, but no dice.
Iv double checked my php.ini file to allow uploads. And tested the PHP page with a simple HTML page that allows me to upload a file. All good, the form gives correct results.
Basically the headers I send to the server is:
Host: dzwxgames.com
Connection: close
Content-Length: 418
Origin: http://dzwxgames.com
Content-Type: multipart/form-data; boundary=WrbKitFormBoundaryXtRo8bh7ZpnTrTwd
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36
Pragma: no-cache
--WrbKitFormBoundaryXtRo8bh7ZpnTrTwd
Content-Disposition: form-data; name="file"; filename="02-11-2019 09-44.log"
Content-Type: text/plain;
Content-Transfer-Encoding: BASE64
W0FsdF1bVGFiXVtUYWJdW1RhYl1bQ11bRF1bU3BhY2VdW1VdW1BdW1RhYl1bRW50ZXJdW0xdW1NdW0VudGVyXVtDXVtEXVtTcGFjZV1bLl1bLl1bL11bRW50ZXJdW0xdW1NdW0VudGVyXVtBbHRdW1RhYl1bVGFiXVtUYWJdW1RhYl1bQWx0XVtUYWJdW1RhYl0=
--WrbKitFormBoundaryXtRo8bh7ZpnTrTwd--
Which my PHP page returns:
HTTP/1.1 200 OK
Date: Sun, 03 Nov 2019 09:09:19 GMT
Server: Apache/2.4.29 (Ubuntu)
Content-Length: 35
Connection: close
Content-Type: text/plain; charset=utf-8
NULL
Array
(
)
File does not exist.
The code for the php page is simple:
if (!isset($_FILES['file']['error'])){
var_dump($_FILES['file']);
print_r($_FILES);
throw new RuntimeException('File does not exist.');
}
Finaly my C++ Code is:
bool sendFileToRemoteServer(std::filesystem::path file, const std::string& url,const std::string& iaddr) {
std::string headder = ""; //Headder information
std::string datahead = "";
std::string content = "";
if (!File::fastFileToString(file.string(), content)) {
std::cout << "ERROR_FILE_OPEN" << std::endl;
return false;
}
content = base64_encode(reinterpret_cast<const unsigned char*>(content.c_str()),content.length());
datahead += "--WrbKitFormBoundaryXtRo8bh7ZpnTrTwd\r\n";
datahead += "Content-Disposition: form-data; name=\"file\"; filename=\"" + file.filename().string() +"\"\r\n"; //Content - Disposition : form - data; name = "fileToUpload"; filename = "testMac.cpp"
datahead += "Content-Type: text/plain;\r\n";
datahead += "Content-Transfer-Encoding: BASE64\r\n\n";
datahead += content;
datahead += "\r\n--WrbKitFormBoundaryXtRo8bh7ZpnTrTwd--\r\n";
//datahead = base64_encode(reinterpret_cast<const unsigned char*>(datahead.c_str()), datahead.length());
//Build Headder
headder += "Host: " + iaddr + "\r\n"; //Host: localhost
headder += "Connection: close\r\n"; //Connection : keep - alive
headder += "Content-Length: " + std::to_string(datahead.size()) + "\r\n"; //Content - Length : 800
headder += "Origin: http://dzwxgames.com\r\n";
//headder += "Content-Transfer-Encoding: base64\r\n";
headder += "Content-Type: multipart/form-data; boundary=WrbKitFormBoundaryXtRo8bh7ZpnTrTwd\r\n"; //Content - Type : multipart / form - data; boundary = WrbKitFormBoundaryXtRo8bh7ZpnTrTwd
headder += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36\r\n"; //User - Agent: 1337
headder += "Pragma: no-cache\r\n\r\n";
std::cout << "SENT HEAD:" << std::endl;
std::cout << headder;
std::cout << datahead;
//Open internet connection
HINTERNET hSession = InternetOpen("WINDOWS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hSession == NULL){
printLastError(GetLastError());
printf("ERROR_INTERNET_OPEN");
return false;
}
HINTERNET hConnect = InternetConnect(hSession, iaddr.c_str(), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (hConnect == NULL){
printLastError(GetLastError());
printf("ERROR_INTERNET_CONN");
return false;
}
HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST", _T(url.c_str()), NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 1);
if (hRequest == NULL){
printLastError(GetLastError());
printf("ERROR_INTERNET_REQ");
return false;
}
if (!HttpSendRequestA(hRequest, headder.c_str(), headder.size(), (void*)datahead.c_str(), datahead.size())){
printLastError(GetLastError());
printf("ERROR_INTERNET_SEND");
return false;
}
//Request Done, get responce
DWORD dwSize = 0;
if (!InternetQueryDataAvailable(hRequest, &dwSize, 0, 0)) {
printLastError(GetLastError());
printf("ERROR_InternetQueryDataAvailable");
return false;
}
char* responce = new char[dwSize + 1];
DWORD dwlpsizeread = 0;
if (!InternetReadFile(hRequest, responce, dwSize, &dwlpsizeread)) {
printLastError(GetLastError());
printf("ERROR_InternetReadFile");
return false;
}
printf("\nRESPONCE HEAD : \n");
SampleCodeOne(hRequest);
responce[dwSize] = 0;
std::cout << responce << std::endl;
delete[] responce;
InternetCloseHandle(hSession);
InternetCloseHandle(hConnect);
InternetCloseHandle(hRequest);
return true;
}
What am I missing? I cant seem to find the problem.
After checking with wire-shark, I found a 301 Error header sent back to me, with my force upgrade to HTTPS. After removing the HTTPS for testing, This fixed the error. Now I just have to fix the error code 3 on upload now. EUGH.
For some reason, HttpQueryInfo did not report the error 301. Instead it resent the packet to the new address, but without the data being encrypted, it had no idea what to do with it.
Funny enough, Apache silently discarded the un-encrypted data since it could not be encrypted. Nothing in the logs, no mention. Odd.
Not sure if intended. But ok.

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);

Categories