PHP學(xué)習(xí)筆記---實(shí)現(xiàn)導(dǎo)出csv功能(附帶打包zip教程)

對(duì)于許多的從事數(shù)據(jù)智能開發(fā)的同僚來說,從庫(kù)中提取出數(shù)據(jù)后進(jìn)行數(shù)據(jù)整理并且導(dǎo)出csv文件的功能是很常見的,導(dǎo)出一個(gè)csv文件方便用其他的數(shù)據(jù)工具進(jìn)行分析。所以在這里分享一下我在工作過程中實(shí)現(xiàn)導(dǎo)出csv文件功能的歷程與所獲。

前言

首先,我被告知需要在laravel框架中實(shí)現(xiàn)下載接口這個(gè)任務(wù)時(shí),整個(gè)人是懵逼的,完全不知道怎么著手去實(shí)現(xiàn)這個(gè)功能,但是對(duì)于一個(gè)理工科生來說,碰到問題并不可怕,剝絲抽繭,一步一步來。我分析,既然要實(shí)現(xiàn)下載功能接口,首先需要做的就是提供一個(gè)接口,而如何做一個(gè)接口我在<<Laravel使用心得--簡(jiǎn)易路由操作>>中已介紹,向前端提供一個(gè)URI即達(dá)到了接口的意義,其次是如何實(shí)現(xiàn)下載,最后是如何寫入一個(gè)csv文件,本篇文章就從后兩個(gè)方向介紹,并且最后附帶PHP中文件打包功能的實(shí)現(xiàn)介紹

本來想打包功能單獨(dú)寫一篇博客的,后來發(fā)現(xiàn)這個(gè)功能實(shí)現(xiàn)比較簡(jiǎn)單,而深層次的我也暫時(shí)不會(huì),就附帶本篇文章最后了

下載

一、通過傳遞HTTP報(bào)頭實(shí)現(xiàn)下載

首先在度娘上找到的實(shí)現(xiàn)下載的方式之一:是通過向?yàn)g覽器傳遞HTTP報(bào)頭,告訴瀏覽器這個(gè)URI的相關(guān)動(dòng)作讓瀏覽器去實(shí)現(xiàn)。
HTTP報(bào)頭是HTTP協(xié)議的一個(gè)部分,一般上用于客戶端和服務(wù)端之間握手時(shí)的通信,通俗的理解就是 http服務(wù)器和客戶端(一般為瀏覽器)之間數(shù)據(jù)傳輸之前的對(duì)話,告訴瀏覽器你想干什么。
而在PHP中實(shí)現(xiàn)HTTP報(bào)頭參數(shù)傳遞功能的是header()方法,header() 函數(shù)向客戶端發(fā)送原始的 HTTP 報(bào)頭。其中認(rèn)識(shí)到一點(diǎn)很重要,即必須在任何實(shí)際的輸出被發(fā)送之前調(diào)用 header() 函數(shù),例如在調(diào)用header()函數(shù)前不要寫print_r()或var_dump()等函數(shù)。
傳遞報(bào)頭參數(shù)的代碼:

header("Content-type:text/csv");
header("Content-Disposition:attachment;filename=" . $start_date . '~' . $end_date . '_fare.csv');
header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
header('Expires:0');
header('Pragma:public');

其中第一行是告訴瀏覽器我需要導(dǎo)出文件,格式是csv,在Content-type這個(gè)參數(shù)類型中可以指定許多的導(dǎo)出文本的格式,例如rar、zip這樣的壓縮包格式
傳遞這樣的報(bào)頭后,導(dǎo)出的文件的內(nèi)容將是你在調(diào)用該header()函數(shù)的方法內(nèi)的return值,例如return 123;則csv文件中就是123。
這種方式可以實(shí)現(xiàn)下載,但是總歸看上去不太好看,如此優(yōu)秀的laravel框架怎么可能會(huì)不涉及到下載方法的封裝呢,于是后來使用了另一種方法。

二、通過response方法實(shí)現(xiàn)下載

在看了其他前輩寫的代碼中,我發(fā)現(xiàn)有一行代碼

return reponse()->download($file)

看單詞意思也知道這行代碼是起什么作用的。Response是laravel框架中的門面(facade),在這個(gè)框架中是可以直接引用調(diào)用的功能
例如:

//響應(yīng)重定向
Route::get('example/test24', function(){
    return Redirect::to('example/test21')->with('username', 'xiaoming');
});
//定制HTTP響應(yīng)
Route::get('example/test21', function(){
    return Response::make('內(nèi)容不存在', 404);
});
//響應(yīng)視圖
Route::get('example/test22', function(){
    return Response::view('test22');
});

以上的例子是response在封閉函數(shù)中的直接調(diào)用,在其他的地方自然也是可以直接使用的,而下載文件就可以使用Response::download()方法
我們先看一下這個(gè)的源代碼:

    /**
     * Create a new file download response.
     *
     * @param  \\SplFileInfo|string  $file
     * @param  string  $name
     * @param  array  $headers
     * @param  string|null  $disposition
     * @return \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse
     */
    public function download($file, $name = null, array $headers = [], $disposition = 'attachment');

可以看到這個(gè)下載方法的參數(shù),有$file, $name = null, array $headers = [], $disposition = 'attachment',后面都有默認(rèn)值,可以不傳遞,也可以用于參數(shù)擴(kuò)展,利用這個(gè)方法就可以實(shí)現(xiàn)下載
例如:

public function getDownload()
{
    //PDF file is stored under project/public/download/info.pdf
    $file= public_path(). "/download/info.pdf";
    $headers = array(
              'Content-Type: application/pdf',
            );
    return Response::download($file, 'filename.pdf', $headers);
}

由此處的header()可以看出是要求下載一個(gè)pdf文件,而在laravel 5框架中使用此功能還可以使用

return response()->download($file, 'filename.pdf', $headers);

這種方式,功能是一樣的,其中也可以只指定第一個(gè)參數(shù),這樣下載的文件就是你的文件之前指定好的類型。

寫入csv文件方法

介紹了如何實(shí)現(xiàn)下載的兩種方法,現(xiàn)在來說一下如何將數(shù)據(jù)寫入csv文件

字符串連接方法

首先要知道,csv文件的內(nèi)容其實(shí)就是一串拼接起來的字符串,起始指定好表頭字符串,后面就以該表頭的順序依次拼接數(shù)據(jù)即可,只是在表頭和每一行數(shù)據(jù)的末尾都添加一個(gè)換行符\\n來達(dá)到表格對(duì)齊的效果即可。
例如:

$head_str = "日期,姓名,年齡,學(xué)校\\n";
$cnt  = count($data);
for ($i =0;$i<$cnt;$i++) {
        $tmp = implode(",",$data[$i]);
        $head_str .= $tmp."\\n";
}

其中$data是從庫(kù)中取出的數(shù)據(jù)的二維數(shù)組,而每一個(gè)第一層索引指向的就是對(duì)應(yīng)的每一行數(shù)據(jù),然后利用for循環(huán)遍歷取出每一行數(shù)據(jù)進(jìn)行拼接。
這一種方法是和傳遞HTTP報(bào)頭實(shí)現(xiàn)下載的方法配合使用效果更好,因?yàn)樵谄唇油瓿珊笾苯釉诜椒▋?nèi)return $head_str,就能將整個(gè)數(shù)據(jù)內(nèi)容讀入到了下載的csv文件中。當(dāng)然,也可以使用fwrite()方法寫入一個(gè)新文件$file,然后利用response->download($file)方法下載該文件即可。

export()方法

后來發(fā)現(xiàn),每次這樣拼接數(shù)據(jù)非常的麻煩,可以寫一個(gè)公共的方法,以便在其他地方實(shí)現(xiàn)類似的功能時(shí)可以直接調(diào)用

    public static function exportData($data = array(), $title = [])
    {
        $new_data = [];
        if (!empty($data)) {
            if(empty($title))
            {
                foreach ($data as $key => $val) {
                    $new_data[$key] = isset($val) ?   mb_convert_encoding($val, 'gbk', 'utf-8') : '';
                }
            } else {
                foreach ($title as $key => $val) {
                    $new_data[$key] = isset($data[$key]) ? mb_convert_encoding($data[$key], 'gbk', 'utf-8') : '';
                }
            }
            $str =  implode(',', $new_data);
            fwrite(self::$fp, $str."\\n");
        }
    }

這個(gè)方法的實(shí)現(xiàn)原理是將數(shù)據(jù)進(jìn)行轉(zhuǎn)碼處理然后利用fwrite()方法寫入一個(gè)新文件。其中self::$fp是指定的文件的路徑,這個(gè)php手冊(cè)上看一下fwrite()方法的介紹就能曉得參數(shù)的意思。寫入了新的文件后就可以再通過reponse->download()方法來下載了。

php文件打包教程

在數(shù)據(jù)量非常龐大時(shí),一次性取出大量的數(shù)據(jù)然后寫入csv文件再下載的這個(gè)流程是不適用的,因?yàn)閿?shù)據(jù)量龐大會(huì)導(dǎo)致取數(shù)時(shí)間很長(zhǎng),命令運(yùn)行超出內(nèi)存。此時(shí)可以采用的方法就是將大量的數(shù)據(jù)按時(shí)間維度寫入多個(gè)csv文件,然后再根據(jù)需要的時(shí)間區(qū)間將多個(gè)csv文件打包下載即可,所以在這也講一下我如何實(shí)現(xiàn)文件打包。
在php中,利用的是ZipArchive()類,通過這個(gè)類的實(shí)例化來實(shí)現(xiàn)打包。

依然是感興趣的同學(xué)自行在php手冊(cè)上學(xué)習(xí)

代碼:

//獲取zip包名
$zip_file = $save_path . '/' . $start_date . '-' . $end_date . '.zip';
if (file_exists($zip_file)) {
        return response()->download($zip_file);
}
//文件打包
$zip = new ZipArchive();
if ($zip -> open($zip_file, ZipArchive::CREATE) == true) {
        foreach ($file_dir as $file) {
             if (file_exists($file)) {
             $zip -> addFile($file, basename($file));
             }
        }
}
$zip -> close();

這樣就實(shí)現(xiàn)了打包,其中$file_dir變量是你要打包的文件的路徑數(shù)組,里面包含所有你想打包的文件路徑,$zip_file變量是你想打包成zip文件的包的路徑+名稱。

有的同學(xué)在使用此方法時(shí)有時(shí)會(huì)不管用,以我的經(jīng)驗(yàn),一般都是文件的路徑不正確,或者是沒有指定絕對(duì)路徑
注意:在$zip -> addFile()方法中不要使用路徑變量拼接,最好在使用該方法前就寫好路徑。使用了拼接不會(huì)報(bào)錯(cuò),但是依然會(huì)文件添加不進(jìn)去,這里是一個(gè)大坑,我找了好久才發(fā)現(xiàn)。

最后:本人新手程序員,一起進(jìn)步?。。?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,836評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,808評(píng)論 25 708
  • //我所經(jīng)歷的大數(shù)據(jù)平臺(tái)發(fā)展史(三):互聯(lián)網(wǎng)時(shí)代 ? 上篇http://www.infoq.com/cn/arti...
    葡萄喃喃囈語閱讀 51,285評(píng)論 10 200
  • 親愛的,每天都好想你,miss you so much 我發(fā)現(xiàn),以前,我會(huì)生你的氣好久,現(xiàn)在,上一秒生氣下一秒就想...
    8454a51837ec閱讀 133評(píng)論 0 0
  • 姓名;沈軍耀 公司;寧波大發(fā)化纖有限公司 組號(hào);反省一組 期數(shù);224期。日精進(jìn)打卡一百零二十二天 (知~學(xué)習(xí));...
    沈軍耀閱讀 529評(píng)論 0 2