如何解析类似于 .ini 文件的格式化文本?

问题描述

我有一个 HTML 格式的输入表单,用于使用 PHP用户数据导入数据库 (MysqL)。

输入中的信息必须是这样的:

[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01
[account]
user = {user3}
pwd = {password3}
expdate = 2028-01-01

现在,PHP 代码应该解析用户数和每个用户信息并分别保存每个用户信息。

我的 PHP 代码是:

$users = $_POST["users"];
$users = explode(chr(10) . chr(10),$users);
for ($i = 0; $i < count($users); $i++) { 
    $users[$i] = explode(" ",$users[$i]);
    $username = $users[$i][2];
    $pwd = $users[$i][5];
    $exp = $users[$i][8];
    if (strtotime($exp) === false) {
        // ...code
    } else {
        $expiredate = date("Y-m-d",strtotime($exp));
    }
}

当输入是单个用户时:

[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01

我的输出被破坏了(这里是 var_export() 输出):

array (
  'username' => '{user1}
pwd','pwd' => '=','exp' => '2028-01-01'
)

问题在于爆炸——pwd 键附加到 username 值,pwd=,它有时会给出错误的格式防止被保存的日期。

作为一种解决方法,在每个输入的用户名密码后放置空格后,所有数据都解析成功。

此外,当我在输入表单中输入多个用户时:

[account]
user = {user1} 
pwd = {password1} 
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01

PHP 代码只读取第一个用户并只保存第一个用户的信息,我希望它们都被保存。

所以:

尝试编辑我的代码搜索了很多,很不走运,不知道PHP代码有什么问题。

解决方法

您的输入看起来像一个 .ini 文件。
使用 explode() 将输入字符串拆分为由 [account] 分隔的片段,然后使用 parse_ini_string() 解析每个片段并获取数组中的数据:

$users = <<< END
[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01
[account]
user = {user3}
pwd = {password3}
expdate = 2028-01-01
END;

// Use $users = $_POST['users'] in the real code

// Parse the input data
$data = array_map(
    function($entry) { return parse_ini_string($entry); },array_filter(           // remove the empty entries (before the first '[account]',between two consecutive appearances of '[account]'
        explode('[account]',$users),function($entry) { return strlen(trim($entry)); }
    )
);

print_r($data);

输出为:

Array
(
    [1] => Array
        (
            [user] => {user1}
            [pwd] => {password1}
            [expdate] => 2028-01-01
        )

    [2] => Array
        (
            [user] => {user2}
            [pwd] => {password2}
            [expdate] => 2028-01-01
        )

    [3] => Array
        (
            [user] => {user3}
            [pwd] => {password3}
            [expdate] => 2028-01-01
        )

)

Check it online

接下来,处理解析的信息很简单:

foreach ($data as $account) {
  // do something with $account['user'],$account['pwd'],$account['expdate']
  // Use the DateTime class and its friends to validate and handle $account['expdate']
}

parse_ini_string() 能够在一次调用中解析整个字符串并正确处理这些部分,如果它的第二个参数是 true。但是,因为所有部分都被命名为 account,所以它合并了值;输入中稍后出现的键值对会覆盖之前的值。
这就是为什么我们首先将输入分成几部分,然后一次输入 parse_ini_string() 一个部分的原因。

,

你可以试试这个

PHP - HTML :
<div class="all_forms">
<?php for ($z = 0; $z < 5; $z++) { ?>
<form method="POST" id="passenger-<?= $z ?>-details">
   <input type="text" class="form-control" name="username" placeholder="Username">
   <input type="password" class="form-control" name="password" placeholder="Password">
   <input type="date" class="form-control" name="date" placeholder="date">
</form>
<?php } ?>
</div>
JavaScript - JQuery
var passenger_details_array = [];
   $('.all_forms').find("form").map(function(idx,form) {
      var str = $('#' + form.id).serialize();
      passenger_details_array.push(str);
   });
   var data = {
      token: 'SOME_SECURITY_TOKEN',passenger_details: passenger_details_array
   };
   $.post('http://domain/path/file.php',data,function(response) {
            console.log(response);
   });
PHP - Saving Info

$passenger_details = $_POST['passenger_details'];
foreach ($passenger_details as $value) {
   parse_str($value,$tmp);
//here you have $tmp and in this you will find all proper details like (one by one)
// ['username' => 'U1','password' => 'user1_pass','date' => 'whatever']
}

//$passenger_details has data like

[
      ['username' => 'U1','date' => 'whatever'],['username' => 'U2','password' => 'user2_pass',['username' => 'U3','password' => 'user3_pass','date' => 'whatever']
]
,

[account] 行上拆分,带有可选的前导换行符序列和强制性的尾随换行符序列。不允许在爆炸中产生空元素。

\R 匹配与平台无关的换行序列,因此不必担心 \r\n\n 问题。

^(字符串锚点的开头)由 m 模式修饰符修改,使其与每一行的开头匹配。

? 表示零或之前的任何内容之一。这使得尾随的 \R 成为可选的。

如果您的真实文本在用户详细信息之间有一个空行,您只需在前导 {2} 后添加 \R 以使用额外的换行符序列。

对每个生成的元素调用 parse_ini_string()。清洁和完成;不需要额外的过滤或修整。爆炸过程不再麻烦。

代码:(Demo)

$data = <<<NOT_INI
[account]
user = {user1}
pwd = {password1}
expdate = 2028-01-01
[account]
user = {user2}
pwd = {password2}
expdate = 2028-01-01
[account]
user = {user3}
pwd = {password3}
expdate = 2028-01-01
NOT_INI;

var_export(
    array_map(
        'parse_ini_string',preg_split(
            '~\R?^\[account]\R~m',$data,null,PREG_SPLIT_NO_EMPTY
        )
    )
);

输出:

array (
  0 => 
  array (
    'user' => '{user1}','pwd' => '{password1}','expdate' => '2028-01-01',),1 => 
  array (
    'user' => '{user2}','pwd' => '{password2}',2 => 
  array (
    'user' => '{user3}','pwd' => '{password3}',)