$method, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => false, CURLOPT_TIMEOUT => 300, ]); $data = curl_exec($curl); $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE); $error = curl_error($curl); curl_close($curl); if ($data === false || $status < 200 || $status >= 300) { throw new RuntimeException("HTTP $status: " . ($error ?: $data)); } return $data; } function api(string $route, array $body): array { global $origin, $key; $data = request($origin . '/api/v1' . $route, 'POST', json_encode($body, JSON_THROW_ON_ERROR), ['Authorization: Bearer ' . $key, 'Content-Type: application/json']); return json_decode($data, true, 512, JSON_THROW_ON_ERROR); } $size = filesize($path); $file = fopen($path, 'rb'); if ($file === false) throw new RuntimeException('Cannot open file'); try { $plan = api('/uploads/init', ['filename' => basename($path), 'sizeBytes' => $size]); fwrite(STDERR, 'Upload ID: ' . $plan['fileId'] . PHP_EOL); if ($plan['partSize'] < 1 || $plan['partSize'] > 64 * 1024 * 1024) throw new RuntimeException('Unexpected part size'); $parts = []; for ($number = 1; $number <= $plan['partCount']; $number++) { $length = min($plan['partSize'], $size - ($number - 1) * $plan['partSize']); $bytes = stream_get_contents($file, $length); if ($bytes === false || strlen($bytes) !== $length) throw new RuntimeException('File changed during upload'); $address = $plan['single'] ? $plan['uploadUrl'] : api('/uploads/parts', ['fileId' => $plan['fileId'], 'from' => $number, 'count' => 1])['parts'][0]['url']; if (!str_starts_with($address, '/api/v1/uploads/')) throw new RuntimeException('Unexpected upload URL'); $data = request($origin . $address, 'PUT', $bytes, ['Authorization: Bearer ' . $key, 'Content-Type: application/octet-stream']); if (!$plan['single']) { $etag = json_decode($data, true, 512, JSON_THROW_ON_ERROR)['etag'] ?? ''; if (!$etag) throw new RuntimeException('Missing part ETag'); $parts[] = ['partNumber' => $number, 'etag' => trim($etag, '"')]; } } $result = api('/uploads/complete', ['fileId' => $plan['fileId'], 'parts' => $parts]); echo ($result['shareUrl'] ?? json_encode($result, JSON_THROW_ON_ERROR)) . PHP_EOL; } finally { fclose($file); }