热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP实现文件上传下载实例详细讲解

日常开发中,文件的上传和下载是非常重要的并且是不可或缺的一步操作,所以,就需要我们掌握它。浏览器在客户端上传文件,点击提交,文件被传送给服务器中的某个php文件进行处理,该php对该上传文件保存到服务器。
一、上传原理与配置

1.1 原理

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

1.2 客户端配置

所需:表单页面(选择上传文件);

具体而言:发送方式为POST,添加enctype="multipart/form-data"属性,两者缺一不可(但是,优缺点并存,这里也限定了上传的方式和上传的文件之后的调用等方面,后面会说到








请选择您要上传的文件:

先是表单页面(请自动忽略前端问题。。。),关键就是form的属性;另外就是input 中用到了type="file"这一点(体现到php的强大的拓展等等)。

然后是doAction.php

先把print_r($_FILES)这个信息看一下

Array
(
    [myFile] => Array
        (
            [name] => 梁博_简历.doc
            [type] => application/msword
            [tmp_name] => D:\wamp\tmp\php1D78.tmp
            [error] => 0
            [size] => 75776
        )

)

所以得到的是个二维数组,该怎么用,都是基本的东西(其实我喜欢降维再用);

基本是一眼就懂的东西,不罗嗦,关键有两个:tmp_name临时文件名;error报错信息(代号,后面可以利用);

然后这里看一下doAction后面一部分,利用报错信息来反馈给用户,需要说明的是为什么报错,和报错信息是什么都

1.3 关于报错

--报错原因

基本上都是超过或者不符合服务器关于上传文件的配置,那么服务器端配置有哪些呢?

先考虑上传我们用了什么?POST,upload

所以在php.ini中找这么几项:

file_upload:On

upload_tmp_dir=——临时文件保存目录;

upload_max_filesize=2M

max_file_uploads=20——允许一次上传的最大文件数量(注意和上面那个的区别,有没有size,别乱想)

post_max_size=8M——post方式发送数据的最大值

其他相关配置

max_exectuion_time=-1——最大执行时间,避免程序不好占用服务器资源;

max_input_time=60

max_input_nesting_level=64——输入嵌套深度;

memory_limit=128M——最大单线程的独立内存使用量

总之都是有关资源的配置。

--错误号

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; 没有文件被上传。

注意:这个错误信息是第一步上传的信息,也就是上传到临时文件夹的情况,而不是move或者copy的情况。

二、上传相关限制

2.1 客户端限制


请选择您要上传的文件:

这里用input的属性对上传文件的大小和类型进行了限制,但是个人感觉:一,html代码是“可见的”;二,常不起作用(没找到原因,但因为第一个我也想放弃它,知道就好。

2.2 服务器端限制

主要限制大小和类型,再有就是方式。

$maxsize) {
        exit("上传文件过大!");
    }
    if (!in_array($ext, $allowExt)) {
        exit("非法文件类型");
    }
    if (!is_uploaded_file($tmp_name)) {
        exit("上传方式有误,请使用post方式");
    }
    if (@move_uploaded_file($tmp_name, $uniName)) {//@错误抑制符,不让用户看到警告
        echo "文件".$filename."上传成功!";
    }else{
        echo "文件".$filename."上传失败!";
    }
    //判断是否为真实图片(防止伪装成图片的病毒一类的
    if (!getimagesize($tmp_name)) {//getimagesize真实返回数组,否则返回false
        exit("不是真正的图片类型");
    }

}else{
    switch ($error){
        case 1:
            echo "超过了上传文件的最大值,请上传2M以下文件";
            break;
        case 2:
            echo "上传文件过多,请一次上传20个及以下文件!";
            break;
        case 3:
            echo "文件并未完全上传,请再次尝试!";
            break;
        case 4:
            echo "未选择上传文件!";
            break;
        case 7:
            echo "没有临时文件夹";
            break;
    }
}

2.3 封装

函数

$maxSize) {
        exit("上传文件过大!");
    }
    if (!in_array($ext, $allowExt)) {
        exit("非法文件类型");
    }
    if (!is_uploaded_file($tmp_name)) {
        exit("上传方式有误,请使用post方式");
    }
    //判断是否为真实图片(防止伪装成图片的病毒一类的
    if (!getimagesize($tmp_name)) {//getimagesize真实返回数组,否则返回false
        exit("不是真正的图片类型");
    }
    if (@move_uploaded_file($tmp_name, $destination)) {//@错误抑制符,不让用户看到警告
        echo "文件".$filename."上传成功!";
    }else{
        echo "文件".$filename."上传失败!";
    }
    

}else{
    switch ($error){
        case 1:
            echo "超过了上传文件的最大值,请上传2M以下文件";
            break;
        case 2:
            echo "上传文件过多,请一次上传20个及以下文件!";
            break;
        case 3:
            echo "文件并未完全上传,请再次尝试!";
            break;
        case 4:
            echo "未选择上传文件!";
            break;
        case 7:
            echo "没有临时文件夹";
            break;
    }
}
return $destination;
}

调用

三、多文件的上传实现

3.1 利用单文件封装








请选择您要上传的文件:
请选择您要上传的文件:
请选择您要上传的文件:
请选择您要上传的文件:

这里的思路,从print_r($_FILES)中去找,打印出来看到是个二维数组,很简单,遍历去用就好了!

上面那个function的定义改一下,给定一些默认值

function uploadFile($fileInfo,$path="uploads",$allowExt=array('jpeg','jpg','png','tif'),$maxSize=10485760){

这样子,简单是简单,但遇到一些问题。

正常的上传4个图片是没问题,但要是中间激活了函数中的exit,就会立即停止,导致其他图片也无法上传。

3.2升级版封装

旨在实现针对多个或单个文件上传的封装

首先这样子写个静态文件








请选择您要上传的文件:
请选择您要上传的文件:
请选择您要上传的文件:
请选择您要上传的文件:

打印一下$_FILES

Array
(
    [myFile] => Array
        (
            [name] => Array
                (
                    [0] => test32.png
                    [1] => test32.png
                    [2] => 333.png
                    [3] => test41.png
                )

            [type] => Array
                (
                    [0] => image/png
                    [1] => image/png
                    [2] => image/png
                    [3] => image/png
                )

            [tmp_name] => Array
                (
                    [0] => D:\wamp\tmp\php831C.tmp
                    [1] => D:\wamp\tmp\php834C.tmp
                    [2] => D:\wamp\tmp\php837C.tmp
                    [3] => D:\wamp\tmp\php83BB.tmp
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                    [2] => 0
                    [3] => 0
                )

            [size] => Array
                (
                    [0] => 46174
                    [1] => 46174
                    [2] => 34196
                    [3] => 38514
                )

        )

)

可以得到一个三维数组。

复杂是复杂了,但复杂的有规律,各项数值都在一起了,很方便我们取值!!

所以先得到文件信息,变成单文件处理那种信息

function getFiles(){
    $i=0;
    foreach($_FILES as $file){
        if(is_string($file['name'])){  //单文件判定
            $files[$i]=$file;
            $i++;
        }elseif(is_array($file['name'])){
            foreach($file['name'] as $key=>$val){  //我的天,这个$key用的diao
                $files[$i]['name']=$file['name'][$key];
                $files[$i]['type']=$file['type'][$key];
                $files[$i]['tmp_name']=$file['tmp_name'][$key];
                $files[$i]['error']=$file['error'][$key];
                $files[$i]['size']=$file['size'][$key];
                $i++;
            }
        }
    }
    return $files;
    
}

然后之前的那种exit错误,就把exit改一下就好了,这里用res

function uploadFile($fileInfo,$path='./uploads',$flag=true,$maxSize=1048576,$allowExt=array('jpeg','jpg','png','gif')){
    //$flag=true;
    //$allowExt=array('jpeg','jpg','gif','png');
    //$maxSize=1048576;//1M
    //判断错误号
    $res=array();
    if($fileInfo['error']===UPLOAD_ERR_OK){
        //检测上传得到小
        if($fileInfo['size']>$maxSize){
            $res['mes']=$fileInfo['name'].'上传文件过大';
        }
        $ext=getExt($fileInfo['name']);
        //检测上传文件的文件类型
        if(!in_array($ext,$allowExt)){
            $res['mes']=$fileInfo['name'].'非法文件类型';
        }
        //检测是否是真实的图片类型
        if($flag){
            if(!getimagesize($fileInfo['tmp_name'])){
                $res['mes']=$fileInfo['name'].'不是真实图片类型';
            }
        }
        //检测文件是否是通过HTTP POST上传上来的
        if(!is_uploaded_file($fileInfo['tmp_name'])){
            $res['mes']=$fileInfo['name'].'文件不是通过HTTP POST方式上传上来的';
        }
        if($res) return $res;
        //$path='./uploads';
        if(!file_exists($path)){
            mkdir($path,0777,true);
            chmod($path,0777);
        }
        $uniName=getUniName();
        $destination=$path.'/'.$uniName.'.'.$ext;
        if(!move_uploaded_file($fileInfo['tmp_name'],$destination)){
            $res['mes']=$fileInfo['name'].'文件移动失败';
        }
        $res['mes']=$fileInfo['name'].'上传成功';
        $res['dest']=$destination;
        return $res;
        
    }else{
        //匹配错误信息
        switch ($fileInfo ['error']) {
            case 1 :
                $res['mes'] = '上传文件超过了PHP配置文件中upload_max_filesize选项的值';
                break;
            case 2 :
                $res['mes'] = '超过了表单MAX_FILE_SIZE限制的大小';
                break;
            case 3 :
                $res['mes'] = '文件部分被上传';
                break;
            case 4 :
                $res['mes'] = '没有选择上传文件';
                break;
            case 6 :
                $res['mes'] = '没有找到临时目录';
                break;
            case 7 :
            case 8 :
                $res['mes'] = '系统错误';
                break;
        }
        return $res;
    }
}

里面封装两个小的

function getExt($filename){
    return strtolower(pathinfo($filename,PATHINFO_EXTENSION));
}

/**
 * 产生唯一字符串
 * @return string
 */
function getUniName(){
    return md5(uniqid(microtime(true),true));
}

然后在静态中,使用multiple属性实现多个文件的输入








请选择您要上传的文件:

doAction6.php

';
    $uploadFiles[]=@$res['dest'];
}
$uploadFiles=array_values(array_filter($uploadFiles));
//print_r($uploadFiles);

四、面向对象的文件上传

fileName=$fileName;
        $this->maxSize=$maxSize;
        $this->allowMime=$allowMime;
        $this->allowExt=$allowExt;
        $this->uploadPath=$uploadPath;
        $this->imgFlag=$imgFlag;
        $this->fileInfo=$_FILES[$this->fileName];
    }
    /**
     * 检测上传文件是否出错
     * @return boolean
     */
    protected function checkError(){
        if(!is_null($this->fileInfo)){
            if($this->fileInfo['error']>0){
                switch($this->fileInfo['error']){
                    case 1:
                        $this->error='超过了PHP配置文件中upload_max_filesize选项的值';
                        break;
                    case 2:
                        $this->error='超过了表单中MAX_FILE_SIZE设置的值';
                        break;
                    case 3:
                        $this->error='文件部分被上传';
                        break;
                    case 4:
                        $this->error='没有选择上传文件';
                        break;
                    case 6:
                        $this->error='没有找到临时目录';
                        break;
                    case 7:
                        $this->error='文件不可写';
                        break;
                    case 8:
                        $this->error='由于PHP的扩展程序中断文件上传';
                        break;
                        
                }
                return false;
            }else{
                return true;
            }
        }else{
            $this->error='文件上传出错';
            return false;
        }
    }
    /**
     * 检测上传文件的大小
     * @return boolean
     */
    protected function checkSize(){
        if($this->fileInfo['size']>$this->maxSize){
            $this->error='上传文件过大';
            return false;
        }
        return true;
    }
    /**
     * 检测扩展名
     * @return boolean
     */
    protected function checkExt(){
        $this->ext=strtolower(pathinfo($this->fileInfo['name'],PATHINFO_EXTENSION));
        if(!in_array($this->ext,$this->allowExt)){
            $this->error='不允许的扩展名';
            return false;
        }
        return true;
    }
    /**
     * 检测文件的类型
     * @return boolean
     */
    protected function checkMime(){
        if(!in_array($this->fileInfo['type'],$this->allowMime)){
            $this->error='不允许的文件类型';
            return false;
        }
        return true;
    }
    /**
     * 检测是否是真实图片
     * @return boolean
     */
    protected function checkTrueImg(){
        if($this->imgFlag){
            if(!@getimagesize($this->fileInfo['tmp_name'])){
                $this->error='不是真实图片';
                return false;
            }
            return true;
        }
    }
    /**
     * 检测是否通过HTTP POST方式上传上来的
     * @return boolean
     */
    protected function checkHTTPPost(){
        if(!is_uploaded_file($this->fileInfo['tmp_name'])){
            $this->error='文件不是通过HTTP POST方式上传上来的';
            return false;
        }
        return true;
    }
    /**
     *显示错误 
     */
    protected function showError(){
        exit(''.$this->error.'');
    }
    /**
     * 检测目录不存在则创建
     */
    protected function checkUploadPath(){
        if(!file_exists($this->uploadPath)){
            mkdir($this->uploadPath,0777,true);
        }
    }
    /**
     * 产生唯一字符串
     * @return string
     */
    protected function getUniName(){
        return md5(uniqid(microtime(true),true));
    }
    /**
     * 上传文件
     * @return string
     */
    public function uploadFile(){
        if($this->checkError()&&$this->checkSize()&&$this->checkExt()&&$this->checkMime()&&$this->checkTrueImg()&&$this->checkHTTPPost()){
            $this->checkUploadPath();
            $this->uniName=$this->getUniName();
            $this->destination=$this->uploadPath.'/'.$this->uniName.'.'.$this->ext;
            if(@move_uploaded_file($this->fileInfo['tmp_name'], $this->destination)){
                return  $this->destination;
            }else{
                $this->error='文件移动失败';
                $this->showError();
            }
        }else{
            $this->showError();
        }
    }
}
uploadFile();
echo $dest;

五、下载







下载1.rar

下载1.jpg
通过程序下载1.jpg
下载nv.jpg

总结:



二维数组的降维处理;

$_FILES变量

move_upload_file();copy();

tmp_name临时文件;

拓展名的提取;

真实图片的验证;

唯一文件名的生成;

函数封装以及调用;

利用单个文件函数实现多文件上传;

小功能的封装;

多文件的遍历;

面向对象的开发过程;

下载;

以上就是全部的讲解,希望可以帮助到大家,有错误的地方请指出。

更多相关问题请访问PHP中文网:PHP视频教程

以上就是PHP实现文件上传下载实例详细讲解的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
author-avatar
小志19841126_466
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有