c++ equivalent for php shell_exec - php

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.

Related

Upload files using QNetworkManager is not woking

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"

OPENSSL Blowfish CBC encryption differs from PHP to C++

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

How to read PHP's -gzcompress- data from c++

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

C++ popen to run PHP

i'm using popenRWE from http://www.jukie.net/bart/blog/popenRWE and making the script below
int pipes[3];
int pid;
const char *const args[] = {
"php ",
NULL
};
pid = popenRWE(pipes, args[0], args);
char *cmd = "<?php echo 'hello world';?> ";
cout << "write: " << write(pipes[0], cmd, strlen(cmd)) << endl;
cout << "err: " << errno << endl;
char res[100];
cout << "read: " << read(pipes[1], res, 100) << endl;
cout << "result: " << res << endl;
when i use cat command, it works, the input is the ouput (that's what cat doing), but using php the read is empty. i have confirmed that php is installed and on my path by running
echo "<?php echo 'hello world';?>" | php
directly on the console, and got the output. Can someone please advise or help on this code? Thanks in advance.
There are three problems with your code:
There is no executable named "php ". There is just "php" (notice that there is no space). The reason why this does not work is beceause popenRWE uses execvp which does not start a shell to execute the command but it expects the filename of the binary you want to executed (it searches for it in $PATH though).
You should close the stdin-filehandle after you've written your data, otherwise you might have to wait indefinitely for the output to be written.
Also you should wait for the php-process to finish using waitpid because otherwise you might "lose" some of the output.
To wrap it up:
int pipes[3];
int pid;
const char *const args[] = {
"php",
NULL
};
pid = popenRWE(pipes, args[0], args);
char *cmd = "<?php echo 'hello world', \"\\n\";?> ";
cout << "write: " << write(pipes[0], cmd, strlen(cmd)) << endl;
cout << "err: " << errno << endl;
close(pipes[0]);
// TODO: proper error handling
int status;
waitpid(pid, &status, 0);
char res[100];
int bytesRead = read(pipes[1], res, (sizeof(res)/sizeof(char))-1);
// zero terminate the string
res[bytesRead >= 0 ? bytesRead : 0] = '\0';
cout << "read: " << bytesRead << endl;
cout << "result: " << res << endl;

How can I handle packed data from Perl/PHP in C++?

I got a problem implementing a PHP programm in C++. It is about the PHP/Perl function unpack. I don't know how to do the follwing in C++ (no problem in reading a file... but how do i unpack("C*") the read contents).
<?php
$file = fopen("bitmaskt.dat", "rb");
//create the data stream
$matrix_x = unpack("C*", fread($file, 286));
$matrix_y = unpack("C*", fread($file, 286));
$mask_data = unpack("C*", fread($file, 286));
$reed_ecc_codewords = ord(fread($file, 1));
$reed_blockorder = unpack("C*", fread($file, 128));
fclose($file);
?>
Currently, I'm very hopeless solving this problem on my own - I'm searching for days, all I found are questions... Is there any free unpack() c++ implementation out there? :-(
Perl's documentation for pack covers the templates used for pack and unpack.
Say you generated bitmaskt.dat with
#! /usr/bin/perl
use warnings;
use strict;
open my $fh, ">", "bitmaskt.dat" or die "$0: open: $!";
my #data = (42) x 286;
print $fh pack("C*" => #data);
print $fh pack("C*" => #data);
print $fh pack("C*" => #data);
print $fh pack("C" => 7);
print $fh pack("C*" => (1) x 128);
close $fh or warn "$0: close";
You might read it with
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
typedef unsigned char datum_t;
typedef std::vector<datum_t> buf_t;
std::istream &read_data(std::istream &in, buf_t &buf, size_t n)
{
std::istreambuf_iterator<char> it(in.rdbuf()), eos;
while (it != eos && n-- != 0)
buf.push_back(static_cast<datum_t>(*it++));
return in;
}
For example:
int main()
{
std::ifstream bm("bitmaskt.dat", std::ifstream::binary | std::ifstream::in);
struct {
buf_t buf;
size_t len;
std::string name;
} sections[] = {
{ buf_t(), 286, "matrix_x" },
{ buf_t(), 286, "matrix_y" },
{ buf_t(), 286, "mask_data" },
{ buf_t(), 1, "reed_ecc_codewords" },
{ buf_t(), 128, "reed_blockorder" },
};
const int n = sizeof(sections) / sizeof(sections[0]);
for (int i = 0; n - i > 0; i++) {
if (!read_data(bm, sections[i].buf, sections[i].len)) {
std::cerr << "Read " << sections[i].name << " failed" << std::endl;
return 1;
}
}
const int codeword = 3;
std::cout << (unsigned int) sections[codeword].buf[0] << '\n';
return 0;
}
Output:
7
I don't know about any general implementation of unpack for C++, but that doesn't seem to be the thing you need anyway.
if matrix_x is defined somewhere as unsigned char matrix_x[286] and you have an opened input stream inFile
then what you need to do is inFile.get(matrix_x, 286). This reads 286 bytes from the input and places them in the array pointed to by matrix_x.

Categories