一、剖析

需要:以字节流的模式间接批改laravel框架中的config文件夹下的配置文件,并不影响正文

语言:php

知识点:文件存储形式、文件io读写、栈的应用

思路:间接读取文件,查找key的指针位和旧值的长度后,通过fwrite写入笼罩

问题:

  1. 如何排除正文内的内容?
    答:用栈存储弹出正文符号来疏忽正文的解析。
  2. 如果存在雷同的key,如何辨别不同的数组?
    答:倒数第二个key时,先存储一个"[",循环读取到 "]"即可完结。
  3. 如果存在value==key,那就会定位谬误,如何解决?
    答:从以后地位登程查找 "=>" 来判断以后是key还是value。
  4. fwrite写入笼罩,长短替换和短长替换时呈现格局谬误,如何解决?
    答:将value后的数据长期保留后清空,写入新值后接上长期数据。
  5. 兼容局部格局?比方字符之间没有空格、存在换行逗号等。
    答:针对空格换行逗号进行解决。

调用形式: 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());        }    }

三、代码优化
待续。。