ASP文件上传原理分析及实现实例

ASP文件上传原理分析及实现实例,第1张

摘要 在基于/的应用环境中 上传各种类型的文件一直是困扰用户文件管理应用的难题之一 在HTTP中上传文件有三种机制 RFC PUT和WebDAV 常用的实现方法是利用在RFC 中引入的一个新类型 File以及ADO Stream对象 本文对上述上传方法及实现原理作了论述 并给出了具体解决实例     ASP FILE对象

当前 基于/模式的应用比较流行 当用户需要将文件传输到上时 常用方法之一是运行FTP并将每个用户的FTP默认目录设为用户的Web主目录 这样用户就能运行FTP客户程序并上传文件到指定的 Web目录 这就要求用户必须懂得如何使用FTP客户程序 因此 这种解决方案仅对熟悉FTP且富有经验的用户来说是可行的 如果我们能把文件上传功能与Web集成 使用户仅用Web就能完成上传任务 这对于他们来说将是非常方便的 但是 一直以来 由于File System Object的仅能传送文本文件的局限 所以ASP最大的难题就是文件上传问题 下面介绍的就是如何在基于HTTP协议的网页中实现文件的上传

一 通过HTTP上传的三种机制

通过HTTP上传有三种机制 RFC PUT 和 WebDAV

PUT 是在HTTP 引入了一个新的HTTP动词 当web收到一个HTTP PUT和对象名字 它将会验证用户 接收HTTP流的内容 并把它直接存入web 由于这可能会对一个web站点造成破坏 并且还会失去HTTP最大的优势 可编程性 在PUT的情况下 自己处理请求 没有空间让CGI或者ASP应用程序介入 唯一让你的应用程序捕获PUT的方法是在低层 *** 作 ISAPI过滤层 由于相应的原因 PUT的应用很有限

而WebDAV允许web内容的分布式拆吵认证与翻译 它引入了几种新的HTTP动词 允许通过HTTP上传 锁定/解锁 登记/检验web内容行御知 Office 中的 Save to web 就是通过WebDAV来实现的 如果你所感兴趣的一切都是上传内容 WebDAV应用得非常出色 它解决了很多问题 然而 如果你需要在你的web应用程序里面上传文件 WebDAV对你就毫无用处可言 象HTTP PUT一样 那些WebDAV的动词是被解释的 而不是web应用程序 你需要工作在ISAPI过滤层来访问WebDAV的这些动词 并在你的应用程序中解释内容

RFC () 最终被W C在HTML 中接受前 是作为一种建议标准 它是一种非常简单但是功能很强大的想法 在表单字段中定义一个新类型  <INPUT TYPE= FILE >

    并且在表单本身加入了不同的编码方案 不再使用典型的  <FORM ACTION= formproc asp METHOD= POST >    而是使用  <FORM ACTION= formproc asp METHOD= POST ENCTYPE= multipart/form data >

这种编码方案在传送大量数据的时候 比起缺省的 application/x url encoded 表单编码方案 显得效率要高得多 URL编码只有很有限的字符集 使用任何超出字档消符集的字符 必须用 %nn 代替 这里的nn表示相应的 个十六进制数字 例如 即使是普通的空格字符也要用 % 代替 而RFC 使用多部分MIME编码 就象通常在e mail消息中看到的那样 不编码来传送大量数据 而只是在数据周围加上很少的简单但实用的头部 主要的厂商都采用了建议的 浏览…… 按钮 用户能很容易的使用本地 打开文件…… 对话框选择要上传的文件

RFC 仍然将大多数文件上传的灵活方法留给了你的web应用程序 PUT用得很有限 WebDAV对内容的作者很有用 比如FrontPage用户 但是对想在web应用程序中加入文件上传的web开发者来说很少用到 因此 RFC 是在web应用程序中加入文件上传的最好的办法

在实际应用中 免费提供了Posting Acceptor ASP不懂 multipart/form data 编码方案 取而代之 提供了Posting Acceptor Posting Acceptor是一种在上传完成后 接受REPOST到一个ASP页的ISAPI应用程序

Sofare Artisans的SA FileUp是最早的商业Active Server之一 几经改进 现在作为一个纯粹的ASP存在

二 基于ASP的文件上传实现原理分析

基本原理是 采用ADO Stream对象的BinaryRead方法将FORM中的所有数据读出 从中截取出所需的文件数据 以二进制文件方式存盘

下面是上传文件页面的一个例子()  <><body><form name= Upload Method= Post Enctype= multipart/form data Action= Upload asp ><input type= file name= FileName ><INPUT TYPE= Submit VALUE= Upload ></TD></form></body></>

    程序中使用了文件对象 这样在Upload asp中采用BinaryRead方法读来的原始数据就不仅仅是选择的文件本身的数据 还包含该文件在用户硬盘上的路径 类型 提交页面的表单等相关信息的描述 这样我们就需从中提取出文件的具体内容 根据分析 数据的头部信息与数据的分界线是两对回车换行符 尾部也有分隔信息 我们可以采用类似以下的方法获取文件数据  Dim FormData FormSize DataStart CLStr DivStrFormSize=Request TotalBytesFormData=Request BinaryRead(FormSize)CLStr=ChrB( )&ChrB( )DataStart=InStrB(FormData CLStr&CLStr)+ 是两对回车换行符的长度DivStr=LeftB(FormData InStrB(FormData CLStr) )DataSize=InStrB(DataStart+ FormData DivStr) DataStart FormData=MidB(FormData DataStart DataSize)    FormData就是文件的内容了     中间根据需要 可进行相应的处理 最后的工作就是将文件保存了 保存的方法可以有两种 一种是利用VB或VC之类程序中的二进制文件 *** 作方法 在工程中加入适当的类型库 最终编译成DLL文件 使用时再将该DLL文件注册就可以了 文件存贮程序如下  Public Function SaveFile(Pathname As String) As String Dim objContext As ObjectContext Dim objRequest As Request  Set objContext=GetObjectContext() Set objRequest=objContext( Request ) 以下的一段代码是进行文件存贮的有关 *** 作 Dim FormData() As Byte CLStr DivStr Dim DataStart As Long DataSize As Long DataSize=objRequest TotalBytes Redim FormData(DataSize ) FormData=objRequest BinaryRead(DataSize) CLStr=ChrB( ) &ChrB( ) DataStart=InStrB(FormData CLStr &CLStr)+ DivStr=LeftB(FormData InStrB(FormData CLStr) ) DataSize=InStrB(DataStart+ FormData DivStr) DataStart FormData=MidB(FormData DataStart DataSize) 创建一个二进制文件并将FormData写入其中 Open Pathname For Binary As Put # FormData Close # SaveFile= OK! End Function     第二种方法是利用ADO STREAM中提供的二进制文件 *** 作方法来完成 保存文件的语句是 StreamOBJ SaveToFile (fileName ) 在 这种 *** 作中 我们可以将有关的 *** 作存放在一个类文件中 在应用时 直接将该类文件包含在ASP程序中就可以了 具体处理方法 请参阅有关介绍 三.文件上传实现方法实例 实现文件上传可使用或无方式 对于类 比如说microsoft posting acceptor(简称mpa) 就是公司发布的一个免费 这类的安装也比较方便 对于的mpa 运行它的安装文件就可以了 而一般的dll形式的 我们则需要进行注册 例如 要使用aspcnUP dll 只要在Window 上执行regsvr [path\]aspcnUP dll 系统出现注册成功的信息提示就可以使用该了 对于无类 如的无上传类 upload_ xsoft 在使用时 只要在处理程序中包含以下的语句就可以了  <! #include FILE= upload inc >set upload=new upload_ xSoft 建立上传对象    有关的属性与 *** 作方法 请参阅该的使用手册     下面是詀spcnUP dll为例 上传部分类型文件的源代码(upload asp)  <% @ language= vbscript  Set fileUP=Server CreateObject( aspcn Upload ) fileUP Maxsize=  fileUP Path= d:\upfile  fileUP Upload For i= to fileUP Countfieldname=fileUP FieldName(i)If fileUP FileType(fieldname)= zip Or ileUP FileType(fieldname)= rar Then fileUP Save fieldnameEnd If  Next Set fileUP=Nothing%>  四.结束语 应用模式还在快速地发展着 在ASP.NET中 已经内置了文件上传的功能 使用非常简单方便 作为一种全新的技术 ASP.NET并不只是ASP的简单升级 它是一个用于Web开发的全新框架 其中包含了许多新的特性 ASP.NET提供了更易于编写 结构更清晰的代码 利用这些代码我们将会更容易地进行再利用和共享 从而开发出更多更实用的程序来 lishixinzhi/Article/program/net/201311/13562

<?php

  /** 

    file: fileupload.class.php 文件上传类FileUpload

    本类的实例对象用于处理上传文件,可以上传一个文件,也可同时处理多个文件上传

  */

  class FileUpload { 

    private $path = "./uploads"          //上传文件保存的路径

    private $allowtype = array('jpg','gif','png') //设置限制上传文件的类型

    private $maxsize = 1000000           //限制文件上传大小(字节)

    private $israndname = true           //设置是否随机重命名文件, false不随机

 

    private $originName              //源文件名

    private $tmpFileName              //临时文件名

    private $fileType               //文件类型(文件后缀)

    private $fileSize               //文件大小

   余肆 private $newFileName              //新文件名

    private $errorNum = 0             //错误号

    private $errorMess=""             //错误报告消息

 

    /**

     * 用于设置成员属性($path, $allowtype,$maxsize, $israndname)

     * 可以通过连贯 *** 作一次设置多个属性值

     *@param  string $key  成员属性名(不区分大小写)

    或塌 *@param  mixed  $val  为成员属性设置的值

     *@return  object     返回自己对象$this,可以用于连贯 *** 作

     */

    function set($key, $val){

      $key = strtolower($key) 

      if( array_key_exists( $key, get_class_vars(get_class($this) ) ) ){

        $this->setOption($key, $val)

      }

      return $this

    }

 

    /**

     * 调用该方法上传文件

     * @param  string $fileFile  上传文件的表单名称 

     * @return bool        如果上传成功返回数true 

     */

 

    function upload($fileField) {

      $return = true

      /* 检衫毁圆查文件路径是滞合法 */

      if( !$this->checkFilePath() ) {       

        $this->errorMess = $this->getError()

        return false

      }

      /* 将文件上传的信息取出赋给变量 */

      $name = $_FILES[$fileField]['name']

      $tmp_name = $_FILES[$fileField]['tmp_name']

      $size = $_FILES[$fileField]['size']

      $error = $_FILES[$fileField]['error']

 

      /* 如果是多个文件上传则$file["name"]会是一个数组 */

      if(is_Array($name)){    

        $errors=array()

        /*多个文件上传则循环处理 , 这个循环只有检查上传文件的作用,并没有真正上传 */

        for($i = 0 $i < count($name) $i++){ 

          /*设置文件信息 */

          if($this->setFiles($name[$i],$tmp_name[$i],$size[$i],$error[$i] )) {

            if(!$this->checkFileSize() || !$this->checkFileType()){

              $errors[] = $this->getError()

              $return=false 

            }

          }else{

            $errors[] = $this->getError()

            $return=false

          }

          /* 如果有问题,则重新初使化属性 */

          if(!$return)          

            $this->setFiles()

        }

 

        if($return){

          /* 存放所有上传后文件名的变量数组 */

          $fileNames = array()      

          /* 如果上传的多个文件都是合法的,则通过销魂循环向服务器上传文件 */

          for($i = 0 $i < count($name) $i++){ 

            if($this->setFiles($name[$i], $tmp_name[$i], $size[$i], $error[$i] )) {

              $this->setNewFileName() 

              if(!$this->copyFile()){

                $errors[] = $this->getError()

                $return = false

              }

              $fileNames[] = $this->newFileName  

            }          

          }

          $this->newFileName = $fileNames

        }

        $this->errorMess = $errors

        return $return

      /*上传单个文件处理方法*/

      } else {

        /* 设置文件信息 */

        if($this->setFiles($name,$tmp_name,$size,$error)) {

          /* 上传之前先检查一下大小和类型 */

          if($this->checkFileSize() && $this->checkFileType()){ 

            /* 为上传文件设置新文件名 */

            $this->setNewFileName() 

            /* 上传文件  返回0为成功, 小于0都为错误 */

            if($this->copyFile()){ 

              return true

            }else{

              $return=false

            }

          }else{

            $return=false

          }

        } else {

          $return=false 

        }

        //如果$return为false, 则出错,将错误信息保存在属性errorMess中

        if(!$return)

          $this->errorMess=$this->getError()  

 

        return $return

      }

    }

 

    /** 

     * 获取上传后的文件名称

     * @param  void   没有参数

     * @return string 上传后,新文件的名称, 如果是多文件上传返回数组

     */

    public function getFileName(){

      return $this->newFileName

    }

 

    /**

     * 上传失败后,调用该方法则返回,上传出错信息

     * @param  void   没有参数

     * @return string  返回上传文件出错的信息报告,如果是多文件上传返回数组

     */

    public function getErrorMsg(){

      return $this->errorMess

    }

 

    /* 设置上传出错信息 */

    private function getError() {

      $str = "上传文件<font color='red'>{$this->originName}</font>时出错 : "

      switch ($this->errorNum) {

        case 4: $str .= "没有文件被上传" break

        case 3: $str .= "文件只有部分被上传" break

        case 2: $str .= "上传文件的大小超过了HTML表单中MAX_FILE_SIZE选项指定的值" break

        case 1: $str .= "上传的文件超过了php.ini中upload_max_filesize选项限制的值" break

        case -1: $str .= "未允许类型" break

        case -2: $str .= "文件过大,上传的文件不能超过{$this->maxsize}个字节" break

        case -3: $str .= "上传失败" break

        case -4: $str .= "建立存放上传文件目录失败,请重新指定上传目录" break

        case -5: $str .= "必须指定上传文件的路径" break

        default: $str .= "未知错误"

      }

      return $str.'<br>'

    }

 

    /* 设置和$_FILES有关的内容 */

    private function setFiles($name="", $tmp_name="", $size=0, $error=0) {

      $this->setOption('errorNum', $error)

      if($error)

        return false

      $this->setOption('originName', $name)

      $this->setOption('tmpFileName',$tmp_name)

      $aryStr = explode(".", $name)

      $this->setOption('fileType', strtolower($aryStr[count($aryStr)-1]))

      $this->setOption('fileSize', $size)

      return true

    }

 

    /* 为单个成员属性设置值 */

    private function setOption($key, $val) {

      $this->$key = $val

    }

 

    /* 设置上传后的文件名称 */

    private function setNewFileName() {

      if ($this->israndname) {

        $this->setOption('newFileName', $this->proRandName())  

      } else{ 

        $this->setOption('newFileName', $this->originName)

      } 

    }

 

    /* 检查上传的文件是否是合法的类型 */

    private function checkFileType() {

      if (in_array(strtolower($this->fileType), $this->allowtype)) {

        return true

      }else {

        $this->setOption('errorNum', -1)

        return false

      }

    }

 

    /* 检查上传的文件是否是允许的大小 */

    private function checkFileSize() {

      if ($this->fileSize > $this->maxsize) {

        $this->setOption('errorNum', -2)

        return false

      }else{

        return true

      }

    }

 

    /* 检查是否有存放上传文件的目录 */

    private function checkFilePath() {

      if(empty($this->path)){

        $this->setOption('errorNum', -5)

        return false

      }

      if (!file_exists($this->path) || !is_writable($this->path)) {

        if (!@mkdir($this->path, 0755)) {

          $this->setOption('errorNum', -4)

          return false

        }

      }

      return true

    }

 

    /* 设置随机文件名 */

    private function proRandName() {    

      $fileName = date('YmdHis')."_".rand(100,999)    

      return $fileName.'.'.$this->fileType 

    }

 

    /* 复制上传文件到指定的位置 */

    private function copyFile() {

      if(!$this->errorNum) {

        $path = rtrim($this->path, '/').'/'

        $path .= $this->newFileName

        if (@move_uploaded_file($this->tmpFileName, $path)) {

          return true

        }else{

          $this->setOption('errorNum', -3)

          return false

        }

      } else {

        return false

      }

    }

  }


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12212297.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存