PHP强化之13 - 文件上传与下载

版权声明:著作权归作者所有,转载请注明出处 https://blog.csdn.net/weixin_42565457/article/details/85001069

一、文件上传

将客户端文件上传到服务器端,再将服务器端的文件(临时文件)移动到指定目录即可。

1、form表单

文件的上传一般都是经过form表单来实现的。

1)标签enctype属性
表单中enctype="multipart/form-data"是用于设置表单的MIME编码。

默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;只有使用了multipart/form-data且提交方式为POST都能完整的传递文件数据。

2)MAX_FILE_SIZE 隐藏字段
MAX_FILE_SIZE 隐藏字段(单位为字节)必须放在文件输入字段之前,其值为接收文件的最大尺寸。这是对浏览器的一个建议,PHP 也会检查此项。
如:<input type="hidden" name="MAX_FILE_SIZE" value="101321" />

在浏览器端可以简单绕过此设置,不可信,因此不要指望用此特性来阻挡大文件。(不过鉴于友好性最好还是在表单中加上此项目,因为它可以避免用户在花时间等待上传大文件之后才发现文件过大上传失败的麻烦。)

3)通过accept属性限制上传文件类型
<input type='file' name='myfile' accept='文件的MIME类型' />
如:accept="image/gif, image/jpeg",如果不限制图像的格式,可以写为:accept="image/*"

accept 属性只能与<input type="file">配合使用。它规定能够通过文件上传进行提交的文件类型。(提示:请避免使用该属性,应该在服务器端验证文件上传。)

4)例子

<form action="upload.php" method="post" enctype="multipart/form-data">
  <input type="hidden" name="MAX_FILE_SIZE" value="101321" />
  请选择您要上传的文件:
  <input type="file" name="myfile" accept="image/*" /><br/>
  <input type="submit" value="上传"/>

5)一次选择多个文件

扫描二维码关注公众号,回复: 4504096 查看本文章
<input type="file" name="filename" multiple="multiple" />

2、全局变量 $_FILES

通过form表单上传文件后,在服务器端则需要使用全局数组$_FILES来获取文件信息。

1)$_FILES字段说明

  • $_FILES[‘myfile’][‘name’]  为上传文件的原文件名
  • $_FILES[‘myfile’][‘type’]  为上传文件的 MIME 类型
  • $_FILES[‘myfile’][‘size’]  已上传文件的大小,单位为字节
  • $_FILES[‘myfile’][‘tmp_name’]  文件被上传后在服务端储存的临时文件名
  • $_FILES[‘myfile’][‘error’]  文件上传的错误代码

2)error字段说明

  • 0(UPLOAD_ERR_OK):没有错误发生,文件上传成功。
  • 1(UPLOAD_ERR_INI_SIZE):上传的文件超过了 php.ini 中upload_max_filesize 选项限制的值。
  • 2(UPLOAD_ERR_FORM_SIZE):上传文件的大小超过了 HTML 表单中MAX_FILE_SIZE 选项指定的值。
  • 3(UPLOAD_ERR_PARTIAL):文件只有部分被上传。
  • 4(UPLOAD_ERR_NO_FILE):没有文件被上传。
  • 5:上传文件大小为0。

3、服务器配置

在php.ini中可以对文件上传进行如下的配置:

file_uploads = On    ; Whether to allow HTTP file uploads.
;upload_tmp_dir =    ; Temporary directory for HTTP uploaded files (will use system default if not
upload_max_filesize = 2M   ; Maximum allowed size for uploaded files.
max_file_uploads = 20   ; Maximum number of files that can be uploaded via a single request
post_max_size = 8M   ; Maximum size of POST data that PHP will accept.

max_execution_time = 30   ; Maximum execution time of each script, in seconds
max_input_time = 60   ; Maximum amount of time each script may spend parsing request data. 
memory_limit = 128M   ; Maximum amount of memory a script may consume (128MB)

4、相关函数

1)is_uploaded_file
bool is_uploaded_file ( string $filename )
如果 filename 所给出的文件是通过 HTTP POST 上传的则返回 TRUE。这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件。
为了能使 is_uploaded_file() 函数正常工作,必段指定类似于 $_FILES[‘userfile’][‘tmp_name’] 的变量,而在从客户端上传的文件名 $_FILES[‘userfile’][‘name’] 不能正常运作。
is_uploaded_file ($_FILES['userfile']['tmp_name'] )

2)move_uploaded_file
bool move_uploaded_file ( string $filename , string $destination )
本函数检查并确保由 filename 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 destination 指定的文件。
Warning:如果目标文件已经存在,将会被覆盖!!

3)file_exists  检查文件或目录是否存在
4)is_writable   判断给定的文件名是否可写
5)iconv  字符编码互转
6)getimagesize  检查是否为图片文件(其他类型的文件就算后缀名改了也能被检测到)

5、服务器代码示例

header('content-type:text/html;charset=utf-8');
$fileinfo=$_FILES["myfile"];
$ext = pathinfo($fileinfo["name"],PATHINFO_EXTENSION);  //提取上传文件的拓展名

//服务器端设定限制
$max_size = 10485760;  //10M,10*1024*1024
$allow_ext = array('jpeg','jpg','png','gif');  //允许上传的文件类型(拓展名)
$path = "uploads";  //上传目录
if (!file_exists($path)) {   //当目录不存在,就创建目录
    mkdir($path,0777,true);
}

//得到唯一的文件名!防止因为文件名相同而产生覆盖
$uni_name=md5(uniqid(microtime(true),true)).$ext;  //md5加密,uniqid产生唯一id,microtime做前缀
$destination = "uploads/".$uni_name;


if ($fileinfo["error"] == 0) {
    if ($fileinfo["size"] > $maxsize) {
        exit("上传文件过大!");
    }
    if (!in_array($ext, $allow_ext )) {
        exit("非法文件类型");
    }
    if (!is_uploaded_file($fileinfo["tmp_name"])) {
        exit("上传方式有误,请使用post方式");
    }
    if (@move_uploaded_file($fileinfo["tmp_name"], $destination)) {
        echo "文件".$fileinfo["name"]."上传成功!";
    }else{
        echo "文件".$fileinfo["name"]."上传失败!";
    }
    //判断是否为真实图片(防止伪装成图片的病毒一类的
    if (!getimagesize($fileinfo["tmp_name"])) {  //getimagesize真实返回数组,否则返回false
        exit("不是真正的图片类型");
    }

}else{
    exit("文件上传失败$fileinfo['error']");
}

二、文件下载

通常文件下载过程是十分简单的,建立一个链接指向到目标文件就可以了。

1、触发下载

方法一:点击

<a href="download.php?filename=test.jpg">下载test.jpg</a>

方法二:重定向

Header("Location: http://www.xxx.com/xxx.rar");    

2、后端代码

$file_name = $_GET['filename'];     //下载文件名    
$file_dir = "uploads/";        //下载文件存放目录   
if (! file_exists ( $file_dir . $file_name )) {    
  exit ("文件找不到");  
}else{
  //打开文件    
  $file = fopen ( $file_dir . $file_name, "r" );

  Header ( "Content-type: application/octet-stream" );   //代表文件MIME类型是文件流格式。
  Header ( "Accept-Ranges: bytes" );    
  Header ( "Accept-Length: " . filesize ( $file_dir . $file_name ) );   
  //attachment是用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name
  Header ( "Content-Disposition: attachment; filename=" . $file_name );  
  
  //读取文件内容并直接输出到浏览器    
  echo fread ( $file, filesize ( $file_dir . $file_name ) );    
  fclose ( $file );    
  exit();   
}

注意:在文件下载的页面要为纯php代码,除了需要下载的文件,不可以再有其它内容输出。否则会数据大小不一致,导致下载失败。

或者可以直接使用readfile函数:

header('content-disposition:attachment;filename='.basename($filename));
header('content-length:'.filesize($filename));
readfile($filename);

一、文件上传

将客户端文件上传到服务器端,再将服务器端的文件(临时文件)移动到指定目录即可。

1、form表单

文件的上传一般都是经过form表单来实现的。

1)标签enctype属性
表单中enctype="multipart/form-data"是用于设置表单的MIME编码。

默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;只有使用了multipart/form-data且提交方式为POST都能完整的传递文件数据。

2)MAX_FILE_SIZE 隐藏字段
MAX_FILE_SIZE 隐藏字段(单位为字节)必须放在文件输入字段之前,其值为接收文件的最大尺寸。这是对浏览器的一个建议,PHP 也会检查此项。
如:<input type="hidden" name="MAX_FILE_SIZE" value="101321" />

在浏览器端可以简单绕过此设置,不可信,因此不要指望用此特性来阻挡大文件。(不过鉴于友好性最好还是在表单中加上此项目,因为它可以避免用户在花时间等待上传大文件之后才发现文件过大上传失败的麻烦。)

3)通过accept属性限制上传文件类型
<input type='file' name='myfile' accept='文件的MIME类型' />
如:accept="image/gif, image/jpeg",如果不限制图像的格式,可以写为:accept="image/*"

accept 属性只能与<input type="file">配合使用。它规定能够通过文件上传进行提交的文件类型。(提示:请避免使用该属性,应该在服务器端验证文件上传。)

4)例子

<form action="upload.php" method="post" enctype="multipart/form-data">
  <input type="hidden" name="MAX_FILE_SIZE" value="101321" />
  请选择您要上传的文件:
  <input type="file" name="myfile" accept="image/*" /><br/>
  <input type="submit" value="上传"/>

5)一次选择多个文件

<input type="file" name="filename" multiple="multiple" />

2、全局变量 $_FILES

通过form表单上传文件后,在服务器端则需要使用全局数组$_FILES来获取文件信息。

1)$_FILES字段说明

  • $_FILES[‘myfile’][‘name’]  为上传文件的原文件名
  • $_FILES[‘myfile’][‘type’]  为上传文件的 MIME 类型
  • $_FILES[‘myfile’][‘size’]  已上传文件的大小,单位为字节
  • $_FILES[‘myfile’][‘tmp_name’]  文件被上传后在服务端储存的临时文件名
  • $_FILES[‘myfile’][‘error’]  文件上传的错误代码

2)error字段说明

  • 0(UPLOAD_ERR_OK):没有错误发生,文件上传成功。
  • 1(UPLOAD_ERR_INI_SIZE):上传的文件超过了 php.ini 中upload_max_filesize 选项限制的值。
  • 2(UPLOAD_ERR_FORM_SIZE):上传文件的大小超过了 HTML 表单中MAX_FILE_SIZE 选项指定的值。
  • 3(UPLOAD_ERR_PARTIAL):文件只有部分被上传。
  • 4(UPLOAD_ERR_NO_FILE):没有文件被上传。
  • 5:上传文件大小为0。

3、服务器配置

在php.ini中可以对文件上传进行如下的配置:

file_uploads = On    ; Whether to allow HTTP file uploads.
;upload_tmp_dir =    ; Temporary directory for HTTP uploaded files (will use system default if not
upload_max_filesize = 2M   ; Maximum allowed size for uploaded files.
max_file_uploads = 20   ; Maximum number of files that can be uploaded via a single request
post_max_size = 8M   ; Maximum size of POST data that PHP will accept.

max_execution_time = 30   ; Maximum execution time of each script, in seconds
max_input_time = 60   ; Maximum amount of time each script may spend parsing request data. 
memory_limit = 128M   ; Maximum amount of memory a script may consume (128MB)

4、相关函数

1)is_uploaded_file
bool is_uploaded_file ( string $filename )
如果 filename 所给出的文件是通过 HTTP POST 上传的则返回 TRUE。这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件。
为了能使 is_uploaded_file() 函数正常工作,必段指定类似于 $_FILES[‘userfile’][‘tmp_name’] 的变量,而在从客户端上传的文件名 $_FILES[‘userfile’][‘name’] 不能正常运作。
is_uploaded_file ($_FILES['userfile']['tmp_name'] )

2)move_uploaded_file
bool move_uploaded_file ( string $filename , string $destination )
本函数检查并确保由 filename 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 destination 指定的文件。
Warning:如果目标文件已经存在,将会被覆盖!!

3)file_exists  检查文件或目录是否存在
4)is_writable   判断给定的文件名是否可写
5)iconv  字符编码互转
6)getimagesize  检查是否为图片文件(其他类型的文件就算后缀名改了也能被检测到)

5、服务器代码示例

header('content-type:text/html;charset=utf-8');
$fileinfo=$_FILES["myfile"];
$ext = pathinfo($fileinfo["name"],PATHINFO_EXTENSION);  //提取上传文件的拓展名

//服务器端设定限制
$max_size = 10485760;  //10M,10*1024*1024
$allow_ext = array('jpeg','jpg','png','gif');  //允许上传的文件类型(拓展名)
$path = "uploads";  //上传目录
if (!file_exists($path)) {   //当目录不存在,就创建目录
    mkdir($path,0777,true);
}

//得到唯一的文件名!防止因为文件名相同而产生覆盖
$uni_name=md5(uniqid(microtime(true),true)).$ext;  //md5加密,uniqid产生唯一id,microtime做前缀
$destination = "uploads/".$uni_name;


if ($fileinfo["error"] == 0) {
    if ($fileinfo["size"] > $maxsize) {
        exit("上传文件过大!");
    }
    if (!in_array($ext, $allow_ext )) {
        exit("非法文件类型");
    }
    if (!is_uploaded_file($fileinfo["tmp_name"])) {
        exit("上传方式有误,请使用post方式");
    }
    if (@move_uploaded_file($fileinfo["tmp_name"], $destination)) {
        echo "文件".$fileinfo["name"]."上传成功!";
    }else{
        echo "文件".$fileinfo["name"]."上传失败!";
    }
    //判断是否为真实图片(防止伪装成图片的病毒一类的
    if (!getimagesize($fileinfo["tmp_name"])) {  //getimagesize真实返回数组,否则返回false
        exit("不是真正的图片类型");
    }

}else{
    exit("文件上传失败$fileinfo['error']");
}

二、文件下载

通常文件下载过程是十分简单的,建立一个链接指向到目标文件就可以了。

1、触发下载

方法一:点击

<a href="download.php?filename=test.jpg">下载test.jpg</a>

方法二:重定向

Header("Location: http://www.xxx.com/xxx.rar");    

2、后端代码

$file_name = $_GET['filename'];     //下载文件名    
$file_dir = "uploads/";        //下载文件存放目录   
if (! file_exists ( $file_dir . $file_name )) {    
  exit ("文件找不到");  
}else{
  //打开文件    
  $file = fopen ( $file_dir . $file_name, "r" );

  Header ( "Content-type: application/octet-stream" );   //代表文件MIME类型是文件流格式。
  Header ( "Accept-Ranges: bytes" );    
  Header ( "Accept-Length: " . filesize ( $file_dir . $file_name ) );   
  //attachment是用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name
  Header ( "Content-Disposition: attachment; filename=" . $file_name );  
  
  //读取文件内容并直接输出到浏览器    
  echo fread ( $file, filesize ( $file_dir . $file_name ) );    
  fclose ( $file );    
  exit();   
}

注意:在文件下载的页面要为纯php代码,除了需要下载的文件,不可以再有其它内容输出。否则会数据大小不一致,导致下载失败。

或者可以直接使用readfile函数:

header('content-disposition:attachment;filename='.basename($filename));
header('content-length:'.filesize($filename));
readfile($filename);

《THE END》

猜你喜欢

转载自blog.csdn.net/weixin_42565457/article/details/85001069