Возможности Как это работает Тарифы Документация Cookbook Партнёрам Личный кабинет
Серверный код
🚀

Интеграция с PHP

12 мин чтения Средне

Полное руководство по интеграции Pushler.ru с PHP. События, авторизация каналов, асинхронная отправка.

PHP SDK API

📋 Что получится

  • Broadcasting events через Pushler.ru
  • Private и Presence каналы
  • Авторизация и безопасность
  • Асинхронная отправка для высоких нагрузок
Универсальный подход: Примеры на PHP, но API и паттерны работают с любым языком — Node.js, Python, Go, Ruby, Java, C# и др. Pushler.ru предоставляет REST API для интеграции.

⚡ Быстрая настройка

Установка SDK

Bash
# PHP SDK
composer require pushler/php-sdk

# JavaScript SDK (для фронтенда)
npm install @pushler/js

Инициализация на сервере (PHP)

PHP
<?php
// pushler.php — инициализация Pushler

require_once 'vendor/autoload.php';

use PushlerRu\PushlerClient;

// Создаём клиент Pushler
$pushler = new PushlerClient(
    'key_ваш_ключ',      // Можно вынести в .env или config
    'secret_ваш_секрет'
);

// Для проектов с конфигом:
// $pushler = new PushlerClient(
//     getenv('PUSHLER_APP_KEY'),
//     getenv('PUSHLER_APP_SECRET')
// );

📡 Отправка событий

Базовая отправка события

PHP
<?php
// Подключаем Pushler
require_once 'pushler.php';

// Отправка события в публичный канал
$pushler->trigger(
    'news',                    // Название канала
    'article.published',       // Название события
    [                          // Данные
        'id' => 123,
        'title' => 'Новая статья',
        'author' => 'Иван Иванов'
    ]
);

// Отправка в приватный канал
$pushler->trigger(
    'private-user-456',
    'notification',
    [
        'type' => 'info',
        'message' => 'У вас новое сообщение'
    ]
);

// Отправка в несколько каналов сразу
$pushler->trigger(
    ['private-user-1', 'private-user-2', 'private-user-3'],
    'broadcast',
    ['message' => 'Важное объявление для всех']
);

Пример: Уведомление при создании заказа

PHP
<?php
// create_order.php

require_once 'pushler.php';

// Получаем данные заказа
$orderData = json_decode(file_get_contents('php://input'), true);
$userId = getCurrentUserId();

// Создаём заказ в БД
$pdo = getDbConnection();
$stmt = $pdo->prepare('
    INSERT INTO orders (user_id, total, status, created_at) 
    VALUES (?, ?, "pending", NOW())
');
$stmt->execute([$userId, $orderData['total']]);
$orderId = $pdo->lastInsertId();

// Данные для события
$eventData = [
    'order_id' => $orderId,
    'status' => 'pending',
    'status_text' => 'Ожидает подтверждения',
    'total' => $orderData['total'],
    'created_at' => date('c')
];

// Уведомляем клиента
$pushler->trigger(
    "private-user-{$userId}",
    'order.created',
    $eventData
);

// Уведомляем менеджеров
$pushler->trigger(
    'private-managers',
    'order.new',
    [
        'order_id' => $orderId,
        'total' => $orderData['total'],
        'customer' => getUserById($userId)
    ]
);

echo json_encode(['order_id' => $orderId, 'status' => 'created']);

Пример: Обновление статуса заказа

PHP
<?php
// update_order_status.php

require_once 'pushler.php';

$orderId = (int) $_POST['order_id'];
$newStatus = $_POST['status'];

// Обновляем в БД
$pdo = getDbConnection();
$stmt = $pdo->prepare('UPDATE orders SET status = ? WHERE id = ?');
$stmt->execute([$newStatus, $orderId]);

// Получаем данные заказа
$stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?');
$stmt->execute([$orderId]);
$order = $stmt->fetch(PDO::FETCH_ASSOC);

$statusTexts = [
    'pending' => 'Ожидает подтверждения',
    'confirmed' => 'Подтверждён',
    'processing' => 'Готовится',
    'shipped' => 'В доставке',
    'delivered' => 'Доставлен'
];

// Отправляем уведомление клиенту
$pushler->trigger(
    "private-user-{$order['user_id']}",
    'order.status.updated',
    [
        'order_id' => $orderId,
        'status' => $newStatus,
        'status_text' => $statusTexts[$newStatus] ?? $newStatus,
        'updated_at' => date('c')
    ]
);

echo json_encode(['success' => true]);

🔐 Авторизация каналов

PHP
<?php
// auth.php — endpoint авторизации каналов

require_once 'pushler.php';

header('Content-Type: application/json');

$channelName = $_POST['channel_name'];
$socketId = $_POST['socket_id'];
$userId = getCurrentUserId();

// Проверяем авторизацию
if (!$userId) {
    http_response_code(401);
    echo json_encode(['error' => 'Unauthorized']);
    exit;
}

// Проверяем доступ к каналу
if (!canAccessChannel($userId, $channelName)) {
    http_response_code(403);
    echo json_encode(['error' => 'Forbidden']);
    exit;
}

// Для presence-каналов
if (str_starts_with($channelName, 'presence-')) {
    $user = getUserById($userId);
    
    $auth = $pushler->authorizePresenceChannel($channelName, $socketId, [
        'user_id' => (string) $userId,
        'user_info' => [
            'name' => $user['name'],
            'avatar' => $user['avatar']
        ]
    ]);
    
    echo json_encode($auth);
    exit;
}

// Для приватных каналов
$auth = $pushler->authorizeChannel($channelName, $socketId);
echo json_encode($auth);

// ============================================
// Функция проверки доступа
// ============================================
function canAccessChannel(int $userId, string $channelName): bool
{
    // Приватный канал пользователя
    if (preg_match('/^private-user-(\d+)$/', $channelName, $matches)) {
        return (int) $matches[1] === $userId;
    }

    // Канал заказа — владелец или админ
    if (preg_match('/^private-order-(\d+)$/', $channelName, $matches)) {
        $orderId = (int) $matches[1];
        $order = getOrderById($orderId);
        return $order && ($order['user_id'] === $userId || isAdmin($userId));
    }

    // Канал менеджеров
    if ($channelName === 'private-managers') {
        return isManager($userId);
    }

    // Presence-канал чата
    if (preg_match('/^presence-chat-(\d+)$/', $channelName, $matches)) {
        $chatId = (int) $matches[1];
        return userHasAccessToChat($userId, $chatId);
    }

    return false;
}

🌐 Клиент (JavaScript)

Подключение и подписка

HTML
<!-- Подключение SDK -->
<script src="https://cdn.pushler.ru/sdk/pushler.min.js"></script>
JavaScript
// Инициализация
const pushler = new PushlerClient({
    appKey: 'key_ваш_ключ',
    authEndpoint: '/auth.php'
});

pushler.on('connected', () => {
    console.log('Подключено к Pushler');
    
    // Публичный канал — не требует авторизации
    const newsChannel = pushler.subscribe('news');
    newsChannel.on('article.published', (data) => {
        console.log('Новая статья:', data.title);
    });

    // Приватный канал пользователя
    const userChannel = pushler.subscribe(`private-user-${userId}`);
    
    userChannel.on('notification', (data) => {
        showNotification(data.message);
    });
    
    userChannel.on('order.status.updated', (data) => {
        updateOrderStatus(data.order_id, data.status, data.status_text);
    });

    // Presence-канал (для онлайн-статуса)
    const chatChannel = pushler.subscribe(`presence-chat-${chatId}`);
    
    chatChannel.on('pushler:subscription_succeeded', (data) => {
        console.log('Онлайн:', Object.values(data.members).map(m => m.name));
    });
    
    chatChannel.on('pushler:member_added', (member) => {
        console.log(`${member.info.name} присоединился`);
    });
    
    chatChannel.on('pushler:member_removed', (member) => {
        console.log(`${member.info.name} вышел`);
    });
});

// Обработка ошибок
pushler.on('error', (error) => {
    console.error('Ошибка Pushler:', error.message);
});

Vue 3 компонент для отслеживания заказа

Vue
<!-- OrderTracker.vue -->
<template>
  <div class="order-tracker">
    <div class="status" :class="order.status">
      {{ statusText }}
    </div>
    <div class="timeline">
      <div 
        v-for="step in steps" 
        :key="step.status"
        :class="['step', { active: isStepActive(step.status), done: isStepDone(step.status) }]"
      >
        <div class="dot"></div>
        <div class="label">{{ step.label }}</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import PushlerClient from '@pushler/js';

const props = defineProps({
    orderId: { type: Number, required: true },
    userId: { type: Number, required: true },
    initialStatus: { type: String, required: true },
    appKey: { type: String, required: true }
});

const order = ref({ status: props.initialStatus });

const steps = [
    { status: 'pending', label: 'Ожидание' },
    { status: 'confirmed', label: 'Подтверждён' },
    { status: 'processing', label: 'Готовится' },
    { status: 'shipped', label: 'Доставка' },
    { status: 'delivered', label: 'Доставлен' }
];

const statusTexts = {
    pending: 'Ожидает подтверждения',
    confirmed: 'Заказ подтверждён',
    processing: 'Готовим ваш заказ',
    shipped: 'Заказ в пути',
    delivered: 'Доставлен'
};

const statusText = computed(() => statusTexts[order.value.status] || order.value.status);

const statusOrder = ['pending', 'confirmed', 'processing', 'shipped', 'delivered'];
const isStepActive = (status) => status === order.value.status;
const isStepDone = (status) => statusOrder.indexOf(status) < statusOrder.indexOf(order.value.status);

let pushler = null;
let channel = null;

onMounted(() => {
    pushler = new PushlerClient({
        appKey: props.appKey,
        authEndpoint: '/auth.php'
    });

    pushler.on('connected', () => {
        channel = pushler.subscribe(`private-user-${props.userId}`);
        
        channel.on('order.status.updated', (data) => {
            if (data.order_id === props.orderId) {
                order.value.status = data.status;
                showToast(`Статус заказа: ${data.status_text}`);
            }
        });
    });
});

onUnmounted(() => {
    channel?.unsubscribe();
    pushler?.disconnect();
});
</script>

🔄 Асинхронная отправка

Для высоконагруженных проектов рекомендуем использовать очереди:

PHP
<?php
// Добавляем задачу в очередь (Redis/RabbitMQ/DB)
function queuePushlerEvent(string $channel, string $event, array $data): void
{
    $job = [
        'channel' => $channel,
        'event' => $event,
        'data' => $data,
        'created_at' => time()
    ];
    
    // Пример с Redis
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->rPush('pushler_queue', json_encode($job));
}

// Worker для обработки очереди
// worker.php — запускается отдельным процессом
require_once 'pushler.php';

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

while (true) {
    $jobJson = $redis->blPop('pushler_queue', 5);
    
    if ($jobJson) {
        $job = json_decode($jobJson[1], true);
        
        try {
            $pushler->trigger($job['channel'], $job['event'], $job['data']);
            echo "Отправлено: {$job['event']} в {$job['channel']}\n";
        } catch (Exception $e) {
            echo "Ошибка: {$e->getMessage()}\n";
            // Можно добавить повторную попытку
        }
    }
}

📊 Примеры событий

Уведомление пользователю

PHP
<?php
// Функция отправки уведомления
function sendNotification(int $userId, string $type, string $title, string $message): void
{
    global $pushler;
    
    $pushler->trigger(
        "private-user-{$userId}",
        'notification.received',
        [
            'id' => uniqid('notif_'),
            'type' => $type, // 'info', 'success', 'warning', 'error'
            'title' => $title,
            'message' => $message,
            'created_at' => date('c')
        ]
    );
}

// Использование
sendNotification(123, 'success', 'Заказ оплачен! 🎉', 'Ваш заказ #456 успешно оплачен.');
sendNotification(123, 'info', 'Новое сообщение', 'Вам написал менеджер.');

Новое сообщение в чате

PHP
<?php
// При отправке сообщения в чат
function broadcastChatMessage(int $chatId, array $message, ?string $excludeSocketId = null): void
{
    global $pushler;
    
    $pushler->trigger(
        "presence-chat-{$chatId}",
        'message.sent',
        [
            'message' => [
                'id' => $message['id'],
                'content' => $message['content'],
                'user' => [
                    'id' => $message['user_id'],
                    'name' => $message['user_name'],
                    'avatar' => $message['user_avatar']
                ],
                'created_at' => $message['created_at']
            ]
        ],
        $excludeSocketId // Исключаем отправителя
    );
}

⚠️ Типичные ошибки

1. Событие не отправляется

PHP
// ❌ Неправильно — неверные ключи
$pushler = new PushlerClient('wrong_key', 'wrong_secret');

// ✅ Правильно — проверьте ключи в личном кабинете
$pushler = new PushlerClient(
    'key_xxxxxxxxxxxxxxxx',   // Ваш App Key
    'secret_xxxxxxxxxxxxxxxx' // Ваш App Secret
);

2. Ошибка авторизации канала

PHP
// ❌ Неправильно — auth.php возвращает HTML вместо JSON
echo "<html>Error</html>";

// ✅ Правильно — всегда JSON
header('Content-Type: application/json');
http_response_code(403);
echo json_encode(['error' => 'Forbidden']);

3. Не указан authEndpoint на клиенте

JavaScript
// ❌ Неправильно — нет authEndpoint для приватных каналов
const pushler = new PushlerClient({ appKey: 'key_xxx' });
pushler.subscribe('private-user-123'); // Ошибка!

// ✅ Правильно
const pushler = new PushlerClient({
    appKey: 'key_xxx',
    authEndpoint: '/auth.php' // Путь к вашему скрипту авторизации
});

4. CORS ошибки

PHP
// auth.php — добавьте CORS заголовки если фронт на другом домене
header('Access-Control-Allow-Origin: https://your-frontend.com');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
header('Access-Control-Allow-Credentials: true');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

Готовы попробовать?

Создайте бесплатный аккаунт и начните интеграцию за пару минут