乐趣区

关于php:以字节流的形式修改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、配置文件内容:

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

三、代码优化
待续。。

退出移动版