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

對于許多的從事數(shù)據(jù)智能開發(fā)的同僚來說,從庫中提取出數(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è)功能叹括,但是對于一個(gè)理工科生來說算墨,碰到問題并不可怕,剝絲抽繭汁雷,一步一步來净嘀。我分析,既然要實(shí)現(xiàn)下載功能接口侠讯,首先需要做的就是提供一個(gè)接口挖藏,而如何做一個(gè)接口我在<<Laravel使用心得--簡易路由操作>>中已介紹,向前端提供一個(gè)URI即達(dá)到了接口的意義厢漩,其次是如何實(shí)現(xiàn)下載膜眠,最后是如何寫入一個(gè)csv文件,本篇文章就從后兩個(gè)方向介紹溜嗜,并且最后附帶PHP中文件打包功能的實(shí)現(xiàn)介紹

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

下載

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

首先在度娘上找到的實(shí)現(xiàn)下載的方式之一:是通過向?yàn)g覽器傳遞HTTP報(bào)頭,告訴瀏覽器這個(gè)URI的相關(guān)動作讓瀏覽器去實(shí)現(xiàn)土全。
HTTP報(bào)頭是HTTP協(xié)議的一個(gè)部分捎琐,一般上用于客戶端和服務(wù)端之間握手時(shí)的通信,通俗的理解就是 http服務(wù)器和客戶端(一般為瀏覽器)之間數(shù)據(jù)傳輸之前的對話涯曲,告訴瀏覽器你想干什么野哭。
而在PHP中實(shí)現(xiàn)HTTP報(bào)頭參數(shù)傳遞功能的是header()方法,header() 函數(shù)向客戶端發(fā)送原始的 HTTP 報(bào)頭幻件。其中認(rèn)識到一點(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框架怎么可能會不涉及到下載方法的封裝呢弧哎,于是后來使用了另一種方法。

二稚虎、通過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á)到表格對齊的效果即可钾怔。
例如:

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

其中$data是從庫中取出的數(shù)據(jù)的二維數(shù)組碱呼,而每一個(gè)第一層索引指向的就是對應(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手冊上看一下fwrite()方法的介紹就能曉得參數(shù)的意思。寫入了新的文件后就可以再通過reponse->download()方法來下載了矾缓。

php文件打包教程

在數(shù)據(jù)量非常龐大時(shí)怀酷,一次性取出大量的數(shù)據(jù)然后寫入csv文件再下載的這個(gè)流程是不適用的,因?yàn)閿?shù)據(jù)量龐大會導(dǎo)致取數(shù)時(shí)間很長而账,命令運(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手冊上學(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í)會不管用肌幽,以我的經(jīng)驗(yàn)晚碾,一般都是文件的路徑不正確,或者是沒有指定絕對路徑
注意:在$zip -> addFile()方法中不要使用路徑變量拼接喂急,最好在使用該方法前就寫好路徑格嘁。使用了拼接不會報(bào)錯(cuò),但是依然會文件添加不進(jìn)去廊移,這里是一個(gè)大坑糕簿,我找了好久才發(fā)現(xiàn)。

最后:本人新手程序員狡孔,一起進(jìn)步6!苗膝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末殃恒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荚醒,更是在濱河造成了極大的恐慌芋类,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件界阁,死亡現(xiàn)場離奇詭異,居然都是意外死亡胖喳,警方通過查閱死者的電腦和手機(jī)泡躯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人较剃,你說我怎么就攤上這事咕别。” “怎么了写穴?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵惰拱,是天一觀的道長。 經(jīng)常有香客問我啊送,道長偿短,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任馋没,我火速辦了婚禮昔逗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘篷朵。我一直安慰自己勾怒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布声旺。 她就那樣靜靜地躺著笔链,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腮猖。 梳的紋絲不亂的頭發(fā)上鉴扫,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音缚够,去河邊找鬼幔妨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谍椅,可吹牛的內(nèi)容都是我干的误堡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼雏吭,長吁一口氣:“原來是場噩夢啊……” “哼锁施!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杖们,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悉抵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后摘完,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姥饰,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年孝治,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了列粪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片审磁。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖岂座,靈堂內(nèi)的尸體忽然破棺而出态蒂,到底是詐尸還是另有隱情,我是刑警寧澤费什,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布钾恢,位于F島的核電站,受9級特大地震影響鸳址,放射性物質(zhì)發(fā)生泄漏瘩蚪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一氯质、第九天 我趴在偏房一處隱蔽的房頂上張望募舟。 院中可真熱鬧,春花似錦闻察、人聲如沸拱礁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呢灶。三九已至,卻和暖如春钉嘹,著一層夾襖步出監(jiān)牢的瞬間鸯乃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工跋涣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缨睡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓陈辱,卻偏偏與公主長得像奖年,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子沛贪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

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

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