7

Currently I have a script like the following:

<?php
$filename = "http://someurl.com/file.ext";
header('Content-Type: application/octet-stream');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$filename);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 500);
$data=curl_exec($ch);
curl_close($ch);
echo $data;
?>

The problem is that the server just send the response after download the whole file. I want to make it work like a "stream", sending chunks of data as response while the file is downloaded.

Is that possible to achieve with PHP and cURL?

2
  • This might be what you're looking for. Commented Jul 17, 2016 at 2:34
  • I never used composer before and I am in shared hosting, but I will search more about it. Commented Jul 17, 2016 at 3:01

2 Answers 2

13

It's possible. You can use the curl option CURLOPT_WRITEFUNCTION to specify a callback where you'll receive chunks of data so you can send them directly to the client as curl downloads the file.

<?php

$filename = "http://someurl.com/file.ext";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$filename);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 500);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) {
    echo $data;
    return strlen($data);
});
curl_exec($ch);
curl_close($ch);
Sign up to request clarification or add additional context in comments.

9 Comments

Tested it with a 5 mb file. Instead of just gradually send the chuncks I believe that it send the data already transfered from begin many times or it is in some way corrupted. This requires a specific php version?
The writefunction should never receive the same data twice. The minimum PHP version is 5.3 to allow the anonymous function to be supplied to CURLOPT_WRITEFUNCTION. Otherwise no requirement. I tried it again with various files from 5 MB to 480 MB and it started downloading on my computer nearly immediately and the files checksums matched up and opened fine.
I finally found the problem, was caused by cloudflare... The code works as expected. Thank you.
Is it possible to redirect the original content-length to the php proxy and pass it to header-function?
@SuperNova There is no guarantee a length is sent. If they send a content-length header, it's easy to grab that using CURLOPT_HEADERFUNCTION and send it before any data is sent. You may also be able to borrow some logic from this other answer of mine which shows how to get the content length of a remote resource.
|
1

Curl will by default output the response directly, unless you specify CURLOPT_RETURNTRANSFER.

Your code will work just by removing CURLOPT_RETURNTRANSFER and the last echo:

<?php
$filename = "http://someurl.com/file.ext";
header('Content-Type: application/octet-stream');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$filename);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 500);
$data=curl_exec($ch);
curl_close($ch);
?>

1 Comment

CURLOPT_RETURNTRANSFER is 1 of several options that stops that default behavior. others include: CURLOPT_NOBODY and CURLOPT_FILE, and CURLOPT_WRITEFUNCTION

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.