一、剖析
需要:以字节流的模式间接批改laravel框架中的config文件夹下的配置文件,并不影响正文
语言:php
知识点:文件存储形式、文件io读写、栈的应用
思路:间接读取文件,查找key的指针位和旧值的长度后,通过fwrite写入笼罩
问题:
- 如何排除正文内的内容?
答:用栈存储弹出正文符号来疏忽正文的解析。 - 如果存在雷同的key,如何辨别不同的数组?
答:倒数第二个key时,先存储一个”[“,循环读取到 “]”即可完结。 - 如果存在value==key,那就会定位谬误,如何解决?
答:从以后地位登程查找 “=>” 来判断以后是key还是value。 - fwrite写入笼罩,长短替换和短长替换时呈现格局谬误,如何解决?
答:将value后的数据长期保留后清空,写入新值后接上长期数据。 - 兼容局部格局?比方字符之间没有空格、存在换行逗号等。
答:针对空格换行逗号进行解决。
调用形式: ConfigHelper::setOrigin(config_path(“bank.php”), “test.a.b”, “test”);
二、例子+代码
1、配置文件内容:
<?php
/*
* @Description:
*/
/*
|--------------------------------------------------------------------------
| 配置文件
|--------------------------------------------------------------------------
*/
return [
// 最大绑定数量
'max' => 5,
// 是否为单银行账号绑定 false => 多个, true => 单个
'single' => false,
// 平台是否为单银行账号绑定 false => 多个, true => 单个
'single_admin' => true,
"test" => [
'a' => [
"b" => 1
]
],
"test1" => [
'b' => "b"
]
];
2.代码:
public static function setOrigin(string $filename, $key, $value)
{
try {
if (empty($filename) || empty($key) || empty($value)) {
throw new \Exception("the params is not empty");
}
$f = fopen($filename, "r+");
$keys = explode(".", $key);
$total = count($keys);
//替换开始的指针地位
$start = 0;
//替换值的长度
$length = 0;
//栈来管制正文域
$stack = [];
//栈来管制数组域
$stack1 = [];
//完结标记
$end = "";
$map = [
'//' => "\n",
'/*' => "*/",
];
foreach ($keys as $k => $val) {
//兼容""和''
$goal1 = "\"" . $val . "\"";
$goal2 = "'" . $val . "'";
$len = strlen($goal1);
while (!feof($f)) {
$first = fread($f, 1);
//记录以后地位
$pointer = ftell($f);
//读取两个字节判断正文
$second = $first . fread($f, 1);
//文件完结或出了数组域则退出
if (feof($f) || (count($stack1) > 0 && $first == "]")) {
break;
}
//入栈
if (array_key_exists($second, $map)) {
$stack[] = $second;
continue;
}
//出栈
if (count($stack) != 0 && ($map[$stack[count($stack) - 1]] == $first || $map[$stack[count($stack) - 1]] == $second)) {
array_pop($stack);
continue;
}
//获取指标字符串
$tmp = $second . fread($f, $len - 2);
//判断是否匹配指标字符串key
if (count($stack) == 0 && ($tmp == $goal1 || $tmp == $goal2)) {
//排除匹配到的字符串是value
$status = 0;
//找到这行完结看看是否有=>
while (($equl = fread($f, 1)) != "=" && ($equl != "\n" && $equl != ",")) {
}
if ($equl . fread($f, 1) == "=>") {
$status = 1;
}
//真正匹配到key
if ($status == 1) {
//匹配key后,倒数第二个索引有个数组域
if ($total > 1 && $k == $total - 2) {
$stack1[] = "[";
}
//最初一个key,要思考没有空格的状况 >
if ($k == $total - 1) {
while (fread($f, 1) == " ") {
}
$start = ftell($f) - 1;
//value的完结标记:换行或空格或,
while (($tag = fread($f, 1)) != "\n" && $tag != " " && $tag != ",") {
}
$end = $tag == "," ? "" : $tag;
$length = ftell($f) - $start;
break;
}
break;
}
}
//回到以后地位
fseek($f, $pointer);
}
}
//未找到
if ($start == 0 && $length == 0) throw new \Exception("the config is not found");
//将start + lenght 之后的数据长期保留
$tmp = "";
fseek($f, $start + $length);
while (!feof($f)) {
$tmp .= fread($f, 2);
}
//清空前面的数据
ftruncate($f, $start);
//挪动指针到值地位并写入新值
fseek($f, $start);
$replace = "\"" . $value . "\"," . $end;
fwrite($f, $replace, strlen($replace));
//将前面的数据tmp从新写入
fwrite($f, $tmp, strlen($tmp));
fclose($f);
} catch (\Exception $e) {
echo $e->getMessage();
// throw new \Exception($e->getMessage() .'-'. $e->getLine());
}
}
三、代码优化
待续。。
发表回复