程式化編碼 — 限 Ultra 訂戶使用。請於 帳戶 → API 金鑰建立金鑰,將金鑰直接放在以下端點 URL 中即可。
| 方案 | 單檔上限 | API 存取 | 需要 multipart 嗎? |
|---|---|---|---|
| Free | 5 KB | — | — |
| Pro | 100 MB | — | 否(單次 PUT 即可) |
| Ultra | 300 MB | 有 | 檔案 >100 MB 必須走 multipart |
Cloudflare 邊緣對單一 request body 上限為 100 MB。超過此值的檔案, 必須切成 50 MB 的 part 並走下方的 multipart 端點。
POST https://webhook.binaryphp.com/upload/<api_key>
X-BPHP-Filename: plugin.php # 必填,副檔名 .php 或 .zip
X-BPHP-Domain: app.example.com,*.example.com
X-BPHP-Mac: aa:bb:cc:dd:ee:ff # 選填
X-BPHP-Expire: 2027-12-31 # 選填
X-BPHP-Webhook: https://you.example.com/wh # 選填,異步通知用
<檔案二進位內容作為 request body>
→ 200 {
"job_id": "...",
"download_url": "https://...presigned R2 URL...",
"expires_at": "2026-05-09T...",
"size": 12345,
"license": { "domains": [...], ... }
}
curl 一行版:
curl -X POST https://webhook.binaryphp.com/upload/$API_KEY \
-H "X-BPHP-Filename: plugin.php" \
-H "X-BPHP-Domain: app.example.com" \
--data-binary @plugin.php
三步驟:init → 個別 PUT 每個 part → complete。
POST https://webhook.binaryphp.com/upload/<api_key>/init
X-BPHP-Filename: bigplugin.zip
X-BPHP-Total-Size: 200000000
→ 200 {
"job_id": "...",
"upload_id": "...", # R2 multipart 不透明 id
"r2_key": "uploads/<job_id>.zip",
"part_size": 52428800, # 建議 50 MB 一片
"part_count": 4,
"max_part_size": 104857600, # 100 MB 硬限
"parts": [
{ "part_no": 1, "upload_url": "https://...presigned PUT..." },
{ "part_no": 2, "upload_url": "..." },
{ "part_no": 3, "upload_url": "..." },
{ "part_no": 4, "upload_url": "..." }
]
}
upload_url 做 PUT這些預簽名 URL 直接打 R2,不耗 Worker 頻寬。
每個 PUT 回應的 ETag header 必須收集起來,complete
階段一併送上:
PUT <upload_url>
<從檔案 (part_no-1)*part_size 偏移處讀取 part_size 個 bytes>
← 200 OK
ETag: "abc123def456..."
每個 part 必須 ≥5 MB(最後一片可小於),且 ≤100 MB。
POST https://webhook.binaryphp.com/upload/<api_key>/complete
Content-Type: application/json
{
"upload_id": "...",
"r2_key": "uploads/<job_id>.zip",
"filename": "bigplugin.zip",
"parts": [
{ "part_no": 1, "etag": "\"abc...\"" },
{ "part_no": 2, "etag": "\"def...\"" },
{ "part_no": 3, "etag": "\"ghi...\"" },
{ "part_no": 4, "etag": "\"jkl...\"" }
],
"domain": "app.example.com",
"mac": "",
"expire": "2027-12-31",
"plugin": "",
"webhook": ""
}
→ 200 { "job_id", "download_url", "expires_at", "size", "license" }
若中途 part 上傳失敗,請呼叫 /upload/<api_key>/abort
並帶 { upload_id, r2_key },避免殘留的 part 留在 R2 計費。
設定 X-BPHP-Webhook(或 complete body 中的 "webhook")
以接收 encode.completed 事件。通知由 Cloudflare 邊緣 IP 送出,
不會洩漏我們主機 IP。Body 以你的 API key 為共享密鑰用 HMAC-SHA256 簽章:
POST <你的 webhook URL>
X-BinaryPHP-Signature: t=1736208000,v1=<hex>
X-BinaryPHP-Event: encode.completed
Content-Type: application/json
{
"event": "encode.completed",
"job_id": "...",
"download_url": "...",
"expires_at": "...",
"size": 12345,
"license": { ... }
}
驗證範例(PHP):
$sig_h = $_SERVER['HTTP_X_BINARYPHP_SIGNATURE'] ?? '';
[$tpart, $vpart] = array_pad(explode(',', $sig_h, 2), 2, '');
$ts = (int) substr($tpart, 2);
$got = substr($vpart, 3);
if (abs(time() - $ts) > 300) http_response_code(401);
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', "$ts.$body", $YOUR_API_KEY);
if (!hash_equals($expected, $got)) http_response_code(401);
ext-curl。自動依檔案大小選擇單次或 multipart 流程;
中途失敗會 abort R2 multipart,避免殘片產生計費。
API_KEY=bphp_live_xxx php upload.php big.zip --domain=app.example.com
requests。同樣自動判斷 + abort 清理。
| 狀態碼 | 意思 | 處理方式 |
|---|---|---|
| 401 | 金鑰錯誤或已撤銷 | 到「帳戶 → API 金鑰」重新建立 |
| 402 | 方案不支援此操作(如 Free 上傳 zip) | 升級方案 |
| 413 | 檔案 / Content-Length 超過方案上限 | 改走 multipart,或升 Pro→Ultra(300 MB) |
| 400 | 缺欄位或格式錯(filename、parts 等) | 查看回應 body,會指出缺哪個欄位 |
| 502 | R2 multipart 操作失敗 | 重試 init;R2 偶有 <1% 機率失敗 |