1. Analysis
requirements: directly modify the configuration file in the config folder in the laravel framework in the form of byte stream, and does not affect the comments
Language: php
knowledge points: file storage method, file io reading and writing, stack usage
Idea: reads the file directly, finds the pointer bit of the key and the length of the old value, and writes and overwrites it through fwrite
question:
- How to exclude content in comments?
Answer: Use stack storage to pop up comment symbols to ignore comment parsing. - If the same key exists, how to distinguish between different arrays?
Answer: When the penultimate key is stored, first store a "[", and read the cycle to "]" to end. - If there is value==key, there will be a positioning error. How to solve it?
Answer: Start from the current position and search for "=>" to determine whether it is currently key or value. - How to solve the format error when fwrite write overwrite, long-short replacement and short-length replacement?
Answer: The data after value is temporarily saved and then cleared, and the temporary data is connected after writing the new value. - Compatible with some formats? For example, there are no spaces between characters, and there are newline commas, etc.
Answer: deal with the space-wrap comma.
call method:
配置文件bank.php中 test['a']['b'] = 1,
调用 ConfigHelper::setOrigin(config_path("bank.php"), "test.a.b", "test")后,
修改1为test
Two, example + code
1. Configuration file content:
<?php
/*
* @Description:
*/
/*
|-----------------------------------------------------------------
| 配置文件
|-----------------------------------------------------------------
*/
return [
// 最大绑定数量
'max' => 5,
// 是否为单银行账号绑定 false => 多个, true => 单个
'single' => false,
// 平台是否为单银行账号绑定 false => 多个, true => 单个
'single_admin' => true,
"test" => [
'a' => [
"b" => 1
]
],
"test1" => [
'b' => "b"
]
];
2. Code:
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) {
throw new \Exception($e->getMessage() .'-'. $e->getLine());
}
}
Three, code optimization
to be continued. .
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。