Loading php in the background
Moderator: General Moderators
Loading php in the background
Hi
I've searched the internet and these forums and can't quite find what i'm looking for - i think i may be using the wrong search terms :/
I'm making a mailing list system and building it into a CMS that I have designed. I want the user to be able to login to their CMS, compose an email and simply hit send for the email to go out to the mailing list (lets call this page sendmail.php).
I have a script (mail.php) which will go through a database of email addresses and send out the same email to each one of them. I have used things like ignore_user_abort(true) and set_time_limit(0) so as soon as I launch the mailout script I can close it safe in the knowledge it will eventually go through the whole mailing list.
This all works great, my problem is, I want the user to be able to click send (on sendmail.php) and immediately be redirected to another page such as the front page of their CMS. In the mean time I want the script mail.php to be executed in the background. I found White Shadows blog which had a function which did almost what i want.
The problem with it is it uses http request to post to the page in effect loading it in the background. As it is part of a CMS it needs to be secure and anyone who knows the URL could in effect send an email (possibly a blank one) out to the whole mailing list.
So, I need to store the file outside my webroot for security reasons which stops me using the post method from White Shadows blog.
I know its a long post but I thought I would try and be as clear as possible. Any help is greatly appreciated!
Ross
I've searched the internet and these forums and can't quite find what i'm looking for - i think i may be using the wrong search terms :/
I'm making a mailing list system and building it into a CMS that I have designed. I want the user to be able to login to their CMS, compose an email and simply hit send for the email to go out to the mailing list (lets call this page sendmail.php).
I have a script (mail.php) which will go through a database of email addresses and send out the same email to each one of them. I have used things like ignore_user_abort(true) and set_time_limit(0) so as soon as I launch the mailout script I can close it safe in the knowledge it will eventually go through the whole mailing list.
This all works great, my problem is, I want the user to be able to click send (on sendmail.php) and immediately be redirected to another page such as the front page of their CMS. In the mean time I want the script mail.php to be executed in the background. I found White Shadows blog which had a function which did almost what i want.
The problem with it is it uses http request to post to the page in effect loading it in the background. As it is part of a CMS it needs to be secure and anyone who knows the URL could in effect send an email (possibly a blank one) out to the whole mailing list.
So, I need to store the file outside my webroot for security reasons which stops me using the post method from White Shadows blog.
I know its a long post but I thought I would try and be as clear as possible. Any help is greatly appreciated!
Ross
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
You could set something up using a referrer key or something along those lines. Maybe even cURL. But immediately redirecting away from the processing page may not work for you when sending out a lot of emails at once since this process takes time.
Re: Loading php in the background
would it be better to create a queue type system and run the actual email script with a cron job?
so your cms user creates his email, and clicks send. that stuff is stored in your db somewhere temporarily. set a cron to run every few minutes to do the mailings.
so your cms user creates his email, and clicks send. that stuff is stored in your db somewhere temporarily. set a cron to run every few minutes to do the mailings.
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
I was thinking cron originally, but this might not be the best idea. Though it could be the best idea. I am still thinking of ways to do what you want.
Perhaps you could look at a library like Swiftmailer and look into the batchSend() method. It takes an array of email addresses and sends them out in a process type order without bogging the app down.
Perhaps you could look at a library like Swiftmailer and look into the batchSend() method. It takes an array of email addresses and sends them out in a process type order without bogging the app down.
Re: Loading php in the background
Hi thanks for the replies
Liljester, Cron jobs would be perfect (although invoking the script on user action is a bit more efficient), but unfortunately my client is on shared hosting so don't have access
The php script I set up works similar to a cron job (as far as php will allow) as it loops through the batch sending process with a waiting time between batches to compensate for server load.
Everah, I think you might have the most practical idea so far (but not perfect
), using a referer key, I'll could set a key to the individual message and call the script with the message key. Once the email has been loaded and processing begins I could flag the message as unusable/sendable.
Re batch sending.. I know batch is faster but I'm not having a problem with my script itself, it is sending and behaving perfectly, I just want the user experience to be seamless so want this already working script to be called without the user knowing.. ( I am using swift mailer
- but, the batch sending does not give a break down of which emails failed/succeeded - only which failed as an array. I want to actively be able to track via database how far the script has got in sending out emails) - each address will be flagged as having the mailout sent or not yet.
I think I'm going to try the referrer key idea now - i know it'll work it just doesn't quite provide the security I'm after.
(I have had one thought but not got it to work so far, if you redirect with header("Location...") is there a way to make the server carry on processing the script after the header() funcion call? - to me that sounds like a perfect solution... I'm not sure ignore_user_abort will quite cut it)
Liljester, Cron jobs would be perfect (although invoking the script on user action is a bit more efficient), but unfortunately my client is on shared hosting so don't have access
The script ignores user termination so redirecting away from the processing page should be fine, the script will only end when it has sent (or not sent) to all email addresses.Everah wrote:But immediately redirecting away from the processing page may not work for you when sending out a lot of emails at once since this process takes time.
Everah, I think you might have the most practical idea so far (but not perfect
Re batch sending.. I know batch is faster but I'm not having a problem with my script itself, it is sending and behaving perfectly, I just want the user experience to be seamless so want this already working script to be called without the user knowing.. ( I am using swift mailer
I think I'm going to try the referrer key idea now - i know it'll work it just doesn't quite provide the security I'm after.
(I have had one thought but not got it to work so far, if you redirect with header("Location...") is there a way to make the server carry on processing the script after the header() funcion call? - to me that sounds like a perfect solution... I'm not sure ignore_user_abort will quite cut it)
Re: Loading php in the background
Just been looking into another way to combat it, maybe I could use something like exec() or shell_exec() to load the script silently. I'm a totally inexperienced in command line stuff :/
The closest thing I got is
(taken from php.net)
The thing is first time i tried this script it seemed to work, ever since i cannot get it to work at all (it seems as if the mail script loaded in the background does not get loaded at all)
The closest thing I got is
Code: Select all
<?php
$runCommand = 'php -q swift/mail.php';
$nullResult = `$runCommand > /dev/null &`;
?>
The thing is first time i tried this script it seemed to work, ever since i cannot get it to work at all (it seems as if the mail script loaded in the background does not get loaded at all)
Re: Loading php in the background
Ross,
I'm trying to do exactly what you are and just made a post today about my failed attempts with test.php:
test_exec.php:
I'm trying to do exactly what you are and just made a post today about my failed attempts with test.php:
Code: Select all
<?
exec('/usr/bin/php /pathname/test_exec.php > /dev/null 2>&1 &');
?>Code: Select all
#!/usr/bin/php -q
<?
mail("to@mail.com","subject","message","From: me@mail.com");
?>- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
@djepayne - What are you trying to do?
Re: Loading php in the background
Everah,
I'm trying to send an email message to 100's of members in my association.
Using "mail" inside of a "foreach" loop keeps my web page open for several minutes until all the messages are sent. I want the web page to just tell me, "Now sending email to 238 members".
I'm trying to send an email message to 100's of members in my association.
Using "mail" inside of a "foreach" loop keeps my web page open for several minutes until all the messages are sent. I want the web page to just tell me, "Now sending email to 238 members".
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
Have you looked at swiftmailer? The batch send dispatches emails to many thousands of users without hanging up the sending page.
Re: Loading php in the background
I did load Swiftmailer and found that sending to 12 test emails took 33 seconds. Not exactly fast enough for me.
-
crazycoders
- Forum Contributor
- Posts: 260
- Joined: Tue Oct 28, 2008 7:48 am
- Location: Montreal, Qc, Canada
Re: Loading php in the background
Your problem has been fixed almost since the first post. You wish to put your script outside your webroot just for security. There are tons of ways to secure the access of your script apart from putting it outside your webroot. It could be a dynamically generated key stored in the database for that massmailling only.
For example, take your sender_name, sender_email, type of massmail, add a salt specifically for your software and put in there also the date the massmail was created at the specific second it was created... MD5 the whole lot, it gives you a key just for the massmail and voila. You have a unique key very hard to use that cannot be accessed by anyone as long as you do not give access to the creation date/time of the mailing.
Next setup a page where the user sees his massmails and a link to launch the massmail.
The page that launches the massmail has access to the key, it generates it and opens an HTTP socket and requests the sending queue script and simply closes the socket without waiting for response. It then redirects the user to the list page and shows that the massmail is underway.
The sending script is in charge of sending the mails and just sets a timeout of 0 so it never expires and runs through all the mails it has to send and updates the count of emails sent and the state of the massmail. When it's done it closes the output buffer and stops existing.
This technique is often used to logically fork the process without actually using the FORK functions and it works marvelously well. The only problem is the fact that you are not always authorized to use set_time_limit on all servers. But if you do have control of this, then you are ok.
Regarding the key to access the mailing, it could also be sent via email to someone and the person could click on the link to activate the massmailing. You could then simply prevent the person from launching 2 massmails by updating the database with a state field and denying to run again the massmail until completed. Even more wacky, you could implement a dynamic salt in your hashkey where the hour of the time of generation is used and thus if the key is used outside of lets say, 13h-13h59, then the key doesn't resolve anymore and the sending is denied.
There are tons of ways to protect your scripts from being ran. Instead of finding a way to secure by removing the access, use a different approach, access control
For example, take your sender_name, sender_email, type of massmail, add a salt specifically for your software and put in there also the date the massmail was created at the specific second it was created... MD5 the whole lot, it gives you a key just for the massmail and voila. You have a unique key very hard to use that cannot be accessed by anyone as long as you do not give access to the creation date/time of the mailing.
Next setup a page where the user sees his massmails and a link to launch the massmail.
The page that launches the massmail has access to the key, it generates it and opens an HTTP socket and requests the sending queue script and simply closes the socket without waiting for response. It then redirects the user to the list page and shows that the massmail is underway.
The sending script is in charge of sending the mails and just sets a timeout of 0 so it never expires and runs through all the mails it has to send and updates the count of emails sent and the state of the massmail. When it's done it closes the output buffer and stops existing.
This technique is often used to logically fork the process without actually using the FORK functions and it works marvelously well. The only problem is the fact that you are not always authorized to use set_time_limit on all servers. But if you do have control of this, then you are ok.
Regarding the key to access the mailing, it could also be sent via email to someone and the person could click on the link to activate the massmailing. You could then simply prevent the person from launching 2 massmails by updating the database with a state field and denying to run again the massmail until completed. Even more wacky, you could implement a dynamic salt in your hashkey where the hour of the time of generation is used and thus if the key is used outside of lets say, 13h-13h59, then the key doesn't resolve anymore and the sending is denied.
There are tons of ways to protect your scripts from being ran. Instead of finding a way to secure by removing the access, use a different approach, access control
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
That is odd. I have sent thousands of emails with it before and never even saw a process taking place. Are you using the batchSend() method?djepayne wrote:I did load Swiftmailer and found that sending to 12 test emails took 33 seconds. Not exactly fast enough for me.
Re: Loading php in the background
Code: Select all
$swift->batchSend($message, $recipients, "webmaster@pmpa.net");
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Re: Loading php in the background
That may be something to post to the Swiftmailer forum then. That seems odd that 17 emails would take 30 something seconds.