PHP SDK für Dateikonvertierung#
enconvert/enconvert-php ist der offizielle PHP-Client für die EnConvert API. Installiere ihn mit Composer, gib ihm einen API-Key, und du bekommst zwei Dinge: zwölf Konvertierungsmethoden, die URLs, Bilder und Dokumente in PDFs, PNGs, Markdown und Datenformate verwandeln, sowie einen $client->v2-Namensraum, der das lebende Web in agentenfertiges Markdown, Screenshots und strukturiertes JSON liest. Das SDK zielt auf PHP 8.1+, basiert auf Guzzle 7, nutzt durchgehend camelCase-Options-Arrays und gibt readonly typisierte Ergebnisobjekte statt loser Arrays zurück. Lange Konvertierungen, die ein HTTP-Timeout überdauern, werden per Job-Polling automatisch aufgefangen.
enconvert/enconvert-php · Quelle: conversionapi/php-sdk · PHP: 8.1+ · Benötigt: guzzlehttp/guzzle ^7.8
Installation#
composer require enconvert/enconvert-php
Das Paket lädt automatisch unter dem PSR-4-Namensraum Enconvert\ und bringt kein CLI, keine Konfigurationsdatei und keinen Service Provider mit. Es funktioniert unverändert in reinem PHP, Laravel, Symfony, WordPress und jedem PSR-4-Projekt.
Schnellstart#
<?php
require __DIR__ . '/vendor/autoload.php';
use Enconvert\Client;
$client = new Client(getenv('ENCONVERT_API_KEY'));
// Eine Live-Seite in ein PDF konvertieren und direkt auf die Festplatte streamen.
$result = $client->convertUrlToPdf('https://example.com', [
'saveTo' => 'page.pdf',
]);
echo $result->presignedUrl, ' ', $result->fileSize, ' bytes', PHP_EOL;
// Das Lesen einer Seite für einen Agenten nutzt denselben Client und denselben Key.
$op = $client->v2->perceive('https://example.com', ['outputs' => ['markdown', 'structured']]);
echo $op->renderQuality, PHP_EOL; // 0.0 bis 1.0, z. B. 0.93
echo $op->outputs['markdown']->url, PHP_EOL; // signierte Download-URL
Das SDK ist ausschließlich serverseitig. Ein privater Key (sk_live_...) darf niemals in einen Browser oder eine Mobile-App gelangen.
Was der Client bereitstellt#
| Oberfläche | Wie du sie erreichst | Was sie tut |
|---|---|---|
| Datei- und URL-Konvertierung | $client->convert*() |
Zwölf Methoden über POST /v1/convert/*, plus Job- und Batch-Polling. |
| Web-Intelligence (V2) | $client->v2 (oder $client->v2()) |
Dreiundzwanzig Methoden über /v2/*: perceive, discover, lookup, distill, ingest, watch. |
| Format-Introspektion | Enconvert\Formats |
Die 43 implementierten {input}-to-{output}-Paare, MIME-Auflösung und Ausgabelisten pro Eingabe. |
| Fehler | Enconvert\Exception\* |
Basisklasse EnconvertException plus ApiException, AuthenticationException, QuotaException, RateLimitException. |
| Ergebnisse | Enconvert\Model\* |
Readonly Value Objects mit camelCase-Eigenschaften. |
$client->v2 ist eine öffentliche readonly-Eigenschaft. $client->v2() ist ein identischer Zugriff für alle, die Methodensyntax bevorzugen. Jeder V2-Endpunkt verlangt einen privaten API-Key; öffentliche Keys werden abgelehnt.
Datei-Konvertierung#
Jede Einzeldatei-Methode gibt ein ConversionResult mit einer vorsignierten Download-URL zurück. Übergibst du saveTo, streamt das SDK die Bytes zusätzlich an diesen lokalen Pfad und legt dabei übergeordnete Verzeichnisse an.
convertUrlToPdf#
Rendere jede erreichbare URL zu einem PDF.
$result = $client->convertUrlToPdf('https://example.com', [
'singlePage' => false,
'pdfOptions' => ['pageSize' => 'A4', 'orientation' => 'landscape'],
'viewportWidth' => 1440,
'saveTo' => 'report.pdf',
]);
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
saveTo |
string |
keiner | Lokaler Pfad, in den das PDF gestreamt wird. Übergeordnete Verzeichnisse werden angelegt. |
singlePage |
bool |
true |
true erzeugt eine einzige fortlaufende Seite. false paginiert anhand von pdfOptions.pageSize. |
pdfOptions |
array |
keiner | Seitengröße, Ausrichtung, Ränder, Skalierung, Graustufen, Kopf- und Fußzeile. Siehe PDF-Optionen. |
viewportWidth, viewportHeight |
int |
1920, 1080 |
Größe des Browser-Viewports in Pixeln. |
loadMedia |
bool |
true |
Vor der Erfassung auf Bilder und Videos warten. |
enableScroll |
bool |
true |
Von oben nach unten scrollen, damit Lazy-Loader auslösen. |
outputFilename |
string |
auto | Überschreibt den generierten Dateinamen. |
auth, cookies, headers |
array |
keiner | Seitenzugriff: Basic Auth ['username' => ..., 'password' => ...], eingeschleuste Cookies, eigene Request-Header. |
auth nicht mit einem Authorization-Header. Die API lehnt diesen Konflikt ab, statt zu raten, welche Zugangsdaten gemeint sind.
convertUrlToScreenshot#
Erfasse ein PNG einer beliebigen URL.
$shot = $client->convertUrlToScreenshot('https://example.com', [
'viewportWidth' => 1440,
'saveTo' => 'shot.png',
]);
Akzeptiert dieselben Optionen für Viewport, Medien, Scrollen, Dateiname und Seitenzugriff wie convertUrlToPdf, ohne singlePage und pdfOptions.
convertUrlToMarkdown#
Extrahiere sauberes GitHub-Flavored Markdown aus einer URL. Navigation, Fußzeilen, Werbung und Skripte werden entfernt, der Haupttext des Artikels bleibt erhalten, und YAML-Frontmatter (Titel, Beschreibung, URL, Links, Bilder) wird vorangestellt.
$md = $client->convertUrlToMarkdown('https://example.com/article', [
'saveTo' => 'article.md',
]);
Gleicher Optionssatz wie bei convertUrlToScreenshot.
convertImage#
Konvertiere zwischen jpeg, png, svg, heic und webp oder rastere ein PDF zu JPEG.
// Von einem Pfad.
$client->convertImage('photo.heic', ['outputFormat' => 'webp', 'saveTo' => 'photo.webp']);
// Aus rohen Bytes. Der Dateiname löst Eingabeformat und MIME-Typ auf.
$client->convertImage(
['data' => file_get_contents('photo.heic'), 'filename' => 'photo.heic'],
['outputFormat' => 'webp', 'saveTo' => 'photo.webp']
);
$client->convertImage('scan.pdf', ['outputFormat' => 'jpeg', 'saveTo' => 'scan.jpeg']); // rastern
Das Eingabeformat ergibt sich aus der Dateiendung: .jpg, .jpeg, .png, .svg, .heic, .webp und .pdf. Das Ausgabeformat ist erforderlich und wird für dich normalisiert, jpg wird also zu jpeg aufgelöst.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
outputFormat |
string |
Ja | Eines von jpeg, png, svg, heic, webp. |
saveTo |
string |
Nein | Lokaler Pfad, in den das Ergebnis gestreamt wird. |
outputFilename |
string |
Nein | Überschreibt den generierten Dateinamen. |
convertDocument#
Konvertiere Dokumente und Datenformate. outputFormat ist standardmäßig pdf.
// docx zu pdf, dann json zu yaml
$client->convertDocument('report.docx', ['saveTo' => 'report.pdf']);
$client->convertDocument('data.json', ['outputFormat' => 'yaml', 'saveTo' => 'data.yaml']);
// markdown zu pdf mit Seiteneinrichtung
$client->convertDocument('README.md', [
'outputFormat' => 'pdf',
'pdfOptions' => ['pageSize' => 'A4', 'margins' => ['top' => 20, 'bottom' => 20]],
'saveTo' => 'readme.pdf',
]);
Erkannte Eingabe-Erweiterungen: .doc, .docx, .xls, .xlsx, .ppt, .pptx, .html, .htm, .odt, .ods, .odp, .ots, .pages, .numbers, .md, .markdown, .csv, .json, .xml, .yaml, .yml, .toml.
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
outputFormat |
string |
"pdf" |
Zielformat. Die Aliasse jpg, yml, htm und md werden aufgelöst. |
saveTo |
string |
keiner | Lokaler Pfad, in den das Ergebnis gestreamt wird. |
outputFilename |
string |
keiner | Überschreibt den generierten Dateinamen. |
pdfOptions |
array |
keiner | Seiteneinrichtung. Wird berücksichtigt, wenn die Ausgabe ein PDF ist. |
EPUB hat kein eigenes Dokumentpaar. Schicke .epub-Dateien durch convertToPdf oder convertToMarkdown.
Unterstützte Konvertierungspaare#
| Eingabe | Ausgaben |
|---|---|
json |
csv, toml, xml, yaml |
xml |
csv, json |
yaml, toml |
json |
csv |
json, xml |
markdown |
html, pdf |
html |
pdf |
doc, excel, ppt, odt, ods, odp, ots, pages, numbers |
pdf |
jpeg, png, svg, heic, webp |
untereinander (alle 20 Paare) |
pdf |
jpeg |
Das SDK prüft das {input}-to-{output}-Paar gegen diese Tabelle und wirft eine EnconvertException, bevor eine Anfrage deinen Prozess verlässt, samt der Liste der gültigen Ausgaben für diese Eingabe in der Meldung. Du kannst dieselbe Tabelle direkt abfragen:
use Enconvert\Formats;
Formats::validOutputsFor('json'); // ["csv", "toml", "xml", "yaml"]
Formats::validOutputsFor('pdf'); // ["jpeg"]
Formats::normalizeOutputFormat('JPG'); // "jpeg"
Formats::mimeFor('deck.pptx'); // der PPTX-MIME-Typ
count(Formats::IMPLEMENTED_CONVERSIONS); // 43
convertToMarkdown#
Erkenne das Format eines Dokuments serverseitig automatisch und erhalte Markdown zurück. Das ist der Baustein für die RAG-Aufnahme von Dateien, die du bereits auf der Festplatte hast.
$client->convertToMarkdown('handbook.docx', ['saveTo' => 'handbook.md']);
Akzeptiert PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT/MD sowie ältere oder ODF-Office-Dateien. Bilder werden nicht unterstützt. Die Optionen sind saveTo und outputFilename; an diesem Endpunkt gibt es keine PDF-Optionen.
convertToPdf#
Erkenne fast jede Eingabe automatisch und erhalte ein PDF zurück.
$client->convertToPdf('slides.pptx', ['saveTo' => 'slides.pdf']);
// Eine PDF-Eingabe wird durchgereicht, das dient also zugleich der Graustufen-Normalisierung.
$client->convertToPdf('scan.pdf', ['pdfOptions' => ['grayscale' => true], 'saveTo' => 'gray.pdf']);
Akzeptiert Office, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, reinen Text, Rasterbilder, SVG, EPUB und ein bestehendes PDF als Durchreichung.
pdfOptions.grayscale wird hier berücksichtigt. Das Format wird serverseitig erkannt, die Seitengeometrie kommt also aus dem Quelldokument. Nimm convertDocument oder convertUrlToPdf, wenn du Seitengröße, Ränder, Ausrichtung, Kopf- oder Fußzeilen brauchst.
convertWebsiteToPdf und convertWebsiteToScreenshot#
Ermittle jede Seite einer Website, konvertiere jede einzelne im Hintergrund und sammle alles in einem einzigen ZIP. Beide arbeiten asynchron und geben ein BatchSubmission statt eines ConversionResult zurück. Sie benötigen einen privaten API-Key mit Crawl-Zugriff.
$batch = $client->convertWebsiteToPdf('https://example.com', [
'crawlMode' => 'sitemap', // "auto" (Standard) | "sitemap" | "full"
'excludePatterns' => ['/blog/tag/'], // nur im Full-Crawl-Modus
'notificationEmail' => '[email protected]',
]);
echo $batch->batchId, ' ', $batch->urlCount, ' ', $batch->discoveryMethod, PHP_EOL;
// Blockiert, bis der Batch "processing" verlässt, dann das ZIP speichern.
$status = $client->waitForBatch($batch->batchId, ['saveTo' => 'site.zip']);
echo $status->completed, ' of ', $status->total, ' pages converted', PHP_EOL;
// Oder frage ihn selbst mit getBatchStatus() ab.
$s = $client->getBatchStatus($batch->batchId);
echo $s->status === 'processing' ? 'still working' : $s->zipDownloadUrl, PHP_EOL;
convertWebsiteToScreenshot nimmt dieselben Optionen ohne singlePage und pdfOptions und erzeugt ein ZIP mit PNGs.
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
crawlMode |
string |
"auto" |
auto, sitemap oder full. |
includePatterns, excludePatterns |
string[] |
keiner | URLs nach Muster behalten oder verwerfen. Ausschlüsse greifen im Full-Crawl-Modus. |
notificationEmail, callbackUrl |
string |
keiner | E-Mail-Adresse und Webhook, die bei Abschluss benachrichtigt werden. |
viewportWidth, viewportHeight, loadMedia, enableScroll |
gemischt | Server-Standard | Render-Optionen pro Seite. Werden nur gesendet, wenn du sie setzt. |
auth, cookies, headers |
array |
keiner | Seitenzugriff für Websites hinter einem Login. |
outputFilename |
string |
keiner | Überschreibt den ZIP-Dateinamen. |
waitForBatch akzeptiert intervalMs (Standard 5000), timeoutMs (Standard 1800000, also 30 Minuten) und saveTo. Es wirft eine ApiException mit Status 504, wenn die Frist verstreicht, während der Batch noch läuft.
getJobStatus#
Frage einen einzelnen asynchronen oder wiederhergestellten Konvertierungsjob ab.
$status = $client->getJobStatus('job_abc123');
if ($status->status === 'success') {
echo $status->presignedUrl, PHP_EOL;
} elseif ($status->status === 'failed') {
echo $status->error, PHP_EOL;
}
Gibt einen JobStatus mit status (processing, success oder failed), presignedUrl, objectKey und error zurück. Du brauchst ihn selten direkt, weil das SDK für dich abfragt. Siehe Timeout-Recovery.
Web-Intelligence (V2)#
Der Namensraum $client->v2 verwandelt lebende Webseiten in agentenfertige Daten: rendern, suchen, extrahieren, aufnehmen und überwachen. Jeder Lesevorgang trägt renderQuality, einen Wert von 0.0 bis 1.0, der ein echtes Rendering von einem gescheiterten unterscheidet. Eine Challenge-Seite, eine Cookie-Wall, ein Login-Bildschirm oder eine leere SPA-Hülle kommt mit niedrigem Wert und gefüllten warnings zurück, sodass ein schlechter Lesevorgang nie unbemerkt in den Kontext eines Agenten gelangt. Der Inhalt wird trotzdem zurückgegeben: Er ist markiert, nicht versteckt. Die Konzepte findest du in der V2-Übersicht.
Perceive#
Rendere eine URL und erzeuge aus diesem einen Rendering alle Ausgaben, die du angefordert hast. Siehe die Perceive-Referenz.
$op = $client->v2->perceive('https://example.com/pricing', [
'outputs' => ['markdown', 'screenshot', 'structured'],
'extract' => ['tables', 'metadata'],
'onlyMainContent' => true,
'waitFor' => '.price',
]);
echo $op->renderQuality, ' ', $op->statusCode, PHP_EOL; // Score, HTTP-Status der Quelle
print_r($op->deductions); // z. B. ["login_wall" => 0.65]
echo $op->outputs['markdown']->url, PHP_EOL; // signierte URL, 15 Minuten
print_r($op->structured);
// Signierte URLs laufen ab. Signiere sie später neu, ohne erneut zu rendern.
$again = $client->v2->getPerceiveOperation($op->operationId);
| Option | Typ | Beschreibung |
|---|---|---|
outputs |
string[] |
Beliebige aus markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
string[] |
Strukturierte Felder, die gezogen werden, zum Beispiel metadata, structured_data, headings, tables, main_content, all. |
schema |
array |
Schema für die LLM-gestützte strukturierte Extraktion. |
onlyMainContent |
bool |
Entfernt das Seitengerüst aus der Markdown-Ausgabe. |
waitFor, waitTimeoutMs |
string, int |
Nach der Navigation auf einen CSS-Selektor oder einen JS-Ausdruck warten. |
jsCode |
string |
JavaScript, das nach der Navigation auf der Seite ausgeführt wird. |
viewport, mobile, blockResources |
array, bool, string[] |
Render-Geometrie und Ressourcentypen, die vor dem Laden abgebrochen werden. |
cacheMode |
string |
enabled, bypass oder refresh. |
headers, cookies, auth |
array |
Seitenzugriff für authentifizierte Seiten. |
respectRobots |
bool |
Lehnt URLs ab, die robots.txt verbietet. |
pdfOptions |
array |
Seiteneinrichtung für die pdf-Ausgabe. |
directDownload |
bool |
Gibt die rohen Artefakt-Bytes zurück. Nur von perceive() akzeptiert. |
proxyUrl, geolocation, actionChain |
gemischt | Vom SDK serialisiert, von der API reserviert. |
Batch-Perceive#
$batch = $client->v2->perceiveBatch(['https://a.com', 'https://b.com'], [
'outputs' => ['markdown'],
'outputMode' => 'zip',
]);
// Kleine Batches werden inline fertig. Größere kommen als queued zurück, frage sie also ab.
if ($batch->status !== 'completed') {
$batch = $client->v2->getPerceiveBatch($batch->jobId);
}
foreach ($batch->items as $item) {
echo $item->url, ' ', $item->renderQuality, PHP_EOL;
}
echo $batch->zip?->url, PHP_EOL;
Bis zu 1000 URLs teilen sich einen Options-Block. outputMode ist manifest (Standard) oder zip. directDownload wird hier nicht akzeptiert.
Ein einzelnes Artefakt streamen#
perceiveDirect() überspringt den JSON-Envelope und reicht dir die Bytes. Es muss genau eine artefakterzeugende Ausgabe angefordert werden, und das SDK erzwingt das vor dem Senden, structured allein wirft also eine Exception.
$direct = $client->v2->perceiveDirect('https://example.com', [
'outputs' => ['pdf'],
]);
file_put_contents($direct->filename ?? 'page.pdf', $direct->content);
echo $direct->renderQuality, ' ', $direct->contentType, PHP_EOL;
echo $direct->operationId, ' cache hit: ', var_export($direct->cacheHit, true), PHP_EOL;
// Ein gespeichertes Artefakt später erneut herunterladen. Lass den Ausgabenamen weg,
// wenn die Operation genau ein Artefakt erzeugt hat.
$saved = $client->v2->downloadPerceiveArtifact($direct->operationId, 'pdf');
PerceiveDirectResult trägt content, contentType, filename, operationId, objectKey, cacheHit, renderQuality, sourceStatusCode, contentHash und warningsCount. Eine ApiException mit Status 410 bedeutet, dass das gespeicherte Artefakt nicht mehr verfügbar ist.
Discover#
Zähle die URLs einer Website ausschließlich über HTTP auf. Kein Browser-Rendering, daher ist es schnell. Siehe die Discover-Referenz.
$found = $client->v2->discover('https://example.com', [
'mode' => 'hybrid', // "sitemap" | "crawl" | "hybrid"
'maxUrls' => 200,
'maxDepth' => 3,
'excludePatterns' => ['/tag/'],
'sameDomainOnly' => true,
]);
echo $found->total, ' urls, truncated: ', var_export($found->truncated, true), PHP_EOL;
print_r($found->sources); // z. B. ["sitemap" => 42, "crawl" => 30]
Die Optionen sind mode, maxUrls, maxDepth, includePatterns, excludePatterns, sameDomainOnly und respectRobots.
Lookup#
Führe eine kategorisierte Websuche aus und rendere die besten Treffer auf Wunsch automatisch. Siehe die Lookup-Referenz.
$search = $client->v2->lookup('best static site generators', [
'category' => 'web', // web | news | images | scholar | patents | maps
'numResults' => 10,
'country' => 'us',
'timeFilter' => 'month',
'perceiveTop' => 3, // die 3 besten Treffer automatisch rendern
]);
foreach ($search->results as $hit) {
echo $hit->position, '. ', $hit->title, ' ', $hit->url, PHP_EOL;
echo ' quality ', $hit->perceive?->renderQuality ?? 'not perceived', PHP_EOL;
}
Die Optionen sind category, country, locale, timeFilter, numResults, page, location, autocorrect und perceiveTop.
Distill#
Schemagesteuerte strukturierte Extraktion über eine URL-Liste oder eine ermittelte Website. Siehe die Distill-Referenz.
$extraction = $client->v2->distill([
'urls' => ['https://example.com/pricing'],
'schema' => ['plans' => 'list of plan names with monthly prices'],
'cssSchema' => [ // optionaler kostenloser CSS-Durchlauf vor der LLM-Stufe
'baseSelector' => '.plan-card',
'fields' => [
['name' => 'name', 'type' => 'text', 'selector' => 'h3'],
['name' => 'price', 'type' => 'text', 'selector' => '.price'],
],
],
]);
print_r($extraction->results[0]->data);
echo $extraction->results[0]->extractionTier, PHP_EOL; // css | llm | mixed | none
echo $extraction->results[0]->fieldsFromCss, '/', $extraction->results[0]->fieldsFromLlm, PHP_EOL;
// Oder ermittle zuerst die URL-Menge.
$client->v2->distill([
'discoverFrom' => ['url' => 'https://example.com', 'mode' => 'sitemap', 'maxPages' => 10],
'schema' => ['title' => 'page title', 'summary' => 'one-line summary'],
]);
schema ist erforderlich, und genau eines von urls oder discoverFrom muss vorhanden sein. Verletzt du eine der beiden Regeln, wirft das SDK vor dem Senden eine EnconvertException. Weitere Optionen sind waitFor, waitTimeoutMs, headers, cookies und respectRobots.
Ingest#
Verwandle eine ganze Website oder einen Stapel hochgeladener Dokumente über eine einzige Pipeline in gechunktes, RAG-fertiges JSONL. Ingest arbeitet immer asynchron. Siehe die Ingest-Referenz.
// Von einer Website.
$job = $client->v2->ingest([
'mode' => 'sitemap', // "urls" (Standard) | "sitemap" | "crawl"
'url' => 'https://docs.example.com',
'maxPages' => 100,
'chunk' => ['maxWords' => 512, 'sentenceOverlap' => 1],
'webhookUrl' => 'https://my.app/hooks/enconvert',
]);
// Oder aus hochgeladenen Dateien: PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT/MD, ältere und ODF-Office.
$fileJob = $client->v2->ingestFiles(['handbook.pdf', 'notes.docx'], [
'chunk' => ['maxWords' => 512, 'sentenceOverlap' => 1],
]);
// Abfragen, bis es fertig ist.
do {
sleep(5);
$status = $client->v2->getIngestJob($job->jobId);
} while (in_array($status->status, ['queued', 'discovering', 'processing'], true));
if ($status->status === 'completed') {
echo $status->totalChunks, ' chunks: ', $status->outputUrl, PHP_EOL; // signiertes JSONL
}
mode ist standardmäßig urls, was ein nicht leeres urls-Array verlangt und url ablehnt. Die Modi sitemap und crawl verlangen eine Start-url und lehnen urls ab. Das SDK erzwingt beide Regeln lokal. Weitere Optionen sind maxPages, maxDepth, sameDomainOnly, includePatterns, excludePatterns, respectRobots, waitFor, waitTimeoutMs, chunk und webhookUrl.
// Job-Verwaltung.
$list = $client->v2->listIngestJobs(['limit' => 20, 'skip' => 0]);
foreach ($list->jobs as $summary) {
echo $summary->jobId, ' ', $summary->status, ' ', $summary->totalChunks, PHP_EOL;
}
$client->v2->cancelIngestJob($job->jobId); // idempotent
// Webhook-Signierung.
$secret = $client->v2->getWebhookSecret();
echo $secret->signatureHeader, ' ', $secret->signatureScheme, PHP_EOL;
$client->v2->rotateWebhookSecret(); // alte Signaturen verifizieren nicht mehr
$client->v2->retryIngestWebhook($job->jobId); // einen Abschluss-Callback erneut zustellen
Watch#
Rendere eine URL in festem Takt erneut und lass dich benachrichtigen, wenn sie sich ändert. Siehe die Watch-Referenz.
$watcher = $client->v2->createWatcher('https://example.com/pricing', [
'frequencyMinutes' => 60, // Untergrenze eine Stunde
'diffMode' => 'auto', // auto | text | structured | tables | metadata
'webhookUrl' => 'https://my.app/hooks/changes',
'notifyEmail' => true,
]);
echo $watcher->watcherId, ' next check ', $watcher->nextCheckAt, PHP_EOL;
$snapshots = $client->v2->getWatcherSnapshots($watcher->watcherId, ['limit' => 10]);
foreach ($snapshots->snapshots as $snap) {
if ($snap->hasChanges) {
echo $snap->checkedAt, ' similarity ', $snap->similarity,
' changes ', $snap->changeCount, PHP_EOL;
}
}
$client->v2->updateWatcher($watcher->watcherId, ['status' => 'paused']);
$client->v2->updateWatcher($watcher->watcherId, ['webhookUrl' => '']); // löscht den Webhook
$client->v2->deleteWatcher($watcher->watcherId); // Soft Delete, idempotent
createWatcher akzeptiert frequencyMinutes, diffMode, trackFields, webhookUrl und notifyEmail. updateWatcher akzeptiert diese fünf plus status und verlangt mindestens ein Feld, sonst wirft es eine EnconvertException. listWatchers akzeptiert skip und limit.
PDF-Optionen#
Werden als pdfOptions-Array an convertUrlToPdf, convertDocument, convertToPdf (nur Graustufen), convertWebsiteToPdf und V2-perceive mit einer pdf-Ausgabe übergeben. Das SDK serialisiert camelCase-Schlüssel in das Wire-Format der API und sendet nur die Schlüssel, die du setzt.
$client->convertUrlToPdf('https://example.com', [
'pdfOptions' => [
'pageSize' => 'A4',
'orientation' => 'landscape',
'margins' => ['top' => 10, 'bottom' => 10, 'left' => 15, 'right' => 15],
'scale' => 0.9,
'header' => ['content' => 'Quarterly Report', 'height' => 15],
'footer' => ['content' => 'Page {{page}} of {{total_pages}}', 'height' => 12],
],
'singlePage' => false,
'saveTo' => 'report.pdf',
]);
| Feld | Typ | Beschreibung |
|---|---|---|
pageSize |
string |
A0 bis A6, B0 bis B5, Letter, Legal, Tabloid, Ledger. Wird ignoriert, wenn sowohl pageWidth als auch pageHeight gesetzt sind. |
pageWidth, pageHeight |
float |
Eigene Seitengröße in Millimetern. Setze beide gemeinsam. |
orientation |
string |
portrait oder landscape. |
margins |
array |
['top' => ..., 'bottom' => ..., 'left' => ..., 'right' => ...] in Millimetern. |
scale |
float |
Render-Skalierung, 0.1 bis 2.0. Nur bei paginierter Ausgabe. |
grayscale |
bool |
Wandelt das PDF nachträglich in Graustufen um. |
header |
array |
['content' => '<html>', 'height' => 15]. Höhe in Millimetern. |
footer |
array |
Gleiche Struktur wie header. |
Inhalte von Kopf- und Fußzeile unterstützen die Vorlagenvariablen {{page}}, {{total_pages}}, {{date}}, {{title}} und {{url}}. Die vollständige Parameter-Referenz steht unter Parameter und Optionen.
Fehlerbehandlung#
Alles, was das SDK wirft, stammt von Enconvert\Exception\EnconvertException ab, ein einziger catch-Block kann also die gesamte Oberfläche abdecken.
use Enconvert\Exception\{
ApiException, AuthenticationException, EnconvertException, QuotaException, RateLimitException
};
try {
$client->convertUrlToPdf('https://example.com', ['saveTo' => 'page.pdf']);
} catch (AuthenticationException $e) {
error_log('Check ENCONVERT_API_KEY: ' . $e->getMessage());
} catch (RateLimitException $e) {
error_log('Too many requests, back off and retry.');
} catch (QuotaException $e) {
error_log($e->getMessage());
} catch (ApiException $e) {
error_log(sprintf('API error [%d]: %s', $e->getStatusCode(), $e->getMessage()));
} catch (EnconvertException $e) {
error_log('Client-side or transport failure: ' . $e->getMessage());
}
| Klasse | Ausgelöst bei | Statuscode |
|---|---|---|
AuthenticationException |
Ungültiger, fehlender oder widerrufener API-Key | Antworten mit 401 und 403 |
QuotaException |
HTTP 402 | 402 |
RateLimitException |
Zu viele Anfragen | 429 |
ApiException |
Jede andere 4xx- oder 5xx-Antwort | der tatsächliche Code |
EnconvertException |
Basisklasse und jeder clientseitige Fehler | keiner |
ApiException::getStatusCode() gibt den numerischen Status zurück; der Meldung ist [code] vorangestellt. Eine 403-Antwort wird auf AuthenticationException abgebildet, deren getStatusCode() 401 meldet: Verzweige also über die Klasse statt über die Zahl, wenn du beide unterscheiden musst.
EnconvertException wird auch ohne Netzwerk-Roundtrip geworfen, sobald das SDK erkennt, dass die Anfrage aussichtslos ist: ein leerer API-Key, ein fehlender Dateipfad, eine unbekannte Dateiendung, ein nicht implementiertes Konvertierungspaar, ein distill-Aufruf ohne Schema oder mit urls und discoverFrom zugleich, ein Widerspruch zwischen ingest-Modus und Payload, eine leere ingestFiles-Liste, ein perceiveDirect-Aufruf, der nicht genau eine Artefakt-Ausgabe benennt, ein updateWatcher-Aufruf ohne Felder sowie jeder Guzzle-Transportfehler (gemeldet als HTTP request failed: ...).
Die vollständige Zuordnung der Meldungen steht in der Fehlercodes-Referenz.
Timeout-Recovery#
Große Dokumentkonvertierungen und langsame Seiten können ein Reverse-Proxy-Timeout überdauern, selbst wenn die Konvertierung auf dem Server letztlich erfolgreich ist. Das SDK fängt das von allein auf:
- Vor jeder Konvertierungsanfrage erzeugt es eine 32 Zeichen lange Hex-Job-ID und sendet sie als
job_idim Body oder im Multipart-Formular. - Kommt diese Anfrage mit 5xx zurück, wirft das SDK keine Exception mehr, sondern beginnt,
GET /v1/convert/status/{job_id}alle 3 Sekunden abzufragen. - Sobald der Job
successmeldet, gibt das SDK das Ergebnis zurück. Meldet erfailed, wirft es eineApiExceptionmit der Fehlermeldung des Servers. - Ein
404beim Abfragen bedeutet "noch nicht erfasst", und das Polling läuft weiter. Die Frist beträgt 5 Minuten, danach wirft esApiException(504, 'Conversion timed out').
Dafür ist kein Code nötig. Zwei bewusste Ausnahmen: Die Website-Batch-Übermittlungen (convertWebsiteToPdf, convertWebsiteToScreenshot) haben keine Job-Zeile, ein 5xx wird dort also sofort gemeldet, und V2-Methoden nutzen überhaupt kein Job-Polling.
Erfolgreiche Antworten, die job_id weglassen, werden mit der vom Client erzeugten ID ergänzt, $result->jobId ist also immer mit getJobStatus() verwendbar.
Konfiguration#
use Enconvert\Client;
$client = new Client(getenv('ENCONVERT_API_KEY'), [
'timeout' => 300, // Sekunden
'base_url' => 'https://api.enconvert.com', // Überschreiben für ein selbst gehostetes Gateway
]);
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
$apiKey (erstes Argument) |
string |
erforderlich | Privater API-Key (sk_live_...). Ein leerer String wirft eine EnconvertException. |
timeout |
int\|float |
300 |
Anfrage-Timeout in Sekunden, der bei Guzzle übliche Wert. Gilt für jede HTTP-Anfrage des Clients. Die Frist für das Job-Polling ist davon getrennt und fest auf 300 Sekunden gesetzt. |
base_url |
string |
https://api.enconvert.com |
API-Host. Abschließende Schrägstriche werden entfernt. |
Beachte, dass der Options-Schlüssel base_url in snake_case steht, während jede andere Request-Option im SDK in camelCase geschrieben wird. Anfragen werden mit einem X-API-Key-Header authentifiziert; saveTo-Downloads gehen direkt an den Speicher und senden bewusst keinen Key, weil die URL bereits signiert ist.
Ergebnisform#
Jede Einzeldatei-Konvertierung gibt ein Enconvert\Model\ConversionResult mit readonly öffentlichen Eigenschaften zurück:
final class ConversionResult
{
public readonly string $presignedUrl; // signierte Download-URL
public readonly string $objectKey; // Objekt-Key im Speicher
public readonly string $filename; // serverseitiger Dateiname
public readonly int|float|null $fileSize; // Bytes
public readonly int|float|null $conversionTimeSeconds;
public readonly ?string $jobId; // die ID für die Timeout-Recovery
}
Vorsignierte URLs laufen nach 15 Minuten ab und können bis dahin mehrfach abgerufen werden. Für dauerhaften Zugriff lade die Bytes herunter (übergib saveTo oder rufe die URL selbst ab) und lege sie in deinem eigenen Bucket ab.
Die übrigen Ergebnistypen folgen demselben Muster: JobStatus, BatchSubmission, BatchStatus mit seinen BatchItem[] und, unter Enconvert\Model\V2, PerceiveResult, PerceiveDirectResult, PerceiveBatchResult, OutputArtifact, DiscoverResult, LookupResult, LookupItem, DistillResult, DistillItem, IngestJob, IngestJobList, IngestJobSummary, Watcher, WatcherList, WatcherSummary, WatcherSnapshot, WatcherSnapshotList, WebhookSecret, WebhookRetryResult und Tokens. Wire-Felder kommen in snake_case an und werden auf camelCase-Eigenschaften abgebildet; von dir gelieferte Payloads wie Schemata, extrahierte Daten, überwachte Felder und Diff-Einträge werden unverändert durchgereicht.
Quelle und Issues#
- Packagist: enconvert/enconvert-php
- GitHub: conversionapi/php-sdk · ein Issue eröffnen
- Lizenz: MIT
- Weitere Clients: alle SDKs · REST-Endpunkte
Häufig gestellte Fragen#
Wie konvertiere ich Dateien in PHP mit Composer?#
Führe composer require enconvert/enconvert-php aus, erzeuge new Enconvert\Client($apiKey) und rufe eine Methode wie convertUrlToPdf, convertImage, convertDocument, convertToPdf oder convertToMarkdown auf. Ergänze bei jeder davon saveTo, und das SDK streamt die konvertierten Bytes für dich an diesen lokalen Pfad und legt dabei übergeordnete Verzeichnisse an.
Wie konvertiere ich DOCX in PHP in ein PDF?#
Rufe $client->convertDocument('report.docx', ['saveTo' => 'report.pdf']) auf. Das Ausgabeformat ist standardmäßig pdf, outputFormat ist also nicht nötig. Das Eingabeformat wird aus der Dateiendung gelesen, und das SDK prüft das Paar doc-to-pdf gegen seine Tabelle mit 43 implementierten Konvertierungen, bevor irgendetwas gesendet wird: Ein nicht unterstütztes Paar scheitert sofort mit einer Meldung, die auflistet, was für diese Eingabe gültig ist.
Wie konvertiere ich eine URL in PHP in ein PDF?#
Rufe $client->convertUrlToPdf('https://example.com', ['saveTo' => 'page.pdf']) auf. Standardmäßig wird die Seite als eine fortlaufende Seite bei einem Viewport von 1920x1080 gerendert, mit aktiviertem Laden von Medien und Scrollen. Setze singlePage auf false und übergib pdfOptions, wenn du echte Paginierung mit Seitengröße, Rändern, Kopf- und Fußzeilen willst.
Wie scrape ich in PHP eine Webseite und bekomme sauberes Markdown?#
Nutze den V2-Namensraum: $client->v2->perceive($url, ['outputs' => ['markdown', 'structured']]). Er rendert die Seite in einem echten Browser, JavaScript-lastige Websites funktionieren also, und liefert eine signierte Markdown-URL plus inline strukturierte Daten. Prüfe renderQuality im Ergebnis, bevor du dem Inhalt vertraust; ein niedriger Wert mit gefüllten deductions bedeutet, dass das Rendering auf eine Anti-Bot-Seite, eine Login-Wall oder eine leere Hülle gestoßen ist. Für einen leichteren Einmalweg ohne V2-Funktionen funktioniert auch convertUrlToMarkdown.
Wie konvertiere ich HEIC in PHP in WebP?#
Rufe $client->convertImage('photo.heic', ['outputFormat' => 'webp', 'saveTo' => 'photo.webp']) auf. Jedes Paar aus jpeg, png, svg, heic und webp wird unterstützt, dazu die Rasterung von pdf zu jpeg. Du kannst auch rohe Bytes als ['data' => $bytes, 'filename' => 'photo.heic'] übergeben, wobei der Dateiname Eingabeformat und MIME-Typ auflöst.
Funktioniert das EnConvert PHP SDK mit Laravel oder Symfony?#
Ja. Das Paket ist eine schlichte PSR-4-Bibliothek mit Guzzle 7 als einziger Abhängigkeit und ohne Framework-Bindung, es passt also unverändert in Laravel, Symfony, WordPress oder ein einfaches Skript. Binde Enconvert\Client mit dem Key aus deiner Umgebungskonfiguration in deinen Container und injiziere ihn, wo du ihn brauchst.
Was passiert, wenn eine Konvertierung länger dauert als das HTTP-Timeout?#
Das SDK fängt das von allein auf. Es sendet mit jeder Konvertierungsanfrage eine vom Client erzeugte job_id, und wenn die Anfrage 5xx zurückgibt, fragt es still GET /v1/convert/status/{job_id} alle 3 Sekunden für bis zu 5 Minuten ab und gibt das Ergebnis zurück, sobald der Job success erfasst. Nach Ablauf der Frist wirft es ApiException(504, 'Conversion timed out'). Website-Batch-Übermittlungen nehmen daran nicht teil, da sie keine Job-Zeile haben.
Wie lange ist die vorsignierte Download-URL gültig?#
Vorsignierte Download-URLs laufen nach 15 Minuten ab und können bis dahin mehrfach verwendet werden. V2-Artefakt-URLs tragen aus demselben Grund ein expiresIn von 900 Sekunden, und getPerceiveOperation($operationId) signiert sie aus den gespeicherten Objekt-Keys neu, ohne die Seite erneut zu rendern. Für alles Dauerhafte lade die Bytes herunter und behalte sie in deinem eigenen Speicher.
Welche PHP-Version verlangt das SDK?#
PHP 8.1 oder neuer. Das SDK nutzt durchgehend readonly-Eigenschaften, enum-artige Union-Typen, benannte Argumente und match-Ausdrücke, 8.0 und älter werden also nicht unterstützt. Seine einzige Laufzeitabhängigkeit ist guzzlehttp/guzzle ^7.8.