Delay in PHP mail() function - php

I have a small ordering taking app which submits the order to a PHP script by ajax.
When the PHP script receives the order it places it in a database, sends an 'OK' message back to the client and then sends a confirmation email to the customer and another to me.
The problem is that the client is not seeing the 'OK' (which updates the browser display) for about 15 seconds. If I comment out the email sends, no delay.
... write to database
echo "OK";
mail($semail,'Msg Subject',$message, $header, $bounceto);
mail($semail2,'Msg Subject',$mesage, $header, $bounceto);
Message is only a couple of lines.
Questions:
why would there be a delay when calling the mail() function?
how can I cause the 'OK' message to be sent without waiting for the PHP script to complete? A flush of some sort I'm guessing.

That's because http://php.net/manual/en/function.mail.php returns boolean value for success or failure and your mail server takes time to process email request.
You can implement some kind of MYSQL queue for emails where you would put emails to be sent and check it with background task (for example using CRON to lauch YourMailQueueProcessingScripts.php that will check if there are any emails to send and perform the sending operation - have in mind that you can run CRON once per minute at most and I don't know if 1 minute delay of sending email is acceptable by you)

It should work with fastcgi-finish-request.php but it requires PHP FPM
Adding this will output the buffer to the user and cut the connection, the rest of the script will still be executed, but no additional output will be sent, so be sure to output everything before you call fastcgi_finish_request() and thereafter the mail() function

Related

Scheduling emails with cron jobs from a mysql table

I am trying to set up a system where a user enters some information in a form and an email will be constructed where the information is saved into mysql.
I am trying to figure out how to make it so the email will be sent, for example, 20 minutes after the user makes their input. (Without the user staying on the browser).
I need this delay as I need the ability for an admin to log on to a page to look at the email and possibly edit it before it sends.
Is this possible through a cron job. Am I able to set one up that automatically checks sql table for an update and then sends the email after a certain time?
Or is it possible to delay a php script with the sleep function and then send the email. Can I make the PHP script still run when user has closed site and left?
you can use mySQL to store the data sent by the user. this data will be accessed later using another script triggered by a cron Job: if you have the ability to set cron jobs in the control panel or via access to the server, go ahead, use cron tab syntax to define when the job will be triggered, this website may help you:
https://crontab-generator.org/
another approach is to use external service to trigger an event every interval, the event could be accessing the cron job script via HTTP.
if you want your email to be sent exactly after 20 mins, please add a field to your mysql table indicating the desired send date(beware of timezones).
you may also want to add a flag indicating if the email is sent, so you do not send the same email twice.
You can't (easily) have a PHP script stay alive that long.
Your best strategy, IMO, would be to have the PHP script create the email file, and notify the human.
Then you can have PHP run a shell script which uses the "at" program to schedule a task to happen in 20 minutes. At is a cousin of cron, but is better suited for this job.
That scheduled task will be to take the e-mail message, move it some place else (like a "done" directory), and pipe it through your mailer. tip: /usr/sbin/sendmail -t < myEmailFile will work on most Linux boxen.

How do you make a long-running PHP script display a success message immediately?

The goal
I am trying to create a PHP script which emails a rather large (6MB) PDF file to users on a website that request it. A user enters their email address into a form, submits the form, and the file is sent to them via a PHP Mailer instance. The user is displayed a success page on submitting of the form.
The problem
After the data is submitted via the POST method, there is a long pause and the server eventually returns a 404. However, the email is received perfectly fine with the PDF attachment after a few minutes.
Troubleshooting / attempted solutions
I attribute the problem to PHP Mailer simply taking too long a time to send the email because of the large attachment. The server times out and resorts to returning a 404. In the mean time, the script eventually finishes processing and the email is thereafter received.
If I remove the attachment and just send a blank email, the script loads very quickly and shows the success/confirmation page.
I have considered creating a redirect, but everywhere that I have found explanations on how to achieve a redirect in PHP, it is said that you should kill the original script (which I do not want to do).
The question
How do I allow the email script to take its time to run, while immediately displaying a success message to the user so they are not left confused?
This is a task for a message queue. Store all information needed to send the mail in a queue and have a background task taking this information and sending your mails. If the insertion to the message queue succeeded, display the success message to the user.
If you do not have access to background scripts (e.g. shared hosting), you can still have a direct response. Just use ignore_user_abort(true) and send a correct Content-Length header. Browsers will trust that header and show the response, while your script can continue running and send the mail.
Another solution: Do a quick trick instead of attaching a big file in the email instantly. Give them the download link of the PDF File. Thus the content becomes too short. But no attachment.
You can effort to create unique URL to download the same PDF file by different users.
Otherwise, email queuing is good, as discussed.
Instead of emailing the file immediately, store the request in a database with all the details you need in order to send it. Then you can use a cronjob/scheduled task to regularly (every minute if you like) check the database for any outstanding requests and send the emails in the background.
As no codes were provided, you can use AJAX to call your script and show a success message wherever you want. The script will be called, the user will get the message and as soon the script finish, the user will receive the email.
Of course, the success message shouldn't be implemented in the AJAX handlers, otherwise the message will be delayed as well.
This is a good use case for an asynchronous job queue such as Gearman or Beanstalk.
You have to run an external worker process that will wait for tasks from the job server.
On the web server side, just create the task, send it to the job server to dispatch it to the worker process, and exit the PHP script.
The worker process will then proceed to send the mails while the web server can continue serving HTTP requests.

Using CodeIgniter and PHP, is there a way to issue a redirect to the client and continue executing the present script?

I have a page which handles form input. It does a few things, sends a few emails, and redirects the client to another page. Things work well.
The issue I that sending email is slow, and if I have to send a couple emails, the response time is unacceptable. I would like to redirect the client to the result page, and then send the emails. Unfortunately, the redirect() call in CodeIgniter ends execution.
Is there a way to do a 302 redirect and allow the execution of the script to continue?
It is important that the 302 redirect headers get flushed out. It would be OK, but is not required, that the connection be closed. What is important that the user gets redirected before the emails get sent, in order to not have to wait for the email sending to finish.
I think using a message queue would be more appropriate than having a possible zombie process sitting there. Essentially when this action is taken dump a job into a job queue with the body of the e-mail, who it's going to, the subject etc. Then have a cron job set up to read this queue every two minutes, say, and send out the e-mail.
You can also look into using something like the Simple Queue Service from Amazon (http://aws.amazon.com/sqs/faqs/#What_can_I_do_with_Amazon_SQS) along with the Simple E-Mail Service to create a scaleable solution.

PHP page times out - can I resolve via asynchronous display?

I have a PHP page that sends notification emails. When it sends out more than ~100 it times out. I'd like the page to work like Kayak so that the user can see progress occurring (so they will wait longer).
How can my page quickly load (preventing timeout) before sending the emails, then update as and when the process runs (e.g. as each email is sent a line gets written to the screen)?
You could do this with AJAX. Send an AJAX-request that sends out 50 (or any other number that fits into the timelimit) and echos out the result. When the request successfully finished send out the next AJAX-Request with a parameter called offset, that will be used to skip the first X datasets.

dont wait for script to finish

I have a php script that sends SMS, the problem is that it takes some time before every SMS is sent. In my site the page will wait until this script has finished running. How can I give user a message that SMS will be sent and resume the site's normal operation.
The only issue here is that the browser thinks it is are waiting for more output from the script when there will be none. You could offload to a seperate process, or use an asynchronous web call, or you could simply.....
<?php
register_shutdown_function('when_alls_done');
.... // render page
exit;
function when_alls_done()
{
if ($_REQUEST['send_to_phone']) {
send_sms($_REQUEST['send_to_phone'], $_REQUEST['message']);
}
}
The webserver should flush the request at the 'exit' and let the browser know that the response is complete (an explicit flush in the PHP code prior to that will either not flush the webserver buffer or it will result in the output being chunk encoded with another chunk to come).
C.
Put the messages in a queue in your database. Then have a script running as a cron job in the background to take care of the queue.
It's very easy when you know how:
<?php
echo 'A sms will be sent!';
fastcgi_finish_request();
// Put all your time consuming code here!
?>
Instead or sending the SMS right there and then you can store it somewhere (for example the database). You can then build an extra script (in PHP or whatever else you want) that polls the database looking for SMS to send and dispatches them. You can have this run every x seconds or minutes via cron or scheduled task according to your OS. This way you take a time consuming task out of the page whose job is to communicate with user in a timely manner.
If you are on LAMP
Write a cron job that will query a queue (in database) for pending SMS and send them.
In your script add the SMS to the queue.
Show the user status of his SMS on another page.
With Ajax you can query in background for the status of recently sent SMS. As soon as you see sent notify user.
to do this you can use ajax.
on some button press just send an ajax request to the php file moulded to send sms. and put a notification in the screen like 'sending sms!!!' and on the response of the ajax action change the 'sending sms' to 'success!!!'....
for using ajax you can use jquery..
if you dont know jquery comment me for the video tutorials... i have some beginners video tutorial for jquery....
Have a nice day!!!!!

Categories