數(shù)據(jù)庫可以存字節(jié)數(shù)據(jù)的啊,自己寫到數(shù)據(jù)庫即可,讀出來后再形成文件即可
成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的賈汪網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
對于任何一個(gè)網(wǎng)站肯定是少不了下載功能,常見的下載功能有圖片、視頻、Excel表格,如果文件比較小的話,那么不會(huì)遇到任何的問題,但是當(dāng)文件信息而超過了PHP的最大內(nèi)存,那么在這個(gè)時(shí)候它就會(huì)有的內(nèi)存溢出的問題。
那么它們是因?yàn)槭裁炊l(fā)生的?對于這個(gè)過程的原理才是我們應(yīng)該真正要去弄明白的事情
下載大數(shù)據(jù)量的EXCEL文件為何要報(bào)錯(cuò)?
PHP在下載大Excel表格的時(shí)候,那么首先它是需要去把MySQL的數(shù)據(jù)從硬盤上面讀取到內(nèi)存,但讀取它是一次性載入到我們的內(nèi)存,如果說它一次性載入的數(shù)據(jù)量遠(yuǎn)遠(yuǎn)大于最大內(nèi)存,然后再來執(zhí)行瀏覽器的業(yè)務(wù)下載。那么這個(gè)時(shí)候它就會(huì)發(fā)生我們這個(gè)內(nèi)存溢出。
就比如:說我們現(xiàn)在有100M的數(shù)據(jù)量,但是我們PHP內(nèi)存最大只有64M,那么這個(gè)它肯定是裝不了的,我們可以把那個(gè)內(nèi)存比喻為一個(gè)水杯,這個(gè)水杯的容量比喻為內(nèi)存,現(xiàn)在杯子最大容量為64L。你要存放100L??隙ǚ挪幌?/p>
大事化小,小事化了。拆分成段
從上面可以看到文件下載,它是分為兩步,首先是載入內(nèi)存然后執(zhí)行瀏覽器的輸出下載,那么既然大型文件一次性載入不了,那可以采用“大事化小,小事化了”思路,我們可以實(shí)現(xiàn)邊寫邊下載,也就是分批次的讀取與寫入。
因?yàn)橛脩舻脑挘灰罱K拿到這個(gè)文件就可以,對于瀏覽器的下載原理不需要關(guān)心。只需要給到文件下載提示給用戶即可,然后后端在實(shí)時(shí)的分批次的寫入到要下載的文件當(dāng)中。
實(shí)現(xiàn)思路步驟:
1、一設(shè)置瀏覽器下載Excel需要的Header
2、打開php://output流,并設(shè)置寫入文件句柄。
注:(php://output,是一個(gè)可寫的輸出流,允許程序像操作文件一樣將輸出寫入到輸出流中,PHP會(huì)把輸出流中的內(nèi)容發(fā)送給web服務(wù)器并返回給發(fā)起請求的瀏覽器)
3、獲取數(shù)據(jù)庫所有數(shù)據(jù)量,并設(shè)置每次查詢的條數(shù),通過這兩個(gè)值計(jì)算分批查詢的次數(shù)
4、基于分批查詢的次數(shù)循環(huán)查詢數(shù)據(jù)庫,然后寫入到文件中,同時(shí)清除本次操作變量內(nèi)存,刷新緩沖到瀏覽器,讓瀏覽器的文件始終實(shí)時(shí)保持到最新的大小
注:刷新用ob_flush、flush()
PHP的I/O流
在這里我們用到了PHP的一個(gè)IO的輸入輸出,也就是我們常用的
php://inputphp://output。
php://input
php://input可以讀取原始的POST數(shù)據(jù)。相較于$form-data”.
注:p
php://output是一個(gè)只寫的數(shù)據(jù)流,允許你以print和echo一樣的方式寫入到輸出緩沖區(qū)。
綜上:實(shí)現(xiàn)思維與原理很重要如有感悟,歡迎在線咨詢
PHP文件下載的原理及實(shí)現(xiàn)
通常文件下載過程是十分簡單的 建立一個(gè)鏈接指向到目標(biāo)文件就可以了 例如下面的鏈接
a href=// xxx /xxx rar點(diǎn)擊下載文件/a
但是 實(shí)際情況可能會(huì)稍復(fù)雜 比如需要用戶填寫完整注冊信息后才可以下載該文件 這時(shí)最先想到的是使用Redirect的方式 下面介紹兩種方式
( )用Redirect方式 先檢查表格是否已經(jīng)填寫完畢和完整 然后將鏈接指到該文件 這樣用戶就可以下載 請看下面的示例代碼
?php
/*文件功能 檢查變量form是否完整*/
if($form){
//重新定向?yàn)g覽器指向
Header( Location: // // xxx /xxx rar )
exit;
}
?
( )根據(jù)下載文件的序號來查找 鏈接的形式如下
a href= // xxx /download php?id= 點(diǎn)擊下載文件/a
上面的鏈接使用ID方式接收要下載文件的編號 然后再用Redirect的方式連接到真實(shí)的文件鏈接
以上這兩種方法雖然實(shí)現(xiàn)了文件的下載功能 但是缺點(diǎn)是直接暴露了文件所屬的路徑 而且沒有防盜鏈的功能 所以上面的方式是簡單直接但存在安全隱患的文件下載方式 在PHP中 通常是利用header()函數(shù)和fread()函數(shù)來實(shí)現(xiàn)安全的文件下載
例如 需要下載的是一個(gè)文件名為xxx rar的文件 首先創(chuàng)建文件是download php的PHP文件 通過前面的例子很容易通過文件的ID號從數(shù)據(jù)庫中得到待下載文件的真實(shí)位置 在獲得文件的真實(shí)存儲(chǔ)位置后 可以通過header()函數(shù)的location參數(shù)直接重定向到這個(gè)文件 但是這樣仍然是不安全的 因?yàn)槟承┫螺d軟件還是可以通過重定向分析獲得該文件的位置信息 因此需要用另外一種方法 就是PHP的文件處理API函數(shù) 它是通過fread()函數(shù)把文件直接輸出到瀏覽器提示用戶下載 這樣所有的處理都是在服務(wù)器端完成的 因此用戶就無法獲得文件具體存儲(chǔ)位置信息的 示例代碼如下
?
$file_name = xxx rar ;???? //下載文件名
$file_dir = /up/ ;??????? //下載文件存放目錄
//檢查文件是否存在
if (! file_exists ( $file_dir $file_name )) {
echo 文件找不到 ;
exit ()
} else {
//打開文件
$file = fopen ( $file_dir $file_name r )
//輸入文件標(biāo)簽
Header ( Content type: application/octet stream )
Header ( Accept Ranges: bytes )
Header ( Accept Length: filesize ( $file_dir $file_name ) )
Header ( Content Disposition: attachment; filename= $file_name )
//輸出文件內(nèi)容
//讀取文件內(nèi)容并直接輸出到瀏覽器
echo fread ( $file filesize ( $file_dir $file_name ) )
fclose ( $file )
exit ()
}
?
【代碼解讀】
上述代碼中 程序發(fā)送Header信息是用來告訴Apache和瀏覽器下載文件的相關(guān)信息的 content type的含義代表文件MIME類型是文件流格式 如果在Apache配置里面把文件的MIME類型設(shè)為application/octet stream(如add application/octet stream xxx rar) 那么瀏覽器(客戶端)就會(huì)知道 這是一個(gè)文件流格式的文件并提示用戶下載 Accept Ranges是一個(gè)響應(yīng)頭標(biāo) 它允許服務(wù)器指明將在給定的偏移和長度處 為資源組成部分的接受請求 該頭標(biāo)的值被理解為請求范圍的度量單位 Content Length是指定包含于請求或響應(yīng)中數(shù)據(jù)的字節(jié)長度 例如 Content Length: Content Disposition:attachment是用來告訴瀏覽器 文件是可以當(dāng)做附件被下載 下載后的文件名稱為$file_name該變量的值
運(yùn)行download php文件 效果如圖 所示 從圖中可以看到文件按照預(yù)想的方式被提示下載 單擊 保存 按鈕將文件保存在本地
圖 ? PHP文件安全下載
返回目錄 PHP典型模塊與項(xiàng)目實(shí)戰(zhàn)大全
編輯推薦
Java Web開發(fā)詳解
PHP Web開發(fā)學(xué)習(xí)實(shí)錄
lishixinzhi/Article/program/PHP/201311/21519