How to send MySQL backup to email with cronjob - cron

I am trying to automatically backup my database from cPanel using a cronjob. I want to send the database to my email address when the cronjob is run and I have written code (below) but it is still not working.
mysqldump -e --user=username --password='password' dbname | gzip | uuencode sql_backup.gz | mail example#example.com
In my email when cronjob is run I am getting this message:
/usr/local/cpanel/bin/jailshell: mail: command not found
mysqldump: Got errno 32 on write
I have been referring to this article: Automatic MySQL Backup.
I hope you understand my question and help me.
I have also tried with curl but still not working. You can check my steps that I had followed.
First Step: Created mail_alert.sh file and added bellow code.
#!/bin/bash
curl --url "smtps://smtp.gmail.com:465" --ssl-reqd \
--mail-from "example#gmail.com" --mail-rcpt "example#gmail.com" \
--upload-file mail.txt --user "example#gmail.com:mypassword" --insecure
Second Step: Created mail.txt and added below code.
From: "Name" example#gmail.com
To: "Name" example#gmail.com
Subject: Backup completed
The backup has been completed.
Third Step: Added code in command line.
mysqldump -e --user=username --password='password' dbname | gzip | uuencode sql_backup.gz | sh public_html/sql/mail_alert.sh
After this I am getting this message in my mail.
curl: option --ssl-reqd: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
mysqldump: Got errno 32 on write

Looks like mail is not available for you to use or is not installed.
Another option to consider is to using curl to send emails as described here: https://stackoverflow.com/a/16069786/280842
Here's how you could implement this, using code from the link above:
mail_alert.sh file contents
#!/bin/bash
curl --url "smtps://smtp.gmail.com:465" --ssl-reqd \
--mail-from "username#gmail.com" --mail-rcpt "john#example.com" \
--upload-file mail.txt --user "username#gmail.com:password" --insecure
mail.txt file contents
From: "User Name" <username#gmail.com>
To: "John Smith" <john#example.com>
Subject: Backup completed
The backup has been completed.
It's considered a bad security practice to pass
account credentials thru command line arguments. The
above example is for demo purpose only.
Then add your newly created script to your existing cron job
mysqldump -e --user=username --password='password' dbname | gzip | uuencode sql_backup.gz | sh /home/myuser/mail_alert.sh

OK, I will show you how to create a php script that backs up a MySQL database WITHOUT phpMyAdmin and then attaches the .sql file to an email.
Well today I needed to create a little script that backed up a database and then sent it in an email. I found the best way to do this was using the mysqldump program. Usually you have permission to run this program even on a Reseller hosting package.
In linux the program is usually located at
CODE:
/usr/bin/mysqldump
Ok so lets get started.
First of all we need to setup our variables containing MySQL credentials, email addresses to send to, path to store sql file, absolute path to mysqldump program.
CODE:
ini_set("memory_limit","250M"); // We don't want any nasty memory error messages
$SendTo[] = 'myemailaddress#thephpanswers.com'; // This is your email address, you can copy this line and add another recipient
$path = '/home/website/public_html/backupSQL/sql/' // This is the absolute path to where we are going to save the .sql files - please note you should place a .htaccess to deny any users browsing the directory
$tmpFilename = time() .'_mysql.sql'; // This is the tmp filename for the sql, needs to be different everytime
define('mysqlUser','mysqlusername'); // This is the username for the MySQL database
define('mysqlPass','mysqlpassword'); // Password for the username
define('mysqlDatabase','mysqldatabase'); // The database you wish to backup
define('mysqldump','/usr/bin/mysqldump'); // The absolute path to the mysqldump program
Using mysqldump to backup MySQL database:
mysqldump is very easy to use, for more information visit here: http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html
Now we just add the shell_exec to tell mysqldump to backup the database.
CODE:
shell_exec(mysqldump . ' -u ' . mysqlUser .' -p' . mysqlPass .' ' . mysqlDatabase .' > ' . $path .$tmpFilename); // See the > $path . $tmpFilename these are populated from the variables you set above
You can now run this script and see if it actually creates the .sql file in folder you specified.
Sending an attachment in PHP
Ok so we know our file is located at $path . $tmpFilename so lets get on with the complicated emailing of the attachment.
CODE:
$from = "Backup <backup#domain.co.uk>"; // Who the email is coming from
$subject = 'MySQL Database backup'; // The subject of the email
$absoluteFile = $path . $tmpFilename; // Keep it simple, creates a variable of where the file is
$fileType = 'text/plain'; // Content type
$mailBodyText = '<h1>MySQL Database attached</h1>'; // Our HTML body of the email
$mineBoundaryStr=md5(time()); // Needs to be random for the mime
// Advanced headers from http://xahlee.org/php/send_mail_attachment.html
$headers= <<<EEEEEEEEEEEEEE
From: $from
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="$mineBoundaryStr"
EEEEEEEEEEEEEE;
$mailBodyEncodedText = <<<TTTTTTTTTTTTTTTTT
This is a multi-part message in MIME format.
--{$mineBoundaryStr}
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
$mailBodyText
TTTTTTTTTTTTTTTTT;
$file = fopen($absoluteFile,'rb');
$data = fread($file,filesize($absoluteFile));
fclose($file);
$data = chunk_split(base64_encode($data));
$mailBodyEncodedText .= <<<FFFFFFFFFFFFFFFFFFFFF
--$mineBoundaryStr
Content-Type: $fileType;
name=$tmpFilename
Content-Disposition: attachment;
filename="$tmpFilename"
Content-Transfer-Encoding: base64
$data
--$mineBoundaryStr--
FFFFFFFFFFFFFFFFFFFFF;
foreach($SendTo as $k => $v) { // Loop through all our recipients
mail( $v , date("H:i - jS \of F Y") . 'MySQL Database backup' , $mailBodyEncodedText, $headers ); // Send the emails
}
So lets put all the script together and you should have this:
CODE:
<?php ini_set("memory_limit","250M"); // We don't want any nasty memory error messages
$SendTo[] = 'myemailaddress#thephpanswers.com'; // This is your email address, you can copy this line and add another recipient
$path = '/home/website/public_html/backupSQL/sql/' // This is the absolute path to where we are going to save the .sql files - please note you should place a .htaccess to deny any users browsing the directory
$tmpFilename = time() .'_mysql.sql'; // This is the tmp filename for the sql, needs to be different everytime
define('mysqlUser','mysqlusername'); // This is the username for the MySQL database
define('mysqlPass','mysqlpassword'); // Password for the username
define('mysqlDatabase','mysqldatabase'); // The database you wish to backup
define('mysqldump','/usr/bin/mysqldump'); // The absolute path to the mysqldump program
shell_exec(mysqldump . ' -u ' . mysqlUser .' -p' . mysqlPass .' ' . mysqlDatabase .' > ' . $path .$tmpFilename); // See the > $path . $tmpFilename these are populated from the variables you set above
$from = "Backup <backup#domain.co.uk>"; // Who the email is coming from
$subject = 'MySQL Database backup'; // The subject of the email
$absoluteFile = $path . $tmpFilename; // Keep it simple, creates a variable of where the file is
$fileType = 'text/plain'; // Content type
$mailBodyText = '<h1>MySQL Database attached</h1>'; // Our HTML body of the email
$mineBoundaryStr=md5(time()); // Needs to be random for the mime
// Advanced headers from http://xahlee.org/php/send_mail_attachment.html
$headers= <<<EEEEEEEEEEEEEE
From: $from
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="$mineBoundaryStr"
EEEEEEEEEEEEEE;
$mailBodyEncodedText = <<<TTTTTTTTTTTTTTTTT
This is a multi-part message in MIME format.
--{$mineBoundaryStr}
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
$mailBodyText
TTTTTTTTTTTTTTTTT;
$file = fopen($absoluteFile,'rb');
$data = fread($file,filesize($absoluteFile));
fclose($file);
$data = chunk_split(base64_encode($data));
$mailBodyEncodedText .= <<<FFFFFFFFFFFFFFFFFFFFF
--$mineBoundaryStr
Content-Type: $fileType;
name=$tmpFilename
Content-Disposition: attachment;
filename="$tmpFilename"
Content-Transfer-Encoding: base64
$data
--$mineBoundaryStr--
FFFFFFFFFFFFFFFFFFFFF;
foreach($SendTo as $k => $v) { // Loop through all our recipients
mail( $v , date("H:i - jS \of F Y") . 'MySQL Database backup' , $mailBodyEncodedText, $headers ); // Send the emails
}
?>
You really should protect the directory you choose for the .SQL files, this can be done by creating a file named .htaccess and save it in the directory. The contents of the .htaccess are as follows:
CODE:
order allow,deny
deny from all
You can now automate this with a cron job, set the cron job to run the script every day at midnight
I hope this helps some people out there!
PS: After using this script I realised there is no real security on the .sql dumps, I found using openssl or something similiar on .sql files before emailing them it is 100% secure!

Related

Access Azure Blob storage account from azure data factory

I have a folder with list of files in my storage account and having been trying to delete one of the files using pipeline. In-order to get that done I have used "Web" in pipeline, copied the blob storage url and access keys.
Tired using the access keys directly under Headers|Authorization. Also tried the concept of Shared Keys at https://learn.microsoft.com/en-us/azure/storage/common/storage-rest-api-auth#creating-the-authorization-header
Even tried getting this work with curl, but it returned an Authentication Error every time I tried to run
# List the blobs in an Azure storage container.
echo "usage: ${0##*/} <storage-account-name> <container-name> <access-key>"
storage_account="$1"
container_name="$2"
access_key="$3"
blob_store_url="blob.core.windows.net"
authorization="SharedKey"
request_method="DELETE"
request_date=$(TZ=GMT LC_ALL=en_US.utf8 date "+%a, %d %h %Y %H:%M:%S %Z")
#request_date="Mon, 18 Apr 2016 05:16:09 GMT"
storage_service_version="2018-03-28"
# HTTP Request headers
x_ms_date_h="x-ms-date:$request_date"
x_ms_version_h="x-ms-version:$storage_service_version"
# Build the signature string
canonicalized_headers="${x_ms_date_h}\n${x_ms_version_h}"
canonicalized_resource="/${storage_account}/${container_name}"
string_to_sign="${request_method}\n\n\n\n\n\n\n\n\n\n\n\n${canonicalized_headers}\n${canonicalized_resource}\ncomp:list\nrestype:container"
# Decode the Base64 encoded access key, convert to Hex.
decoded_hex_key="$(echo -n $access_key | base64 -d -w0 | xxd -p -c256)"
# Create the HMAC signature for the Authorization header
signature=$(printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | base64 -w0)
authorization_header="Authorization: $authorization $storage_account:$signature"
curl \
-H "$x_ms_date_h" \
-H "$x_ms_version_h" \
-H "$authorization_header" \
-H "Content-Length: 0"\
-X DELETE "https://${storage_account}.${blob_store_url}/${container_name}/myfile.csv_123"
The curl command returns an error:
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:XX
Time:2018-08-09T10:09:41.3394688Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'xxx' is not the same as any computed signature. Server used following string to sign: 'DELETE
You cannot authorize directly from the Data Factory to the storage account API. I suggest that you use an Logic App. The Logic App has built in support for Blob store:
https://learn.microsoft.com/en-us/azure/connectors/connectors-create-api-azureblobstorage
You can call the Logic App from the Data Factory Web Activity. Using the body of the Data Factory request you can pass variables to the Logic app like the blob path.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Rest;
using Microsoft.Azure.Management.ResourceManager;
using Microsoft.Azure.Management.DataFactory;
using Microsoft.Azure.Management.DataFactory.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.WindowsAzure.Storage;
namespace ClearLanding
{
class Program
{
static void Main(string[] args)
{
CloudStorageAccount backupStorageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=yyy;AccountKey=xxx;EndpointSuffix=core.windows.net");
var backupBlobClient = backupStorageAccount.CreateCloudBlobClient();
var backupContainer = backupBlobClient.GetContainerReference("landing");
var tgtBlobClient = backupStorageAccount.CreateCloudBlobClient();
var tgtContainer = tgtBlobClient.GetContainerReference("backup");
string[] folderNames = args[0].Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string folderName in folderNames)
{
var list = backupContainer.ListBlobs(prefix: folderName + "/", useFlatBlobListing: false);
foreach (Microsoft.WindowsAzure.Storage.Blob.IListBlobItem item in list)
{
if (item.GetType() == typeof(Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob))
{
Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob blob = (Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob)item;
if (!blob.Name.ToUpper().Contains("DO_NOT_DEL"))
{
var tgtBlob = tgtContainer.GetBlockBlobReference(blob.Name + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"));
tgtBlob.StartCopy(blob);
blob.Delete();
}
}
}
}
}
}
}
I tried resolving this by compiling the above code and referencing it using custom activity in C# pipeline. The code snippet above transfers files from landing folder to a backup folder and deletes the file from landing

Amazon CloudFront invalidation API

The images used in our application are rendered from Amazon CloudFront.
When an existing image is modified, it does not reflect the image change immediately since CloudFront take around 24 hours to update.
As a workaround, I'm planning to call CreateInvalidation to reflect the file change immediately.
Is it possible to use this invalidation call without SDK?
Using ColdFusion programming language and does not seem to have SDK for this.
You can simply make POST request. Example on PHP from Steve Jenkins
<?php
/**
* Super-simple AWS CloudFront Invalidation Script
* Modified by Steve Jenkins <steve stevejenkins com> to invalidate a single file via URL.
*
* Steps:
* 1. Set your AWS Access Key
* 2. Set your AWS Secret Key
* 3. Set your CloudFront Distribution ID (or pass one via the URL with &dist)
* 4. Put cf-invalidate.php in a web accessible and password protected directory
* 5. Run it via: http://example.com/protected_dir/cf-invalidate.php?filename=FILENAME
* or http://example.com/cf-invalidate.php?filename=FILENAME&dist=DISTRIBUTION_ID
*
* The author disclaims copyright to this source code.
*
* Details on what's happening here are in the CloudFront docs:
* http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html
*
*/
$onefile = $_GET['filename']; // You must include ?filename=FILENAME in your URL or this won't work
if (!isset($_GET['dist'])) {
$distribution = 'DISTRIBUTION_ID'; // Your CloudFront Distribution ID, or pass one via &dist=
} else {
$distribution = $_GET['dist'];
}
$access_key = 'AWS_ACCESS_KEY'; // Your AWS Access Key goes here
$secret_key = 'AWS_SECRET_KEY'; // Your AWS Secret Key goes here
$epoch = date('U');
$xml = <<<EOD
<InvalidationBatch>
<Path>{$onefile}</Path>
<CallerReference>{$distribution}{$epoch}</CallerReference>
</InvalidationBatch>
EOD;
/**
* You probably don't need to change anything below here.
*/
$len = strlen($xml);
$date = gmdate('D, d M Y G:i:s T');
$sig = base64_encode(
hash_hmac('sha1', $date, $secret_key, true)
);
$msg = "POST /2010-11-01/distribution/{$distribution}/invalidation HTTP/1.0\r\n";
$msg .= "Host: cloudfront.amazonaws.com\r\n";
$msg .= "Date: {$date}\r\n";
$msg .= "Content-Type: text/xml; charset=UTF-8\r\n";
$msg .= "Authorization: AWS {$access_key}:{$sig}\r\n";
$msg .= "Content-Length: {$len}\r\n\r\n";
$msg .= $xml;
$fp = fsockopen('ssl://cloudfront.amazonaws.com', 443,
$errno, $errstr, 30
);
if (!$fp) {
die("Connection failed: {$errno} {$errstr}\n");
}
fwrite($fp, $msg);
$resp = '';
while(! feof($fp)) {
$resp .= fgets($fp, 1024);
}
fclose($fp);
print '<pre>'.$resp.'</pre>'; // Make the output more readable in your browser
Some alternatives to invalidating an object are:
Updating Existing Objects Using Versioned Object Names, such as image_1.jpg changing to image_2.jpg
Configuring CloudFront to Cache Based on Query String Parameters such as configuring CloudFront to recognize parameters (eg ?version=1) as part of the filename, therefore your app can reference a new version by using ?version=2 and that forces CloudFront to treat it as a different object
For frequent modifications, I think the best approach is to append a query string to the image url (time stamp or hash value of the object) and configure Cloudfront to forward query strings, which will always return the latest image when query string differs.
For infrequent modifications, apart from SDK, you can use AWS CLI which will also allows to invalidate the cache upon builds, integrating with your CI/CD tools.
E.g
aws cloudfront create-invalidation --distribution-id S11A16G5KZMEQD \
--paths /index.html /error.html

Gmail RESTAPI how to fetch the message body for any mime type message through gmail php api?

I am working on a project to retrieve the gmail inbox messages through GMAIL REST API and populate them into a new user interface that is going to be used for other purpose. This project is in PHP. I am currently using PHP version. This is the code snippet that I am using to retrieve the message body.
$service = new Google_Service_Gmail($client);
$user = 'me';
function get_Message_Body($messageId,$service)
{
$optParamsGet = [];
$optParamsGet['format'] = 'full';
echo "this is optParamsGet";
var_dump($optParamsGet);
$message = $service->users_messages->get('me',$messageId,$optParamsGet);
echo "this is message";
var_dump($message);
echo "<pre>".$message->snippet."</pre>";
$messagePayload = $message->getPayload();
$headers = $message->getPayload()->getHeaders();
$parts = $message->getPayload()->getParts();
$body = $parts[0]['body'];
echo "this is body";
var_dump($body);
$rawData = $body->data;
$sanitizedData = strtr($rawData,'-_', '+/');
$decodedMessage = base64_decode($sanitizedData);
echo $decodedMessage;
}
get_Message_Body($_REQUEST["id"], $service);
However, I see that this code works only for messages with mime/type of multipart/alternative. However, I need to retrieve the message body and attachments for any kind of gmail message. How do I do that. This is the output that I see for a different mime type on the new user interface
The code snippet for retrieving the messages
Here the message body in the snippet, does not pass into the data parameter in the MessagePartBody. Unlike this code which is mime type mulipart/alternative, where the code passes into the message body->parts and rendered on ui.enter image description here

"Host key verification failed" using PHP Script - CentOS

I am trying to create eJabberd users using PHP script.
The following script is working perfectly on my local system(Ubuntu 14.04) :
<?php
error_reporting(E_ALL);
ini_set('display_errors', '-1');
$username = 'userx1';
$password = '123456';
$node = 'localhost';
exec('ssh -t -t <hostname> ejabberdctl register '.$username.' '.$node.' '.$password.' 2>&1', $output, $status);
if($output == 0)
{
echo "User created successfully.";
}
else
{
// Failure, $output has the details
echo '<pre>';
foreach($output as $o)
{
echo $o."\n";
}
echo '</pre>';
}
But when I am trying to run on the server(CentOS).
Its giving me following error :
Host key verification failed.
I tried some solutions like :
https://askubuntu.com/questions/45679/ssh-connection-problem-with-host-key-verification-failed-error
https://www.youtube.com/watch?v=IJj0uD7EgGk
but no success.
Any reference will be very helpful. Thanks in advance.
Found A better way to crate user to eJabberd server.
mod_rest :
https://github.com/processone/ejabberd-contrib/tree/master/mod_rest
Provides you to make REST calls to the server.

Sending fpdf attachments does not work on my linux suse server but it does on my shared hosting account

I have a php program i have developed on the internet. So far i have used a shared hosting package. Everything worked until i moved to a vps (apache2 suse 9.1 plesk) . I have found certain php functions have not been activated. I have solved most of them by using the internet.
My main problem is emailing pdfs with fpdf. i.e
<?php
// download fpdf class (http://fpdf.org)
require("fpdf.php");
// fpdf object
$pdf = new FPDF();
// generate a simple PDF (for more info, see http://fpdf.org/en/tutorial/)
$pdf->AddPage();
$pdf->SetFont("Arial","B",14);
$pdf->Cell(40,10, "this is a pdf example");
// email stuff (change data below)
$to = "steven#siteaddress.co.uk";
$from = "me#domain.com";
$subject = "send email with pdf attachment";
$message = "<p>Please see the attachment.</p>";
// a random hash will be necessary to send mixed content
$separator = md5(time());
// carriage return type (we use a PHP end of line constant)
$eol = PHP_EOL;
// attachment name
$filename = "example.pdf";
// encode data (puts attachment in proper format)
$pdfdoc = $pdf->Output("", "S");
$attachment = chunk_split(base64_encode($pdfdoc));
// main header (multipart mandatory)
$headers = "From: ".$from.$eol;
$headers .= "MIME-Version: 1.0".$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"".$separator."\"".$eol.$eol;
$headers .= "Content-Transfer-Encoding: 7bit".$eol;
$headers .= "This is a MIME encoded message.".$eol.$eol;
// message
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: text/html; charset=\"iso-8859-1\"".$eol;
$headers .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$headers .= $message.$eol.$eol;
// attachment
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: application/octet-stream; name=\"".$filename."\"".$eol;
$headers .= "Content-Transfer-Encoding: base64".$eol;
$headers .= "Content-Disposition: attachment".$eol.$eol;
$headers .= $attachment.$eol.$eol;
$headers .= "--".$separator."--";
// send message
//mail($to, $subject, "", $headers);
if (#mail($to, $subject, "",$headers)) {
echo('<p>Mail sent successfully.</p>');
} else {
echo('<p>Mail could not be sent.</p>');
}
?>
The file above works on my share hosting , but when it comes to sending from my vps i get this error message from my file
Mar 23 19:16:56 h1871885 suhosin[64630]: ALERT - mail() - double newline in headers, possible injection, mail dropped (attacker '86.137.40.199', file '/srv/www/vhosts/sitename.co.uk/httpdocs/main/email.php', line 111)
after much trial, the error is from this line
if (#mail($to, $subject, "",$headers))
If i remove the "", it sends the email on my vps but there is no attachment. this also happens on my shared account. The attachment ends up in the message with a hole load of chars'.
So i def need them in there. does anyone have a clue how to overcome this problem.
many thanks
after setting suhosin.ini to 0
Mar 23 20:52:48 h1871885 suhosin[60778]: ALERT - mail() - double newline in headers, possible injection, mail dropped (attacker '86.137.40.199', file '/srv/www/vhosts/sitename.co.uk/httpdocs/main/email1.php', line 56)
You have an awful lot of .$eol.$eol in your $headers, and I imagine suhosin is forbidding the mail on the second instance. But I presume you've looked enough at RFC2822 to know exactly where you need blank lines in your message formatting, so you can turn off suhosin's mail() protection, assuming you're confident that you don't have any remotely exploitable injection vulnerabilities.

Resources