Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help me understand CURLOPT_READFUNCTION

Tags:

php

curl

libcurl

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.

like image 324
Mihir Avatar asked Apr 11 '11 09:04

Mihir


2 Answers

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.

like image 145
Poet Avatar answered Oct 25 '22 10:10

Poet


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.

like image 5
Artefacto Avatar answered Oct 25 '22 11:10

Artefacto