一.前言
本章节继续来讲解php,前面讲解了一些php的基础语法,本章节继续来讲解一下php,主要是来讲解php中的流程控制和函数。
二.流程控制
2.1 if
<?php
header("Content-Type: text/html; charset=utf-8");
$a = rand(1, 10);
if ($a > 5) {
echo "随机点数比较大";
}
echo "<br>";
echo "当前的点数是" . $a;
?>
2.2 else
<?php
header("Content-Type: text/html;charset=utf-8");
$user = $_POST["username"];
$pass = $_POST["password"];
if ($user == 'admin' and $pass == '123456'){
echo "登录成功";
}else{
echo "登录失败";
}
?>
当然这个需要我们写一个form表单来实现前后端交互
2.3 elseif/else if
<?php
$jixiao = 'F'; // 绩效等级初始化
if ($jixiao == 'A') {
echo "发放1.2倍薪资";
} elseif ($jixiao == 'B') {
echo "正常发放薪资";
} elseif ($jixiao == 'C') {
echo "发放90%薪资";
} else {
echo "发放80%薪资"; // 当前执行分支
}
?>
2.4 while
条件不成立,一次都不执行
<?php
$i = 1;
while ($i <= 10) {
echo '哈哈'.$i.'次'.'<br>';
$i++;
}
?>
2.5 do-while
条件不成立,也会执行一次
<?php
$i = 0; // 初始化计数器为0
do {
echo $i; // 先执行输出(此时$i=0)
} while ($i > 0);// 后检查条件(0>0为false)
?>
2.6 for
有限循环
<?php
#$i=1初始值,$i<=10 条件,$i++每次加1
for ($i = 1; $i <= 10; $i++) {
echo $i;
}
?>
2.7 foreach
遍历数组
<?php
# 属组的索引默认是从0开始的数字,也可以自行指定索引
$cars = array(
"特等奖" => "布加迪",
"一等奖" => "捷豹",
"二等奖" => "法拉利",
"三等奖" => "玛莎拉蒂"
);
foreach ($cars as $key => $value) {
echo "<tr><td>$key</td><td></td><td>$value</td><td></tr>";
}
?>
2.8 break 打断
打断循环;结束循环
<?php
$cars = array(
"特等奖" => "布加迪",
"一等奖" => "捷豹",
"二等奖" => "法拉利",
"三等奖" => "玛莎拉蒂",
"四等奖" => "迈凯伦"
);
foreach ($cars as $key => $value) {
if ($key == '三等奖') {
break;
} else {
echo $key."是".$value."<br>";
}
}
?>
2.9 continue 继续
跳出本轮,开始下一轮
<?php
$cars = array(
"特等奖" => "布加迪",
"一等奖" => "捷豹",
"二等奖" => "法拉利",
"三等奖" => "玛莎拉蒂",
"四等奖" => "迈凯伦"
);
foreach ($cars as $key => $value) {
if ($key == '三等奖') {
continue;
} else {
echo $key."是".$value."<br>";
}
}
?>
2.10 switch
条件判断
<?php
$a = 5;
$b = 10;
$c = 4;
switch ($c) {
case 1:
echo "$a + $b = " . ($a + $b) . "<br>";
break;
case 2:
echo "$a - $b = " . ($a - $b) . "<br>";
break;
case 3:
echo "$a * $b = " . ($a * $b) . "<br>";
break;
case 4:
echo "$a / $b = " . ($a / $b) . "<br>";
break;
default: // 条件都不成立时执行
echo '原来啥也不是';
break;
}
?>
三.PHP的函数
介绍:
函数的英文叫作:function,而function的解释项中有另外一个含义:功能,函数就是功能,比如我们 发微信,可能发微信这个后台代码逻辑就是一个函数,将整体的发微信的逻辑代码封装到了函数中,调 用并执行这个函数,就能够实现发微信的动作。
3.1 语法
<?php
header("Content-Type: text/html;charset=utf-8");
// 欢迎函数
function welcom() {
echo "欢迎光临!";
}
// 调用欢迎函数
welcom();
echo '<br>做一下加法计算!<br>';
// 第一个add函数(直接输出版)
function add($a, $b) {
$c = $a + $b;
echo '加法计算结果为:'.$c.'<br>';
}
// 调用第一个add函数
add(3, 4);
echo '计算结束...<br>';
// 第二个add函数(返回值版)
function add1($a, $b) {
$c = $a + $b;
return $c;
}
// 调用第二个add函数
$ret = add1(3, 4);
echo $ret.'<br>';
echo '计算结束...<br>';
?>
3.2 内置函数
3.2.1 文件包含的函数
根据您提供的PHP文件包含函数对比表格,以下是核心知识点总结:
📌 PHP文件包含函数对比表
函数 | 包含失败时的表现 | 主要特点 |
---|---|---|
include | 返回警告 | 脚本继续执行,适合动态包含(如根据条件包含不同文件) |
require | 产生致命错误 | 脚本终止执行,适合包含核心文件(如数据库配置等必须文件) |
include_once | 返回警告 | 在include基础上增加重复包含检查,避免函数/类重定义 |
require_once | 产生致命错误 | 在require基础上增加重复包含检查,适合必须且只需包含一次的重要文件 |
🔍 使用建议:
- 动态内容包含 → 选择include(如:
include 'header_'.$lang.'.php'
) - 关键文件包含 → 选择require(如:
require 'database_config.php'
) - 避免重复包含 → 带_once版本(特别是类和函数定义文件)
💡 典型应用场景:
// 场景1:模板系统(允许失败)
include 'templates/'.$_GET['page'].'.php';
// 场景2:数据库配置(必须成功)
require 'config/database.php';
// 场景3:函数库(只需加载一次)
require_once 'lib/functions.php';
⚠️ 注意:
- 包含路径建议使用
__DIR__
绝对路径(如:require __DIR__.'/config.php'
) - 生产环境应关闭错误显示,改用错误日志记录包含失败情况
3.2.2 数学常用函数
我们简单学几个即可:abs()、ceil()、floor()、round()、max()、min()、rand()。
函数名 | 描述 | 实例 | 输入参数 | 输出结果 |
---|---|---|---|---|
abs() |
求绝对值 | $abs = abs(-4.2); // 4.2 |
数字(整型/浮点) | 绝对值数字 |
ceil() |
进一法取整 | echo ceil(9.001); // 10 |
浮点数 | 向上取整后的整数 |
floor() |
舍去法取整 | echo floor(9.999); // 9 |
浮点数 | 向下取整后的整数 |
fmod() |
浮点数取余 | $r = fmod(5.7, 1.3); // 0.5 |
被除数, 除数(x>y) | 浮点余数 |
pow() |
返回数的n次方 | echo pow(-1, 20); // 1 |
基数, 指数 | 乘方值 |
round() |
浮点数四舍五入 | echo round(1.95583, 2); // 1.96 |
数值, [可选精度] | 按精度舍入后的结果 |
sqrt() |
求平方根 | echo sqrt(9); // 3 |
被开方数(≥0) | 平方根值 |
max() |
求最大值 | echo max(1,3,5,6,7); // 7 |
数字或数组 | 最大值 |
min() |
求最小值 | echo min([2,4,5]); // 2 |
数字或数组 | 最小值 |
mt_rand() |
生成更好的随机数 | echo mt_rand(0,9); // 0~9随机整数 |
[最小值], 最大值 | 范围内的随机整数 |
rand() |
生成随机数 | echo rand(); // 随机整数 |
[最小值], 最大值 | 随机整数 |
pi() |
获取圆周率值 | echo pi(); // 3.1415926535898 |
无 | 圆周率常量 |
3.2.3 字符串常用函数
1. 基础处理
函数名 | 描述 | 示例 |
---|---|---|
trim() |
删除两端空格/指定字符 | $str="\nHello \n"; echo trim($str); → "Hello" |
ltrim() |
删除左侧空格/指定字符 | echo ltrim("\tHello"); → "Hello" |
rtrim() |
删除右侧空格/指定字符 | echo rtrim("Hello \n"); → "Hello" |
strlen() |
返回字符串长度 | echo strlen("中文"); → 6 (字节数) |
mb_strlen() |
多字节字符串长度 | echo mb_strlen("中文","UTF-8"); → 2 |
strrev() |
反转字符串 | echo strrev("Hello"); → "olleH" |
2. 大小写转换
函数名 | 描述 | 示例 |
---|---|---|
strtolower() |
转为小写 | echo strtolower("HELLO"); → "hello" |
strtoupper() |
转为大写 | echo strtoupper("hello"); → "HELLO" |
ucfirst() |
首字母大写 | echo ucfirst("hello"); → "Hello" |
ucwords() |
每个单词首字母大写 | echo ucwords("hello world"); → "Hello World" |
3. 截取与分割
函数名 | 描述 | 示例 |
---|---|---|
substr() |
截取字符串 | echo substr("Hello",1,3); → "ell" |
mb_substr() |
多字节安全截取 | echo mb_substr("中文",0,1,"UTF-8"); → "中" |
str_split() |
将字符串转为数组 | print_r(str_split("Hi",1)); → Array([0]=>'H',[1]=>'i') |
explode() |
按分隔符拆分字符串 | print_r(explode(",","a,b,c")); → Array([0]=>'a',[1]=>'b',[2]=>'c') |
implode() |
将数组连接成字符串 | echo implode("-",[1,2,3]); → "1-2-3" |
chunk_split() |
按长度分割字符串 | echo chunk_split("123456",2,"-"); → "12-34-56-" |
4. 查找与替换
函数名 | 描述 | 示例 |
---|---|---|
strpos() |
查找首次出现位置(区分大小写) | echo strpos("Hello","e"); → 1 |
stripos() |
查找首次位置(不区分大小写) | echo stripos("Hello","E"); → 1 |
str_replace() |
替换字符串(区分大小写) | echo str_replace("a","*","abc"); → "*bc" |
str_ireplace() |
替换字符串(不区分大小写) | echo str_ireplace("A","*","abc"); → "*bc" |
substr_replace() |
替换子串 | echo substr_replace("world","Hello ",0,0); → "Hello world" |
substr_count() |
统计子串出现次数 | echo substr_count("abab","ab"); → 2 |
5. 编码与安全
函数名 | 描述 | 示例 |
---|---|---|
htmlentities() |
转义HTML实体 | echo htmlentities("<div>"); → "<div>" |
htmlspecialchars() |
转义特殊字符 | echo htmlspecialchars("'"); → "'" |
addslashes() |
转义引号 | echo addslashes("I'm"); → "I'm" |
stripslashes() |
去除转义符 | echo stripslashes("I\'m"); → "I'm" |
md5() |
生成MD5哈希 | echo md5("123"); → "202cb962ac59075b964b07152d234b70" |
iconv() |
字符编码转换 | echo iconv("GBK","UTF-8","中文"); → UTF-8编码的中文字符 |
6. 多字节字符串处理
函数名 | 描述 | 示例 |
---|---|---|
mb_strlen() |
安全获取字符串长度 | echo mb_strlen("中文","UTF-8"); → 2 |
mb_substr() |
安全截取多字节字符串 | echo mb_substr("中文",0,1,"UTF-8"); → "中" |
mb_http_output() |
设置HTTP输出编码 | mb_http_output("UTF-8"); |
mb_check_encoding() |
验证编码有效性 | var_dump(mb_check_encoding("中文","GB2312")); → bool(true/false) |
3.2.4 时间日期函数
中国的时区在东八区。时间相关函数:date()、getdate()、time(),我们就说一下这三个吧。
<!--$d = date('Y-m-d H:i:s'); # 格式化时间日期的-->
<!--$d = date('Y-m-d H:i:s', 1661910865); # 通过某个时间戳来格式化时间-->
<!--$t = time(); # 获取当前时间戳-->
<?php
// 时区的报错,修改php.ini,date.timezone = Asia/Shanghai
$mytime = getdate(); // 得到当前时间日期的一个属组
// $mytime = getdate(1661910865); // 通过时间戳获取日期属组(注释状态)
echo "年 :".$mytime['year']."<br>";
echo "月 :".$mytime['mon']."<br>";
echo "日 :".$mytime['mday']."<br>";
echo "时 :".$mytime['hours']."<br>";
echo "分 :".$mytime['minutes']."<br>";
echo "秒 :".$mytime['seconds']."<br>";
echo "一个小时中的第几钟 :".$mytime['minutes']."<br>";
echo "这是一分钟的第几秒 :".$mytime['seconds']."<br>";
echo "星期名称 :".$mytime['weekday']."<br>";
echo "月份名称 :".$mytime['month']."<br>";
echo "时间戳 :".$mytime[0]."<br>";
?>
3.2.5 数组常用函数
主要是数组元素的增删改查操作。
<?php
header("Content-Type: text/html;charset=utf-8"); // 在响应头中添加了content-type:utf-8,header()是php提供的加工响应头键值对的
$a = array('aa', 'bb', 33, 55);
echo $a[0] . '<br>';
echo var_dump($a) . '<br>';
$a[5] = 'kk';
echo var_dump($a) . '<br>';
$a[1] = 'cc';
echo var_dump($a) . '<br>';
// unset()删除
unset($a[1]);
echo var_dump($a) . '<br>';
?>
其他数组常用函数:
1. 数组操作基础
函数名 | 描述 | 示例 | 重要度 |
---|---|---|---|
unset() |
删除指定元素 | unset($arr['key']); |
★★★ |
count() |
计算数组元素个数 | count($arr); |
★★★ |
array_keys() |
返回所有键名组成的新数组 | array_keys($arr); |
★★ |
array_values() |
返回所有值组成的新数组 | array_values($arr); |
★★ |
2. 元素查找判断
函数名 | 描述 | 示例 |
---|---|---|
in_array() |
判断值是否存在 | in_array('a', $arr); |
array_key_exists() |
检查键名是否存在 | array_key_exists('k',$arr); |
array_search() |
搜索值并返回对应键名 | array_search('v',$arr); |
3. 数组生成与填充
函数名 | 描述 | 示例 |
---|---|---|
range() |
生成范围数组 | range(1,5); → [1,2,3,4,5] |
array_fill() |
填充指定长度的数组 | array_fill(0,3,'x'); |
array_combine() |
合并两个数组(键+值) | array_combine($keys,$vals); |
4. 数组排序
函数名 | 排序方式 | 特点 |
---|---|---|
sort() |
值升序(不保键) | 重置键名 |
asort() |
值升序(保键) | 保持键值对应 |
ksort() |
键名升序排序 | 按键名字典序 |
natsort() |
自然排序(大小写敏感) | 适合含数字的字符串 |
5. 高级操作
函数名 | 描述 | 典型应用 |
---|---|---|
array_slice() |
截取数组片段 | array_slice($arr,2,3); |
array_splice() |
替换数组片段 | array_splice($arr,1,2,$new); |
array_filter() |
过滤空值/指定值 | array_filter($arr); |
array_sum() |
计算数值数组的和 | array_sum([1,2,3]); → 6 |
6. 特殊处理
函数名 | 功能 | 注意点 |
---|---|---|
shuffle() |
随机打乱数组 | 会破坏键名 |
array_rand() |
随机返回键名 | 返回键名而非值 |
extract() |
将数组键转为变量名 | 慎用,可能覆盖已有变量 |
3.2.6 PHP文件和目录操作
<?php
// readfile() 读取文件内容,并返回文件的长度
$a = readfile('1.txt');
echo '<br>';
echo $a; // 输出文件长度
// 写入数据示例
$a = 'aabbkkdd';
file_put_contents('1.txt', $a); // 没有文件会自动创建
$b = 'ooooo';
file_put_contents('1.txt', $b); // 每次写入新数据都会先清空原文件数据
// 读取文件内容示例
$a = file_get_contents('1.txt');
// 读取远程图片内容(需配置SSL)
$a = file_get_contents('http://www.baidu.com/img/flexible/logo/pc/result.png');
// 配置说明注释:
// 1. windows下的PHP,到php.ini中把 extension=php_openssl.dll 前面的;删掉,重启服务
// 2. linux下的PHP,必须安装openssl模块
// 将远程文件保存到本地(注释状态)
// file_put_contents('1.txt', $a);
echo $a;
?>
3.2.7 fopen
fopen、fread、fwrite、fclose操作读取文件。
resource fopen ( string $文件名, string 模式)
string fread ( resource $操作资源(也就是文件路径), int 读取长度)
bool fclose ( resource $操作资源 )
注:resource 、string、bool表示的是方法的返回值 。
fopen的模式有下面几个,我们来讲一下fopen的模式: 带+号的先pass
模式 | 读写权限 | 指针位置 | 文件不存在时 | 文件存在时 | 典型应用场景 |
---|---|---|---|---|---|
r |
只读 | 文件头 | 返回false |
正常打开 | 读取配置文件、日志分析 |
r+ |
读写 | 文件头 | 返回false |
正常打开 | 需要修改文件开头内容 |
w |
只写 | 文件头 | 尝试创建 | 清空内容 | 创建新日志文件、覆盖旧数据 |
w+ |
读写 | 文件头 | 尝试创建 | 清空内容 | 需要完全重写文件 |
a |
只写(追加) | 文件末尾 | 尝试创建 | 保留内容,追加写入 | 日志记录、持续数据收集 |
a+ |
读写(追加) | 文件末尾 | 尝试创建 | 保留内容,可读可追加 | 需要读取历史日志并追加新记录 |
x |
只写(独占) | 文件头 | 尝试创建 | 返回false |
防止文件覆盖的锁机制 |
x+ |
读写(独占) | 文件头 | 尝试创建 | 返回false |
需要独占读写权限的场景 |
实例:
<?php
// 以只读模式打开文件
$a = fopen('1.txt', 'r');
// 被注释的读取方式(按字节读取)
#$b = fread($a, 18);
// 逐行读取文件内容
$b = fgets($a);
echo $b . "<br>";
// 循环读取剩余内容
while(!feof($a)) { // !feof($a)表示如果读到文件最后了
$b = fgets($a);
echo $b . "<br>";
}
// 尝试写入内容(会失败)
$b = fwrite($a, 'aaaaa'); // 失败返回false,成功返回写入的字符个数
echo $b . "<br>";
// 写入结果判断
if ($b == false) {
echo '写入失败'; // r模式打开的文件不能写入,r+模式可以写,但是会从文件内容开头覆盖原有内容
}
// 被注释的关闭操作
#fclose($a);
?>
3.2.8 PHP目录处理函数
处理文件夹的基本思想如下:
1.读取某个路径的时候判断是否是文件夹
2.是文件夹的话,打开指定文件夹,返回文件目录的资源变量
3.使用readdir读取一次目录中的文件,目录指针向后偏移一次
4.使用readdir读取到最后,没有可读的文件返回false
5.关闭文件目录
我们来学习一比常用函数:
函数名 | 功能描述 | 返回值 | 使用示例 |
---|---|---|---|
scandir() |
获取目录下所有文件和子目录 | 数组(按字母序排序) | $items = scandir('/path'); → 包含. 和.. 的条目数组 |
opendir() |
打开目录句柄 | 资源类型 | $handle = opendir('/path'); → 需配合readdir() 使用 |
readdir() |
从目录句柄读取条目 | 字符串(文件名) | while($file=readdir($handle)){...} → 需手动过滤. 和.. |
is_dir() |
判断是否为目录 | 布尔值 | if(is_dir('/path')){...} → 常用于递归遍历时判断 |
closedir() |
关闭目录句柄 | 无 | closedir($handle); → 防止资源泄漏 |
filetype() |
获取文件类型 | 'file'或'dir' | echo filetype('/path'); → 比is_dir() 更直观但性能略低 |
例如:列举当前目录列表
<?php
// 获取当前脚本所在目录的绝对路径
$a = dirname(__FILE__); // 等价于 __DIR__ (PHP 5.3+)
echo '<br>';
// 读取目录内容(包含.和..)
$b = scandir($a);
var_dump($b); // 打印完整目录数组
// 遍历目录项
foreach ($b as $key => $filename) {
// 跳过当前目录(.)和上级目录(..)
if ($filename == '.' || $filename == '..') {
continue;
}
echo $filename . "<br>"; // 输出有效文件名
}
// 检查指定文件类型
filetype($a . '\wp'); // 判断wp文件/目录类型
filetype($a . '\1.txt'); // 判断1.txt文件类型
?>
3.2.9 PHP创建临时文件
我们之前创建的文件都是永久文件。
而创建临时文件在我们平时的项目开发中也非常有用。创建临时文件的几个好处:用完后即删除,不需 要去维护这个文件的删除状态。
<?php
// 创建临时文件(自动生成唯一文件名)
$handle = tmpfile(); // 返回文件句柄资源
// 写入UTF-8数据(1个中文字符占3字节)
$numbytes = fwrite($handle, '写入临时文件'); // 返回写入的字节数
// 调试时可取消注释观察临时文件
// sleep(60); // 暂停60秒(此时文件可被其他进程查看)
// 关闭即自动删除(无持久化存储)
fclose($handle);
// 输出结果:中文+英文字符共15字节
echo '向临时文件中写入了'.$numbytes.'个字节';
// Windows存储路径:C:\Users\用户名\AppData\Local\Temp\phpXXXX.tmp
?>
3.2.10 PHP移动、拷贝和删除文件
重命名
我们日常在处理文件的时候,可以删除文件、重命名文件也可以也可复制文件。
我们先来说重命名,重命名的函数是: bool rename($旧名,$新名); ,方法的返回结果是布尔值。
这个函数返回一个bool值,将旧的名字改为新的名字。
<?php
// 定义原始文件名
$filename = 'test.txt';
// 生成新文件名(追加.xx后缀)
$filename2 = $filename . '.xx';
// 重命名文件(同级目录)
rename($filename, $filename2);
// 移动文件到xx目录并重命名
rename($filename, '\\xx\\' . $filename2);
?>
复制文件
复制文件,就相当于是克隆技术,将一个原来的东西再克隆成一个新的东西。两个长得一模一样。 boolcopy(源文件,目标文件)
功能:将指定路径的源文件,复制一份到目标文件的位置。
我们来通过实验和代码来玩玩:
<?php
// 旧文件名定义
$filename = '1.txt';
// 新文件名生成(追加_new后缀)
$filename2 = $filename . '_new';
// 执行文件复制操作
copy($filename, $filename2);
?>
总结:你会通过上面的例子,发现多出来了一个文件。
删除文件
删除文件就是将指定路径的一个文件删除,不过这个删除是直接删除。使用的是windows电脑,你在回 收站看不到这个文件。你只会发现,这个文件消失了。 bool unlink(指定路径的文件)
<?php
// 定义要删除的文件名
$filename = '1.txt';
// 执行文件删除操作并返回结果
if (unlink($filename)) {
echo "删除文件成功 $filename!\n";
} else {
echo "删除 $filename 失败!\n";
}
?>
检测文件属性
比如,检测一下xx.txt文件是否存在
<?php
if(file_exists('index.html')) {
echo '文件已存在';
exit;
}
?>
常用文件属性函数
函数名 | 参数类型 | 返回值 | 功能描述 | 使用示例 |
---|---|---|---|---|
file_exists() |
字符串(路径) | bool | 检测文件/目录是否存在 | file_exists('/var/www/test.php') |
is_readable() |
字符串(路径) | bool | 检测文件是否可读 | is_readable('config.ini') |
is_writeable() |
字符串(路径) | bool | 检测文件是否可写 | is_writeable('log.txt') |
is_executable() |
字符串(路径) | bool | 检测文件是否可执行 | is_executable('app.sh') |
is_file() |
字符串(路径) | bool | 检测是否是普通文件 | is_file('data.json') |
is_dir() |
字符串(路径) | bool | 检测是否是目录 | is_dir('uploads/') |
clearstatcache() |
无 | void | 清除文件状态缓存 | clearstatcache() |
3.2.11 PHP文件权限设置
chmod 主要是修改文件的的权限。主要是针对linux系统的,这个我们前面学过,就不多说了。
<?php
// 修改Linux系统文件权限为755
chmod("/var/wwwroot/index.html", 755);
// 使用符号模式设置权限
chmod("/var/wwwroot/index.html", "u+rwx,go+rx");
// 八进制格式设置权限
chmod("/somedir/somefile", 0755);
?>
3.2.12 PHP文件路径函数
我们经常会遇到处理文件路径的情况。
例如:
1.文件后缀需要取出来
2.路径需要取出名字不取目录
3.只需要取出路径名中的目录路径
4.或者把网址中的各个部份进行解析取得独立值
5.甚至是自己组成一个url出来
... ....
很多地方都需要用路径处理类的函数。
我们把常用的路径处理函数为大家做了标注,大家对着这个路径处理函数进行处理即可:
函数名 | 功能描述 | 参数说明 | 返回值示例 |
---|---|---|---|
pathinfo() |
解析文件路径各组成部分 | (路径, [选项]) |
['dirname'=>'/a','basename'=>'b.txt'] |
basename() |
提取路径中的文件名 | (路径, [后缀过滤]) |
'image.jpg' (输入/a/b/image.jpg ) |
dirname() |
获取文件所在目录路径 | (路径) |
'/a/b' (输入/a/b/file.txt ) |
parse_url() |
分解URL为关联数组 | (URL) |
['scheme'=>'https', 'host'=>'example.com'] |
http_build_query() |
将数组转换为URL查询字符串 | (关联数组) |
'name=John&age=30' |
http_build_url() |
组装URL组件为完整URL | (基础URL, 组件数组) |
需安装pecl_http 扩展 |
示例,记住示例中的几个即可
<?php
// 解析文件路径信息
$path_parts = pathinfo('d:/www/index.inc.php');
// 输出各组成部分
echo '文件目录名:' . $path_parts['dirname'] . "<br/>";
echo '文件全名:' . $path_parts['basename'] . "<br/>";
echo '文件扩展名:' . $path_parts['extension'] . "<br/>";
echo '不包含扩展的文件名:' . $path_parts['filename'] . "<br/>";
?>
3.2.13 PHP文件上传
在web常见漏洞中有一个文件上传的漏洞,后面我们会讲到。
在我们日常使用中经常会遇到很多种这样的情况:
QQ空间里面上传图片呀
微信朋友圈上传图片
发邮件里面上传邮件资料附件
认证的时候要求上传照片或身份证
文件上传需要注意php.ini这个配置文件,这个文件我们在phpstudy中就能看到
只有 file_uploads = on 时,php才能支持上传文件
phpinfo()函数,也可以看到这些配置信息。
配置项 | 默认值 | 推荐值 | 功能说明 | 修改建议 |
---|---|---|---|---|
file_uploads |
on | on | 主开关:on开启文件上传功能,off禁用 | 生产环境必须保持on |
upload_tmp_dir |
系统临时目录 | 自定义路径 | 存储临时文件的目录(如:C:\Users\用户名\AppData\Local\Temp ) |
建议改为独立目录:upload_tmp_dir = /var/php_upload_tmp |
post_max_size |
8M | 200M | POST请求最大值(必须≥upload_max_filesize ) |
在php.ini中修改:post_max_size = 200M |
upload_max_filesize |
2M | 100M | 单个文件大小限制 | 需同步调整post_max_size :upload_max_filesize = 100M |
memory_limit |
128M | 256M | 脚本内存限制(处理大文件时需增加) | 根据服务器配置调整:memory_limit = 256M |
建议尺寸: file_size(文件大小) < upload_max_filesize < post_max_size < memory_limit
另外,需要注意的是脚本执行时间,max_execution_time配置,这个参数的单位为秒。它是设定脚本的 最大执行时间。也可以根据需求做适当的改变。通常不需要来修改,系统默认值即可。超大文件上传的 时候,可能会涉及到这一项参数的修改。上传时间太长了,会超时。如果你将此项参数设为0,则是不限 制超时时间,不建议使用,文件太大了,想别的方式处理,一般会分块传输 。
完成了php.ini的相关配置,我们就可以开始试着完成第一次文件上传了。别忘了重启服务。
通过php获取webserver相关配置信息的代码
<?php
// 设置响应头为UTF-8编码的HTML格式
header("Content-Type: text/html; charset=utf-8");
// 获取服务器和客户端信息
$a = $_SERVER['HTTP_HOST']; // 获取当前域名
$b = $_SERVER['HTTP_USER_AGENT']; // 获取用户浏览器信息
// 输出信息并换行
echo $a . '<br>';
echo $b . '<br>';
?>
上传文件步骤
1.系统返回的错误码详解
错误码 | 含义 | 原因分析 | 解决方案 |
---|---|---|---|
0 | 上传成功 | 文件通过所有验证 | 可继续执行move_uploaded_file() 等后续操作 |
1 | 超出upload_max_filesize |
文件大小超过php.ini中的全局限制(默认2M) | 修改php.ini:upload_max_filesize = 100M 需同步调整 post_max_size |
2 | 超出表单指定大小 | 超过<input type="file" name="file" max-size="500000"> 等表单限制 |
检查前端表单设置或后端验证逻辑 |
3 | 部分文件上传 | 网络中断或浏览器崩溃导致 | 重新上传或检查网络连接 |
4 | 无文件上传 | 用户未选择文件或表单未设置enctype="multipart/form-data" |
检查HTML表单属性:<form method="post" enctype="multipart/form-data"> |
6 | 临时目录缺失 | upload_tmp_dir 配置错误或权限不足 |
创建目录并设权限:mkdir /tmp/uploads; chmod 777 /tmp/uploads |
7 | 写入失败 | 磁盘空间不足/权限问题/文件名非法 | 检查磁盘空间:df -h 确保目标目录可写: chown -R www-data:www-data /uploads |
注:错误码中没有5。
2.自定义判断是否超出文件大小范围
在开发上传功能时。我们作为开发人员,除了php.ini中规定的上传的最大值外。我们通常还会设定一个 值,是业务规定的上传大小限制。
例如:
新浪微博或者QQ空间只准单张头像图片2M。而在上传图册的时候又可以超过2M来上传。
所以说,它的系统是支持更大文件上传的。
此处的判断文件大小,我们用于限制实际业务中我们想要规定的上传的文件大小。
3.判断后缀名和mime类型是否符合
在网络世界里面也有坏人。他们会把图片插入病毒,在附件中上传病毒,他们会在网页中插入病毒或者 黄色图片。
我们需要对于上传的文件后缀和mime类型都要进行判断才可以。
百度解释:MIME(Multipurpose Internet Mail Extensions)是多用途互联网邮件扩展类型。是设定 某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定 应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
通俗解释: 有兴趣看一看
其实MIME更像是一种协议。
首先,我们要了解浏览器是如何处理内容的。在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有Flash ......那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME Type,也就是 该资源的媒体类型。
媒体类型通常是通过 HTTP 协议,由 Web 服务器告知浏览器的,更准确地说,是通过 ContentType 来表示的,例如:
Content-Type: text/HTML
表示内容是 text/HTML 类型,也就是超文本文件。为什么是"text/HTML"而不是"HTML/text"或者 别的什么?MIME Type 不是个人指定的,是经过 ietf 组织协商,以 RFC 的形式作为建议的标准发布在网 上的,大多数的 Web 服务器和用户代理都会支持这个规范 (顺便说一句,Email 附件的类型也是通过MIME Type 指定的)。
通常只有一些在互联网上获得广泛应用的格式才会获得一个 MIME Type,如果是某个客户端自己定义的 格式,一般只能以 application/x- 开头。
XHTML 正是一个获得广泛应用的格式,因此,在 RFC 3236 中,说明了 XHTML 格式文件的 MIME Type 应该是 application/xHTML+XML。
当然,处理本地的文件,在没有人告诉浏览器某个文件的 MIME Type 的情况下,浏览器也会做一些默 认的处理,这可能和你在操作系统中给文件配置的 MIME Type 有关。
比如在 Windows 下,打开注册表的"HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type"主键,你可以看到所有 MIME Type 的配置信息。
在把输出结果传送到浏览器上的时候,浏览器必须启动适当的应用程序来处理这个输出文档。这可以通过 多种类型MIME(多功能网际邮件扩充协议)来完成。在HTTP中,MIME类型被定义在Content-Type header中。
例如,假设你要传送一个Microsoft Excel文件到客户端。那么这时的MIME类型就是"application/vnd.ms-excel"。在大多数实际情况中,这个文件然后将传送给Execl来处理(假设我们设 定Execl为处理特殊MIME类型的应用程序)。在ASP中,设定MIME类型的方法是通过Response对象的ContentType属性。
多媒体文件格式MIME
最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML 文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识 数据类型。
MIME意为多目Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件 客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输 的不仅是普通的文本,而变得丰富多彩。
每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的 种类。
常见的MIME类型
超文本标记语言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF图形 .gif image/gif
JPEG图形 .ipeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
Internet中有一个专门组织IANA来确认标准的MIME类型,但Internet发展的太快,很多应用程序等 不及IANA来确认他们使用的MIME类型为标准类型。因此他们使用在类别中以x-开头的方法标识这个类别还没 有成为标准,例如:x-gzip,x-tar等。事实上这些类型运用的很广泛,已经成为了事实标准。只要客户机和 服务器共同承认这个MIME类型,即使它是不标准的类型也没有关系,客户程序就能根据MIME类型,采用具体 的处理手段来处理数据。而Web服务器和浏览器(包括操作系统)中,缺省都设置了标准的和常见的MIME类 型,只有对于不常见的 MIME类型,才需要同时设置服务器和客户浏览器,以进行识别。
由于MIME类型与文档的后缀相关,因此服务器使用文档的后缀来区分不同文件的MIME类型,服务器中必 须定义文档后缀和MIME类型之间的对应关系。而客户程序从服务器上接收数据的时候,它只是从服务器接受数 据流,并不了解文档的名字,因此服务器必须使用附加信息来告诉客户程序数据的MIME类型。服务器在发送真 正的数据之前,就要先发送标志数据的MIME类型的信息,这个信息使用Content-type关键字进行定义,例如 对于HTML文档,服务器将首先发送以下两行MIME标识信息,这个标识并不是真正的数据文件的一部分。
Content-type: text/html
注意,第二行为一个空行,这是必须的,使用这个空行的目的是将MIME信息与真正的数据内容分隔开。
MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。官方的 MIME 信息是由 Internet Engineering Task Force (IETF) 在下面的文档中提供的:RFC-822 Standard for ARPA Internet text messages
RFC-2045 MIME Part 1: Format of Internet Message Bodies
RFC-2046 MIME Part 2: Media Types
RFC-2047 MIME Part 3: Header Extensions for Non-ASCII Text
RFC-2048 MIME Part 4: Registration Procedures
RFC-2049 MIME Part 5: Conformance Criteria and Examples
不同的应用程序支持不同的 MIME 类型。
在判断后缀和MIME类型的时候,我们会用到PHP的一个函数in_array(),该函数传入两个参数。
第一个参数是要判断的值;
第二个参数是范围数组。
我们用这个函数来判断文件的后缀名和mime类型是否在允许的范围内。
4.生成文件名
我们的文件上传成功了,不会让它保存原名。因为,有些人在原名中有敏感关键词会违反我国的相关法 律和法规。我们可以采用date()、mt_rand()或者unique()生成随机的文件名。
5.判断是否是上传文件
文件上传成功时,系统会将上传的临时文件上传到系统的临时目录中。产生一个临时文件。同时会产生 临时文件名。我们需要做的事情是将临时文件移动到系统的指定目录中。而移动前不能瞎移动,或者移 动错了都是不科学的。移动前我们需要使用相关函数判断上传的文件是不是通过 HTTP POST 上传的,is_uploaded_file()传入一个参数($_FILES中的缓存文件名),is_uploaded_file() 函数检查指定的文件是否 是通过 HTTP POST 上传的,如果文件是通过 HTTP POST 上传的,该函数返回 TRUE。
6.移动临时文件到指定位置
临时文件是真实的临时文件,我们需要将其移动到我们的网站目录下面了。让我们网站目录的数据,其 他人可以访问到,我们使用: move_uploaded_file() 。这个函数是将上传文件移动到指定位置,并命名。
需要传入两个参数:
第一个参数是指定移动的上传文件;
第二个参数是指定的文件夹和名称拼接的字符串。
大致步骤
php文件上传表单注意事项
代码示例
创建index.html文件,内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传表单</title>
</head>
<body>
<h1>上传文件</h1>
<form action="chuli.php" method="post" enctype="multipart/form-data">
请选择文件:<input type="file" name="file" />
<input type="submit" value="上传" />
</form>
</body>
</html>
注意事项:
1.form 表单中的参数method 必须为post。若为get是无法进行文件上传的
2.enctype须为multipart/form-data
再创建一个php文件,比如叫做chuli.php
<?php
// 获取上传文件信息
$arr = $_FILES["file"];
// var_dump($arr);
// 文件类型与大小限制条件
if(($arr["type"]=="image/jpeg" || $arr["type"]=="image/png") && $arr["size"]<10241000) {
// 生成唯一文件名(时间戳+原文件名)
$filename = "./images/".date('YmdHis').$arr["name"];
// 检查文件是否已存在
if(file_exists($filename)) {
echo "该文件已存在";
} else {
// 处理中文文件名编码转换
$filename = iconv("UTF-8","gb2312",$filename);
// 移动临时文件到目标位置(核心操作)
move_uploaded_file($arr["tmp_name"], $filename);
echo "文件上传成功";
}
} else {
echo "上传的文件大小或类型不符";
}
?>
3.2.14 php执行系统命令函数
system('指令')
exec('指令'),这个指令的结果回显不太好,但是指令执行是没问题的。
四.总结
本章节讲的内容很多,大家吸收消化一下,实在不记得也没啥关系,点赞关注加收藏,遇到的时候再来看就好了啦