Ir para o conteúdo
Documentação

Guias PHP

Integração com PHP

Envie um arquivo ou lote à automação do painel e receba os resultados no seu servidor.

PHP 8.1+ · extensão cURL

Você vai precisar de uma automação publicada e uma chave com execute e read.

Nesta página

Configure os dados do painel

Copie a chave autorizada, o ID e a versão publicada da automação. Configure as quatro variáveis no ambiente do servidor.

Ambiente do servidor
# PHP 8.1+ com a extensão cURLDUCKFILE_API_URL=https://duckfile.com/api/v1/externalDUCKFILE_API_KEY=SUA_CHAVE_NO_SERVIDORDUCKFILE_AUTOMATION_ID=UUID_DA_AUTOMACAODUCKFILE_AUTOMATION_VERSION=1

Use HTTPS com certificado válido e mantenha a chave somente no backend.

Envie e receba os arquivos

Baixe o arquivo de integração, incorpore ao seu projeto e chame a função. Ela envia, acompanha e recebe cada resultado individualmente. Aceita um caminho ou uma lista de caminhos.

PHP
<?phprequire __DIR__ . '/duckfile.php'; $resultado = \DuckfileExample\executarAutomacao(__DIR__ . '/imagem.png');print_r($resultado['arquivos']);

Guarde os arquivos recebidos no seu próprio sistema. A execução não salva nada na biblioteca da conta.

Use os resultados no seu negócio

A função retorna o ID, o estado e os caminhos locais em arquivos. Em resultado parcial, preserve os itens recebidos e trate as falhas separadamente. A função só termina após baixar os resultados disponíveis.

Retorno ilustrativo
{"id":"UUID_DA_EXECUCAO","status":"COMPLETED","arquivos":[{"id":"UUID_DO_ARQUIVO","path":"resultado-UUID.webp","bytes":12345}],"falhas":[]}

Código da integração

Fonte de exemplo, sem SDK oficial. Você pode incorporar e adaptar a implementação, incluindo persistir a chave de idempotência e o ID da execução para recuperar falhas de rede. Nenhuma etapa da automação é definida nesse código.

duckfile.php
<?phpnamespace DuckfileExample; // Exemplo para incorporar ao seu servidor; não é um SDK oficial.function executarAutomacao(string|array $entrada, ?string $idempotencyKey = null, string $outputDir = '.'): array {    $base = rtrim((string) getenv('DUCKFILE_API_URL'), '/');    $url = parse_url($base);    if (!$url || ($url['scheme'] ?? '') !== 'https' || empty($url['host']) || isset($url['user']) || isset($url['pass']) || isset($url['query']) || isset($url['fragment']) || !str_ends_with($url['path'] ?? '', '/api/v1/external')) {        throw new \RuntimeException('Configure a base HTTPS da API.');    }    $key = (string) getenv('DUCKFILE_API_KEY');    $automation = (string) getenv('DUCKFILE_AUTOMATION_ID');    $version = filter_var(getenv('DUCKFILE_AUTOMATION_VERSION'), FILTER_VALIDATE_INT);    $uuid = '/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/i';    if (!$key || strpbrk($key, "\r\n") !== false || !preg_match($uuid, $automation) || !$version || $version < 1) throw new \RuntimeException('Configure chave, ID e versão publicados no painel.');    $paths = is_array($entrada) ? $entrada : [$entrada];    if (!$paths || count($paths) > 100) throw new \RuntimeException('Informe um arquivo ou lote.');    $types = ['png'=>'image/png','jpg'=>'image/jpeg','jpeg'=>'image/jpeg','webp'=>'image/webp','avif'=>'image/avif'];    $fields = ['version'=>(string) $version];    $total = 0;    foreach ($paths as $index=>$path) {        $mime = $types[strtolower(pathinfo($path, PATHINFO_EXTENSION))] ?? null;        $size = filesize($path); $total += $size;        if (!$mime || !$size || $size > 25000000 || $total > 79000000) throw new \RuntimeException('Use imagens de até 25 MB e respeite 80 MB com o formulário.');        $fields['files['.$index.']'] = new \CURLFile($path, $mime, basename($path));    }    $requestId = $idempotencyKey ?? bin2hex(random_bytes(16));    $request = function(string $path, ?array $form = null, $output = null, int $expected = 0) use ($base, $key, $requestId) {        $curl = curl_init($base.$path);        $headers = ['Authorization: Bearer '.$key];        if ($form !== null) $headers[] = 'Idempotency-Key: '.$requestId;        $options = [CURLOPT_HTTPHEADER=>$headers, CURLOPT_RETURNTRANSFER=>true,            CURLOPT_CONNECTTIMEOUT=>10, CURLOPT_TIMEOUT=>$form !== null ? 150 : 120,            CURLOPT_FOLLOWLOCATION=>false, CURLOPT_PROTOCOLS=>CURLPROTO_HTTPS,            CURLOPT_REDIR_PROTOCOLS=>CURLPROTO_HTTPS, CURLOPT_SSL_VERIFYPEER=>true, CURLOPT_SSL_VERIFYHOST=>2];        if ($ca = ini_get('curl.cainfo')) $options[CURLOPT_CAINFO] = $ca;        if ($form !== null) $options[CURLOPT_POSTFIELDS] = $form;        if ($output !== null) {            $written = 0;            $options[CURLOPT_WRITEFUNCTION] = function($handle, string $chunk) use ($output, $expected, &$written): int {                $written += strlen($chunk);                if ($written > $expected) return 0;                return fwrite($output, $chunk);            };        }        curl_setopt_array($curl, $options);        $body = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE); $failure = curl_error($curl);        unset($curl);        if ($body === false || $status < 200 || $status >= 300) throw new \RuntimeException('API: HTTP '.$status.($failure ? ' · '.$failure : '').'. Idempotency-Key para repetir o envio: '.$requestId);        return $output === null ? json_decode($body, true, 512, JSON_THROW_ON_ERROR)['data'] : null;    };    $run = $request('/automations/'.$automation.'/runs', $fields);    if (!preg_match($uuid, $run['id'])) throw new \RuntimeException('ID de execução inválido.');    $runId = $run['id']; $deadline = time() + 35*60;    while (!in_array($run['status'], ['COMPLETED','PARTIAL','FAILED','CANCELLED','EXPIRED'], true)) {        if (time() >= $deadline) throw new \RuntimeException('Acompanhe a execução '.$runId.' antes de reenviar.');        sleep(2); $run = $request('/runs/'.$runId);    }    if (!is_dir($outputDir) && !mkdir($outputDir, 0700, true)) throw new \RuntimeException('Não foi possível criar a pasta de saída.');    $arquivos = [];    foreach ($run['files'] ?? [] as $file) {        $result = $file['result'] ?? null;        if (!$result) continue;        $path = '/runs/'.$runId.'/files/'.$file['id'];        if (!preg_match($uuid, $file['id']) || $result['path'] !== $path) throw new \RuntimeException('Caminho de resultado inválido.');        $suffix = ['image/png'=>'png','image/jpeg'=>'jpg','image/webp'=>'webp','image/avif'=>'avif'][$result['mimeType']] ?? null;        $expected = filter_var($result['bytes'], FILTER_VALIDATE_INT);        if (!$suffix || !$expected || $expected > 100000000) throw new \RuntimeException('Formato ou tamanho de resultado inválido.');        $target = rtrim($outputDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'resultado-'.$file['id'].'.'.$suffix;        if (file_exists($target)) throw new \RuntimeException('O resultado já existe. Escolha outra pasta de saída.');        $partial = $target.'.part'; $stream = fopen($partial, 'xb');        if ($stream === false) throw new \RuntimeException('Não foi possível salvar o resultado.');        try {            $request($path, null, $stream, $expected);            if (fstat($stream)['size'] !== $expected) throw new \RuntimeException('Arquivo recebido incompleto.');            fclose($stream); $stream = null;            if (!link($partial, $target)) throw new \RuntimeException('Não foi possível concluir o arquivo sem sobrescrever.');        } finally {            if (is_resource($stream)) fclose($stream);            if (is_file($partial)) unlink($partial);        }        $arquivos[] = ['id'=>$file['id'], 'path'=>$target, 'bytes'=>$expected];    }    if (!$arquivos) throw new \RuntimeException('Nenhum arquivo disponível: '.$run['status']);    return ['id'=>$runId, 'status'=>$run['status'], 'idempotencyKey'=>$requestId, 'arquivos'=>$arquivos,        'falhas'=>array_values(array_filter($run['files'] ?? [], fn($file)=>$file['status'] !== 'COMPLETED' || $file['partial']))];}if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {    echo json_encode(executarAutomacao(array_slice($argv, 1)), JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT).PHP_EOL;}

Trate falhas e reenvios

Não crie outra execução apenas porque a conexão caiu. Preserve a chave de idempotência e os mesmos arquivos. Acompanhe o ID já recebido; mudança de versão, falta de crédito e falha de validação exigem tratamento próprio.