Как сохранить JSON на сервере
medium

Как сохранить JSON на сервере

И отдать его обратно по запросу.

Мы уже научились отправлять на сервер и принимать обратно данные в JSON-формате. Финальный шаг — будем хранить все наши данные на сервере, чтобы получить доступ к ним с любого устройства. Это поможет нам делать проекты независимыми от локального хранилища.

Как это будет работать

Мы возьмём код из прошлого проекта про отправку JSON на сервер и добавим в него новые возможности.

Логика будет такая:

  1. Мы научим сервер каждый раз запоминать данные, которые отправит ему наша страница. Чтобы убедиться, что данные в порядке, мы сразу же в ответ будем посылать результат — то, как сервер это запомнил.
  2. После этого мы поработаем с данными от сервера в понятном для JavaScript виде. Для этого мы немного их поменяем и отправим обратно на сохранение. Это поможет нам понять, как работать с данными в других проектах.

👉 Мы специально используем самые простые и не самые лучшие конструкции в PHP и JavaScript. Наша цель — собрать быстрый прототип и показать, как можно обмениваться данными с сервером. Когда разберёмся с этим, можно и код пооптимизировать. А пока так.

Сохраняем JSON в файл на сервере

Сейчас работает так — по нажатию на кнопку «Проверить JSON» наша страница отправляет на сервер JSON-строку с двумя ключами: именем и фамилией. Новая задача сервера — сохранять себе все полученные данные и отправлять их обратно на страницу. Чтобы данные не потерялись после окончания работы программы, будем сохранять их на сервере в файл json.data. Мы выбрали такое название, но вы можете взять любое другое, имя файла ни на что не влияет.

Так как по нажатию этой кнопки страница обращается на сервере к файлу json.php, то и изменять тоже нужно именно его. Сделаем так:

  1. Получаем данные от страницы (это уже сделано в прошлом проекте).
  2. Проверяем, есть ли на сервере нужный нам файл с данными — json.data.
  3. Если есть — запоминаем его содержимое, а если такого файла нет — создаём его отдельной командой.
  4. Всё, что было в этом файле, переводим в массив, с которым умеет работать PHP. Таким способом у нас каждая JSON-запись будет храниться в отдельной ячейке массива.
  5. Добавляем новую запись в этот массив — кладём в него то, что пришло со страницы.
  6. Записываем это всё обратно в файл и тут же читаем обратно из него — так мы убедимся, что запись прошла нормально и мы можем с этим работать.
  7. Отправляем всё содержимое файла на страницу, чтобы там увидеть, что сервер работает как нужно.

Задача этого алгоритма — сохранять данные на сервере и отдавать их обратно на страницу. На языке PHP то же самое будет выглядеть так:

<?php
// на какие данные рассчитан этот скрипт
header("Content-Type: application/json");
// 1. Получаем данные от страницы
$data = json_decode(file_get_contents("php://input"));
// 2. Проверяем, есть ли на сервере нужный нам файл с данными — json.data.
// Берём новую переменную и пишем в неё имя файла
$filename = 'data.json';
// 3. Если есть — запоминаем его содержимое, а если такого файла нет — создаём его отдельной командой.
if (file_exists($filename)) {
    // Если файл есть — открываем его и читаем данные
    $file = file_get_contents('data.json');
    // Если такого файла нет…
} else {
// …то создаём его сами
    $file = fopen("data.json", "a+");
}
// 4/ Всё, что было в этом файле, переводим в массив, с которым умеет работать PHP. Таким способом у нас каждая JSON-запись будет храниться в отдельной ячейке массива.
$taskList = json_decode($file, true);
// 5. Добавляем новую запись в этот массив — кладём в него то, что пришло со страницы.
$taskList[] = array($data);
// 6. Записываем это всё обратно в файл и тут же читаем обратно из него — так мы убедимся, что запись прошла нормально и мы можем с этим работать.
// Записываем данные в файл…
file_put_contents('data.json', json_encode($taskList));
// …и сразу считываем их обратно
$file = file_get_contents('data.json'); // Открыть файл data.json
// 7. Отправляем всё содержимое файла на страницу, чтобы там увидеть, что сервер работает как нужно.
echo $file;
// Освобождаем память от переменных, которые нам пока не нужны
unset($file);
unset($taskList);

Обратите внимание на последние строки в коде — мы освобождаем память на сервере, чтобы она не хранила те переменные, которые нам уже не нужны. Зачем это делать и что будет, если этого не делать, — почитайте в статье про сборщики мусора.

Сразу видно, что сервер сохраняет каждые отправленные данные. Нам даже не пришлось пока ничего менять в самом HTML-файле

Подготавливаем страницу

Теперь научим нашу страницу правильно обрабатывать ответ от сервера и работать с полученными данными. Для этого нам нужно:

  1. Преобразовать сырые данные, полученные от сервера, в вид, понятный для JavaScript.
  2. Любым образом поменять их значения.
  3. Отправить изменённые данные назад на сервер.
  4. Получить сразу их обратно и вывести на экран, чтобы убедиться, что сервер правильно понял все изменения.

Перед тем как работать с полученными данными в JavaScript, нам нужно их куда-то сохранить. Для этого в самом начале скрипта заведём новую переменную res, и добавим в функцию sendJSON() такую строку:

// запоминаем данные, которые пришли с сервера
res = this.responseText;
// выводим то, что ответил нам сервер —
так мы убедимся, что данные он получил правильно
result.innerHTML = this.responseText;

Теперь в этой переменной у нас будут лежать сырые данные, которые отправит нам сервер.

Чтобы мы могли отдельно управлять всеми изменениями, добавим в наш HTML-файл с прошлого проекта новую кнопку рядом с первой:

<!-- эта кнопка поменяет полученные данные
и отправит их снова на сервер --!>
<button onclick="editJSON()">Изменить JSON</button>

Сделаем функцию editJSON(), которая сработает по нажатию на эту кнопку. Работать она будет так:

  1. Возьмёт сырые данные от сервера и преобразует их в формат, понятный для JavaScript.
  2. Найдёт все имена, посчитает количество символов в них и допишет это число к имени. Так мы поймём, что данные можно менять как нам нужно.
  3. Преобразует всё это обратно в JSON и отправит на сервер.
  4. На всякий случай снова выведет результат на странице, чтобы мы убедились, что на сервере лежат уже новые данные.

Чтобы не писать код заново, мы скопируем уже существующую функцию sendJSON(), переименуем её в editJSON() и добавим в неё то, что нам нужно. А перед этим в самом начале скрипта снова добавим две новые переменные:

  • newData, где мы будем хранить данные в понятном формате;
  • sendData, куда мы поместим новую JSON-строку перед отправкой на сервер.

Что мы делаем с JSON, полученным с сервера

Перед тем как показать финальный код, поясним один момент. Мы переводим данные с сервера в формат для JavaScript командой

newData = JSON.parse(res).map(Object.values);

В результате мы получаем двумерный массив, с которым можно работать так:

newData[1][0].name = 'Привет';
newData[3][0].lastname = 'Привет';

Дело тут вот в чём: первая цифра в квадратных скобках отвечает за порядковый номер JSON-записи, которые мы отправляли на сервер. Нумерация идёт с нуля, как принято у программистов.

Вторая цифра у нас всегда 0, потому что хотя это и двумерный массив, но каждая запись состоит всего из одного элемента. Так как нумерация с нуля, то мы и пишем 0.

После этого через точку идёт имя поля — у нас это name и lastname. Через них мы можем обращаться к конкретным значениям и менять в них что угодно.

Такая громоздкость получилась из-за того, что мы решили проблему в лоб — просто перевели данные с помощью встроенных средств языка. Это можно было сделать гораздо красивее, но так — быстрее.

Сам код новой функции:

function editJSON() {
  // переводим данные от сервера в массив, понятный для JavaScript
  newData = JSON.parse(res).map(Object.values);
  // добавляем к каждому имени число с его длиной в скобках
  for (var i = newData.length - 1; i >= 0; i--) {
    newData[i][0].name = newData[i][0].name + '(' + newData[i][0].name.length + ')';
    console.log(newData[i][0].name);
  }
  // а вот сюда мы поместим ответ от сервера
  let result = document.querySelector('.result');
  // создаём новый экземпляр запроса XHR
  let xhr = new XMLHttpRequest();
  // адрес, куда мы отправим нашу JSON-строку
  let url = "http://mihailmaximov.ru/projects/json/edit.php";
  // открываем соединение
  xhr.open("POST", url, true);
  // устанавливаем заголовок — выбираем тип контента, который отправится на сервер, в нашем случае мы явно пишем, что это JSON
  // xhr.setRequestHeader("Content-Type", "application/json");
  // когда придёт ответ на наше обращение к серверу, мы его обработаем здесь
  xhr.onreadystatechange = function () {
    // если запрос принят и сервер ответил, что всё в порядке
    if (xhr.readyState === 4 && xhr.status === 200) {
      // выводим то, что ответил нам сервер — так мы убедимся, что данные он получил правильно
      result.innerHTML = this.responseText;
    }
  };
  // преобразуем наши новые данные в JSON-строку
  sendData = JSON.stringify(newData);
  // когда всё готово, отправляем JSON на сервер
  xhr.send(sendData);
}

Делаем новый PHP-обработчик на сервере

В скрипте мы обращались к файлу edit.php, которого у нас ещё нет. Всё, что нужно от этого файла, — чтобы он сохранил то, что ему пришло, и тут же отправил это обратно, чтобы мы убедились, что всё хорошо. Мы специально выносим такую простую функцию в отдельный файл, чтобы каждый из них отвечал за свою область работы.

Сам файл довольно прост:

<?php
// на какие данные рассчитан этот скрипт
header("Content-Type: application/json");
// получаем данные от страницы
$data = file_get_contents("php://input");
// открываем наш файл с данными
$file = file_get_contents('data.json');
// записываем в него то, что пришло от страницы
file_put_contents('data.json', $data);
// тут же заново считываем все данные, чтобы убедиться, что всё записалось правильно
$file = file_get_contents('data.json');
// и сразу отправляем их на страницу, чтобы это увидел пользователь
echo $data;
// освобождаем память
unset($file);
Сразу видим результат — программа посчитала количество символов в каждом имени, добавила их и сохранила все данные на сервере

Что дальше

Теперь у нас всё готово, чтобы переделать наши старые проекты и научить их хранить свои данные в облаке. Этим и займёмся.

<!DOCTYPE html>
<html>

<head>
  <title>
    Отправляем JSON-данные на сервер
  </title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>

<body style="text-align:center;" id="body">
  <!-- заголовок -->
  <h1> Простая форма для проверки работы JSON </h1>
  <!-- делаем форму с полями ввода -->
  <p>
    <input type="text" id="name" placeholder="Ваше имя">
    <input type="text" id="lastname" placeholder="и фамилия">
    <!-- по нажатию на эту кнопку данные уйдут на сервер -->
    <button onclick="sendJSON()">Проверить JSON</button>
    <!-- эта кнопка поменяет полученные данные и отправит их снова на сервер -->
    <button onclick="editJSON()">Изменить JSON</button>
    <!-- а вот тут они появятся снова, но уже после обработки сервером -->
  <p class="result" style="color:blue"></p>
  </p>
  <!-- скрипт, который обработает нажатие на кнопку и отправит данные на сервер -->
  <script>
    var res;
    var newData;
    var sendData;
    // эта функция сработает при нажатии на кнопку
    function sendJSON() {
      // с помощью jQuery обращаемся к элементам на странице по их именам
      let name = document.querySelector('#name');
      let lastname = document.querySelector('#lastname');
      // а вот сюда мы поместим ответ от сервера
      let result = document.querySelector('.result');
      // создаём новый экземпляр запроса XHR
      let xhr = new XMLHttpRequest();
      // адрес, куда мы отправим нашу JSON-строку
      let url = "http://mihailmaximov.ru/projects/json/json.php";
      // открываем соединение
      xhr.open("POST", url, true);
      // устанавливаем заголовок — выбираем тип контента, который отправится на сервер, в нашем случае мы явно пишем, что это JSON
      // xhr.setRequestHeader("Content-Type", "application/json");
      // когда придёт ответ на наше обращение к серверу, мы его обработаем здесь
      xhr.onreadystatechange = function () {
        // если запрос принят и сервер ответил, что всё в порядке
        if (xhr.readyState === 4 && xhr.status === 200) {
          // запоминаем данные, которые пришли с сервера
          res = this.responseText;
          // выводим то, что ответил нам сервер — так мы убедимся, что данные он получил правильно
          result.innerHTML = this.responseText;
        }
      };
      // преобразуем наши данные в JSON-строку
      data = JSON.stringify({ "name": name.value, "lastname": lastname.value });
      // когда всё готово, отправляем JSON на сервер
      xhr.send(data);
    }
    function editJSON() {
      // переводим данные от сервера в массив, понятный для JavaScript
      newData = JSON.parse(res).map(Object.values);
      // добавляем к каждому имени число с его длиной в скобках
      for (var i = newData.length - 1; i >= 0; i--) {
        newData[i][0].name = newData[i][0].name + '(' + newData[i][0].name.length + ')';
        console.log(newData[i][0].name);
      }
      // а вот сюда мы поместим ответ от сервера
      let result = document.querySelector('.result');
      // создаём новый экземпляр запроса XHR
      let xhr = new XMLHttpRequest();
      // адрес, куда мы отправим нашу JSON-строку
      let url = "http://mihailmaximov.ru/projects/json/edit.php";
      // открываем соединение
      xhr.open("POST", url, true);
      // устанавливаем заголовок — выбираем тип контента, который отправится на сервер, в нашем случае мы явно пишем, что это JSON
      // xhr.setRequestHeader("Content-Type", "application/json");
      // когда придёт ответ на наше обращение к серверу, мы его обработаем здесь
      xhr.onreadystatechange = function () {
        // если запрос принят и сервер ответил, что всё в порядке
        if (xhr.readyState === 4 && xhr.status === 200) {
          // выводим то, что ответил нам сервер, — так мы убедимся, что данные он получил правильно
          result.innerHTML = this.responseText;
        }
      };
      // преобразуем наши новые данные JSON в строку
      sendData = JSON.stringify(newData);
      // когда всё готово, отправляем JSON на сервер
      xhr.send(sendData);
    }
  </script>
</body>

</html>

<?php
// на какие данные рассчитан этот скрипт
header("Content-Type: application/json");
// 1. Получаем данные от страницы
$data = json_decode(file_get_contents("php://input"));
// 2. Проверяем, есть ли на сервере нужный нам файл с данными — json.data.
// Берём новую переменную и пишем в неё имя файла
$filename = 'data.json';
// 3. Если есть — запоминаем его содержимое, а если такого файла нет — создаём его отдельной командой.
if (file_exists($filename)) {
    // Если файл есть — открываем его и читаем данные
    $file = file_get_contents('data.json');
    // Если такого файла нет…
} else {
// …то создаём его сами
    $file = fopen("data.json", "a+");
}
// 4/ Всё, что было в этом файле, переводим в массив, с которым умеет работать PHP. Таким способом у нас каждая JSON-запись будет храниться в отдельной ячейке массива.
$taskList = json_decode($file, true);
// 5. Добавляем новую запись в этот массив — кладём в него то, что пришло со страницы.
$taskList[] = array($data);
// 6. Записываем это всё обратно в файл и тут же читаем обратно из него — так мы убедимся, что запись прошла нормально и мы можем с этим работать.
// Записываем данные в файл…
file_put_contents('data.json', json_encode($taskList));
// …и сразу считываем их обратно
$file = file_get_contents('data.json'); // Открыть файл data.json
// 7. Отправляем всё содержимое файла на страницу, чтобы там увидеть, что сервер работает как нужно.
echo $file;
// Освобождаем память от переменных, которые нам пока не нужны
unset($file);
unset($taskList);

<?php
// на какие данные рассчитан этот скрипт
header("Content-Type: application/json");
// получаем данные от страницы
$data = file_get_contents("php://input");
// открываем наш файл с данными
$file = file_get_contents('data.json');  
// записываем в него то, что пришло от страницы
file_put_contents('data.json',$data);  
// тут же заново считываем все данные, чтобы убедиться, что всё записалось правильно
$file = file_get_contents('data.json'); 
// и сразу отправляем их на страницу, чтобы это увидел пользователь
echo $data;
// освобождаем память 
unset($file);        
?>

Текст

Михаил Полянин

Редактор

Михаил Полянин

Корректор

Ирина Михеева

Иллюстрация

Даня Берковский

Вёрстка

Мария Дронова

Соцсети и вот это всё

Виталий Вебер

Рассказал всем

Виталий Вебер

Апскиллинг, как говорится
Апскиллинг — это, например, переход с уровня junior на уровень middle, а потом — senior. У «Яндекс Практикума» есть курсы ровно для этого: от алгоритмов и типов данных до модных фреймворков.
Изучить вопрос
Апскиллинг, как говорится Апскиллинг, как говорится Апскиллинг, как говорится Апскиллинг, как говорится
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
medium