Načítanie a sťahovanie
fetch() — GET do pamäte
Chránený GET, ktorého telo sa načíta do pamäte v rámci limitu bajtov a jedného časového rozpočtu:
$page = SafeFetch::fetch(
$url,
maxBytes: 1_000_000, // default safe-fetch.fetch.max_bytes (5 MiB)
timeout: 20, // default safe-fetch.fetch.timeout (30 s), every hop together, 1–600
accept: 'text/html',
headers: ['X-Trace' => $id], // never Host; sent to the first origin only
followRedirects: true, // default: the policy's redirects
policy: SafeFetch::policy(), // default: the configured policy
);
$page->status; // 2xx
$page->body; // the whole body, within the cap
$page->contentType; // or null
$page->url; // the URL the answer came from (the last hop, rebuilt)
$page->headers; // array<string, list<string>>
$page->header('etag');
$page->json('data.items', []); // the body decoded as JSON (null when it is not), a dot-notation keyFetchedResponse::json(?string $key = null, mixed $default = null) dekóduje telo pri každom volaní (objekty ako polia); telo, ktoré nie je platný JSON, je null, takže kľúč vráti $default.
download() — ten istý GET streamovaný do súboru
Pre súbor príliš veľký na držanie v pamäti — import, nahratie média z URL. Prijíma rovnaké voľby ako fetch() a zlyháva rovnako; telo ide cez ten istý limit do súboru, nikdy do pamäte:
$file = SafeFetch::download($url, $path, maxBytes: 50_000_000); // $path: e.g. storage_path('app/imports/feed.xml')
$file->status; // 2xx
$file->path; // where the body is — the path you gave
$file->bytes; // its size, as written (decoded)
$file->contentType; // or null
$file->url; // the URL the answer came from (the last hop, rebuilt)
$file->headers; // array<string, list<string>>
$file->header('etag');- Adresár musí existovať a byť zapisovateľný a cesta nesmie byť súbor len na čítanie ani adresár — inak InvalidArgumentException, ešte pred odoslaním čohokoľvek.
- Telo ide do dočasného súboru vedľa $path (.<name>.<random>) a na $path sa premenuje, až keď sťahovanie uspeje — atomická výmena v rámci jedného súborového systému. Súbor, ktorý už na $path je, zostane medzitým celý a ponechá si práva; nový súbor dostane práva podľa umask.
- Symlink na $path sa zapíše „cezeň“, ako pri bežnom zápise: dočasný súbor vznikne vedľa cieľa odkazu a nahradí ho, a odkaz zostane odkazom.
- Každý krok začne dočasný súbor odznova, takže telo presmerovania sa doň nikdy nedostane.
- Pri akomkoľvek zlyhaní sa dočasný súbor zmaže — telo nad limitom, stav mimo 2xx, odmietnuté presmerovanie, prerušené spojenie, plný disk — a súbor, ktorý už na $path bol, zostane bez zmeny. Neúspešné premenovanie vyhodí RuntimeException.
- Ak worker počas sťahovania tvrdo skončí, dočasný súbor .<name>.XXXXXX môže v adresári zostať — môžete ho bezpečne zmazať, nič ho nečíta.
Správanie oboch
- Číta sa len telo odpovede 2xx. Každá iná odpoveď sa posúdi len podľa stavu a hlavičiek — prenos skončí pred telom, takže 503 s obrovskou chybovou stránkou zostane opakovateľnou 503. Informačná odpoveď (103 Early Hints) sa preskočí.
- Limit bajtov: odpoveď 2xx s Content-Length nad limitom skončí pred telom; akékoľvek iné telo sa odreže, keď limit prekročí — počíta sa po dekódovaní, takže sa zastaví aj komprimovaná bomba. V oboch prípadoch: FetchFailed (too_large).
- Presmerovania: followRedirects: true (alebo pravidlá) sleduje pri GET všetkých päť stavov, ak pravidlá neurčia vlastné; ponechá sa len výsledné telo.
- Hlavičky, ktoré odovzdáte, idú len na prvý origin a hlavička Host sa odmietne (UnsafeRequestOptions).
- Požiadavka vzniká z továrne HTTP klienta v kontajneri, takže na ňu odpovie a zaznamená ju Http::fake().
Chyby
| Čo | Výnimka (dôvod) | retryable() |
|---|---|---|
| odmietnuté ochranou | DestinationRejected | nie |
| hostiteľ sa nepreloží (pri overení alebo curl 6) | DestinationUnavailable (unresolved) | áno |
| rozpočet minutý medzi krokmi | DestinationUnavailable (timeout) | áno |
| mimo 2xx | FetchFailed (status) | 408, 429, 5xx |
| nad limitom | FetchFailed (too_large) | nie |
curl 28 | FetchFailed (timeout) | áno |
curl 51, 53, 54, 58, 59, 60, 64, 66, 77, 80, 82, 83, 90, 91 | FetchFailed (tls) | nie |
| akákoľvek iná chyba curl | FetchFailed (connection) | áno |
| nečitateľné HTTP (stav mimo 100–599) | FetchFailed (protocol) | nie |
| telo sa nepodarilo uložiť (plný disk, zlyhaný presun do php://temp) | RuntimeException | — lokálna chyba, nikdy FetchFailed |
| hlavička Host | UnsafeRequestOptions | — |
| download(): pre cestu neexistuje zapisovateľný adresár | InvalidArgumentException | — |
use RoundlyConsulting\SafeFetch\Exceptions\FetchFailed;
use RoundlyConsulting\SafeFetch\Exceptions\SafeFetchException;
try {
$page = SafeFetch::fetch($url, maxBytes: 1_000_000);
} catch (FetchFailed $e) {
$e->reason(); // Reason::Status, TooLarge, Timeout, Connection, Tls or Protocol
$e->status(); // the HTTP status for Reason::Status, otherwise null
$e->retryAfter(); // the server's Retry-After in seconds, for 408 / 429 / 5xx
$e->retryable();
} catch (SafeFetchException $e) {
$e->retryable(); // DestinationUnavailable (unresolved, timeout): yes · DestinationRejected: never
}- Retry-After sa číta v sekundách alebo ako HTTP dátum, najviac 86 400.
- getPrevious() pri chybe prenosu je RuntimeException, ktorá uvádza len triedu pôvodnej výnimky a kód curl — nikdy vlastnú správu Guzzle, ktorá obsahuje URL adresu a adresu, na ktorú sa pripojil.
- Mapujú sa len chyby prenosu. Všetko ostatné sa k volajúcemu dostane tak, ako bolo vyhodené — odmietnutie ochranou, LogicException z fake pre požiadavku, na ktorú neodpovedal žiadny stub Http::fake(), StrayRequestException z Http::preventStrayRequests(), chyba programátora. download() vtedy ponechá súbor, ktorý na ceste už bol, bez zmeny.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.