cURL 'Content-length required' error... 3 days of searching, no luck

39,170

Solution 1

I think you need to set CURLOPT_HTTPHEADER. You can try to pass data as a json string as stated below.

$post_data = array(
    "end" => array("dateTime" => "2013-14-11T10:40:00.000-07:00"),  
    "start" => array("dateTime" => "2013-14-11T10:00:00.000-07:00"),  
    "summary" => "my_summary",
    "description" => "my_description"
);

$post_data = json_encode($post_data);
curl_setopt($ch2, CURLOPT_HTTPHEADER, array(  
   'Content-Type: application/json',  
   'Content-Length: ' . strlen($post_data),)  
 );  

Solution 2

I was receiving the same content error as you and found that I had an erroneous line break in my header, caused by a variable I was including.

I tracked this down using curl_setopt($ch, CURLINFO_HEADER_OUT, true); which makes curl_getinfo() include the request's headers in its output.

Using trim() on the variable fixed it.

Solution 3

So I just quickly used a curl_getinfo call to see what was being sent (not quite your recommendation, but it was faster to try this first)... and sure enough... there's no content-length anywhere. I tried it both with the Content-length header being declared by me, and NOT being declared by me. Both options resulted in what you see:

It's also worth noting that is says content_type = text/html... even though I had it declared as application/json

being used:

curl_setopt($ch2, CURLOPT_HTTPHEADER, array(
   'Authorization: GoogleLogin auth='.$auth_code,
   'Content-Type: application/json',  
   'Content-length:' . strlen($post_data))
 );

Here's the output of curl_getinfo:

Array (
    [url] => https://www.googleapis.com/calendar/v3/calendars/XXXXXXXXXX%40developer.gserviceaccount.com/events?sendNotifications=true&pp=1&key=XXXXXXXX-XXXXXXXXXXXXXXXXXXXXXX
    [content_type] => text/html; charset=UTF-8
    [http_code] => 411
    [header_size] => 147
    [request_size] => 737
    [filetime] => -1
    [ssl_verify_result] => 0
    [redirect_count] => 0
    [total_time] => 0.104391
    [namelookup_time] => 0.000687
    [connect_time] => 0.025284
    [pretransfer_time] => 0.079614
    [size_upload] => 159
    [size_download] => 934
    [speed_download] => 8947
    [speed_upload] => 1523
    [download_content_length] => 934
    [upload_content_length] => 159
    [starttransfer_time] => 0.104356
    [redirect_time] => 0
    [certinfo] => Array
        (
        )

    [primary_ip] => 2607:f8b0:400e:c04::5f
    [primary_port] => 443
    [local_ip] => 2600:3c01::f03c:91ff:fe69:4a05
    [local_port] => 57581
    [redirect_url] =>  )

Solution 4

Updated answer...

In the second curl call you seem to have used the wrong handle for one line...

curl_setopt($ch, CURLOPT_POST, true);

is supposed to be

curl_setopt($ch2, CURLOPT_POST, true);

Original answer... You're not passing a header. Did you try passing the content-length as a header in this format?

curl_setopt($ch,CURLOPT_HTTPHEADER,array('HeaderName: HeaderValue'));

Your header is currently just the number 1

curl_setopt($ch,CURLOPT_HTTPHEADER,array('Content-length:'.strlen($post_data)));

Solution 5

I was struggling for a while with a similar problem. In my case it was because one of the values I was setting in my headers ended with a newline character. This meant that the server receiving the post would see the double-newline and prematurely think the headers were finished (which stopped the Content-Length header from being read). Solution was to trim the newline char.

Share:
39,170
Kyle
Author by

Kyle

Updated on August 06, 2020

Comments

  • Kyle
    Kyle almost 4 years

    Before you ask: I have already checked every similar question that already had an answer, and none of the proposed solutions work. So I'm hoping someone may be able to notice a mistake in my code.

    When submitting a cURL post to Google, I am returned with a 411 error, "POST requests require a Content-length header"

    //Info required to authenticate
    $URL = "https://www.google.com/accounts/ClientLogin";
    $POST = http_build_query(array(
     'Email' => '[email protected]',
     'Passwd' => 'XXXXXXXXXXXXXXX',
     'source' => 'primary',
     'service' => 'cl'
    ));
    
    $ch = curl_init( $URL );
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $POST);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    $response = curl_exec($ch); //returns SID=<sid code>nLSID=<lsid code>nAuth=<auth code> or ERROR=<message>
    if ( curl_errno($ch) )
     die( 'Error contacting server' );
    
    //Successful auth results in http code 200
    if ( curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200 )
     die( 'Failed to authenticate' );
    
    //Extract auth code - Authorization: GoogleLogin auth=yourAuthToken
    $auth_code = substr($response, strpos($response, 'Auth=')+5);
    
    //We're done here
    curl_close($ch);
    
    
    $url = "https://www.googleapis.com/calendar/v3/calendars/".urlencode('[email protected]')."/events?sendNotifications=true&pp=1&key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx";  
    
    $post_data = http_build_query(array(
        "end" => array("dateTime" => "2013-14-11T10:40:00.000-07:00"),  
        "start" => array("dateTime" => "2013-14-11T10:00:00.000-07:00"),  
        "summary" => "my_summary",
        "description" => "my_description"
    ));
    
    $headers = array(
        'Authorization: GoogleLogin auth='.$auth_code.'',
        'Content-Type: application/json'
    );
    
    $ch2 = curl_init();  
    curl_setopt($ch2, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch2, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch2, CURLOPT_POSTFIELDS, $post_data);  
    
    $output = curl_exec($ch2);  
    
    curl_close($ch2);
    
    echo '<pre>'.print_r($output).'</pre>';
    

    Things I have tried:

    -Adding the 'Content-length: '.strlen($post_data)

    -Content-type of 'x-www-form-urlencoded'

    -using a very simply json string for post_data so that I didn't use http_build_query

    -Trying to make it send as a PUT instead of POST

    -And a few other things over the course of the last few days that I can't quite recall right now

    Intent: To add an event to only MY calendar using only PHP with no authentication steps required by the user. This must be able to run all within a php function, asynchronously (called via AJAX)

    NOTE: Not using Wordpress or any other CMS

    -Kyle

  • Kyle
    Kyle over 10 years
    I've tried adding the Content-length header before with no luck. Lots of people on other threads have said cURL add's this header automatically. Just to be sure, I tried re-adding it (in-case I spelled something wrong the first time) curl_setopt($ch2, CURLOPT_HTTPHEADER, array( 'Authorization: GoogleLogin auth='.$auth_code, 'Content-Type: application/json', 'Content-length:' . strlen($post_data)) ); (Code formatting isn't cooperating for me right now.)
  • Kyle
    Kyle over 10 years
    Also, keep in mind I have two separate cURL calls in the code. The first is to get an authentication token, and the second (using that token), is the one that I used the headers on since it is actually sending content) Also, just for fun, I just tried adding the content-length header to the first call for the authentication cURL call, and it didn't do anything different :(
  • Lenny
    Lenny over 10 years
    Wow, I just found it. Your second curl call you have a line that is using the $ch handle instead of $ch2 so it's not getting set as a post. Updated answer.
  • Kyle
    Kyle over 10 years
    Oh good catch! I can't believe I didn't see that! Unfortunately it didn't fix the issue though :( Could this possibly be a server configuration issue? I'm not familiar with the impact a server's configuration plays on curl calls, but maybe?
  • Lenny
    Lenny over 10 years
    I highly doubt it, but you COULD shoot that call at your own php script and have that php script var_dump the headers and post values and then have CURL output the response to see that everything is getting sent as expected.
  • Vrajesh Doshi
    Vrajesh Doshi about 3 years
    In my case the data is passed as an array as the value of CURLOPT_POSTFIELDS. How do I calculate and pass Content-Length ? I am getting the same 411 error. Please guide