• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • curl_setopt_array()

    (PHP 5 >= 5.1.3, PHP 7)

    为 cURL 传输会话批量设置选项

    说明

    curl_setopt_array(resource $ch,array $options): bool

    为 cURL 传输会话批量设置选项。这个函数对于需要设置大量的 cURL 选项是非常有用的,不需要重复地调用curl_setopt()。

    参数

    $ch

    由curl_init()返回的 cURL 句柄。

    $options

    一个array用来确定将被设置的选项及其值。数组的键值必须是一个有效的curl_setopt()常量或者是它们对等的整数值。

    返回值

    如果全部的选项都被成功设置,返回TRUE。如果一个选项不能被成功设置,马上返回FALSE,忽略其后的任何在$options数组中的选项。

    范例

    初始化新的 cURL 会话并抓取 web 页面

    <?php
    // 创建一个新 cURL 资源
    $ch = curl_init();
    // 设置 URL 和相应的选项
    $options = array(CURLOPT_URL => 'http://www.example.com/',
                     CURLOPT_HEADER => false
                    );
    curl_setopt_array($ch, $options);
    // 抓取 URL 并把它传递给浏览器
    curl_exec($ch);
    // 关闭 cURL 资源,并且释放系统资源
    curl_close($ch);
    ?>
    

    早于PHP 5.1.3这个函数可以做如下模拟:

    我们对curl_setopt_array()的等价实现

    <?php
    if (!function_exists('curl_setopt_array')) {
       function curl_setopt_array(&$ch, $curl_options)
       {
           foreach ($curl_options as $option => $value) {
               if (!curl_setopt($ch, $option, $value)) {
                   return false;
               } 
           }
           return true;
       }
    }
    ?>
    

    注释

    Note:

    就curl_setopt()来说,传递一个数组到CURLOPT_POST将会把数据以multipart/form-data的方式编码,然而传递一个URL-encoded字符串将会以application/x-www-form-urlencoded的方式对数据进行编码。

    参见

    In case that you need to read SSL page content from https with curl, this function can help you:
    <?php
    function get_web_page( $url,$curl_data )
    {
      $options = array(
        CURLOPT_RETURNTRANSFER => true,     // return web page
        CURLOPT_HEADER     => false,    // don't return headers
        CURLOPT_FOLLOWLOCATION => true,     // follow redirects
        CURLOPT_ENCODING    => "",      // handle all encodings
        CURLOPT_USERAGENT   => "spider",   // who am i
        CURLOPT_AUTOREFERER  => true,     // set referer on redirect
        CURLOPT_CONNECTTIMEOUT => 120,     // timeout on connect
        CURLOPT_TIMEOUT    => 120,     // timeout on response
        CURLOPT_MAXREDIRS   => 10,      // stop after 10 redirects
        CURLOPT_POST      => 1,      // i am sending post data
          CURLOPT_POSTFIELDS   => $curl_data,  // this are my post vars
        CURLOPT_SSL_VERIFYHOST => 0,      // don't verify ssl
        CURLOPT_SSL_VERIFYPEER => false,    //
        CURLOPT_VERBOSE    => 1        //
      );
      $ch   = curl_init($url);
      curl_setopt_array($ch,$options);
      $content = curl_exec($ch);
      $err   = curl_errno($ch);
      $errmsg = curl_error($ch) ;
      $header = curl_getinfo($ch);
      curl_close($ch);
     // $header['errno']  = $err;
     // $header['errmsg'] = $errmsg;
     // $header['content'] = $content;
      return $header;
    }
    $curl_data = "var1=60&var2=test";
    $url = "https://www.example.com";
    $response = get_web_page($url,$curl_data);
    print '<pre>';
    print_r($response);
    ?>
    
    If you are writing a mini API for your library, and if you are doing merging of options, remember to use the union operator (+) !
    So something like this will definitely fail. This is because array_merge effectively resets all the keys in the array into running numbers:
    <?php
    function post($url, $options = array) {
      $ch = curl_init();
      curl_setopt_array($ch, array_merge(array(
        CURLOPT_HEADER => 1,
        CURLOPT_RETURNTRANSFER => 1,
        .....
       )));
    ?>
    Rather, this is the correct way of doing it:
    <?php
    function post($url, $options = array) {
      $ch = curl_init();
      curl_setopt_array($ch, array(
        CURLOPT_HEADER => 1,
        CURLOPT_RETURNTRANSFER => 1,
        .....
       ) + (array) $options);
    ?>
    
    Once upon a time I've got an error like "Problem with the SSL CA cert (path? access rights?)". Since what I was doing was pretty much an administrative task with no actual security issues involved, I decided to disallow certificate validation and this is where the most interesting stuff began.
    First I did it like this and it worked:
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    Next I thought, "But hey, I don't want any hardcoded stuff here. Let's use it in a configurable way!". And so I did something like this:
    // in configuration
    $CURL_OPTIONS = array(CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_SSL_VERIFYHOST => 0);
    ...........
    // in place of two direct calls from earlier
          curl_setopt_array($ch, $CURL_OPTIONS);
    And I was so happy, there was no error anymore... and do you think I was happy for a long time? If so, then you're wrong. It stopped giving an error, while it didn't start to work!
    I checked the actual data but they were allright. Then I thought: "Is it the curl_setopt_array() problem? Let's make it a cycle." The way it is mentioned in this help, actually.
          foreach ($CURL_OPTIONS as $name => $value)
          {
            curl_setopt($ch, $name, $value);
          }
    And... it did not work the same way as with the curl_setopt_array() call. And the data were still allright...
    So, if by chance you can't set CURL options with the curl_setopt_array() call, then now you know what to do and you know it is definitely not you who is to blame.
    P.S.
    By the way, the configuration used was:
    Linux i-ween.com 3.2.0-4-amd64 #1 SMP Debian 3.2.73-2+deb7u3 x86_64
    PHP Version 5.5.17
    Starting in PHP 5.2.0, CURLOPT_FOLLOWLOCATION can't be set via curl_setopt_array() (or curl_setopt()) when either safe_mode is enabled or open_basedir is set. In these cases, the order of CURLOPT_* settings in the array can be important.
    This function does not mix with `curl_file_create` (`CURLFile` object) and `CURLOPT_POSTFIELDS`. Took me forever to figure out, but essentially I was getting an "Invalid filename" PHP warning and the files weren't being sent. I was able to correct the issue in a matter like so:
    curl_setopt_array($curl, $curlOpts);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
    I removed the `$postFields` value from `$curlOpts` and set it separately using `curl_setopt`.
    You might be tempted to use array_merge with arrays where CURLOPT constants are the keys, but beware.
    <?php
    array_merge([], [CURLOPT_FOO => "foo"], [CURLOPT_BAR => "bar"]);
    ?>
    Since these constants are numeric, array_merge will happily reindex:
    <?php
    [0 => "foo", 1 => "bar"];
    ?>
    
    You can use CURLOPT_HEADERFUNCTION with a callback inside an object. This makes is it easy to capture the headers for later use. For example:
    <?php
    class Test
    {
      public $headers;
      //...
      public function exec($opts)
      {
        $this->headers = array();
        $opts[CURLOPT_HEADERFUNCTION] = array($this, '_setHeader');
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        return curl_exec($ch);
      }
      private function _setHeader($ch, $header)
      {
        $this->headers[] = $header;
        return strlen($header);
      }
      
    }
    $test = new Test();
    $opts = array(
      //... your curl opts here
    );
    $data = $test->exec($opts);
    print_r($test->headers);
    ?>
    ...something like that
    (This works in php v. 5.1.4)
    There is no CURLOPT_MAXFILESIZE in the PHP module but it's function only works with Content-Length headers anyway. There are two ways of checking download sizes, one is after the download is complete using filesize(), the other is as the download is running allowing you to terminate before wasting time and disk space.
    <?php
    $GLOBALS['file_size'] = 0;
    $GLOBALS['max_file_size'] = 1024 * 1024;
    function on_curl_header($ch, $header)
    {
      $trimmed = rtrim($header);  
      if (preg_match('/^Content-Length: (\d+)$/', $trimmed, $matches))
      {
        $file_size = $matches[1];
        if ($file_size > $GLOBALS['max_file_size']) {
          // handle error here.
        }
      }
      return strlen($header);
    }
    function on_curl_write($ch, $data)
    {
      $bytes = strlen($data);
      $GLOBALS['file_size'] += $bytes;
      if ($GLOBALS['file_size'] > $GLOBALS['max_file_size']) {
        // handle error here.
      }
      return $bytes;
    }
    $ch = curl_init();
    $options = array(CURLOPT_URL    => 'http://www.php.net/',
         CURLOPT_HEADER    => false,
         CURLOPT_HEADERFUNCTION  => 'on_curl_header',
         CURLOPT_WRITEFUNCTION  => 'on_curl_write');
    curl_setopt_array($ch, $options);
    curl_exec($ch);
    // ...
    ?>
    
    it should be noted that when using CURLOPT_POSTFIELDS in a loop, CURLOPT_POSTFIELDS appends to the sting. You can use unset() if you don't want this sort of behavior.
    <?php
    //this will append postfields
    while(true) {
      $options = array(CURLOPT_POSTFIELDS => 'foo=bar&foo2=bar');
      $ch = curl_init("http://www.example.com");
      curl_setopt_array($ch, $options);
      curl_exec($ch);
      curl_close($ch);
    }
    //this will NOT append postfields
    while(true) {
      $options = array(CURLOPT_POSTFIELDS => 'foo=bar&foo2=bar');
      $ch = curl_init("http://www.example.com");
      curl_setopt_array($ch, $options);
      curl_exec($ch);
      curl_close($ch);
      unset($options[CURLOPT_POSTFIELDS]);
    }
    ?>
    

    上篇:curl_reset()

    下篇:curl_setopt()