I have a page where users enter their email address, click "Send", and the webserver will email them a ~10mb attachment. Right now, I have the page just display "Sending..." and the user waits about 20 seconds on this page.
Instead, I want to have it say "Your attachment will be emailed in a few minutes," sending that process somewhere else and allowing the user to continue browsing without having to open up a new tab.
I really just need someone to point me in the right direction because I don't even know what to Google at this point.
You could call another php file that will process the email sending and make sure to put in this call:
ignore_user_abort(true);
What this does is allows the php process to finish, even though the browser leaves. So you could initiate the process via ajax and then go to another page saying your attachment has been sent.
For more info:
http://www.php.net/manual/en/function.ignore-user-abort.php
I recommend checking out this question I posted a while ago.
How can I run a PHP script in the background after a form is submitted?
The answer explains how you can run a PHP script in the background after a form is submitted. This, of course, is just one way to accomplish this. Another would be to build a list of addresses and set up a cron to run a script on a timed interval. Both can accomplish the same thing, it just depends on how you wish to tackle the issue and what you can do on your server.
Related
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.
I have a webform that sends data to PHP script.
PHP script may take a while to process the data. What I want to do is to send raw data to database, then redirect the visitor to "thank you" page and then continue processing the data in background. Important thing is that the script must continue working even if the visitor closes "thank you" page.
Can you advise which solution should I look into?
P.S. I use nginx + php-fpm if that matters.
UPDATE. I've found info about using ignore_user_abort(true). Could this be the way to go?
What I want to do is to send raw data to database, then redirect the visitor to "thank you" page and then continue processing the data in background.
That basically describes how I'd do it right there, actually.
Consider two separate applications. One is the web application, which saves the user input to the database and then continues to interact with the user. The other is a scheduled console application (a standalone script invoked by cron most likely) which looks for data in the database to be processed and processes it.
The user uploads the data, receives a "thank you" message, and his/her interaction is complete. The next time the scheduled task runs (every couple minutes, maybe?) it sees the pending data in the database, flags it as being processed (so if another instance of the script runs it doesn't also try to process the same data), processes it, flags it as being done (so it doesn't pick it up again next time), and completes.
You can notify the user of the completed process a couple of different ways. The back-end script can send the user an email (active notification), or perhaps the web application can examine the table for the flagged completed records the next time the user visits the page (passive notification).
Something like this should work :
pclose(popen('php script.php &', 'r'));
http://fr2.php.net/manual/fr/function.popen.php
You can also use more options or others functions to get more control over the execution :
http://fr2.php.net/manual/fr/function.proc-open.php
But use this carefully and be sure you need this way to resolve your problem.
Ajax would be nice.
You need to do the thing asynchronously. Use AJAX to achieve this
I have a registration form on my site. The form is sent to the server via AJAX and is then validated. Then it will output an address for the browser to be redirected to, if it was validated as valid information. PHP will then send a validation email to the email specified. The problem is that the sending of the email takes 10 seconds, and I don't want my users to wait for 10 seconds from they press Register to they get redirected...
Is there a way for PHP to tell the client the information was correctly validated and output the redirection URL, and continue sending the email without the client waiting?
It's called a background job.
To do this in the simplest way (note: not the best, but the simplest):
I'm assuming you're storing your registration details in some form of database. Add an extra column to flag that you need to send the validation email to this user.
In another script, check the database for any rows with this flag set, and send the email from there.
This second script will be triggered by a cronjob or similar, on a schedule of your choosing.
This way, users don't need to wait for that 10 seconds.
There are more efficient solutions that will cope better for larger scale sites, but I'm guessing that you don't yet need to know this, and that if I brought them into the equation it'd confuse matters. Look into Job Queues, if you want to know more.
I have a page that allows for used input, when the user inputs his/her specifications and selects submit the algorithm will run. This can take a few minutes depending on input. The user will also be directed to a page which will show their results. I want to show a block of php code that allows for the user to input their email and an email containing the url for results will be sent to them automatically when the results are ready. However, if the results are ready I want the block of code (acting like loading page) to 'disappear' and the results visualisation code to run.i.e. show the results. is this possible? I'm fairly new to programming, so not sure the way to go about this. Thanks for the help.
The thing about PHP script is that, it will keep running until -
1) The server kills the script.
2) Script kills itself.
So whatever you are doing, it will keep running in the PHP script untill it is finished and t the end you could place the algorithm to mail the user. To have the results placed back when they are ready you could use Ajax. You could see the following tutorial for Ajax with jQuery: http://www.devirtuoso.com/2009/07/beginners-guide-to-using-ajax-with-jquery/
On my site, I have a feature that allows you to follow the updates of other users. When a user makes a change to their info, anyone following him or her will be emailed of this change.
I have it set up so that the php changes the info in the database, then searches through the users contacts to see who is following him/her, and sends emails to those who are following notifying them of the change.
The problem I have run into since adding this notification feature, is that insead of the page loading (form posts to itself) and showing the change almost instantly, (depending on how many people are following a particular user) it can take a few munites for the page to load and show the update (because the php is sending all the emails before the page reloads).
How can I set it up, where the script to send the emails, is run somewhere in the background, and the user does not have to wait for the emails to send before the page reloads, and could possibly even exit out of the website and still have the emails send if still the script is still running?
P.S. All my programming and development skills have been self taught, so I don't know a lot of terminology..... You may have to dumb down your responses so that I will understand what you are talking about. Sorry for the inconvenience, and thank you very much for any help.
I'm surprised it takes several minutes just to send some emails, but anyway you can do this in at least four ways:
Use ajax to send the form data to a separate script that sends the emails while the form posts normally
Have the form script fork (pcntl required)
Make an asynchronous request to your own page via php (either set a low timeout with cURL, or open a socket)
Use exec('script-that-sends-emails args >> some-other-file 2>&1 &');