[PHP从小白到大牛]-020 PHP文件函数封装

622 阅读7分钟

函数封装

文件操作相关

创建文件

/**
 * create_file, 根据文件路径, 创建文件
 *
 * @param  string $filename 文件路径
 *
 * @return boolean true表示创建成功, false表示创建失败
 */
function create_file(string $filename) {
    // 判断文件名是否存在
    if (file_exists($filename)) {
        // 如果存在, 则返回false
        return false;
    }
    // 判断路径是否存在, 如果不存在, 则创建
    if (!file_exists(dirname($filename))) {
        // 如果不存在文件夹, 则创建, 权限给777, 递归创建, 就是如果有多级, 就创建多个文件夹, 比如"hello/world"
        mkdir(dirname($filename), 0777, true);
    }
    // 往文件里写数据, 判断是否可写, 如果不可写, 会返回false
    if (file_put_contents($filename, '') !== false) {
        return true;
    }
    // 最后给一个返回值, 否则没有返回值的函数, 会返回null, 尽量做到, 每个函数都有返回值
    return false;
}

删除文件

/**
 * del_file 根据文件路径, 删除文件
 *
 * @param  string $filename 文件路径
 *
 * @return boolean true表示创建成功, false表示创建失败
 */
function del_file(string $filename) {
    // 先判断以下, 如果文件不存在, 或者文件不可写, 都返回false, 之所以先判断是否可写, 因为如果有写保护, 文件会删不掉
    if (!file_exists($filename) || !is_writable($filename)) {
        // 返回false
        return false;
    }
    // 如果删除成功, 返回true
    if (unlink($filename)) {
        // 返回成功
        return true;
    }
    // 如果走到这一步了, 说明之前没有删除成功, 返回false
    return false;
}

复制文件

/**
 * copy_file 复制文件到新的路径
 *
 * @param  string $filename 文件路径
 * @param  string $dest 新的目录路径
 *
 * @return boolean true表示创建成功, false表示创建失败
 */
function copy_file(string $filename, string $dest) {
    // 如果第二个参数不是目录, 递归创建
    if (!is_dir($dest)) {
        // 权限777, 最高权限, 递归创建
        mkdir($dest, 0777, true);
    }
    // DIRECTORY_SEPARATOR, 系统常量, 表示系统分隔符, 
    // 因为每个操作系统的分隔符都不一样, 所以写成常量, 可以做到跨平台/操作系统
    // $destName为新的文件路径
    $destName = $dest . DIRECTORY_SEPARATOR . basename($filename);
    // 如果文件已经存在, 则返回false, 不让复制
    if (file_exists($destName)) {
        // 返回false
        return false;
    }
    // 如果复制成功, 返回true
    if (copy($filename, $destName)) {
        // 返回true, 表示成功
        return true;
    }
    // 如果走到这一步, 说明之前的系统函数copy()没有成功, 返回false
    return false;
}

重命名文件

/**
 * rename_file 重命名文件
 *
 * @param  string $oldName 文件路径
 * @param  string $newName 新的文件的名字, 只要名字即可, 因为是同一个路径
 *
 * @return boolean true表示创建成功, false表示创建失败
 */
function rename_file(string $oldName, string $newName) {
    // 重命名之前, 先判断参数一是不是文件, 不是文件则不能重命名, 因为只有文件可以重命名
    if (!is_file($oldName)) {
        // 返回false
        return false;
    }
    // 获取参数一的路径
    $path = dirname($oldName);
    // 拼接出新文件的路径
    $destName = $path . DIRECTORY_SEPARATOR . $newName;
    // 重命名之前, 先判断有没有重名函数
    if (is_file($destName)) {
        // 如果已经存在同名文件, 返回false
        return false;
    }
    // 使用系统函数rename, 来重命名文件
    if (rename($oldName, $newName)) {
        // 如果成功, 返回true
        return true;
    }
    // 如果走到这一步, 说明系统函数rename()没有执行成功, 返回false
    return false;
}

剪切文件

/**
 * cut_file 剪切文件
 *
 * @param  string $filename 文件路径
 * @param  string $dest 剪切到的目录路径
 *
 * @return boolean true表示创建成功, false表示创建失败
 */
function cut_file(string $filename, string $dest) {
    // 剪切文件之前, 需要判断是不是文件, 如果不是文件, 返回false
    if (!is_file($filename)) {
        // 如果不是文件, 返回false
        return false;
    }
    // 判断路径是否存在, 如果不存在, 则创建
    if (!is_dir($dest)) {
        // 递归创建路径, 给与最高权限, 777
        mkdir($dest, 0777, true);
    }
    // 拼接文件路径
    $destName = $dest . DIRECTORY_SEPARATOR . basename($filename);
    // 如果存在重名文件, 则不能剪切
    if (is_file($destName)) {
        // 返回false
        return false;
    }
    // 使用系统函数rename, 来实现剪切功能
    if (rename($filename, $destName)) {
        // 成功返回true
        return true;
    }
    // 如果走到这一步, 说明系统函数rename(), 没有执行成功, 返回false
    return false;
}

文件信息相关

返回文件信息

/**
 * get_file_info 获取文件信息, 返回的是一个关联数组
 *
 * @param  string $filename 文件路径
 *
 * @return array 返回包括文件信息的关联数组
 * @return array['atime'] 访问时间
 * @return array['mtime'] 修改时间
 * @return array['ctime'] 创建时间
 * @return array['size'] 文件大小, 调用trans_byte函数进行转换
 * @return array['type'] 返回文件类型, 调用系统函数filetype
 */
function get_file_info(string $filename) {
    // 获取文件信息的前提: 可以找到这个文件, 并且该文件可读
    if (!is_file($filename) || !is_readable($filename)) {
        // 如果找不到文件或者不可读, 返回false
        return false;
    }
    // 返回一个数组, 时间格式为 年-月-日 时:分:秒
    return [
        // 访问时间
        'atime' => date("Y-m-d H:i:s", fileatime($filename)),
        // 修改时间
        'mtime' => date("Y-m-d H:i:s", filemtime($filename)),
        // 创建时间
        'ctime' => date("Y-m-d H:i:s", filectime($filename)),
        // 文件大小, 调用trans_byte函数进行转换
        'size' => trans_byte(filesize($filename)),
        // 返回文件类型, 调用系统函数filetype
        'type' => filetype($filename),
    ];
}

字节单位转换的函数

/**
 * trans_byte 文件大小的单位转换
 *
 * @param  int $byte 总的字节数
 * @param  int $precision 四舍五入时, 保留的小数点位数, 默认两位
 *
 * @return string 带上单位的文件大小
 */
function trans_byte(int $byte, int $precision = 2) {
    // 定义一些变量, 用来描述单位之间的换算关系
    $kb = 1024;
    // 1mb = 1024kb
    $mb = 1024 * $kb;
    // 1gb = 1024mb
    $gb = 1024 * $mb;
    // 1tb = 1024gb
    $tb = 1024 * $gb;

    // 进行单位转换
    if ($byte < $kb) { // 如果不足1kb, 单位为b
        // 返回字节数
        return $byte . 'B';
    } elseif ($byte < $mb) { // 如果不够1mb, 返回kb数
        // 四舍五入, 保留两位
        return round($byte / $kb, $precision) . 'KB';
    } elseif ($byte < $gb) { // 如果不够1gb, 返回mb数
        // 四舍五入, 保留两位
        return round($byte / $mb, $precision) . 'MB';
    } elseif ($byte < $tb) { // 如果不够1tb, 返回gb数
        // 四舍五入, 保留两位
        return round($byte / $gb, $precision) . 'GB';
    } else { // 最后不管多大, 返回都是TB数
        // 四舍五入, 保留两位
        return round($byte / $tb, $precision) . 'TB';
    }
}

读取文件内容,返回字符串

/**
 * read_file 根据文件路径, 获取/读取文件的内容
 *
 * @param  string $filename 文件路径
 *
 * @return string 文件的内容
 */
function read_file(string $filename) {
    // 读取文件信息的前提, 是文件能找到, 并且可读
    if (is_file($filename) && is_readable($filename)) {
        // 如果能找到文件, 并且拥有读的权限, 则使用系统函数 file_get_contents()来获取文件信息, 并且返回
        return file_get_contents($filename);
    }
    // 如果走到这一步, 说明没能返回文件的内容, 那么返回false
    return false;
}

读取文件中的内容到数组中

/**
 * read_file_array 获取文件内容, 返回数组, 一行是一个元素
 *
 * @param  string $filename 文件路径
 * @param  boolean $skip_empty_lines 是否跳过空行, 默认false, 不跳过
 *
 * @return array 文件内容, 一行是一个元素
 */
function read_file_array(string $filename, bool $skip_empty_lines = false) {
    // 能够读取文件的前提: 存在文件, 并且该文件可读
    if (is_file($filename) && is_readable($filename)) {
        // 是否要跳过空行
        if ($skip_empty_lines) {
            // 如果跳过空行, 需要设置第二个参数, 需要同时设置两个
            // FILE_IGNORE_NEW_LINES 在数组每个元素的末尾不要添加换行符
            // FILE_SKIP_EMPTY_LINES 跳过空行
            // 必须同时设置, 不设置FILE_IGNORE_NEW_LINES的话, 只有一个换行符也会当成一行, 因为不是空行
            return file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        } else {
            // 如果不跳过空行, 直接调用系统函数file(), 来返回文件内容的数组
            return file($filename);
        }
    }
    // 如果走到这一步, 说明没能返回文件的内容, 那么返回false
    return false;
}

向文件中写入内容

/**
 * write_file 把变量写入文件中
 *
 * @param  string $filename 文件路径
 * @param  mixed $data 需要写入文件的变量, 数据类型不限
 *
 * @return boolean 操作结果, 如果成功返回true, 失败返回false
 */
function write_file(string $filename, $data) {
    // 获取文件的路径部分
    $dirname = dirname($filename);
    // 如果路径不存在, 则创建
    if (!file_exists($dirname)) {
        // 根据路径, 创建文件夹, 权限777, 递归创建
        mkdir($dirname, 0777, true);
    }
    // 判断是否为数组或者对象, 如果是, 需要序列化成字符串, 因为不能直接写
    if (is_array($data) || is_object($data)) {
        // 序列化数组或者对象
        $data = serialize($data);
    }
    // 如果能成功写入, 返回true
    if (file_put_contents($filename, $data) !== false) {
        // 代表能够写入
        return true;
    } else { 
        // 否则返回false
        return false;
    }
}

向文件中写入内容,之前内容不清空

/**
 * write_file1 写入文件, 可以选择是否保留原来的内容
 *
 * @param  string $filename 文件路径
 * @param  mixed $data 要写入的变量, 数据类型不限
 * @param  bool $clearFlag 是否清除内容, true为清除, false为不清除(保留内容)
 *
 * @return boolean 操作结果, 如果成功返回true, 失败返回false
 */
function write_file1(string $filename, $data, bool $clearFlag = false) {
    // 获取文件路径的目录部分
    $dirname = dirname($filename);
    // 如果目录不存在, 则创建
    if (!file_exists($dirname)) {
        // 权限777, 递归创建目录
        mkdir($dirname, 0777, true);
    }
    // 如果文件存在, 并且可读, 就读取数据
    if (is_file($filename) && is_readable($filename)) {
        // 获取文件中的内容
        $srcData = file_get_contents($filename);
    }else{
        // 否则内容为空字符串
        $srcData = "";
    }
    // 如果变量是数组或者是对象, 则需要序列化, 不然写不到文件里去
    if (is_array($data) || is_object($data)) {
        // 序列换数组或者对象
        $data = serialize($data);
    }
    // 如果不清除文件, 则采用拼接的方式
    if(!$clearFlag){
        // 把内容拼接到文件的最后, 类似于append
        $data = $srcData . $data;
    }
    // 如果写入成功, 返回true, 否则返回false
    if (file_put_contents($filename, $data) !== false) {
        return true; // 成功
    } else {
        return false; // 失败
    }
}

截断文件到指定大小

/**
 * truncate_file 将文件截断到给定的长度
 *
 * @param  string $filename 文件路径
 * @param  int $length 截取长度, 可以是负数, 为变成0
 *
 * @return bool 操作结果, 如果成功返回true, 失败返回false
 */
function truncate_file(string $filename, int $length) {
    // 如果是文件并且可写, 则进行操作, 否则返回false
    if (is_file($filename) && is_writable($filename)) {
        // 使用fopen获取文件句柄
        $handle = fopen($filename, 'r+');
        // 判断截断的长度, 如果为负数, 则改成0
        $length = $length < 0 ? 0 : $length;
        // 使用系统函数ftruncate进行截断
        ftruncate($handle, $length);
        // 关闭文件
        fclose($handle);
        // 返回成功
        return true;
    }
    // 如果走到这一步, 说明操作失败, 返回false
    return false;
}

下载文件

function down_file(string $filename, array $allowDownExt = array('jpeg', 'jpg', 'png', 'gif', 'txt', 'html', 'php', 'rar', 'zip')) {
    if (!is_file($filename) || !is_readable($filename)) {
        return false;
    }
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    if (!in_array($ext, $allowDownExt)) {
        return false;
    }
    header('Content-Type:application/octet-stream');
    header('Accept-Ranges: bytes');
    header('Accept-Length: ' . filesize($filename));
    header('Content-Disposition: attachment;filename=king_' . basename($filename));
    readfile($filename);
    exit;
}

下载文件

/**
 * down_file 根据文件路径, 下载文件
 * 
 * @param  string $filename     文件路径
 * @param  array  $allowDownExt 允许的后缀名
 * 
 * @return void               
 */
function down_file(string $filename, array $allowDownExt = array('jpeg', 'jpg', 'png', 'gif', 'txt', 'html', 'php', 'rar', 'zip')) {
    // 判断文件是否存在, 并且可读, 因为我们需要往里写数据
    if (!is_file($filename) || !is_readable($filename)) {
        // 不可读, 或者不存在, 则报错
        return false;
    }
    // 获取后缀名
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    // 如果后缀名不符合要求, 则返回false, 不让下载
    if (!in_array($ext, $allowDownExt)) {
        return false;
    }
    //通过header()发送头信息
    //告诉浏览器输出的是字节流
    header('Content-Type:application/octet-stream');
    //告诉浏览器返回的文件大小是按照字节进行计算的
    header('Accept-Ranges: bytes');
    // 获取文件大小
    $filesize = filesize($filename);
    //告诉浏览器返回的文件大小
    header('Accept-Length: ' . $filesize);
    //告诉浏览器文件作为附件处理,告诉浏览器最终下载完的文件名称
    header('Content-Disposition: attachment;filename=king_' . basename($filename));
    //读取文件中的内容
    //规定每次读取文件的字节数为1024字节,直接输出数据
    $read_buffer = 1024;
    // 获取文件句柄
    $handle = fopen($filename, 'rb');
    // 循环读取, 直到文件结束
    while (!feof($handle)) {
        echo "hello";
        // fread 系统函数, 文件句柄, 每次读取的大小
        echo fread($handle, $read_buffer);
    }
    // 关闭句柄
    fclose($handle);
    // 退出
    exit;
}

单文件上传

/**
 * upload_file 上传文件
 * @param  array        $fileInfo   文件信息
 * @param  string       $uploadPath 上传后, 文件保存的路径
 * @param  bool|boolean $imageFlag  是否检测为真实的图片
 * @param  array        $allowExt   允许的后缀
 * @param  int|integer  $maxSize    上传文件的最大值
 * @return string|bool  如果成功, 返回保存的文件路径, 如果失败返回false                   
 */
function upload_file(array $fileInfo, string $uploadPath = './uploads', bool $imageFlag = true, array $allowExt = array('jpeg', 'jpg', 'png', 'gif'), int $maxSize = 2097152) {


    // 定义常量, UPLOAD_ERRS, 上传错误信息, 是一个关联数组
    define('UPLOAD_ERRS', [
        'upload_max_filesize' => '超过了PHP配置文件中upload_max_filesize选项的值',
        'form_max_size' => '超过了表单MAX_FILE_SIZE选项的值',
        'upload_file_partial' => '文件部分被上传',
        'no_upload_file_select' => '没有选择上传文件',
        'upload_system_error' => '系统错误',
        'no_allow_ext' => '非法文件类型',
        'exceed_max_size' => '超出允许上传的最大值',
        'not_true_image' => '文件不是真实图片',
        'not_http_post' => '文件不是通过HTTP POST方式上传上来的',
        'move_error' => '文件移动失败',
    ]);
    // 上传成功没有错误的处理逻辑
    if ($fileInfo['error'] === 0) {
        // 获取文件后缀
        $ext = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
        // 判断后缀是否符合要求, 不符合, 输出信息"非法文件类型", 返回false
        if (!in_array($ext, $allowExt)) {
            echo UPLOAD_ERRS['no_allow_ext'];
            return false;
        }
        // 如果文件大小过大, 输出信息"超出允许上传的最大值", 返回false
        if ($fileInfo['size'] > $maxSize) {
            echo UPLOAD_ERRS['exceed_max_size'];
            return false;
        }
        // 如果需要检测图片是否为真是图片
        if ($imageFlag) {
            // 判断一下, 如果不是图片, 输出信息"文件不是真实图片", 返回false
            // getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组
            if (@!getimagesize($fileInfo['tmp_name'])) {
                echo UPLOAD_ERRS['not_true_image'];
                return false;
            }
        }
        // 如果文件不是走的http post, 输出信息"文件不是通过HTTP POST方式上传上来的", 返回false
        // is_uploaded_file() 函数检查指定的文件是否是通过 HTTP POST 上传的
        if (!is_uploaded_file($fileInfo['tmp_name'])) {
            return UPLOAD_ERRS['not_http_post'];
        }


        // 开始保存
        // 上传文件的保存路径是否存在, 如果不存在, 则递归创建
        if (!is_dir($uploadPath)) {
            mkdir($uploadPath, 0777, true);
        }
        // 给文件起一个名字, 目的是为了排重
        // microtime(true) 秒级时间戳.毫米级时间戳
        // uniqid生成唯一id, 使用microtime作为前缀
        // md5加密, 生成32位字符串
        $uniName = md5(uniqid(microtime(true), true)) . '.' . $ext;
        // 生成需要保存的完整文件名
        $dest = $uploadPath . DIRECTORY_SEPARATOR . $uniName;
        // move_uploaded_file 函数将上传的文件移动到新位置
        if (@!move_uploaded_file($fileInfo['tmp_name'], $dest)) {
            // 如果失败, 输出"文件移动失败""
            echo UPLOAD_ERRS['move_error'];
            return false;
        }
        // 如果没有问题, 输出 文件上传成功
        echo '文件上传成功';
        // 返回上传完以后的文件路径
        return $dest;
    } else {
        // 判断具体上传失败时的错误, 返回中文信息
        switch ($fileInfo['error']) {
        case 1:
            $mes = UPLOAD_ERRS['upload_max_filesize']; // 超过了PHP配置文件中upload_max_filesize选项的值
            break;
        case 2:
            $mes = UPLOAD_ERRS['form_max_size']; // 超过了表单MAX_FILE_SIZE选项的值
            break;
        case 3:
            $mes = UPLAOD_ERRS['upload_file_partial']; // 文件部分被上传
            break;
        case 4:
            $mes = UPLOAD_ERRS['no_upload_file_select']; // 没有选择上传文件
            break;
        case 6:
        case 7:
        case 8:
            $mes = UPLAOD_ERRS['upload_system_error']; // 系统错误
            break;
        } 
        // 错误信息
        echo $mes;
        // 返回false
        return false;
    }
}

压缩单个文件

/**
 * zip_file 压缩单个文件
 * 
 * @param  string $filename 文件路径
 * 
 * @return bool   true表示压缩成功, false表示压缩失败
 */
function zip_file(string $filename) {
	// 判断文件是否存在, 没有则返回false
    if (!is_file($filename)) {
        return false;
    }
    // 实例化一个ZipArchive对象
    $zip = new ZipArchive();
    // 设置压缩文件的文件名, 原文件后面加zip, 类似于: hello.txt ==> hello.txt.zip
    $zipName = basename($filename) . '.zip';
    // 打开一个压缩文件, 开始往里写内容, 如果没有就创建, 如果有就覆盖
    if ($zip->open($zipName, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
    	// 往压缩包里添加文件, 把结果赋值给一个变量
    	$result = $zip->addFile($filename);
        // 关闭压缩包
        $zip->close();
        // 如果变量为true, 说明添加成功, 删除原文件
        if ($result) {
        	// 删除原文件
            unlink($filename);
        }
        // 返回成功
        return true;
    } else {
    	// 返回失败
        return false;
    }
}

多文件压缩

/**
 * zip_files 多文件压缩
 * 
 * @param  string $zipName 自定义压缩文件名
 * @param  mixed $files   需要压缩的文件路径, 个数不限
 * 
 * @return bool          成功返回true, 失败返回false
 */
function zip_files(string $zipName, ...$files) {
	// 获取后缀名
    $zipExt = strtolower(pathinfo($zipName, PATHINFO_EXTENSION));
    // 如果后缀名不是zip, 返回false
    if ('zip' !== $zipExt) {
        return false;
    }
    // 实例化ZipArchive()对象
    $zip = new ZipArchive();
    // 打开一个压缩文件, 开始往里写内容, 如果没有就创建, 如果有就覆盖
    if ($zip->open($zipName, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
    	// 遍历文件, 要压缩的文件的路径
        foreach ($files as $file) {
        	// 判断是否可以找到文件
            if (is_file($file)) {
            	// 如果没有问题, 添加到压缩文件里
                $zip->addFile($file);
            }
        }
        // 关闭压缩文件
        $zip->close();
        // 返回 true
        return true;
    } else {
    	// 返回 false
        return false;
    }
}

解压缩

/**
 * unzip_file 解压缩文件到指定路径
 * 
 * @param  string $zipName 压缩包的文件路径
 * @param  string $dest    解压缩到指定路径
 * 
 * @return bool          成功返回true, 失败返回false
 */
function unzip_file(string $zipName, string $dest) {
	// 判断能否找到压缩文件, 如果找不到, 返回false
    if (!is_file($zipName)) {
        return false;
    }
    // 判断解压路径是否存在, 没有则创建
    if (!is_dir($dest)) {
        mkdir($dest, 0777, true);
    }
    // 实例化ZipArchive对象
    $zip = new ZipArchive();
    // 打开压缩文件, 解压到指定路径
    if ($zip->open($zipName)) {
    	// 解压到路径
        $zip->extractTo($dest);
        // 关闭压缩文件
        $zip->close();
        // 返回true
        return true;
    } else {
    	// 返回false
        return false;
    }
}

$_FILES详解

$_FILES参数详解:

  • $_FILES["file"]["name"]–被上传文件的名称
  • $_FILES["file"]["type"]–被上传文件的类型
  • $_FILES["file"]["size"]–被上传文件的大小, 以字节计
  • $_FILES["file"]["tmp_name"]–存储在服务器的文件的临时副本的名称
  • $_FILES["file"]["error"]–由文件上传导致的错误代码

$_FILES["file"]["error"]中的["error"]值情况

UPLOAD_ERR_OK

  • 0: 没有错误发生, 文件上传成功

UPLOAD_ERR_INI_SIZE

  • 1: 上传的文件超过了php.ini中upload_max_filesize(默认情况为2M)选项限制的值

UPLOAD_ERR_FORM_SIZE

  • 2: 上传文件的大小超过了HTML表单中MAX_FILE_SIZE选项指定的值

UPLOAD_ERR_PARTIAL

  • 3: 文件只有部分被上传

UPLOAD_ERR_NO_FILE

  • 4: 没有文件被上传
  • 5: 传文件大小为 0