本文目錄
一、表單的參數傳遞
1.1 複選框參數傳遞
複選框參數傳遞存在問題,例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
echo $_POST['languages'];
}
?>
<form action="" method="post">
語言:<input type="checkbox" name="languages" value="PHP">PHP
<input type="checkbox" name="languages" value="javascript">javascript
<input type="checkbox" name="languages" value="node">node
<input type="checkbox" name="languages" value="vue">vue
<button type="submit" name="button">確定</button>
</form>
</body>
</html>
效果:
可以很直觀的發現,複選框當我們選擇兩個以上時只會選擇最後一個,那麼我們需要在複選框的name屬性後加個[ ]
表示這個是一系列的數組,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
print_r($_POST['languages']);
}
?>
<form action="" method="post">
語言:<input type="checkbox" name="languages[]" value="PHP">PHP
<input type="checkbox" name="languages[]" value="javascript">javascript
<input type="checkbox" name="languages[]" value="node">node
<input type="checkbox" name="languages[]" value="vue">vue
<button type="submit" name="button">確定</button>
</form>
</body>
</html>
效果:
這樣就可以解決複選框的問題了。
1.2 其他表單參數傳遞
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (isset($_POST['button'])) {
echo '姓名:'.$_POST['username'].'<br/>';
echo '密碼:'.$_POST['password'].'<br/>';
echo '性別:'.$_POST['sex'].'<br/>';
echo '居住地:'.$_POST['area'].'<br/>';
echo '留言:'.$_POST['mark'].'<br/>';
}
echo '<hr/>';
?>
<form action="" method="post">
姓名:<input type="text" name="username"><br/>
密碼:<input type="password" name="password"><br/>
性別:<input type="radio" name="sex" value="1" checked>男
<input type="radio" name="sex" value="0">女<br/>
愛好:
居住地:
<select name="area">
<option value="amoy">廈門</option>
<option value="fuzhou">福州</option>
</select><br/>
備註:<textarea name="mark" cols="30" rows="5"></textarea>
<button type="submit" name="button">確定</button>
</form>
</body>
</html>
效果:
二、文件參數的傳遞(二進制)
2.1 文件域
開發中需要上傳圖片、音樂、視頻等等,這種上傳傳遞是二進制數據。
文件域:<input type="file" name="image">
2.2 表單enctyoe屬性
enctype 屬性規定在發送到服務器之前應該如何對錶單數據進行編碼。默認地,表單數據會編碼爲 “application/x-www-form-urlencoded”。就是說,在發送到服務器之前,所有字符都會進行編碼。
表單的enctype屬性,默認情況下,表單傳遞的是字符流,不能傳遞二進制,通過enctype屬性設置可以傳遞複合數據。
enctype有三種格式:
application/x-www-form-urlencoded
只能傳字符串,帶格式的,xml
multipart/form-data
能傳字符串或者二進制數據,文件上傳必須設置這個。text/plain
傳字符串,不帶格式。
2.3 接收文件$_FILES
超全局變量$_FILES
是一個二維數組,用來保存客戶端上傳到服務器的文件信息。二維數組的行是文件域的名稱,列有5個。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
echo '<pre/>';
print_r($_FILES);
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="image">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
- name:上傳的文件名
- type:上傳的類型,這個類型是MIME類型
- size:文件的大小,以字節爲單位
- tmp_name:文件上傳時的臨時文件
- error:錯誤的編碼(值有0、1、2、3、4、6、7)0表示正確
error值描述:
error值 | 錯誤描述 |
---|---|
0 | 正確 |
1 | 文件大小超過了php.ini允許的最大值 |
2 | 文件大小超過了表單允許的最大值 |
3 | 只有部分文件上傳 |
4 | 沒有文件上傳 |
6 | 找不到臨時文件 |
7 | 文件寫入失效 |
可以在php.ini中設置允許的最大值:
php.ini中設置允許最大爲2M。
設置表單允許的最大值:
只要掌握錯誤號,0和4即可。
2.4 將上傳文件移到指定位置。move_uploaded_file(臨時地址, 目標地址)
函數:move_uploaded_file(臨時地址, 目標地址)
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
// 如果有文件上傳並且正確,進行上傳文件移到指定位置
if ($_FILES['image']['error'] == 0) {
move_uploaded_file($_FILES['image']['tmp_name'], './'.$_FILES['image']['name']);
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="image">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
可以看到已經從桌面上傳到www
文件夾下了。
php.ini中與上傳文件相關的一些配置:
- post_max_size = 8M(表單允許的最大值)
- upload_max_filesize = 2M(允許上傳文件的大小)
- upload_tmp_dir =“F:/Program/tmp”(指定臨時文件地址)
- file_uploads = On(是否允許文件上傳)
- max_file_uploads = 20(允許同時上傳20個文件)
2.5 優化文件上傳,同名處理。
在文件上傳時,如果是相同名字的將覆蓋,那這個肯定不是我們想要的,接下來來優化下這個問題。
在這之前,先介紹兩個處理字符串的函數strchr( )
和strrchr( )
。例:
<?php
$path='counter.name.jpg';
echo strchr($path, '.');
?>
效果:
strchr( 匹配的字符串,以什麼爲選擇起始標誌) :這個方法從左邊開始匹配。
<?php
$path='counter.name.jpg';
echo strrchr($path, '.');
?>
效果:
strrchr( 匹配的字符串,以什麼爲選擇起始標誌) :這個方法從右邊開始匹配。
- 通過時間戳拼接3位隨機數做文件名
<?php
$path='counter.name.jpg';
echo time().rand(100,999).strrchr($path, '.');
?>
效果:
2. 通過php自帶的uniqid( )做文件名
uniqid(前綴,true)。
例:
<?php
$path='counter.name.jpg';
echo uniqid('goods_').strrchr($path, '.'), '<br/>';
echo uniqid('goods_', true).strrchr($path, '.');
?>
效果:
2.6 驗證文件格式
- 判斷文件後綴名。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
$arr=array('.jpg','.png','.gif'); // 允許的擴展名
$ext=strrchr($_FILES['languages']['name'],'.'); // 上傳文件擴展名
if (in_array($ext, $arr)) {
echo '允許上傳';
}
else {
echo '不允許上傳';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
但是如果我在桌面新建一個記事本,aa.txt
,然後我將後綴改爲.jpg
,那麼它也是允許上傳的,但是他的本質還是文本,所以這裏的安全係數不高。不能防止文件僞裝。
- 判斷mime類型
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
$arr=array('image/jpeg','image/png','image/gif'); // 允許的擴展名
$mime=$_FILES['languages']['type']; // mime類型
if (in_array($mime, $arr)) {
echo '允許上傳';
}
else {
echo '不允許上傳';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
可以看到判斷mime類型也不能防止文件僞裝。
- php_fileinfo擴展
在php.ini配置中找到如圖:
開啓擴展後,就可以調用裏面定義的函數。例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
// 1.創建finfo資源
$info=finfo_open(FILEINFO_MIME_TYPE);
var_dump($info);
// 2.將finfo資源和文件做比較
echo finfo_file($info,$_FILES['languages']['tmp_name']);
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
那麼這個就可以防止文件僞裝了,它可以強大到你的記事本是空的都知道,如果寫了內容或者腳本也能分析出來,這邊就不試了,就是在aa.jpg
中寫入js
腳本,它也能檢測出來。感興趣的小夥伴可以自己試試。
三、優化文件上傳例題
- 驗證是否有誤
- 驗證格式
- 驗證大小
- 驗證是否是http上傳
- 上傳實現
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
function checkErr($file) {
$error = $file['error'];
// 1.驗證錯誤
if ($error != 0) {
switch ($error) {
case 1:
return '文件大小超過了php.ini允許的最大值'.ini_get('upload_max_filesize');
case 2:
return '文件大小超過了表單允許的最大值';
case 3:
return '只有部分文件上傳';
case 4:
return '沒有文件上傳';
case 6:
return '找不到臨時文件';
case 7:
return '文件寫入失效';
default:
return '未知錯誤';
}
}
// 2.驗證格式
$info=finfo_open(FILEINFO_MIME_TYPE);
$mime=finfo_file($info,$file['tmp_name']);
$arr=array('image/jpeg','image/png','image/gif');
if (!in_array($mime,$arr)) {
return '只能上傳'.implode(',',$arr);
}
// 3.驗證大小
$size=1024000;
if ($file['size']>$size) {
return '文件大小不能超過'.number_format($size/1024,1).'kb';
}
// 4.驗證是否是http上傳
if (!is_uploaded_file($file['tmp_name'])) {
return '文件不是HTTP POST 上傳的<br/>';
}
return null;
}
if (!empty($_POST)) {
if ($err = checkErr($_FILES['languages'])) {
echo $err;
}
else {
// 5.文件上傳
//$folder=date('Y-m-d H:i:s') // 將當前的時間轉成 年-月-日 小時:分鐘:秒數
echo $folder=date('Y-m-d'); // 文件夾名稱
$path="./uploads/${folder}"; // 文件夾路徑
if (!is_dir($path)) {
mkdir($path);
}
else {
$filename=uniqid('',true).strrchr($_FILES['languages']['name'], '.'); // 文件名
$filepath="$path/$filename"; // 文件路徑
if (move_uploaded_file($_FILES['languages']['tmp_name'], $filepath)) {
echo "上傳成功,路徑是:${filepath}";
}
else {
echo '失敗<br/>';
}
}
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="languages">
<button type="submit" name="button">上傳</button>
</form>
</body>
</html>
效果:
可以看到按照預期的上傳成功了。
在學習的php的路上,如果你覺得本文對你有所幫助的話,那就請關注點贊評論三連吧,謝謝,你的肯定是我寫博的另一個支持。