PHP 文件上传基础学习

目录

1.2 文件操作

1.将字符串写到文件中

小结:

2、读取文件和读取并且输出文件

3、打开文件并操作

4、打开文件读取

5、打开文件追加

6、是否是文件

7、判断文件或文件夹是否存在

8、删除文件【unlink】

9、ASCII美国信息交换标准代码

10、二进制读取【fread(文件指针,文件大小)】

1.3表单提交数据的两种方式

1.3.1 两种方式

1.3.2 区别

1.4 服务器接收数据的三种方式

1.5 参数传递

1.5.1 复选框的传递

1.5.2例题

1.6 文件上传

1.6.4 与文件上传有关的配置

1.7 优化文件上传

1.7.1 更改文件名

1.7.2验证文件格式


1.2 文件操作

1.将字符串写到文件中

<?php 
header("Content-type:text/html;charset=utf-8");
//  1、将字符串写到文本中
$str="1\r\n2\r\n3\r\n4\r\n5";
file_put_contents('./test.txt',$str);
?>

小结:

1、所有的写操作都是清空重写即覆盖

2、在文本中换行是\r\n windows

\r:光标移动到当前行的最前面
\n:将光标向下移动一行
Enter键=\r\n 计算机做了两步 移动到当前行的最前面 再向下移动一行

3、\r\n是特殊字符 必须放在“ ”内部 在单引号内部就是写入字符串

2、读取文件和读取并且输出文件

echo file_get_contents('./test.txt');   //将整个文件读入一个字符串中再输出      
readfile('./test.txt');         //读取输出文件内容

3、打开文件并操作

fopen(地址,模式) 打开文件夹
模式:
r:读     read
w:写     write
a:追加   append

例题:

//  3、打开文件并进行操作
    $fp=fopen('./test.txt', 'w');   //打开文件返回文件指针(文件地址 )
    //var_dump($fp);              //resource(6) of type (stream)
    for ($i=1; $i <=10 ; $i++)
    {
    fputs($fp,"关关雎鸠\r\n");  //循环十次写入关关雎鸠 每写一次就换行
    }
    fclose($fp);            //关闭文件

4、打开文件读取

    $fp=fopen('./test.txt','r');        //打开文件读取 默认只读一行
    while ($line=fgets($fp)) {
        echo $line.'<br>';             //循环读取
    }

5、打开文件追加

    $fp=fopen('./test.txt','a');    //打开文件追加
    fputs($fp,'在河之洲');      //在文件的末尾增加  

小结:

1、打开文件 返回文件指针(文件指针即文件地址)返回资源类型

2、打开文件写、追加的操作 。如果文件不存在,那就创建一个新的文件

3、打开文件读操作, 文件不存在就报错

4、fputs写一行、fgets读一行、fclose关闭文件 如果你不关闭 计算机也会帮你关闭?(不太理解)

5、追加是在文件末尾追加

6、是否是文件

echo is_file('./test.txt')?'是':'不是'; // 三元运算符判断是否是文件

7、判断文件或文件夹是否存在

echo file_exists('./test.txt')?'存在':'不存在';

8、删除文件【unlink】

    // 给出一个文件路径
    $path='./test.txt';
    //判断文件是否存在
    if (file_exists($path)) {   
    //如果是文件夹 用rmdir删除    
        if (is_dir($path)) {       
            rmdir($path);
    //如果是文件,用unlink删除文件
        }elseif (is_file($path)) {
            unlink($path);     
        }
    # 否则输出文件不存在
    }else{
        echo '文件不存在';
    }

 我这里是存在的 但是不知道为啥被拒绝了权限 有知道的师傅可以告诉我一下

9、ASCII美国信息交换标准代码

分为两种 一种可见 一种不可见 键盘上每一个键都是ASCII码 控制字符和可见字符

10、二进制读取【fread(文件指针,文件大小)】

文件的存储有两种形式:字符流和二进制流

二进制的读取按文件大小来读的

$a='C:\Users\lyr\Desktop\13jpg.jpg';
$c=fopen($a,'r');
header('content-type:image/jpeg');  //告知浏览器下面的代码通过jpg方式解析
echo fread($c,filesize($a));        //二进制的读取
//多学一招
header('content-type:image/jpeg');
echo file_get_contents('C:\Users\lyr\Desktop\13jpg.jpg');   
//file_get_contents既能读字符串又能读二进制文件
运行结果如下

 

小结:

1、文本流有明确的结束符,二进制流没有明确的结束符号,通过文件大小判断文件是否读取完毕。

2、file_get_contents() 既可以进行字符流的读取,也可以进行二进制的读取。

1.3表单提交数据的两种方式

1.3.1 两种方式

1、get

2、post

<form action=" " method="post" accept-charset="utf-8">
<form action=" " method="get" accept-charset="utf-8">

tips:如果form action不写就是提交到本页面上 

1.3.2 区别

1、从外观上看

get提交在地址上可以看到参数 post提交在地址栏看不到到参数

2、安全性

get不安全 post安全

3、提交原理

get提交是将参数一个个的提交

post提交是将所有参数作为一个整体提交

4、提交数据的大小

get提交一般不超过255个字符

post提交的大小取决于服务器

 

5、灵活性

get很灵活,只要有页面得到跳转就可以传递参数(不要传递敏感数据)

post不灵活,post提交需要有表单的参与

1、html跳转
<a href="./P82 File domain enctype.php?name=tom&age=20">跳转</a>
2、js跳转
<script type="text/javascript">
    location.href='P82 File domain enctype.php?name=tom&age=20';
    location.assign('P82 File domain enctype.php?name=tom&age=20');
    location.replace('P82 File domain enctype.php?name=tom&age=20');
</script>
3、php跳转
<?php 
header('location:P82 File domain enctype.php?name=tom&age=20')
?>
GETPOST
外观上get提交在地址上可以看到参数post提交在地址栏看不到到参数
提交数据大小get提交一般不超过255个字符(IE)最大值不同浏览器不一样提交大量数据,可以通过php.ini配置文件来设置post提交的参数
安全性get不安全post安全
提交原理提交的数据之间是独立的将提交的数据变成XML格式提交
灵活性很灵活,只要有页面的跳转就能传递数据不灵活

1.4 服务器接收数据的三种方式

通过名字获取名字对应的值

$_POST:数组类型 保存POST提交的数据
$_GET:数组类型 保存GET提交的数据
$_REQUEST:既能获取POST又能获取GET的值
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>服务器接收数据</title>
</head>
<body>
#表单提交数据
<form action="" method="get" accept-charset="utf-8">
        语文<input type="text" name="ch" value="" placeholder=""><br>
        英语<input type="text" name="ma" value="" placeholder=""><br>
            <input type="submit" name="button" value="提交">  
</form>
#超链接提交数据
<a href="P83 Server receiving data.php?ch=88&ma=55">跳转</a><br>
#js提交数据
<script type="text/javascript">
    function fun(){
        location.href='./P83 Server receiving data.php?ch=88&ma=55'
    }
</script>
<input type="button" value="点击" onclick="location.href='./P83 Server receiving data.php?ch=99&ma=55'"><br>
<?php 
if (!empty($_GET)) {
    echo '这是get提交的数据'.'<br>';
    echo '语文:'.$_GET['ch'].'<br>';
    echo '数学:'.$_GET['ma'].'<br>';
    echo '<hr>';
    echo '语文:'.$_REQUEST['ch'].'<br>';
    echo '数学:'.$_REQUEST['ma'].'<br>';
}
 ?>
</body>
</html>

 

思考题:

在一个请求中既有get又有post,get和post传递的名字一样的时候,通过$_REQUEST获取的数据是什么?

答案:取决于配置文件php.ini 先获取get的值 再获取post的值

 

例题:

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>REQUEST</title>
</head>
<body>
<form action="P80 Request.php?username=berry" method="post" accept-charset="utf-8">
<input type="text" name="username" value="" placeholder="">
<input type="submit" name="button" value="提交">
</form>
// 分析:先获取get的username 再获取post的username 后面的值将前面的值覆盖
<?php 
if (!empty($_POST)) {
    echo 'name:'.$_REQUEST['username'].'<br>';
}
 ?>
</body>
</html>

小结:

1、在开发的时候,如果明确是post提交就用$_POST获取数据, get同理

2、request获取效率低,尽可能不要使用,除非提交的类型不确定的情况才能使用

1.5 参数传递

1.5.1 复选框的传递

复选框的命名要注意带 [ ](英文输入法)!!!

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
    <title>参数传递</title>
</head>
<body>
<form action=" " method="post" accept-charset="utf-8">
爱好: <input type="checkbox" name="hobby[]" value="爬山">爬山
      <input type="checkbox" name="hobby[]" value="抽烟">抽烟
      <input type="checkbox" name="hobby[]" value="喝酒">喝酒
      <input type="checkbox" name="hobby[]" value="烫头">烫头
      <input type="submit" name="button" value="提交">    
</form>
<hr>
<?php 
if (isset($_POST['button'])) {
    //var_dump($_POST);
    echo '<br>';
    print_r($_POST['hobby']) ;
}
 ?>

运行结果:

 

小结:

1、表单提交到本页面需要判断一下是否有POST提交

2、数组的提交表单元素名字必须带有[ ]

1.5.2例题

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
    <title>参数传递</title>
</head>
<body>
<form action=" " method="post" accept-charset="utf-8">
姓名: <input type="text" name="username" value="" placeholder="请输入你的用户名"> <br/>
密码: <input type="password" name="pwd" value="" placeholder="请输入你的密码"> <br/>
性别: <input type="radio" name="sex" value="男" placeholder="" checked="男"> 男
    <input type="radio" name="sex" value="女" placeholder=""> 女 <br>
爱好: <input type="checkbox" name="hobby[]" value="爬山">爬山 
    <input type="checkbox" name="hobby[]" value="抽烟">抽烟
    <input type="checkbox" name="hobby[]" value="喝酒">喝酒
    <input type="checkbox" name="hobby[]" value="烫头">烫头<br>
籍贯:
    <select name="jiguan" >
        <option value="上海">上海</option>
        <option value="北京">北京</option>
    </select><br>
留言: <textarea name="words" rows="5"  cols="30"></textarea>
    <input type="submit" name="button" value="提交">  
</form>
<hr>
<?php 
if (isset($_POST['button'])) {
    var_dump($_POST);
    echo '<hr>';
    echo '姓名:'.$_POST['username'].'<br>';
    echo '密码:'.$_POST['pwd'].'<br>';
    echo '性别:'.$_POST['sex'].'<br>';
    echo '爱好:'.(isset($_POST['hobby'])?implode(',', $_POST['hobby']):'没有爱好'.'<br>');
    echo '籍贯:'.$_POST['jiguan'].'<br>';
    echo '留言:'.$_POST['words'];
    echo '<hr>';
    print_r(isset($_POST['hobby'])?$_POST['hobby']:'没有爱好'.'<br>');
}
    
 ?>
</body>
</html>

运行结果:

 

1.6 文件上传

开发中需要上传图片、音乐、视频等等,这种上传是二进制数据

1.6.1 客户端上传文件

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>文件上传</title>
</head>
<body>
<form action="" method="post" enctype="application/x-www-form-urlencoded">
    //将表单中的数据转成xml一起提交 这个只能传输字符串 带格式的xml文档
<input type="file" name="" >
</form>
    <form action="" method="post" enctype="multipart/form-data">
    //既能传字符串也能传二进制
<input type="file" name="" >
</form>
</form>
    <form action="" method="post" enctype="text/plain">
    //类似记事本样的字符串 不带格式那种 主要用来做电子邮件
<input type="file" name="" >
</form>
</body>
</html>

 

补充:xml和html的区别

<username>tom</username>
<sex>a</sex>
xml和html的唯一区别在于 xml可以自定义而html是定义好的
xml叫可扩展标签 好像标签也是成对出现的

表单的enctype属性

默认情况下,表单传递的是字符流,通过设置表单的enctype属性传递复合数据

enctype属性的值有:
​
1.application/x-www-form-urlencoded:【默认的】表示传递的是带格式的文本数据
​
2.multipart/form-data: 复合的表单数据 【字符串,文件】文件上传必须设置此值
​
3.text/plain: 用于向服务器传递无格式的文本数据,主要用于用户电子邮件,速度快效率高

单词

multipart:复合
form-data:表单数组

1.6.2 服务器接收文件

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>$_FIlES</title>
</head>
<body>
<?php 
if(!empty($_POST)){
    echo '<pre>';
    print_r($_FILES);
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="image" ><br>
<input type="submit" name="button" value="提交">
</form>
</body>
</html>

 

超全局变量$_FILES是一个二维数组,用来保存客户端上传到服务器的文件信息。二维数组的行是文件域的名称,列有5个。

1、$_FILES[]['name']     #上传的文件名
2、$_FILES[]['type']     #上传的文件类型,这个类型是MIME类型(image/jpeg image/gif image/png)
3、$_FILES[]['size']     #文件的大小,以字节为单位
4、$_FILES[]['tmp_name'] #文件上传时候的临时文件
5、$_FILES[]['error']    #错误编码(值有0、1、2、3、4、6、7)0表示正确
$_FILES[]['error']详解
值   错误描述
0    正确
1    文件大小超过了php.ini中的最大值
2    文件大小超过了表单允许的最大值
3    只有部分上传
4    没有文件上传
6    找不到临时文件
7    文件写入失败

 
**注意:MAX_FILE_SIZE必须在文件域的上面**!!! 我这里写错了 
​
**只要掌握的错误号:0和4**

 

1.6.3 将上传文件移动到指定位置

move_uploaded_file

也就是说也有可能是不用http post也可以上传文件的 具体方法我不太了解 以后知道了再补充上 

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>$_FIlES</title>
</head>
<body>
<?php 
if(!empty($_POST)){
if ($_FILES['image']['error']==0) {
    echo $_FILES['image']['error'].'<br>';
    move_uploaded_file($_FILES['image']['tmp_name'], './'.$_FILES['image']['name']);
}else{
    echo '上传有误';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<!-- <input type="hidden" name="MAX_FILE_SIZE" value="2"> -->
<input type="file" name="image" ><hr>
<input type="submit" name="button" value="提交">
</form>
</body>
</html>

小结上传的同名文件会被覆盖 所以需要对文件进行重命名

1.6.4 与文件上传有关的配置

post_max_size = 8M: 表单允许的最大值
​
upload_max_filesize = 2M: 允许上传的文件大小
​
upload_tmp_dir = E:\wamp\wamp\www\f.com\tmp : 指定临时文件地址,如果不知道操作系统指定
​
file_uploads = On : 是否允许文件上传
​
max_file_uploads = 20 : 允许同时上传20个文件

1.7 优化文件上传

1.7.1 更改文件名

方法一:通过时间戳做文件名

<?php 
$path='face.jpg';
$b= time();
echo '<hr>';
$a=strrchr($path, '.'); //从右边开始第一个.开始截取到最后
echo $b.rand(111,999).$a;
?>
//输出结果:1650032734405.jpg

方法二:通过uniqid()实现

$path='face.stu.jpg';
echo uniqid().strrchr($path, '.').'<br>';               //生成唯一的id
echo uniqid('goods_').strrchr($path, '.').'<br>';       //带有前缀
echo uniqid('goods_',true).strrchr($path, '.').'<br>';  //唯一ID+随机数

1.7.2验证文件格式

方法一:判断文件的扩展名(不能识别文件伪装)

操作思路:将允许的文件后缀和上传的文件后缀做对比

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>验证格式</title> 
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<!-- <input type="hidden" name="MAX_FILE_SIZE" value="2"> -->
<input type="file" name="image" ><hr>
<input type="submit" name="button" value="提交">
</form>
<?php 
if (!empty($_POST)) {
    // echo '<pre>';
    // print_r($_FILES);
    $a=strrchr($_FILES['image']['name'], '.');  
    echo $a;
    $allow=array('.jpg','.png','.gif');     //允许的扩展名
    if (in_array($a,$allow)) {
        echo '上传成功';
    }else{
        echo  '上传失败';
    }
}
 ?>
</body>
</html>

上传图片木马成功 白名单的话还可以考虑0x00截断

 

方法二:通过$_FILES比较mime类型(不能防止文件伪装)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>验证格式</title> 
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<!-- <input type="hidden" name="MAX_FILE_SIZE" value="2"> -->
<input type="file" name="image" ><hr>
<input type="submit" name="button" value="提交">
</form>
<?php 
if (!empty($_POST)) {
    // echo '<pre>';
    // print_r($_FILES);
    $a=$_FILES['image']['type'];    
    echo $a.'<br>';
    $mime=array('image/jpeg','image/png','image/gif');      //允许的扩展名
    if (in_array($a,$mime)) {
        echo '上传成功';
    }else{
        echo  '上传失败';
    }
}
 ?>
</body>
</html>

上传一个伪装成jpg的php文件可以成功上传 你懂我意思吧 

方法三:开启php_fileinfo扩展(可以防止文件伪装)

 

注意:开启fileinfo扩展以后就可以使用finfo*开头的函数了

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>验证格式</title> 
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<!-- <input type="hidden" name="MAX_FILE_SIZE" value="2"> -->
<input type="file" name="image" ><hr>
<input type="submit" name="button" value="提交">
</form>
<?php 
if (!empty($_POST)) {
    // echo '<pre>';
    // print_r($_FILES);
    // 第一步:创建finfo资源
    $info=finfo_open(FILEINFO_MIME_TYPE);
    var_dump($info);
    echo '<hr>';
    //var_dump($info).'<br>';
    // 第二步:将info资源和文件做比较
    $mime=finfo_file($info,$_FILES['image']['tmp_name']);
    echo $mime.'<br>';
    // 第三步:比较是否合法
    $allow=array('image/jpeg','image/png','image/gif');
    echo in_array($mime,$allow)?'allow':'not allow';
    $a=$_FILES['image']['type'];    
    echo $a.'<br>';
    $mime=array('image/jpeg','image/png','image/gif');      //允许的扩展名
    if (in_array($a,$mime)) {
        echo '上传成功';
    }else{
        echo  '上传失败';
    }
}
 ?>
</body>
</html>

上传一个伪装为jpg的php文件无法成功 

 

但是上传一个图片木马可以成功

 

小结:fileinfo_file()并不安全

 

1.7.3 优化文件上传例题

步骤:

1、验证是否有误

2、验证格式

3、验证大小

4、验证是否是http上传

 

5、上传实现

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>文件上传验证</title>   
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="img" ><hr>
<input type="submit" name="button" value="提交">
</form>
<?php 
 // 验证错误
function check($file){
    $error=$file['error'];
    if ($error!==0) {
        switch ($error) {
            case '1':
                echo'文件大小超过了php.ini中的最大值,最大值是:'.ini_get_all('upload_max_filesize');# code...
                return false;
            case '2':
                echo'文件大小超过了表单允许的最大值';# code...
                return false;
            case '3':
                echo' 只有部分上传';# code...
                return false;
            case '4':
                echo'没有文件上传';# code...
                return false;   
            case '6':
                echo'找不到临时文件';# code...
                return false;
            case '7':
                echo'文件写入失败';# code...
                return false;       
            default:
                echo '未知错误';
                return false;
        }
    }
    // 2、验证格式
$info=finfo_open(FILEINFO_MIME_TYPE);
$mime=finfo_file($info,$file['tmp_name']);
$allow=array('image/jpeg','image/png','image/gif');
$a=array('jpeg','png','gif');
 if (!in_array($mime,$allow)) {
    echo '只能上传'.implode('/', $a);
    return false;
    }
    // 3、验证大小
$size=999999;
if ($file['size']>$size) {
    echo '文件大小超过'.number_format($size/1024,1).'K';
}
    //4 、验证是否是HTTP上传
    if (!is_uploaded_file($file['tmp_name'])) {
        return '文件不是http post 上传的';
    }
    echo  '文件上传成功';
}
//表单提交
if (!empty($_POST)) {
// 验证是否有错误
    if ($error=check($_FILES['img'])) {
         echo $error;
    }else{
//文件上传,上传的文件保存在当天的文件夹中
     $foldername=date('Y-m-d');
     $folderpath="./uploads/{$foldername}";
     if (!is_dir($folderpath))
     mkdir($folderpath);
     $filename=uniqid(' ',true).strrchr($_FILES['img']['name'], '.');
     $filepath="$folderpath/$filename";
     if (move_uploaded_file($_FILES['img']['tmp_name'], $filepath))
     echo "上传成功,路径是:{$foldername}/{$filename}";
    else 
        echo '上传失败';
    }
}
 ?>
</body>
</html>

 

小结:

1、将时间戳转换格式

echo date('Y-m-d H:i:s',1231346).'<br>';        #将时间戳转换为年-月-日 小时-分钟-秒
echo date('Y-m-d H:i:s');                      #将当前时间转换成年-月-日 小时-分钟-秒

2、设置时区

 

3、PHP的执行可以不需要Apache的参与 可以在本地运行文件

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值