БлогNot. Привязываем к клиенту Javascript серверную часть на PHP

Привязываем к клиенту Javascript серверную часть на PHP

Мне понадобилось в учебных целях (и пока без JQuery) продемонстрировать, как можно для клиентского скрипта, например, некой игры, написанной на HTML+Javascript, поддерживать с помощью серверного скрипта на PHP некий общий для всех файл (например, таблицу лучших игроков).

При этом хотелось бы сделать следующее:

  • реализовать отправку данных от клиентского скрипта серверному, который отвечает за сохранение общей для всех таблицы результатов;
  • хранить в обычном текстовом файле небольшое фиксированное число записей вида "счёт-имя-дата/время" (базу пока тоже не используем);
  • максимально просто и хотя бы минимально безопасно обновлять данные по запросу из клиента;
  • серверный скрипт должен уметь сообщать клиентскому результаты своей работы, то есть, по выполнении кода, редиректить обратно на страницу клиента, при этом клиентский скрипт показывает, что сделал серверный.

Саму "игру" возьмём простейшей, кто больше раз нажмёт кнопку, тот и прав. А раз можно только тупо кликать, пусть "Кликушей" продукт и называется.

Вот код клиентского скрипта и комментарии к нему:

<script type="text/javascript" charset="UTF-8">
 function trim(string) {
  return string.replace (/\s+/g, " ").replace(/(^\s*)|(\s*)$/g, '');
 }
 function getname () {
  var name = window.prompt ("Пожалуйста, введите Ваше имя:", "Гость");
  if (name==null || trim(name)=='') name = "Гость";
  return trim(name);
 }
 function getparam () {
  var params_object = {}; 
  var params_array = window.location.search.substring(1).split("&"); 
  for (var i=0; i<params_array.length; i++) { 
   var getVar = params_array[i].split("="); 
   params_object[getVar[0]] = (typeof(getVar[1])=="undefined" ? "" : getVar[1]); 
  } 
  return params_object; 
 }
 function click1 () { document.f1.cnt0.value=++cnt; }
 function click2 () { document.f1.cnt.value=document.f1.cnt0.value; }


 document.writeln ('<p id="status">Стань лучшей кликушей :)</p>');

 var params = getparam ();
 var status=params['status'];
 var status_msg= new Array (
  'Вы успешно записаны в список лучших',
  'К сожалению, Ваш результат не попал в список лучших',
  'Неверный вызов скрипта');
 if (status!='' && status!='undefined') {
  var status_number = parseInt(status);
  if (!isNaN(status_number) && status_number>-1 && status_number<status_msg.length)
   document.getElementById('status').innerHTML = status_msg[status];
 }
 var name=decodeURI(params['name']);
 if (name=='' || name=='undefined') name = getname();
 var cnt=0;

 document.writeln ('<form name="f1" method="post" action="server.php">'+
  '<p>Ваше имя: '+name+". \n"+
  'Щёлкай: <input type="button" name="cnt0" value="0" onClick="click1()"> '+"\n"+
  '<input type="hidden" name="name" value="'+name+'">'+"\n"+
  '<input type="submit" name="cnt" value="Отправь&nbsp;результат" onClick="click2()"></form></p>'+"\n"+
  '<p><a href="server.php?a=show" target="_blank">Список&nbsp;лучших</a></p>');
</script>
<noscript><p>Извините, для работы приложения нужен включённый Javascript</p></noscript>

Рекомендуется в заголовке HTML-документа со скриптом поставить вот такие мета-теги:

<head>
 <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
 <meta content="text/html; charset=UTF-8" http-equiv="content-type">
 <title>Clickusha (client side)</title>
</head>

Метод trim убирает из строки-параметра как лишние пробелы между словами, так и лишние лидирующие или завершающие пробелы.

Метод getname() позволяет ввести имя пользователя или оставить его без изменений. Рекомендуется всегда использовать имя по умолчанию. Как-то я видел "бесконечный" ввод имени, то есть, примерно вот такую getname():

function getname () {
 var input=false;
 var name='';
 while (input==false) {
  name = prompt("Пожалуйста, введите Ваше имя:", "Гость");
  if (name!=null && trim(name)!='') input=true;
 } 
 return trim(name);
}

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

Метод getparam() - пример того, как на Javascript обработать параметры, переданные странице методом GET (через URL-адрес). Возвращает объект, а не просто массив, то есть, при вызове

var params = getparam ();
параметр с именем status надо получать в виде
var status=params['status'];

Методы click1() и click2() понадобились потому, что стандартная кнопка отправки данных в HTML <input type="submit"> игнорирует другие кнопочные элементы, так что мы не смогли бы передать число от кнопки с цифрой.

Можно было попробовать отправлять результат и так:

document.writeln ('<a href="#" onClick="post1()">Отправь&nbsp;результат</a>');
//...
function post1 () { 
 if (name!="" && cnt>0) { 
  location.replace ('server.php?name='+name+'&cnt='+cnt);
 } 
}

принимая его в серверном скрипте методом GET, но это может быть запрещено, например, модулем Анти-баннер антивируса Касперского.

Основные действия серверного скрипта подробно закомментированы:

<?php
 //Глобальные настройки скрипта:
 $GLOBALS['key'] = "\t"; //Разделитель в записи "Счёт-Имя-Дата/Время"
 $GLOBALS['limit'] = 10; //Максимальное число записей
 $GLOBALS['filename'] = './data.txt'; //Путь к файлу с  записями

 //Шапка страницы на HTML:
 function start1 () {
  echo '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
   <html>
    <head>
     <meta content="text/html; charset=UTF-8" http-equiv="content-type">
     <title>Clickusha (server side)</title>
    </head>
   <body>';
 }

 //Подвал страницы на HTML:
 function end1 () {
  echo '</body></html>';
  exit (2);
 }

 //Функция для сравнения 2 записей файла
 function compare ($a,$b) {
  //счёт-имя-дата/время
  @list ($ca,$na,$da) = explode ($GLOBALS['key'], $a);
  @list ($cb,$nb,$db) = explode ($GLOBALS['key'], $b);
  if (intval($ca)>intval($cb)) return 1;
  else if (intval($ca)<intval($cb)) return -1;
  else {
   if (intval($da)>intval($db)) return 1;
   else if (intval($da)<intval($db)) return -1;   
   else return strcmp($na,$nb);
  }
 }

 $status = 1; //Статус, который вернём клиенту; 1=ошибка

 //Читаем и вносим в массив $a список из файла:
 $table = @file_get_contents ($GLOBALS['filename']);
 $a = explode("\n", $table, $GLOBALS['limit']);
 if (isset($_GET['a'])) { //Если это был запрос "Показать список"
  start1();
  if (count($a)<2 and empty($a[0])) {
   echo '<p>Список лучших пока пуст, станьте первым</p>';
  }
  else {
   echo '<table border="1" cellpadding="4" cellspacing="0">'."\n".
    '<tr><th>Имя</th><th>Результат</th><th>Дата</th></tr>';
   for ($i=0; $i<min(count($a),$GLOBALS['limit']); $i++) if (!empty($a[$i])) {
    list ($result, $name, $date) = explode ($GLOBALS['key'], $a[$i]);
    echo '<tr><td>'.$name.'</td><td>'.$result.'</td><td>'.date("d.m.Y, H:i",$date).'</td></tr>';
   }
   echo '</table>'."\n";
  }
  end1();
 }
 else if (isset($_POST['name']) and isset($_POST['cnt'])) { //Если это был запрос на внесение данных
  $name = htmlspecialchars(trim($_POST['name'])); //Получить имя
  $cnt = intval(htmlspecialchars(trim($_POST['cnt']))); //...и счёт игрока
  if ($cnt>0) { //Если счёт не пуст,
   $time = time(); //получить метку времени,
   $key = $GLOBALS['key']; //разделитель записей,
   $item = "$cnt$key$name$key$time"; //сформировать строку с новой записью,
   array_push ($a, $item); //сунуть её в массив,
   $a = array_unique($a); //на всякий случай, убить одинаковые элементы в массиве,
   if (count($a)>1) uasort ($a,'compare'); //отсортировать записи собственной функцией,
   $a = array_slice(array_reverse ($a),0,$GLOBALS['limit']); 
    //перевернуть массив (по убыванию счёта) и избавиться от лишних записей
   $data = implode ("\n",$a); //положить данные в строку $data
   $status = (in_array($item,$a)==true?0:1); //новый элемент в массиве? Если да, статус=0 (успех)
   if ($status==0) {
    $res = @file_put_contents ($GLOBALS['filename'],$data,LOCK_EX); //монопольно записать в файл
    if ($res === false) $status = 2; //НЕ удалось записать - увы, вернём ошибку :)
   }
  }
 }

 header('Location: index.html?status='.$status.'&name='.$name); //Вернём клиенту его имя и статус
?>

Следует помнить, что для более безопасной работы с данными существуют базы, а сделать всё с меньшими усилиями в наше время можно с помощью библиотеки JQuery.

 Посмотреть всё в работе


теги: javascript php jquery безопасность

26.09.2014, 13:23; рейтинг: 10645