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
I think you need to set
CURLOPT_HTTPHEADER. You can tried with pass data as a json string.
$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),) );
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.
trim() on the variable fixed it.
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
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
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] => )
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);
You’re not passing a header. Did you try passing the content-length as a header in this format?
Your header is currently just the number 1
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.