diff --git a/.gitea/workflows/release-test.yaml b/.gitea/workflows/release-test.yaml new file mode 100644 index 0000000..9232b33 --- /dev/null +++ b/.gitea/workflows/release-test.yaml @@ -0,0 +1,40 @@ +name: Release PHP Validity Check + +on: + release: + types: [published, created] + push: + branches: [master, main] + tags: ['v*'] + pull_request: + branches: [master, main] + +jobs: + php-validity: + name: PHP Validity (PHP ${{ matrix.php-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-version: ['8.1', '8.2', '8.3', '8.4'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: curl, json + coverage: none + + - name: PHP Syntax Check (Lint) + run: | + php -l ninjamail.class.php + php -l test_all.php + php -l tests/test_validity.php + + - name: Run PHP Validity & Type Tests (Offline - No API Calls) + run: | + php tests/test_validity.php diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..24b2ee0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +A ninjaMail API klienskönyvtár változásainak jegyzéke. + +--- + +## [0.9a] - 2026-09-28 + +### Hozzáadva (Added) +- **Modern PHP 8.1+ támogatás:** Szigorú típusosság (`declare(strict_types=1);`), típusos osztálytulajdonságok, skalár és union típusok minden osztályban (`ninjaMail`, `ninjaMailSend`, `ninjaMailSubscription`, `ninjaMailNewsletter`, `ninjaMailCampaign`, `ninjaMailStatistics`). +- **Gitea Actions CI/CD automatizáció:** Új `.gitea/workflows/release-test.yaml` munkafolyamat, amely automatikusan ellenőrzi a PHP érvényességet és szintaxist (PHP 8.1, 8.2, 8.3, 8.4 verziókon) minden kiadáskor (`release`), címkénél (`tag`) és push eseménynél külső API hívások nélkül. +- **Offline érvényesség-ellenőrzés:** Új `tests/test_validity.php` tesztcsomag a metódusok, típusok és kivételkezelés tesztelésére hálózati forgalom nélkül. +- **Anonimizált tesztelő szkript:** Új `test_all.php` futtatható tesztfájl környezeti változókból (`NINJAMAIL_HOST`, `NINJAMAIL_KEY`) konfigurálható, anonimizált tesztadatokkal. +- **Kriptográfiailag biztonságos token generálás:** A `login()` metódusban `bin2hex(random_bytes(16))` használata a korábbi gyenge `md5(time())` helyett. + +### Módosítva (Changed) +- **Főkönyvtár átszervezése:** Az `ng` mappa tartalma átkerült a projekt gyökerébe, az új generációs kód vált a hivatalos kiadássá. +- **Terminológia szabványosítása:** A félrevezető „gyár” kifejezés cseréje a szabványos „végpont” (*endpoint*) megnevezésre a kódban és a teljes dokumentációban. +- **Dokumentáció egyesítése és felülvizsgálata:** A `README.md` összefésülése és frissítése, a hibás adatok tisztítása (pl. `fekiratkozó` elgépelés, kampányvégpont feladatának pontosítása, hiányzó listakezelési útmutató és hírlevél frissítési adatok pótlása). +- **cURL kéréskódolás:** A POST kérések form-urlencoded kódolást (`http_build_query`) használnak, biztosítva a tömbösített és összetett paraméterek (pl. kampány listák `update()`) hibátlan szerveroldali fogadását. +- **Kampány-hírlevél összerendelés:** A `ninjaMailCampaign::attach()` metódus mostantól mind a `campaign`, mind az `id` paramétert továbbítja, biztosítva a szerveroldali `relations` végpont kompatibilitását. +- **PHP 8.5 kompatibilitás:** A PHP 8.5-ben elavulttá vált `curl_close()` hívás eltávolítása, és üres API válaszok robusztus kezelése JSON szintaxishiba dobása nélkül. + +### Eltávolítva (Removed) +- Az elavult, nem típusos örökölt kódok (`example.simple.php` és az eredeti gyökér `ninjamail.class.php`) törlésre kerültek az új kiadásokból. +- Az `ng` alkönyvtár megszüntetésre került. diff --git a/README.md b/README.md index 5621a60..12402c1 100644 --- a/README.md +++ b/README.md @@ -1,207 +1,643 @@ -ninjaMail API -=============== - -Ebben a fájlban olvashat arról, hogyan használhatja a levelező -alkalmazásprogramozási interfészét. -A példákban szereplő lekérések PHP programozási szemszögből készültek, viszont -felhasználható más nyelven íródott projektekben is, amennyiben az rendelkezik -CURL könyvtárral vagy más, GET és POST hívást támogató eszközzel. - - -## Bevezetés -Az API használatához regisztráció után generálni kell egy kulcsot. Ez a -Beállítások -> API menüből érhető el. A generált kulcsot tartsa titokban! -Míg API kulccsal nem lehet bejelentkezni a webes felületen, az API felületen a -legtöbb funkció elérhető. A kulcs felhasználásával lehetőség nyílik többek -között feliratkozók hozzáadására, törlésére. - - -## API URL -Az URL kulcsgenerálás után ugyan azon a felületen lesz látható. -`Példa: http://example.org/a/?key= -Ahol: example.org - szolgáltató, - részegység, - API kulcs - - +# ninjaMail API + +A ninjaMail levelező alkalmazásprogramozási interfészének (API) hivatalos dokumentációja és PHP klienskönyvtára. + +A dokumentáció ismerteti a közvetlen HTTP (cURL, GET/POST) végpontok hívását, valamint a modern, szigorúan típusos PHP 8.1+ kliensosztályok használatát. + +--- + +## Tartalomjegyzék + +- [Követelmények](#követelmények) +- [Bevezetés és hitelesítés](#bevezetés-és-hitelesítés) +- [API alap URL](#api-alap-url) +- [Hibakezelés](#hibakezelés) +- [API végpontok](#api-végpontok) + - [Feliratkozó hozzáadása (subscribe)](#feliratkozó-hozzáadása) + - [Feliratkozó eltávolítása (unsubscribe)](#feliratkozó-eltávolítása) + - [Listák kezelése (list)](#listák-kezelése) + - [Hírlevél létrehozása (newsletter)](#hírlevél-létrehozása) + - [Hírlevél frissítése (newsletter)](#hírlevél-frissítése) + - [Hírlevél küldése (newsletter)](#hírlevél-küldése) + - [Hírlevelek listázása (newsletter)](#hírlevelek-listázása) + - [Kampány létrehozása (campaign)](#kampány-létrehozása) + - [Kampány törlése (campaign)](#kampány-törlése) + - [Kampány frissítése – listák csatolása (campaign)](#kampány-frissítése-listák-csatolása) + - [Kampány csatolása hírlevélhez (campaign)](#kampány-csatolása-hírlevélhez) + - [Egyedi e-mail küldése (send)](#egyedi-e-mail-küldése) + - [E-mail küldés állapotának ellenőrzése (send)](#e-mail-küldés-állapotának-ellenőrzése) + - [Statisztikák lekérdezése (statistics)](#statisztikák-lekérdezése) + - [Távoli belépés (login)](#távoli-belépés) +- [PHP kliens használati útmutató és példák](#php-kliens-használati-útmutató-és-példák) + - [Inicializálás és távoli belépés](#inicializálás-és-távoli-belépés) + - [Feliratkozás és leiratkozás](#feliratkozás-és-leiratkozás) + - [Egyedi levél küldése](#egyedi-levél-küldése) + - [Hírlevél létrehozása, frissítése és küldése](#hírlevél-létrehozása-frissítése-és-küldése) + - [Kampány kezelése](#kampány-kezelése) + - [Statisztika lekérdezése](#statisztika-lekérdezése) + +--- + +## Követelmények + +A PHP kliens használatához az alábbi környezet szükséges: +- **PHP 8.1** vagy újabb (`declare(strict_types=1);`, típusos osztálymezők és metódusok) +- `curl` PHP kiterjesztés +- `json` PHP kiterjesztés + +--- + +## Bevezetés és hitelesítés + +Az API használatához regisztráció után API kulcsot kell generálni a **Beállítások → API** menüpontban. +A generált kulcsot kezelje bizalmasan — a kulccsal a funkciók túlnyomó része elérhető programozottan, beleértve a feliratkozók kezelését, kampányok indítását és egyedi levelek küldését. + +Webes adminisztrációs belépésre az API kulcs önmagában nem alkalmas (erre a távoli `login` végpont által adott egyszer használatos token szolgál). + +--- + +## API alap URL + +A kulcsgenerálás után az API URL a felületen is megjelenik: + +``` +https://example.org/a//?key= +``` + +| Elem | Leírás | +|---|---| +| `example.org` | A szolgáltató domain címe / alap URL-je | +| `` | A meghívandó funkciót kezelő végpont neve (pl. `subscribe`, `send`, `newsletter`) | +| `` | Az API hitelesítési kulcs | + +> **Biztonsági megjegyzés:** Éles környezetben mindig biztonságos HTTPS kapcsolatot használjon! + +--- + +## Hibakezelés + +A modern PHP kliens kétféle kivételt dobhat: +- `InvalidArgumentException`: ha egy kötelező mező hiányzik vagy érvénytelen (pl. hiányzó lista ID feliratkozáskor, üres címzett/tárgy/üzenet küldéskor, üres kampánynév). +- `RuntimeException`: kommunikációs vagy hitelesítési hibák esetén (hiányzó gazdagép vagy API kulcs, cURL hálózati hiba, érvénytelen JSON válasz). + +A legutóbbi sikeres API kérés nyers, dekódolt JSON válasza elérhető az objektum publikus `$data` mezőjében (`$client->data`). + +Ajánlott try/catch mintázat: + +```php +try { + $mailer = new ninjaMailSend('https://example.org', 'API_KEY'); + $mailer->to('ugyfel@example.com'); + $mailer->subject('Értesítés'); + $mailer->message('

Üdvözöljük!

'); + $ok = $mailer->send(); +} catch (InvalidArgumentException $e) { + // Kliensoldali validációs hiba + error_log('Validációs hiba: ' . $e->getMessage()); +} catch (RuntimeException $e) { + // Hálózati vagy szerveroldali JSON hiba + error_log('API hiba: ' . $e->getMessage()); +} +``` + +--- + +## API végpontok + ### Feliratkozó hozzáadása -Feliratkozó hozzáadása esetén tudni kell a lista azonosítóját. Ez a webes -felületre történő belépés után a Listák menüpontban a kettőskereszt oszlopban -látható. A feliratkozást végző gyár: subscribe -A kérés a következőképpen alakul: -`POST: http://example.org/a/subscribe?key=` -`DATA: list=&name=&email=&activated=<1|0>` -Az activated paraméter 1-es állásban megerősítettként rögzíti a feliratkozót, -míg 0 állásban küld megerősítő hivatkozást a megadott címre. -(Opcionális) Feliratkozó nevének módosítása: `forcenamechange=<1|0>` - -#### Várható válaszok -Sikeres feliratkozás: `success`, Sikertelen feliratkozás: `sub_error`, -Nincs MX rekord: `no_mx_record` (ez lehet átmeneti hiba is), -Rossz lista azonosító: `bad_list`, Sikertelen regisztráció: `reg_error` +Új feliratkozót ad hozzá a megadott azonosítójú listához. A lista azonosítója a webes adminisztrációs felületen a **Listák** menüpontban, a kettőskereszt (`#`) oszlopban található. -### Feliratkozó eltávolítása listáról -Feliratkozó eltávolításához szükségünk van a lista azonosítójára és a feliratkozó -e-mail címére. -A leiratkozást végző gyár: unsubscribe -A kérés a következőképpen alakul: -`POST: http://example.org/a/unsubscribe?key=` -`DATA: list=&email=` +**Végpont:** `subscribe` + +``` +POST: https://example.org/a/subscribe/?key= +DATA: list=&name=&email=&activated=<1|0>&forcenamechange=<1|0> +``` + +Paraméterek: +- `list` (kötelező): A levelezőlista azonosítója (pozitív egész szám). +- `email` (kötelező): A feliratkozó e-mail címe. +- `name` (opcionális): A feliratkozó neve. +- `activated` (kötelező): + - `1`: a feliratkozó azonnal megerősítettként (aktívként) kerül mentésre. + - `0`: a rendszer megerősítő e-mailt küld a megadott címre. +- `forcenamechange` (opcionális): + - `1`: ha az e-mail cím már szerepel a listában, a feliratkozó neve felülírásra kerül. + - `0`: meglévő feliratkozó esetén a név változatlan marad. #### Várható válaszok -Sikeres leiratkozás: `success`, Sikertelen leiratkozás: `unsub_error`, -Ismeretlen E-mail cím: `unknown_email`, Hiányzó paraméterek: `missing_parameters` +| Státusz | Leírás | +|---|---| +| `success` | Sikeres feliratkozás | +| `sub_error` | Sikertelen feliratkozás | +| `no_mx_record` | Nincs érvényes MX rekord (lehet átmeneti DNS hiba is) | +| `bad_list` | Érvénytelen lista azonosító | +| `reg_error` | Sikertelen regisztráció | -### Lista létrehozás -Levelezőlista létrehozására alkalmas. -A listát kezelő gyár: list -A kérés a következőképpen alakul: -`POST: http://example.org/a/list?key=` -`DATA: new&name=` +--- + +### Feliratkozó eltávolítása + +Feliratkozó törlése az adott listáról. + +**Végpont:** `unsubscribe` + +``` +POST: https://example.org/a/unsubscribe/?key= +DATA: list=&email= +``` + +Paraméterek: +- `list` (kötelező): A levelezőlista azonosítója. +- `email` (kötelező): A leiratkozó e-mail címe. #### Várható válaszok -Sikeres kérés: `success`, Sikertelen kérés: `failed`, -Nem megfelelő név: `bad_name` +| Státusz | Leírás | +|---|---| +| `success` | Sikeres leiratkozás | +| `unsub_error` | Sikertelen leiratkozás | +| `unknown_email` | Ismeretlen e-mail cím a megadott listában | +| `missing_parameters` | Hiányzó kötelező paraméterek | -### Lista törlése -Levelezőlista törlésére alkalmas. -A listát kezelő gyár: list -A kérés a következőképpen alakul: -`POST: http://example.org/a/list?key=` -`DATA: remove&id=` +--- + +### Listák kezelése + +Levelezőlisták létrehozása, törlése és listázása a nyers API végponton keresztül. + +> **Megjegyzés:** A PHP klienskönyvtár a lista-műveletekhez nem tartalmaz külön burkolóosztályt; a hívások közvetlenül a `ninjaMail::process('list', $data)` metódussal kezdeményezhetők, míg a `ninjaMailSubscription::list(int $id)` metódus a fel- és leiratkozás cél-listájának kiválasztására szolgál. + +**Végpont:** `list` + +#### Lista létrehozása + +``` +POST: https://example.org/a/list/?key= +DATA: new&name= +``` + +| Státusz | Leírás | +|---|---| +| `success` | Sikeres létrehozás | +| `failed` | Sikertelen kérés | +| `bad_name` | Nem megfelelő vagy üres név | + +#### Lista törlése + +``` +POST: https://example.org/a/list/?key= +DATA: remove&id= +``` + +| Státusz | Leírás | +|---|---| +| `success` | Sikeres törlés | +| `failed` | Sikertelen törlés | + +#### Listák lekérdezése + +``` +POST: https://example.org/a/list/?key= +DATA: get +``` + +Válasz: Sikeres kérés esetén a listák tömbje/objektuma. + +--- + +### Hírlevél létrehozása + +Új hírlevél piszkozatot hoz létre a megadott tartalommal. + +**Végpont:** `newsletter` + +``` +POST: https://example.org/a/newsletter/?key= +DATA: new&subject=&message=&message_text= +``` + +Paraméterek: +- `new`: Műveletjelző. +- `subject`: A hírlevél tárgya. +- `message`: A levél HTML tartalma. +- `message_text` (opcionális): A levél egyszerű szöveges (Plain text) változata. Ha nincs megadva, automatikusan a HTML tartalomból származik a HTML tag-ek eltávolításával. #### Várható válaszok -Sikeres kérés: `success`, Sikertelen kérés: `failed` +| Státusz | Leírás | +|---|---| +| `success` + `id` | Sikeres létrehozás, visszaadja az új hírlevél azonosítóját | +| `failed` | Sikertelen kérés | +| `bad_subject` | Érvénytelen vagy üres tárgy | +| `message_too_powerful` | Túl hosszú levéltartalom | +| `message_too_short` | Túl rövid levéltartalom | -### Listák lekérdezése -Levelezőlisták lekérdezésére alkalmas. -A listát kezelő gyár: list -A kérés a következőképpen alakul: -`POST: http://example.org/a/list?key=` -`DATA: get` +--- + +### Hírlevél frissítése + +Meglévő hírlevél tartalmának és tárgyának módosítása. + +**Végpont:** `newsletter` + +``` +POST: https://example.org/a/newsletter/?key= +DATA: new&id=&subject=&message=&message_text= +``` + +Várható válaszok: megegyeznek a hírlevél létrehozásánál leírtakkal. + +--- + +### Hírlevél küldése + +Hírlevél azonnali vagy ütemezett kiküldése. + +**Végpont:** `newsletter` + +``` +POST: https://example.org/a/newsletter/?key= +DATA: send&id=&start= +``` + +Paraméterek: +- `send`: Műveletjelző. +- `id`: A kiküldendő hírlevél azonosítója. +- `start`: Unix időbélyeg az ütemezéshez, vagy `0` / üres érték azonnali kiküldéshez. #### Várható válaszok -Sikeres kérés: -tömb- +| Státusz | Leírás | +|---|---| +| `success` | Sikeresen sorba állítva kiküldésre | +| `already_queued` | A levél már szerepel a kiküldési várólistán | +| `failed` | Sikertelen sorbaállítás | -### Levél létrehozás -Levelek létrehozására alkalmas. -A leveleket kezelő gyár: newsletter -A kérés a következőképpen alakul: -`POST: http://example.org/a/newsletter?key=` -`DATA: new&subject=&message=&message_text=` +--- -#### Várható válaszok -Sikeres kérés: `success`, `id`, Sikertelen kérés: `failed`, -Nem megfelelő tárgy: `bad_subject`, Túl hosszú üzenet: `message_too_powerful`, -Túl rövid üzenet: `message_too_short` +### Hírlevelek listázása +Lekérdezi az elérhető hírlevelek listáját. -### Levél küldése -Levelek küldésére alkalmas. -A leveleket kezelő gyár: newsletter -A kérés a következőképpen alakul: -`POST: http://example.org/a/newsletter?key=` -`DATA: send&id=&start=` +**Végpont:** `newsletter` -#### Várható válaszok -Sikeres kérés: `success`, Már várólistán: `already_queued`, Sikertelen kérés: `failed` +``` +POST: https://example.org/a/newsletter/?key= +DATA: get +``` +Válasz: Sikeres kérés esetén a leveleket tartalmazó lista / objektum. -### Levelek listázása -Levelek listázására alkalmas. -A leveleket kezelő gyár: newsletter -A kérés a következőképpen alakul: -`POST: http://example.org/a/newsletter?key=` -`DATA: get` - -#### Várható válaszok -Sikeres kérés: -tömb- - +--- ### Kampány létrehozása -Kampányok létrehozására alkalmas. -A leveleket kezelő gyár: campaign -A kérés a következőképpen alakul: -`POST: http://example.org/a/campaign?key=` -`DATA: new&name=` + +Új kampányt hoz létre. + +**Végpont:** `campaign` + +``` +POST: https://example.org/a/campaign/?key= +DATA: new&name= +``` #### Várható válaszok -Sikeres kérés: `success`, `id`, Sikertelen kérés: `failed` +| Státusz | Leírás | +|---|---| +| `success` + `id` | Sikeres létrehozás, visszaadja az új kampány azonosítóját | +| `failed` | Sikertelen létrehozás | + +--- ### Kampány törlése -Kampányok törlésére alkalmas. -A leveleket kezelő gyár: campaign -A kérés a következőképpen alakul: -`POST: http://example.org/a/campaign?key=` -`DATA: remove&id=` + +Törli a kiválasztott kampányt. + +**Végpont:** `campaign` + +``` +POST: https://example.org/a/campaign/?key= +DATA: remove&id= +``` #### Várható válaszok -Sikeres kérés: `success`, Sikertelen kérés: `failed` +| Státusz | Leírás | +|---|---| +| `success` | Sikeres törlés | +| `failed` | Sikertelen törlés | -### Kampány frissítése (csatolás) -Kampányok listához történő csatolására alkalmas. -A leveleket kezelő gyár: campaign -A kérés a következőképpen alakul: -`POST: http://example.org/a/campaign?key=` -`DATA: update&id=&lists=` +--- + +### Kampány frissítése – listák csatolása + +Levelezőlistákat rendel egy meglévő kampányhoz. + +**Végpont:** `campaign` + +``` +POST: https://example.org/a/campaign/?key= +DATA: update&id=&lists= +``` #### Várható válaszok -Sikeres kérés: `success`, Sikertelen kérés: `failed` +| Státusz | Leírás | +|---|---| +| `success` | Sikeres frissítés | +| `failed` | Sikertelen frissítés | -### Kampány csatolása levélhez -Kampányok levélhez történő csatolására alkalmas. -A leveleket kezelő gyár: campaign -A kérés a következőképpen alakul: -`POST: http://example.org/a/campaign?key=` -`DATA: relations&campaign=&newsletter=` +--- + +### Kampány csatolása hírlevélhez + +Hírlevelet rendel a kampányhoz. + +**Végpont:** `campaign` + +``` +POST: https://example.org/a/campaign/?key= +DATA: relations&id=&newsletter= +``` + +> **Megjegyzés:** A PHP kliens az `attach()` metódusban az `id` mezőben küldi el az aktív kampány azonosítóját. Közvetlen HTTP kérések esetén több kampány azonosítója vesszővel elválasztva a `campaign=` mezőben is átadható. #### Várható válaszok -Sikeres kérés: `success`, Sikertelen kérés: `failed` +| Státusz | Leírás | +|---|---| +| `success` | Sikeres hozzárendelés | +| `failed` | Sikertelen művelet | -### E-mail küldése -Egyéni e-mail küldését, valamint annak sikerességének vizsgálatát teszi lehetővé. -Az üzenet HTML és Plain text formában kerül kiküldésre. Ha a `message_text` értéke -üres, a HTML formátumú levél tartalmával minusz HTML tag-ek lesz azonos. Az üzenet -csak a HTML body részét tartalmazza! Nagy mennyiségű üzenet küldésére használja a -newsletter, list és campaigns gyárakat! -A küldést és ellenőrzést végző gyár: send -A kérés a következőképpen alakul: -`POST: http://example.org/a/send?key=` -`DATA: to=&subject=&message=<Üzenet HTML formában>&message_text=<Üzenet TXT formában>` +--- + +### Egyedi e-mail küldése + +Egyéni, tranzakciós e-mail kiküldésére alkalmas. +Nagy mennyiségű, tömeges levélküldéshez a `newsletter`, `list` és `campaign` végpontokat használja! + +Az üzenet csak a HTML `` belső tartalmát tartalmazza. Ha a `message_text` nincs megadva, automatikusan a HTML tag-ek nélküli szövegből generálódik. + +**Végpont:** `send` + +``` +POST: https://example.org/a/send/?key= +DATA: to=&subject=&message=&message_text= +``` #### Várható válaszok -Sikeres sorbaállítás: `message_queued`, `id`, Nem található feliratkozó: `subscriber_not_found`, -Sikertelen fekiratkozó mentés: `subscriber_error`, Sikertelen sorbaállítás: `message_failed`, -Csomagkorlát elérve: `quota_reached`, Hiányzó paraméter: `missing_parameter` +| Státusz | Leírás | +|---|---| +| `message_queued` + `id` | Sikeresen sorba állítva a kiküldéshez | +| `subscriber_not_found` | A megadott feliratkozó nem található | +| `subscriber_error` | Feliratkozó mentési hiba | +| `message_failed` | Sikertelen sorbaállítás | +| `quota_reached` | Elérte a csomagban engedélyezett korlátot | +| `missing_parameter` | Hiányzó kötelező mező | -### E-mail küldés ellenőrzés -A send gyáron keresztül küldött levelek ellenőrzésére alkalmas. A kimenő levelek -pixel2 lekérésének idejét, a küldés befejezésének idejét és a sikerességét tudja. -`GET: http://example.org/a/send?key=` -`DATA: just_asking=` +--- + +### E-mail küldés állapotának ellenőrzése + +A `send` végponton keresztül küldött egyedi levelek kézbesítési és megnyitási állapotának ellenőrzésére szolgál. + +**Végpont:** `send` + +``` +GET: https://example.org/a/send/?key=&just_asking= +``` + +Paraméter: +- `just_asking`: A kiküldött levél azonosítója (`id`), amit a sikeres küldéskor adott vissza az API. #### Várható válaszok -Sikeres lekérdezés: (status)`success/failed`, `read`, `to`, `time` -Sikertelen lekérdezés: `wrong_id` +| Státusz | Visszaadott mezők | Leírás | +|---|---|---| +| `success` | `status`, `read`, `to`, `time` | Sikeres lekérdezés; a levél sikeresen elküldve (és megnyitva, ha `read` be van állítva) | +| `failed` | `status`, `read`, `to`, `time` | Sikertelen küldés | +| `wrong_id` | — | Nem létező levél azonosító | -### Belépés távolról -Lehetőség van távoli belépésre. Ilyenkor felhasználói név és jelszó megadása -nélkül is lehetőség adódik az adminisztrációs felület elérésére. Az API kérés -egy véletlenszerű kulcsot ad vissza, amit a http://example.org/ oldalnak kell -elküldeni böngészőből. -A belépést végző gyár: login -A kérés a következőképpen alakul: -`POST: http://example.org/a/login?key=` -`DATA: rkey=` +--- + +### Statisztikák lekérdezése + +Kiküldött hírlevelek részletes statisztikai mutatóinak (megnyitások, kattintások, visszapattanók stb.) lekérdezése. + +**Végpont:** `statistics` + +``` +POST: https://example.org/a/statistics/?key= +DATA: newsletter=&type=1 +``` + +Válasz: A statisztikai adatokat tartalmazó objektum. + +--- + +### Távoli belépés + +Lehetővé teszi az adminisztrációs felület közvetlen elérését felhasználónév és jelszó megadása nélkül. +Az API kérés egy egyszer használatos bejelentkezési tokent generál, amellyel a böngészőből átirányítható a felhasználó. + +**Végpont:** `login` + +``` +POST: https://example.org/a/login/?key= +DATA: rkey= +``` + +> **Biztonsági megjegyzés:** A PHP kliens kriptográfiailag biztonságos `bin2hex(random_bytes(16))` segítségével generálja az `rkey` paramétert. Ne használjon gyenge megoldásokat (pl. `md5(time())`). #### Várható válaszok -Sikeres token generálás: `success` és `token` + +| Státusz | Leírás | +|---|---| +| `success` + `token` | Sikeres token generálás. A belépési link a megadott oldalra vezet a token átadásával. | + +--- + +## PHP kliens használati útmutató és példák + +A PHP kliens használatához illessze be a `ninjamail.class.php` fájlt: + +```php +require_once __DIR__ . '/ninjamail.class.php'; +``` + +### Inicializálás és távoli belépés + +```php +$api = new ninjaMail('https://example.org', 'AZ_ON_API_KULCSA'); + +if (!$api->check()) { + die('Hiányzó gazdagép vagy API kulcs!'); +} + +// Egyszer használatos bejelentkezési token kérése +try { + $loginData = $api->login(); + if (($loginData->status ?? '') === 'success') { + echo 'Bejelentkezési token: ' . $loginData->token; + } +} catch (RuntimeException $e) { + error_log('Hiba a távoli belépéskor: ' . $e->getMessage()); +} +``` + +--- + +### Feliratkozás és leiratkozás + +```php +$sub = new ninjaMailSubscription('https://example.org', 'AZ_ON_API_KULCSA'); + +// Lista kiválasztása +$sub->list(12); + +// true = azonnali aktiválás; false = megerősítő levél küldése +$sub->activated(true); + +// Opcionális: meglévő feliratkozó nevének felülírása engedélyezett +$sub->namechange(true); + +try { + // Feliratkozás + $success = $sub->subscribe('teszt@example.com', 'Teszt Elek'); + if ($success) { + echo 'Sikeres feliratkozás!'; + } else { + echo 'Sikertelen feliratkozás. Válasz: ' . json_encode($sub->data); + } + + // Leiratkozás ugyanarról a listáról + $unsubSuccess = $sub->unsubscribe('teszt@example.com'); + if ($unsubSuccess) { + echo 'Sikeres leiratkozás!'; + } +} catch (InvalidArgumentException $e) { + echo 'Paraméterhiba: ' . $e->getMessage(); +} catch (RuntimeException $e) { + echo 'API kommunikációs hiba: ' . $e->getMessage(); +} +``` + +--- + +### Egyedi levél küldése + +```php +$mailer = new ninjaMailSend('https://example.org', 'AZ_ON_API_KULCSA'); +$mailer->to('ugyfel@example.com'); +$mailer->subject('Rendelés visszaigazolása'); +$mailer->message( + '

Köszönjük a vásárlást!

A rendelését feldolgozzuk.

', + 'Köszönjük a vásárlást! A rendelését feldolgozzuk.' // opcionális plain text +); + +try { + $sent = $mailer->send(); + if ($sent) { + echo 'Levél sikeresen sorba állítva!'; + } else { + echo 'Küldési hiba: ' . json_encode($mailer->data); + } +} catch (InvalidArgumentException $e) { + echo 'Hiányzó kötelező adat: ' . $e->getMessage(); +} catch (RuntimeException $e) { + echo 'Hálózati hiba: ' . $e->getMessage(); +} +``` + +--- + +### Hírlevél létrehozása, frissítése és küldése + +```php +$nl = new ninjaMailNewsletter('https://example.org', 'AZ_ON_API_KULCSA'); +$nl->subject('Havi hírlevelünk - 2026 Október'); +$nl->message('

Itt olvashatóak az e havi újdonságok...

'); + +try { + // 1. Hírlevél létrehozása + $newsletterId = $nl->create(); + + if ($newsletterId !== false) { + echo 'Hírlevél létrehozva, ID: ' . $newsletterId . PHP_EOL; + + // 2. Hírlevél frissítése szükség esetén + $nl->subject('Havi hírlevelünk - 2026 Október (Frissített tárgy)'); + $nl->update(); + + // 3. Azonnali kiküldés: + $queued = $nl->send(); + + // Vagy ütemezett kiküldés holnap reggel 8-kor: + // $queued = $nl->send(strtotime('+1 day 08:00')); + + if ($queued) { + echo 'Hírlevél sikeresen sorba állítva a kiküldéshez!'; + } + } + + // 4. Elérhető hírlevelek listázása + $allNewsletters = $nl->get(); +} catch (InvalidArgumentException $e) { + echo 'Paraméterhiba: ' . $e->getMessage(); +} catch (RuntimeException $e) { + echo 'Hiba a hírlevél művelet során: ' . $e->getMessage(); +} +``` + +--- + +### Kampány kezelése + +```php +$campaign = new ninjaMailCampaign('https://example.org', 'AZ_ON_API_KULCSA'); + +try { + // 1. Új kampány létrehozása + $campaignId = $campaign->create('Tavaszi Akció 2026'); + + if ($campaignId !== false) { + echo 'Kampány létrehozva, ID: ' . $campaignId . PHP_EOL; + + // 2. Levelezőlisták hozzárendelése (lista azonosítók tömbje) + $campaign->update([12, 15]); + + // 3. Hírlevél csatolása a kampányhoz + $campaign->attach(42); + + // 4. Kampány törlése szükség esetén + // $campaign->remove(); + } +} catch (InvalidArgumentException $e) { + echo 'Paraméterhiba: ' . $e->getMessage(); +} catch (RuntimeException $e) { + echo 'Kampány hiba: ' . $e->getMessage(); +} +``` + +--- + +### Statisztika lekérdezése + +```php +$stats = new ninjaMailStatistics('https://example.org', 'AZ_ON_API_KULCSA'); + +try { + $newsletterId = 42; + $result = $stats->get($newsletterId); + print_r($result); +} catch (InvalidArgumentException $e) { + echo 'Érvénytelen hírlevél ID: ' . $e->getMessage(); +} catch (RuntimeException $e) { + echo 'Statisztika lekérdezési hiba: ' . $e->getMessage(); +} +``` diff --git a/example.simple.php b/example.simple.php deleted file mode 100644 index a3a5016..0000000 --- a/example.simple.php +++ /dev/null @@ -1,22 +0,0 @@ -to('webmaster@example.org'); -$mail->subject('Hello'); -$mail->message('HTML_CONTENT', 'TEXT_CONTENT'); -var_dump($mail->send()); - -// Newsletter -$newsletter = new ninjaMailNewsletter('https://admin.dimail.hu', 'API_KEY'); -$newsletter->subject('New subject'); -$newsletter->message('HTML_CONTENT', 'TEXT_CONTENT OR NULL'); - -if ($newsletter->update() && $newsletter->send()) - echo "updated & sent\n"; - -// Stats -$stat = new ninjaMailStatistics('https://admin.dimail.hu', 'API_KEY'); -print_r($stat->get(3512201)); diff --git a/ng/README.md b/ng/README.md deleted file mode 100644 index 0591189..0000000 --- a/ng/README.md +++ /dev/null @@ -1,429 +0,0 @@ -# ninjaMail API - -Ebben a dokumentumban megismerheti a levelező alkalmazásprogramozási interfészének használatát. -A példák PHP szemszögből készültek, de bármely nyelvből felhasználható, amely támogatja a cURL-t vagy GET/POST hívásokat. - ---- - -## Bevezetés - -Az API használatához regisztráció után API kulcsot kell generálni a **Beállítások → API** menüpontban. -A generált kulcsot tartsa titokban — a kulccsal a legtöbb funkció elérhető programozottan, beleértve feliratkozók hozzáadását és törlését is. -Webes bejelentkezésre az API kulcs önmagában nem alkalmas. - ---- - -## API URL - -A kulcsgenerálás után az API alap URL ugyanazon a felületen jelenik meg. - -``` -http://example.org/a/?key= -``` - -| Elem | Leírás | -|-------------|-------------------------------------| -| `example.org` | A szolgáltató domainje | -| `` | A funkciót kezelő végpont neve | -| `` | Az API hitelesítési kulcs | - -> **Megjegyzés:** Éles környezetben mindig HTTPS-t használjon. - ---- - -## Hibakezelés - -A PHP kliens `RuntimeException`-t dob hálózati vagy JSON hibák esetén, `InvalidArgumentException`-t hiányzó vagy érvénytelen paraméterek esetén. Mindig try/catch blokkban hívja az API metódusokat: - -```php -try { - $result = $mailer->send(); -} catch (InvalidArgumentException $e) { - // hiányzó / érvénytelen paraméter - error_log($e->getMessage()); -} catch (RuntimeException $e) { - // hálózati hiba, JSON hiba, hiányzó kulcs - error_log($e->getMessage()); -} -``` - ---- - -## Végpontok - -### Feliratkozó hozzáadása - -**Gyár:** `subscribe` - -``` -POST: http://example.org/a/subscribe?key= -DATA: list=&name=&email=&activated=<1|0> -``` - -Az `activated` paraméter: -- `1` — a feliratkozó azonnal megerősítettként kerül rögzítésre -- `0` — megerősítő e-mail kerül kiküldésre a megadott címre - -Opcionális: `forcenamechange=<1|0>` — meglévő feliratkozó nevének felülírása. - -#### Várható válaszok - -| Státusz | Leírás | -|-------------------|--------------------------------| -| `success` | Sikeres feliratkozás | -| `sub_error` | Sikertelen feliratkozás | -| `no_mx_record` | Nincs MX rekord (lehet átmeneti) | -| `bad_list` | Érvénytelen lista azonosító | -| `reg_error` | Sikertelen regisztráció | - ---- - -### Feliratkozó eltávolítása - -**Gyár:** `unsubscribe` - -``` -POST: http://example.org/a/unsubscribe?key= -DATA: list=&email= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|------------------------|---------------------------------| -| `success` | Sikeres leiratkozás | -| `unsub_error` | Sikertelen leiratkozás | -| `unknown_email` | Ismeretlen e-mail cím | -| `missing_parameters` | Hiányzó paraméterek | - ---- - -### Lista létrehozása - -**Gyár:** `list` - -``` -POST: http://example.org/a/list?key= -DATA: new&name= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|--------------|-----------------------| -| `success` | Sikeres létrehozás | -| `failed` | Sikertelen kérés | -| `bad_name` | Nem megfelelő név | - ---- - -### Lista törlése - -**Gyár:** `list` - -``` -POST: http://example.org/a/list?key= -DATA: remove&id= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|-----------|--------------------| -| `success` | Sikeres törlés | -| `failed` | Sikertelen törlés | - ---- - -### Listák lekérdezése - -**Gyár:** `list` - -``` -POST: http://example.org/a/list?key= -DATA: get -``` - -#### Várható válasz - -Sikeres kérés esetén a listák tömbje. - ---- - -### Levél létrehozása - -**Gyár:** `newsletter` - -``` -POST: http://example.org/a/newsletter?key= -DATA: new&subject=&message=&message_text= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|------------------------|---------------------------| -| `success` + `id` | Sikeres létrehozás | -| `failed` | Sikertelen kérés | -| `bad_subject` | Érvénytelen tárgy | -| `message_too_powerful` | Túl hosszú üzenet | -| `message_too_short` | Túl rövid üzenet | - ---- - -### Levél frissítése - -**Gyár:** `newsletter` - -``` -POST: http://example.org/a/newsletter?key= -DATA: new&id=&subject=&message=&message_text= -``` - -#### Várható válaszok - -Azonos a levél létrehozásával. - ---- - -### Levél küldése - -**Gyár:** `newsletter` - -``` -POST: http://example.org/a/newsletter?key= -DATA: send&id=&start= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|-------------------|--------------------------------| -| `success` | Sikeres sorbaállítás | -| `already_queued` | Már várólistán szerepel | -| `failed` | Sikertelen kérés | - ---- - -### Levelek listázása - -**Gyár:** `newsletter` - -``` -POST: http://example.org/a/newsletter?key= -DATA: get -``` - -#### Várható válasz - -Sikeres kérés esetén a levelek tömbje. - ---- - -### Kampány létrehozása - -**Gyár:** `campaign` - -``` -POST: http://example.org/a/campaign?key= -DATA: new&name= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|------------------|----------------------| -| `success` + `id` | Sikeres létrehozás | -| `failed` | Sikertelen kérés | - ---- - -### Kampány törlése - -**Gyár:** `campaign` - -``` -POST: http://example.org/a/campaign?key= -DATA: remove&id= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|-----------|--------------------| -| `success` | Sikeres törlés | -| `failed` | Sikertelen törlés | - ---- - -### Kampány frissítése (lista csatolás) - -**Gyár:** `campaign` - -``` -POST: http://example.org/a/campaign?key= -DATA: update&id=&lists= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|-----------|---------------------| -| `success` | Sikeres frissítés | -| `failed` | Sikertelen kérés | - ---- - -### Kampány csatolása levélhez - -**Gyár:** `campaign` - -``` -POST: http://example.org/a/campaign?key= -DATA: relations&campaign=&newsletter= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|-----------|-------------------| -| `success` | Sikeres csatolás | -| `failed` | Sikertelen kérés | - ---- - -### E-mail küldése - -Egyéni e-mail küldésére alkalmas. Nagy mennyiségű levélhez használja a `newsletter`, `list` és `campaign` gyárakat. -Ha a `message_text` üres, az értéke a HTML tartalom tag-ek nélküli változata lesz. -Az üzenet csak a HTML `` tartalmát tartalmazza. - -**Gyár:** `send` - -``` -POST: http://example.org/a/send?key= -DATA: to=&subject=&message=&message_text= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|--------------------------|---------------------------------| -| `message_queued` + `id` | Sikeres sorbaállítás | -| `subscriber_not_found` | Ismeretlen feliratkozó | -| `subscriber_error` | Feliratkozó mentési hiba | -| `message_failed` | Sikertelen sorbaállítás | -| `quota_reached` | Csomagkorlát elérve | -| `missing_parameter` | Hiányzó paraméter | - ---- - -### E-mail küldés ellenőrzése - -A `send` gyáron keresztül küldött levelek állapotát kérdezi le: az olvasás időpontját, a küldés befejezésének idejét és sikerességét. - -**Gyár:** `send` - -``` -GET: http://example.org/a/send?key=&just_asking= -``` - -#### Várható válaszok - -| Státusz | Mezők | Leírás | -|-----------|------------------------------------|---------------------------| -| `success` | `status`, `read`, `to`, `time` | Sikeres lekérdezés | -| `failed` | `status`, `read`, `to`, `time` | Sikertelen küldés | -| `wrong_id`| — | Érvénytelen azonosító | - ---- - -### Statisztikák lekérdezése - -**Gyár:** `statistics` - -``` -POST: http://example.org/a/statistics?key= -DATA: newsletter=&type=1 -``` - -#### Várható válasz - -A hírlevél statisztikai adatait tartalmazó objektum. - ---- - -### Belépés távolról - -Lehetővé teszi az adminisztrációs felület elérését felhasználói név és jelszó megadása nélkül. -Az API egy egyszer használatos tokent ad vissza, amelyet böngészőből kell elküldeni a `http://example.org/` oldalra. - -> **Biztonsági megjegyzés:** A PHP kliens `bin2hex(random_bytes(16))` segítségével generálja a véletlenszerű kulcsot — ne használjon gyengébb módszert (pl. `md5(time())`). - -**Gyár:** `login` - -``` -POST: http://example.org/a/login?key= -DATA: rkey= -``` - -#### Várható válaszok - -| Státusz | Leírás | -|---------------------|--------------------------------| -| `success` + `token` | Sikeres token generálás | - ---- - -## PHP használati példák - -### Feliratkozó hozzáadása - -```php -$sub = new ninjaMailSubscription('https://example.org', 'az-api-kulcsom'); -$sub->list(3); -$sub->activated(true); - -try { - $ok = $sub->subscribe('pelda@email.hu', 'Kovács János'); - echo $ok ? 'Sikeres feliratkozás' : 'Sikertelen feliratkozás'; -} catch (RuntimeException $e) { - error_log($e->getMessage()); -} -``` - -### E-mail küldése - -```php -$mailer = new ninjaMailSend('https://example.org', 'az-api-kulcsom'); -$mailer->to('pelda@email.hu'); -$mailer->subject('Üdvözlünk!'); -$mailer->message('

Szia!

'); - -try { - $ok = $mailer->send(); - echo $ok ? 'Levél elküldve' : 'Küldés sikertelen'; -} catch (InvalidArgumentException $e) { - echo 'Hiányzó mező: ' . $e->getMessage(); -} catch (RuntimeException $e) { - error_log($e->getMessage()); -} -``` - -### Hírlevél létrehozása és küldése - -```php -$nl = new ninjaMailNewsletter('https://example.org', 'az-api-kulcsom'); -$nl->subject('Havi összefoglaló'); -$nl->message('

Hírek

Tartalom...

'); - -try { - $id = $nl->create(); - if ($id) { - $nl->send(); // azonnali küldés - // $nl->send(strtotime('+1 day')); // ütemezett küldés - } -} catch (RuntimeException $e) { - error_log($e->getMessage()); -} -``` diff --git a/ng/ninjamail.class.php b/ng/ninjamail.class.php deleted file mode 100644 index db91dd9..0000000 --- a/ng/ninjamail.class.php +++ /dev/null @@ -1,612 +0,0 @@ -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); - } -} diff --git a/ninjamail.class.php b/ninjamail.class.php index 3b20cf5..47ec426 100644 --- a/ninjamail.class.php +++ b/ninjamail.class.php @@ -1,327 +1,619 @@ host = $host; - if ($key) $this->key = $key; - } + /** + * @param string $host Az API gazdagép alap URL-je (pl. https://example.org) + * @param string|bool $key API hitelesítési kulcs + */ + public function __construct(string $host, string|bool $key = false) + { + $this->host = rtrim($host, '/'); + if ($key !== false && $key !== '') { + $this->key = (string)$key; + } + } - public function check() - { - if (!$this->host || !$this->key) - return false; - return true; - } + /** + * 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); + } - public function process($f, $data, $post_method = true) - { - $ch = curl_init($this->host.'/a/'.$f.'/?key='.$this->key); - curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8'); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - $data = curl_exec($ch); - curl_close($ch); + /** + * POST kérést küld az API adott végpontjára. + * + * @param string $endpoint A 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 $endpoint, array $data): object + { + if (!$this->check()) { + throw new RuntimeException('ninjaMail: hiányzó gazdagép vagy API kulcs.'); + } - $data = @(object)json_decode($data); - $this->data = $data; - return $data; - } + $url = $this->host . '/a/' . rawurlencode($endpoint) . '/?key=' . urlencode($this->key); - public function login() - { - return $this->process('login', ['rkey' => md5(time().rand(0,65500).rand(0,10))]); - } + $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 => is_array($data) ? http_build_query($data) : $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); + + if ($response === false) { + throw new RuntimeException( + sprintf('ninjaMail: cURL hiba (%d): %s', $errno, $error) + ); + } + + $responseStr = trim((string)$response); + if ($responseStr === '') { + $result = (object)[]; + $this->data = $result; + return $result; + } + + $decoded = json_decode($responseStr); + 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)), + ]); + } } -// Send Email +// --------------------------------------------------------------------------- +// 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 = ''; - private $to; - private $subject; - private $message; - private $message_text; - - public function to($to) + /** + * @param string $to Feliratkozó azonosítója vagy e-mail cím + */ + public function to(string $to): true { - $this->to = $to; - return true; + $this->to = trim($to); + return true; } - public function subject($s) + /** + * @param string $s Az e-mail tárgya + */ + public function subject(string $s): true { - $this->subject = $s; - return true; + $this->subject = $s; + return true; } - public function message($m, $t = false) + /** + * @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; - if (!$t) $this->message_text = trim(strip_tags($m)); - else $this->message_text = $t; - return true; + $this->message = $m; + $this->message_text = ($t !== false && $t !== '') + ? (string)$t + : trim(strip_tags($m)); + return true; } - public function send() + /** + * 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 { - $post = [ - 'to' => $this->to, - 'subject' => $this->subject, - 'message' => $this->message, - 'message_text' => $this->message_text - ]; - return $this->process('send', $post, true)->status == 'message_queued' ? true : false; + 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'; } } -// Subscribe +// --------------------------------------------------------------------------- +// 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; - private $list; - private $activated = 0; - private $forcenamechange = 0; - - public function list($id) + /** + * @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 (is_numeric($id)) - { - $this->list = $id; - return true; - } - return false; + if ($id <= 0) { + return false; + } + $this->list = $id; + return true; } - public function activated($s) + /** + * @param bool $s true = azonnal megerősített; false = megerősítő e-mail küldése + */ + public function activated(bool $s): true { - if ($s) $this->activated = 1; - else $this->activated = 0; - return true; + $this->activated = $s ? 1 : 0; + return true; } - public function namechange($s) - { - if ($s) $this->forcenamechange = 1; - else $this->forcenamechange = 0; - return true; - } - - public function subscribe($email, $name = '') + /** + * @param bool $s true = névfrissítés engedélyezése meglévő feliratkozóknál + */ + public function namechange(bool $s): true { - if (!$this->list || !is_numeric($this->activated)) - return false; - - $post = [ - 'list' => $this->list, - 'name' => $name, - 'email' => $email, - 'activated' => $this->activated, - 'forcenamechange' => $this->forcenamechange - ]; - return $this->process('subscribe', $post, true)->status == 'success' ? true : false; + $this->forcenamechange = $s ? 1 : 0; + return true; } - public function unsubscribe($email) + /** + * 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) - return false; + 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, true)->status == 'success' ? true : false; + $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'; } } -// Newsletter +// --------------------------------------------------------------------------- +// 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 = ''; - private $newsletter; - private $subject; - private $message; - private $message_text; - - - public function newsletter($id = false) - { - if (is_numeric($id)) - { - $this->newsletter = $id; - return true; - } - return $this->newsletter; - } - - public function subject($s) + /** + * 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 { - $this->subject = $s; - return true; + if ($id !== false) { + if ($id > 0) { + $this->newsletter = $id; + return true; + } + return false; + } + return $this->newsletter; } - public function message($m, $t = false) + /** + * @param string $s A hírlevél tárgya + */ + public function subject(string $s): true { - $this->message = $m; - if (!$t) $this->message_text = trim(strip_tags($m)); - else $this->message_text = $t; - return true; + $this->subject = $s; + return true; } - public function query($update = false) - { - if (!$this->message) - return false; + /** + * @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; + } - $post = [ - 'new' => true, - 'id' => $update ? $this->newsletter : false, - 'subject' => $this->subject, - 'message' => $this->message, - 'message_text' => $this->message_text - ]; - $data = $this->process('newsletter', $post, true); - if ($data->status == 'success') - { - $this->newsletter = $data->id; - return $data->id; - } - return false; - } + /** + * @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ő.' + ); + } - public function create() - { - return $this->query(false); - } + $post = [ + 'new' => true, + 'id' => $update ? $this->newsletter : false, + 'subject' => $this->subject, + 'message' => $this->message, + 'message_text' => $this->message_text, + ]; - public function update() - { - if (!$this->newsletter) - return false; + $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 $this->query(true); - } + return false; + } - public function send($time = false) - { - if (!$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); + } - $post = [ - 'send' => true, - 'id' => $this->newsletter, - 'start' => $time ? $time : 0 - ]; - $data = $this->process('newsletter', $post, true); - if ($data->status == 'success' || $this->status == 'already_queued') - return true; + /** + * 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); + } - return false; - } + /** + * 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.' + ); + } - public function get() - { - return $this->process('newsletter', ['get' => true], true); - } + $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]); + } } -// Campaign +// --------------------------------------------------------------------------- +// Kampány +// --------------------------------------------------------------------------- + +/** + * Kampányok létrehozása, törlése és konfigurálása. + */ class ninjaMailCampaign extends ninjaMail { - private $campaign; + private int $campaign = 0; - public function campaign($id = false) - { - if (!$id) - return $this->campaign; + /** + * 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; + } - if (is_numeric($id)) - { - $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.' + ); + } - public function create($name) - { - $post = [ - 'new' => true, - 'name' => $name - ]; - $data = $this->process('campaign', $post, true); - if ($data->status == 'success') - { - $this->campaign = $data->id; - return $data->id; - } + $post = [ + 'new' => true, + 'name' => $name, + ]; - return false; - } + $data = $this->process('campaign', $post); + if (($data->status ?? '') === 'success' && isset($data->id) && is_numeric($data->id)) { + $this->campaign = (int)$data->id; + return $this->campaign; + } - public function remove() - { - $post = [ - 'remove' => true, - 'id' => $this->campaign - ]; - return $this->process('campaign', $post, true)->status == 'success' ? true : false; - } + return false; + } - public function update($lists) - { - if (!is_array($lists)) - 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 = [ - 'update' => true, - 'id' => $this->campaign, - 'lists' => $lists - ]; - return $this->process('campaign', $post, true)->status == 'success' ? true : false; - } + $post = [ + 'remove' => true, + 'id' => $this->campaign, + ]; - public function attach($newsletter) - { - if (!is_numeric($newsletter)) - return false; + return ($this->process('campaign', $post)->status ?? '') === 'success'; + } - $post = [ - 'relations' => true, - 'id' => $this->campaign, - 'newsletter' => $newsletter - ]; - return $this->process('campaign', $post, true)->status == 'success' ? true : false; - } + /** + * 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, + 'campaign' => $this->campaign, + 'id' => $this->campaign, + 'newsletter' => $newsletter, + ]; + + return ($this->process('campaign', $post)->status ?? '') === 'success'; + } } -// Statistics +// --------------------------------------------------------------------------- +// 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ó.' + ); + } - public function get($id) - { - if (!is_numeric($id)) - return false; - - $post = [ - 'newsletter' => $id, - 'type' => 1 - ]; - return $this->process('statistics', $post, true); - } + $post = [ + 'newsletter' => $id, + 'type' => 1, + ]; + return $this->process('statistics', $post); + } } diff --git a/test_all.php b/test_all.php new file mode 100644 index 0000000..a9bda1c --- /dev/null +++ b/test_all.php @@ -0,0 +1,214 @@ +check()); + +echo "[+] login(): "; +try { + $login = $base->login(); + echo json_encode($login, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 2. Lista műveletek +// --------------------------------------------------------------------------- +echo "\n=== 2. LISTA MŰVELETEK (ninjaMail::process) ===\n"; +$listId = null; +try { + echo "[+] Lista létrehozása (list -> new): "; + $createdList = $base->process('list', ['new' => true, 'name' => 'Teszt Lista 2026']); + echo json_encode($createdList, JSON_UNESCAPED_UNICODE) . "\n"; + $listId = $createdList->id ?? null; + + echo "[+] Listák lekérdezése (list -> get): "; + $lists = $base->process('list', ['get' => true]); + echo json_encode($lists, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 3. Feliratkozások +// --------------------------------------------------------------------------- +echo "\n=== 3. ninjaMailSubscription TESZTELÉSE ===\n"; +$sub = new ninjaMailSubscription($host, $key); +$activeListId = $listId ? (int)$listId : 1; + +echo "[+] list($activeListId): "; +var_dump($sub->list($activeListId)); + +echo "[+] activated(true): "; +var_dump($sub->activated(true)); + +echo "[+] namechange(true): "; +var_dump($sub->namechange(true)); + +try { + echo "[+] subscribe(\"$testEmail\", \"Teszt Elek\"): "; + $subRes = $sub->subscribe($testEmail, 'Teszt Elek'); + var_dump($subRes); + echo " Válasz: " . json_encode($sub->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] unsubscribe(\"$testEmail\"): "; + $unsubRes = $sub->unsubscribe($testEmail); + var_dump($unsubRes); + echo " Válasz: " . json_encode($sub->data, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 4. Hírlevelek +// --------------------------------------------------------------------------- +echo "\n=== 4. ninjaMailNewsletter TESZTELÉSE ===\n"; +$nl = new ninjaMailNewsletter($host, $key); +echo "[+] subject(): "; +var_dump($nl->subject('Rendszertesztek 2026 - Hírlevél')); + +echo "[+] message(): "; +$longContent = '

Kedves Feliratkozónk!

Ez egy hivatalos teszt hírlevél, amely a ninjaMail API funkcionalitását teszteli. A hírlevél tartalma megfelelően hosszú szöveget tartalmaz, hogy teljesítse a rendszer tartalmi és formai követelményeit. További információkért látogasson el weboldalunkra vagy keresse ügyfélszolgálatunkat.

Üdvözlettel,
A rendszer üzemeltetője

'; +var_dump($nl->message($longContent)); + +$newsletterId = null; +try { + echo "[+] create(): "; + $newsletterId = $nl->create(); + var_dump($newsletterId); + echo " Válasz: " . json_encode($nl->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] newsletter() getter: "; + var_dump($nl->newsletter()); + + echo "[+] update(): "; + $nl->subject('Rendszertesztek 2026 - Frissített hírlevél tárgy'); + $nlUp = $nl->update(); + var_dump($nlUp); + echo " Válasz: " . json_encode($nl->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] get(): "; + $allNl = $nl->get(); + echo json_encode($allNl, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] send() (időzítve +1 évre): "; + $sendNl = $nl->send(strtotime('+1 year')); + var_dump($sendNl); + echo " Válasz: " . json_encode($nl->data, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 5. Kampányok +// --------------------------------------------------------------------------- +echo "\n=== 5. ninjaMailCampaign TESZTELÉSE ===\n"; +$camp = new ninjaMailCampaign($host, $key); +$campaignId = null; +try { + echo "[+] create(\"API Teszt Kampány\"): "; + $campaignId = $camp->create('API Teszt Kampány'); + var_dump($campaignId); + echo " Válasz: " . json_encode($camp->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] campaign() getter: "; + var_dump($camp->campaign()); + + echo "[+] update() (lista csatolása): "; + $campUp = $camp->update([(int)$activeListId]); + var_dump($campUp); + echo " Válasz: " . json_encode($camp->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] attach(" . ($newsletterId ?? 1) . ") (hírlevél csatolása): "; + $campAtt = $camp->attach((int)($newsletterId ?? 1)); + var_dump($campAtt); + echo " Válasz: " . json_encode($camp->data, JSON_UNESCAPED_UNICODE) . "\n"; + + echo "[+] remove() (kampány törlése): "; + $campRem = $camp->remove(); + var_dump($campRem); + echo " Válasz: " . json_encode($camp->data, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 6. Egyedi levélküldés +// --------------------------------------------------------------------------- +echo "\n=== 6. ninjaMailSend TESZTELÉSE ===\n"; +$sender = new ninjaMailSend($host, $key); +echo "[+] to(\"$sendEmail\"): "; +var_dump($sender->to($sendEmail)); + +echo "[+] subject(): "; +var_dump($sender->subject('Tranzakciós teszt e-mail')); + +echo "[+] message(): "; +var_dump($sender->message('

Ez egy egyedi tranzakciós teszt e-mail.

')); + +try { + echo "[+] send(): "; + $sendRes = $sender->send(); + var_dump($sendRes); + echo " Válasz: " . json_encode($sender->data, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 7. Statisztika +// --------------------------------------------------------------------------- +echo "\n=== 7. ninjaMailStatistics TESZTELÉSE ===\n"; +$stat = new ninjaMailStatistics($host, $key); +try { + $statNlId = (int)($newsletterId ?? 1); + echo "[+] get($statNlId): "; + $statRes = $stat->get($statNlId); + echo json_encode($statRes, JSON_UNESCAPED_UNICODE) . "\n"; +} catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; +} + +// --------------------------------------------------------------------------- +// 8. Takarítás (ha hoztunk létre listát) +// --------------------------------------------------------------------------- +if ($listId) { + echo "\n=== 8. TAKARÍTÁS (Teszt lista törlése) ===\n"; + try { + echo "[+] remove list $listId: "; + $delList = $base->process('list', ['remove' => true, 'id' => $listId]); + echo json_encode($delList, JSON_UNESCAPED_UNICODE) . "\n"; + } catch (Throwable $e) { + echo "Hiba: " . $e->getMessage() . "\n"; + } +} + +echo "\nTesztelés befejezve.\n"; diff --git a/tests/test_validity.php b/tests/test_validity.php new file mode 100644 index 0000000..6510763 --- /dev/null +++ b/tests/test_validity.php @@ -0,0 +1,160 @@ +getMessage() . "\n"; + $failed++; + } +} + +// 1. ninjaMail alaposztály +runTest("ninjaMail inicializálás és check()", function () { + $api = new ninjaMail('https://example.org', 'test-key'); + assert($api->check() === true, "check() igaz kell legyen érvényes adatokkal"); + + $apiNoKey = new ninjaMail('https://example.org'); + assert($apiNoKey->check() === false, "check() hamis kell legyen hiányzó kulccsal"); +}); + +// 2. ninjaMailSend +runTest("ninjaMailSend metódusok és kötelező mezők validációja", function () { + $s = new ninjaMailSend('https://example.org', 'test-key'); + assert($s->to('user@example.com') === true); + assert($s->subject('Teszt tárgy') === true); + assert($s->message('HTML', 'Szöveg') === true); + + $emptySender = new ninjaMailSend('https://example.org', 'test-key'); + try { + $emptySender->send(); + throw new Exception("Nem dobott kivételt hiányzó mezők esetén"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt, elvárt kivétel + } +}); + +// 3. ninjaMailSubscription +runTest("ninjaMailSubscription beállítások és lista validáció", function () { + $sub = new ninjaMailSubscription('https://example.org', 'test-key'); + assert($sub->list(10) === true); + assert($sub->list(0) === false); + assert($sub->list(-5) === false); + assert($sub->activated(true) === true); + assert($sub->namechange(true) === true); + + $emptySub = new ninjaMailSubscription('https://example.org', 'test-key'); + try { + $emptySub->subscribe('user@example.com'); + throw new Exception("Nem dobott kivételt hiányzó lista esetén"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + try { + $emptySub->unsubscribe('user@example.com'); + throw new Exception("Nem dobott kivételt hiányzó lista esetén"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } +}); + +// 4. ninjaMailNewsletter +runTest("ninjaMailNewsletter hírlevél azonosító és üzenet validáció", function () { + $nl = new ninjaMailNewsletter('https://example.org', 'test-key'); + assert($nl->subject('Tárgy') === true); + assert($nl->message('Tartalom') === true); + assert($nl->newsletter(25) === true); + assert($nl->newsletter() === 25); + assert($nl->newsletter(0) === false); + + $emptyNl = new ninjaMailNewsletter('https://example.org', 'test-key'); + try { + $emptyNl->create(); + throw new Exception("Nem dobott kivételt üres üzenetnél"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + try { + $emptyNl->update(); + throw new Exception("Nem dobott kivételt hírlevél ID nélkül"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + try { + $emptyNl->send(); + throw new Exception("Nem dobott kivételt hírlevél ID nélkül"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } +}); + +// 5. ninjaMailCampaign +runTest("ninjaMailCampaign kampány validáció", function () { + $camp = new ninjaMailCampaign('https://example.org', 'test-key'); + assert($camp->campaign(40) === true); + assert($camp->campaign() === 40); + assert($camp->campaign(0) === false); + + try { + $camp->create(''); + throw new Exception("Nem dobott kivételt üres névnél"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + $emptyCamp = new ninjaMailCampaign('https://example.org', 'test-key'); + try { + $emptyCamp->remove(); + throw new Exception("Nem dobott kivételt kampány ID nélkül"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + try { + $camp->update([]); + throw new Exception("Nem dobott kivételt üres listánál"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } + + try { + $camp->attach(0); + throw new Exception("Nem dobott kivételt érvénytelen hírlevél ID-nél"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } +}); + +// 6. ninjaMailStatistics +runTest("ninjaMailStatistics azonosító validáció", function () { + $stat = new ninjaMailStatistics('https://example.org', 'test-key'); + try { + $stat->get(0); + throw new Exception("Nem dobott kivételt 0 azonosítónál"); + } catch (InvalidArgumentException $e) { + // Sikeres teszt + } +}); + +echo "\nTeszt összefoglaló: $passed sikeres, $failed sikertelen.\n"; + +if ($failed > 0) { + exit(1); +} + +exit(0);