So I'm trying to upload a simple text file using Qt Network Mangager to a php script that I'm serving. But it's not working. I tried examples with QHttpMultiPart and with Setting raw data headers in request but none work.
Here is my Qt Code:
#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDebug>
#include <QEventLoop>
#include <QObject>
#include <QVariantMap>
#include <QJsonDocument>
#include <QFile>
#include <QHttpMultiPart>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString address = "http://localhost/api_test/";
//address = "https://dashboard.viewmind.ai/dashboard/api_test/welcome.php";
QUrl api_url = QUrl(address);
QVariantMap postDatamap;
postDatamap.insert("Name","Ariel Ñoño");
postDatamap.insert("Age",37);
QJsonDocument json = QJsonDocument::fromVariant(postDatamap);
qDebug() << "Sending the request";
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkRequest request(api_url);
QString bound = "<<<<<boundary>>>>>";
request.setRawHeader(QString("Content-Type").toUtf8(),QString("multipart/form-postData; boundary=" + bound).toUtf8());
//QByteArray postData;
QByteArray postData(QString("--" + bound + "\r\n").toUtf8());
postData.append("Content-Disposition: form-postData; name=\"action\"\r\n\r\n");
postData.append("welcome.php\r\n");
postData.append(QString("--" + bound + "\r\n").toUtf8());
postData.append("Content-Disposition: form-postData; name=\"uploaded\"; filename=\"");
postData.append("test.json");
postData.append("\"\r\n");
postData.append("Content-Type: text/xml\r\n\r\n"); //postData type
QFile file("test.json");
if (!file.open(QIODevice::ReadOnly)){
qDebug() << "QFile Error: File not found!";
delete networkManager;
return 0;
} else { qDebug() << "File found, proceed as planned"; }
postData.append(file.readAll());
postData.append("\r\n");
postData.append(QString("--" + bound + "\r\n").toUtf8());
request.setRawHeader(QString("Content-Length").toUtf8(), QString::number(postData.length()).toUtf8());
//request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json; charset=utf-8");
//request.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-postData; name=\"text\""));
//qDebug() << QString(json.toJson());
//QHttpMultiPart multipart(QHttpMultiPart::FormDataType);
//QHttpPart textPart;
// QFile file("test.json");
// if (!file.open(QIODevice::ReadOnly)){
// qDebug() << "Could not open file for reading";
// delete networkManager;
// return 0;
// }
//textPart.setBodyDevice(&file);
//multipart.append(textPart);
//file.setParent(&multipart);
//QNetworkReply *reply = networkManager->post(request,json.toJson());
//QNetworkReply *reply = networkManager->post(request,file.readAll());
//QNetworkReply *reply = networkManager->post(request,&multipart);
QNetworkReply *reply = networkManager->post(request,postData);
//file.setParent(reply);
//multipart.setParent(reply);
// Using the loop to wait for the reply to finish.
QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
qDebug() << "Reply is finished";
//file.close();
if (reply->error() != QNetworkReply::NoError){
qDebug() << "The following error ocurred";
qDebug() << reply->errorString();
return 0;
}
QString postData_returned = QString::fromUtf8(reply->readAll());
qDebug() << "DATA RETURNED";
qDebug() << postData_returned;
return 0;
}
My php code looks like this
<?php
header("Access-Control-Allow-Origin: *"); // Anyone can access
header("Content-Type: application/json; charset=UTF-8"); // Will return json data.
error_log("FILES iS");
vardump_toerror($_FILES);
?>
It is my understanding that the $_FILES super global should get filled with the file information. Am I mistaken? But the print out shows it's empty.
I am not an expert in PHP but I find it unnecessary to use the content-type application/json since multipart (submit forms) is not part of that protocol. On the other hand I can't find a reference of the vardump_toerror function so I change with var_dump so my test php is:
<?php
var_dump($_FILES);
?>
In a previous question for PyQt5 I implemented a similar logic for django that also applies in this case so I will show a translation.
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTextCodec>
QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QVariantMap::const_iterator i_data = data.constBegin();
while (i_data != data.constEnd()) {
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
postpart.setBody(i_data.value().toByteArray());
multipart->append(postpart);
++i_data;
}
QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
while (i_filenames != filenames.constEnd()) {
QFile *file = new QFile(i_filenames.value());
if(!file->open(QIODevice::ReadOnly)){
delete file;
continue;
}
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=\"%1\"; filename=\"%2\"")
.arg(i_filenames.key(), file->fileName()));
postpart.setBodyDevice(file);
multipart->append(postpart);
file->setParent(multipart);
++i_filenames;
}
return multipart;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QUrl url("http://localhost:4000/upload.php");
QNetworkAccessManager manager;
QMap<QString, QString> filenames;
filenames["fileToUpload"] = "/path/of/data.txt";
QHttpMultiPart *multipart = buildMultpart({}, filenames);
QNetworkRequest request(url);
QNetworkReply *reply = manager.post(request, multipart);
multipart->setParent(reply);
QObject::connect(reply, &QNetworkReply::finished, QCoreApplication::quit);
a.exec();
if(reply->error() == QNetworkReply::NoError){
qDebug() << reply->readAll();
}
else{
qDebug() << reply->error() << reply->errorString();
}
delete reply;
return 0;
}
Output:
"array(1) {\n [\"fileToUpload\"]=>\n array(5) {\n [\"name\"]=>\n string(8) \"data.txt\"\n [\"type\"]=>\n string(0) \"\"\n [\"tmp_name\"]=>\n string(14) \"/tmp/phpVmOAhO\"\n [\"error\"]=>\n int(0)\n [\"size\"]=>\n int(6)\n }\n}\n"
Related
Im trying to get my c++ app to authenticate user/pass against a web database. To do so, I have a simple html form for user/pass which triggers the authentication php script.
Im having a hard time understanding cURL since im a complete noob on it.
Right now, I'm able to send data to the html form, but i dont even know if im doing properly.
Ideally, I would like you to teach me how to do it, and how to read a response. I mean, if the login goes right, how do i get c++ to know it?
All the code i have:
HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form method="post" action="check.php">
<input type="text" name="uname"/>
<input type="password" name="password"/>
<input type="submit"/>
</form>
</html>
PHP
<?php
$fileDir = '/var/www/html/forums/';
require($fileDir . '/src/XF.php');
XF::start($fileDir);
$app = \XF::setupAPP('XF\App');
$username = $_POST['uname']; $password = $_POST['password'];
$ip = $app->request->getIp();
$loginService = $app->service('XF:User\Login', $username, $ip);
$userValidate = $loginService->validate($password, $error);
if(!$userValidate)
{
//Not good pass / user
$data = ['validated' => false];
}
else $data = ['validated' => true];
header('Content-type: application/json');
echo json_encode($data);
?>
C++
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <curl/curl.h>
using namespace std;
int main()
{
char username[20];
char password[25];
cout << "Username: ";
cin >> username;
cout << "Password: ";
cin >> password;
/*------------------------------------------*/
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_URL, "https://localhost/index.hmtl");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "uname=?&password=?", username, password);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
EDIT: WORKING SOLUTION
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <curl/curl.h>
using namespace std;
string urlencode(const string &str) {
char *escaped = curl_escape(str.c_str(), str.length());
if (escaped == NULL) throw runtime_error("curl_escape failed!");
string ret = escaped;
curl_free(escaped);
return ret;
}
size_t my_write_function(const void * indata, const size_t size, const size_t count, void *out) {
(*(string*)out).append((const char*)indata, size*count);
return size * count;
}
int main()
{
string username;
string password;
cout << "Username: ";
getline(cin, username);
cout << "Password: ";
getline(cin, password);
/*------------------------------------------*/
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_URL, "https://urlto/index.html");
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, string("uname=" + urlencode(username) + "&password=" + urlencode(password)).c_str());
string response;
curl_easy_setopt(curl, CURLOPT_URL, "https://urlto/check.php");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_function);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
//cout << "Response from website: " << response << endl;
if (response.find("true") == string::npos) {
cout << "Failed to login";
}
else cout << "Log in successful";
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
i dont even know if im doing properly. - well, there's certainly a couple of bugs in your code,
first, what do you think happens if the username is longer than 20 bytes, or the password is longer than 25 bytes? try
string username;
getline(cin, username);
instead. c++ will keep increasing the size of username as needed until you run out of ram, as it should be.
and i see you're using CURLOPT_POSTFIELDS (and wrongly), until you know what you're doing, i recommend you use CURLOPT_COPYPOSTFIELDS instead. (btw i pretty much always use COPYPOSTFIELDS myself) this line is wrong:
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "uname=?&password=?", username, password);`
because curl_easy_setopt() only accepts 3 parameters, but you're trying to give it 5. i don't think that will even compile, but even if it does, it certainly shouldn't work at runtime.
try instead something like:
string urlencode(const string& str)
{
char *escaped = curl_escape(str.c_str(), str.length());
if (unlikely(escaped==NULL))
{
throw runtime_error("curl_escape failed!");
}
string ret = escaped;
curl_free(escaped);
return ret;
}
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, string("uname="+urlencode(username)+"&password="+urlencode(password)).c_str());
as for reading (and capturing) the output, there's lots of ways to do it, but how about hooking the CURLOPT_WRITEFUNCTION? that tends to work, something like:
size_t my_write_function( const void * indata, const size_t size, const size_t count, void *out){
(*(string*)out).append((const char*)indata,size*count);
return size*count;
}
then
string response;
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,my_write_function);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response);
res = curl_easy_perform(curl);
cout << "response from website: " << response << endl;
now you can check if you logged in or not by check checking for the existence of the string "true" in the response (because it should respond something like {validated:true} if you are), eg
if(response.find("true")==string::npos){
cout << "failed to authenticate!";
}else{
cout << "authenticated successfully!";
}
(and a warning, while it may be tempting to use a lambda callback with CURLOPT_WRITEFUNCTION, it's a trap, c++ lambdas may crash when given to curl as callbacks... been there, done that.)
I am trying to encrypt and decrypt a communication between a C++ library and a PHP server using OPENSSL library in both of them. I want to use the Blowfish CBC algorithm but it seems that the results are different between the C++ code and the PHP code. The C++ code is taken from here:
This is the PHP code:
<?php
function strtohex($x)
{
$s='';
foreach (str_split($x) as $c) $s.=sprintf("%02X",ord($c));
return($s);
}
$encryptedMessage = openssl_encrypt("input", "BF-CBC", "123456", 0, "initvect");
echo $encryptedMessage;
echo "\n";
echo strtohex($encryptedMessage);
The PHP output is this:
x9jDa2WMwvQ=
78396A446132574D7776513D
This is the c++ code:
bool do_encrypt(const char *in, unsigned char *out, int *outlen, unsigned char *key, unsigned char *iv)
{
int buflen, tmplen;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), nullptr, key, iv);
if (!EVP_EncryptUpdate(&ctx, out, &buflen, (unsigned char*)in, strlen(in)))
{
return false;
}
if (!EVP_EncryptFinal_ex(&ctx, out + buflen, &tmplen))
{
return false;
}
buflen += tmplen;
*outlen = buflen;
EVP_CIPHER_CTX_cleanup(&ctx);
return true;
}
unsigned char output[2048] = { 0 };
int outLen;
auto result = do_encrypt("input", output, &outLen, (unsigned char*)"123456", (unsigned char*)"initvect");
BIGNUM *outputStr = BN_new();
BN_bin2bn(output, outLen, outputStr);
cout << base64_encode(output, outLen) << "\n";
cout << BN_bn2hex(outputStr) << "\n";
The C++ output is this:
EfRhhWqGmSQ=
11F461856A869924
Can someone please help me understand what I'm doing wrong? Any help will be very much appreciated.
Thanks!
Edit 1:
I managed to fix the C++ code after jww's answer and it worked well. I was missing the EVP_CIPHER_CTX_set_key_length However, I couldn't make the PHP code return the same thing and eventually we decided to move to AES and it now works flawlessly. Thanks!
For your OpenSSL code, I believe you need to call EVP_CIPHER_CTX_set_key_length to tell the library the key is only 6 bytes.
Let me throw Crypto++ into the arena below. OpenSSL and Crypto++ will converge on the right answer once you add the missing EVP_CIPHER_CTX_set_key_length OpenSSL call. The right answer is 32CEBA7E046431EB (in hex).
I don't know what's going on with PHP:
x9jDa2WMwvQ=
78396A446132574D7776513D
Considering x is ASCII 0x78, 9 is ASCII 0x39, I'm guessing you hex encoded the Base64 string.
$ cat test.cxx
#include "blowfish.h"
#include "modes.h"
#include "channels.h"
#include "filters.h"
#include "base64.h"
#include "hex.h"
using namespace CryptoPP;
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
const byte key[] = "123456"; // 6
const byte iv[] = "initvect"; // 8
CBC_Mode<Blowfish>::Encryption encryptor;
encryptor.SetKeyWithIV(key, 6, iv, 8);
string r1, r2;
ChannelSwitch chsw;
Base64Encoder e1(new StringSink(r1));
HexEncoder e2(new StringSink(r2));
chsw.AddDefaultRoute(e1);
chsw.AddDefaultRoute(e2);
string msg = "input";
StringSource ss(msg, true,
new StreamTransformationFilter(encryptor,
new Redirector(chsw)));
cout << r1 << endl;
cout << r2 << endl;
return 0;
}
The test program results in:
$ ./test.exe
Ms66fgRkMes=
32CEBA7E046431EB
Here's the OpenSSL portion of things. Notice EVP_EncryptInit_ex is called twice. First, EVP_EncryptInit_ex is called to set the block cipher EVP_bf_cbc. The key length is set with EVP_CIPHER_CTX_set_key_length. Then second, EVP_EncryptInit_ex is called to set the key and iv.
#include <openssl/evp.h>
#include <iostream>
#include <iomanip>
#include <stdexcept>
using namespace std;
typedef unsigned char byte;
int main()
{
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
int rc;
const byte key[] = "123456"; // 6
const byte iv[] = "initvect"; // 8
rc = EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, 0, 0);
if (rc != 1)
throw runtime_error("EVP_EncryptInit_ex failed");
rc = EVP_CIPHER_CTX_set_key_length(&ctx, 6);
if (rc != 1)
throw runtime_error("EVP_CIPHER_CTX_set_key_length failed");
rc = EVP_EncryptInit_ex(&ctx, NULL, NULL, key, iv);
if (rc != 1)
throw runtime_error("EVP_EncryptInit_ex failed");
const byte msg[] = "input";
byte buf[32];
int len1 = sizeof(buf), len2 = sizeof(buf);
rc = EVP_EncryptUpdate(&ctx, buf, &len1, msg, 5);
if (rc != 1)
throw runtime_error("EVP_EncryptUpdate failed");
rc = EVP_EncryptFinal_ex(&ctx, buf+len1, &len2);
if (rc != 1)
throw runtime_error("EVP_EncryptFinal_ex failed");
for(unsigned int i=0; i<len1+len2; i++)
cout << std::hex << setw(2) << setfill('0') << (int)buf[i];
cout << endl;
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
I'm trying to send data with curl to my PHP file and then I can do all the other actions like hashing password/data with salt, running database queries eco. It seems to work fine, but there's only one problem. I'm not sure how to secure it, with an authorization token for example. I want to be able to query data from my PHP file using the written application only. I can see how this would become a problem, if people had access to the link through web browser for example.
I've included my code below, if someone needs something similar.
main.cpp
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <curl/curl.h>
#include <sha.h>
#include <hex.h>
using namespace std;
using namespace CryptoPP;
size_t size = 0;
size_t write_to_string(void *ptr, size_t size, size_t count, void *stream) {
((string*)stream)->append((char*)ptr, 0, size*count);
return size*count;
}
template <class T>
string QueryDB(initializer_list<T> list) // Use initialize_list to query an undefined number of params
{
CURL *curl;
CURLcode res;
string submitdata = "", query_result;
int i = 1;
for (auto elem : list) // For each param append to the submitdata string
{
if (i == 1) { // If first param, we append "?"
string d = "?" + to_string(i) + "=" + elem;
submitdata.append(d);
} else if (i > 1) { // If not first param, we append "&" as it's the second, third, fourth ... param
string d = "&" + to_string(i) + "=" + elem;
submitdata.append(d);
}
i++;
}
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
string loginurl = string("http://localhost/login.php");
curl_easy_setopt(curl, CURLOPT_USERPWD, "randomhttpuser:randomhttppassword");
curl_easy_setopt(curl, CURLOPT_URL, (loginurl + submitdata).c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &query_result);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
else {
query_result = "CONNECTION FAILED";
}
curl_global_cleanup();
return query_result;
}
string SHA256Hash(string input)
{
SHA256 hash;
string hashed_input;
StringSource ss(input, true, new HashFilter(hash, new HexEncoder(new StringSink(hashed_input))));
return hashed_input;
}
int main()
{
string username = "testuser";
string raw_password = "testpass";
// Hash password and send it as a query to PHP file
// query_result will hold the value of REQUEST response
auto hashed_password = SHA256Hash(raw_password);
auto query_result = QueryDB({ username, hashed_password });
cout << "=========================================== [ POST ] ===========================================" << endl;
cout << "User: " << username.c_str() << endl;
cout << "Raw Password: " << raw_password.c_str() << endl;
cout << "Hashed password: " << hashed_password.c_str() << endl;
cout << "========================================== [ REQUEST ] =========================================" << endl;
cout << query_result.c_str() << endl;
Sleep(15 * 1000);
return 0;
}
login.php
<?php
$reqparams = array();
function AddStringToArray($name,$string) {
global $reqparams;
$reqparams[$name] = $string;
}
/* Check if specified param exists in reqparams array */
function GetRequestParam($value) {
global $reqparams;
if (array_key_exists($value, $reqparams)) {
$returnvalue = $reqparams[$value];
} else {
$returnvalue = "INVALID PARAMETER";
}
return $returnvalue;
}
$authuser = "randomhttpuser";
$authpw = "randomhttppassword";
$authorized = False;
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Failed to authorize!';
exit;
} else {
if($_SERVER['PHP_AUTH_USER'] == $authuser && $_SERVER['PHP_AUTH_PW'] == $authpw)
{
$authorized = True;
} else {
$authorized = False;
die('Failed to authorize!');
}
}
if($authorized == True)
{
/* Store each REQUEST and it's value in the $reqparams array using AddStringToArray function */
foreach ($_REQUEST as $key => $value)
{
$value = addslashes($value);
$value = strip_tags($value);
AddStringToArray($key, $value);
}
/* You should remember in which order you called the params in your REQUEST query or if you really want, you can just use:
$variable = $_REQUEST['param_name'];
However, if an undefined param is specified, it will result in an warning and ruin your output, if you manually parse it */
$user = GetRequestParam(1);
$pass = GetRequestParam(2);
/* GetRequestParam returns 'INVALID_PARAMETER' instead of a warning that an undefined param was requested */
$invalid_param = GetRequestParam(42);
/* Re-hash password with a salt that's stored in the PHP file only, before using or comparing it to the value stored in database or doing whatever else */
$salt = $user . $pass . "secretkey42";
$salt_hashed_passsword = strtoupper(hash('sha256', $salt));
echo "User: $user";
echo "\nHashed Password: $salt_hashed_passsword (Salt)";
}
?>
Edit: I could use HTTP header, but isn't it possible to reverse my application and abuse it?
Edit: I currently decided to use HTTP authentication as a temporary measure.
I stored a random generated username and password in my PHP file and compare them to the PHP_AUTH_USER/PW which are sent in the HTTP header from my cpp application using CURLOPT_USERPWD:
curl_easy_setopt(curl, CURLOPT_USERPWD, "randomhttpusername:randomhttppassword");
Hopefully, this will at least make it a bit harder for the hacker. First he will have to RE my application to get the the user/password and even after that he can only query the response if password belongs to specified user or not - since most of my queries are hard coded. You could even store the number of failed logins and temporarily ban him for x amount of time. Rest of the queries are made after login returns true.
I've also updated the code above to use the changes I've made and added some comments if you're too lazy to go over the code line-by-line. Feel free to give me some tips on how to improve the code or optimize for better use.
From what I understood, you want to implement a some sort of login system using auth tokens. In this case, OAuth can do the job. Here's a tutorial written on SitePoint that can guide you through the process.
What will be the C++ equivalemt command for below mentioned php command:
$command = shell_exec("sqlldr {$connect_string} control={$ctl_file_name} log={$log_file_name}");
So based on your comments a solution that would work would be to use popen(3):
#include <cstdio>
#include <iostream>
#include <string>
int main()
{
// Set file names based on your input etc... just using dummies below
std::string
ctrlFileName = "file1",
logFileName = "file2",
cmd = "sqlldr usr/pwd#LT45 control=" + ctrlFileName + " log=" + logFileName ;
std::cout << "Executing Command: " << cmd << std::endl ;
FILE* pipe = popen(cmd.c_str(), "r");
if (pipe == NULL)
{
return -1;
}
char buffer[128];
std::string result = "";
while(!feof(pipe))
{
if(fgets(buffer, 128, pipe) != NULL)
{
result += buffer;
}
}
std::cout << "Results: " << std::endl << result << std::endl ;
pclose(pipe);
}
Try forkpty, you get a file descriptor which you can use to read from the other pseudoterminal.
This is my c++ code:
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QFile>
#include <QByteArray>
QByteArray UnZip (QString zipfilename)
{
QFile infile(zipfilename);
infile.open(QIODevice::ReadOnly);
//QByteArray uncompressedData = infile.readAll();
QByteArray uncompressedData = qUncompress(infile.readAll());
infile.close();
return uncompressedData;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//QString path = "/Users/davide/Desktop/fh8RkbUf";
QString path = "/Users/davide/Desktop/test";
QByteArray data = UnZip(path);
qDebug() << "message";
return a.exec();
}
; that returns qUncompress: Z_DATA_ERROR: Input data is corrupted
However, data should be zlib compressed and php's gzuncompress($data) works fine.
Also, cat file | uncompress returns errors.
The code php side is
$data = gzcompress($data, 6);
$success = file_put_contents($file, $data);