【问题标题】:Write php array code to file without evaluating expressions将php数组代码写入文件而不评估表达式
【发布时间】:2015-07-15 14:10:38
【问题描述】:

我正在尝试编写一些代码来生成一个带有数组的 php 文件,like this

但是,为了创建正确的配置文件,我需要能够在数组中保留表达式“原样”。这是因为该文件将被许多用户使用,并且表达式基于用户设置的环境变量等进行评估。

所以,假设我们在数组中有这个键/值,我最终想要输出到文件中:

[
    ...
    'connection' => $isFork ? $sourceArray['connection'] : config('database.default'),
    ...
]

当这个数组最终被写入一个 php 文件时(现在使用var_exportfile_put_contents)我会看到

'connection' => config('database.default')

成为

'connection' => 'default_connection',

因为表达式已被计算。我需要的是一种方法来防止表达式作为数组中的值被评估但也确保

'connection' => $isFork ? $sourceArray['connection']

确实评估为

'connection' => 'my_connection'

有什么办法吗?

编辑:我基本上想做this,但反过来用表达式。

【问题讨论】:

  • 如果您想阻止评估,请使用引号?也许我不在主题? '连接' => $isFork ? $sourceArray['connection'] : 'config('database.default')',
  • ho.. 好的,您想在不评估的情况下输出它.. 为什么不像字符串一样使用? $string = '\'connection\' => $isFork ? $sourceArray[\'connection\'] : config(\'database.default\')';
  • @Jean-philippeEmond :输出没有进入浏览器,我正在尝试生成一个 config.php 文件。当我想要的是'connection' => config('database.default')

标签: php arrays


【解决方案1】:

如果我对您的理解正确,您的解决方案是使用字符串表示您的数组,以便不对语句进行评估。我会serialize 该数组并将该字符串放入文件中。在收到邮件后立即告诉您的窥视者unserialize。更好的是,json_encode 你的数组将为你提供一个 json 字符串。你可以通过put_file_contents 把它放进去,然后告诉你的窥视者json_decode 的内容。他们可以像这样使用它json_decode($content, TRUE),这将使他们返回关联数组。

更新

所以你想直接编写 PHP。我看到你的数组中有连接的东西,所以我认为它是某种包含连接设置等的配置文件是安全的。

// filename should have the .ini at the end 
function writeConfig( $filename, $yourArray ) {
    $fh = fopen($filename, "w");
    // making sure its available
    if (!is_resource($fh)) {
        return false;
    }
    // start dumping you array to the file 
    foreach ($yourArray as $key => $value) {
        fwrite($fh, sprintf("%s = %s\n", $key, $value));
    }
    fclose($fh); // close file

    return true;
}

当你想读它时

function readConfigFile( $fileThatMadeAbove ) {
    return parse_ini_file($fileThatYouMadeAbove, false, INI_SCANNER_NORMAL);
}

既然是配置信息,在php中使用ini可能会更好。

如果你想尝试简单的解决方案

$fp=fopen('filename.php','w');
fwrite($fp, "$yourArray");
fclose($fp);

老实说,我不知道你是否可以做"$yourArray",而且我没有地方测试它。您很可能需要执行print_r($yourArray),因为它是您写入文件的字符串,这就是我在上面提出建议的原因。

我没有想法。祝你好运(:

【讨论】:

  • 这对于我想要完成的事情来说步骤太多了。目标是允许用户从 cli 执行命令,将现有的配置文件作为输入,并输出一个新的配置文件(仍然是 php 代码)。
  • 将您的键值数组写入文件file_put_contents(json_encode($array)) 并通过file_get_contents(json_decode($fileName)) 检索它我没有看到too many steps 所以我出去了......祝你好运
  • so.. 使用fopen 读取文件。将每个时间放入一个数组中。之后,fopen 用于使用该数组写入新文件。
  • @Jean-philippeEmond 和 ODelibalta ,一旦生成文件,我就无法控制它。这是一个使用普通数组创建有效、可读的 php 文件的练习,用户可以根据需要在生成后编辑和使用该文件。我不能限制他们必须解码 json 或反序列化的东西。它需要是可用的 php 代码。
  • 我告诉你关于生成你的 php.ini 文件。您需要生成,因此当您尝试生成它时,只需将所有信息放入一个数组中。(每行)用单引号并使用 write 方法写入文件。使用并剥离斜杠并添加 \n 或 @987654338 @ 在每一行的末尾你想要一个新的一行。当您插入数组时,您的配置参数已经编译。所以,转义它,用删除\写入文件并在字符串插入Check This之后添加PHP_EOL\n,看看我告诉你什么
【解决方案2】:

使用var_export 无法做到这一点。我能看到的最好方法是创建一个输出字符串并使用file_put_contents 将其输出到文件中。

这可以通过复制数组结构来实现,例如

$arr_str = "[\n";
         . "\t'simple_annotations' => false,\n"
         . "];";

或者通过创建一个辅助函数来代替 var_export。像这样的:

function var_str($var, $level = 0){
    if(is_array($var)) return arr_str($var, $level+1);
    elseif(is_string($var)) return '\''.$var.'\'';
    elseif(is_numeric($var)) return $var;
    elseif(is_null($var)) return 'null';
    elseif(is_bool($var)) return ($var ? 'true' : 'false');
}

function arr_str($arr, $level){
    $str = "[\n";
    foreach($arr as $k => $e){
        $str .= str_repeat("\t", $level);
        $str .= "'".$k."' => ".var_str($e, $level).",\n";
    }
    return $str.str_repeat("\t", $level-1).']';
}

print var_str($my_array);

【讨论】:

  • 如何生成数组的原始代码表示形式的字符串?
  • 与创建任何字符串的方式相同(并确保逃避 php 会尝试评估的内容): $string = "\$array = array('connection' => 'default_connection') ;";
  • 需要构建数组,这不是一件简单的事情,我可以硬编码一个字符串。我真的需要为数组的每个部分编写一个字符串构建器吗?没有更简单的方法吗?
  • 我基本上需要这个,但是反过来用stackoverflow.com/questions/11267434/…的表达方式
【解决方案3】:

搜索了几个小时后,我得出结论,完全控制我想做的事情的唯一方法是使用模板引擎。

该项目使用Laravel,所以我使用Blade,但任何引擎都可以工作(我最初尝试使用Twig)。

我写出了我的配置的每个部分,就好像它是一个常规的 php 数组一样,然后使用 Blade 括号来包含为每个键找到正确值所需的逻辑。如果值不是表达式,我会评估代码,如果是,我会将表达式写入字符串。

我最终得到了这个:

//example.blade.php

[
    'meta' => '{{{ $isFork ? $data['metadata']['driver'] : 'annotations' }}}',
    'connection' => {{{ $isFork ? '\''.$data['connection'].'\'' : 'config("database.default")'  }}},
    'paths' => {{ var_export(ArrayUtil::get($data['metadata']['paths'], $data['metadata']), true) }},
    'repository' => '{{{ ArrayUtil::get($data['repository'], EntityRepository::class) }}}',
    'proxies' => [
        'namespace' => {{{ isset($data['proxy']['namespace']) ? '\'' . $data['proxy']['namespace'] .'\'' : 'false' }}},
        'path'          => '{{{ ArrayUtil::get($data['proxy']['directory'], storage_path('proxies')) }}}',
        'auto_generate' => {{{ ArrayUtil::get($data['proxy']['auto_generate'], env('DOCTRINE_PROXY_AUTOGENERATE', 'false')) }}}
    ],
    'events'     => [
        'listeners'   => [],
        'subscribers' => []
    ],
    'filters' => []
]

和输出:

[
            'meta' => 'yaml',
            'connection' => config('database.default'),
            'paths' => array(
                0 => '/proj/app/Models/mappings',
            ),
            'repository' => 'Doctrine\ORM\EntityRepository',
            'proxies' => [
                'namespace' => false,
                'path' => '/proj/storage/proxies',
                'auto_generate' => false
            ],
            'events' => [
                'listeners' => [],
                'subscribers' => []
            ],
            'filters' => []
]

您可以看到我可能需要扩展我使用var_export 的数组。除了它非常简单。

【讨论】:

    猜你喜欢
    • 2019-01-30
    • 1970-01-01
    • 2015-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    • 2016-07-26
    • 1970-01-01
    相关资源
    最近更新 更多