以字节流的形式修改laravel框架config配置文件

一、分析

需求:以字节流的形式直接修改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、配置文件内容:

  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());
        }
    }

三、代码优化
待续。。

你可能感兴趣的:(phplaravel)