PHP之文件的锁定、上传与下载
PHP之文件的锁定、上传与下载
小结文件的锁定机制、上传和下载
1.文件锁定
现在都在讲究什么分布式、并发等,实际上文件的操作也是并发的,在网络环境下,多个用户在同一时刻访问页面,对同一服务器上的同一文件进行着读取,如果,这个用户刚好读到一半,另一个用户就写入了消息,那么前一个用户读到的就是错误数据,在数据库里面好像是称为脏数据,而如果某用户写到一半时,另一用户也对该文件进行写操作,那么就造成了写入数据的混乱和错误,因此才php有一个锁机制,类似于数据库的锁,当某用户在对文件操作时就加上某种锁,使得在同一时间其他用户不能对该文件进行操作或只能进行有限的操作,来保证在这些情况下的文件数据的正确性。
主要使用flock函数,原型:bool flock(resource $handle , int $operation [, int &$wouldblock ]),第一个参数是指向文件的句柄变量,第二个是加锁的方式,分别为
LOCK_SH:共享锁(share),在读取文件时加的锁,加锁后就其他用户不能再对该文件进行写,但可以读取该文件内容;
LOCK_EX:排他锁(exclude),或者叫独占锁,在写文件时使用,加了该锁后,只能是当前用户进行写操作,其他的用户不能读取和写入;
LOCK_NB:附加锁,在文件锁定短时间大量用户的访问操作可能会造成flock在锁定时堵塞,如果再加上该锁后可避免该情况(是不是这么一弄就能解决大量读写操作的问题,怕不行...);
LOCK_UN:释放锁,对前面的各种锁进行一次性释放,解锁。
如果容易堵塞,还可使用第三个参数wouldblock,如果把它设置为1,在锁定后就会阻挡其他进程来进行一些操作,但是windows上不支持,另外附加锁LOCK_NB,windows也是不支持的。
另外,关闭句柄变量的fclose操作也可以释放这些锁。
废话少说,看代码
复制代码
function readFileData($filename){
if(true == ($handle = fopen($filename, 'r'))){
if(flock($handle, LOCK_SH+LOCK_NB)){ // 加共享锁和附加锁,附加锁防止阻塞
$str = '';
while(!feof($handle)){
$str .= fread($handle, 128);
}
flock($handle, LOCK_UN); // 释放该锁
fclose($handle);
return $str;
}
else{
echo 'add a share lock failed';
return '';
}
}
else{
return '';
}
}
复制代码
注意使用多重锁的方式,是LOCK_SH+LOCK_NB,,在排他锁时也可这么用,它们都是枚举变量。对于写操作类似
复制代码
function writeInFile($filename, $data){
if(true == ($handle = fopen($filename, 'a'))){
if(flock($handle, LOCK_EX)){ //加上排他锁
fwrite($handle, $data);
flock($handle, LOCK_UN); //释放锁
fclose($handle);
}
else{
echo 'add exclusive lock failed';
return;
}
}
}
复制代码
实际上这也是解决php来实现多进程/线程读取文件的方式,php没有多线程这么一说,但加锁机制可以来模拟这种方式,实现对文件某些操作的队列处理,面试时别说你不知道-_-
2.文件上传
文件上传就是将本地的文件上传到服务器上,我们在用度场的云、鹅场的云上传文件时均是如此,当然实际情况肯定比这简单程序复杂。HTTP协议实现了文件的上传机制,首先要在本地选择上传的文件,上传到服务器后,服务端又要做一些处理,为此客户端和服务端均要做一些设置。
1、客户端
文件上传最基本的方法是通过form表单进行POST传递文件,实际上通过PUT方法也可以上传文件,只不过这种方法不安全,需要配置一些安全验证机制,这里只写最常用的方式。form表单的input标签可以设置成文件上传按钮type="file",直接解决了如何选择文件的问题,接下来需要设置form的两个属性:enctype和method
enctype:设置成multipart/form-data
method:设置成post
关于enctype属性设置可参考W3School的解释
第一条是默认的值,在我们使用HTTP协议传递一般的表单数据时,实际上默认对数据进行了分块编码,比如默认的urlencode方式(空格转为+,其他非字母字符转为%加两个十六进制大写数);当enctype设置为第二个时,不会进行字符编码,使用上传控件(input标签type设为file时即是)上传文件,必须设定为这个值;第三个则是值对空格编码为+,但不对非字母字符进行编码。
我们知道GET方法一般用于获取数据,且传递数据大小有限,而且POST方法可以传递比GET大得多的数据。
form的属性设置完成后,还要传递一个值过去,使用隐藏域(),它的name属性设为MAX_FILE_SIZE,之所以要设定这个值,是先大概定一个文件尺寸值,避免在用户传一个大文件传了半天再告诉他:sorry,你的文件太大了-_-它的value属性值就是文件的size,以字节为单位。当然某些书上说,这个值只是作为参考,可轻易进行欺骗,这里只是象征性的表示,很可惜我这只菜鸟对安全了解甚少,只知道普通注入、XSS等,暂且用着吧。
那么就可以写一个简单得不能再简单的页面了,作为客户端用:
2、服务端
文件上传到了服务器上还要经过一些处理过程,就像网购派送快递,到了目的地也还得分个类,确认下目的地对错吧。到了目的地的后续处理需要php脚本,上面在提交表单时的action属性就指定了提交的处理脚本。我们知道在php中,$_POST保存的是post传递的数据,而上传文件的相关信息保存在$_FILES里边,假设服务端脚本是这样的:
echo '_FILES:
'; <p> print_r($_FILES);</p> <p> </p> <p> echo '_POST: </p><pre class="brush:php;toolbar:false">'; <p> print_r($_POST);</p> <p> 不管服务端如何处理的,先看看这两个数组里面有什么:</p> <p> </p> <p> </p> <p> </p> <p> 看FILES数组的选项就猜得到,这些就是上传文件的名字、类型、尺寸、错误信息等等,还有这个FILES是二维数组。在弄清楚这些选项之前有必要了解几个php配置选项,打开php.ini文件,找到下面四项(其实看注释也明白了):</p> <p> </p> <p> file_uploads:是否允许通过HTTP传递文件,默认是On允许;</p> <p> </p> <p> upload_max_filesize:允许传递文件的最大大小,以M为单位,这是服务端配置文件设定的选项;</p> <p> </p> <p> max_file_uploads:一次请求所允许传递的做多文件个数;</p> <p> </p> <p> post_max_size:通过POST传递数据的最大大小,因为文件传递也是post方式,也算post传递,需要特别注意的是,它必须要大于upload_max_filesize选项,因为在一次post传递过程中不仅会上传文件,还会传递其他数值,比如上面的POST数组中的数据,必须考虑到,比如upload_max_filesize设为150M,这个就可以设为200M;</p> <p> </p> <p> upload_tmp_dir:上传文件的临时目录,配置文件里面默认为空,会使用操作系统默认的临时目录,因此上面的FILES数组中的tmp_name中的眼熟的路径就可以解释了,使用windows默认的存放临时文件的目录,而且服务器默认对文件名作了修改。</p> <p> </p> <p> 那么FILES数组中的uploadFile哪里来的,为什么要用它做键名,这是因为在上传控件的name属性就是uploadFile,它标记的是这个控件的上传文件信息,因此我们可以放多个上传控件,设置不同的name,当然设置一样的name也可以,完全可以把它们全放在一个数组里边,如<input type="file" name="upload[]">。</p> <p> </p> <p> 现在回过头看FILE数组的键名代表的信息,type是MIME类型,以/分隔,前面是主要类型,后面是具体文件类型,error肯定表示错误,有这么几种情况,0:没有错误,上传成功; 1:文件超过了PHP配置指令中的upload_max_filesize规定的大小; 2:文件超过HTML表单中MAX_FILE_SIZE规定的大小,3:文件只有部分上传; 4:没有文件上传。现在关于FILES数组的问题全部明白了。</p> <p> </p> <p> 问题是,是不是上传成功就不做任何处理了,当然不是,总不能全堆在一个临时目录里面,上传多了必然就要将文件移到别的地方,而php提供了专门而安全的函数。is_uploaded_file函数,判断是否通过HTTP POST上传,可以确保恶意的用户去欺骗脚本而管理这些文件,例如/etc/pass(又是linux...),至于具体怎样,我还不清楚。move_uploaded_file函数,将上传文件移动到新位置,同时还可判断文件是否为合法上传,即通过HTTP POST方式,他们运行成功均返回布尔类型true。</p> <p> </p> <p> 扯了半天,上传文件大概要经过这样几个步骤:</p> <p> </p> <p> 1、客户端写好上传控件脚本,并传递一个限制文件大小的隐藏值;</p> <p> </p> <p> 2、服务端首先判断FILES数组error值,看是否出错;</p> <p> </p> <p> 3、判断是否为允许上传的类型(可以不判断);</p> <p> </p> <p> 4、判断在服务端脚本里边是否超过指定的文件大小;</p> <p> </p> <p> 5、上传到临时位置,生成新文件名(防止把已有同名文件覆盖掉),检查并移动到新目录下。</p> <p> </p> <p> 客户端准备工作刚已做,看服务端处理代码:</p> <p> </p> <p>复制代码</p> <p><?php </p> </p><p> $typeWhiteList = array('txt', 'doc', 'php', 'zip', 'exe'); // 类型白名单,过滤不允许上传的文件类型</p> <p> $max_size = 1000000; // 大小限制 为1M</p> <p> $upload_path = 'D:/WAMP/upload/'; // 指定移至的目录</p> <p> </p> <p> // 1、判断是否成功上传到服务器 </p> <p> $error = $_FILES['uploadFile']['error'];</p> <p> if($error > 0){</p> <p> switch($error){</p> <p> case 1: exit('超过php配置的最大文件上传限制');</p> <p> case 2: exit('超过HTML表单的最大文件上传限制');</p> <p> case 3: exit('文件只有部分被上传');</p> <p> case 4: exit('没有上传任何文件');</p> <p> default: exit('未知类型错误');</p> <p> }</p> <p> }</p> <p> </p> <p> // 2、判断是否为允许上传的类型</p> <p> $extension = pathinfo($_FILES['uploadFile']['name'], PATHINFO_EXTENSION); // 获取扩展名</p> <p> if(!in_array($extension, $typeWhiteList)){</p> <p> if($extension == '')</p> <p> exit('不允许上传空类型文件');</p> <p> else </p> <p> exit('不允许上传'.$extension.'类型文件');</p> <p> } </p> <p> </p> <p> // 3、判断是否为允许大小</p> <p> if($_FILES['uploadFile']['size'] > $max_size){</p> <p> exit('超过了允许上传到的'.$max_size.'字节');</p> <p> }</p> <p> </p> <p> // 4、已到指定位置</p> <p> $filename = date('Ymd').rand(1000, 9999); // 生成一个新文件名,防止覆盖</p> <p> if(is_uploaded_file($_FILES['uploadFile']['tmp_name'])){ // 判断是否通过HTTP POST上传</p> <p> if(!move_uploaded_file($_FILES['uploadFile']['tmp_name'], $upload_path.$filename.'.'.$extension)){</p> <p> exit('无法移动到指定位置');</p> <p> }</p> <p> else{</p> <p> echo '文件上传成功<br>';</p> <p> echo '文件名: '.$upload_path.$filename.'.'.$extension.'<br>';</p> <p> }</p> <p> }</p> <p> else{</p> <p> exit('文件未通过合法途径上传');</p> <p> }</p> <p>复制代码</p> <p> 本想迅速体验一把,结果报了个Warning,说时间设置依赖系统...bug总是这么不期而遇,设置好时间后,再试,perfect!</p> <p> </p> <p> </p> <p> </p> <p> 3.文件下载</p> <p> </p> <p> 文件下载就比较简单了,简单的文件下载只需要用一个HTML链接就够了,使用<a>标签,href属性指定资源位置,一点就可。但这种方式只能处理浏览器默认无法识别的MIME类型,比如rar、7z等压缩的数据。</a></p> <p> </p> <p>复制代码</p> <p></p> <p> </p> <p> </p><title>donwload file</title> <p> <meta http-equiv="Content-Type" content="text/html" charset="utf-8"></p> <p> </p> <p> </p> <p> <a href="resource/header.txt">header.txt</a><br></p> <p> <a href="resource/php.zip">php.zip</a><br></p> <p> <a href="resource/pic.ico">pic.ico</a></p> <p> </p> <p> </p> <p></p> <p>复制代码</p> <p> 对于这些浏览器不认识的类型文件,点链接,它直接弹框让你下载,有的浏览器甚至直接就下了,那么对于文本txt、jpg等浏览器默认识别的类型的文件,一点击则会直接展现在页面上,比如上面header.txt、pic.ico。如何不展示在页面上而去下载它们呢,使用header函数。</p> <p> </p> <p> header函数会通过发送头信息告知,请把该文件当成一个附件,这样点击的时候,就也会下载了。</p> <p> </p> <p>复制代码</p> <p><?php </p> </p><p> $filename = 'header.txt';</p> <p> header('Content-Type: text/plain'); // 类型为普通文本</p> <p> header('Content-Disposition:attachment; filename="$filename"'); // Content-Disposition:attachment,告诉它这是附件</p> <p> header('Content-Length:'.filesize($filename)); // 告知文件大小</p> <p> </p> <p> readfile($filename); // 读取文件直接输出,便于下载</p> <p>复制代码</p>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

開啟微信,在我中選擇設置,選擇通用後選擇儲存空間,在儲存空間選擇管理,選擇要恢復檔案的對話選擇感嘆號圖示。教學適用型號:iPhone13系統:iOS15.3版本:微信8.0.24解析1先開啟微信,在我的頁面中點選設定選項。 2接著在設定頁面中找到並點選通用選項。 3然後在通用頁面中點選儲存空間。 4接下來在儲存空間頁面中點選管理。 5最後選擇要恢復檔案的對話,點選右側的感嘆號圖示。補充:微信文件一般幾天過期1要是微信接收的文件並沒有點開過的情況下,那在七十二鐘頭之後微信系統會清除掉,要是己經查看了微信

在Windows系統中,照片應用程式是一個方便的方式來檢視和管理照片和影片。透過這個應用程序,用戶可以輕鬆存取他們的多媒體文件,而無需安裝額外的軟體。然而,有時用戶可能會碰到一些問題,例如在使用照片應用程式時遇到「無法開啟此文件,因為不支援該格式」的錯誤提示,或在嘗試開啟照片或影片時出現文件損壞的問題。這種情況可能會讓使用者感到困惑和不便,需要進行一些調查和修復來解決這些問題。當用戶嘗試在Photos應用程式上開啟照片或影片時,會看到以下錯誤。抱歉,照片無法開啟此文件,因為目前不支援該格式,或該文件

在本文中,我們將介紹如何解決在Windows系統中刪除檔案或資料夾時出現「準備刪除」提示的問題。這個提示意味著系統正在進行一些背景操作,例如檢查檔案權限、驗證檔案是否被其他程式佔用、計算要刪除項目的大小等。我們將為您提供一些解決方法,以確保您能夠順利刪除文件,而無需等待太長時間。為什麼Windows要花這麼長時間才能刪除檔案? Windows準備刪除檔案所需的時間受多種因素影響,包括檔案大小、儲存裝置速度和後台進程。長時間或被卡住的「正在準備刪除」提示可能暗示系統資源不足、磁碟錯誤或檔案系統問題。在

Tmp格式檔案是一種暫存檔案格式,通常由電腦系統或程式在執行過程中產生。這些文件的目的是儲存臨時數據,以幫助程式正常運行或提高效能。一旦程式執行完成或電腦重啟,這些tmp檔案往往就沒有了存在的必要性。所以,對於Tmp格式檔案來說,它們本質上是可以刪除的。而且,刪除這些tmp檔案能夠釋放硬碟空間,確保電腦的正常運作。但是,在刪除Tmp格式檔案之前,我們需

在電腦中刪除或解壓縮資料夾,時有時會彈出提示對話框“錯誤0x80004005:未指定錯誤”,如果遇到這中情況應該怎麼解決呢?提示錯誤碼0x80004005的原因其實很多,但大部分因為病毒導致,我們可以重新註冊dll來解決問題,下面,小編給大夥講解0x80004005錯誤代碼處理經驗。有使用者在使用電腦時出現錯誤代碼0X80004005的提示,0x80004005錯誤主要是由於電腦沒有正確註冊某些動態連結庫文件,或電腦與Internet之間存在不允許的HTTPS連接防火牆所引起。那麼如何

gho檔案是一種GhostImage影像文件,它通常用於將整個硬碟或分割區的資料備份成一個檔案。在一些特定的情況下,我們需要將這種gho檔案重新安裝回硬碟上,以還原硬碟或分割區到先前的狀態。下面將介紹gho檔案的安裝方法。首先,在安裝之前,我們需要準備以下工具和材料:實體的gho文件:確保你擁有一份完整的gho文件,它通常以.gho為後綴名,並且包含有備份

夸克網盤和百度網盤都是現在最常用的儲存文件的網盤軟體,如果想要將夸克網盤內的文件保存到百度網盤,要怎麼操作呢?本期小編整理了夸克網盤電腦端的檔案轉移到百度網盤的教學步驟,一起來看看是怎麼操作吧。 夸克網盤的檔案怎麼存到百度網盤?要將夸克網盤的文件轉移到百度網盤,首先需在夸克網盤下載所需文件,然後在百度網盤用戶端中選擇目標資料夾並開啟。接著,將夸克網盤中下載的檔案拖放到百度網盤用戶端開啟的資料夾中,或使用上傳功能將檔案新增至百度網盤。確保上傳完成後在百度網盤中查看檔案是否已成功轉移。這樣就

檔案路徑是作業系統中用於識別和定位檔案或資料夾的字串。在檔案路徑中,常見的有兩種符號分隔路徑,即正斜線(/)和反斜線()。這兩個符號在不同的作業系統中有不同的使用方式和意義。正斜線(/)是Unix和Linux系統中常用的路徑分隔符號。在這些系統中,檔案路徑是以根目錄(/)為起始點,每個目錄之間使用正斜線進行分隔。例如,路徑/home/user/Docume
