文件的下載很簡單,在前端HTML標(biāo)記語言中就能實(shí)現(xiàn)嘴拢。但是桩盲,文件的上傳卻不是那么容易,需要進(jìn)行服務(wù)器端的簡單編程席吴。而且赌结,還有很多細(xì)節(jié)方面的注意事項(xiàng),官方文件中都沒有說明孝冒,這也是很多人對(duì)文件上傳這個(gè)問題很苦惱的原因柬姚。其實(shí)只需要注意幾個(gè)細(xì)節(jié),就能輕松搞定文件上傳啦庄涡!
圖文 / 丁建雄
小白是單純?yōu)榕d趣而寫作的獨(dú)立創(chuàng)作人量承,如果您喜歡小白的文章,歡迎關(guān)注、交流宴合、分享(引用請(qǐng)鏈接到本文)焕梅。
PHP簡介
PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本預(yù)處理器”)是一種通用開源腳本語言卦洽。語法吸收了C語言贞言、Java和Perl的特點(diǎn),利于學(xué)習(xí)阀蒂,使用廣泛该窗,主要適用于Web開發(fā)領(lǐng)域。PHP 獨(dú)特的語法混合了C蚤霞、Java酗失、Perl以及PHP自創(chuàng)的語法。它可以比CGI或者Perl更快速地執(zhí)行動(dòng)態(tài)網(wǎng)頁昧绣。用PHP做出的動(dòng)態(tài)頁面與其他的編程語言相比规肴,PHP是將程序嵌入到HTML(標(biāo)準(zhǔn)通用標(biāo)記語言下的一個(gè)應(yīng)用)文檔中去執(zhí)行,執(zhí)行效率比完全生成HTML標(biāo)記的CGI要高許多夜畴;PHP還可以執(zhí)行編譯后代碼拖刃,編譯可以達(dá)到加密和優(yōu)化代碼運(yùn)行,使代碼運(yùn)行更快贪绘。
這個(gè)是百度百科的解釋兑牡,其實(shí)簡單來講,PHP就是一門在服務(wù)器端通用的編程語言税灌,功能十分強(qiáng)大均函!
HTML是一種標(biāo)記語言,而對(duì)于一些需要復(fù)雜動(dòng)態(tài)運(yùn)算的算法設(shè)計(jì)菱涤,HTML就無法實(shí)現(xiàn)了苞也。這個(gè)時(shí)候,在服務(wù)器端狸窘,就需要類似PHP墩朦,JavaScript這種腳本語言來實(shí)現(xiàn)。小白的背景是光電專業(yè)翻擒,當(dāng)時(shí)學(xué)的是C++氓涣,所以對(duì)PHP這種通用型腳本語言情有獨(dú)鐘。
PHP是一種比較松散的語言陋气,這也就使得他更接近于人類自然語言劳吠,沒有很多的限制,但是你需要注意更多的細(xì)節(jié)巩趁,才能游刃有余痒玩,小白強(qiáng)烈推薦淳附!
文件上傳
這里所指的文件上傳不同于服務(wù)器端的FTP上傳,是指在網(wǎng)頁客戶端蠢古,在訪問頁面進(jìn)行實(shí)時(shí)的文件上傳操作奴曙。
具體而言,實(shí)現(xiàn)方法有很多種草讶,比如:基于Java洽糟、xml、HTML的方法堕战;在HTML頁面直接嵌入式簡單JavaScript的方法坤溃;使用Apache fileupload庫的方法;基于HTML嘱丢、PHP腳本的方法等薪介。
小白基本這些方法都嘗試過,個(gè)人覺得HTML+PHP的方法最穩(wěn)定越驻、簡單汁政、實(shí)用。
HTML表單
HTML表單是一個(gè)強(qiáng)大的網(wǎng)頁信息交互系統(tǒng)缀旁,尤其是一些少量信息的交互烂完,表單處理將變得十分高效。
大家可以這么理解诵棵,我們?yōu)g覽網(wǎng)頁大部分時(shí)候只是為了得到信息。但是有些時(shí)候祝旷,我們需要向網(wǎng)頁反饋我們的想法履澳、信息,這個(gè)時(shí)候就需要表單出場(chǎng)了怀跛。
至于表單的細(xì)節(jié)性問題距贷,這里先不細(xì)聊,在我的前端開發(fā)文章集 [ 網(wǎng)頁設(shè)計(jì) ] 篇章會(huì)有文章專門討論表單吻谋,這里就直截了當(dāng)上代碼忠蝗。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello, world</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1>你好,世界漓拾!</h1>
<!--put your contents here-->
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<br/>
<br/>
<input type="file" name="file" id="file"/>
<br />
<input type="submit" name="submit" value="提交上傳" />
</form>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
這里代碼還是沿用的之前Hello阁最,World的版本,注意中間 <form></form>
部分是新增的代碼骇两。
稍微解釋一下各個(gè)部分的內(nèi)容:
action="upload.php"
是頁面指向速种,也就是這個(gè)表單提交的頁面URL是 upload.php
,這個(gè)頁面其實(shí)是我們下面要編寫的一個(gè)處理腳本程序低千。程序是需要變量的配阵,而下面的 input
選項(xiàng)就是存放的變量,包含了變量的類型 type
和變量的名稱 name
。
我們是制作一個(gè)上傳文件的表單棋傍,那么表單的方法就是上傳救拉,即 method="post"
。我們還要指定文件的編碼方式瘫拣,默認(rèn)地亿絮,表單數(shù)據(jù)會(huì)編碼為 application/x-www-form-urlencoded
。就是說拂铡,在發(fā)送到服務(wù)器之前壹无,所有字符都會(huì)進(jìn)行編碼,這是單純的文字的編碼方式感帅。但是斗锭,對(duì)于文件就不行了,得使用 multipart/form-data
方法失球。
那個(gè) <label>
是等同于輸入文件按鈕的一個(gè)新的標(biāo)簽岖是,也就是說你可以在同一個(gè)頁面的不同處設(shè)立上傳按鈕,上傳到同一個(gè)空間实苞,而只需要重寫標(biāo)簽豺撑,不需要重寫上傳控件。
<input type="file" name="file" id="file"/>
定義了上傳控件文件的類型黔牵、名稱聪轿、和ID(為了重定義標(biāo)簽使用的名字)。
<input type="submit" name="submit" value="提交上傳" />
這個(gè)是提交按鈕猾浦,只要點(diǎn)了這個(gè)按鈕陆错,就會(huì)轉(zhuǎn)向腳本文件,并把文件上傳到服務(wù)器上金赦。
其實(shí)音瓷,表單屬性如果要細(xì)聊會(huì)很復(fù)雜。當(dāng)然夹抗,也正是由于他的重要性绳慎,多樣性,才有了多姿多彩的網(wǎng)頁設(shè)計(jì)規(guī)劃漠烧。這是一個(gè)非常有趣的話題杏愤,小白將在前端的文章中跟大家好好討論一下。
PHP腳本
PHP語言的一般結(jié)構(gòu)
<?php
echo "Hello沽甥,World声邦!";
?>
是不是很簡單,這個(gè)就是PHP版本的Hello摆舟,world亥曹。
其實(shí)邓了,PHP還可以跟HTML語言混合使用,基本上HTML能做的事情媳瞪,PHP都能做到骗炉,就是可能在繁瑣程度上會(huì)有不同。而且蛇受,類似上面的Hello句葵,World在PHP編寫好之后,是可以直接發(fā)布到HTML上顯示的兢仰,只需要額外套用個(gè)HTML框架即可乍丈,比如
<!DOCTYPE html>
<html>
<body>
<?php
echo "Hello,World把将!";
?>
</body>
</html>
就跟之前的網(wǎng)頁版Hello轻专,world的顯示效果幾乎一模一樣(這里為了大家能看清楚,沒有套用之前Bootstrap的框架)察蹲。
代碼部分请垛,我這邊是參考的w3school的 PHP教程,自己稍微做了一些修改
<?php
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg"))
&& ($_FILES["file"]["size"] < 2000000))
{
if ($_FILES["file"]["error"] > 0)
{
echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
}
else
{
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload/" . $_FILES["file"]["name"]);
echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "Invalid file";
}
?>
這個(gè)就是表單中提到的 upload.php
文件了洽议。
這邊一些基本的條件語句相信大家有點(diǎn)編程基礎(chǔ)的都能看懂吧宗收,這邊就不贅述了。
PHP變量命名規(guī)則是以 $
開始的亚兄,這里的變量其實(shí)就一個(gè) $_FILES
混稽。注意,PHP變量是對(duì)大小寫敏感的审胚。其余的變量屬性 file name type size
等都是從表單中獲得的荚坞,也就是說,這個(gè)腳本的實(shí)例化是依賴于表單的輸入文件的菲盾。這個(gè)PHP文件只是作為一種處理方法,而跟HTML標(biāo)記不一樣各淀,不具有實(shí)際存在的形態(tài)懒鉴,必須依賴于外部輸入才能執(zhí)行。
這里碎浇,前面三個(gè)或 和一個(gè)與 條件構(gòu)成了上傳文件的約束 临谱。在這里,規(guī)定只能上傳 gif奴璃、jpeg 悉默、和 pjpeg 格式的小于2000000bit大小的圖片。當(dāng)然苟穆,這個(gè)只是個(gè)約束范例抄课,如果大家要傳輸各類文件唱星,只需要加上其他約束就行了。如果要任何文件都傳輸跟磨,那么就直接刪掉約束條件就行了间聊。但是,不建議這么做抵拘,當(dāng)網(wǎng)站面向大眾的時(shí)候哎榴,這么做很容易成為黑客入侵的快速入口,對(duì)服務(wù)器來講是致命的僵蛛。
內(nèi)部尚蝌,關(guān)鍵性的上傳代碼是
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload/" . $_FILES["file"]["name"]);
echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
}
這條語句的意思是,先看目錄下有沒有同名稱文件充尉,如果有飘言,就提示已經(jīng)存在相同文件,并提示喉酌,且不會(huì)繼續(xù)上傳热凹;如果沒有相同文件,則使用 move_uploaded_file
方法將文件上傳到指定目錄中泪电,并且輸出存儲(chǔ)目錄般妙。
這里,最關(guān)鍵的上傳步驟就存在于上傳方法那個(gè)封裝好的函數(shù)之中相速,這塊是標(biāo)準(zhǔn)化的庫函數(shù)碟渺,大家直接調(diào)用就可以了,在安裝了PHP的服務(wù)器上突诬,這個(gè)函數(shù)是存在于默認(rèn)的庫中的苫拍,不需要額外添加。
分享一個(gè)自己的小故事
關(guān)鍵詞:權(quán)限旺隙、刷新——服務(wù)器文件默認(rèn)權(quán)限對(duì)文件上傳的影響绒极。
一般來講,服務(wù)器為了安全性考慮蔬捷,一般是默認(rèn)只讀權(quán)限垄提。小白使用的CentOS系統(tǒng),安裝的是Apache服務(wù)器周拐。
這里還有個(gè)小故事铡俐,小白初次接觸文件上傳的時(shí)候,在網(wǎng)上找了各路博客大神的帖子妥粟,基本把相關(guān)的熱帖都看遍了审丘,還有官方說明文檔。但是勾给,很不巧滩报,文件上傳總是不成功(雖然文件提示都已經(jīng)上傳了锅知,也就是說程序都跑通了,但是服務(wù)器上就是沒有文件)露泊。
咋辦呢喉镰?小白開始懷疑了,難道官方文檔也有錯(cuò)惭笑?
后來侣姆,在折騰了3個(gè)小時(shí)之后,在一個(gè)論壇回復(fù)里面看到有人稍微說了一下權(quán)限 問題沉噩,我也沒抱太大希望捺宗,因?yàn)闆]多少人討論過權(quán)限。
于是川蒙,小白就抱著試試看的心態(tài)蚜厉,修改了目標(biāo)文件夾的權(quán)限。沒想到畜眨,奇跡出現(xiàn)了—— 提示有變化了昼牛,之前都是簡單提示已經(jīng) 存儲(chǔ)完畢,這次是 文件已存在 康聂。
有點(diǎn)小欣喜贰健,但是,目標(biāo)文件夾還是沒有文件疤裰伶椿!
咋辦呢?這次至少知道文件已經(jīng)存儲(chǔ)在服務(wù)器上了氓侧,但是為什么還是看不到呢脊另?難道是延遲?
小白先登出服務(wù)器约巷,再進(jìn)入偎痛,還是看不到!到底是個(gè)咋回事独郎?當(dāng)時(shí)都已經(jīng)凌晨3點(diǎn)了看彼,小白真的要崩潰了,但是不搞出來也睡不著啊囚聚,算了,擼起袖子繼續(xù)找标锄,一定要搞出來顽铸,畢竟有眉目了!
小白在自己本地的電腦上是習(xí)慣于不斷刷新(雖然感覺并沒有什么用)料皇,由于服務(wù)器端小白是FTP登錄谓松,窗口比較小星压,沒注意過刷新。但是鬼譬,就在這個(gè)時(shí)候娜膘,小白不小心點(diǎn)了一下刷新!
奇跡出現(xiàn)了优质,上傳的所有文件都出現(xiàn)了竣贪!瞬間如釋重負(fù)、欣喜若狂肮Α演怎!
哎呀媽呀!原來是這個(gè)問題啊避乏,這下我終于懂得刷新的重要性了爷耀,瞬間對(duì)刷新有了全新的理解!
故事還沒結(jié)束拍皮。
第二天早上歹叮,雖然四點(diǎn)多才睡覺的,但是小白8點(diǎn)就醒了铆帽,想想昨晚的成果咆耿,瞬間又有了動(dòng)力,繼續(xù)干锄贼,再摸索摸索票灰,看看有沒有新的發(fā)現(xiàn)。
我把之前的文件夾刪除了宅荤,新建了一個(gè)文件夾屑迂,看看上傳效果。不搞不知道冯键,一搞嚇一跳惹盼,原封不動(dòng)的代碼,又不行了惫确!
不過手报,不要急,這個(gè)bug處理過改化,不就是權(quán)限 問題嘛掩蛤!我把權(quán)限修改好,又做了一次陈肛,這下好了揍鸟!這里小白要著重說明一個(gè)事情:
很多人都知道設(shè)定一個(gè)文件夾及其子文件夾的權(quán)限之后,原有文件夾的屬性肯定是不變的句旱。但是阳藻,如果在文件夾下面新建一個(gè)子文件夾晰奖,那這個(gè)子文件夾的權(quán)限會(huì)繼承 父文件夾的權(quán)限嗎?
答案是腥泥,不會(huì)匾南!新建的子文件夾權(quán)限還是默認(rèn)的權(quán)限,不會(huì)因?yàn)楦篙叺臋?quán)限而繼承蛔外,若要繼承蛆楞,得再設(shè)定一次權(quán)限,才能改變新建文件夾的權(quán)限屬性冒萄。
這個(gè)問題是最重要的了臊岸,小白為這個(gè)問題付出了4個(gè)多小時(shí)的努力,問題雖小尊流,卻很關(guān)鍵帅戒!
由此,小白感覺現(xiàn)在的各路博客大神 寫文章真是有點(diǎn)水了崖技。都喜歡各種轉(zhuǎn)載逻住、抄襲,而不去真正實(shí)踐迎献,實(shí)踐才能找到問題瞎访,也才能寫出真正對(duì)求知者有用的文章。否則吁恍,泥沙俱下扒秸,人云亦云,垃圾太多的結(jié)果就是浪費(fèi)了大家太多的時(shí)間冀瓦。
這也是小白最初想寫一點(diǎn)自己的心得的原因伴奥。小白每一次的寫作都是自己親自嘗試過的,有任何的細(xì)小的問題翼闽,小白都會(huì)在文章中跟大家詳細(xì)討論拾徙。無懼簡單,避免含糊感局、裝高大上尼啡。寫出最淺顯易懂的文章,闡釋最基本的技術(shù)原理询微,這是小白的追求崖瞭。
結(jié)語
好啦,又到了本期問題思考環(huán)節(jié)了撑毛!
本期的問題是這樣的
問題1:
仔細(xì)看的小伙伴一定已經(jīng)發(fā)現(xiàn)了书聚,這個(gè)上傳重復(fù)文件的判斷語句似乎是不合理的!
我們正常的文件上傳情況都是如果有重復(fù)文件,會(huì)跳出一個(gè)處理對(duì)話框寺惫,選擇是否覆蓋掉原始文件,然而這里卻沒有蹦疑。你能不能設(shè)計(jì)一個(gè)簡單的方案西雀,來彌補(bǔ)這個(gè)小缺陷,達(dá)到正常的處理效果呢歉摧?
問題2:
在服務(wù)器端艇肴,如果某個(gè)文件夾有寫 權(quán)限,會(huì)對(duì)服務(wù)器安全造成影響叁温,具體影響可能有哪些再悼?你有沒有什么好的解決辦法呢?
技術(shù)問題沒有高級(jí)與低級(jí)之分膝但,無論多么細(xì)小的問題冲九,你提出來都會(huì)給別人或多或少提供幫助與參考。
所以跟束,大家有任何疑問或者建議都可以留言或者私信小白哦~
歡迎各位查閱相關(guān)資料莺奸,在留言中積極參加討論。
參考文獻(xiàn)
PHP_百度百科
HTML_<form>標(biāo)簽的enctype 屬性
Andre Villeneuve