轉載自: http://blog.csdn.net/wzhw2008/article/details/7606146
php定時發郵件,其實是一個‘很古老’的話題!因為php不像jsp那么‘強大’,不能執行一些定時任務,所以有好多想定時實現的功能無法實現,或者雖然實現了,但終究是把負擔加在了訪客,或是管理員身上!因為很大一部分的是通過客服端 瀏覽器 請求時觸發一個事件的,用這個方法的系統/應用不在少算。下面我就說三種方法吧!
最典型、應該也是使用最廣泛的一個就是:像 DEDECMS(不要說,你不知道DEDECMS是什么東西)一樣通過客服端 瀏覽器 觸發的方式,DEDECMS他們后台有個計划任務管理,其中就有一個方法是通過js觸發,下面是他們的原文一個說明:
計划任務執行的說明
·為了確保任務能執行完全,建議使用Dede的客戶端工具,否則只能通過JS觸發,但JS觸發有很多不確定因素會導致任務不能完成;
·JS觸發方式:在所有文檔頁面中用JS調用/plus/task.php?client=js(必須禁用計划任務的密碼,系統配置參數->其它選項);
·自行定制客戶端:直接訪問“http://網址/plus/task.php?clientpwd=管理密碼”,會返回其中一個可執行任務的網址(沒有可用任務則返回串:notask),然后客戶端運行這個網址即可。
他們的說明很清楚的指出:通過js觸發,js這就是一個客服端的代碼,所以必須要客服端觸發他們的計划任務。第一種方法先說到這里
第二種方法:相信很多人都去谷歌(php 定時發送郵件),百度搜過‘php 定時發送郵件’,發現一大部分說通過系統的任務計划去實現(xp通過at命令/控制面板添加任務計划;linux的crontab命令實現),本人覺得這是一個最垃圾的辦法,一般人的空間用的都是 虛擬主機 ,哪有你接觸到服務器的可能,主機提供商當然也不可能為你在服務器上去添加什么 定時任務 。所以,這種方法雖然是網上查到的最多的,但它其實就是一個完全不現實的東西,自己沒事拿來玩玩還是可以,真正要有所用途是不可能的!
下面再介紹本人的一個思路:在第一種方法中我們提到 客服端 請求,不過一直強調的是通過瀏覽器,可是你想想 訪問網站的方法就只有瀏覽器嗎!?當然不止,比如:在dos下,我們可以用telnet命令‘登陸’web服務器,在其他程序里面同樣可以,比如java 可以通過java.net.url 讀取網頁內容,其實這就是一次相當於瀏覽器的請求,當然php就更不用說了:file、file_get_contents、fsockopen、還有強大的curl擴展(當然要使用這些方法,都有一定的條件)。既然這樣我們實現 定時發送郵件 的功能方法就多了很多,因為只要你請求了一次web服務器,服務器就會執行對應的程序(發送到時間的郵件),那是不是就算你開個迅雷下載一下你的 任務頁面也可以實現定時發送郵件了,答案是肯定的!!!
可這次,我要說的一個方法跟上面的都不同。搜索引擎,大家都用吧!應該對它們大概的工作模式還是了解吧!?它們的蜘蛛會 定時/不定時 的去抓取網頁,這是不是也是一個web請求,當然是的!!那么我們的定時發送郵件,是不是有更好的實現方法了。我們在自己的網頁里,加一個小小的判斷,就可以知道來訪的是 搜索引擎的蜘蛛了,還是普通的訪客了!!在php里有一個環境變量:$_SERVER['HTTP_USER_AGENT'],可以很容易的讀取到向服務器請求的是‘誰’。既然我們知道了,來訪的是‘誰’,那么我們就可以對不同的來訪者 執行不同的代碼!當我們,發現時搜索引擎時,就執行一個 已經到指定時間的郵件,是不是就解決了定時發郵件的問題!!有人肯定會有疑問,搜索引擎到底多久會來我的網站抓取一次了,這個問題 還是請你自己到谷歌網站管理員找答案吧,我就不解釋了!!當然這個方法也不是就完美無缺的,它應該對網站SEO會有些影響,所以在你使用該方法時還是全面考慮一下,權衡一下你自己需求!(為了更好的說明搜索引擎抓取的速度,附個圖。這個是谷歌抓取我博客的統計信息)
當然,你可能會問:第一種通用的方法不是也可以嗎?那是自然。我們現在做個假設:每天有100封郵件等待發送,上網高峰肯定是出現在早上8點到晚上10點,這個沒得懷疑,那么這中間時間的跨度是14小時,那么平均下來就是每小時得發送7封郵件左右,這個發送郵件的動作肯定是由一個游客觸發。這也就意味着這位游客得等你的系統發送7封郵件之后才能看到你的網頁內容。你想想這是一個多長到時間,只恐怕人家早就沒耐心等下去了!所以這就是有搜索引擎觸發的好處!
亂七八糟說了這么多,具體代碼我就不給出了,相信文章寫到這個地步,你懂的(當然,如果仍有什么問題可以在下面留言)。時間到時過得蠻快的啊!!看看右下角,qq早就安靜的睡了,只留下一時間還在加速的跑着,還是定時的東西好啊!時間不早了,寫寫睡吧:
時隔這么久,再來補上一點吧!網上還有一種比較‘火’的方法,使用php的兩個系統函數,分別是:ignore_user_abort、set_time_limit。我簡單我一下實現方法吧!主要是通過設置php執行腳本最大超時時間來實現,set_time_limit(0),確保php腳本不會因為超時而,停止腳本的執行;通過ignore_user_abort(true),保證腳本不會因為客服端放棄請求而停止腳本的執行!采用這種方法起碼要保證一點:服務器沒有禁用:ignore_user_abort函數(因為一般的虛擬空間都是禁用這個函數的)。這個方法本人以前也試用過,不過沒有得到期望的結果:我的方法是用php做gtalk機器人,實現微博更新。結果是這樣的:機器人一般能保證2–3小時不等的在線時間,然后會自動下線!這也就說明用這個方法來定時發送郵件還是可以的,即便是一兩小時內沒人訪問你的網站,也完全有可能實現在這接下來的一段時間內實現郵件的發送。不過這個方法最大的缺的就是對服務器性能 的消耗特別大,這也就是為什么虛擬主機禁用ignore_user_abort函數的原因吧!
php定時計划任務實現方法
我在uchome 中 分析到, uchome是這樣做的
1. 把所有的計划任務存放到數據庫
2. 每次用戶進行操作或打開頁面的時候都按排序執行一條計划任務. 也就是輪番判斷,時間到了的, 就在用戶進程中執行.
uchome的計划任務代碼在 ./source/function_cron.php
上面只自己分析uchome代碼關於計划任務大概的結果, 拋磚引玉. 希望誰有好的方法拿出來共享.
ignore_user_abort()
我前一段時間徹底研究過計划任務,認為計划任務的思路很多,但最適合Web的還是觸發式的,就是類似於DZ和PHPWind的,似乎大多數web應用也都是這么做的,再說幾種其他的供參考
1,為了提供穩定的觸發,用crontab+wget或者ab提供定時訪問
2,nohup + php寫守護程序
3,直接用php寫個死循環還提供觸發,這時需要用緩存或者數據庫來協助推出循環,還有必須用sleep或者usleep控制觸發頻率
4,crontab+php
5,web觸發方式,這也有區別,一種是定時觸發,一種是定周期觸發,DZ和PHPWind都是定時觸發,我最后采用的是定周期觸發
具體的實現思路 很容易想,就不多說了
自己有主機肯定用crontab來執行命令行PHP
沒有只能寫在代碼中了
用crontab會比較好, 如果用循環的話, 最好也要把循環和具體處理程序分開, 不然內存會一直增加.
今天一不小心在php手冊上發現了這個函數-ignore_user_abort,這個函數可以幫助我們實現像linux中的cron一樣實現計划任務,下面一起來看下該如何來實現。
首先看下php手冊對這個函數的解釋
Description
int ignore_user_abort ([ bool $setting ] )
Sets whether a client disconnect should cause a script to be aborted.
也就是說無論客戶端是否關閉瀏覽器,下面的程序都會執行.
再看下其參數
Parameters
setting
If not set, the function will only return the current setting.
這個函數接受一個參數,來決定是否啟用ignore_user_abort的功能。
再看其返回值:
Return Values
Returns the previous setting, as a boolean.
這里說返回前一次的設置,並且是bool值得,經過我的測試,這個說法是不對的,返回的明明是int型的,不相信的話大家可以寫一個php文件來測試下。
說了這么多了,到底該如何用php的這個函數實現計划任務呢?還跌借助另外一個函數,這個函數是set_time_limit,通過set_time_limit0)可以設置程序的運行時間為無限制,php默認的運行時間是30秒,通過set_time_limit(0)可以讓程序無限制的執行下去。在程序執行之前加上ignore_user_abort(1)和set_time_limit(0)即可以了,最終程序該如何寫呢?給大家一個例子。
1. <?php
2. ignore_user_abort(); // run script in background
3. set_time_limit(0); // run script forever
4. $interval=30; // do every 15 minutes…
5. do{
6. $fp = fopen(‘text3.txt’,'a’);
7. fwrite($fp,’test’);
8. fclose($fp);
9. sleep($interval); // wait 15 minutes
10. }while(true);
11. ?>