Node.js + PHP — интеграция

С каждым днём технологии развиваются всё интенсивнее. Новое приходит на смену старому либо дополняет его. Так происходит и в мире веб-разработки. Старый-добрый PHP порой не может справится с поставленными задачами, либо справляется, но не так легко и элегантно, как новые технологии (например, Node.js).

Но решение можно найти всегда. Можно полностью погрузится с головой в новшества, можно писать костыли, а можно привлечь для помощи новшества.

В этой статье я хотел бы рассказать как-раз о третьем варианте. Думаю, если Вы читаете эту статью, то, наверняка, интересовались что же за зверь такой этот Node.js, и мне нет смысла об этом рассказывать.

Поговорим лучше об интерации Node.js с PHP. В частности статья будет об интеграции с PHP модуля для Node.js под названием socket.io, но думаю любой другой энтузиаст сможет применить описанные решения для себя.

Чтобы не писать слишком абстрактно, поставим задачу: написать проект на PHP (на фреймворке или своими руками) с личными кабинетами пользователей и межпользовательской системой сообщений, т.е. “Диалогами”.

В ходе разработки всплывает две основные проблемы.

Проблема №1 — авторизация

Представим что Вы сделали авторизацию и личные кабинеты на вашем сайте. И вот подходит момент когда пора писать “Диалоги”. Первым делом Вы устанавливаете node.js и модуль socket.io, пишете server-side для “Диалогов”.

1
2
3
4
5
var io = require('socket.io').listen(8080);
io.set('log level', 1);
io.sockets.on('connection', function (socket) {
????????
});

Тут и появляется вопрос… Как же идентифицировать нашего авторизованного через PHP пользователя в Node.js? Ведь у него есть вполне определённый id. Но как нам его получить. В большинстве случаев, для этого используются cookies. Они служат своего рода указателями на php-сессию хранимую на сервере.

Идея первая (ошибочная)

Сразу всплывает вариант получить cookies и с помощью них получить php-сессию. К сожалению, решения я не нашёл. Даже не предполагаю, что такое возможно.

Идея вторая

Идея заключается в том, чтобы хранить сессии не native-методом, а, например, в базе или memcached, или redis. Соглашусь что решение элегантное. Но давольно-таки сложное для новичков. Используя его всплывёт ряд проблем: установка и настройка хранилища сессий и конечно же сериализация сессий на стороне PHP (все сохраняемые сессии автоматически сериализуются и требуют десериализации после их получения). Одно из таких решений представлено здесь: Integrating Node.js with PHP. И ещё презентация с парой схем и полезными ссылками.

Идея третья (простая)

По неизвестным мне причинам, в интернете ничего похожего не нашёл. Идея заключается в том, чтобы (утрирую) “спросить у PHP авторизован ли у тебя пользователь с таким вот cookie 1234?”. Для этого мы воспользуемся “аналогом cURL для Node.js” — requestify. Систаксис этого модуля схож с ajax запросами в jQuery. С помощью него мы будем посылать запрос PHP, подделывая кукисы на кукисы пользователя. Модуль Socket.io имеет встроенную функцию авторизации, что значительно упрощает нам жизнь.

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
var requestify = require('requestify');

var io = require('socket.io').listen(8080);
io.set('log level', 1);
/**
* Авторизация для socket.io
* Выдаёт себя за пользовательский браузер (кукисы + юзерагент) и проверяет авторизованность в php
*/
io.configure(function(){
io.set('authorization', function(handshakeData, callback) {
requestify.get('http://example.com/ajax/get_user_array', {
dataType: 'json',
headers: {
'Cookie': handshakeData.headers["cookie"],
'User-Agent': handshakeData.headers["user-agent"],
'X-Requested-With': 'XMLHttpRequest'
}
}).then(function(response) {
var user = JSON.parse(response.getBody());
handshakeData.user = user;
callback(null, true);
}, function(err){
callback(null, false);
});
});
});

io.sockets.on('connection', function (socket) {
// переменная в которой теперь содержится информация о текущем пользователе в виде json массива, вернувшегося из PHP
var user = socket.handshake.user;
socket.join(user.id);

//здесь пишутся собственные методы обработки событий

socket.on('disconnect', function() {
socket.leave(user.id);
});
});

Метод get_user_array() в PHP:

1
2
3
4
5
6
7
8
9
10
11
function get_user_array() {
$user = Auth::instance()->get_user();
if(!$user)
throw new HTTP_Exception_404('File not found!');
$user = array(
'id' => $user->id,
'username' => $user->username,
'email' => $user->email,
);
echo json_encode($user);
}

Если пользователь не авторизован - возвращется 404. В противном случае возвращется json-массив с информацией о пользователе.

Проблема №2 — работа с базой

  1. Идея первая — работа с базой напрямую из Node.js. Для этого есть множество модулей. Уверен Вы сможете выбрать подходящий.
  2. Идея вторая — использовать requestify. Как и в первом случае с авторизацией можно отсылать запросы. Например, на отправку сообщений (http://example.com/ajax/send_message).

Конечно же выбор способов за Вами. Я же предпочёл метод запросов.

Был бы рад получит Ваши отзывы, вопросы, замечания!

Поделиться Комментарии