記錄一下以前做的後台excel格式導出統計信息的功能,也是最近同事問到了相關東西,一時之間竟忘了具體的細節,因此記錄一下;
大家知道,excel導出數據的功能,後台幾乎是必須功能,一般都是點擊後,生成文件然後自動下載,
如果是數據量小的話,一下子便可請求完成,從而下載到本地;
但是,如果數據量特別大的時候,頁面就必須一直在等待,直到寫入excel成功,
這樣便影響了後台使用者無法操作其他頁面,為此,對excel導出做了以下功能優化:
生成excel文件的方法有很多,暫不一一記錄,只是記錄本次的方法;
這裡用到了table的html格式,以及相應的excel的聲明
(隱約記得其他的方法用office07打開的時候好像是亂碼,後面嘗試用csv格式文件,可還是亂碼,所以用了table的形式)
文件的開頭:
文件的結尾:
當然,文件中間就是一些tr td 標簽了。
場景:
用戶點擊 生成excel後,跳轉到下載頁面,程序在後台執行,用戶可不必等待生成完成,可執行其他操作;
下載頁面可看到文件生成的進度以及是否可下載狀態
思路:
點擊 生成excel,顯示下載頁面 ---> show_download方法
生成excel ---> create_excel 方法
show_download方法中調用 create_excel方法,而show_download 方法中,自己用了一下命令行執行程序的方式,
利用php命令行的方式,把參數傳遞給 create_excel方法
1 // $cmd = "/usr/bin/php /home/xxx/xxx.php " . $strjoin . " >/dev/null & "; 2 // $a=exec($cmd, $out, $returndata); 3 4 5 $command = "/usr/bin/php ".STATISTIC_EXPORT_SCRIPT_DIR."xxx.php " . "'" .$strjoin ."'". " " . $uid . " ". $action ." & "; 6 $process = proc_open($command, array(),$pipes); 7 $var = proc_get_status($process); 8 proc_close($process); 9 $pid = intval($var['pid'])+1;
而在create_excel方法中:
需填寫以下代碼:
1 set_time_limit(0); //取消腳本運行時間的超時上限 2 3 ignore_user_abort(TRUE); //後台運行,不受用戶關閉浏覽器的影響
調用相關的api得到數據:
1 $statistic = call_user_func(array('shellscript','get_result'),$url,$params); 2 if(!is_object($statistic) || !isset($statistic->data->items)){ 3 usleep(400000);//停止400毫秒 4 $statistic = call_user_func(array('shellscript','get_result'),$url,$params); 5 }
但是怎麼顯示相應的文件生成進度呢,怎麼知道文件到底生成好了沒有呢?
這裡,我用到的方法是,在寫入數據文件的時候data.xsl,每個數據文件都生成一個對應的文件進度文件,暫且稱為flag_data.xsl;
思路:
查看文件的進度方法:
文件的下載就好說了,既然已經都生成成功,下載的方法如下:
1 public function execscript_download(){ 2 $filename = $_REQUEST['filename']; 3 $uid = $_REQUEST['uid']; 4 $file_dir = STATISTIC_EXPORT_FILE_DIR.$uid.'/'.$filename; 5 if (!file_exists($file_dir)){ 6 header("Content-type: text/html; charset=utf-8"); 7 echo "File not found!"; 8 exit; 9 } else { 10 ini_set("memory_limit","500M"); 11 header('Content-Description: File Transfer'); 12 header('Content-Type: application/octet-stream'); 13 header('Content-Disposition: attachment; filename='.basename($file_dir)); 14 header('Content-Transfer-Encoding: binary'); 15 header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); 16 header('Cache-Control: must-revalidate,post-check=0, pre-check=0'); 17 header('Pragma: public'); 18 header('Content-Length: ' . filesize($file_dir)); 19 readfile($file_dir); 20 } 21 22 }
本地本來已經測試完畢,可上線後,卻出現了奇怪的問題;
現象描述:
當在後台點擊生成文件,跳轉到下載頁的時候,因為下載頁是顯示文件進度的頁面,
竟然出現有時候有剛剛點擊的文件進度,有時候沒有,就感覺沒有生成相應的文件一樣;解決方法:
因為數據文件和進度文件都是生成在程序的某個文件夾file中,所以讀取的時候都是讀取的文件夾下的文件,從而判斷顯示進度;
後面才知道,由於後台程序有兩台服務器,導致讀取以及下載的時候找不到相應的文件夾,兩個服務器相應的文件夾弄個共享目錄就可以了
由於下載的文件多了,導致文件夾下的文件越來越多,而原來生成的文件是沒有價值的,所以加了個定期刪除文件的功能,只保留近七天的文件
當然可以用crontab,只不過我比較懶,是在點擊生成文件的時候,判斷了一下文件夾中的過期文件,從而刪除
1 public function execscript_process_show(){ 2 $this->load->library('smarty'); 3 $uid = $_REQUEST['uid']; 4 $url_dir = STATISTIC_EXPORT_FILE_DIR.$uid .'/';//@todo 5 if(!is_dir($url_dir)){ 6 @mkdir($url_dir,0777); 7 } 8 $files = scandir($url_dir); 9 if(!empty($files)){ 10 foreach ($files as $key => $value) { 11 if($value!='.' && $value!='..'){ 12 foreach ($files as $key => $value) { 13 if($value!='.' && $value!='..'){ 14 if(substr($value, 0 , 5)!="flag_"){ 15 $filenamedate = substr($value, 0,10); 16 $today = date('Y-m-d',time()); 17 $filenamedate = date('Y-m-d',strtotime($filenamedate)+(STATISTIC_FILE_EXPIRE_DAY-1)*24*3600); 18 if($today>$filenamedate){//文件過期 19 @unlink($url_dir . $value); 20 @unlink($url_dir . 'flag_' . $value); 21 } 22 } 23 } 24 } 25 } 26 } 27 } 28 29 $this->smarty->assign('uid',$uid); 30 $this->smarty->display('interact/statistic/execscript.tpl'); 31 }
大文件的導出大體就是這個樣子,歡迎大家吐槽,共同交流;
當時在用命令行執行方法的時候,也參考了一下相應的資料,記錄一下;
http://blog.csdn.net/yysdsyl/article/details/4636457 http://www.codesky.net/article/201202/163385.html http://www.cnblogs.com/zdz8207/p/3765567.html http://blog.163.com/mojian20040228@126/blog/static/4112219320097300922992/ http://php.net/manual/en/features.commandline.php http://blog.csdn.net/yangjun07167/article/details/5603425 http://blog.csdn.net/yunsongice/article/details/5445448 http://www.cppblog.com/amazon/archive/2011/12/01/161281.aspx http://blog.51yip.com/tag/proc_open http://www.justwinit.cn/post/1418/ http://limboy.me/tech/2010/12/05/php-async.html