一、剖析
需要:以字节流的模式间接批改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()); } }
三、代码优化
待续。。