Send Emails behind the scene with Cron Jobs - php

I have this method to notify "my followers" which is called after a new event has been added. It works but with more than one email makes all the process very slow since the popup waits that all the emails have been sent before showing to the user that the event has been added and the spinning wheel is going forever. I can't think of any way to do it "behind the scene" after the user get the message that the event has been added.
public function notifiedFollowers($creator_id, $type, $event_id){
$query = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
$query->bindParam(1, $creator_id, PDO::PARAM_INT);
$query->execute();
while($row = $query->fetch(PDO::FETCH_OBJ)) {
$creator = new User($creator_id);
$creatorName = $creator->data()->name;
$user = new User($row->followers_id);
$mail = new PHPMailer();
$template = New MailFactory();
$mail->IsSMTP();
$mail->Host = "myHost";
$mail->SMTPAuth = true;
$mail->Username = "myUser";
$mail->Password = "myPassword";
$mail->IsHTML(true);
$mail->From = 'from email';
$mail->FromName = 'from name';
$mail->AddAddress($user->data()->username);
$mail->Subject = 'add subject here';
$mail->Body = $template->notifiedFollowersEmail($creatorName, $user->data()->name, $type, $event_id);
if(!$mail->send()) {
echo $mail->ErrorInfo;
die();
}
}
}
*UPDATE******
I solved the problem using cron jobs. Please check my answer.

I finally found a perfect solution: Cron Job
First of all I created a database where I store the "job" that has to be done
CREATE TABLE IF NOT EXISTS `cron_jobs_new_event` (
`cron_job_id` int(32) NOT NULL AUTO_INCREMENT,
`event_id` int(32) NOT NULL,
`user_id` int(32) NOT NULL,
`notify` int(32) NOT NULL,
`executed` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`cron_job_id`),
KEY `event_id` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Constraints for table `cron_jobs_new_event`
--
ALTER TABLE `cron_jobs_new_event`
ADD CONSTRAINT `cron_jobs_new_fk` FOREIGN KEY (`event_id`) REFERENCES `event` (`event_id`) ON DELETE CASCADE ON UPDATE CASCADE;
I use hostgator so I set up the cron job to run every 15 minutes:
cron.php simply call a method from my class Notification
<?php require 'core/init.php';
$notification = new Notification();
$notification->notifiedFollowers();
and this is my method that does the magic (at least for me ;-)
public function notifiedFollowers(){
$query = $this->_db->prepare("SELECT user_id FROM cron_jobs_new_event WHERE executed = '0' AND notify = '1'");
$query->execute();
while($row = $query->fetch(PDO::FETCH_OBJ)) {
$userCreator = $row->user_id;
$q = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
$q->bindParam(1, $userCreator, PDO::PARAM_INT);
$q->execute();
while($followers = $q->fetch(PDO::FETCH_OBJ)) {
$type='try';
$creator = new User($followers->user_id);
$creatorName = $creator->data()->name;
$userFollower = new User($followers->followers_id);
$mail = new PHPMailer();
$template = New MailFactory();
$mail->IsSMTP();
$mail->Host = "my host";
$mail->SMTPAuth = true;
$mail->Username = "my username";
$mail->Password = "myPassword";
$mail->IsHTML(true);
$mail->From = 'ev';
$mail->FromName = 'Events Team';
$mail->AddAddress($userFollower->data()->username);
$mail->Subject = 'Somebody add a new event!';
$mail->Body = $template->notifiedFollowersEmail($creatorName, $userFollower->data()->name, $type, $followers->event_id);
if(!$mail->send()) {
echo $mail->ErrorInfo;
die();
}
}
//here I update the database so next time the cron runs, It won't send the same message
$update = $this->_db->prepare("UPDATE cron_jobs_new_event SET executed = '1' WHERE cron_job_id = ?");
$update->bindParam(1, $row->cron_job_id, PDO::PARAM_INT);
$update->execute();
}
}
I hope this helps somebody else

You are looking for Threads
<?php
class AsyncEmail extends Thread {
public function __construct($arg){
$this->arg = $arg;
}
public function run() {
/** Add your email sending code here. **/
}
}
// and call this following lines in loop
$aEmail = new AsyncEmail( $arg );
var_dump($aEmail->start());
?>
This code will work asynchronously in the background of your code, and your user will not have to wait for any step to complete.
Have a look at this PHP threading call to a php function asynchronously

Related

Multiple requests being send unintentionally

I am using a PHP Script written by me with AWS (Amazon Web Service) PHP Script to send emails using SMTP
Everytime I run this script, say I have 3 user's in my database, then the first user get's mail of the first, second and third person. The second user get's mail to second and third person. And the third user get's the mail to the third person only.
I don't know why this is happening, and been pulling my hair for some time. Maybe I am missing some point, that is why adding a question here.
Pre-Requisites:
func1() = Is used to get emails from DB whom I have not send Emails Yet, return's a single value (ID) only
func2() = Is used to get the data of that particular user whose ID was found in func1()
func3() = Is used to mark "Send" to that particular ID whom we send the mail.
<?php
require 'aws-autoloader.php';
require 'vendor/autoload.php';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->setFrom('myemail#address.com', 'My Company Name');
$mail->Username = 'Username';
$mail->Password = 'Password';
$mail->Host = 'email-smtp.us-west-2.amazonaws.com';
class Db {
public function dbconnect(){
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
return $conn;
}
public function func1()
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func1()");
$stmt->execute();
$result=NULL;
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
public function func2($id)
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func2(?)");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
public function func3($id)
{
$conn=$this->dbconnect();
$stmt = $conn->prepare("CALL func3(?)");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$item=NULL;
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$item[] = $row;
}
return $item;
$stmt->close();
$conn->close();
}
}
$count=0;
$obj=new Db;
$ids=$obj->func1();
while(($ids[0][0]!=0)&&($count<1000)){
$ids=$obj->func1();
$rslt=$obj->func2($ids[0][0]);
if($rslt[0][0]!=NULL)
{
$idno=$rslt[0][0];
$companyname=$rslt[0][2];
$email=$rslt[0][16];
$complete=NULL;
do{
$mail->addAddress($email, $companyname);
$mail->Subject = 'My Subject';
$mail->Body = '<p>Hello</p>';
$mail->AltBody = "Hello";
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->isHTML(true);
if(!$mail->send()) {
echo "Email not sent. " , $mail->ErrorInfo , PHP_EOL;
} else {
$complete=$obj->func3($ids[0][0]);
}
}while($complete[0][0]!=3);
}
$count=$count+1;
//if($count%10==0) Trying to give a small break after each 10 emails are send
sleep(1);
}
$count=$count-1;
echo 'Email Send to: '.$count.' Users.<br>';
?>
After the function is called, I receive emails as described at the start. And all the users are marked "Send"
Any Idea what I may be doing wrong to get result like that.
Your code is using the same PHPMailer object for each email, and it is adding addresses using $mail->addAddress() without resetting the list of email addresses between emails hence the list of recipients is growing each time.
You can call $mail->clearAllRecipients() for each new email or you could create a new PHPMailer object for each email. Note that if you choose the former approach then you should check to see if there are any other things that also need to be reset from one email to the next.

PDO email verification

I am trying to make a user registration script.
In my registration.php script, I validate user inputs then insert them into database. I then want to send the user a verification link in an email using SMTP with:
$user_activation_hash = sha1(uniqid(mt_rand(), true)); //creating ramdom string
$mail = new PHPMailer;
$mail->IsSMTP();
$mail->CharSet = 'UTF-8';
$mail->Host = "info"; // SMTP server
$mail->Username = "info"; // SMTP account username
$mail->Password = "info"; // SMTP account password
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->Port = info; // set the SMTP port for the server
$mail->From = "info"; //the email the mail comes from
$mail->FromName = "someName"; //what name should be shown at the email
$mail->AddAddress($email); //where the mail should be sent to
$mail->Subject = "email validation"; //subject of the mail
//how the link should look in the mail the "url" should point to the verification.php file
$link = "url path to my verification.php script".'?verification_code='.urlencode($user_activation_hash);
//the message in the mail with the above link
$mail->Body = "Please click on this link to activate your account:".' '.$link;
if(!$mail->Send()) {
echo "there was an error sending the mail" . ' ' . $mail->ErrorInfo;
//if there is an error sending the mail then I delete it here
return false;
} else {
//here I update the user with the new random created string
$sql = 'UPDATE `user` SET verification = :verification WHERE Id = :Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->bindParam(':verification', $user_activation_hash, PDO::PARAM_STR);
$stmt->execute();
$dbh = null;
return true;
}
All of this works fine so far the registered user gets an email with the random link created.
here is an example of the link the user gets: http://url/to/verification.php?verification_code=80371b8ff9b0d5fb444f4be68c8b5a0d9757603b
When they click the link they are directed to my verification.php script:
if(!empty($_GET['verification_code']) && isset($_GET['verification_code'])){
$verificationCode = $_GET['verification_code'];
//check the database for the verification code from the link
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':verification', $verificationCode, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
$Id = $row['Id'];
if (empty($row)){
echo "the account was not found";
}else{
//if they match. make the user active in db
$sql = 'UPDATE user SET isActive = 1, verification = NULL WHERE Id=:Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
echo "The account has been activated!";
}
}
}
Okay so here is my headache and I hope I can explain it properly:
All of this works. When I create the first user it works after registration I can see a verification code in the database and when I click the link it gets activated. But the following users getting registered is being activated at once when I hit the registration.php script! It is like both scripts are being run at once and then making the activation link completely unnecessary.
I have no idea what causes this behavior. Is it because my pdo connection isn't closed properly from my first script? Is it because PHP normally just runs all scripts in a directory when only one I called? Is it because I don't understand how the $_GET function works?
I can't possible find a way why this shouldn't work so here is some of the things I have already tried:
I have tried registering a user with the verification.php script commented out then first uncomment it and click the link being send when the user is registered. this works.
I have tried moving my verification.php script to another folder. Didn't help anything
I have tried closing the connection in the verification.php then made a new PDO after. this didn't work either.
I have tried alot of ways to change the $_GET method but no success.
UPDATE!: now i have tried to see exactly where the code breaks and i noticed something unusual. when the registration.php is run the user is set in the database as not active. As soon as i recieve the email with the link. the user is set to active, without ever clicking the link
Please tell me someone out there knows what's up.
the problem is the first user when registered the table was completely empty
but when the second user registered and enter the verification.php with no get value it searches for the user that has verification = null (the first user)
and complete the code esily so all you need is to modify your code
just edit the first query in the verification.php file instead of this
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification';
do it like this
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
for the checking that if the value is sent or not
if(isset($_GET["verification_code"]){
$sql = 'SELECT Id, verification FROM `user` WHERE verification = :verification AND isActive = 0';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':verification', $verificationCode, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
$Id = $row['Id'];
if ($Id == null){
echo "the account was not found";
}else{
// check if the verificationcode found in the database, matches the verificationcode from the link
if ($row['verification'] !== $verificationCode) {
//checking if it already exists and if there is an error then deleting the user
} else {
//if they match. make the user active in db
$sql = 'UPDATE user SET isActive = 1, verification = NULL WHERE Id=:Id';
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':Id', $Id, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->fetch();
echo "The account has been activated!";
}
}
}

Registration activation wont work (anymore)

So a couple of months ago i worked on my registration form with an com code (that is being send through the email) to activate it. The case is that the registration, and the activation of it always worked. But since recently, after some changes, it suddenly wont work anymore. The registration works,the email is being send to me with the com code link, and it also says i can now log in, but as soon as i try to log in with the made account, it sends me to my login error (wrong password or email). As soon as i look in my databse i also see that the data hasnt been inserted (its empty). Ive looked and done multiple things trying to get it fixed but none of it is working. So my last resort: stack;) The code is posted below (left the form code out btw since i dont think that is giving the problem):
The code for connection to the databse is (which is included everywhere):
<?php
$user = "XX";
$host = "XX";
$password = "XX"; //http://www.codinghorror.com/blog/2007/09/youre-probably-storing-passwords-incorrectly.html //
$database = "XX";
$conn = new mysqli($host, $user, $password, $database)or die ("Error message");
// check connection
if ($conn->connect_error) {
trigger_error('Database connection failed: ' . $conn->connect_error, E_USER_ERROR);
}
?>
After entering the register button this is the register checking page:
session_start();
include('configdb.php');
if(isset($_SESSION['error']))
{
header("Location: indexresp.php");
exit;
}
else{
if (isset($_POST["submit"])){
$register = $_POST['submit'];
$email2 = strip_tags($_POST['email']);
mysqli_select_db($conn, $database);
$emailcheck = mysqli_query($conn, "SELECT email from user WHERE email='$email2'");
$check = mysqli_num_rows($emailcheck);
if ($check == 0){
}
else {
$_SESSION['error']['email'] = "This Email is already used.";
header("Location: indexresp.php");
exit;
}
}
// the register (form field) data:
$voornaam = $_POST['voornaam'];
$achternaam = $_POST['achternaam'];
$email = $_POST['email'];
$password = $_POST['wachtwoord'];
$com_code = md5(uniqid(rand()));
$sql2 = "INSERT INTO user (email, password, com_code, voornaam, achternaam) VALUES ('$email', '$password', '$com_code', '$voornaam', '$achternaam')";
require("class.phpmailer.php");
$mail = new PHPMailer();
$mail->CharSet = 'UTF-8';
$mail->IsSMTP(); // set mailer to use SMTP
$mail->SMTPSecure = "tls";
$mail->Host = "smtp.gmail.com"; // specify main and backup server
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Port = XXX;
$mail->Username = "XXXXX"; // SMTP username
$mail->Password = "XXX"; // SMTP password
$mail->SetLanguage("nl");
$mail->From = "XXXXX";
$mail->FromName = "Oblectare";
$mail->AddAddress("$email");
// name is optional
$mail->AddReplyTo("XXXXX", "Information");
$mail->WordWrap = 50; // set word wrap to 50 characters
//$mail->AddAttachment("/var/tmp/file.tar.gz"); // add attachments
//$mail->AddAttachment("/tmp/image.jpg", "new.jpg"); // optional name
$mail->IsHTML(true); // set email format to HTML
$mail->Subject = "Account registratie";
$mail->Body = "http://localhost/debasis/hoofdstuk03/confirm.php?passkey=$com_code <br>This adress needs to be copyed in the browser and this is your password:<br><br>" .$password;
$mail->AltBody = "http://localhost/debasis/hoofdstuk03/confirm.php?passkey=$com_code. This adress needs to be copyed in the browser and this is your password:" .$password;
if(!$mail->Send())
{
echo "Error mail<p>";
echo "Mail Error: " . $mail->ErrorInfo;
exit;
}
include ('mailconfirmation.php'); // text to say the email has been send
}
So this code sends an email with the activation code (com code). The code for the email confirmation is just plain text so i left it out.
The next being done is setting the activation (with the supplied link) to yes. This is the code that does that:
include('configdb.php');
$passkey = $_GET['passkey'];
$sql = "UPDATE user SET com_code=NULL WHERE com_code='$passkey'";
$result = mysqli_query($conn,$sql) or die(mysqli_error());
if($result)
{
echo '<div>Your account is now active. You may now Log in</div>';
}
else
{
echo "Some error occur.";
}
?>
So when it passes the if (connection) the user gets redirected to the index where he can login with his account info and his info should be activated (by the update). I think the problem is in this piece of code as the sql variable in here doesnt update the com_code anymore for some reason.
After the redirection i try to login with the just inputted (and as it should be: the activated) details.
The code that checks the login (which look if the pass and mail are valid) is as follows:
session_start();
include('configdb.php');
if(isset($_POST['submit_login']))
{
$email = trim($_POST['email']);
$password = trim($_POST['password']);
$result = mysqli_query($conn,"SELECT * FROM user WHERE email='$email' AND password='$password' AND com_code IS NULL"); // was password
$num_row = mysqli_num_rows($result);
$row=mysqli_fetch_array($result);
if( $num_row ==1 )
{
$_SESSION['email']=$row['email'];
header("Location: member.php");
exit;
}
else
{
include ('errorlogin.php');
}
}
I hope one of you guys can help me with this problem cause after 2 hours searching it is (for now) enough for me;)
Sorry for my english and some dutch words in the code (try'd to translate some).
Thx in advance!
Your insert part :
$sql2 = "INSERT INTO user ..."
Is never used in the provided code. Maybe you removed the SQL process by error.

PHPMailer: Attach a file located on server

I'm trying to send an (up to 4) attachments using PHPMailer. The files are on my server.
This is how my script works:
User sees a job or resume and contacts them by using the contact form. The contact form stores the data along with the attachments on the server. We will then review the message filtering out spams/scams. If the message is genuine then we will send the message through.
I have the information stored on the server and Im able to send that information via email however the attachments are not sending.
Here is the code used to send the mail:
if ($_GET['status'] == 'approve') {
$id = $_GET['id'];
dbconnect($dbuser, $dbpass, $db);
$sql = "SELECT * FROM $db.mail WHERE id = $id";
$results=mysql_query($sql) or die(mysql_error());
while($row = mysql_fetch_array($results, MYSQL_ASSOC)) {
$id = $row["id"];
$to = $row["to"];
$from = $row["from"];
$subject = $row["subject"];
$message = $row["message"];
$file1 = $row["file1"];
$file2 = $row["file2"];
$file3 = $row["file3"];
$file4 = $row["file4"];
$result = mysql_query("UPDATE mail SET `status` = '1', `approvedtime` = NOW() WHERE id = " . $_GET['id'])
or die(mysql_error());
header("Location: mail.php");
// PHPMailer - Start
$email = new PHPMailer();
$email->setLanguage('ja');
$email->From = $from;
$email->FromName = 'MySite.com';
$email->Subject = $subject;
$email->Body = $message;
$email->addAddress($to);
if (!empty($file1)) {
$file1 = 'upload/'.$file1;
$email->AddAttachment($file1);
}
if (!empty($file2)) {
$file2 = 'upload/'.$file2;
$email->AddAttachment($file2);
}
if (!empty($file3)) {
$file3 = 'upload/'.$file3;
$email->AddAttachment($file3);
}
if (!empty($file4)) {
$file4 = 'upload/'.$file4;
$email->AddAttachment($file4);
}
return $email->Send();
// PHPMailer - Start
}
} elseif ($_GET['status'] == 'reject') {
dbconnect($dbuser, $dbpass, $db);
$result = mysql_query("UPDATE mail SET `status` = '2', `approvedtime` = NOW() WHERE id = " . $_GET['id'])
or die(mysql_error());
header("Location: mail.php");
}
Why are the attachments not sending? Am I missing a step in my code or have something incorrect?
Thanks for the help!

Phpmailer Multiple Mail

I'm trying to save multiple tasks and send multiple emails for each user. My code is shortly like this:
<?php
//Save All
foreach($_POST['decode'] as $dcode){
$sec = mysql_query("SELECT owner,mcode FROM members WHERE mcode='$dcode' ORDER BY id ASC");
while($list = mysql_fetch_array($sec)){$mcode=$list[mcode];$owner=$list[owner];}
if (mysql_query ("INSERT INTO tasks (tcode,adder,tdt,title,mcode,subject)
values ('$tcode','$adder','$tdt','$title','$mcode','$subject')")){
echo $owner.' done.<br>';header ("refresh: 5; url=members.php");
//Send info
include("scripts/class.phpmailer.php");
//To who
$sec = mysql_query("SELECT name,em FROM members WHERE mcode='$mcode' ORDER BY id ASC");
while($list = mysql_fetch_array($sec)){$name = $list[name];$em = $list[em];}
//Sender
$sec = mysql_query("SELECT owner FROM members WHERE mcode='$owner' ORDER BY id ASC");
while($list = mysql_fetch_array($sec)){$owner = $list[owner];}
$mail= new PHPMailer();
$mail->AddAddress($em , $name);
$mail->Subject=$owner."has send mail";
$mail->Body="content";
$mail->IsSMTP();
$mail->Host="host.host.com";
$mail->SMTPAuth=true;
$mail->Username="username";
$mail->Password="pass";
$mail->IsHTML(true);
$mail->From="sendermail";
$mail->FromName="Sender";
$mail->Port="587";
$done=$mail->Send();
// Check Mail
if(!$done){echo "Error! Mail not send";}else{echo "Mail send";}
}else{echo "Not Saved";}
}//Save All
?>
It saves the tasks. And sends a single mail. But i cant send multiple emails for each task.
Phpmailer sends error: Cannot declare class
I've tried this way for that error:
if(class_exists('PHPMailer') != true){$mail= new PHPMailer();}
And it says Call to a member function AddAddress()
And ive tried this way:
$mail->ClearAddresses();
And i think im putting the codes to wrong areas. Can u please help me to fix this.
I've searched "stack" and tried a few methods also. But they doesnt work on mine.
I think thats about the foreach command.
//Sender
$sec = mysql_query("SELECT owner FROM members WHERE mcode='$owner' ORDER BY id ASC");
while($list = mysql_fetch_array($sec))
{
$owner = $list[owner];
}
$mail= new PHPMailer();
$mail->Body="content";
$mail->Subject=$owner."has send mail";
$mail->IsSMTP();
$mail->Host="host.host.com";
$mail->SMTPAuth=true;
$mail->Username="username";
$mail->Password="pass";
$mail->IsHTML(true);
$mail->From="sendermail";
$mail->FromName="Sender";
$mail->Port="587";
//To who
$sec = mysql_query("SELECT name,em FROM members WHERE mcode='$mcode' ORDER BY id ASC");
while($list = mysql_fetch_assoc($sec))
{
$email = $list['em'];
$mail->ClearAddresses();
$mail->AddAddress($email);
$mail->Send();
}

Categories