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

三、代码优化
待续。。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理