From ce25084cde60f59b427d82ea8e786bb57ee34dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1ndor?= <1+sandros@noreply.localhost> Date: Wed, 13 May 2026 12:43:28 +0200 Subject: [PATCH] Add ng/ninjamail.class.php --- ng/ninjamail.class.php | 612 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 612 insertions(+) create mode 100644 ng/ninjamail.class.php diff --git a/ng/ninjamail.class.php b/ng/ninjamail.class.php new file mode 100644 index 0000000..db91dd9 --- /dev/null +++ b/ng/ninjamail.class.php @@ -0,0 +1,612 @@ +host = rtrim($host, '/'); + if ($key !== false && $key !== '') { + $this->key = (string)$key; + } + } + + /** + * Ellenőrzi, hogy az API gazdagép és kulcs be van-e állítva. + */ + public function check(): bool + { + return !empty($this->host) && !empty($this->key); + } + + /** + * POST kérést küld az API adott végpontjára. + * + * @param string $f A gyár/végpont neve (pl. 'subscribe') + * @param array $data POST mezők tömbje + * @return object A dekódolt JSON válasz objektumként + * @throws RuntimeException Ha hiányoznak a hitelesítési adatok, cURL hiba + * esetén, vagy ha a válasz nem érvényes JSON + */ + public function process(string $f, array $data): object + { + if (!$this->check()) { + throw new RuntimeException('ninjaMail: hiányzó gazdagép vagy API kulcs.'); + } + + $url = $this->host . '/a/' . rawurlencode($f) . '/?key=' . urlencode($this->key); + + $ch = curl_init($url); + if ($ch === false) { + throw new RuntimeException('ninjaMail: nem sikerült inicializálni a cURL munkamenetet.'); + } + + curl_setopt_array($ch, [ + CURLOPT_ENCODING => 'UTF-8', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $data, + CURLOPT_TIMEOUT => $this->timeout, + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => 2, + CURLOPT_FOLLOWLOCATION => false, + CURLOPT_MAXREDIRS => 0, + CURLOPT_HTTPHEADER => ['Accept: application/json'], + ]); + + $response = curl_exec($ch); + $errno = curl_errno($ch); + $error = curl_error($ch); + curl_close($ch); + + if ($response === false) { + throw new RuntimeException( + sprintf('ninjaMail: cURL hiba (%d): %s', $errno, $error) + ); + } + + $decoded = json_decode((string)$response); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new RuntimeException( + 'ninjaMail: érvénytelen JSON válasz: ' . json_last_error_msg() + ); + } + + $result = (object)$decoded; + $this->data = $result; + return $result; + } + + /** + * Véletlenszerű kulccsal indít távoli belépési munkamenetet. + * + * @return object API válasz (tartalmaz 'token' mezőt siker esetén) + * @throws RuntimeException Lásd: process() + */ + public function login(): object + { + return $this->process('login', [ + 'rkey' => bin2hex(random_bytes(16)), + ]); + } +} + + +// --------------------------------------------------------------------------- +// Levélküldés +// --------------------------------------------------------------------------- + +/** + * Egyszeri e-mail küldése megadott címzettnek. + */ +class ninjaMailSend extends ninjaMail +{ + private string $to = ''; + private string $subject = ''; + private string $message = ''; + private string $message_text = ''; + + /** + * @param string $to Feliratkozó azonosítója vagy e-mail cím + */ + public function to(string $to): true + { + $this->to = trim($to); + return true; + } + + /** + * @param string $s Az e-mail tárgya + */ + public function subject(string $s): true + { + $this->subject = $s; + return true; + } + + /** + * @param string $m HTML tartalom + * @param string|bool $t Opcionális egyszerű szöveges változat; + * ha nincs megadva, a HTML-ből kerül levezetésre + */ + public function message(string $m, string|bool $t = false): true + { + $this->message = $m; + $this->message_text = ($t !== false && $t !== '') + ? (string)$t + : trim(strip_tags($m)); + return true; + } + + /** + * Elküldi az e-mailt. + * + * @return bool true ha a levél sikeresen sorba állt + * @throws InvalidArgumentException Ha kötelező mező hiányzik + * @throws RuntimeException Lásd: process() + */ + public function send(): bool + { + if (empty($this->to) || empty($this->subject) || empty($this->message)) { + throw new InvalidArgumentException( + 'ninjaMailSend: a to, subject és message mezők kötelezők.' + ); + } + + $post = [ + 'to' => $this->to, + 'subject' => $this->subject, + 'message' => $this->message, + 'message_text' => $this->message_text, + ]; + + return $this->process('send', $post)->status === 'message_queued'; + } +} + + +// --------------------------------------------------------------------------- +// Feliratkozások +// --------------------------------------------------------------------------- + +/** + * Feliratkozók hozzáadása és eltávolítása levelezőlistákból. + */ +class ninjaMailSubscription extends ninjaMail +{ + private int $list = 0; + private int $activated = 0; + private int $forcenamechange = 0; + + /** + * @param int $id Lista azonosítója + * @return bool false ha az azonosító nem pozitív egész szám + */ + public function list(int $id): bool + { + if ($id <= 0) { + return false; + } + $this->list = $id; + return true; + } + + /** + * @param bool $s true = azonnal megerősített; false = megerősítő e-mail küldése + */ + public function activated(bool $s): true + { + $this->activated = $s ? 1 : 0; + return true; + } + + /** + * @param bool $s true = névfrissítés engedélyezése meglévő feliratkozóknál + */ + public function namechange(bool $s): true + { + $this->forcenamechange = $s ? 1 : 0; + return true; + } + + /** + * Feliratkozó hozzáadása a listához. + * + * @param string $email A feliratkozó e-mail címe + * @param string $name A feliratkozó neve (opcionális) + * @return bool true sikeres feliratkozás esetén + * @throws InvalidArgumentException Ha a lista nincs beállítva + * @throws RuntimeException Lásd: process() + */ + public function subscribe(string $email, string $name = ''): bool + { + if ($this->list <= 0) { + throw new InvalidArgumentException( + 'ninjaMailSubscription: lista azonosítója nincs beállítva.' + ); + } + + $post = [ + 'list' => $this->list, + 'name' => $name, + 'email' => $email, + 'activated' => $this->activated, + 'forcenamechange' => $this->forcenamechange, + ]; + + return $this->process('subscribe', $post)->status === 'success'; + } + + /** + * Feliratkozó eltávolítása a listából. + * + * @param string $email A leiratkozó e-mail címe + * @return bool true sikeres leiratkozás esetén + * @throws InvalidArgumentException Ha a lista nincs beállítva + * @throws RuntimeException Lásd: process() + */ + public function unsubscribe(string $email): bool + { + if ($this->list <= 0) { + throw new InvalidArgumentException( + 'ninjaMailSubscription: lista azonosítója nincs beállítva.' + ); + } + + $post = [ + 'list' => $this->list, + 'email' => $email, + ]; + + return $this->process('unsubscribe', $post)->status === 'success'; + } +} + + +// --------------------------------------------------------------------------- +// Hírlevél +// --------------------------------------------------------------------------- + +/** + * Hírlevelek létrehozása, frissítése és küldése. + */ +class ninjaMailNewsletter extends ninjaMail +{ + private int $newsletter = 0; + private string $subject = ''; + private string $message = ''; + private string $message_text = ''; + + /** + * Lekérdezi vagy beállítja az aktuális hírlevél azonosítóját. + * + * @param int|false $id Hírlevél azonosítója a beállításhoz; false = lekérdezés + * @return int|bool Lekérdezési módban az aktuális azonosítót adja vissza; + * beállítási módban true/false + */ + public function newsletter(int|false $id = false): int|bool + { + if ($id !== false) { + if ($id > 0) { + $this->newsletter = $id; + return true; + } + return false; + } + return $this->newsletter; + } + + /** + * @param string $s A hírlevél tárgya + */ + public function subject(string $s): true + { + $this->subject = $s; + return true; + } + + /** + * @param string $m HTML tartalom + * @param string|bool $t Opcionális egyszerű szöveges változat + */ + public function message(string $m, string|bool $t = false): true + { + $this->message = $m; + $this->message_text = ($t !== false && $t !== '') + ? (string)$t + : trim(strip_tags($m)); + return true; + } + + /** + * @param bool $update true = meglévő frissítése; false = új létrehozása + * @return int|false Az új/frissített hírlevél azonosítója, vagy false hiba esetén + * @throws InvalidArgumentException Ha nincs üzenet beállítva + * @throws RuntimeException Lásd: process() + */ + private function query(bool $update = false): int|false + { + if (empty($this->message)) { + throw new InvalidArgumentException( + 'ninjaMailNewsletter: az üzenet tartalma kötelező.' + ); + } + + $post = [ + 'new' => true, + 'id' => $update ? $this->newsletter : false, + 'subject' => $this->subject, + 'message' => $this->message, + 'message_text' => $this->message_text, + ]; + + $data = $this->process('newsletter', $post); + if ($data->status === 'success' && isset($data->id) && is_numeric($data->id)) { + $this->newsletter = (int)$data->id; + return $this->newsletter; + } + + return false; + } + + /** + * Új hírlevelet hoz létre. + * + * @return int|false Az új hírlevél azonosítója, vagy false hiba esetén + */ + public function create(): int|false + { + return $this->query(false); + } + + /** + * Meglévő hírlevelet frissít. + * + * @return int|false A hírlevél azonosítója, vagy false hiba esetén + * @throws InvalidArgumentException Ha nincs hírlevél kiválasztva + */ + public function update(): int|false + { + if ($this->newsletter <= 0) { + throw new InvalidArgumentException( + 'ninjaMailNewsletter: hírlevél azonosítója nincs beállítva a frissítéshez.' + ); + } + return $this->query(true); + } + + /** + * Hírlevelet küld azonnali vagy ütemezett időpontban. + * + * @param int|false $time Unix időbélyeg a küldés időpontjához; false vagy 0 = azonnali + * @return bool true sikeres sorbaállítás esetén + * @throws InvalidArgumentException Ha nincs hírlevél kiválasztva + * @throws RuntimeException Lásd: process() + */ + public function send(int|false $time = false): bool + { + if ($this->newsletter <= 0) { + throw new InvalidArgumentException( + 'ninjaMailNewsletter: hírlevél azonosítója nincs beállítva a küldéshez.' + ); + } + + $post = [ + 'send' => true, + 'id' => $this->newsletter, + 'start' => ($time && $time > 0) ? $time : 0, + ]; + + $data = $this->process('newsletter', $post); + return in_array($data->status ?? '', ['success', 'already_queued'], true); + } + + /** + * Listázza az elérhető híreveleket. + * + * @return object API válasz tömbbel + * @throws RuntimeException Lásd: process() + */ + public function get(): object + { + return $this->process('newsletter', ['get' => true]); + } +} + + +// --------------------------------------------------------------------------- +// Kampány +// --------------------------------------------------------------------------- + +/** + * Kampányok létrehozása, törlése és konfigurálása. + */ +class ninjaMailCampaign extends ninjaMail +{ + private int $campaign = 0; + + /** + * Lekérdezi vagy beállítja az aktuális kampány azonosítóját. + * + * @param int|false $id Kampány azonosítója beállításhoz; false = lekérdezés + * @return int|bool Lekérdezési módban az aktuális azonosítót adja vissza; + * beállítási módban true/false + */ + public function campaign(int|false $id = false): int|bool + { + if ($id === false) { + return $this->campaign; + } + if ($id > 0) { + $this->campaign = $id; + return true; + } + return false; + } + + /** + * Új kampányt hoz létre. + * + * @param string $name A kampány neve + * @return int|false Az új kampány azonosítója, vagy false hiba esetén + * @throws InvalidArgumentException Ha a név üres + * @throws RuntimeException Lásd: process() + */ + public function create(string $name): int|false + { + if (trim($name) === '') { + throw new InvalidArgumentException( + 'ninjaMailCampaign: a kampány neve nem lehet üres.' + ); + } + + $post = [ + 'new' => true, + 'name' => $name, + ]; + + $data = $this->process('campaign', $post); + if ($data->status === 'success' && isset($data->id) && is_numeric($data->id)) { + $this->campaign = (int)$data->id; + return $this->campaign; + } + + return false; + } + + /** + * Törli az aktuális kampányt. + * + * @return bool true sikeres törlés esetén + * @throws InvalidArgumentException Ha nincs kampány kiválasztva + * @throws RuntimeException Lásd: process() + */ + public function remove(): bool + { + if ($this->campaign <= 0) { + throw new InvalidArgumentException( + 'ninjaMailCampaign: kampány azonosítója nincs beállítva a törléshez.' + ); + } + + $post = [ + 'remove' => true, + 'id' => $this->campaign, + ]; + + return $this->process('campaign', $post)->status === 'success'; + } + + /** + * Listákat rendel a kampányhoz. + * + * @param int[] $lists Lista azonosítók tömbje + * @return bool true sikeres frissítés esetén + * @throws InvalidArgumentException Ha a $lists üres vagy nincs kampány beállítva + * @throws RuntimeException Lásd: process() + */ + public function update(array $lists): bool + { + if (empty($lists)) { + throw new InvalidArgumentException( + 'ninjaMailCampaign: legalább egy lista azonosítója szükséges.' + ); + } + if ($this->campaign <= 0) { + throw new InvalidArgumentException( + 'ninjaMailCampaign: kampány azonosítója nincs beállítva a frissítéshez.' + ); + } + + $post = [ + 'update' => true, + 'id' => $this->campaign, + 'lists' => $lists, + ]; + + return $this->process('campaign', $post)->status === 'success'; + } + + /** + * Hírlevelet csatol a kampányhoz. + * + * @param int $newsletter A csatolni kívánt hírlevél azonosítója + * @return bool true sikeres csatolás esetén + * @throws InvalidArgumentException Ha az azonosító érvénytelen vagy nincs kampány beállítva + * @throws RuntimeException Lásd: process() + */ + public function attach(int $newsletter): bool + { + if ($newsletter <= 0) { + throw new InvalidArgumentException( + 'ninjaMailCampaign: érvénytelen hírlevél azonosító.' + ); + } + if ($this->campaign <= 0) { + throw new InvalidArgumentException( + 'ninjaMailCampaign: kampány azonosítója nincs beállítva a csatoláshoz.' + ); + } + + $post = [ + 'relations' => true, + 'id' => $this->campaign, + 'newsletter' => $newsletter, + ]; + + return $this->process('campaign', $post)->status === 'success'; + } +} + + +// --------------------------------------------------------------------------- +// Statisztika +// --------------------------------------------------------------------------- + +/** + * Hírlevél-statisztikák lekérdezése. + */ +class ninjaMailStatistics extends ninjaMail +{ + /** + * Statisztikát kér le egy adott hírlevélről. + * + * @param int $id A hírlevél azonosítója + * @return object Az API statisztikai válasza + * @throws InvalidArgumentException Ha az azonosító érvénytelen + * @throws RuntimeException Lásd: process() + */ + public function get(int $id): object + { + if ($id <= 0) { + throw new InvalidArgumentException( + 'ninjaMailStatistics: érvénytelen hírlevél azonosító.' + ); + } + + $post = [ + 'newsletter' => $id, + 'type' => 1, + ]; + + return $this->process('statistics', $post); + } +}