风之旅人 Android Dev Engineer

10.PHP表单传值和文件上传

2019-10-18
PHP

表单传值和文件上传

表单传值

GET传值

  1. form表单: <form method=”GET”>表单元素</form>
  2. a标签: <a href=”www.itcast.cn/index.php?学科=PHP”>
  3. location对象的href属性
    <script>location.href=www.itcast.cn/index.php?data=PHP</script>
    
  4. location对象的assign()方法
    <script>location.assign(www.itcast.cn/index.php?data=PHP)</script>
    

getpost能够传输的数据格式有区别: get传输简单数据(数值/字符串),post可以提交复杂数据(二进制等).

PHP接收数据的三种方式

不管是$_GET/$_POST/$_REQUEST三个都是PHP超全局没有范围限制预定义数组表单元素的name属性的值作为数组的下标而value属性对应的值就是数组的元素值

$_GET方式接收GET方式提交的数据
$_POST方式接收POST方式提交的数据
$_REQUEST方式接收POST或者GET提交的所有数据
1. $_REQUEST所存储数据的内容$_POST和$_GET合并存储到一个数组
2. $_REQUEST和$_POST与$_GET的联系如果GET和POST中有同名数组元素下标),POST会覆盖GETPHP中数组元素下标具有唯一性),这个可以在php.ini中进行配置

GET/POST/REQUEST关系

//接收数据
echo '<pre>';

var_dump($_GET);	//GET方式提交的数据

echo '<hr>';
var_dump($_POST);	//POST方式提交的数据

echo '<hr>';
var_dump($_REQUEST);	//两种方式提交的数据

浏览器 http://localhost/test.php?xxx=true
🍎
array(1) {
  ["xxx"]=>
  string(4) "true"
}
------------------------------------
array(0) {
}
------------------------------------
array(1) {
  ["xxx"]=>
  string(4) "true"
}

证明在REQUEST中POST会覆盖GET

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>
 </head>
 <body>
	<form method="POST" action="01receive_data.php?username=getusername">
		<input type="text" name="username" value=""/>
		<input type="password" value=""/>
		<input type="submit" name="sub" value="submit"/>
	</form>
 </body>
</html>

如图:

PHP处理复选框数据

复选框表单项的命名方式

复选框通常是将一类内容以同样同名的形式传递给后台数据库存储通常是一个字段存储复选框的特点选中才会提交

1	在浏览器端checkbox的name属性的值不论什么都会被浏览器毫无保留的提交
2	在PHP中$_POST/$_GET都会对同名name属性进行覆盖

解决方案:浏览器不识别[](浏览器不认为有特殊性),但是PHP认为 [] 有特殊性:系统自动认为该符号是数组的形式, 所以PHP就会自动的将同名的但是带有 [] 的元素组合到一起形成一个数组

hobby[]

<form method="POST" action="04checkbox.php">
 <input type="checkbox" name="hobby[]" value="basketball">basketball
 <input type="checkbox" name="hobby[]" value="football">football
 <input type="checkbox" name="hobby[]" value="pingpang">pingpang
 <input type="submit" name="btn" value="提交"/>
 </form>

复选框数据的接收形式

PHP会自动组合同名元素的为数组

其中,action 指向的 php 文件只做结果输出

//接收checkbox数据
header('Content-type:text/html;charset=utf-8');	//告诉浏览器当前服务器返回的内容是text/html,同时需要浏览器用utf-8字符集解析
echo '<pre>';
print_r($_POST);

复选框数据的常见处理(implode,explode)

  1. 单选按钮的数据处理

Radio button:可以出现多个选择项,但是只能选择其中一个

1、	表单中使用的name属性,使用同名即可:只能选中一个
2、	后台接收数据也不需要额外处理
3、	数据库存储的话只需要一个字段存储普通数据即可(数字或者字符串.
4、	PHP拿到数据之后,组织SQL直接存储到数据表即可
🌰
<input type="radio" name="gender" value="1" checked="checked"/><input type="radio" name="gender" value="2"/>
  1. 多选按钮的数据处理
1	表单中name属性使用数组格式名字[]一类复选框数据使用一个.
2	后台接收到数据之后是一个数组数组不能存储到数据库.
3	PHP需要将数组转换成指定格式的字符串使用分隔符分隔每一个元素并且形成字符串implode(分隔符 ,数组),如果是反过来操作那么取出数据之后使用 explode 把字符串变成数组
🌰
//将复选框内容存储到数据库
header('Content-type:text/html;charset=utf-8');
$hobby = isset($_POST['hobby']) ? $_POST['hobby'] : array();
echo '<br>';
var_dump($hobby);

//数组转换成有格式的字符串
$hobby_string = implode($hobby,'|');
echo '<br>';
echo $hobby_string;

//假设 $hobby_string 是从数据库取出来的字段
echo '<br>';
var_dump(explode('|',$hobby_string));
🍎
array(2) { [0]=> string(8) "football" [1]=> string(8) "pingpang" }
football|pingpang
array(2) { [0]=> string(8) "football" [1]=> string(8) "pingpang" }

🐖在HTML显示当中通过判断复选框元素是否在数组中存在来确定复选框checkbox是否有checked=checked属性in_array()

4	PHP组织SQL直接存储到数据库
  1. 其他常规同名表单项的数据处理
    除开radio button单选框和checkbox复选框,很少会出现同名的表单项。如果非要使用同名的来进行管理,那么可以采用checkbox方式进行操作
    1、	表单中同名增加[]
    2、	PHP接收时数组处理
    3、	PHP转换成有格式的字符串
    4、	数据库字符串存储
    
复选框细节

如果复选框没有选中,那么浏览器就不会提交。因此在PHP接收使用复选框(单选框)数据的时候,应该先判断是否存在该数据

$hobby = isset($_POST['hobby']) ? $_POST['hobby'] : array();

文件上传

文件上传原理

文件从用户本地电脑通过传输方式(Web表单)保存到服务器所在电脑 指定的目录 下。

  • 1、 增加文件上传的表单:浏览器请求一个服务器的HTML脚本(包含文件上传表单.
  • 2、 用户从本地选择一个文件(点击上传框(按钮).
  • 3、 用户点击上传:文件会通过物联网传输到 服务器
  • 4、 服务器操作系统会将文件保存到临时目录:是以临时文件格式保存(windows下tmp.
  • 5、 服务器脚本开始工作:判断文件有效
  • 6、 服务器脚本将有效文件从临时目录移动到指定的目录下(完成.

表单写法

  1. method 属性:表单提交方式必须为POST
  2. enctype (encode type)属性:form 表单属性,主要是规范表单数据的编码方式

  3. 上传表单:file表单
<body>
  <form method="POST" enctype="multipart/form-data" action="xxx.php">
	<input type="file" name="image" />
	<input type="submit" name="btn" value="上传文件"/>
  </form>
</body>

酱婶儿👇


在PHP中,有一个 预定义变量$_FILES 是专门用来存储用户上传的文件的。

header('Content-type:text/html;charset=utf-8');
echo '<pre>';

var_dump($_POST);
var_dump($_FILES);
🍎
array(1) {
  ["btn"]=>
  string(12) "上传文件"
}
array(1) {
  ["image"]=>    //表单name属性的值
  array(5) {
    ["name"]=>
    string(40) "clementine_16px_1173677_easyicon.net.ico"
    ["type"]=>
    string(12) "image/x-icon"
    ["tmp_name"]=>
    string(27) "C:\Windows\Temp\phpFF6C.tmp"
    ["error"]=>
    int(0)
    ["size"]=>
    int(1150)
  }
}

可以通过 $_FILES 查看文件的一些信息。

测试:如果没有enctype属性,那么上传文件会是什么样子?

array(2) {
  ["image"]=>
  string(40) "clementine_16px_1173677_easyicon.net.ico"
  ["btn"]=>
  string(12) "上传文件"
}
array(0) {
}

$_ FILES变量详解

  1. name:文件在用户(浏览器端)电脑上实际存在的名字(实际用来保留后缀.
  2. tmp_name:文件上传到服务器后操作系统保存的临时路径(实际用来给PHP后期使用.
  3. type:MIME(多功能互联网邮件扩展)类型,用来在计算机中客户端识别文件类型(确定软件.
  4. error:文件上传的代号,用来告知应用软件(PHP)文件接收过程中出现了什么问题(PHP后期根据代码进行文件判断.

  1. size:文件大小(PHP根据实际需求来确定是否该保留.
$_ FILES错误信息说明
 PHP 4.2.0 开始PHP 将随文件信息数组一起返回一个对应的错误代码
该代码可以在文件上传时生成的文件数组中的 error 字段中被找到也就是 $_FILES['userfile']['error']

UPLOAD_ERR_OK
其值为 0没有错误发生文件上传成功
UPLOAD_ERR_INI_SIZE
其值为 1上传的文件超过了 php.ini  upload_max_filesize 选项限制的值
UPLOAD_ERR_FORM_SIZE
其值为 2上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值
UPLOAD_ERR_PARTIAL
其值为 3文件只有部分被上传
UPLOAD_ERR_NO_FILE
其值为 4没有文件被上传
UPLOAD_ERR_NO_TMP_DIR
其值为 6找不到临时文件夹PHP 4.3.10  PHP 5.0.3 引进
UPLOAD_ERR_CANT_WRITE
其值为 7文件写入失败PHP 5.1.0 引进

Note:
以上值在 PHP 4.3.0 之后变成了 PHP 常量

移动临时文件到目标位置

文件上传之后会保存到 $FILES 中,那么访问文件信息的形式就是 $ FILES[‘表单name属性值’][‘元素信息’]

  1. 判断是否为上传的文件: is_uploaded_file()
  2. 移动文件: move_uploaded_file()
//1、取得文件信息 👉 五个元素
$file = $_FILES['image'];

//2、判断是否是上传文件:临时文件
if(is_uploaded_file($file['tmp_name'])){
  //是上传文件 👉 文件被复制到目录 C:\fastwork\Apache24\htdocs\uploads
  //$file['tmp_name'] 取出的是"合法的上传文件"
  if(move_uploaded_file($file['tmp_name'],'uploads/' . $file['name'])){
    echo '文件保存成功!';
  }else{
    echo '文件保存失败!';
  }
}else{
  //不是上传文件
  echo '文件上传失败!';
}

多文件上传

🌈准备 test.php

header('Content-type:text/html;charset=utf-8');
echo '<pre>';

var_dump($_POST);
var_dump($_FILES);

当商品需要上传多个图片进行展示的时候:那么需要使用多文件上传

针对一个内容但是不同文件说明: 同名表单

<form method="POST" enctype="multipart/form-data" action="test.php">
  <input type="file" name="image[]" />
  <input type="file" name="image[]" />
  <input type="file" name="image[]" />
  <input type="submit" name="btn" value="批量上传"/>
</form>
🍎
array(1) {
  ["btn"]=>
  string(12) "批量上传"
}
array(1) {
  ["image"]=>
  array(5) {
    ["name"]=>
    array(3) {
      [0]=>
      string(7) "app.ico"
      [1]=>
      string(8) "atom.exe"
      [2]=>
      string(10) "Update.exe"
    }
    ["type"]=>
    array(3) {
      [0]=>
      string(12) "image/x-icon"
      [1]=>
      string(24) "application/x-msdownload"
      [2]=>
      string(24) "application/x-msdownload"
    }
    ["tmp_name"]=>
    array(3) {
      [0]=>
      string(27) "C:\Windows\Temp\phpBA60.tmp"
      [1]=>
      string(27) "C:\Windows\Temp\phpBA61.tmp"
      [2]=>
      string(27) "C:\Windows\Temp\phpBA71.tmp"
    }
    ["error"]=>
    array(3) {
      [0]=>
      int(0)
      [1]=>
      int(0)
      [2]=>
      int(0)
    }
    ["size"]=>
    array(3) {
      [0]=>
      int(186361)
      [1]=>
      int(431616)
      [2]=>
      int(1838112)
    }
  }
}

👀 $_ FILES 数组按照 name,type,tmp_name,error,size 五元素进行分类。

当商品需要进行多个维度图片说明的时候:需要使用多文件上传

针对是不同内容所以表单名字不一样: 批量解决问题

<form method="POST" enctype="multipart/form-data" action="test.php">
	<input type="file" name="banner" />
	<input type="file" name="ad" />
	<input type="file" name="header" />
	<input type="submit" name="btn" value="批量上传"/>
</form>
🍎
array(1) {
  ["btn"]=>
  string(12) "批量上传"
}
array(3) {
  ["banner"]=>
  array(5) {
    ["name"]=>
    string(7) "app.ico"
    ["type"]=>
    string(12) "image/x-icon"
    ["tmp_name"]=>
    string(27) "C:\Windows\Temp\php1615.tmp"
    ["error"]=>
    int(0)
    ["size"]=>
    int(186361)
  }
  ["ad"]=>
  array(5) {
    ["name"]=>
    string(8) "atom.exe"
    ["type"]=>
    string(24) "application/x-msdownload"
    ["tmp_name"]=>
    string(27) "C:\Windows\Temp\php1616.tmp"
    ["error"]=>
    int(0)
    ["size"]=>
    int(431616)
  }
  ["header"]=>
  array(5) {
    ["name"]=>
    string(10) "Update.exe"
    ["type"]=>
    string(24) "application/x-msdownload"
    ["tmp_name"]=>
    string(27) "C:\Windows\Temp\php1626.tmp"
    ["error"]=>
    int(0)
    ["size"]=>
    int(1838112)
  }
}

👀 $_ FILES 数组按照 banner,ad,header 业务内容进行分类。

分析以上两种情况 👉 多文件上传的$_ FILES变量的数据结构形式

  • 同名指的是 html 中 input 标签的 name
<input type="file" name="ad" />

批量上传:同名表单:将表单名字形成一个数组,而且同时将文件对应的五个要素:name、tmp_name、size、type、error都形成对应数量的数组,每个文件上传对应数组元素的下标都是一样的:name[0] 和type[0]是属于同一个文件

批量上传:不同名表单:每个文件都会形成一个属于自己独立的5个元素的数组

对多文件信息的遍历读取和处理

  1. 不同名多文件上传处理方式:按照表单名字从$_FILES中取出来就可以直接使用(明确知道表单中有多少个文件上传); 如果不确定表单中有多少个文件上传,不适合挨个去取(效率不高),可以通过遍历 $_ FILES 数组,挨个取出来实现文件上传
<input type="file" name="banner" />
<input type="file" name="ad" />
<input type="file" name="header" />

//不同名文件遍历处理方式
foreach($_FILES as $file){
  //$file就是一个完整的上传文件信息:找到临时路径,指定存放路径
  if(is_uploaded_file($file['tmp_name'])){
    //存储
    move_uploaded_file($file['tmp_name'],'uploads/' . $file['name']);
  }
}
  1. 同名多文件上传:想办法得到一个文件对应的五个元素数组。从 $_ FILES 中把对应的 name\tmp_name\size\error\type 挨个取出来, 然后存放到不同的数组中。
<form method="POST" enctype="multipart/form-data" action="test.php">
 <input type="file" name="image[]" />
 <input type="file" name="image[]" />
 <input type="file" name="image[]" />
 <input type="submit" name="btn" value="批量上传"/>
</form>

//同名文件遍历处理方式
//此时遍历$_FILES没有意义,只有一个数组元素;应该变量$_FILES['userfile']['任意一个要素:name|tmp_name|size|error|type']
//判断元素存在而且是数组:name有代表是文件,name元素有多个(数组)代表是同名批量上传
if(isset($_FILES['image']['name']) && is_array($_FILES['image']['name'])){
  //遍历构造数组元素
  $images = array();		//存储所有的文件信息,一个元素代表一个文件(数组.

  foreach($_FILES['image']['name'] as $k => $name){
    $images[] = array(
      'name' => $name,
      'tmp_name' => $_FILES['image']['type'][$k],
      'type' => $_FILES['image']['tmp_name'][$k],
      'error' => $_FILES['image']['error'][$k],
      'size' => $_FILES['image']['size'][$k]
    );
  }
}

print_r($images);

文件上传后续问题

实现上传功能代码的重复利用封装文件上传函数
功能上传文件
条件条件判断
	🌈需要上传的文件信息对应的5个元素的数组
	1	文件类型是否合适外部指定MIME类型
	2 文件存储到什么位置外部指定
	3	文件格式限制文件后缀)?外部限定
    4 文件大小限制外部指定

结果实现文件上传
	1	成功结果能够在以后看到需要将文件的路径和文件名字返回存储到数据库.
	2 失败返回false指定错误原因引用参数.

锚点

步骤
1. 封装出一个上传函数
2. 判断文件是否有效
3. 判断保存路径是否有效
4. 判断文件本身上传的过程中是否有错误error
5. 文件类型的处理通过MIME匹配即可
6. 文件格式的处理后缀名的问题
7. 文件大小的处理
8. 移动到指定目录
8. 命名冲突的处理上传同名文件中文名字文件怎么办

//PHP文件上传功能封装函数
header('Content-type:text/html;charset=utf-8');

/*
 * 实现文件上传(单.
 * @param1 array $file,需要上传的文件信息:一维5元素数组(name\tmp_name\error\size\type)
 * @param2 array $allow_type,允许上传的MIME类型
 * @param3 string $path,存储的路径
 * @param4 string &$error,如果出现错误的原因
 * @param5 array $allow_format = array(),允许上传的文件格式
 * @param6 int $max_size = 2000000,允许上传的最大值
*/
function upload_single($file,$allow_type,$path,&$error,$allow_format = array(),$max_size = 2000000){
  //判断文件是否有效
  if(!is_array($file) || !isset($file['error'])){
    //文件无效
    $error = '不是一个有效的上传文件!';
    return false;
  }

  //判断文件存储路径是否有效
  if(!is_dir($path)){
    //路径不存在
    $error = '文件存储路径不存在!';
    return false;
  }

  //判断文件上传过程是否出错
  switch($file['error']){
    case 1:
    case 2:
      $error = '文件超出服务器允许大小!';
      return false;
    case 3:
      $error = '文件上传过程中出现问题,只上传一部分!';
      return false;
    case 4:
      $error = '用户没有选中要上传的文件!';
      return false;
    case 6:
    case 7:
      $error = '文件保存失败!';
      return false;
  }

  //判断MIME类型
  if(!in_array($file['type'],$allow_type)){
    //该文件类型不允许上传
    $error = '当前文件类型不允许上传!';
    return false;
  }

  //判断后缀是否允许
  //取出后缀
  $ext = ltrim(strrchr($file['name'],'.'),'.');
  if(!empty($allow_format) && !in_array($ext,$allow_format)){
    //不允许上传
    $error = '当前文件的格式不允许上传!';
    return false;
  }

  //判断当前文件大小是否满足当前需求
  if($file['size'] > $max_size){
    //文件过大
    $error = '当前上传的文件超出大小,最大允许' . $max_size . '字节!';
    return false;
  }


  //构造文件名字:类型_年月日+随机字符串.$ext
  $fullname = strstr($file['type'],'/',TRUE) . date('YYYYmmdd');
  //产生随机字符串
  for($i = 0;$i < 4;$i++){
    $fullname .= chr(mt_rand(65,90));
  }
  //拼凑后缀
  $fullname .= '.' . $ext;

  //移动到指定目录
  if(!is_uploaded_file($file['tmp_name'])){
    //文件不是上传的
    $error = '错误:不是上传文件!';
    return false;
  }

  if(move_uploaded_file($file['tmp_name'],$path . '/' . $fullname)){
    //成功
    return $fullname;
  }else{
    //移动失败
    $error = '文件上传失败!';
    return false;
  }

}


//提供数据
$file = $_FILES['image'];
$path = 'uploads';
$allow_type = array('image/jpg','image/jpeg','image/gif','image/pjpeg');
$allow_format = array('jpg','gif','jpeg');
$max_size = 8000000;

if($filename = upload_single($file,$allow_type,$path,$error,$allow_format,$max_size)){
  echo $filename;
}else{
  echo $error;
}

相关文章

评论