删除PHP中的JSON数组元素,并重新编码为JSON

Jah*_*hid 2 php json

function deleteNews($selected) {
    $file = file_get_contents('news.json', true);

    $data=json_decode($file,true);
    unset($file);

foreach($selected as $index){
 unset($data[$index]);
 }


  $result=json_encode($data);

  file_put_contents('news.json', $result);
    echo $result;
    unset($result);
    $url="./deleteNews.php";
   //redirect($url);
    }
Run Code Online (Sandbox Code Playgroud)

上述函数应该从JSON中删除条目,如:

[
     {
           "dummy":"dummy",
           "dummy1":"dumy"
      },
      {
           "dummy":"dummy1",
           "dummy1":"dummy"
      }
]
Run Code Online (Sandbox Code Playgroud)

但最后该函数在JSON中插入数字索引,这是不可取的.

结果是这样的

[
    "0":
       {
          "dummy":"dummy",
          "dummy1":"dumy"
       },
     "1":
       {
           "dummy":"dummy1",
           "dummy1":"dummy"
       }
 ]
Run Code Online (Sandbox Code Playgroud)

如何从中获取原始JSON格式?我不想要0 1 2索引部分.

NB:就是foreach这样做.如果没有foreach,则按预期创建JSON.

LSe*_*rni 7

TL; DR PHP阵列,所有的数字键,从零开始,整理无孔都将得到渲染成JSON数组唯一的一种[ "square", "brackets" ].所有其他类型将成为JSON词典{ "curly": "brackets" }.


你观察到的行为的原因,以及array_values解决问题的原因(在这种情况下实际上确实如此),是PHP和JSON数组和字典之间的区别.

这是一个带有连续数字键的PHP数组:

$a = array( "Apple", "Banana", "Canteloupe" );
Run Code Online (Sandbox Code Playgroud)

这真的是

$a = array( 0 => "Apple", 1 => "Banana", 2 => "Canteloupe" );
Run Code Online (Sandbox Code Playgroud)

在JSON中,这将成为一个数组:

[ "Apple", "Banana", "Canteloupe" ]
Run Code Online (Sandbox Code Playgroud)

这是一个带有文本键(哈希)的PHP数组:

$a = array( "a" => "Apple", "b" => "Banana", "c" => "Canteloupe" );
Run Code Online (Sandbox Code Playgroud)

在JSON中,这是一个字典(请注意花括号):

{ "a": "Apple", "b": "Banana", "c": "Canteloupe" }
Run Code Online (Sandbox Code Playgroud)

某些操作将PHP数组呈现为数组(ARA)更改为-rendered-as-dictionary(ARD).

这些操作是:

  • 将TEXT键添加到NUMERIC数组.

  • 数字键不是不间断排序的序列0 ... N.

所以这些似乎是数组,但实际上是字典:

$a = array ( 2 => "Canteloupe", 1 => "Banana", 0 => "Apple" );

$a = array ( 0 => "Apple", 2 => "Canteloupe" );

$a = array ( 1 => "Banana", 0 => "Apple" );
Run Code Online (Sandbox Code Playgroud)

最后这就是为什么删除一个不是最后一个键的键将会破坏你的数组并使它成为一个字典的原因:

0 1 2 3 => remove 3 => 0 1 2 => still an array!
0 1 2 3 => remove 2 => 0 1 3 => NOT an array!
0 1 2 3 => remove 2 => 0 1 3 => not an array => remove 3 => 0 1 => again an array!
Run Code Online (Sandbox Code Playgroud)

如果您要将数组置于任何重新编号操作中,或者array_values,您将再次获得纯数值数组:

/**
* delete news items given their index.
*
* @param array $selected     the list of indexes (e.g. [ 0, 1, 7 ])
* @return nothing
*/

function deleteNews(array $selected = [ ]) {
    try {
        $news = array_values( // Reorder...
            array_diff_key( // ...all keys...
                json_decode(file_get_contents('news.json', true), true), // ...in here...
                array_flip($selected) // ...that are not in $selected.
            )
        );
    } catch (\Exception $e) {
        // TODO handle errors (e.g. file not found and bad JSON)
    }
    try {
        file_put_contents('news.json', json_encode($news));
    } catch (\Exception $e) {
        // TODO handle errors
    }
    // $url="./deleteNews.php";
    // redirect($url);
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您的代码删除了数组的最后一个索引,那么事情似乎就会起作用.一旦取消设置在数组中创建了一个洞,或者添加了一个文本键......

排序[ 1 => "B", 0 => "A" ]也是如此:是一个JSON字典.对它进行排序,保留关键关联[ 0 => "A", 1 => "B" ],并成为JSON数组.

有关您的代码需要注意的一点是:您将include-path设置为true时读取"news.json" .但是然后将其保存到当前目录中.如果你的路径中的其他任何地方都有"news.json",除了当前目录,你最终会得到两个 news.json文件; 然后使用两者中的哪一个取决于包含路径本身.

本地文件和安全性

保存本地文件,就像在这里发生的那样news.json,是可以的,但是一些预防措施通常都是有序的.

一般来说,最好将这些"变量"文件放在它们自己的目录中(例如"./cache"或"./temp").htaccess,并且除非需要,否则它们适合防止直接读取/执行,因此权限可能是更明确地执行.

例如,可以使用"./data"目录,并将其他地方的PHP文件设置为只读Web服务器; 最后指示Apache Web服务器,以便这个目录在Web服务器可写时无法轻易用于利用系统:

<directory "/var/www/mysite/htdocs/data">
    # You CANNOT ask for /data and have a directory listing. Just in case.
    options      -Indexes
    # You CANNOT save "news.php" and have it executed :-)
    php_flag     engine     off
</directory>
Run Code Online (Sandbox Code Playgroud)

这样,即使有人成功上传您系统上的文件并且该文件包含可执行的恶意PHP代码,也不允许执行该代码(至少不是直接执行).