Clickusha (server side)

JS-PHP MVC интерфейс — cобираем всё вместе

Для начала я хочу поблагодарить m007, который подал идею, как можно упростить Programmer-friendly интерфейс взаимодействия Клиент(JS)-Сервер(PHP), что и поспособствовало написанию этой статьи.

Данная статья является заключительной, в которой я объединю JS-Шаблоны, PHP Model-controller, и добавлю Динамическое создание UI методов на JS (некоторые идеи которого были взяты из статьи m007). Тем самым мы получим на выходе неплохой и удобный фундамент для создания своих AJAX приложений.

Динамическое создание методов на JavaScript

Для начала хочу обратить ваше внимание, что все наши методы лежат в PHP-библиотеке. Каждый метод можно вызвать, передав определенные параметры в стиле JSON. И чтобы вызвать PHP-метод из JS, я предлагал в прошлой статье использовать функцию server_exec. Но можно это сделать более удобно и
информативно для программиста.
m007 предложил вызывать функции прямо из JS, то есть вместо server_exec(«database_func(. );»,function()<. >) использовать в JS database.func(. ).

В PHP, для не объявленных функций, есть метод __call. В JS такого метода нет, но можно предварительно подгрузить методы из PHP-библиотеки и динамически добавить их в JS-класс.

Для этого в PHP-класс UserInterface (см. прошлую статью) был добавлен метод, который при ‘пустом’ запросе выводил все зарегистрированные методы.
На Javascript написан класс PHPUIclass, который является интерфейсом для UserInterface. В этом классе описан метод обработки `пустого` запроса (спасибо DmitryBaranovskiy за приведение кода в порядок):

this .add= function (res) var methods=eval( » );
for ( var index in methods)
that[methods[index]] = ( function (name) return function () request.push( ‘»‘ + name + ‘»:’ + that.methods(Array.prototype.slice.call(arguments)));
if (!timer)
timer=window.setTimeout( function () ajax_load(url, «method=» , that.ajax_run, true );
>,0);
>;
>)(methods[index]);
> * This source code was highlighted with color=’gray’>Source Code Highlighter .

Эта функция вызывается, когда PHP-библиотека возвращает названия зарегистрированных методов UI (ответ на ‘пустой’ запрос). Исходя из этих данных, этот метод создаёт внутри своего класса новые методы, которые используют для вызова public-методов PHP-библиотеки.

Читайте также:  Css style textarea background color

При запуске метода, происходит кодирование входящих параметров (request.push(‘»‘+methods[index]+'»:’+that.methods(Array.prototype.slice.call(arguments)))) и установка нулевого таймера на функцию для отсылки запроса. Думаю, что некоторых читателей этот момент удивил. По этому я остановлюсь на нём поподробнее.

Javascript не имеет потоков и весь код выполняет последовательно. Состояния у него всего два – выполнение кода и ожидание прерывания. Прерывания могут прийти, например, от таймера (по таймауту), от AJAX запроса (при смене статуса) и т д. При этом запускается состояния выполнение кода, который не прерывается, пока не дойдёт до конца.
Именно для этого я использую нулевой таймер, который запустит выполнение функции отсылающей запрос на сервер, после окончания выполнения основного кода. Сделано это для того, чтобы отсылать всё одним инкрементированным запросом, состоящим из всех вызываеммых функций и обрабатывать результаты последовательно.

Теперь можно перейти к обработке результатов запроса. Так как обработчик будет вызван не сразу – то это будет функция или несколько функций, которые необходимо вызвать, когда придет ответ.
Этим занимаются методы run и ajax_run. Первый добавляет функции на запуск после получения ответа. Функции должны иметь вид function(data). А функция ajax_run занимается их запуском.

this .ajax_run= function (req) var ret=eval( ‘(‘ +req.responseText+ ‘)’ );
for ( var i in func)
if (func[i])
func[i](ret);
request=[];
func=[];
timer= false ;
> * This source code was highlighted with color=’gray’>Source Code Highlighter .

В результате мы получаем модифицируйщийся класс, в зависимости от установленных методов в PHP. И взаимодействие с ним выглядит очень удобно:

//Инициализация класса удаленной работы с файлами.
/* Синхронный запрос на вызов FileManager.php.
Получение методов dir,save,read.
Динамическое создание функций. */
var File= new PHPUIclass( ‘FileManager.php’ );

//Вызов удалённых функций
/* Установка таймера и формирования запроса */
File.save( «edited.txt» , «Отредактированная часть файла» );
File.read( «save.log» );

Читайте также:  Http error 500 php mysql

//Установка функций для получения результатов запроса.
/* Добавление функции для обработки запроса read */
File.run(show_file);

/* Добавление функции для обработки запроса dir */
File.run(show_dir);

//Конец выполнения скрипта, а значит выполнение POST-запроса по Timeout(0) и возвращение результатов в show_file и show_dir * This source code was highlighted with Source Code Highlighter .

function check_file(result) if (result.ERROR && result.ERROR.checkfile)
show_error(result.ERROR.checkfile);
else // Всё прошло нормально?
// Тогда ещё один запрос, уже на чтение.
File.read(result[ «filename» ]);
File.run(show_file);
>
>

//Вызов удалённых функций
File.checkfile( «edited.txt» );

File.run(check_file); * This source code was highlighted with Source Code Highlighter .

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

function checkfile($filename) global $UImethod;
if (file_exists($filename))
return $UImethod->read($filename);
else
return array( «ERROR» => array( «checkfile» =>$filename));
>

Теряется модульность, но в данной реализации Javascript библиотеки, пока это единственный выход. Возможно в будующем я усовершенствую её, при необходимости.

Пример

А вот — простой пример. File-viewer с возможностью редактировать файлы.

PHP:
UI.php основной класс UserInterface — подключается в библиотеку.
mod.fileview.php библиотека для чтения-записи файлов — функции read и save.
mod.dirview.php библиотека для чтения дириктории — функция dir.
mod.backup.php библиотека для формирования save.log — функции read,save,dir.
FileManager.php основной файл, который включает в себя все модули и запускает обработчик запроса.

Javascript:
PHPUI.js основной класс, который занимается подключением к интерфейсу UserInterface в php.
skin.js — класс работы с шаблонами.
index.html — загрузка шаблонов, вывод файлов.

Послесловие

Плюсы:
— Удобство программирования и создания новых методов для JS-интерфейса
— Ясность и прозрачность кода
— Универсальность методов
— Возможен вызов функций с неопределенным количеством параметров
Минусы:
— Нет проверки на параметры методов. Возможны простейшие ошибки при создании кода. Но для этого можно в PHP-функциях проверять пришедшие параметры (например для DEBUG-MODE). В случае не верных параметров, выводить alert(«ERROR»).

Читайте также:  Сортировка data frame python

p.s. кстати, модель этого проекта является MVC.

Источник

Php серверный javascript клиентский

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

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

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

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

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

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

  

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

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

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

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

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

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

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

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

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

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

      '; > //Подвал страницы на HTML: function end1 () < echo ''; 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($db)) return 1; else if (intval($da) > $status = 1; //Статус, который вернём клиенту; 1=ошибка //Читаем и вносим в массив $a список из файла: $table = @file_get_contents ($GLOBALS['filename']); $a = explode("\n", $table, $GLOBALS['limit']); if (isset($_GET['a'])) < //Если это был запрос "Показать список" start1(); if (count($a)Список лучших пока пуст, станьте первым

'; > else < echo ''."\n". ''; for ($i=0; $i'; > echo '
ИмяРезультатДата
'.$name.''.$result.''.date("d.m.Y, H:i",$date).'
'."\n"; > end1(); > else if (isset($_POST['name']) and isset($_POST['cnt'])) < //Если это был запрос на внесение данных $name = htmlspecialchars(alltrim($_POST['name'])); //Получить имя $cnt = intval(htmlspecialchars(alltrim($_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.

26.09.2014, 13:23 [12189 просмотров]

Источник

Оцените статью