php文件处理与文件上传
Posted cscsdvdsv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php文件处理与文件上传相关的知识,希望对你有一定的参考价值。
文件处理
序列化与反序列化
序列化:将一个变量代表的内存数转换为字符串形式,并持久保存到硬盘上
反序列化:将序列化后保存的字符串数据恢复
序列化:形式 $v1=123;
$s1=serialize($v1);
file_put_contents(‘要保存的目标文件’,$s1);
反序列化: 形式 $s1=file_get_contents(‘保存的文本’);
$v1=unserialize($s1);
__sleep()
:用于对象的序列化,只能将属性保存,方法会忽略,会自动调用这个方法,改方法必须返回一个数组,数组中是计划要进行序列化的属性名,返回的可以改 (要引用文件)
__wake up()
: 用于对象的序列化 (要引用文件)
序列化的做法:
$v1 = 123;
//这是一个变量,代表任意的内存数据
$s1 = serialize( $v1 );
//将任何类型的变量数据,转换为“字符串”
file_put_contents( ‘要保存的目标文本文件’, $s1);
//将该字符串,保存到一个文件里(就是硬盘数据)
反序列化的做法:
$s1=file_get_contents(‘保存序列化的目标文件’);
//从一个文件里读出其中的所有字符
$v1 = unserialize( $s1 );
//将该字符串数据,反序列化转换为变量(数据)
__sleep()
:用于对象的序列化
1,对一个对象进行序列化,只能将其属性数据“保存起来”,而方法被忽略(方法不是数据)
2,对象的序列化的时候,会自动调用该对象所属类的这个魔术方法:__sleep()(前提是有该方法)。且,此时,该方法必须返回一个数组,数组中是“计划”要进行序列化的属性名;
__wakeup()
:用于对象的反序列化
1,对一个对象进行反序列化,其实是恢复其原来保存起来的属性数据,而且,此时必然需要依赖该对象原本的所属类;
2,对象在反序列化的时候,会自动调用该对象所属类的这个魔术方法:__wakeup()
目录操作
创建目录
bool mkdir(string $pathname [,int $mode = 0777 [,bool $recursive=false] ] )
参数:$pathname
创建的目录名称 $mode
指定目录的权限
$mode
在windows系统上,权限设置无效
权限是一个八进制的值:0777
第1位表示所有者权限,第2位表示的所在组权限,第3位表示所有的人权限
每一位权限也是由三个值构成:1为可执行、2为可写、4为可读
举例:如“7”=1+2+4
举例:0644、04444、0755等。
提示:在windows下的只读权限为:0444
$recursive
递归创建,true表示即使上层目录不存在则会自动创建
返回值:创建成功返回true,失败返回false
提示:文件夹不能更换
判断是不是一个目录
bool is_dir(string $filename);
判断给定文件名是否是一个目录
判断目录或文件是否存在
bool file_exists(string $filename)
检查文件或目录是否存在
删除目录
bool rmdir(string $dirname);
目录必须是空才能删除
更改目录的访问权限
bool chmod (string $filename,int $mode)
改变文件模式
$filename
文件名称 $mode
八进制的权限值
取得文件夹访问权限
int fileperms(string $filename);
例如:$dir=”./image”;
$int=fileperms($dir);
//这返回的是十进制的权限值
$int= base_convert(int, 10, 8);
//将十进制转为8进制
echo substr($int,-4);
//8进制只要后四位,只取后四位
//也可以封装成一个函数
function getFileperms($fileName)
return substr(base_convert(fileperms($fileName),10,8),-4);
目录重命名或移动目录
bool rename (string $oldname,string $newname);
打开目录
resource opendir(string $path);
打开目录句柄,成功返回一个句柄(资源),失败false
读取目录中的条目
string readdir([resource $dir_handle]);
从目录句柄中读取条目
显示中文目录或文件
string iconv(string $in_charset, string $out_charset,string $str);
参数:$in_charset
,原字符编码;$out_charset
,转换后字符编码;$str
,要转换的字符串。
关闭目录
void closedir(resource $dir_handle);
关闭目录句柄
目录操作封装
<?php
header("content-type:text/html;charset=utf-8");
/**
* 遍历出一个文件夹下所有的文件和目录
*封装一个函数,可以统计出一个文件夹下面目录的数量和文件的数量。
*封装一个函数,可以删除目录
*/
//测试:遍历出一个文件夹下所有的文件和目录,数组
$filename="./xx";
$result=fileDirectory($filename);
dump($result);
//测试:遍历出一个文件夹下所有的文件和目录,输出
$result=readDirs($filename);
//测试:封装一个函数,可以统计出一个文件夹下面目录的数量和文件的数量。
$filename="./xx";
$result=getFileCount($filename);
dump($result);
//测试:封装一个函数,可以删除目录
$filename="./jj";
$result=del($filename);
dump($result);
/**
* 遍历出一个文件夹下所有的文件和目录
* @param $filename string 文件夹或文件的路径 $deep int 默认0 文件的递归深度
* @return $file_list arr 二维数组
*/
function fileDirectory($filename, $deep=0)
if(! file_exists($filename)) return false; //如果传递过来的路径不存在直接返回false
static $file_list = array(); //存储所有的文件信息,二维数组
$handle = opendir($filename);
while(false !== ($rec = readdir($handle)) )
if($rec == '.' || $rec == '..') continue; //目录下有.和..跳出循环
//当前的文件信息,存储到数组中,这个数组是二维数组中一个
$fileinfo['filename'] = $rec;
$fileinfo['deep'] = $deep;
$file_list[] = $fileinfo;
//判断当前读取到的是否为目录
if(is_dir($filename.'/'.$rec))
fileDirectory($filename.'/'.$rec,$deep+1);
//循环读取完毕后,关闭数据流
closedir($handle);
//返回读取的结果
return $file_list;
/**
* 遍历出一个文件夹下所有的文件和目录
* @param $filename string 文件夹或文件的路径 $deep int 默认0 文件的递归深度
*/
function readDirs($filename,$deep=0)
if(! file_exists($filename)) return false; //如果传递过来的路径不存在直接返回false
$handle = opendir($filename);
while(false !== ($rec = readdir($handle)) )
if($rec == '.' || $rec == '..') continue; //目录下有.和..跳出循环
$rec = iconv("gbk", "utf-8", $rec);
echo str_repeat(' ',$deep*4),$rec,'<br />';
//判断当前读取到的是否为目录
if(is_dir($filename.'/'.$rec))
readDirs($filename.'/'.$rec,$deep+1);
//循环读取完毕后,关闭数据流
closedir($handle);
/**
* 封装一个函数,可以统计出一个文件夹下面目录的数量和文件的数量。
* @param $filename string 文件夹或文件的路径
* @return arr 一维数组
*/
function countDirA($filename,&$dirNum=0,&$fileNum=0)
// 打开句柄
$handle = opendir($dir);
// 当文件名为0的时候,判断是否全等于false,不全等于false继续执行
while(false !== ($rec = readdir($handle)) )
// 过滤.和..
if($fileName == '.' || $fileName == '..') continue;
// 拼接完整路径
$newFile = "$dir/$fileName";
if(is_dir($newFile))
$dirNum++;
countDirA($newFile,$dirNum,$fileNum);
else
$fileNum++;
// 关闭句柄
closedir($handle);
return array($dirNum,$fileNum);
/**
* 封装一个函数,可以删除目录
* @param $filename string 文件夹或文件的路径
*/
function del($filename)
if(! file_exists($filename)) return false; //如果传递过来的路径不存在直接返回false
$handle = opendir($filename);
while(false !== ($rec=readdir($handle)))
if($rec == '.' || $rec == '..') continue; //目录下有.和..跳出循环
//开始删除,是目录递归
if(is_dir($filename.'/'.$rec))
del($filename.'/'.$rec);
else
unlink($filename.'/'.$rec);
//关闭数据流
closedir($handle);
//删除本身的空目录再把自己本身函数结束,返回上一层函数
return rmdir($filename);
/**
* @param $n 任意类型
* @return var_dump(参数) 打印出详细信息
*/
function dump($n=null)
echo "<hr />";
echo "<pre>";
var_dump($n);
echo "</pre>";
echo "<hr />";
文件操作
打开文件
resource fopen(string $filename,string $mode);
打开文件或URL
参数:$filename
要打开的文件名 $mode
文件打开方式
其中$mode
文件打开方式:
“r”只读方式打开,指针移到文件开头
“r+”读写方式打开
“w”写入方式打开,指针移到文件开头。如果文件不存在,会自动创建。清空写
“w+”读写方式打开
“a”追加方式打开,指针移到文件结尾。如果文件不存在,会自动创建。追加写
“a+”读写方式打开
“b”以二进制数据打开,为了安全起见,在打开方式后加上”b”参数。文便内容的移植。
返回:打开成功返回一个句柄(资源),打开失败返回FALSE。
打开模式
基本模式:
• R 读
• W 清空写,文件存在直接打开同时清空。
• A 追加写,文件存在直接打开
• X 新建写,只能新建文件进行操作!就是写操作,与w类似
+扩展模式:
扩展的操作,都可以完成读写操作。
差异与基本模式一致!
• R+ 读写,打开任意文件(无论是存在还是不存在),文件内容不会被清空,依据指针位置,完成读,写操作。其中,写,会替换原有指针位置字节。
• W+ 读写,打开时,同时清空内容,之后指针在哪里,就 在哪里完成读写!与R+唯一的差异,就是会清空文件内容!
• A+ 读写,打开任意文件,不会清空内容,指针仅仅影响读操作。不影响写操作,仅仅可以在末尾写!
• X+ 读写,新建才能打开,依据文件指针位置,进行读写操作!
关闭文件
bool fclose(resource $handle);
关闭一个已打开的文件指针
读取文件内容
读取指定大小
string fread(resource $handle,int $length);
读取文件(可安全用于二进制文件)
$handle
打开的文件指针; $length
读取的字节数,一般1kb=1024b
返回读取的内容
读行
string fgets(resource $handle[,int $length]);
从文件指针中读取一行
参数:$handle
文件指针 $length
可以指定读取的字节数.从handle指向的文件中读取一行并返回长度最多为length-1字节的字符串.碰到换行符(包括在返回值中) 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。如果没有指定 length,则默认为 1K,或者说 1024 字节。
返回读取的字符串
把文件读入数组
array file(string $filename[,int $flags=0]);
把整个文件读入一个数组中
参数:
$filename
文件名,不用打开、关闭文件。
$flags
,附加选项。
FILE_USE_INCLUDE_PATH(1)
,在 include_path 中查找文件。
FILE_IGNORE_NEW_LINES(2)
,在数组每个元素的末尾不要添加换行符
FILE_SKIP_EMPTY_LINES(4)
,跳过空行
返回:返回整个文件的一个数组。
把文件内容读入字符串(不用打开)
string file_get_contents(string $filename)
将整个文件读入一个字符串
提示:不用打开文件,也不用关闭文件
写入文件
写入文件内容
int fwrite(resource $handle,string $string [,int $length]);
写入文件(可安全用于二进制文件)
参数:$handle
打开的文件指针;$string
要写入的字符串;$length
表示要写入的字符数
将字符串写入文件,不用打开
int file_put_contents(string $filename,mixed $data)
将一个字符串写入文件
拷贝文件
bool copy(string $source, string $dest);
删除文件
bool unlink(string $filename);
删除文件
文件指针
bool feof ( resource $handle )
测试文件指针是否到了文件结束的位置
定位指针: fseek(句柄,位置),位置从0开始递增
获取指针位置: ftell(句柄); 获取指针位置
取得文件属性
文件大小:filesize($filename)
创建时间:filectime($filename)
访问时间:fileatime($filename)
修改时间:filemtime($filename)
时间戳
文件权限:fileperms($filename)
文件锁
默认的,PHP的文件操作函数,不是阻塞状态。自由操作状态。
当需要,一个脚本操作而需要阻塞另外的脚本操作时,需要用到文件锁。
锁操作流程:
先加锁,检测锁是否加成功,如果成功再使用!
锁定类型:
读锁: s-Lock(share-lock)共享锁,读操作前,期望增加的锁定。导致,允许并发读,阻塞额外的写操作。
写锁: x-lock(exclusive-lock)排他锁,独占锁,写操作前,尝试添加的锁定类型。导致,其他脚本不能读也不能写。
意向锁:所有的操作资源的脚本都遵循一个约定来使用文件锁(约定)。
函数:
Flock(句柄, 类型)
函数用于添加PHP 的文件锁定。(,添加意向锁。)
类型:
LOCK_SH 读锁
LOCK_EX 写锁
语法如下:
1.
2.
2,需要等待(被阻塞)1 执行完才会执行!
强调,一定要判断锁是否可以添加成功! 可以通过LOCK_NB来在锁定失败时,不阻塞,但是在windows下不被支持:
解锁
Flock($handle, LOCK_UN)来强制解锁,
Fclose()自动解锁!
文件上传
上传文件是通过表单来上传的,表单需添加enctype属性 enctype=”multipart/form-data”
将接收到的文件,存储在 上传临时目录中。默认为 服务器所在操作系统的临时目录。
该临时文件有效期为脚本周期!(时间短)在C/windows/Temp
在临时文件未消失前,将其持久性存储!Move_uploaded_file(临时文件地址,目标文件地址);
通过预定义变量$_FILES
获得所有的上传文件的信息。也可以在php.ini中修改上传文件的临时目录;upload_tmp_dir = 绝对路径
$_FILFS
上传文件的信息和数据,都保存在$_FILFS
全局数组中,不在$_POST
中,$_POST
是普通表单信息
name:原文件名称;
type:上传文件的后缀名;
tmp_name:上传文件的二进制数据,在服务器端的保存位置。
error:上传文件的错误编号。
size:上传文件大小
上传文件错误代码
第5个错误为上传文件大小为0
1为文件超过了php对上传文件大小的设置 upload_max_filesize
2为文件过大,超过表单中元素 MAX_FILE_SIZE
3文件没有上传完
4没有上传文件
6临时上传目录没找到 可以在ini中改;upload_tmp_dir=
7临时文件写入失败 磁盘空间不足,权限不允许
判断文件是否通过HTTP POST上传的
语法:bool is_upload_file(string $filename)
参数:$filename
是上传的临时文件
$filename
就用的是$_FILES[‘uploadFile’][‘tmp_name’]
将上传文件移动到新位置
语法:bool move_upload_file(string $filename,string $destination);
参数: $filename
临时文件 $destination
目标文件,一般将目标文件复制到网站空间
生成唯一ID文件名
语法:string uniqid([string $prefix=””[,bool $more_entropy = false] ])
参数:如果省略2个参数则生成13位的随机数. $prefix
给随机数添加前缀
$more_entropy
后面添加一个子随机数
验证上传文件是否有错误
if($_FILES[‘uploadFile’][‘error’] != 0)exit(‘上传文件发生错误’);
上传文件大小判断
(1) 修改php.ini中的upload_max_filesize配置项(单个文件大小)系统默认上传文件大小为2M
(2) 在表单中使用隐藏域来存储文件的最大允许上传的值
提示:要写在<input type=”file”>
之前才有效
如果超过php.ini中的max_file_size
指定的最大值,则$_FILES[‘upload’][‘error’]=2
(3) 在服务器端也要进行大小判断
使用php.fileinfo对MIME类型进行检查
在php.ini中开启extension=php_fileinfo.dll
finfo_file()
返回指定文件的信息(字符集,MIME类型)
语法:string finfo_file(resource $finfo,string $file_name=NULL);
参数:$finfo
资源 $file_name
指定取出信息的文件名
finfo_open()
创建一个检查MIME类型的资源
语法:resource finfo_open([int $options=FILEINFO_NONE]);
参数:如果是默认参数,则返回含有字符集的MIME类型,如果使用FILEINFO_MIME
参数,只返回MIME类型。
多文件上传处理
情况一:表单中name值不同
例如:商品图片:<input type=”file” name=”goods_image”><br />
用户头像: <input type=”file” name=”user_logo”><br />
品牌图片:<input type=”file” name=”brand_image”><br />
用print_r($_FILES);
在$_FILES
中,每个元素,对应一个5个元素的数组:
此时,需要处理那个,就使用哪个数组即可!
情况二:表单中name值相同
例如:商品图片一:<input type=”file” name=”goods_image[]”><br>
商品图片二:<input type=”file” name=”goods_image[]”><br>
商品图片三:<input type=”file” name=”goods_image[]”><br>
或者:<input type=”file” name=”img[]” multiple=”multiple”>
和上面也一样
用print_r($_FILES);
打印出结果
把相关的整理到一个元素中,该元素对应5个元素(name, type, tmp_name, error, size)的数组。
每个name对应3个值,其他也是一样
下标一致的属于一个文件,只要获得每个下标,就可以通过下标获得对应的5个元素值!
name值相同的文件处理代码
<?php
/**
* 上传工具类,单文件直接实列化请求UploadFile,多文件请求uploadMulti
* 同时提供了一些对外界修改参数的函数
*/
class Upload
private $_error; // 存储当前错误信息
private $_upload_path; // 上传目录
private $_prefix; // 前缀
private $_max_size; // 最大size
private $_ext_list; // 允许的后缀列表
private $_mime_list; // 允许的MIME列表
private $_ext_mime = array( // 图片对应的MIME表
'.jpeg' => 'image/jpeg',
'.jpg' => 'image/jpeg',
'.png' => 'image/png',
'.gif' => 'image/gif'
);
public function __construct()
// 为选项指定默认值
$this->_error = array();
$this->_upload_path = './';
$this->_prefix = '';
$this->_max_size = 5 * 1024 * 1024;
$this->_ext_list = array('.jpg', '.gif', '.png', '.jpeg');
$this->_setMIMEList($this->_ext_list);
/**
* 通过允许的后缀列表获得相对应允许的MIME列表
* @param string $ext_list 允许的后缀列表
* @return void 赋值到 MIME列表属性上
*/
private function _setMIMEList($ext_list)
$mime_list = array();
// 遍历获得每一个后缀名
foreach($ext_list as $ext)
// 利用当前后缀名,获取对应的MIME,存储到MIME列表中!
$mime_list[] = $this->_ext_mime[$ext];
// 赋值到 MIME列表属性上!
$this->_mime_list = $mime_list;
//下面的提供修改这些配置属性的方法:setUploadPath setPrefix setMaxSize setExtList
/**
* 提供修改路径的方法
* @access public
* @param string $upload 目录字符串 默认'./'
* @return void 目录不存在采用默认,存在采用传入的参数
*/
public function setUploadPath($upload_path)
// 不允许将不存在的目录设置为上传目录
if (is_dir($upload_path))
$this->_upload_path = $upload_path;
else
trigger_error('上传目录设置失败,采用默认');
/**
* 提供修改前缀的方法
* @access public
* @param string $prefix 默认''
* @return void 把传入的前缀保存到_prefix
*/
public function setPrefix($prefix)
$this->_prefix = $prefix;
/**
* 提供修改最大大小的方法
* @access public
* @param int $max_size 最大大小 默认1*1024*1024
* @return void 将传入的尺寸保存到_max_size
*/
public function setMaxSize($max_size)
$this->_max_size = $max_size;
/**
* 提供修改允许的后缀名列表
* @param array $ext_list 后缀名组成的数组,默认array('.jpg', '.gif', '.png', '.jpeg');
* @return void 将传入的数组保存到_ext_list,并调用_setMIMEList方法生成对应的MIME类型
*/
public function setExtList($ext_list)
$this->_ext_list = $ext_list;
$this->_setMIMEList($ext_list);
/**
* 文件上传(业务逻辑判断)函数
* 一次上传(判断)一个文件
* @param array $file_info 某个临时上传文件的5个信息,由$_FILES中获得!
* @return string:成功,目标文件名;false: 失败
*/
public function uploadFile($file_info)
// 判断是否有错误
if ($file_info['error'] != 0)
$this->_error[] = '上传文件存在错误';
return false;
// 判断文件类型
// 后缀名
$ext_list = $this->_ext_list; // 允许的后缀名列表
$ext = strrchr($file_info['name'], '.');
if (! in_array($ext, $ext_list))
$this->_error[] = '类型,后缀不合法';
return false;
// MIME
$mime_list = $this->_mime_list; // 允许的mime列表!
if (! in_array($file_info['type'], $mime_list))
$this->_error[] = '类型,MIME不合法';
return false;
// PHP检测MIME
$finfo = new Finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file($file_info['tmp_name']);
if (! in_array($mime_type, $mime_list))
$this->_error[] = '类型,PHP检测MIME不合法';
return false;
// 判断大小
$max_size = $this->_max_size; // 允许的最大尺寸
if ($file_info['size'] > $max_size)
$this->_error[] = '文件过大';
return false;
// 设置目标文件地址
// 上传目录
$upload_path = $this->_upload_path;
// 采用子目录存储
// 获取当前需要的子目录名(目录/小时)
$sub_dir = date('YmdH') . '/'; // 当前的年月日时
// 是否存在
if (! is_dir($upload_path . $sub_dir))
// 不存在,创建
mkdir($upload_path . $sub_dir);
// 目标文件名
$prefix = $this->_prefix;// 前缀
$dst_name = uniqid($prefix, true) . $ext;
// 是否为HTTP上传文件的检测
if (! is_uploaded_file($file_info['tmp_name']))
$this->_error = '不是HTTP上传的临时文件';
return false;
// 移动!
if (move_uploaded_file($file_info['tmp_name'], $upload_path . $sub_dir . $dst_name))
// 移动成功
return $sub_dir . $dst_name; // 仅仅返回 上传目录之后的地址即可!
else
$this->_error = '移动失败';
return false;
/**
* 获取错误信息
* @access public
* @return string 错误信息
*/
public function getError()
return $this->_error;
//示范多文件上传处理,name相同的情况
//$arrFile = array();
//$i=0;
//foreach($file as $key=>$value) 二维数组
// foreach($value as $val) 一维数组
// $arrFile[$i++][$key] = $val;
//
// $i = 0;
//
//name 取出每个名字 $arr[0~3][name]
//type 取出每个类型 $arr[0~3][type]
//tmp_name 取出每个上传的位置 $arr[0~3][tmp_name]
//error 取出每个错误信息 $arr[0~3][error]
//size 取出每个大小 $arr[0~3][size]
/**
* 上传文件判断函数,多文件上传,name值不同
* @param array $file_list 比如:$_FILES['image'] 二维数组
* @return 返回上传目录之后的地址结果
*/
function uploadMulti($file_list)
// 遍历,其中的name元素,得到下标,下面看不懂看177-189
foreach($file_list['name'] as $key=>$v) //传进来的$file_list是二维数组
// 利用下标 获得对应的5个元素值
// $file_info每个文件的信息,$key是0开始的整数
$file_info['name'] = $file_list['name'][$key];
$file_info['type'] = $file_list['type'][$key];
$file_info['tmp_name'] = $file_list['tmp_name'][$key];
$file_info['error'] = $file_list['error'][$key];
$file_info['size'] = $file_list['size'][$key];
// 上传该文件即可!
// 并存储每个文件的上传结果,与$key对应!
$result_list[$key] = $this->uploadFile($file_info);
// 返回上传结果
return $result_list;
以上是关于php文件处理与文件上传的主要内容,如果未能解决你的问题,请参考以下文章