Send Http "Post" Request To Php Code in C or C++ - php

I'm trying to send a "post" reguest to my php file and get the info back, it works fine, but
it also print something before printing my response from the php file. this is what it print
first:
HTTP/1.1 200 OK
Date: Fri, 20 Apr 2012 10:19:12 GMT
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6
Content-Length: 12
Connection: close
Content-Type: text/html
and then my response:
hello world
how can i only print what i'm getting from myphp code, without:
HTTP/1.1 200 OK
Date: Fri, 20 Apr 2012 10:19:12 GMT
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6
Content-Length: 12
Connection: close
Content-Type: text/html
the code i'm using is:
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <unistd.h>
#define SA struct sockaddr
#define MAXLINE 4096
#define MAXSUB 200
#define LISTENQ 1024
extern int h_errno;
ssize_t process_http(int sockfd, char *host, char *page, char *poststr)
{
char sendline[MAXLINE + 1], recvline[MAXLINE + 1];
ssize_t n;
snprintf(sendline, MAXSUB,
"POST %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Content-type: application/x-www-form-urlencoded\r\n"
"Content-length: %d\r\n\r\n"
"%s", page, host, strlen(poststr), poststr);
write(sockfd, sendline, strlen(sendline));
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = '\0';
printf("%s", recvline); // <-- this
}
return n;
}
int main(void)
{
int sockfd;
struct sockaddr_in servaddr;
char **pptr;
//********** You can change. Puy any values here *******
char *hname = "localhost";
char *page = "/mysql_update.php";
char *poststr = "server=dd sd sdsdt\n";
//*******************************************************
char str[50];
struct hostent *hptr;
if ((hptr = gethostbyname(hname)) == NULL) {
fprintf(stderr, " Server down error for host: %s: %s",
hname, hstrerror(h_errno));
exit(1);
}
printf("hostname: %s \n", hptr->h_name);
if (hptr->h_addrtype == AF_INET
&& (pptr = hptr->h_addr_list) != NULL) {
printf("address: %s\n",
inet_ntop(hptr->h_addrtype, *pptr, str,
sizeof(str)));
} else {
fprintf(stderr, "Error call inet_ntop \n");
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(80);
inet_pton(AF_INET, str, &servaddr.sin_addr);
connect(sockfd, (SA *) & servaddr, sizeof(servaddr));
process_http(sockfd, hname, page, poststr);
close(sockfd);
exit(0);
}
Please help me to fix this problem, step by step so' i can understand it, give me information and please if you can' show me a example. ( this will help me and others )

First part of the response you received is made up of HTTP version, Server Response Status Code and various HTTP response headers.
HTTP/1.1 200 OK Date: Fri, 20 Apr 2012 10:19:12 GMT Server:
Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6 Content-Length: 12 Connection: close
Content-Type: text/html
After headers follows HTTP response body (which you need to extract):
hello world
HTTP headers and body are separated with the following sequence of characters: \r\n\r\n. So all you need to do is to search for it and extract everything that is behind it.
You can do this yourself (sockets, parsing...) but my advice is to use some of HTTP libraries: WinInet, WinHttp (both are Microsoft's) or libCurl (open source).

The responses header bit is separated from the content by a blank line.
Need to take into account different line endings. Basically ignore \rs.
So 1st read lines until you get a blank one then start printing them!
EDIT
You have a response as follows
HTTP/1.1 200 OK
Date: Fri, 20 Apr 2012 10:19:12 GMT
...
Content-Type: text/html
Hello World
Notice that there is a blank line between the HTTP headers and the response (HTML in this case).

Related

I am reading a stream of bytes from server using esp8266 by running a .php script on the server but i do not get the correct data

This is the GET request & response which is sent/received to/from the server
Connecting to MD1
.......
WiFi connected
IP address:
192.168.43.135
connecting to smbbitumen.com
Requesting URL: http://www.smbbitumen.com/smbbitumen.com/myftp/API/Users/read.php
HTTP/1.1 200 OK
Date: Sat, 06 Jun 2020 03:00:17 GMT
Server: nginx/1.17.9
Content-Type: text/html
X-Powered-By: PHP/5.4.45
Vary: Accept-Encoding
Accept-Ranges: none
X-Server-Cache: true
X-Proxy-Cache: MISS
Transfer-Encoding: chunked
48
1111000019:30:0020:30:0019:40:0020:40:0019:45:0020:45:0019:50:0020:50:00
0
closing connection
1111000019:30:0020:30:0019:40:0020:40:0019:45:0020:45:0019:50:0020:50:00 -> This is the stream of data which i am reading into esp but it does not get updated in realtime, it remains same. Any ideas, ehy this is happening.....
Also one more thing, when i run the above php link in browser,everytime it returns correct data.
php script which i am using to read data
<?php
clearstatcache();
$myfile = fopen("TEST.txt", "r");
if($myFile === FALSE)
echo "ERROR";
else
echo fread($myfile,filesize("TEST.txt"));
fclose($myfile);
?>
ESP8266 code for connecting to server and running the above script using GET request
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WiFiClientSecure.h>
#include <Ticker.h>
#include <EEPROM.h>
#include <ESP8266HTTPClient.h>
#include<ESP8266WiFiMulti.h>
const char *ssid = "***";
const char *password = "******";
HTTPClient myhttp;
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid,password);
while(WiFi.status()!= WL_CONNECTED)
{
delay(1000);
Serial.println("Connecting...");
}
}
void loop()
{
if(WiFi.status() == WL_CONNECTED)
{
myhttp.begin("http://www.smbbitumen.com/smbbitumen.com/myftp/API/Users/read.php");
int httpCode = myhttp.GET();
if(httpCode > 0)
{
String payload = myhttp.getString();
Serial.println(myhttp.getString());
}
httpCode = 0;
myhttp.end();
}
delay(2000);
}
The issue is related to cache. Change the code in read.php as below
<?php
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
clearstatcache();
$myfile = fopen("TEST.txt", "r");
if($myFile === FALSE)
echo "ERROR";
else
echo fread($myfile,filesize("TEST.txt"));
fclose($myfile);
clearstatcache();
?>
The similar thing can be done by changing the settings for cache on the server.

ESP8266 reads JSON, but doesn't read the PHP file

There is a code for ESP8266, which parses the data on my site and performs the switching on / off of the led. When it was a static JSON file, it all worked without problems. But when I transferred a file to PHP that dynamically updates the data and displays it in JSON format, the script doesn't get it to read. What could be the problem?
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#define pin 5
const char* ssid = "ssid";
const char* password = "password";
const char* host = "www.site.ru"; // domain
String path = "/lightAPI.php";
void setup() {
pinMode(pin, OUTPUT);
pinMode(pin, HIGH);
digitalWrite(5, HIGH);
Serial.begin(9600);
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int wifi_ctr = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP());
}
void loop() {
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: keep-alive\r\n\r\n");
delay(2000); // wait for server to respond
// read response
String section="header";
while(client.available()){
String line = client.readStringUntil('\r');
// Serial.print(line);
// we’ll parse the HTML body here
if (section=="header") { // headers..
Serial.print("");
if (line=="\n") { // skips the empty space at the beginning
section="json";
}
}
else if (section=="json") { // print the good stuff
section="ignore";
String result = line.substring(1);
// Parse JSON
int size = result.length() + 1;
char json[size];
result.toCharArray(json, size);
StaticJsonBuffer<200> jsonBuffer;
JsonObject& json_parsed = jsonBuffer.parseObject(json);
if (!json_parsed.success())
{
Serial.println("parseObject() failed");
return;
}
// Make the decision to turn off or on the LED
if (strcmp(json_parsed["light"], "OFF") == 0) {
digitalWrite(5, HIGH);
Serial.println("LED OFF");
}
else {
digitalWrite(5, LOW);
Serial.println("LED ON");
}
}
}
}
PHP file
<?php
header('Content-Type: application/json');
$status = file_get_contents('txt/lightStatus.txt');
$json = array('light' => $status, 'time' => date("G"));
echo json_encode($json);
?>
There's something wrong with handling the response. It works when connecting to my server but it doesn't work when connecting to yours.
This is what ESP8266 gets when connecting to my server:
HTTP/1.1 200 OK
Date: Sat, 17 Jun 2017 18:21:37 GMT
Server: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.6.19
X-Powered-By: PHP/5.6.19
Content-Length: 31
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json
{"light":"OFF","time":"20"}
And this is what it gets when connecting to yours:
HTTP/1.1 200 OK
Server: nginx admin
Date: Sat, 17 Jun 2017 18:25:53 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
28
{"light":"OFF","online":"0","time":"21"}
0
Unfortunately, I don't have time now to investigate the problem with your code but meanwhile here is a working one which uses HTTPClient to handle request and response (I would recommend using this anyway):
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#define pin 5
const char* ssid = "ssid";
const char* password = "password";
void setup() {
pinMode(pin, OUTPUT);
pinMode(pin, HIGH);
digitalWrite(5, HIGH);
Serial.begin(9600);
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int wifi_ctr = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP());
}
void loop() {
HTTPClient http;
http.begin("http://bot.erm.today/lightAPI.php");
int statusCode = http.GET();
StaticJsonBuffer<200> jsonBuffer;
JsonObject& json_parsed = jsonBuffer.parseObject(http.getString());
http.end();
if (!json_parsed.success())
{
Serial.println("parseObject() failed");
return;
}
// Make the decision to turn off or on the LED
if (strcmp(json_parsed["light"], "OFF") == 0) {
digitalWrite(5, HIGH);
Serial.println("LED OFF");
}
else {
digitalWrite(5, LOW);
Serial.println("LED ON");
}
}
Json is simply a format, a structure, it needs no processing. PHP on the other hand is a server side language that means that is is interpreted by another application and it is actually that application that is interpreting the code that does the work. The esp8266 lacks that application. And will not be able to run your PHP file. I would recommend looking into making an API in php that is stored on a server somewhere and have your esp call out to that. Or see if you can implement your code right on the esp, though you may be limited by CPU, memory, and processing power. Good luck!

HTTP Request with C; call PHP file and read the echo text output/response

I simply want to read the response from a PHP file by calling it in C.
At the moment I have the following PHP script and the C program:
PHP file:
<?php echo "successful"; ?>
C code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
int socket_connect(char *host, in_port_t port){
struct hostent *hp;
struct sockaddr_in addr;
int on = 1, sock;
if((hp = gethostbyname(host)) == NULL){
herror("gethostbyname");
exit(1);
}
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));
if(sock == -1){
perror("setsockopt");
exit(1);
}
if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(1);
}
return sock;
}
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]){
int fd;
char buffer[BUFFER_SIZE];
fd = socket_connect("myserver.bplaced.net", 80);
write(fd, "GET /MySQLadmin/myscript.php HTTP/1.0\r\n\r\n", strlen("GET /MySQLadmin/myscript.php HTTP/1.0\r\n\r\n")); // write(fd, char[]*, len);
bzero(buffer, BUFFER_SIZE);
while(read(fd, buffer, BUFFER_SIZE - 1) != 0){
fprintf(stderr, "%s", buffer);
bzero(buffer, BUFFER_SIZE);
}
shutdown(fd, SHUT_RDWR);
close(fd);
return 0;
}
So far I can contact the server but when I read the BUFFER I receive the following but not the echo text.
Output in the console:
HTTP/1.1 302 Found
Date: Fri, 05 Aug 2016 05:21:14 GMT
Server: Apache/2.4
Location: http://www.bplaced.net/404
Content-Length: 271
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved here.</p>
<hr>
<address>Apache/2.4 Server at default Port 80</address>
</body></html>
Process returned 0 (0x0) execution time : 0.126 s
Press any key to continue.
Maybe I have a typo somewhere but can't find it.
Please help

call php-cgi from c++ with REQUEST_METHOD="POST"

i am want to convert a shell script to c++. Please help me.
this is my shell script file. it worked well, but when i move to c++, it is not work correctly
test.sh
#!/bin/sh
REQUEST_DATA="var_1=val_1&var_2=val_2"
export GATEWAY_INTERFACE="CGI/1.1"
export SERVER_PROTOCOL="HTTP/1.1"
export QUERY_STRING="test=querystring"
export REDIRECT_STATUS="200"
export SCRIPT_FILENAME="/test.php"
export REQUEST_METHOD="POST"
export CONTENT_LENGTH=${#REQUEST_DATA}
export CONTENT_TYPE="application/x-www-form-urlencoded;charset=utf-8"
echo $REQUEST_DATA | /usr/bin/php-cgi
and test.php is
<?php
print_r($_POST);
?>
when i run sh test.sh, i got response:
X-Powered-By: PHP/5.6.13
Set-Cookie: PHPSESSID=f4ntbasno365p08tf94drl7026; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html; charset=UTF-8
Array
(
[var_1] => val_1
[var_2] => val_2
)
When i am trying to convert this to c++
char **sysCline = NULL;
char **sysEnv = NULL;
std::string sData = "var_1=val_1&var_2=val_2";
std::vector<std::string> aArgs;
aArgs.push_back("/usr/bin/php-cgi");
aArgs.push_back("/test.php");
sysCline = new char*[aArgs.size() + 1];
for (i=0; i<aArgs.size(); i++) {
sysCline[i] = new char[aArgs[i].size()+1];
::strncpy(sysCline[i], aArgs[i].c_str(), aArgs[i].size()+1);
}
sysCline[aArgs.size()] = NULL;
// Construct environment
std::vector<std::string> aEnv;
aEnv.push_back("GATEWAY_INTERFACE=CGI/1.1");
aEnv.push_back("SERVER_PROTOCOL=HTTP/1.1");
aEnv.push_back("QUERY_STRING=test=querystring");
aEnv.push_back("REDIRECT_STATUS=200");
aEnv.push_back("REQUEST_METHOD=POST");
aEnv.push_back("CONTENT_TYPE=application/x-www-form-urlencoded;charset=utf-8");
aEnv.push_back("SCRIPT_FILENAME=/test.php");
aEnv.push_back("CONTENT_LENGTH="+ to_string(sData.length()) );
sysEnv = new char*[aEnv.size() + 1];
for (i=0; i<aEnv.size(); i++) {
sysEnv[i] = new char[aEnv[i].size()+1];
::strncpy(sysEnv[i], aEnv[i].c_str(), aEnv[i].size() + 1);
}
sysEnv[aEnv.size()] = NULL;
execve(sysCline[0], sysCline, sysEnv);
When run, i got response:
X-Powered-By: PHP/5.6.13
Set-Cookie: PHPSESSID=2vdp947ghlg0h8st66c9ll3vt6; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html; charset=UTF-8
Array
(
)
It should be same response with sh test.sh
You need to create a pipe in order to pass the POST data to the script:
char *echocmd[] = {"echo", "var_1=val_1&var_2=val_2", NULL};
int pp[2];
int pid, res;
pipe(pp);
if ((pid = fork()) != 0)
{
dup2(pp[1], 1);
close(pp[0]);
res = execvp(echocmd[0], echocmd);
}
else
{
dup2(pp[0], 0);
close(pp[1]);
res = execve(sysCline[0], sysCline, sysEnv);
}
close(pp[1]);
return res;
Thank you #yacc, I found a way, this is demo the way i used
http://cpp.sh/4wgu
The idea is: we will fork current process, use 2 pipes: 1 for stdin and 1 for stdout. in parent process, we will use a pipe to write string to stdin of child process, and in child process, we will dum a pipe for output from child's stdout. with this way, we can write to stdin and read stdout of child process from parent process

How to send text/html data to a browser

Hi i asked a question before here : how-can-i-integrate-php-with-my-http-server
i programmed a personal web server and i tried to integrate it with PHP using the PHP-CGI , i run a system command ("PHP-CGI.exe path/to/php/script.php getvar=getValue") and i send the outputs to the browser , everything works cool except that the output shows in the browser as plain/text page like :
X-Powered-By: PHP/5.4.14 Set-Cookie:
PHPSESSID=9rurvleetdkucms44i4cac9a14; path=/ Expires: Thu, 19 Nov 1981
08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate,
post-check=0, pre-check=0 Pragma: no-cache Content-type: text/html
ID value = AAAA< /h1>
here's the PHP script :
<?php
session_start();
echo "< h1>ID value = < /h1>". $_GET['id'];
?>
and the command i used : php-cgi html_doc/index.php id=AAAA
my question is : why does it send data in plain/text instead of text/html i want?!
and why does it show the header information in the browser like above ?!
Thank you all in advance!
(Notice : i seperated < h1>so it can be appeared!)
this is a BASIC html_to_browser using C sockets
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <strings.h>
int main(int argc, char *argv[]){
char *reply =
"HTTP/1.1 200 OK\n"
"Date: Thu, 19 Feb 2009 12:27:04 GMT\n"
"Server: Apache/2.2.3\n"
"Last-Modified: Wed, 18 Jun 2003 16:05:58 GMT\n"
"ETag: \"56d-9989200-1132c580\"\n"
"Content-Type: text/html\n"
"Content-Length:156\n"
"Accept-Ranges: bytes\n"
"Connection: close\n"
"\n"
"o EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE GRANDE ___2 \n \r\n\r\n"
"THIS IS A HTTP RESPONSE TO BROWSER \n USING C SOCKETS _ \\_t 5 \n \r\n\r\n"
"\r\n\r\n \r\n\r\n \r\n\r\nNOT FINISHED AA _3\r\n\r\n";
int sd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sd,(struct sockaddr*)&addr,sizeof(addr))!=0){
printf("bind error\n");
}
if (listen(sd, 16)!=0){
printf("listen error\n");
}
while(1){
socklen_t size = sizeof(addr);
int client = accept(sd,(struct sockaddr*)&addr, &size);
if (client > 0)
{
printf("client connected\n");
/*send(client, reply, sizeof(reply), 0);*/
send(client, reply, strlen(reply)+1, 0);
}
}
return 0;
}
compile + execute on a console with sudo(to allow port 80) OR change the addr.sin_port to something bigger than '1024'
...ctrl+z to finish
In php you would do header("Content-Type: text/html"); to set a default change the default_mimetype directive in php.INI to the correct mime type.

Categories