PHP文件系统处理

文件系统概述

文件类型
        PHP是以UNIX的文件系统为模型的,因此Windows系统中我们只能获得"file"、"dir"或者"unknown"三种文件类型。而UNIX系统中,可以获得"block"、"char"、"dir"、"fifo"、"file"、"link"和"unknown"7种类型。
        使用filetype()函数获取文件的上述类型,该函数接受一个文件名作为参数,如果文件不存在将返回false。
        is_file()判断给定的文件名是否为一个正常的文件。
        is_dir()判断给定的文件名是否是一个目录。
        is_link()判断给定的文件名是否是一个符号链接。
文件的属性
 PHP的文件属性处理函数
        clearstatcache()函数清除被PHP缓存的文件信息。对同一个文件名进行多次操作,并且需要该文件信息不被缓存时才需要调用它。
    

目录的基本操作

解析目录路径
        UNIX系统中必须使用正斜线"/"作为路径分隔符,而windows系统中默认使用反斜线"\"作为路径分隔符,在程序中表示时还要将"\"转义,但也接受正斜线"/"作为分隔符的写法。建议使用正斜线"/"作为路径分隔符。
        PHP内置常量DIRECTORY_SEPARATOR,其值为当前操作系统的默认文件路径分隔符。
basename()
        返回路径中文件名部分。
1
2
3
4
5
<?php
    $path = "D:/amp/php/php.ini";   
    echo basename($path)."<br/>";           //php.ini
    echo basename($path,".ini")."<br/>";    //php
    echo basename($path,".php");            //php.ini
dirname()
        给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名。
1
2
3
<?php
    $path = "D:/amp/php/php.ini";
    echo dirname($path)."<br/>";        // D:/amp/php
pathinfo()
        返回一个关联数组,其中包括指定路径中的目录名、基本名、扩展名三部分。分别通过dirname、basename、extension来引用。
1
2
3
4
5
6
<?php
    $path = "D:/amp/php/php.ini";
    $path_parts = pathinfo($path);
    echo $path_parts['dirname']."<br/>";    //D:/amp/php
    echo $path_parts['basename']."<br/>";   //php.ini   
    echo $path_parts['extension']."<br/>"//i
遍历目录
opendir()
        用于打开指定目录,接受一个目录及目录名作为参数,函数返回值可供其他目录函数使用的目录句柄(资源类型)。如果该目录不存在或者没有访问权限,则返回false。
readdir()
        读取指定目录,接受已经用opendir()函数打开的可操作目录句柄作为参数,函数返回当前目录指针位置的一个文件名,并将目录指针向后移动一位。当指针位于目录的结尾时,因为没有文件存在则返回false。
closedir()
        关闭指定目录,接受已经用opendir()函数打开的可操作目录句柄作为参数。函数无返回值,运行后将关闭打开的目录。
rewinddir()

        倒回目录句柄,接受已经用opendir()函数打开的可操作目录句柄作为参数。将目录指针重置到目录开始处,即倒回目录的开头。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
    date_default_timezone_set("PRC");
    $num = 0;                                   //用来统计子目录和文件的个数
    $dirname = 'd:/amp/php';                    //保存当前目录下用来遍历的一个目录名
    $dir_handle = opendir($dirname);            //用opendir打开目录
 
    //将遍历的目录和文件名使用表格格式输出
    echo '<table border="0" align="center" width="600" cellspacing="0" cellpadding="0">';
    echo '<caption><h2>目录'.$dirname.'下面的内容</h2></caption>';        
    echo '<tr align="left" bgcolor="#cccccc">';                      
    echo '<th>文件名</th><th>文件大小</th><th>文件类型</th><th>修改时间</th></tr>';
     
    //使用readdir循环读取目录里的内容
    while($file = readdir($dir_handle)) {  
        //将目录下的文件和当前目录连接起来,才能在程序中使用
        $dirFile = $dirname."/".$file;     
 
        $bgcolor $num++%2==0 ? '#FFFFFF' : '#CCCCCC';                //隔行一种颜色
        echo '<tr bgcolor='.$bgcolor.'>';                
        echo '<td>'.$file.'</td>';                                      //显示文件名
            echo '<td>'.filesize($dirFile).'</td>';                     //显示文件大小
            echo '<td>'.filetype($dirFile).'</td>';                     //显示文件类型
            echo '<td>'.date("Y/n/t",filemtime($dirFile)).'</td>';      //格式化显示文件修改时间
            echo '</tr>';
    }
    echo '</table>';                                                  //关闭表格标记
    closedir($dir_handle);                                              //关闭文件操作句柄
 
    echo '在<b>'.$dirname.'</b>目录下的子目录和文件共有<b>'.$num.'</b>个';
统计目录大小
        disk_free_space()计算磁盘空闲容量大小。
        disk_total_apace()计算磁盘大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
    /**
        自定义一个函数dirSize(),统计传入参数的目录大小
        @param  string  $directory  目录名称
        @return double              目录的尺寸大小
    */
    function dirSize($directory) {     
        $dir_size = 0;                                      //用来累加各个文件大小
 
        if($dir_handle = @opendir($directory)) {            //打开目录,并判断是否能成功打开
            while( $filename = readdir($dir_handle) ) {     //循环遍历目录下的所有文件
                if($filename != "." && $filename != "..") { //一定要排除两个特殊的目录
                    $subFile = $directory."/".$filename;    //将目录下的子文件和当前目录相连
                    if(is_dir($subFile))                    //如果为目录
                        $dir_size += dirSize($subFile);     //递归地调用自身函数,求子目录的大小
                    if(is_file($subFile))                   //如果是文件
                        $dir_size += filesize($subFile);    //求出文件的大小并累加
                }
            }
            closedir($dir_handle);                          //关闭文件资源
            return $dir_size;                               //返回计算后的目录大小
        }
    }
 
    $dir_size = dirSize("d:/amp/php");                      //调用该函数计算目录大小
    echo round($dir_size/pow(1024,1),2)."KB";               //字节数转换为“KB”单位并输出
建立和删除目录
        mkdir()创建一个新目录。rmdir()删除目录,只能删除一个空目录并且目录必须存在,如果是非空目录就需要先进入到目录中,使用unlink()函数将目录中的每个文件都删除掉,再回来将这个空目录删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
    /**
        自定义函数递归的删除整个目录
        @param  string  $directory 目录名称
    */
    function delDir($directory) {          
        if(file_exists($directory)) {                           //如果不存在rmdir()函数会出错
            if($dir_handle = @opendir($directory)) {            //打开目录并判断是否成功
                while($filename = readdir($dir_handle)) {       //循环遍历目录
                    if($filename != "." && $filename != "..") { //一定要排除两个特殊的目录
                        $subFile = $directory."/".$filename;    //将目录下的文件和当前目录相连
                        if(is_dir($subFile))                    //如果是目录条件则成立
                            delDir($subFile);                   //递归调用自己删除子目录
                        if(is_file($subFile))                   //如果是文件条件则成立
                            unlink($subFile);                   //直接删除这个文件
                    }
                }
                closedir($dir_handle);                          //关闭目录资源
                rmdir($directory);                              //删除空目录
            }
        }
    }
     
    delDir("phpMyAdmin");       //调用delDir()函数,将程序所在目录中的“phpMyAdmin”文件夹删除
复制目录

        首先对源目录进行遍历,如果遇到的是普通文件,直接使用copy进行赋值;如果遍历时遇到一个目录,则必须建立该目录,然后再对该目录下的文件进行复制操作,如果还有子目录,则使用递归重复操作,最终将整个目录复制完成。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
    /**
        自定义函数递归的复制带有多级子目录的目录
        @param  string  $dirSrc  原目录名称字符串
        @param  string  $dirTo  目标目录名称字符串
    */
    function copyDir($dirSrc, $dirTo) {        
        if(is_file($dirTo)) {                               //如果目标不是一个目录则退出
            echo "目标不是目录不能创建!!";
            return;                                         //退出函数
        }
         
        if(!file_exists($dirTo)) {                          //如果目标目录不存在则创建
            mkdir($dirTo);                                  //创建目录
        }
         
        if($dir_handle = @opendir($dirSrc)) {               //打开目录并判断是否成功
            while($filename = readdir($dir_handle)) {       //循环遍历目录
                if($filename != "." && $filename != "..") { //一定要排除两个特殊的目录
                    $subSrcFile = $dirSrc."/".$filename;    //将源目录的多级子目录连接
                    $subToFile = $dirTo."/".$filename;      //将目标目录的多级子目录连接
                         
                    if(is_dir($subSrcFile))                 //如果源文件是一个目录
                        copyDir($subSrcFile, $subToFile);   //递归调用自己复制子目录
                    if(is_file($subSrcFile))                //如果源文件是一个普通文件
                        copy($subSrcFile, $subToFile);      //直接复制到目标位置
                }
            }
            closedir($dir_handle);                          //关闭目录资源
        }  
    }
     
    //测试函数,将目录"phpMyAdmin"复制到"D:/admin"
    copyDir("phpMyAdmin", "D:/admin");     

文件的基本操作

文件的打开与关闭

        fopen()建立与文件资源的连接,fclose()关闭通过fopen函数打开的文件资源。

fopen()

 

  • 第一个参数:需要被打开的文件URL。
  • 第二个参数:文件操作模式

 


  • 第三个参数是可选的,如果资源位于本地系统,php则认为可以使用本地路径或是相对路径来访问此资源。如果将这个参数设置为1,就会是php考虑配置指令include_path中指定的路径(在php的配置该文件中设置)。
  • 第四个参数也是可选的。fopen()函数允许文件名称以协议名称开始。例如"http://"并且在一个远程位置打开该文件。通过设置这个参数,还可以支持一些其他的协议。

 

        如果fopen()函数成功地打开一个文件,该函数将返回一个指向这个文件的文件指针。对该文件进行操作所使用的读、写一起其他的文件操作函数,都要使用这个资源来访问该文件。如果打开失败,则返回false。
 
fclose()
        资源类型属于php的基本类型之一,一旦完成资源的处理,已定要将其关闭,否则可能会出现一些预料不到的错误。函数fclose()就会撤销fopen()打开的资源类型,成功时返回true,否则返回false。参数必须是使用fopen()或者fsocketopen()函数打开的已存的文件指针。在目录操作中opendir()函数也是开启一个资源,使用closedir()将其关闭。
 
写入文件
        fwrite()函数就可以将字符串内容写入文件中。在文件中通过字符序列\n表示换行符,表示文件中一行的末尾。当需要一次输入或输出一行信息时。
  • 第一个参数:需要打开的文件资源。
  • 第二个参数:需要输入的字符串内容。
  • 第三个参数:可选。将在输入length个字符串时停止。
1
2
3
4
5
6
7
8
9
10
11
<?php
    //声明一个变量用来保存文件名
    $filename = "d:\\data.txt";
    //使用fopen()函数以只写的模式打开文件,如果不存在则创建它,打开失败则通过程序
    $handle = fopen($filename, "w") or die("打开文件失败!");
    //写入文件
    for ($i = 0; $i < 10; $i++){
        fwrite($handle, $i."写啊写!\r\n");
    }
    //关闭打开的文件资源
    fclose($handle);
读取文件内容
        在读取文件时,不仅要注意行结束符号"\n",程序也需要一种标准的方式来识别何时到达文件的末尾,这个标准通常称为EOF(End Of File)字符。在PHP中,使用fepf()函数。该函数接受一个打开的文件资源,判断一个文件指针是否位于的结束出,如果在文件末尾处,则返回true。
fread()
        用来在打开文件中读取指定长度的字符串。也可以安全用于二进制文件,在区分二进制文件和文本文件的系统上打开文件时。fopen()函数的mode参数要加上'b'。函数Fread()的原型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
    header("ContentType:text/html;charset:utf8");
    //从文件中读取制定字节数的内容存入到一个变量中
    $filename = "d:\\data.txt";
    $handle = fopen($filename, "r") or die("文件打开失败!");
    $contents = fread($handle, 100);
    fclose($handle);
    echo $contents."<hr/>";
     
    //从文件中读取全部内容存入到一个变量中,每次读取一部分,循环读取
    $filename = "d:\\01.jpg";
    $handle = fopen($filename, "rb") or die("文件打开失败!");
    $contents = "";
    while (!feof($handle)){
        $contents .= fread($handle, 1024);
    }  
    fclose($handle);
    echo $contents."<hr/>";
     
    //另一种从文件中读取全部内容的方法
    $filename = "d:\\data.txt";
    $handle = fopen($filename, "r") or die("文件打开失败!");
    $contents - fread($handle, filesize($filename));
    fclose($handle);
    echo $contents;
        如果只是讲一个文件的内容读入到另一个字符串中,可以用file_get_contents()函数,它的性能比上面的代码好得多。
 
fgets()、fgetc()
        fgets()一次至多从打开的文件资源中读取一行内容。失败返回false。
第一个参数:打开的资源。
第二个参数:可选。length,返回length-1个字节。或者遇到换行或EOF之前读取的所有内容。如果忽略length,默认为1024个字符。
1
2
3
4
5
6
7
<?php
    $handle = fopen("d:\\data.txt", "r") or die("文件打开失败!");
    while (! feof($handle)){
        $buffer = fgets($handle, 4096);
        echo $buffer."<br/>";
    }
    fclose($handle);
        fgetc()再打开的文件资源中只读取当前指针位置处的一节字符。如果遇到文件结束标志EOF,将返回false值。
1
2
3
4
5
6
<?php
    $handle = fopen("d:\\data.txt", "r") or die("文件打开失败!");
   while (false !== ($char = fgetc($handle))){
       echo $char."<br/>";
   }
    fclose($handle);
file()
        可以把整个文件读入到一个数组中。数组中的每个元素对应文件中相应的行,各元素有换行符分隔,同事换行符仍附加在每个元素的末尾。这样,就可以使用数组的相关函数对文件内容进行处理。
 
readfile()
        该函数可以读取指定的整个文件,立即输出缓冲区,并返回读取的字节数。该函数也不需要使用fopen()函数打开文件。
1
2
<?php
    readfile("d:\\data.txt");
远程访问文件
        如果需要访问远程文件,必须在PHP的配置文件中激活"allow_url_fopen"选项,才能使用fopen()函数打开远程文件,而且其他服务器具有访问权限。使用PHP访问远程文件就像访问本地文件一样,都是使用相同的读写函数处理。
        如果有合法的访问权限,可以以一个用户的身份和某FTP服务器建立链接,这样就可以想改FTP服务器端的文件进行写操作了。可以用该技术来存储远程日志文件等操作,但仅能用该方法来创建新的文件,如果尝试覆盖已经存在的文件,fopen()函数的调用将会失败。而且要以匿名以外的用户名链接服务器,并需要指明用户名(甚至密码)。"ftp:user:password@ftp.xxx.com/root"。
        为了避免由于访问远程主机时发生的超时错误,可以使用set_time_limit()函数对程序的运行时间加以限制。
移动文件指针
int ftell()
        返回文件指针的当前位置的偏移量。
int fseek()
        移动文件指针到第二个参数offset指定的位置。如果没有提供第三个可选参数whence,则位置将设置为从文件开头的offset字节处,否则,第三个可选参数whence可以设置为三个可能的值。
  • SEEK_CUR:设置指针位置为当前位置加上第二个参数所提供的offset字节。
  • SEEK_END:设置指针位置为EOF加上offset字节。在这里,offset必须设置为负值。
  • SEEK_SET:设置指针位置为offset字节处。这与忽略第三个参数whence效果相同。
        执行成功,返回0,失败则返回-1。如果将文件以追加模式"a"或"a+"打开,写入文件的任何数据总是会被附加在后面,不会管文件指针的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
    //以只读模式打开文件
    $fp = fopen('data.txt', 'r') or die("文件打开失败"); 
     
    echo ftell($fp)."<br>";       //输出刚打开文件的指针默认位置,指针在文件的开头位置为0
    echo fread($fp, 10)."<br>";       //读取文件中的前10个字符输出,指针位置发生了变化
    echo ftell($fp)."<br>";       //读取文件的前10个字符之后,指针移动的位置在第10个字节处
 
    fseek($fp, 100, SEEK_CUR);      //将文件指针的位置,由当前位置向后移动100个字节数
    echo ftell($fp)."<br>";           //文件位置在110个字节处
    echo fread($fp, 10)."<br>";       //读取110到120字节数位置的字符串,读取后指针的位置为120
 
    fseek($fp, -10, SEEK_END);      //又将指针移动到倒数10个字节位置处
    echo fread($fp, 10)."<br>";       //输出文件中最后10个字符 
 
    rewind($fp);                    //又移动文件指针到文件的开头
    echo ftell($fp)."<br>";       //指针在文件的开头位置,输出0
 
    fclose($fp);                    //关闭文件资源
bool rewind():

        移动文件指针到文件的开头。       

文件的所定机制

flock()

        可以对文件使用锁定机制(锁定或释放文件)。当一个进程早访问文件时加上锁,其他进程要想对该文件进行访问,必须等到锁定被释放以后。这样避免在兵法访问同一个文件时破坏数据。

第一个参数:一个已经打开的文件资源。

第二个参数:规定使用哪种锁定类型。值为以下:

 

  • LOCK_SH取得共享锁定(从文件中读取数据时使用)。
  • LOCK_EX取得独占锁定(像文件中写入数据时使用)。
  • LOCK_UN释放锁定(无论何种锁定,均由此释放)。
  • LOCK_NB附加锁定(如果不希望flock()在锁定时堵塞,则应在上述锁定后加上此锁)。

 

        如果锁定会堵塞的话(已经被flock()锁定的文件,再次锁定时,flock()函数会被挂起,这时成为锁定堵塞),也可以将可选的第三个参数设置为1,则当进行锁定时会阻塞其他进程。锁定操作也可以被fclose()释放。为了让flock()函数发挥作用,在所有访问文件的程序中都必须使用相同的锁定文件。该函数如果成功则返回true,失败则返回false。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<html>
    <head><title>网络留言板模式</title></head>
    <body>
        <?php
            //声明一个变量保存文件名,在这个文件中保存留言信息
            $filename = "text_data.txt";   
             
            //判断用户是否按下提交按钮,用户提交后则条件成功
            if(isset($_POST["sub"])){  
                //接收表单中三条内容,并整合为一条,使用“||”分隔,使用“<|>”结尾
                $message = $_POST["username"]."||".$_POST["title"]."||".$_POST["mess"]."<|>";
                writeMessage($filename, $message);  //调用自定义函数,将信息写入文件
            }
 
            if(file_exists($filename))                  //判断文件是否存在,如果存在则条件成立
                readMessage($filename);                 //文件存在则调用自定义函数,读取数据
 
            /**
                自定义一个向文件中写入数据的函数
                @param  string  $filename   写入的文件名
                @param  string  $message        写入文件的内容,即消息
            */
            function writeMessage($filename, $message) {   
                $fp = fopen($filename, "a");            //以追加模式打开文件
                if (flock($fp, LOCK_EX)) {              //进行排他型锁定(独占锁定)
                    fwrite($fp, $message);              //将数据写入文件
                        flock($fp, LOCK_UN);            //同样使用flock()函数释放锁定
                } else {                                //如果建立独占锁定失败
                        echo "不能锁定文件!";             //输出错误消息
                }
                fclose($fp);                            //关闭文件资源
            }
             
            /**
                自定义一个遍历读取文件的函数
                @param  string  $filename   读取的文件名
            */
            function readMessage($filename){       
                $fp = fopen($filename, "r");            //以只读的模式打开文件
                flock($fp, LOCK_SH);                    //建立文件的共享锁定
                $buffer = "";                           //将文件中的数据遍历后放入这个字符串中
                while (!feof($fp)) {                    //使用while循环将文件中数据遍历出来 
                    $buffer.= fread($fp, 1024);         //读出数据追加到$buffer变量中
                }  
                 
                $data = explode("<|>", $buffer);          //通过“<|>”将每行留言分隔并存入到数组中
                foreach($data as $line) {               //遍历数组将每行数据以HTML输出
                    //将每行数据再分隔
                    list($username, $title, $message)=explode("||",$line);
                    //判断每部分是否为空
                    if($username!="" && $title!="" && $message!="") {  
                        echo $username.'说:';        //输出用户名
                        echo '&nbsp;'.$title.',';   //输出标题
                        echo $message."<hr>";         //输出留言主题信息
                    }
                }
                flock($fp, LOCK_UN);                    //释放锁定
                fclose($fp);                            //关闭文件资源
            }
        ?>
         
        <!-- 以下为用户输入表单界面(GUI)-->
        <form action="" method="post">
            用户名:<input type="text" size=10 name="username"><br>
            标&nbsp;&nbsp;题:<input type="text" size=30 name="title"><br>
            <textarea name="mess" rows=4 cols=38>请在这里输入留言信息!</textarea>
            <input type="submit" name="sub" value="留言">
        </form>
    </body>
</html>
文件的一些基本操作函数

 

       

文件的上传与下载

文件上传

 客户端上传设置

        如果支持文件上传操作,必须在<form>标签中将enctype和method两个属性指明相应的值。

 

  • enctype="multipart/form-data"用来指定表单编码数据方式,让服务器知道,我们要传递一个文件,并带有常规的表单信息。
  • method="POST"用来致命发送数据的方法。

 

        另外,还需要在form表单中设置一个hidden类型的input框。其中name的值为MAX_FILE_SIZE的隐藏值域,并通过设置其VALUE的值限制上传文件的大小(单位字节),但这个值不能超过PHP的配置文件中upload_max_filesize值设置的大小。

 

1
2
3
4
5
<form action="upload.php"  method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
    选择文件:<input type="file" name="myfile">
    <input type="submit" value="上传文件">
</form>

在服务端通过php处理上传

        要想通过PHP成功地管理文件上传,需要通过以下三方面信息:

 

  • 设置PHP配置文件中的指令:用于精细地调节PHP的文件上传功能。
  • $_FILES多维数组:用于存储各种与上传文件有关信息,其他数据还使用$_POST去接收。
  • PHP的文件上传处理函数:用于上传文件的后续处理。

 

        文件上传与PHP配置文件的设置有关,首先,应该设置php.ini文件中的一些指令,精细调节PHP的文件上传功能。在PHP配置文件php.ini中和上传文件有关的指令如下表:

        除了上述,还有两个专门用于文件上传所使用的is_uploaded_file()和move_uploaded_file()两个函数。

is_uploaded_file()

        判断指定的文件是否是通过HTTP POST上传的,如果是返回true。用于防止潜在的攻击者对原本不能通过脚本交互的文件进行非法管理,这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件。

move_uploaded_file()

        文件上传后,首先会存储与服务器的临时目录中,可以使用该函数将上传的文件移动到新位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
    $allowtype = array("gif", "png", "jpg");   //设置充许上传的类型为gif, png和jpg
    $size = 1000000;                           //设置充许大小为1M(1000000字节)以内的文件
    $path = "./uploads";                       //设置上传后保存文件的路径
     
    //判断文件是否可以成功上传到服务器,$_FILES['myfile']['error'] 为0表示上传成功
    if($_FILES['myfile']['error'] > 0) {    
        echo '上传错误: ';
        switch ($_FILES['myfile']['error']) {
            case 1:  die('上传文件大小超出了PHP配置文件中的约定值:upload_max_filesize'); 
            case 2:  die('上传文件大小超出了表单中的约定值:MAX_FILE_SIZE'); 
            case 3:  die('文件只被部分上载');
            case 4:  die('没有上传任何文件');
            default: die('末知错误');
        }
    }
     
    //判断上传的文件是否为充许的文件类型,通过文件的后缀名
    $hz = array_pop(explode(".", $_FILES['myfile']['name']));
    //通过判断文件的后缀方式,来决定文件是否是充许上传的文件类型
    if(!in_array($hz, $allowtype)) {
        die("这个后缀是<b>{$hz}</b>,不是充许的文件类型!");
    }
     
    /* 也可以通过获取上传文件的MIME类型中的主类型和子类型,来限制文件上传的类型
    list($maintype,$subtype)=explode("/",$_FILES['myfile']['type']);   
    if ($maintype=="text") {   //通过主类型限制不能上传文本文件,例如.txt .html .php等文件
        die('问题: 不能上传文本文件。');
    } */
 
    //判断上传的文件是否为充许大小
    if($_FILES['myfile']['size'] > $size ) {
        die("超过了充许的<b>{$size}</b>字节大小");
    }
     
    //为了系统安全,也为了同名文件不会被覆盖,上传后将文件名使用系统定义
    $filename = date("YmdHis").rand(100,999).".".$hz;
     
    //判断是否为上传文件
    if (is_uploaded_file($_FILES['myfile']['tmp_name'])) {
        if (!move_uploaded_file($_FILES['myfile']['tmp_name'], $path.'/'.$filename)) { 
            die('问题: 不能将文件移动到指定目录。');
        }
    }else{
        die("问题: 上传文件{$_FILES['myfile']['name']}不是一个合法文件: ");
    }
 
    //如果文件上传成功则输出
    echo "文件{$upfile}上传成功,保存在目录{$path}中,大小为{$_FILES['myfile']['size']}字节";  
文件下载

            PHP使用header()函数发送网页的头部信息给浏览器,该函数接受一个头信息的字符串作为参数。文件下载需要发送的头信息包括以下三部分,通过调用三次header()函数完成,在使用readfile()函数将文件内容读取出来并直接输出。

 

1
2
3
4
5
6
7
8
9
<?php
    $filename = "test.gif";                                        
     
    header('Content-Type: image/gif');                                   //指定下载文件类型
    header('Content-Disposition: attachment; filename="'.$filename.'"'); //指定下载文件的描述
    header('Content-Length: '.filesize($filename));                      //指定下载文件的大小  
     
    //将文件内容读取出来并直接输出,以便下载
    readfile($filename);      
文件上传类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
<?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;
            }
        }
    }

 

 
 
    





posted @ 2016-01-25 17:27  staven  阅读(407)  评论(0编辑  收藏  举报