Mihir
Mihir

Reputation: 1176

Help me understand CURLOPT_READFUNCTION

I want to understand CURLOPT_READFUNCTION properly.

I am looking at Rackspace coudfiles php code (REST API).

It has following line.

curl_setopt($ch, CURLOPT_READFUNCTION, array(&$this, '_read_cb'));

Looking at defination of this function:

private function _read_cb($ch, $fd, $length)
{
    $data = fread($fd, $length);
    $len = strlen($data);
    if (isset($this->_user_write_progress_callback_func)) {
        call_user_func($this->_user_write_progress_callback_func, $len);
    }
    return $data;
}

Can you help me understand what values is passed to $fd and $length?

I want to specify $length value specifically, to send file in chunks.

Thanks in advance.

Upvotes: 6

Views: 10675

Answers (2)

Artefacto
Artefacto

Reputation: 97835

The manual appears to be wrong here:

CURLOPT_READFUNCTION The name of a callback function where the callback function takes two parameters. The first is the cURL resource, and the second is a string with the data to be read. The data must be read by using this callback function. Return the number of bytes read. Return 0 to signal EOF.

It actually takes three parameters (see the source code):

  • The first is the curl handle.
  • The second is the PHP stream that set through the option CURLOPT_INFILE.
  • The third is the amount of data that should be read from the PHP stream and passed to the curl library so it can send it to the HTTP server.

EDIT: Fixed in this commit.

Upvotes: 5

Poet
Poet

Reputation: 91

I know this is a bit of a necro - but other people might want to know how this works.

Here's how a typical curl file put block would look:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ret['Location']);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_READFUNCTION, 'curlPutThrottle');
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, $size);

$ret = curl_exec($ch);

and the read function would look something like this (this one throttles to user-defined $goal speed and gives a CLI display feedback)

function curlPutThrottle($ch, $fh, $length = false)
{
    global $size;
    global $current;
    global $throttle;
    global $start;

    /** Set your max upload speed - here 30mB / minute **/
    $goal = (300*1024*1024)/(60*10);

    if (!$length)
    {
        $length = 1024 * 1024;
    }

    if (!is_resource($fh))
    {
        return 0;
    }

    $current += $length;

    if ($current > $throttle) /** Every meg uploaded we update the display and throttle a bit to reach target speed **/
    {
        $pct = round($current/$size*100);
        $disp =  "Uploading (".$pct."%)  -  ".number_format($current, 0).'/'.number_format($size, 0);
        echo "\r     ".$disp.str_repeat(" ", strlen($disp));
        $throttle += 1024*1024;

        $elapsed = time() - $start;
        $expectedUpload = $goal * $elapsed;

        if ($current > $expectedUpload)
        {
            $sleep = ($current - $expectedUpload) / $goal;
            $sleep = round($sleep);

            for ($i = 1; $i <= $sleep; $i++)
            {
                echo "\r Throttling for ".($sleep - $i + 1)." Seconds   - ".$disp;
                sleep(1);
            }
            echo "\r     ".$disp.str_repeat(" ", strlen($disp));
        }
    }

    if ($current > $size)
    {
        echo "\n";
    }

    return fread($fh, $length);
}

Where:

  • $ch is the cURL resource that calls the ReadFunction
  • $fh is the file handle from CURLOPT_INFILE
  • $length is the amount of data it expects to get back.

It returns data from the file of $length length or '' if EOF.

Upvotes: 7

Related Questions