Przykłady kodu

Gotowe wzorce, które możesz wkleić i dopasować do danych w swoim systemie.

Przykłady kodu (wzorce)

Poniżej masz gotowe wzorce zgodne z IVR API: bezpieczne parsowanie webhooka, odpowiedź Action/Session, prosty state machine pod DTMF oraz fallback. Kod jest „do adaptacji” — w produkcji dołóż monitoring, limity i zasady logowania danych wrażliwych.

Wzorzec 1: minimalny endpoint + poprawne parsowanie request (PHP 5.3)

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

// 1) Wczytaj payload — najpierw raw JSON, potem fallback do $_POST['request'].
$raw = file_get_contents('php://input');
$data = null;

if ($raw !== false && trim($raw) !== '') {
    $data = json_decode($raw, true);
}

if (!$data && isset($_POST['request'])) {
    // Niektóre integracje wysyłają request jako pole formularza.
    if (get_magic_quotes_gpc()) {
        $_POST['request'] = stripslashes($_POST['request']);
    }
    $data = json_decode($_POST['request'], true);
}

// 2) Ujednolić: czasem dostajesz { "request": {...} }, a czasem sam obiekt.
if (!is_array($data)) { exit; }
$request = isset($data['request']) && is_array($data['request']) ? $data['request'] : $data;

// 3) Pobierz podstawy do logów/diagnostyki.
$uniqueCallId = isset($request['UniqueCallId']) ? $request['UniqueCallId'] : '';
$eventName    = '';
if (isset($request['Event']) && is_array($request['Event'])) {
    $eventName = isset($request['Event']['EventName']) ? $request['Event']['EventName'] : '';
}

// TODO: logowanie po Twojej stronie (UniqueCallId + EventName + czas odpowiedzi)

// 4) Minimalna odpowiedź (np. na start testów).
$response = array(
    'Action'  => array('Type' => 'Play', 'Prompt' => '1'),
    'Session' => array('step' => 'welcome')
);

echo json_encode($response);
?>

Ten wzorzec eliminuje klasyczny problem: „na serwerze nic nie przychodzi”, gdy payload jest wysyłany jako raw JSON, a nie jako $_POST.

Wzorzec 2: weryfikacja Hash (sekret) + bezpieczne porównanie (PHP 5.3)

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

// Timing-safe compare dla PHP 5.3 (hash_equals jest od PHP 5.6).
function timingSafeEquals($a, $b) {
    $a = (string)$a;
    $b = (string)$b;
    if (strlen($a) !== strlen($b)) return false;
    $res = 0;
    for ($i = 0; $i < strlen($a); $i++) {
        $res |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $res === 0;
}

$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)) { exit; }
$request = isset($data['request']) && is_array($data['request']) ? $data['request'] : $data;

// Oczekiwany sekret (Hash) przechowuj poza repo (config/ENV/secret manager).
$expectedHash = 'TU_WSTAW_SWOJ_HASH';

$incomingHash = isset($request['Hash']) ? $request['Hash'] : '';
if ($incomingHash === '' || !timingSafeEquals($incomingHash, $expectedHash)) {
    // Nie zdradzaj szczegółów w odpowiedzi. Loguj incydent u siebie.
    echo json_encode(array(
        'Action'  => array('Type' => 'Hangup'),
        'Session' => array('reason' => 'unauthorized')
    ));
    exit;
}

// ... dalej normalna logika (Action/Session)
echo json_encode(array(
    'Action'  => array('Type' => 'Play', 'Prompt' => '1'),
    'Session' => array('step' => 'authorized')
));
?>

Hash traktuj jak sekret: nie loguj go wprost, rotuj w razie podejrzenia wycieku i trzymaj poza kodem aplikacji.

Wzorzec 3: state machine (ID + PIN) + fallback do kolejki (PHP 5.3)

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

// --- Parsowanie requestu (jak w wzorcu 1) ---
$raw = file_get_contents('php://input');
$data = null;

if ($raw !== false && trim($raw) !== '') {
    $data = json_decode($raw, true);
}
if (!$data && isset($_POST['request'])) {
    if (get_magic_quotes_gpc()) { $_POST['request'] = stripslashes($_POST['request']); }
    $data = json_decode($_POST['request'], true);
}
if (!is_array($data)) { exit; }
$request = isset($data['request']) && is_array($data['request']) ? $data['request'] : $data;

// --- Kontekst zdarzenia ---
$event = isset($request['Event']) && is_array($request['Event']) ? $request['Event'] : array();
$eventName = isset($event['EventName']) ? $event['EventName'] : '';
$eventData = isset($event['EventData']) ? $event['EventData'] : '';

// --- Session (stan rozmowy) ---
$session = isset($request['Session']) && is_array($request['Session']) ? $request['Session'] : array();
if (!isset($session['state'])) $session['state'] = 'ASK_ID';
if (!isset($session['tries'])) $session['tries'] = 0;

$response = array();

// Helper: przejście do fallbacku
function setFallback(&$response, &$session) {
    // Destination poniżej to przykład — wstaw login obiektu/kolejki z Twojej konfiguracji.
    $response['Action'] = array(
        'Type' => 'CallByObjectLogin',
        'Destination' => 'kolejka_ogolna',
        'Options' => 'Timeout=30'
    );
    $session['state'] = 'END';
}

if ($session['state'] === 'ASK_ID') {
    // Pytamy o ID (np. zamówienia / zgłoszenia)
    $response['Action'] = array('Type' => 'GetDTMF', 'Prompt' => '1', 'Timeout' => '1200', 'MaxDigits' => '10');
    $session['state'] = 'WAIT_ID';
}
else if ($session['state'] === 'WAIT_ID') {
    if ($eventName === 'GetDTMF' && $eventData !== '' && $eventData !== 'timeout') {
        $session['id'] = $eventData;
        $session['state'] = 'ASK_PIN';
    } else {
        $session['tries']++;
        if ($session['tries'] >= 3) {
            setFallback($response, $session);
        } else {
            $session['state'] = 'ASK_ID';
            $response['Action'] = array('Type' => 'Play', 'Prompt' => '3'); // np. "Spróbuj ponownie"
        }
    }

    if (!isset($response['Action'])) {
        $response['Action'] = array('Type' => 'Wait', 'WaitTime' => '0');
    }
}
else if ($session['state'] === 'ASK_PIN') {
    $response['Action'] = array('Type' => 'GetDTMF', 'Prompt' => '2', 'Timeout' => '1200', 'MaxDigits' => '10');
    $session['state'] = 'WAIT_PIN';
}
else if ($session['state'] === 'WAIT_PIN') {
    if ($eventName === 'GetDTMF' && $eventData !== '' && $eventData !== 'timeout') {
        $session['pin'] = $eventData;

        // TODO: weryfikacja w bazie / CRM / ERP (tu tylko przykład)
        $ok = (isset($session['id']) && $session['id'] === $session['pin']);

        if ($ok) {
            // Routing do obiektu po loginie (np. opiekun / dział) — przykładowa nazwa.
            $response['Action'] = array(
                'Type' => 'CallByObjectLogin',
                'Destination' => 'obiekt001',
                'Options' => 'PlayCallStatus,Timeout=30'
            );
            $session['state'] = 'END';
        } else {
            $session['tries']++;
            if ($session['tries'] >= 3) {
                setFallback($response, $session);
            } else {
                $session['state'] = 'ASK_ID';
                $response['Action'] = array('Type' => 'Play', 'Prompt' => '3'); // np. "Błędne dane"
            }
        }
    } else {
        $session['tries']++;
        if ($session['tries'] >= 3) {
            setFallback($response, $session);
        } else {
            $session['state'] = 'ASK_PIN';
            $response['Action'] = array('Type' => 'Wait', 'WaitTime' => '0');
        }
    }
}
else {
    $response['Action'] = array('Type' => 'Hangup');
}

$response['Session'] = $session;
echo json_encode($response);
?>

Produkcyjnie dołóż: weryfikację Hash, maskowanie numerów w logach, monitoring czasu odpowiedzi webhooka i jasny fallback (żadnych pętli bez końca).

Uruchom u siebie

Załóż konto i przejdź szybki start — najpierw “Connected → Play”, potem DTMF, dopiero na końcu routing po danych.

Załóż konto    Szybki start