Среди форматов обмена данными, AJAX программисты часто выделяют JSON (JavaScript Object Notation, “джейсн”), как альтернатива языку XML, а именно потому, что XML больше язык разметки, чем носитель данных. JSON в свою очередь, легкий, человеко-читабельный, текстовый формат для хранения и передачи простых структурированных данных, а так же более комплексных объектов (массивов). В этом уроке мы рассмотрим простой пример формирования данных в JSON средствами PHP, а так же их получение и представление, с помощью JavaScript. Кто еще не понял, это продолжение серии уроков “AJAX PHP поиск” (XML, Prototype).

JSON structure

Чем отличается представление данных в JSON от, допустим, XML. Простой пример:

{ "players" : [
  { "firstName" : "Ryan", "lastName" : "Campbell", "position" : "S" },
  { "firstName" : "Chris", "lastName" : "Campbell", "position" : "QB" },
  { "firstName" : "Kevin", "lastName" : "Hale", "position" : "DT" }
]}

Здесь у нас есть элемент players, который в свою очередь является массивом из трех “рядов”, а каждый такой “ряд” это массив еще из трех элементов (firstName, lastName, position). Самое интересное то, что в языке JavaScript есть встроенная функция eval(), которая “парсит” (разбирает) такие строки.

Ну например, допустим у нас эти данные хранятся в переменной s (уже в JavaScript):

var obj = eval("(" + s + ")");

Мы получаем объект obj, который будет хранить все эти данные в очень удобной структуре:

alert(obj.players[0].firstName); // Ryan
alert(obj.players[1].lastName); // Campbell
alert(obj.players[2].position); // DT

Вот таким образом мы получаем доступ к JSON данным. Формирование таких данных мало чем отличается. Ну например на языке PHP:

1
2
3
4
5
6
7
8
9
10
$a = array();
 
$a["players"][0]["firstName"] = "Ryan";
$a["players"][0]["lastName"] = "Campbell";
$a["players"][0]["position"] = "S";
 
...
 
$json = new Services_JSON();
echo $json->encode($a);

На входе методу encode() подается любой массив, и метод возвращает закодированный в JSON такой же массив, готовый для передачи куда-либо.

Например..

Вспомним уроки создания AJAX поиска методами XML и Prototype. Попробуем еще разок продублировать этот пример, только уже с использованием JSON для представления данных.

Посмотреть в действии можно здесь:
http://logicerror.pp.ru/upload/ajax_search_json/

Начинаем:

  1. база данных MySQL
  2. html файл для вывода информации (index.html)
  3. AJAX скрипт (script.js)
  4. PHP двигатель (search.php)

В php5 уже встроены функции для работы с JSON данными. Для php4 качаем PEAR библиотеку json.php отсюда:
http://pear.php.net/pepr/pepr-proposal-show.php?id=198

База данных и HTML представление страницы у нас не изменилось совсем (ну кроме заголовка в HTML), так что у кого до сих пор нет, копируем отсюда:
http://blog.kovshenin.com/archives/ajax-php-search-xml

AJAX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function getXmlHttp() {
  var xmlhttp;
  try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
      xmlhttp = false;
    }
  }
 
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    xmlhttp = new XMLHttpRequest();
  }
  return xmlhttp;
}
 
function search() {
  var sSearch = document.getElementById("search_input").value;
 
  if (sSearch.length < 3)
  {
    alert("Запрос должен быть не короче 3-х символов.");
    return false;
  }
 
  var xmlHttp;
  xmlHttp = getXmlHttp();
 
  var obj = document.getElementById("search_results");
  obj.innerHTML = "";
  var loading = document.getElementById("searching");
  loading.style.display = "block";
 
 
  xmlHttp.onreadystatechange = function()  {
    if (xmlHttp.readyState == 4)
    {
      loading.style.display = "none";
      var json = eval( "(" + xmlHttp.responseText + ")" );
      for (var i = 0; i < json.entry.length; i++)
      {
        var new_el = document.createElement("div");
        new_el.innerHTML = "<h1>" + json.entry[i].title + "</h1>" + json.entry[i].content;
        new_el.className = "result";
 
        obj.appendChild(new_el);
      }
    }
  }
 
  xmlHttp.open('GET', 'search.php?search='+sSearch+'&rand='+Math.random(), true);
  xmlHttp.send(null);
}

В script.js у нас произошли некоторые изменения в районе обработки и представления данных. Рассмотрим по порядку:

var json = eval( "(" + xmlHttp.responseText + ")" );

В переменную json, мы помещаем объект полученный функцией eval, которая целиком разбирает текст полученный с запрашиваемой страницы - xmlHttp.responseText (JSON ведь именно в текстовом формате данные хранит, помните?). Таким образом, переменная json у нас теперь полноценный объект с данными результата поиска.

1
2
3
4
5
6
7
8
for (var i = 0; i < json.entry.length; i++)
{
  var new_el = document.createElement("div");
  new_el.innerHTML = "<h1>" + json.entry[i].title + "</h1>" + json.entry[i].content;
  new_el.className = "result";
 
  obj.appendChild(new_el);
}

Здесь, узнав сколько всего записей у нас получено (json.entry.length, где entry у нас массив - поймете когда дойдем до части php), мы в цикле обрабатываем все элементы этих записей. То есть, как и в первом самом уроке, создаем новый элемент div, помещаем в него (.innerHTML) один сформированный результат поиска, присваиваем класс result, ну и наконец приклеиваем к объекту obj (поле для результатов поиска).

Теперь рассмотрим, как мы сформировали JSON данные.

PHP & JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
  $db = mysql_connect("localhost", "root", "");
  mysql_select_db("ajax_search");
  mysql_query("SET CHARACTER SET utf8");
 
  require("json.php");
 
  header('Content-type: application/json; charset=utf-8');
  header('Cache-Control: no-cache');
 
  $entry = array();
 
  $sString = mysql_real_escape_string($_GET["search"], $db);
 
  $sql="SELECT * FROM `articles` WHERE `title` LIKE '%$sString%' OR `content` LIKE '%$sString%' ORDER BY `id` DESC LIMIT 10";
  $rs=mysql_query($sql,$db);
 
  if (mysql_num_rows($rs) > 0)
  {
    $i = 0;
    while ($row = mysql_fetch_array($rs))
    {
      $content=htmlspecialchars(strip_tags($row["content"]));
      if (mb_strlen($content, "utf-8") > 250) $content = mb_substr($content, 0, 250, "utf-8") . "...";
      $entry["entry"][$i]["title"] = htmlspecialchars($row["title"]);
      $entry["entry"][$i]["content"] = $content;
      $i++;
    }
  }
  else
  {
    $entry["entry"][0]["title"] = "";
    $entry["entry"][0]["content"] = "Ничего не найдено";
  }
 
  $json = new Services_JSON();
  echo $json->encode($entry);
?>

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

require("json.php");

Мы работаем на php4, так что обязательно подключаем PEAR библиотеку JSON (в которой и описан класс Services_JSON и методы encode/decode.

header('Content-type: application/json; charset=utf-8');

Согласно RFC 4627 JSON данные должны иметь MIME тип application/json, учтите это.

$entry = array();

Создаем простой пустой массив $entry. Сюда мы будем записывать наши данные, а потом кодировать в формат JSON.

1
2
3
4
5
6
7
8
9
10
$i = 0;
while ($row = mysql_fetch_array($rs))
{
  $content=htmlspecialchars(strip_tags($row["content"]));
  if (mb_strlen($content, "utf-8") > 250) $content = mb_substr($content, 0, 250, "utf-8") . "...";
 
  $entry["entry"][$i]["title"] = htmlspecialchars($row["title"]);
  $entry["entry"][$i]["content"] = $content;
  $i++;
}

Здесь переменная $i будет служить в качестве счетчика, далее обрабатываем поля title и content из базы данных (как и раньше), и в своеобразной форме записываем в массив $entry. Расскажу о структуре массива. Первый элемент у нас всегда будет “entry” - мы так к нему обращаемся в javascript - json.entry. Второй элемент - порядковый номер результата (счетчик наш), так же используется в js - json.entry[i]. Ну и последние элементы - поля title и content. И таким же образом к ним обращается js - json.entry[i].title и json.entry[i].content.

$entry["entry"][0]["title"] = "";
$entry["entry"][0]["content"] = "Ничего не найдено";

В случае если поисковой запрос не дал результатов, мы в массив $entry помещаем всего одну запись - нчиего не найдено.

$json = new Services_JSON();
echo $json->encode($entry);

Здесь все просто. Создаем новый объект из класса Services_JSON(), и вызываем функцию encode(), передав наш массив $entry в качестве параметра. Ну и естественно выводим это все.

Заключение

Ну вот, собственно, и все.
По сравнению с XML, JSON более прост и удобен в использовании (особенно тем, кто хорошо ориентируется в массивах), но есть несколько нюансов по безопасности - обязательно проверяйте JSON данные на код javascript перед тем, как использовать его в eval(), т.к. эта функция исполняет javascript код.

Ну а с Prototype можно и не сравнивать, особенно если использовать их в паре - Prototype+JSON. Prototype для удобной работы с AJAX запросами, а JSON для удобного представления данных.

Полезные ссылки

Google Bookmarks Digg Reddit del.icio.us Ma.gnolia Technorati Slashdot Yahoo My Web News2.ru БобрДобр.ru RUmarkz Ваау! Memori.ru rucity.com МоёМесто.ru Mister Wong