Klient PHP
Dla ułatwienia integracji z Connect API udostępniliśmy klasę klienta. Klasa ta posiada odpowiedniki wszystkich metod ConnectAPI, a dodatkowo implementuje funcje logowania i przechowywania tokena autoryzacyjnego.
Klasa ConnectClient do używa:
- PHP w wersji 5.6 lub wyższej;
- biblioteki CURL;
- modułu shmop.
Moduł shmop jest używany do przechowywania tokena autoryzacyjnego w pamięci współdzielonej serwera. Jeśli środowisko nie udostępnia tego modułu, klasa klienta może przechowywać token w pliku na serwerze, wskazanym w parametrze $tokenPath konstruktora klasy ConnectClient. Ze względów wydajnościowych zaleca się użycie shmop, jeśli jest dostępny (nie podany parametr $tokenPath).
⋮ Pokaż kod źródłowy ↧ Pobierz klienta<?php
namespace ConnectAPI;
/**
* Klient interfejsu Connect API systemu Klub Klienta
*/
class ConnectClient {
private const CONNECT_URL = 'https://connect.klubklienta.pl';
private const SHM_SIZE = 512;
private $_uid;
private $_key;
private $_token;
private $_tokenTimeout;
private $_tokenPath;
private $_error;
/**
* Konstruktor klasy
*
* @var string $uid - identyfikator użytkownika Connect API
* @var string $key - klucz logowania użytkownika Connect API
* @var string $tokenPath - ścieżka do katalogu, w którym będą zapisywane tokeny dostępowe do Connect API.
* Jeśli ścieżka nie zostanie podana, do przechowywania tokenów będzie używany mechanizm shared memory (opcja zalecana, serwer musi obsługiwać shmop)
*/
public function __construct($uid, $key, $tokenPath = null) {
$this->_uid = $uid;
$this->_key = $key;
$this->_tokenPath = $tokenPath;
$this->_token = null;
}
/**
* Zwraca komunikat ostatniego błędu
* @return string komunikat błędu
*/
public function error() {
return $this->_error;
}
protected function call($url) {
$curl = curl_init(self::CONNECT_URL . $url);
if ($curl) {
$options = [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [],
];
if ($url != '/auth/login') {
$options[CURLOPT_HTTPHEADER][] = "Authorization: Bearer {$this->_token}";
}
curl_setopt_array($curl, $options);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
if ($status >= 200 && $status <= 299) {
$data = json_decode($response, true);
if ($response && !$data) $data = $response;
$this->_error = null;
}
else {
$data = $response;
$this->_error = $response;
}
curl_close($curl);
return $data;
}
}
private function shmKey() {
return hexdec(hash('crc32', "#ConnectAPI:{$this->_uid}"));
}
private function readTokenData() {
$this->_error = null;
$shmKey = $this->shmKey();
if ($this->_tokenPath) { // storing token in file
$fname = "{$this->_tokenPath}/{$shmKey}";
if (file_exists($fname)) {
return json_decode(file_get_contents($fname), true);
}
}
elseif (function_exists('shmop_open')) { // storing token in shared memory
$shmop = @shmop_open($shmKey, 'c', 0644, self::SHM_SIZE);
if ($shmop) {
$size = shmop_read($shmop, 0, 4);
$json = shmop_read($shmop, 4, (int)$size);
$tokenData = json_decode($json, true);
if (phpversion() < '8') shmop_close($shmop);
return $tokenData;
}
else return null;
}
else {
$this->_error = 'No shmop module nor token path available';
return null;
}
return null;
}
private function writeTokenData($tokenData) {
$this->_error = null;
$shmKey = $this->shmKey();
if ($this->_tokenPath) { // storing token in file
$fname = "{$this->_tokenPath}/{$shmKey}";
if (!file_exists($this->_tokenPath)) {
mkdir($this->_tokenPath, 0777, true);
}
file_put_contents($fname, json_encode($tokenData));
return true;
}
elseif (function_exists('shmop_open')) {
$shmop = shmop_open($shmKey, 'c', 0644, self::SHM_SIZE);
$json = json_encode($tokenData);
shmop_write($shmop, sprintf('%04d', strlen($json)), 0);
shmop_write($shmop, "{$json}", 4);
if (phpversion() < '8') shmop_close($shmop);
return true;
}
else {
$this->_error = 'No shmop module nor token path available';
return false;
}
}
/**
* Logowanie do Connect API
* Logowanie następuje z użyciem UID i KEY przekazanych w konstruktorze klasy
*
* @return bool rezultat logowania, w przypadku niepowodzenia błąd można pobrać metodą error()
*/
public function authorize() {
if ($this->_token && time() < $this->_tokenTimeout) { // token is valid
return true;
}
$tokenData = $this->readTokenData();
if ($this->_error) return false;
if ($tokenData) { // token taken from file or shared memory
if (time() < $tokenData['timeout']) {
$this->_token = $tokenData['token'];
$this->_tokenTimeout = $tokenData['timeout'];
return true;
}
}
// call Connect login
$tokenData = $this->call("/auth/login/{$this->_uid}/{$this->_key}");
if ($this->_error) return false;
if ($tokenData) {
$this->_token = $tokenData['token'];
$this->_tokenTimeout = time() + $tokenData['time'] - 300;
$this->writeTokenData([
'token' => $this->_token,
'timeout' => $this->_tokenTimeout,
]);
return !$this->_error;
}
else {
if (!$this->_error) $this->_error = 'Login failed';
return false;
}
}
/**
* Pobranie listy programów lojalnościowych
*
* @return Program[] tablica obiektów klasy Program
*/
public function programs() {
if (!$this->authorize()) return null;
$data = $this->call('/seller/programs');
if ($data === null) return null;
$result = [];
foreach ($data as $progData) {
$result[] = new Program($progData);
}
return $result;
}
/**
* Pobranie informacji o programie lojalnościowym
*
* @param int $programId identyfikator programu
* @return Program definicja programu lojalnościowego
*/
public function program($programId) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/program/' . (int)$programId);
if ($data === null) return null;
return new Program($data);
}
/**
* Pobranie listy definicji punktów za zakupy
*
* @param int $programId identyfikator programu
* @return Point[] lista definicji punktów
*/
public function points($programId) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/points/' . (int)$programId);
if ($data === null) return null;
$result = [];
foreach ($data as $pointData) {
$result[] = new Point($pointData);
}
return $result;
}
/**
* Pobranie pojedynczej definicji punktów za zakupy
*
* @param int $programId identyfikator programu
* @param string $tag kod definicji punktów
* @return Point definicja punktów
*/
public function point($programId, $tag) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/point/' . (int)$programId . "/{$tag}");
if ($data === null) return null;
return new Point($data);
}
/**
* Pobranie listy nagród
*
* @param int $programId identyfikator programu
* @return Prize[] lista nagród
*/
public function prizes($programId) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/prizes/' . (int)$programId);
if ($data === null) return null;
$result = [];
foreach ($data as $prizeData) {
$result[] = new Prize($prizeData);
}
return $result;
}
/**
* Pobranie nagrody
*
* @param int $programId identyfikator programu
* @param int $tag kod nagrody
* @return Prize nagroda
*/
public function prize($programId, $tag) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/prize/' . (int)$programId . "/{$tag}");
if ($data === null) return null;
return new Prize($data);
}
/**
* Wygenerowanie kodu zaproszenia do programu
*
* @param int $programId identyfikator programu
* @return Code wygenerowany kod
*/
public function invite($programId) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/invite/' . (int)$programId);
if ($this->_error) return null;
return new Code($data);
}
/**
* Wygenerowanie kodu punktów za zakupy o okresie ważności 5 minut
*
* @param int $programId identyfikator programu
* @param string $tag kod definicji punktów
* @param int $number podstawa wyliczenia punktów za zakupy: liczba zakupionych produktów (dla type = Point::TypeNumber) lub kwota zakupu (dla type = Point::TypeAmount)
* @return Code wygenerowany kod
*/
public function givePoints($programId, $tag, $number) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/givePoints/' . (int)$programId . "/{$tag}/" . (int)$number);
if ($this->_error) return null;
return new Code($data);
}
/**
* Wygenerowanie kodu przekazania nagrody o okresie ważności 5 minut
*
* @param int $programId identyfikator programu
* @param string $tag kod nagrody
* @return Code wygenerowany kod
*/
public function givePrize($programId, $tag) {
if (!$this->authorize()) return null;
$data = $this->call('/seller/givePrize/' . (int)$programId . "/{$tag}");
if ($this->_error) return null;
return new Code($data);
}
/**
* Wydłużenie okresu ważności kodu
*
* @param string $code kod, który ma zostać przedłużony
* @return Code wygenerowany kod
*/
public function extendCode($code) {
if (!$this->authorize()) return null;
$data = $this->call("/seller/extendCode/{$code}");
if ($this->_error) return null;
return new Code($data);
}
/**
* Wysłanie e-mailem kodu wraz instrukcjami jego użycia
*
* @param string $code kod, który ma zostać wysłany
* @param string $recipient adres, na który ma zostać wysłany e-mail
* @return Result potwierdzenie wykonania operacji
*/
public function sendCode($code, $recipient) {
if (!$this->authorize()) return null;
$data = $this->call("/seller/sendCode/{$code}/{$recipient}");
if ($data === null) return null;
return new Result($data);
}
/**
* Pobranie informacji o kodzie realizacji nagrody
*
* @param string $code kod realizacji nagrody wygenerowany w aplikacji klienta
* @return CheckResult informacje o kodzie
*/
public function checkCode($code) {
if (!$this->authorize()) return null;
$data = $this->call("/seller/checkCode/{$code}");
if ($data === null) return null;
return new CheckResult($data);
}
/**
* Potwierdzenie kodu realizacji nagrody
*
* @param string $code kod realizacji nagrody wygenerowany w aplikacji klienta
* @return Result potwierdzenie wykonania operacji
*/
public function confirmCode($code) {
if (!$this->authorize()) return null;
$data = $this->call("/seller/confirmCode/{$code}");
if ($data === null) return null;
return new Result($data);
}
}
abstract class Initializable {
protected function init($data) {
if ($data && is_array($data)) {
$vars = get_class_vars(get_class($this));
foreach ($vars as $var => $foo) {
if (key_exists($var, $data)) {
$this->{$var} = $data[$var];
}
}
}
}
}
/**
* Definicja programu lojalnościowego
*/
class Program extends Initializable {
/** @var int identyfikator programu lojalnościowego */
public $id;
/** @var string nazwa programu */
public $name;
/** @var string nazwa organizatora (string) */
public $companyName;
/** @var string opis programu lub slogan reklamowy */
public $descr;
/** @var string opis nagrody powitalnej lub punktów powitalnych */
public $startPrize;
/** @var int liczba punktów za polecenie programu */
public $recommendPoints;
/** @var string data zakończenia programu w formacie YYYY-MM-DD */
public $collectPointsTo;
/** @var string data zakończenia odbioru nagród w formacie YYYY-MM-DD */
public $receivePrizesTo;
public function __construct($data = null) {
$this->init($data);
}
}
/**
* Definicja punktów za zakupy
*/
class Point extends Initializable {
/** @var int punkty przypisane do zakupu */
const TypeNumber = 1;
/** @var int punkty za wielokrotność kwoty zakupu */
const TypeAmount = 2;
/** @var string kod definicji punktów */
public $tag;
/** @var string nazwa definicji punktów */
public $name;
/** @var string typ definicji:
* Point::TypeNumber (1) - przypisane do zakupu;
* Point::TypeAmount (2) - zależne od kwoty zakupów
*/
public $type;
/** @var int liczba punktów za zakupy */
public $points;
/** @var int w przypadku, gdy type = Point::TypeAmount (2), oznacza kwotę, której wielokrotność uprawnia do otrzymania punktów */
public $amount;
/** @var string jednostka zakupu, np. minutę, sztukę, seans, usługę */
public $subject;
/** @var string opis definicji punktów */
public $descr;
/** @var string opis definicji punktów przyjazny dla klienta; wygenerowany automatycznie na podstawie właściwości: name, type, points, amount i subject */
public $label;
public function __construct($data = null) {
$this->init($data);
}
}
/**
* Definicja nagrody
*/
class Prize extends Initializable {
/** @var int zniżka procentowa */
const TypePercentDiscount = 1;
/** @var int zniżka kwotowa */
const TypeAmountDiscount = 2;
/** @var int gratis */
const TypeFree = 3;
/** @var int prezent */
const TypeGift = 4;
/** @var string kod nagrody */
public $tag;
/** @var string name - nazwa nagrody */
public $name;
/** @var int typ nagrody:
* Prize::TypePercentDiscount (1) - zniżka procentowa,
* Prize::TypeAmountDiscount (2) - rabat kwotowy,
* Prize::TypeFree (3) - gratis,
* Prize::TypeGift (4) - prezent
*/
public $type;
/** @var int wartość punktowa nagrody */
public $points;
/** @var int liczba dostępnych sztuk nagrody (null - nielimitowana) */
public $availableCnt;
/** @var bool dostępna tylko dla sprzedawcy */
public $onlyForSeller;
/** @var string opis nagrody */
public $descr;
/** @var string opis nagrody przyjazny dla klienta; wygenerowany automatycznie na podstawie właściwości: name, type, points */
public $label;
public function __construct($data = null) {
$this->init($data);
}
}
/**
* Kod dla aplikacji mobilnej kienta
*/
class Code extends Initializable {
/** @var string kod w postaci cyfrowej */
public $code;
/** @var string adres kierujący użytkownika do użycia kodu */
public $url;
/** @var string kod QR jako obraz image/png w postaci data inline */
public $qr;
/** @var string tytuł kodu */
public $title;
/** @var string nazwa kodu */
public $descr;
/** @var string opis czasu aktywności kodu */
public $time;
/** @var int czas aktywności kodu w sekundach */
public $timeout;
public function __construct($data = null) {
$this->init($data);
}
}
/**
* Rezultat operacji
*/
class Result extends Initializable {
/** @var bool flaga powodzenia operacji */
public $success;
/** @var string tytuł rezultatu potwierdzenia lub nazwa błędu */
public $title;
/** @var string opis rezultatu potwierdzenia lub komunikat błędu */
public $message;
public function __construct($data = null) {
$this->init($data);
}
}
/**
* Rezultat sprawdzenia kodu odbioru nagrody
*/
class CheckResult extends Initializable {
/** @var string tytuł sprawdzonego kodu */
public $title;
/** @var string opis sprawdzonego kodu */
public $descr;
/** @var int liczba sekund pozostała do upłynięcia ważności kodu */
public $timeout;
/** @var int identyfikator programu, w ramach którego wygenerowano kod */
public $programId;
/** @var int kod nagrody */
public $tag;
public function __construct($data = null) {
$this->init($data);
}
}