downloading zip file from buffer to zip file in C++ - c++11

I am trying to download a file from internet in C++. Hold the downloaded contents into HInternet Instance.
Also I populated the header information of HInternet instance. That is looks like
Header contents:
HTTP/1.1 200 OK
Cache-Control: no-cache
Date: Fri, 24 Nov 2017 07:00:26 GMT
Pragma: no-cache
Content-Length: 71156
Content-Type: text/html
Expires: -1
Server: Microsoft-IIS/8.0
Content-Disposition: attachment; filename=642078_3855u.zip
X-AspNet-Version: 4.0.30319
Error 0 has occurred.
Now I am trying to copied the 642088_3855u.zip file into some location.
So, I tried as,
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
dwLastError = GetLastError();
break;
}
// No more available data.
if (!dwSize)
break;
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
bError = true;
break;
}
FILE *pfDestination = NULL;
_wfopen_s(&pfDestination, strDestinationFolder + L"\\" + L"642078_3855u.zip", L"w+b");
if (pfDestination == NULL)
{
bError = true;
break;
}
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
{
fwrite(pszOutBuffer, 1, dwDownloaded, pfDestination);
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
fclose(pfDestination);
// reported that there are bits to read.
if (!dwDownloaded)
break;
} while (dwSize > 0);
}
I am not getting any error, actual size of zip if is 72kb but it is created zip file with 4kb and when I am trying to open zip file, I am getting error Invalid zip file.
Note that: zip file contains executable also.
any suggestion where I am doing mistake.
Thanks,

Related

HTTP Error 500 with Dokuwiki LDAP on signin

My company is using the OpenLDAP plugin for Dokuwiki to secure our admin page. We originally had some setbacks when converting the wiki from an Arch Linux environment to a Windows environment because of configuration issues that I thought were solved. Then, we started getting issues with the LDAP's auth.php, specifically a missing argument error on our TLS error checking code. I fixed that, but now I am stuck with an HTTP Error 500 upon login. What else needs to be done to fix it? My local.php code is below:
`$conf['plugin']['authldap']['debug'] = 1;
$conf['plugin']['authldap']['modPass'] = 1;
//rest of LDAP stuff here
$conf['plugin']['authldap']['server'] = 'myserver'; //Alyse's edits
$conf['plugin']['authldap']['port'] = 389;
$conf['plugin']['authldap']['binddn'] = '%{user}#%{server}'; //Alyse's edits
$conf['plugin']['authldap']['usertree'] = 'dc=mydomain, dc=edu'; //Alyse's edits
$conf['plugin']['authldap']['grouptree'] = 'dc=mydomain, dc=edu'; //Alyse's edits
$conf['plugin']['authldap']['userfilter'] = '(userPrincipalName=%{user}#%{server})'; //Alyse's edits
$conf['plugin']['authldap']['groupfilter'] = '(&(cn=*)(Member=%{dn})(objectClass=group))'; //Alyse's edits
$conf['plugin']['authldap']['version'] = 3; //Alyse's edits
$conf['plugin']['authldap']['referrals'] = -1; //Alyse's edits
$conf['plugin']['authldap']['starttls'] = 1; //Alyse's edits
$conf['plugin']['authldap']['mapping']['name'] = 'displayname'; //Alyse's edits
$conf['plugin']['authldap']['mapping']['grps'] = array('memberof' => '/CN=(.+?),/i'); //Alyses edits
$conf['plugin']['authldap']['userscope'] = 'sub'; //Alyse's edits
$conf['plugin']['authldap']['groupscope'] = 'sub'; //Alyse's edits
$conf['plugin']['authldap']['userkey'] = 'uid';
$conf['plugin']['authldap']['groupkey'] = 'cn';
$conf['plugin']['authsplit']['debug'] = 1;`
The auth.php code is below as well. It is all under the protected function _openLDAP():
`if($this->getConf('version')) {
if(!#ldap_set_option(
$this->con, LDAP_OPT_PROTOCOL_VERSION,
$this->getConf('version')
)
) {
msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
$this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
} else {
//use TLS (needs version 3)
if($this->getConf('starttls')) {
if(!#ldap_start_tls($this->con)) {
msg('Starting TLS failed', -1);
$this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
}
}
// needs version 3
if($this->getConf('referrals') > -1) {
if(!#ldap_set_option(
$this->con, LDAP_OPT_REFERRALS,
$this->getConf('referrals')
)
) {
msg('Setting LDAP referrals failed', -1);
$this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
}`
UPDATE: I am more specifically getting a 0x80070102 error on my php handler. It says that C:\php\php-cgi.exe - The FastCGI process exceeded configuring activity timeout.

QHttpMultiPart generates different boundary

When I try to upload files by QHttpMultiPart, there appears a problem. I use the CommonsMultipartResolver.isMultipart() to validate the request, and it returns false.
So I capture frame by Wireshark, and I found an interesting thing: the boundaries in the frame are all different.
Here is my client code
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart zipPart;
zipPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/zip"));
zipPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\""));
QFile *file = new QFile(pakPath);
file->open(QIODevice::ReadOnly);
zipPart.setBodyDevice(file);
multiPart->append(zipPart);
QNetworkRequest *request = new QNetworkRequest(QUrl(url));
manager->put(*request, multiPart);
And the server code
CommonsMultipartResolver(request.getSession().getServletContext());
if( multipartResolver.isMultipart(request) ) { // here return false
...
I have two questions:
Q1: Is the different boundary make itself be an abnormal in CommonsMultipartResolver?
Q2: Is Different boundary normal or Qt make mistake?
I have a same problem too , my boundary supposed whitout "" ,
I find the source code about QHttpMultiPart class , I found that qt has force set "" by hand . so whatever we set , it will always with "".
qt QHttpMultiPart source code
<pre><code>QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
{
// copy the request, we probably need to add some headers
QNetworkRequest newRequest(request);
// add Content-Type header if not there already
if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
QByteArray contentType;
contentType.reserve(34 + multiPart->d_func()->boundary.count());
contentType += "multipart/";
switch (multiPart->d_func()->contentType) {
case QHttpMultiPart::RelatedType:
contentType += "related";
break;
case QHttpMultiPart::FormDataType:
contentType += "form-data";
break;
case QHttpMultiPart::AlternativeType:
contentType += "alternative";
break;
default:
contentType += "mixed";
break;
}
// putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
}
// add MIME-Version header if not there already (we must include the header
// if the message conforms to RFC 2045, see section 4 of that RFC)
QByteArray mimeHeader("MIME-Version");
if (!request.hasRawHeader(mimeHeader))
newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
QIODevice *device = multiPart->d_func()->device;
if (!device->isReadable()) {
if (!device->isOpen()) {
if (!device->open(QIODevice::ReadOnly))
qWarning("could not open device for reading");
} else {
qWarning("device is not readable");
}
}
return newRequest;
}
</code></pre>
I tried to inherit QHttpMultiPart and rewrite the QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart) function , but it seems too bother to do.
finally , I found a simple way to solve that , it just need to reset boundary paramter agian , that before you post data. it worked. here is my code
<pre><code>
void PeddingBizUI::ossUploadPicture_post(PolicyInfo policy, QString pathName)
{
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart keyPart;
QString fileName = getFileNameFromPath(pathName);
keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-
data; name=\"key\""));
QByteArray ba = QByteArray(QString(policy.dir +
fileName).toStdString().data());
qDebug()<<ba;
keyPart.setBody(ba);
QHttpPart policyPart;
policyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"policy\""));
policyPart.setBody(policy.policy.toStdString().data());
QHttpPart SignaturePart;
SignaturePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"Signature\""));
SignaturePart.setBody(policy.signature.toStdString().data());
QHttpPart OSSAccessKeyIdPart;
OSSAccessKeyIdPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"OSSAccessKeyId\""));
OSSAccessKeyIdPart.setBody(policy.accessId.toStdString().data());
QHttpPart success_action_statusPart;
success_action_statusPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"success_action_status\""));
success_action_statusPart.setBody(QByteArray::number(200));
QHttpPart aclPart;
aclPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-
data; name=\"x-oss-object-acl\""));
aclPart.setBody("public-read");
QHttpPart imagePart;
QString str = QString("form-data; name=\"file\";
filename=\"%1\"").arg(fileName);
qDebug()<<fileName;
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(str));
//不可调换header的先后顺序否则导致
imagePart.setHeader(QNetworkRequest::ContentTypeHeader,
QVariant("image/jpeg")); //请求失败, 提示body data not well formed 失
败
QFile *fileOpen = new QFile(pathName);
fileOpen->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(fileOpen);
fileOpen->setParent(multiPart); // we cannot delete the file now, so delete it
with the multiPart
multiPart->append(keyPart);
multiPart->append(policyPart);
multiPart->append(SignaturePart);
multiPart->append(OSSAccessKeyIdPart);
multiPart->append(success_action_statusPart);
//multiPart->append(aclPart);
multiPart->append(imagePart);
quint32 random[6];
QRandomGenerator::global()->fillRange(random);
QByteArray boundary = "--boundary_zyl_"
+ QByteArray::fromRawData(reinterpret_cast<char *>(random),
sizeof(random)).toBase64();
QUrl url(policy.host);
// QUrl url("http://arithmetic-oss.oss-cn-shenzhen.aliyuncs.com");
QNetworkRequest request(url);
QByteArray contentType;
contentType += "multipart/";
contentType += "form-data";
contentType += "; boundary=";
contentType += boundary;
multiPart->setBoundary(boundary);
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
QNetworkReply *reply = m_netUtils.m_manager->post(request, multiPart);
connect(reply, &QNetworkReply::finished, this, [this, multiPart](){
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
qDebug()<<"ossUploadPicture_post response";
onOssUploadPictureResponse(reply);
multiPart->setParent(reply); //内存泄露
reply->deleteLater();
});
// delete the multiPart with the reply
}</code></pre>
and then problem solved.

Reading boost::asio::streambuf yields bad data

I'm using boost::asio to create a TCP client. I'm testing it out by loading a web site. I can create a connection, read, have my callback fired, etc, no problem. However, at the of every packet, I'm finding this, or something like it:
ýýýý««««««««îþîþ
I'm wondering how I can determine the size of what was actually read. In the code below, assume my socket is set up properly. I've connected to a URL (a plain old web site), sent a request, and have started reading. When I read the data, I get the data back, plus some extra weirdness.
class TcpClient
{
...
boost::asio::streambuf mResponse;
std::shared_ptr<boost::asio::ip::tcp::socket> mSocket;
...
void read()
{
boost::asio::async_read( *mSocket, mResponse,
boost::asio::transfer_at_least( 1 ),
boost::bind( &TcpClient::onRead, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred ) );
}
void onRead( const boost::system::error_code& err, size_t bytesTransferred )
{
if ( err ) {
if ( err == boost::asio::error::eof ) {
cout << "Read complete" << endl;
} else {
cout << "Error" << endl;
}
} else {
char* data = new char[ bytesTransferred ];
istream stream( &mResponse );
stream.read( data, bytesTransferred );
cout << data << endl;
delete [] data;
read();
}
mResponse.consume( mResponse.size() );
}
...
};
Below is the result of the first packet I receive from http://libcinder.org.
HTTP/1.1 200 OK
Server: nginx/0.5.33
Date: Fri, 24 May 2013 01:05:55 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Vary: Cookie
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Cinder | The library for professional-quality creative coding in C++</title>
<meta name="Descýýýý««««««««îþîþ
Answer came via Igor R.
This...
char* data = new char[ bytesTransferred ];
...should be...
char* data = new char[ bytesTransferred + 1 ];
data[ bytesTransferred ] = 0;

Why can't I upload using Windows Phone 7 FTP app

I want to upload a photo, from the WP7 by FTP application. If I choose the photo, and click the upload button, the server response: 503 bad sequence of commands.
public static void UploadFile(Stream file, string RemoteFile)
{
SocketAsyncEventArgs socketEventArg2 = new SocketAsyncEventArgs();
Socket socket2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int bytes;
Execute("STOR " + RemoteFile);
AutoResetEvent sendCompleted = new AutoResetEvent(false);
socketEventArg2.Completed += delegate {
sendCompleted.Set();
};
file.Seek(0, SeekOrigin.Begin);
while ((bytes = file.Read(buffer2, 0, buffer2.Length)) > 0)
{
socketEventArg2.SetBuffer(buffer2, 0, bytes);
socket2.SendAsync(socketEventArg2);
sendCompleted.WaitOne();
}
file.Close();
}
And this method call:
Stream ss = e.ChosenPhoto;
.
.
for (int i = 0; i < library.Pictures.Count; i++)
{
Stream s = library.Pictures[i].GetImage();
if (s.Length == e.ChosenPhoto.Length)
{
string filename = library.Pictures[i].Name;
MessageBoxResult m = MessageBox.Show(filename, "Upload?", MessageBoxButton.OKCancel);
if (m == MessageBoxResult.OK)
{
Ftp.UploadFile(ss, filename);
}
else
{
return;
}
break;
}
}
The ss variable is a Stream type, the filename variable is a String which is name come into being the remote server.
You have to do more than just call STOR with FTP -- file transfers occur over a separate connection than the command connection. See the response to this question for additional details.
Edit
I just noticed this is for WP7. It looks like you're trying to implement FTP on WP7. Boy are you in for a world of hurt. I have a few suggestions you may consider:
First, the easy, but expensive-up-front way: purchase a third party library that does FTP over sockets such as SecureBlackbox.
Second, the more complex, cheaper-initially-but-possibly-more-expensive-long-term way: consider creating an intermediary web service that accepts the file as a WEB request, then transfers the file using FtpWebRequest server-side. Azure will be your friend there, at least until the uploads start sapping bandwidth.
Third, don't support FTP until FtpWebRequest becomes available for WP7.

How can I save a base64-encoded image to disk?

My Express app is receiving a base64-encoded PNG from the browser (generated from canvas with toDataURL() ) and writing it to a file. But the file isn't a valid image file, and the "file" utility simply identifies it as "data".
var body = req.rawBody,
base64Data = body.replace(/^data:image\/png;base64,/,""),
binaryData = new Buffer(base64Data, 'base64').toString('binary');
require("fs").writeFile("out.png", binaryData, "binary", function(err) {
console.log(err); // writes out file without error, but it's not a valid image
});
I think you are converting the data a bit more than you need to. Once you create the buffer with the proper encoding, you just need to write the buffer to the file.
var base64Data = req.rawBody.replace(/^data:image\/png;base64,/, "");
require("fs").writeFile("out.png", base64Data, 'base64', function(err) {
console.log(err);
});
new Buffer(..., 'base64') will convert the input string to a Buffer, which is just an array of bytes, by interpreting the input as a base64 encoded string. Then you can just write that byte array to the file.
Update
As mentioned in the comments, req.rawBody is no longer a thing. If you are using express/connect then you should use the bodyParser() middleware and use req.body, and if you are doing this using standard Node then you need to aggregate the incoming data event Buffer objects and do this image data parsing in the end callback.
this is my full solution which would read any base64 image format and save it in the proper format in the database:
// Save base64 image to disk
try
{
// Decoding base-64 image
// Source: http://stackoverflow.com/questions/20267939/nodejs-write-base64-image-file
function decodeBase64Image(dataString)
{
var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
var response = {};
if (matches.length !== 3)
{
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
return response;
}
// Regular expression for image type:
// This regular image extracts the "jpeg" from "image/jpeg"
var imageTypeRegularExpression = /\/(.*?)$/;
// Generate random string
var crypto = require('crypto');
var seed = crypto.randomBytes(20);
var uniqueSHA1String = crypto
.createHash('sha1')
.update(seed)
.digest('hex');
var base64Data = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAZABkAAD/4Q3zaHR0cDovL25zLmFkb2JlLmN...';
var imageBuffer = decodeBase64Image(base64Data);
var userUploadedFeedMessagesLocation = '../img/upload/feed/';
var uniqueRandomImageName = 'image-' + uniqueSHA1String;
// This variable is actually an array which has 5 values,
// The [1] value is the real image extension
var imageTypeDetected = imageBuffer
.type
.match(imageTypeRegularExpression);
var userUploadedImagePath = userUploadedFeedMessagesLocation +
uniqueRandomImageName +
'.' +
imageTypeDetected[1];
// Save decoded binary image to disk
try
{
require('fs').writeFile(userUploadedImagePath, imageBuffer.data,
function()
{
console.log('DEBUG - feed:message: Saved to disk image attached by user:', userUploadedImagePath);
});
}
catch(error)
{
console.log('ERROR:', error);
}
}
catch(error)
{
console.log('ERROR:', error);
}
This did it for me simply and perfectly.
Excellent explanation by Scott Robinson
From image to base64 string
let buff = fs.readFileSync('stack-abuse-logo.png');
let base64data = buff.toString('base64');
From base64 string to image
let buff = Buffer.from(data, 'base64');
fs.writeFileSync('stack-abuse-logo-out.png', buff);
UPDATE
I found this interesting link how to solve your problem in PHP. I think you forgot to replace space by +as shown in the link.
I took this circle from http://images-mediawiki-sites.thefullwiki.org/04/1/7/5/6204600836255205.png as sample which looks like:
Next I put it through http://www.greywyvern.com/code/php/binary2base64 which returned me:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAB3RJTUUH1QEHDxEhOnxCRgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAXBJREFUeNrtV0FywzAIxJ3+K/pZyctKXqamji0htEik9qEHc3JkWC2LRPCS6Zh9HIy/AP4FwKf75iHEr6eU6Mt1WzIOFjFL7IFkYBx3zWBVkkeXAUCXwl1tvz2qdBLfJrzK7ixNUmVdTIAB8PMtxHgAsFNNkoExRKA+HocriOQAiC+1kShhACwSRGAEwPP96zYIoE8Pmph9qEWWKcCWRAfA/mkfJ0F6dSoA8KW3CRhn3ZHcW2is9VOsAgoqHblncAsyaCgcbqpUZQnWoGTcp/AnuwCoOUjhIvCvN59UBeoPZ/AYyLm3cWVAjxhpqREVaP0974iVwH51d4AVNaSC8TRNNYDQEFdlzDW9ob10YlvGQm0mQ+elSpcCCBtDgQD7cDFojdx7NIeHJkqi96cOGNkfZOroZsHtlPYoR7TOp3Vmfa5+49uoSSRyjfvc0A1kLx4KC6sNSeDieD1AWhrJLe0y+uy7b9GjP83l+m68AJ72AwSRPN5g7uwUAAAAAElFTkSuQmCC
saved this string to base64 which I read from in my code.
var fs = require('fs'),
data = fs.readFileSync('base64', 'utf8'),
base64Data,
binaryData;
base64Data = data.replace(/^data:image\/png;base64,/, "");
base64Data += base64Data.replace('+', ' ');
binaryData = new Buffer(base64Data, 'base64').toString('binary');
fs.writeFile("out.png", binaryData, "binary", function (err) {
console.log(err); // writes out file without error, but it's not a valid image
});
I get a circle back, but the funny thing is that the filesize has changed :)...
END
When you read back image I think you need to setup headers
Take for example imagepng from PHP page:
<?php
$im = imagecreatefrompng("test.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
I think the second line header('Content-Type: image/png');, is important else your image will not be displayed in browser, but just a bunch of binary data is shown to browser.
In Express you would simply just use something like below. I am going to display your gravatar which is located at http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG
and is a jpeg file when you curl --head http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG. I only request headers because else curl will display a bunch of binary stuff(Google Chrome immediately goes to download) to console:
curl --head "http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG"
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 03 Aug 2011 12:11:25 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Mon, 04 Oct 2010 11:54:22 GMT
Content-Disposition: inline; filename="cabf735ce7b8b4471ef46ea54f71832d.jpeg"
Access-Control-Allow-Origin: *
Content-Length: 1258
X-Varnish: 2356636561 2352219240
Via: 1.1 varnish
Expires: Wed, 03 Aug 2011 12:16:25 GMT
Cache-Control: max-age=300
Source-Age: 1482
$ mkdir -p ~/tmp/6922728
$ cd ~/tmp/6922728/
$ touch app.js
app.js
var app = require('express').createServer();
app.get('/', function (req, res) {
res.contentType('image/jpeg');
res.sendfile('cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG');
});
app.get('/binary', function (req, res) {
res.sendfile('cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG');
});
app.listen(3000);
$ wget "http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG"
$ node app.js
I also had to save Base64 encoded images that are part of data URLs, so I ended up making a small npm module to do it in case I (or someone else) needed to do it again in the future. It's called ba64.
Simply put, it takes a data URL with a Base64 encoded image and saves the image to your file system. It can save synchronously or asynchronously. It also has two helper functions, one to get the file extension of the image, and the other to separate the Base64 encoding from the data: scheme prefix.
Here's an example:
var ba64 = require("ba64"),
data_url = "data:image/jpeg;base64,[Base64 encoded image goes here]";
// Save the image synchronously.
ba64.writeImageSync("myimage", data_url); // Saves myimage.jpeg.
// Or save the image asynchronously.
ba64.writeImage("myimage", data_url, function(err){
if (err) throw err;
console.log("Image saved successfully");
// do stuff
});
Install it: npm i ba64 -S. Repo is on GitHub: https://github.com/HarryStevens/ba64.
P.S. It occurred to me later that ba64 is probably a bad name for the module since people may assume it does Base64 encoding and decoding, which it doesn't (there are lots of modules that already do that). Oh well.
Below function to save files, just pass your base64 file, it return filename save it in DB.
import fs from 'fs';
const uuid = require('uuid/v1');
/*Download the base64 image in the server and returns the filename and path of image.*/
function saveImage(baseImage) {
/*path of the folder where your project is saved. (In my case i got it from config file, root path of project).*/
const uploadPath = "/home/documents/project";
//path of folder where you want to save the image.
const localPath = `${uploadPath}/uploads/images/`;
//Find extension of file
const ext = baseImage.substring(baseImage.indexOf("/")+1, baseImage.indexOf(";base64"));
const fileType = baseImage.substring("data:".length,baseImage.indexOf("/"));
//Forming regex to extract base64 data of file.
const regex = new RegExp(`^data:${fileType}\/${ext};base64,`, 'gi');
//Extract base64 data.
const base64Data = baseImage.replace(regex, "");
const filename = `${uuid()}.${ext}`;
//Check that if directory is present or not.
if(!fs.existsSync(`${uploadPath}/uploads/`)) {
fs.mkdirSync(`${uploadPath}/uploads/`);
}
if (!fs.existsSync(localPath)) {
fs.mkdirSync(localPath);
}
fs.writeFileSync(localPath+filename, base64Data, 'base64');
return filename;
}
You can use a third-party library like base64-img or base64-to-image.
base64-img
const base64Img = require('base64-img');
const data = 'data:image/png;base64,...';
const destpath = 'dir/to/save/image';
const filename = 'some-filename';
base64Img.img(data, destpath, filename, (err, filepath) => {}); // Asynchronous using
const filepath = base64Img.imgSync(data, destpath, filename); // Synchronous using
base64-to-image
const base64ToImage = require('base64-to-image');
const base64Str = 'data:image/png;base64,...';
const path = 'dir/to/save/image/'; // Add trailing slash
const optionalObj = { fileName: 'some-filename', type: 'png' };
const { imageType, fileName } = base64ToImage(base64Str, path, optionalObj); // Only synchronous using
Converting from file with base64 string to png image.
4 variants which works.
var {promisify} = require('util');
var fs = require("fs");
var readFile = promisify(fs.readFile)
var writeFile = promisify(fs.writeFile)
async function run () {
// variant 1
var d = await readFile('./1.txt', 'utf8')
await writeFile("./1.png", d, 'base64')
// variant 2
var d = await readFile('./2.txt', 'utf8')
var dd = new Buffer(d, 'base64')
await writeFile("./2.png", dd)
// variant 3
var d = await readFile('./3.txt')
await writeFile("./3.png", d.toString('utf8'), 'base64')
// variant 4
var d = await readFile('./4.txt')
var dd = new Buffer(d.toString('utf8'), 'base64')
await writeFile("./4.png", dd)
}
run();
Easy way to convert base64 image into file and save as some random id or name.
// to create some random id or name for your image name
const imgname = new Date().getTime().toString();
// to declare some path to store your converted image
const path = yourpath.png
// image takes from body which you uploaded
const imgdata = req.body.image;
// to convert base64 format into random filename
const base64Data = imgdata.replace(/^data:([A-Za-z-+/]+);base64,/, '');
fs.writeFile(path, base64Data, 'base64', (err) => {
console.log(err);
});
// assigning converted image into your database
req.body.coverImage = imgname
is very simple
const path = require('path');
const { readFile, stat, writeFile } = require("fs/promises");
(async () => {
try {
const contents = await readFile(path.join(__dirname, 'clau.jpg'), { encoding: 'base64' });
console.log(contents);
await writeFile(path.join(__dirname, 'claumia.jpg'), Buffer.from(contents, 'base64'));
} catch (error) {
console.log(error)
}
})()

Resources