之前发了个100分的求助帖,结果给结贴了,刚发现还是不对。再发一个100分的帖,为了学会技术,我已经拿出200分了,大虾帮帮忙。
关于php文件上传问题,界面很简单,就是一个选择文件的文本框,还有一个上传按钮,我是想选择图片并且上传给服务器,然后服务器进行相应的操作。过大的文件是不允许上传的。但是,对于文件过大的,我不希望上传,之前做的还是上传到服务器然后由服务器看是不是过大,再返回给用户信息,这样做还是增加了服务器的压力。有谁有想法,可以不需要将文件上传到服务器就可以获取它的大小,js是不可以的因为浏览器的兼容问题,我也试过flash和js和php的使用,可是对于某些浏览器还是不兼容。PHP目前支持apc,可是在里面貌似没有找到可以截取http流的方法。
我不知道我这样理解对不对,客户端向服务器端传文件,是先传一个头过去,里面包含文件的具体信息包括大小,然后服务器响应并告诉客户端是否可以传,这样是否有机会获得那个头里面的文件大小,如果过大就不允许传文件。
不把大文件传给服务器,但是还要让服务器知道它有多大以便服务器作出判断是否允许传文件,大家有想法的可以谈谈。

解决方案 »

  1.   

    PHP上传问题总结(文件大小检测,大文件上传) 
          由于涉及到本地和服务器两方面的安全问题,所以基于input type="file"形式的页面文件上传一直处于一个很尴尬的位置。一方面,用户不希望隐私泄露,所以浏览器无法对用户在上传时选择的文件做有效的判 断。另一方面,为了服务器端的安全,减轻传输负担,系统又希望能在用户开始上传之前就将非法的文件拒之门外。
           一来一去,基于原始input方式的上传,成为网络存储网站避之唯恐不及的遗留性问题,也造就了现在千奇百怪的插件、上传客户端。
           input方式的上传就如此之差么?当然不是。上传文件不大的时候,它还是非常简单可靠的,在PHP中,我们只需要一个复合型表单
    <form enctype="multipart/form-data" action="__URL__" method="POST">
          一个输入框
    <input name="userfile" type="file" />
           和服务器端的一行代码
    move_uploaded_file($_FILES['userfile']['tmp_name'], '/var/www/uploads/'. basename($_FILES['userfile']['name']));
           就可以实现整个上传过程。
           但随文件增大,表单上传的不足就会暴露出来。尤其是我们想取得最基本的文件大小来阻止过大文件上传这一简单的想法,也变得如此困难。以下一一道来:
    通过MAX_FILE_SIZE
            我们经常会在手册里读到:
    MAX_FILE_SIZE 隐藏字段(单位为字节)必须放在文件输入字段之前,其值为接收文件的最大尺寸。这是对浏览器的一个建议,PHP 也会检查此项。在浏览器端可以简单绕过此设置,因此不要指望用此特性来阻挡大文件。实际上,PHP 设置中的上传文件最大值是不会失效的。但是最好还是在表单中加上此项目,因为它可以避免用户在花时间等待上传大文件之后才发现文件过大上传失败的麻烦。
           显然PHP的开发者们也考虑到了大文件上传的问题,但就像手册所说,MAX_FILE_SIZE只是对浏览器的一个建议,事实上目前为止所有主流的浏览器并没有采纳这个建议,所以采用MAX_FILE_SIZE约束文件大小形同摆设,不可行。
    通过服务器端
           MAX_FILE_SIZE既然无效,那么用户可以将文件上传到服务器,服务器端通过$_FILES['userfile']['size']判断用户上 传的文件大小,然后决定是否接受上传并返回信息。暂且排除服务器的负荷以及可能存在的恶意破坏行为,这种解决方案听起来无非是浪费一部分带宽,也能对用户 上传文件作出约束。
           但这也是不可行的,PHP的文件上传受到php.ini以下这些设置的影响:
    • post_max_size
    • upload_max_filesize
    • max_execution_time
    • memory_limit
           虽然设置方法在手册中都有比较详细的说明,之所以仍然说此方法不可行,是因为php执行脚本在超过memory_limit时,该次的POST数据会全部丢失并且不会报错!
           试想用户填写了一个超长的表单,并伴随一个超过memory_limit的文件一起上传,经过了漫长的等待时间之后发现等来的又是一张干干净净的空白表 单,那是何等印象深刻的用户体验啊。更何况数十M的服务器流量仅仅用来检测文件大小,是现在的网络环境不允许的。
    通过Javascript
            Javascript是基于浏览器的,虽然JS能完成很多看似不可能的任务,但浏览器做不到的事情JS同样无法做到。先天不足注定了这项工作仅仅靠Javascript是无法胜任的。不过一些IE Only的方法也还是存在的,仅作参考。
    通过Flash
             Flash的FileReference类提供了一套比较全面的文件处理方法,现在大多数大文件上传也都采用了基于Flash的方案。如果利用Flash与Js交互,能否实现客户端对文件大小的检测呢?答案是可行的。
           首先在flash文件中实例化FileReference类。
    var fr = new FileReference();
           基于这个类就可以用Flash提供的file browse和SelectFile事件替代浏览器的事件。我们需要:
           1.绑定SelectFile
    fr.addEventListener(Event.SELECT, onSelectFile);
           2.创建一个供Js访问的对象,用来放置flash得到的文件信息
    var s = {
       size:0,
       name:'',
       type:''
        }
           3.创建file browse方法
    function browseFile():void {
     fr.browse();
        }
           4.当SelectFile事件触发的时候,传递文件信息
    function onSelectFile(e:Event):void {
      s.size = fr.size;
      s.name = fr.name;
      s.type = fr.type;
        }
           5.将browseFile方法公开可供Js调用
    ExternalInterface.addCallback("browseFile", browseFile);
           6.将得到的文件信息传递给Js
    ExternalInterface.call("onSelectFile",s);
           现在我们已经可以通过Js获得由flash传递来的文件大小信息了,具体的实现可以参看Demo。
    结论
           问题至此似乎已经得到解决了,我们已经成功的校验了文件大小不是么。但本文的最终结论是,基于Flash的文件大小校验,仍然不可行。
           文件大小校验的唯一目的,是为了上传。在上面的Demo中可以看到校验成功的文件名会显示在一个输入框里。熟悉上传的同学不觉得少了什么吗?没错,通过 flash只能得到文件名,而无法得到文件的完整路径,而文件路径却是input方式上传的必要条件。所以虽然可以成功的通过Flash与Js交互校验文 件大小,但我们能做到的也仅仅只是校验而已,之后想要上传,唯有继续通过flash方式进行。
           Flash开发出于安全考虑屏蔽了文件的完整路径这无可厚非,不过文件上传,尤其是PHP环境下的文件校验上传方案仍然没有得到最好的解决。
           当然弥补的方法有很多:
    • 基于Perl的项目 FileChucker , XUpload , Uber-Uploader
    • 基于Flash的项目 SWFUpload
    • 还有筒子用PHP直接在服务器华丽的建立socket链接。
          但终究我希望有一天能看到仅基于HTML就能实现的严整健壮的上传方案,但愿这一天不会太远。
          最后是本次的代码下载。
    php文件上传大小设置详解
    用php上传文件,问题最多的就是上传大体积文件时出现错误。 
    这就涉及到php的配置文件:php.ini 在此配置文件中,有这么几个值是跟文件上传有密切关系的: 
    file_uploads = on //是否允许系统支持文件上传 
    ;upload_tmp_dir //临时文件的存储路径,linux下为系统默认路径,win32下需要指定 
    upload_max_filesize = 2m //允许文件上传最大体积 post_max_size = 2m //通过post方法给php时,php所能接受的最大数据容量 如果你上传的文件体积在8m一下(通常情况),那修改以上设置就可以满足你的要求了。。 但要>8m,那除了上面几个值,还要特别关注另外两个值了: 
    max_execution_time = 30 //每个script所执行的最大时间(php上传就时,体积大了,就是个时间问题) 
    memory_limit = 8m //每个script所能消耗的最大memory 试着把这两个值改大些。一般就可以解决大多数问题了。 就此推断,上传文件的体积是可以无穷大的。但还要考虑你的网络情况,等等。 在php.net上,有人说按照这个方法改了后,大于100m的文件还是会出错。 
    不知道是不是php本身的问题了:
    php实现文件上传的一些经验
    • //图片上传处理
    $upload_file=$_FILES['upload_file']['tmp_name'];
    echo $upload_file;
    $upload_file_name=$_FILES['upload_file']['name'];
    $type=strstr($upload_file_name, '.');
    if($upload_file=="")
    {
    $newname="0.jpg"; 
    }
    else
    {
    $newname=$newid.$type;
    }
    //$newname=$newid.$type;
    $intonew2="update mms_news_info set col_image='$newname' where col_id='$newid'";
    mysql_query($intonew2,$db);
     
    if($upload_file){
    $file_size_max = 1000*1000;// 1M限制文件上传最大容量(bytes)
    $store_dir = "neirongimg/";// 上传文件的储存位置
    $accept_overwrite = 1;//是否允许覆盖相同文件
    // 检查文件大小
    if ($upload_file_size > $file_size_max) {
    echo "对不起,你的文件容量大于规定";
    exit;
    }
    // 检查读写文件
    if (file_exists($store_dir . $upload_file_name) && $accept_overwrite) {
    Echo   "存在相同文件名的文件";
    exit;
    }
    //复制文件到指定目录
    if (!move_uploaded_file($upload_file,$store_dir.$newname)) {
    echo "复制文件失败";
    exit;
    }
    }
    Echo   "<p>你上传了文件:";
    echo  $_FILES['upload_file']['name'];
    echo "<br>";
    //客户端机器文件的原名称。
    Echo   "文件的 MIME 类型为:";
    echo $_FILES['upload_file']['type'];
    //文件的 MIME 类型,需要浏览器提供该信息的支持,例如“image/gif”。 
    echo "<br>";
    Echo   "上传文件大小:";
    echo $_FILES['upload_file']['size'];
    //已上传文件的大小,单位为字节。 
    echo "<br>";
    Echo   "文件上传后被临时储存为:";
    echo $_FILES['upload_file']['tmp_name'];
    //文件被上传后在服务端储存的临时文件名。 
    echo "<br>";$Erroe=$_FILES['upload_file']['error'];
    switch($Erroe){
    case 0:
    Echo   "上传成功"; break;
    case 1:
    Echo   "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值."; break;
    case 2:
    Echo   "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。";    break;
    case 3:
    Echo   "文件只有部分被上传";break;
    case 4:
    Echo   "没有文件被上传";break;
    }
      //图片上传处理
    ?>
    +++++++++++++++++++++++++++++++++
    关于错误信息的解释
    从 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; 没有文件被上传。注: 这些在 PHP 4.3.0 之后变成了 PHP 常量。
    PHP 能够接受任何来自符合 RFC-1867 标准的浏览器(包括 Netscape Navigator 3 及更高版本,Microsoft Internet Explorer 3 加微软补丁,或者更高版本)上传的文件。PHP 的这种特性使得我们既可以上传文本文件,也可以上传二进制文件。利用 PHP 的认证和文件操作函数,您就可以控制谁有上传的权限,以及在文件上传后进行哪些处理。
    相关的设置: 请参阅 php.ini 的 file_uploads、 upload_max_filesize、upload_tmp_dir 以及 post_max_size 设置选项。
    请注意 PHP 也支持 PUT 方法的文件上传,Netscape Composer 和 W3C 的 Amaya 客户端使用这种方法。请参阅 PUT 方法支持以获取更多信息。
    您可以如下建立一个特殊的表单来支持文件上传:
    例子 18-1. 文件上传表单
    <form enctype="multipart/form-data" action="_URL_" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000">
    Send this file: <input name="userfile" type="file">
    <input type="submit" value="Send File">
    </form>以上范例中的“_URL_”应该替换成指向一个 PHP 文件的真实 URL。MAX_FILE_SIZE 隐藏域(单位为字节)必须先于文件输入域,其值为接收文件的最大尺寸。同时,要保证您的文件上传表单中要有 enctype="multipart/form-data",否则文件上传将不能工作。警告 
    MAX_FILE_SIZE 的值只是对浏览器的一个建议,实际上它可以被简单的绕过。因此不要把对浏览器的限制寄希望于该值。实际上,PHP 设置中的上传文件最大值,是不会失效的。但是最好还是在表单中加上 MAX_FILE_SIZE,因为它可以避免用户在花时间等待上传大文件之后才发现该文件太大了的麻烦。 为上传文件定义的变量会根据 PHP 的版本及设置的不同而不同。自动全局变量 $_FILES 从 PHP 4.1.0 版本开始被支持。在这之前,从 4.0.0 版本开始,PHP 支持 $HTTP_POST_FILES 数组。这些数组将包含所有关于您上传的文件的信息,其中,我们推荐您使用 $_FILES。如果 PHP 的设置选项 register_globals 为 on,则相关的变量名将也会存在。从 PHP 4.2.0 版本开始,register_globals 的默认值被设为 off。
    以上范例中 $_FILES 数组的内容如下所示。我们假设文件上传字段的名称如上例所示,为 userfile。名称可随意命名。$_FILES['userfile']['name']
    客户端机器文件的原名称。
    $_FILES['userfile']['type']
    文件的 MIME 类型,需要浏览器提供该信息的支持,例如“image/gif”。
    $_FILES['userfile']['size']
    已上传文件的大小,单位为字节。
    $_FILES['userfile']['tmp_name']
    文件被上传后在服务端储存的临时文件名。
    $_FILES['userfile']['error']
    和该文件上传相关的错误代码。['error'] 是在 PHP 4.2.0 版本中增加的。注: 在 PHP 4.1.0 版本以前该数组的名称为 $HTTP_POST_FILES,它并不像 $_FILES 一样是自动全局变量。PHP 3 不支持 $HTTP_POST_FILES 数组。
    当 php.ini 中的 register_globals 被设置为 on 时,您可以使用更多的变量。例如,$userfile_name 等价于 $_FILES['userfile']['name'],$userfile_type 等价于 $_FILES['userfile']['type'] 等。请记住从 PHP 4.2.0 开始,register_globals 的默认值为 off,因此我们建议您不要依赖于改设置项而使用刚刚提到的那些附加变量。
    文件被上传后,默认地会被储存到服务端的默认临时目录中,除非您将 php.ini 中的 upload_tmp_dir 设置为了其它的路径。服务端的默认临时目录可以通过更改 PHP 运行环境的环境变量 TMPDIR 来重新设置,但是在 PHP 脚本内部通过运行 putenv() 函数来设置是不起作用的。该环境变量也可以用来确认其它的操作也是在上传的文件上进行的。 例子 18-2. 使文件上传生效
    请查阅函数 is_uploaded_file() 和 move_uploaded_file() 以获取进一步的信息。以下范例处理由表单提供的文件上传。
    <?php
    // 在 4.1.0 以前的 PHP 中,需要用 $HTTP_POST_FILES 代替 $_FILES。
    // 在 4.0.3 以前的 PHP 中,需要用 copy() 和 is_uploaded_file() 来代替 move_uploaded_file()。
    $uploaddir = '/var/www/uploads/';
    $uploadfile = $uploaddir. $_FILES['userfile']['name'];
    print "<pre>";
    if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir . $_FILES['userfile']['name'])) {
    print "File is valid, and was successfully uploaded.  Here's some more debugging info:\n";
    print_r($_FILES);
    } else {
    print "Possible file upload attack!  Here's some debugging info:\n";
    print_r($_FILES);
    }
    print "</pre>";
    ?>接受上传文件的 PHP 脚本必须在文件上传后进行判断,来决定接下来要对该文件进行那些操作。例如,您可以通过 $_FILES['userfile']['size'] 变量来忽略尺寸太大或太小的文件,也可以通过这是网上的一篇关于这方面的技术贴,我也都尝试了,而且用flash也实现了,可是这个并不是所有浏览器都支持,哎,还是那句话,和js有关的想法在这里不要想了。期待大虾的看法。
      

  2.   

    js是行不太通的 flash是比较好的解决方法
    http://edu.codepub.com/2010/0515/22720.php
      

  3.   


    flash的兼容性太差了,mac下的更是悲催,还有没有别的方法啊?
      

  4.   

    限制:<input type="text" size="4" value="10" name="fileSizeLimit" id="fileSizeLimit"/> K
    <input type="file" name="file1" id="file1" size="40" onchange="changeSrc(this)"/>
    <br>
    <img src=http://blog.xunuo.com/blog/images/icons/23.gif id="fileChecker" alt="test"/><script type="text/javascript">
    var oFileChecker = document.getElementById("fileChecker");function changeSrc(filePicker)
    {
        oFileChecker.src = filePicker.value;
    }oFileChecker.onreadystatechange = function ()
    {
        if (oFileChecker.readyState == "complete")
        {
            checkSize();
        }
    }function checkSize()
    {
        var limit  = document.getElementById("fileSizeLimit").value * 1024;    if (oFileChecker.fileSize > limit)
        {
            alert("too large");
        }
        else
        {
            alert("ok");
        }
    }
    </script>  
      

  5.   

    <script language="JavaScript">  
    <!--  
    function ShowSize(files)  
    {  
      var fso,f;  
      fso=new ActiveXObject("Scripting.FileSystemObject");  
      f=fso.GetFile(files);
      var fileSize = f.size ;
      if((fileSize/1024) < 1024){
        alert(fileSize/1024+"K");
      }else if( ((fileSize/1024) > 1024) && ((fileSize/(1024*1024)) < 1024)){
        alert(fileSize/(1024*1024)+"M");
      }else{
        alert(fileSize/(1024*1024*1024)+"G")
      }
    }  
    //-->  
    </script>  
      

  6.   

    上传的文件通过$_FIFLE['filename']['size']的大小,可以来判断
      

  7.   

    目前不是所有浏览器都支持size的,楼主这个不是很好解决的,见你学习一下php apc,它可以帮助你截获http头文件。
      

  8.   

    已经解决,如果有想了解的,可以大家一起讨论,php的创始人开发的apc解决的。
      

  9.   

    Friefox下flash上传文件的session和页面并不一致,如果有登录权限控制就无法上传,你可以写个log文件来检测session看看
      

  10.   

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    <form action="uploadfile.php" method="post" enctype="multipart/form-data">
    选择文件<input type="file" name="file">
         <input type="submit" value="上传文件">
         <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
    </form>
    </body>
    </html>
    <?php
    /*
    * Created on 2010-11-21
    *
    * To change the template for this generated file go to
    * Window - Preferences - PHPeclipse - PHP - Code Templates
    *//*
      * 文件上传
      *
      * 首先 要有一个上传页面 并且 文件上传  必须用 post方法 必须用 $_FILES 接受 post传过来的文件  进行上传
      *
      *判断是否为上传文件  is_upload_file 返回true
      *
      * 判断  ------  文件 判断文件大小  超大文件提示 文件过大
      *      ------  判断文件上传 是否存在错误
      *   ------ 上传文件格式(类型)判断 函数 in_array()检查函数中是否有某值
      *    bool in_array ( mixed needle, array haystack [, bool strict] )
      *        在 haystack 中搜索 needle,如果找到则返回 TRUE,否则返回 FALSE。
      *
      *type  不说 你也应该知道怎么获得 、、、、、
      *
      */
        $ = false;
    switch($_FILES['file']['error']){
      case 1:
       echo "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值";
       $ = true;
       break;
      case 2:
       echo "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值";
       $ = true;
       break;
      case 3:
       echo "文件只有部分被上传";
       $ = true;
       break;
      case 4:
       echo "没有文件被上传";
       $ = true;
       break;
      case 6:
       echo "找不到临时文件夹";
       $ = true;
       break;
      case 7:
       echo "文件写入失败";
       $ = true;
       break;
    }
    if($){
      echo "上传失败";
    }
    if($_FILES['file']['size']>2000000){
      die("文件过大");
    }var_dump($_FILES);
    $subfile = explode('.',$_FILES['file']['name']);
    if(!in_array($subfile[1],array('jpg','gif','jpeg','rar','txt'))){
       echo "上传文件格式不正确"."<br>";
    }
    $mine = array('image/pjpeg','image/jpg','image/jpeg','image/gif','image/png');
    if(!in_array($_FILES['file']['type'],$mine)){
      echo "上传文件类型不正确"."<br>";
    }
    //echo $subfile[1];
    //var_dump($subfile);
    //echo uniqid().".".$subfile[1];
    if(is_uploaded_file($_FILES['file']['tmp_name'])){
      if(move_uploaded_file($_FILES['file']['tmp_name'],uniqid().".".$subfile[1])){
        echo "上传成功"."<br>";
      }else{
       echo "文件移动失败";
      }
    }else{
      echo "上传失败";
    }
    ?>
      

  11.   

    先要判断文件夹是否成在,如果不存在用mkdir创建~