удаление элемента массива JSON в 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); } 

Вышеупомянутая функция должна удалить запись из JSON, например:

 [ { "dummy":"dummy", "dummy1":"dumy" }, { "dummy":"dummy1", "dummy1":"dummy" } ] 

Но в конце функция вставляет числовые индексы в JSON, что нежелательно.

Результат подобен

 [ "0": { "dummy":"dummy", "dummy1":"dumy" }, "1": { "dummy":"dummy1", "dummy1":"dummy" } ] 

Как я могу получить свой оригинальный формат JSON? Я не хочу, чтобы 0 1 2 части индекса.

NB: это делает foreach . Без foreach , JSON создается, как ожидалось.

Попробуйте с помощью array_values:

 $result = json_encode(array_values($data)); 

TL; DR PHP-массивы со всеми числовыми ключами , начиная с нуля , сортируются и без отверстий, являются единственным видом, который будет отображаться в массив JSON [ "square", "brackets" ] . Все остальные виды станут словарями JSON { "curly": "brackets" } .


Причина наблюдаемого поведения и причина, по которой array_values видимому, array_values проблему (и в этом случае, на самом деле), заключается в различии между массивами PHP и JSON и словарями.

Это массив PHP с непрерывными числовыми ключами:

 $a = array( "Apple", "Banana", "Canteloupe" ); 

Это действительно

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

В JSON это становится массивом :

 [ "Apple", "Banana", "Canteloupe" ] 

Это вместо этого массив PHP с текстовыми клавишами (хэш):

 $a = array( "a" => "Apple", "b" => "Banana", "c" => "Canteloupe" ); 

В JSON это словарь (обратите внимание на фигурные скобки):

 { "a": "Apple", "b": "Banana", "c": "Canteloupe" } 

Некоторые операции изменяют массив с массивом PHP-array-render-as-array (ARA) в -reded-as-dictionary (ARD) .

И эти операции:

  • Добавление ключа TEXT в массив NUMERIC.

  • Наличие цифровых клавиш NOT в непрерывной упорядоченной последовательности 0 … N.

Таким образом, они кажутся массивами, но на самом деле являются словарями :

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

И это, наконец, причина, по которой удаление ключа, который не является последним, приведет к трэш-массиву и сделает его словарем:

 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! 

Если бы вы подвергли массив какой-либо операции перенумерации или array_values , вы получили бы чисто числовой массив:

 /** * delete news items given their index. * * @param array $selected the list of indexes (eg [ 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 (eg 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); } 

Поэтому, если ваш код удалил последние индексы вашего массива, все могло бы работать. Как только отбрасывание создало отверстие в массиве или текстовый ключ был добавлен …

То же самое касается сортировки : [ 1 => "B", 0 => "A" ] – словарь JSON. Сортируйте его, сохраняя ассоциации ключей с [ 0 => "A", 1 => "B" ] , и он становится массивом JSON.

Одно замечание о вашем коде: вы читаете «news.json» с include-path, установленным в true . Но затем вы сохраните его в текущем каталоге. Если у вас есть «news.json» где-нибудь еще на вашем пути, кроме текущего каталога, у вас будет два файла news.json; какой из этих двух используется, зависит от самого включения пути.

Локальные файлы и безопасность

Сохранение локальных файлов, как это происходит здесь с news.json , в порядке, но некоторые меры предосторожности часто в порядке.

В общем, лучше всего разместить такие «переменные» файлы в своем собственном каталоге (например, «./cache» или «./temp») с подходящим .htaccess чтобы предотвратить прямое чтение / выполнение, если это не требуется, и чтобы разрешения могут быть усилены более четко.

Например, можно было бы использовать каталог «./data» и иметь файлы PHP, которые в других местах устанавливаются только для чтения для веб-сервера; и, наконец, проинструктируйте, скажем, веб-сервер Apache, чтобы этот один каталог при записи на веб-сервере не мог быть легко использован для использования в системе:

 <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> 

Таким образом, даже если кто-то успел загрузить файл в вашей системе и этот файл содержал исполняемый, вредоносный PHP-код, этот код не был бы разрешен (не напрямую, по крайней мере).

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

 $data=json_decode($file,true); unset($file); foreach($selected as $index){ unset($data[$index]); } foreach($data as $value){ $new_data[] = $value; } $result=json_encode($new_data); file_put_contents('news.json', $result); echo $result; unset($result); $url="./deleteNews.php"; с $data=json_decode($file,true); unset($file); foreach($selected as $index){ unset($data[$index]); } foreach($data as $value){ $new_data[] = $value; } $result=json_encode($new_data); file_put_contents('news.json', $result); echo $result; unset($result); $url="./deleteNews.php"; не $data=json_decode($file,true); unset($file); foreach($selected as $index){ unset($data[$index]); } foreach($data as $value){ $new_data[] = $value; } $result=json_encode($new_data); file_put_contents('news.json', $result); echo $result; unset($result); $url="./deleteNews.php"; с $data=json_decode($file,true); unset($file); foreach($selected as $index){ unset($data[$index]); } foreach($data as $value){ $new_data[] = $value; } $result=json_encode($new_data); file_put_contents('news.json', $result); echo $result; unset($result); $url="./deleteNews.php"; 

// перенаправление ($ URL); }