有两个类,一个是NutUpFile类,用于保存将要上传的文件的相关信息;一个NutUploader类,用于控制NutUpFile对象,相当于运输器。这两个类都没有完善,只是希望大家能共同学习,并给我一些意见,支持其中的一些不足。本人现在已经发现一些问题在其中,大家讨论讨论。<?php
require_once('NutUpFile.class.php');
//???????????????????????????
/**
 * 还有很多需要改善的地方。
 * 1.考虑那些方法是类方法,那些是公用方法
 * 2.优化算法
 * 3.去掉冗余的数据和方法
 * 4.这个类是否设计正确,有没有做自己范围外的事情
 */
//???????????????????????????
/**
 * 说明:NutUploader是NutUpFile上传文件对象的运输器。
 *  根据传入的NutUpFile对象的相关信息,检测NutUpFile的内容并把对象保存到对应的位置。
 * @author Nutshell
 * @version 1.0
 * @since 2007-9-30 14:51:00
 */class NutUploader{
private $savePath = './'; //保存文件的路径 ??这个是否需要
private $extFilter = 'jpg,jpeg,bmp,gif,png'; //允许上传的文件扩展名,字符串形式:"jpg,bmp,gif,png"
private $maxSize = 512000; //允许上传的文件大小上限; 0代表无限制。
private $overwrite = 0; //覆盖模式;如果同名文件存在,是否覆盖,0代表不行,1代表可以。
private $errno = 0; //错误代号
private $canUpload = true; //是否可以上传,默认可以上传 //以下数组都是关联数组,key值就是对应的NutUpFile对象的上传时间(uploadTime)
private $arrSuccessfulFiles = array(); //上传成功的文件列表
private $arrFailedFiles = array(); //上传失败的文件列表
private $arrReadyUploadFiles = array(); //待上传的文件列表 /**
 * NutUploader的构造函数;
 * 初始化NutUploader的一个对象,用于操作上传文件NutUpFile对象;
 * 
 * @param extFilter 文件格式限制, 默认是'jpg,jpeg,png,bmp,gif'
 * @param maxSize 文件大小最大值限制,默认51200 Byte(即500KB)  
 * @param savePath 文件保存的路径。
 */
function __construct($extFilter = "jpg,jpeg,png,gif", $maxSize = 512000, $savePath = './') {
$this->setSavePath($savePath);
$this->setExtFilter($extFilter);
$this->setMaxSize($maxSize);
$this->setOverwrite(0);
$this->errno = 0;
} /**
 * 上传全部待上传的文件
 *
 * @param NutUpFile $o_NutUpFile NutUpFile对象。默认是空值,代表上传待上传列表里面的所有NutUpFile对象
 */
public function uploadAll($o_NutUpFile = '') {
if ($o_NutUpFile ='') {
//上传所有待上传的文件
foreach ($this->arrReadyUploadFiles as $uFile) {
$this->upload($uFile);
}
} else {
//上传单个文件
$this->upload($o_NutUpFile);
} $this->saveFile();
} /**
 * 上传单个文件
 *
 * @param NutUpFile $o_NutUpFile 待上传的文件
 */
public function upload($o_NutUpFile) {
if ( is_a($o_NutUpFile, 'NutUpFile') ) {
if ( $this->validateAll($o_NutUpFile) ) {
saveFile($o_NutUpFile);
} else {
$this->pushToFail($o_NutUpFile);
}
}
} //??这个是否应该设为类方法
/**
 * 保存上传的文件;
 * 执行检测文件,移动文件等相关动作。
 *
 */
protected function saveFile($o_NutUpFile) {
$tmpName = $o_NutUpFile->getTmpName();
$saveName = $o_NutUpFile->getSavePath().$o_NutUpFile->getFullName(); if ( !is_uploaded_file($tmpName) ) {
$o_NutUpFile->setErrno(6);
return false;
} if ( !move_uploaded_file($tmpName, $saveName) ) {
$o_NutUpFile->setErrno(7);
return true;
} $this->addFile($this->arrSuccessfulFiles, $o_NutUpFile);
$this->delFile($this->arrReadyUploadFiles, $o_NutUpFile); $o_NutUpFile->setErrno(0);
return true;
} /**
 * 为待上传文件列表添加NutUpFile对象
 *
 * @param NutUpFile $o_NutUpFile 待上传的NutUpFile对象
 */
public function addFile($toArr, $o_NutUpFile) {
if ( is_a($o_NutUpFile, 'NutUpFile') ) {
$key = $o_NutUpFile->getUploadTime();
$toArr[$key] = $o_NutUpFile;
}
} /**
 * 从带上传文件列表数组中删除NutUpFile对象
 *
 * @param NutUpFile $o_NutUpFile 要删除的NutUpFile对象
 */
public function delFile($fromArr, $o_NutUpFile) {
$key = $o_NutUpFile->getUploadTime();
unset($fromArr[$key]);
} /**
 * 把NutUpFile对象加到arrSuccessfulFiles数组中
 *
 * @param NutUpFile $o_succFile 上传成功的NutUpFile对象
 */
protected function pushToSuccess($o_succFile) {
addFile($this->arrSuccessfulFiles, $o_succFile);
delFile($this->arrReadyUploadFiles, $o_succFile);
} /**
 * 把NutUpFile对象加到arrFailedFiles数组中
 *
 * @param NutUpFile $o_failFile 上传失败的NutUpFile对象
 */
protected function pushToFail($o_failFile) {
addFile($this->arrFailedFiles, $o_failFile);
delFile($this->arrReadyUploadFiles, $o_succFile);
} /**
 * 检测全部需要检测的内容,包括扩展名范围、大小限制、保存的路径是否可写、同名文件是否可以覆盖。
 *
 * @param NutUpFile $o_NutUpFile 待检测的NutUpFile上传文件对象
 * @return 如果通过检测,返回true, 否则返回false
 */
protected function validateAll($o_NutUpFile) {
if ( $this->validateExt($o_NutUpFile)
&& $this->validateSize($o_NutUpFile)
&& $this->validateWritable($o_NutUpFile)
&& $this->validateOverwrite($o_NutUpFile)
&& $this->validateIsUploadedFile($o_NutUpFile)
&& $this->validateCanMove($o_NutUpFile) ) {
return true;
}
return false;
} /**
 * 检测传入的NutUpFile对象的扩展名,查看是否超出扩展名限制的范围
 *
 * @param NutUpFile $o_NutUpFile NutUpFile文件对象
 * @return 如果没有超出返回true, 否则返回false
 */
protected function validateExt($o_NutUpFile) {
$ext = $o_NutUpFile->getExt(); if (in_array($ext, $this->extFilter)) {
$o_NutUpFile->setErrno(1);
return true;
} else {
return false;
}
} /**
 * 检测传入的NutUpFile对象的大小是否超过上传文件大小的限制范围
 *
 * @param NutUpFIle $o_NutUpFile
 * @return 如果没有超过上传文件大小的限制范围,返回true,否则返回false
 */
protected function validateSize($o_NutUpFile) {
$size = $o_NutUpFile->getSize(); if ($size > $this->maxSize) {
$o_NutUpFile->setErrno(2);
return false;
} $size = $o_NutUpFile->getSize('m');
if ($size > ini_get('post_max_size')) {
$o_NutUpFile->setErrno(3);
return false;
} return true;
}

解决方案 »

  1.   


    /**
     * 检测传入的对象是否可以覆盖在此对象将要保存的路径中的同名文件
     *
     * @param NutUpFile $o_NutUpFile NutUpFile上传文件对象
     * @return 如果NutUploader对象运行在不能覆盖模式,且将要保存文件的路径中存在同名文件返回false,否则返回true
     */
    protected function validateOverwrite($o_NutUpFile) {
    $fullName = $o_NutUpFile->getSavePath.$o_NutUpFile->getFullName;
    if ( $this->overwrite == 0 && @file_exists($fullName) ) {
    $o_NutUpFile->setErrno(4);
    return false;
    } return true;
    } /**
     * 检测传入的NutUpFile对象将要保存的路径是否可以写入
     *
     * @param NutUpFile $o_NutUpFile 待检测的NutUpFile对象
     * @return 如果传入的NutUpFile对象将要保存的路径可以写入,返回true,否则返回false
     */
    protected function validateWritable($o_NutUpFile) {
    $savePath = $o_NutUpFile->getSavePath(); if ( !is_writable($savePath) ) {
    $o_NutUpFile->setErrno(5);
    return false;
    } return true;
    }

    /**
     * 检测文件是否通过表单上传得到的
     *
     * @param NutUpFile $o_NutUpFile 待检测的NutUpFile对象
     * @return 如果是表单上传的返回true, 否则返回false
     */
    protected function validateIsUploadedFile($o_NutUpFile) {
    $tmpName = $o_NutUpFile->getTmpName();
    if ( !is_uploaded_file($tmpName) ) {
    $o_NutUpFile->setErrno(6);
    return false;
    } return true;
    }

    /**
     * 检测临时文件是否可以移动到保存的路径
     *
     * @param NutUpFile $o_NutUpFile 待检测的NutUpFile对象
     * @return 如果可以移动到保存的路径返回true, 否则返回false
     */
    protected function validateCanMove($o_NutUpFile) {
    $tmpName = $o_NutUpFile->getTmpName();
    $saveName = $o_NutUpFile->getSavePath().$o_NutUpFile->getFullName(); if ( !move_uploaded_file($tmpName, $saveName) ) {
    $o_NutUpFile->setErrno(7);
    return false;
    } return  true;
    } /**
     * 设置文件保存的路径
     *
     * @param String $savePath 文件的保存路径
     */
    public function setSavePath($savePath) {
    $savePath = str_replace('\\', '/', $savePath);
    //!!下面的处理是不全面的
    substr($savePath, -1) == '/' ? $savePath : $savePath.'/';
    $this->savePath = $savePath;
    } /**
     * 获取文件保存的路径
     *
     * @return 文件保存的路径
     */
    public function getSavePath() {
    return $this->savePath;
    } /**
     * 设置上传文件允许的扩展名范围
     * 格式为:"jpg,bmp,png"
     *
     * @param String $extFilter 允许的上传文件扩展名范围
     */
    public function setExtFilter($extFilter) {
    echo $extFilter;
    $this->extFilter = explode(',', $extFilter);
    } /**
     * 获取可上传文件的扩展名
     * 格式为:"jpg,bmp,png"
     *
     * @return 文件的扩展名
     */
    public function getExtFilter() {
    return implode(',', $this->extFilter);
    } /**
     * 设置可上传文件的大小上限
     *
     * @param Interger $maxSize 文件最大值(byte)
     */
    public function setMaxSize($maxSize) {
    $this->maxSize = $maxSize;
    } /**
     * 获取可上传文件的大小上限(byte)
     *
     * @return 可上传文件的上限
     */
    public function getMaxSize() {
    return $this->maxSize;
    } /**
     * 设置覆盖模式
     *
     * @param Integer $num 0:不能覆盖; 1:允许覆盖。
     */
    public function setOverwrite($overwrite) {
    $this->overwrite = $overwrite;
    } /**
     * 开启上传功能
     *
     */
    public function canUpload() {
    $this->canUpload = true;
    } /**
     * 关闭上传功能能,关闭后不能上传任何文件
     *
     */
    public function disableUpload() {
    $this->canUpload = false;
    } /**
     * 获取待上传的NutUpFile对象数组
     *
     * @return 待上传的NutUpFile对象数组
     */
    public function getReadyFiles() {
    return $this->arrReadyUploadFiles;
    } /**
     * 获取上传失败的NutUpFile对象数组
     *
     * @return 上传失败的NutUpFile对象数组
     */
    public function getFailedFiles() {
    return $this->arrFailedFiles;
    } /**
     * 获取上传成功的NutUpFile对象数组
     *
     * @return 上传成功的NutUpFile对象数组
     */
    public function getSuccessfulFiles() {
    return $this->arrSuccessfulFiles;
    }}
      

  2.   

    <?php
    /**
     * 上传文件类。
     * 不是用于上传文件的类,而是用于保存上传文件相关信息的类。
     * 
     * @author Nutshell
     * @version 1.0
     * @since 2007-9-30
     * @example $upFile = new NutUpFile('ufile');
     *  $upFile = new NutUpFile('ufile', 'file23', 'userfiles/');
     */class NutUpFile{
    private $saveName = ''; //文件保存的名称(不包括扩展名)
    private $ext; //文件扩展名
    private $fullName; //文件保存后的全名——包括扩展名($saveName + $ext)
    private $originalName; //文件的原名——包括扩展名
    private $savePath = './'; //文件保持的路径
    private $size; //文件大小,默认单位是Byte
    private $type; //文件类型
    private $uploadTime; //文件上传时间
    private $inputName; //提交这个文件的Input元素的名称(name属性)
    private $tmpName; //上传文件的临时名称(包括路径)
    private $errno = 00; //状态代号, 0:上传成功; 00:上传排队中。
    private static $error = array(
       00 => '上传排队中...',
    0 => '上传成功。',
    1 => '文件格式不符合。',
    2 => '文件大小超出Uploder对象的限制。',
    3 => '文件大小超出PHP.ini配置文件的限制',
    4 => '同名文件存在,且不能覆盖。',
    5 => '保存路径不可写。',
    6 => '不是通过上传表单上传的文件。',
    7 => '不能移动临时文件。',
    8 => '',
    9 => '',
    10 => '',
    );

    /**
     * 构造函数。创建一个上传文件的对象,里面包含被上传文件的主要信息。
     *
     * @param String $inputName 提交上传文件的Input元素的名称(name属性)
     * @param String $saveName 文件保存的名称(不包括扩展名)
     * @param String $savePath 文件保存的路径
     */
    public function __construct($inputName, $saveName='', $savePath='./') {
    $uploadFile = $_FILES['ufile']; $this->inputName = trim($inputName);
    $this->tmpName = $uploadFile['tmp_name'];
    $this->originalName = $uploadFile['name'];
    $this->type = $uploadFile['type'];
    $this->size = $uploadFile['size']; $this->setExt();
    $this->setSaveName($saveName);
    $this->setFullName(); //这个方法显得有点多余,可以让用户自己计算。
    $this->setSavePath($savePath);
    $this->setUploadTime();
    }

    /**
     * 设置文件保存的名称
     *
     * @param String $saveName 文件保存的名称(不包括扩展名)。
     *  默认以当前时间加一个随机数作为名称。
     */
    public function setSaveName($saveName='') {
    //!!这里添加文件名字符检测过滤
    $saveName = trim($saveName);

    if ($saveName == '') {
    $saveName = date('YmdHis').'_'.rand(100,999);
    }
    $this->saveName = $saveName;

    if ($saveName != '') {
    $this->setFullName();
    }
    } /**
     * 获取文件保存的名称(不包括扩展名)
     *
     * @return 文件保存的名称
     */
    public function getSaveName() {
    return $this->saveName;
    }

    /**
     * 设置文件扩展名
     *
     */
    protected function setExt() {
    $pieces = explode('.', $this->originalName);
    $ext = $pieces[count($pieces)-1];
    $this->ext = $ext;
    }

    /**
     * 获取文件扩展名
     *
     * @return 文件扩展名
     */
    public function getExt() {
    return $this->ext;
    }

    //!!这个方法有点多余
    /**
     * 设置文件的全名(包括扩展名)
     *
     */
    protected function setFullName() {
    $this->fullName = $this->saveName.'.'.$this->ext;
    }

    /**
     * 获取文件的全名(包括扩展名)
     *
     * @return 文件的全名
     */
    public function getFullName() {
    return $this->fullName;
    }

    /**
     * 获取文件的原名称
     *
     * @return 文件的原名称
     */
    public function getOriginalName() {
    return $this->originalName;
    }
      

  3.   


    /**
     * 设置文件的保存路径
     *
     * @param String $savePath 文件的保存路径
     */
    public function setSavePath($savePath='./') {
    //!!下面的处理是不全面的
    $savePath = str_replace('\\', '/', $savePath);
    substr($savePath, -1) == '/' ? $savePath : $savePath.'/'; 
    $this->savePath = $savePath;
    }

    /**
     * 获取文件的保存路径
     *
     * @return 文件保存路径
     */
    public function getSavePath() {
    return $this->savePath;
    }

    /**
     * 获取文件的大小
     * 
     * @param 大小单位,不区分大小写。b:Byte, k:KB, m:M, g:G。
     * @return 文件的大小
     */
    public function getSize($unit = 'b') {
    $unit = strtolower(trim($unit));
    $size = $this->size;

    switch ($unit) {
    //不用break就出现连除的效果
    case 'g':
    $size = $size/1024;

    case 'm':
    $size = $size/1024;
    break;

    case 'k':
    $size = $size/1024;
    }

    return $size;
    }

    /**
     * 获取文件的MIME类型
     *
     * @return 文件的MIME类型
     */
    public function getType() {
    return $this->type;
    }

    /**
     * 设置文件的上传时间
     *
     */
    protected function setUploadTime() {
    $this->uploadTime = date('Y-m-d H:i:s');
    }

    /**
     * 获取文件的上传时间
     *
     * @return 文件的上传时间
     */
    public function getUploadTime() {
    return $this->uploadTime;
    }

    /**
     * 获取上传文件的Input的元素的name属性
     *
     * @return 上传文件的Input元素的name属性
     */
    public function getInputName() {
    return $this->inputName;
    }

    /**
     * 获取上传文件的临时名称(包括路径)
     *
     * @return 上传文件的临时名称(包括路径)
     */
    public function getTmpName() {
    return $this->tmpName;
    }

    //??由外界设置错误代号,很有危险。
    //??但是我想NutUploader来设置错误信息啊,不使用public还有什么办法?
    /**
     * 设置文件的状态信息代号
     *
     * @param Integer $no 状态代号
     */
    public function setErrno($no) {
    $this->errno = $no;
    }

    public function getErrno() {
    return $this->errno;
    }

    public function getError() {
    $str = self::$error[$this->getErrno()];
    return $str;
    }
    }
      

  4.   

    太长了,没有耐心,,这是php版吗?我跑错地方拉