Endpoint requirements :

  • Set "Authentication" as "Session authentication"
  • Set "Response formatters" as "json"
  • Check resources "User > Login" and "Node > Create"

User requirements :

  • Add permission to create content type "page" for user role

/**
 * Create a token for non-safe REST calls.
 **/
function mymodule_get_csrf_header() {
  $curl_get = curl_init();
  curl_setopt_array($curl_get, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_URL => 'http://your-drupal/services/session/token',
  ));
  $csrf_token = curl_exec($curl_get);
  curl_close($curl_get);
  return 'X-CSRF-Token: ' . $csrf_token;
}

/*
 * Server REST - user.login
 */

// REST Server URL
$request_url = 'http://your-drupal/rest_server_endpoint/user/login';

// User data
$user_data = array(
  'username' => 'user_name',
  'password' => 'user_password',
);
$user_data = http_build_query($user_data);

// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', mymodule_get_csrf_header())); // Accept JSON response
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_POSTFIELDS, $user_data); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

// Check if login was successful
if ($http_code == 200) {
  // Convert json response as array
  $logged_user = json_decode($response);
}
else {
  // Get error msg
  $http_message = curl_error($curl);
  die($http_message);
}


/*
 * Server REST - node.create
 */

// REST Server URL
$request_url = 'http://your-drupal/rest_server_endpoint/node';

// Node data
$node_data = array(
  'title' => 'A node created with services 3.x and REST server',
  'type' => 'page',
  'body[und][0][value]' => '<p>Body</p>',
);
$node_data = http_build_query($node_data);

// Define cookie session
$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;

// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', mymodule_get_csrf_header())); // Accept JSON response
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

// Check if login was successful
if ($http_code == 200) {
  // Convert json response as array
  $node = json_decode($response);
}
else {
  // Get error msg
  $http_message = curl_error($curl);
  die($http_message);
}

print_r($node);

If Successful

Response code: 200 OK
return node nid and node uri as json

If Unsuccessful

Response codes

401 Unauthorized: Wrong username or password, or user doesn't have right permission.
406 Title field required / type field is required

NOTE: Many get the 401 error, but this example seems to work for many: https://www.drupal.org/node/1334758#comment-8656123

Comments

that0n3guy’s picture

To get this to work in Services 3.x in D6, I had to enable: application/x-www-form-urlencoded in server->request parsing. Otherwise I would get:
The requested URL returned error: 406

Anonymous’s picture

In fact, I use the last services version on drupal 7, and I have got 406 errors too.
When I enable "jsonp" and "application/x-www-form-urlencoded", the first 406 error disappear (during the authentication), but it still appears during the node.create request!

Any idea?

delykj’s picture

Same 406 error here when I specify the node author. Anyone have a fix?
'uid' => 10,
'name' => 'myusername',

Thanks.

EliseVanLooij’s picture

I am not clear on how the request url is constructed in the example:

$request_url = 'http://your-drupal/rest_server_endpoint/user/login';

Is rest_server_endpoint a canonical name or a placeholder? In the first case, can someone point met to the documentation, in the second case. how and where is set?

lambic’s picture

rest_server_endpoint is a placeholder. You define endpoints in the services configuration (admin/build/services/add)

quocnam15’s picture

if i have a image filed how i can create node content with image?

sergiu.savva’s picture

There are drupal_http_request function , why do you use cURL?

Raphael Apard’s picture

Yes, we can use drupal_http_request, but for my example, i call webservice from another device, not from a other drupal.

Raphael

phpexamples’s picture

wow.. very nice post.
Thanks.

drupso’s picture

Trying to get this sample, the script is returning a 302 error in $http_code var and I don't know what's the problem.
Anybody got the same problem or knows how to resolve it?
Thanks.
Regards

lambic’s picture

302 is the http code for a redirect, it's not an "error" as such.

drupso’s picture

Finally I could solve this removing a redirect URL Rule that I had activated in Rules Module. Then I got 200 http response. Thanks

yannou’s picture

I found something really strange.

I have some term references in my custom node so, when I build my node_data I use for instance
$node_data['field_something[und]'] = array(array("tid"=>294));
where field_something is a custom term reference.
I can create a node with term references, using curl. It is working well.

Except for the well known "field_tags", when the default widget for autocomplete is activated.

If I use Autocomplete Deluxe widget for field_tags, the service with curl is working !

I am really surprised of this behavior, should I post it in issues ? and where ? (service ? core ?)

checovision’s picture

I could not get the above code to work, so I went through and made some revisions based on other Documentation snippets and got this to work:

/*
 * Server REST - user.login
 */

// REST Server URL
$request_url = 'http://your-drupal/rest_server_endpoint/user/login.json';

// User data
$user_data = array(
  'username' => 'testuser',
  'password' => '1password',
);

// cURL
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $request_url);
curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($user_data)); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

// Check if login was successful
if ($http_code == 200) {
  // Convert json response as array
  $logged_user = json_decode($response);
}
else {
  // Get error msg
  $http_message = curl_error($curl);
  die($http_message);
}

/*
 * Server REST - node.create
 */

// REST Server URL
$request_url = 'http://your-drupal/rest_server_endpoint/node';

// Node data
$node = (object) NULL;
$node->title = 'A node created with services 3.x and REST server';
$node->type = 'page';
$node->body['und'][0]['value'] = '<p>Body</p>';
$node->path = '';
$node_data = (array) $node;

$node_data = json_encode($node_data);

// Define cookie session
$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;

// cURL
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $request_url);
curl_setopt($curl, CURLOPT_POST, TRUE); // Do a regular HTTP POST
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json')); // Accept
curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data); // Set POST data
curl_setopt($curl, CURLOPT_HEADER, TRUE);  // Ask to not return Header
curl_setopt($curl, CURLOPT_COOKIE, $cookie_session); // use the previously saved session
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, FALSE); //True in prod, false for debugging

$response = curl_exec($curl);

$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

// Check if login was successful
if ($http_code == 200) {
  // Convert json response as array
  $node = json_decode($response);
}
else {
  // Get error msg
  $http_message = curl_error($curl);
  die($http_message);
}

print_r($node);

tobyontour’s picture

It's definitely worth var_dump-ing the $http_code and $response after they've been defined to find out exactly where things have gone wrong. Particularly with regards to a 406 error (for instance the default D7 node type is basic_page which is easy to miss).

jonloh’s picture

For some reason, I keep getting error 401 although I'm really sure I got the $cookie_session set.

Edit: The solution was to enable "Session authentication" in the edit settings for the services.

rickl2770’s picture

I am also getting the 401 error and do not understand it.

I tried the first code sample and only changed the endpoint url to match my site. When i ran this I got a 406 error in the node create section.

I changed to the second code sample and this time I am getting the 401 error suggesting an authorisation failure.

I have checked and I have "Session authentication" set in the edit settings for the service I have created in services.

I am using Drupal 7.14 and Services 3

I would appreciate any idea where to look for this authentication issue.

FooZee’s picture

same here, but I'm using D6 instead!!

jyuyang’s picture

Try the first code sample and enable "application/x-www-form-urlencoded" in server tab, that's how I fix this problem.

unqunq’s picture

I only had "application/json" and it was complaining that the title was missing. Then I enabled "application/x-www-form-urlencoded" and it works fine. Thanks.

rahul.palake’s picture

Nice script, however I want to post tags and category along with node data how can I send it? what parameter should I add in node data array?

$node_data = array(
  'title' => 'A node created with services 3.x and REST server',
  'type' => 'page',
  'body[und][0][value]' => '<p>Body</p>',
);
giorgio79’s picture

I believe this sample is flawed as there is no need to get csrf token two times. One time is enough after user login. Also, csrf token needs to be obtained in the same curl session as login, as Drupal Services returns empty otherwise...

PS: I also fixed the DrupalREST class here https://github.com/RandallKent/DrupalREST.PHP/issues/2


<pre>
	<?php
		
		// LOGIN AND GET CSRF TOKEN
		
		/*
			* Server REST - user.login
		*/
		
		// REST Server URL
		$request_url = 'http://mysite....com/server/user/login.json';
		
		// User data
		$user_data = array(
		'username' => 'xxxx',
		'password' => 'xxxx',
		);
		$user_data = http_build_query($user_data);
		
		// cURL
		$curl = curl_init($request_url);
		curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json')); // Accept JSON response
		curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
		curl_setopt($curl, CURLOPT_POSTFIELDS, $user_data); // Set POST data
		curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
		curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
		
		
		$response = curl_exec($curl);
		//print_r($response);
		$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
		//print "<br>".$http_code."</br>";
		// Check if login was successful
		if ($http_code == 200) {
			// Convert json response as array
			$logged_user = json_decode($response);
			//print_r($logged_user);
			
		}
		else {
			// Get error msg
			$http_message = curl_error($curl);
			die($http_message);
		}		

		
		// Define cookie session
		$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;
		
		//GET CSRF TOKEN
		curl_setopt_array($curl, array(
		CURLOPT_RETURNTRANSFER => 1,
		CURLOPT_URL => 'http://mysite....com/services/session/token',
		));
		curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); 
		// $csrf_token = curl_exec($curl);
		//print_r($csrf_token);
		
		$ret = new stdClass;
		
		$ret->response = curl_exec($curl);
		$ret->error    = curl_error($curl);
		$ret->info     = curl_getinfo($curl);
		
		
		//print_r($ret->response);
		$csrf_token = $ret->response;


		/*
			* Server REST - node.create
		*/
		
		// REST Server URL
		$request_url = 'http://mysite....com/server/node';
		
		// Node data
		$node_data = array(
		'title' => 'A node created with services 3.x and REST server',
		'type' => 'page',
		'body[und][0][value]' => '<p>Body</p>',
		);
		$node_data = http_build_query($node_data);

		// cURL
		$curl = curl_init($request_url);
		curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', 'X-CSRF-Token: ' .$csrf_token)); // Accept JSON response
		curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
		curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data); // Set POST data
		curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
		curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
		curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
		
		$response = curl_exec($curl);
		print "<br><br>";
		print_r($response);
		$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
		
		// Check if login was successful
		if ($http_code == 200) {
			// Convert json response as array
			$node = json_decode($response);
		}
		else {
			// Get error msg
			$http_message = curl_error($curl);
			die($http_message);
		}
		
		print_r($node);
		
		
	?>
</pre>

ykyuen’s picture

then response for token is in json format. to get the token string, try using the following instead.

$csrf_token = json_decode($ret->response)->token;
couloir007’s picture

This one worked for me. I was getting nervous I was no where near grokking this. Thank you.

Anonymous’s picture

I'm using Services 3.7 which gave me the token using this after the login:

$csrf_token = $logged_user->token;

So I didn't need all this from the above example:

        //GET CSRF TOKEN
        curl_setopt_array($curl, array(
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_URL => 'http://mysite....com/services/session/token',
        ));
        curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session");
        // $csrf_token = curl_exec($curl);
        //print_r($csrf_token);
        $ret = new stdClass;
        $ret->response = curl_exec($curl);
        $ret->error    = curl_error($curl);
        $ret->info     = curl_getinfo($curl);
        //print_r($ret->response);
        $csrf_token = $ret->response;
Dharmendra.s’s picture

i am using same code only the url and rest api url is changed, but it gives 401 anauthorized aceess error::
it print csrf-token fine and also login into the remote site fine, but when i want to create a node throught curl then it gives 401...
can anyone give me any idea why this gives 401 error,,
when i try in poster it works fine,

amarbijay’s picture

Follow below steps,

  1. Select "Session authentication" while creating a new services
  2. Then go to "Server" tab and then select all the options
  3. http://my-drupal-site/admin/structure/services/list/drupal_services/server
  4. Then go to "Resources" tab and select CRUD operations for node
  5. http://my-drupal-site/admin/structure/services/list/drupal_services/reso...
  6. Then select "Login" and "Token" from USER CRUD operation in "Resources" tab

Write this simple code in php file

function rest_connect(){
	$request_url = 'http://my-drupal-site/Path-to-endpoint/user/login';
	$username = 'user';
	$password = 'password';	
	$user_data = array(
	'username' => $username,
	'password' => $password,
	);
	$user_data = http_build_query($user_data);

	$curl = curl_init($request_url);
	curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json')); // Accept JSON response
	curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
	curl_setopt($curl, CURLOPT_POSTFIELDS, $user_data); // Set POST data
	curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
	curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
	curl_setopt($curl, CURLOPT_COOKIESESSION, true);
	//curl_setopt($curl, CURLOPT_COOKIEFILE, "cookie.txt");
	//curl_setopt($curl, CURLOPT_COOKIEJAR, "cookie.txt");

	$response = curl_exec($curl);
	$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
	if ($http_code == 200) {
	$logged_user = json_decode($response);
		//echo "<pre>";
		//print_r($logged_user);
		return  $logged_user ;
	}
	else {
		$http_message = curl_error($curl);
		return $http_message ;
		//print $http_message ;
	}
	curl_close($curl); 
	//print($results);
}
function rest_post_data($logged_user){
	//print_r($logged_user);exit;
	/*
	* Server REST - node.create
	*/
	// REST Server URL
	$request_url = 'http://my-drupal-site/Path-to-endpoint/node';
	// Node data
	$node_data = array(
	  'title' => 'A node created with services 3.x and REST server',
	  'type' => 'article',
	  'body[und][0][format]' =>'full_html',
	  'body[und][0][value]' => '<p>rest Body</p>',
	);
	$node_data = http_build_query($node_data);
	// Define cookie session
	$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;
	// cURL
	$curl = curl_init($request_url);
	curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', 'X-CSRF-Token: ' . $logged_user->token)); // Accept JSON response
	curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST
	curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data); // Set POST data
	curl_setopt($curl, CURLOPT_HEADER, FALSE);  // Ask to not return Header
	curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
	curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
	$response = curl_exec($curl);
	$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
	// Check if login was successful
	if ($http_code == 200) {
		// Convert json response as array
		$node = json_decode($response);
		return $node;
	}
	else {
		// Get error msg
		$http_message = curl_error($curl);
		return $http_message;
	}
}
// call these two functions
echo "<pre>";
$logdata = rest_connect();
print_r($logdata);
$output = rest_post_data($logdata);
print_r($output);
pratip.ghosh’s picture

Worked perfectly for me

-- Pratip Ghosh

dineshw’s picture

rest_connect() keeps returning hash string like below
0kRJ0zv7QVui6i8A4S0E9Z7YBFNW5cc5JeOfpkdVitY
RdqbZg65MS0iQSxp9yGhTMmBShd5ceRR9dbDk_cawqY

etc

$http_code returns 200 correctly

stuck with rest_connect itself.

On Service settings:
Server: Rest
Authentication: Session authentication is selected
Debug mode enabled : Yes

On Server tab:
All options are selected for Response formatters and Request parsing

On Resource tab:
Use.Login and User.Token is selected with Services Resource API Version 1.1 and Crud operation for Create

Cheers
Dinesh Waghmare (LAMP)
UK, Surrey | India, Mumbai
Web Development | Digital Media Marketing | Strategic Consulting
--
m: +91 9867888266
(Drupal / Wordpress / SugarCRM )

TarKHaoS’s picture

This code works for me. I finally got rid of 401 errors.

Drupal 7.37
Services 7.x-3.12

raj45’s picture

Thanks for posting it @amarbijay, it just works - your code should be the default example.

dirckdigler’s picture

At last I can create a node with curl, I'm sure there are many example that works, I never can't add to the header the token, the only way to do it, was the great amarbijay's example. I would like to show my code:

function _create_node($username, $fname, $lname, $mail, $country, $bdate){

$request_url = 'http://127.0.0.1/proyect/end_point/user/login';
$type = 'article';
$user = 'zp-user';
$pass = '123';
$user_data = array(
'username' => $user,
'password' => $pass,
);
$user_data = http_build_query($user_data);

$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json'));
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $user_data);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);
curl_setopt($curl, CURLOPT_COOKIESESSION, true);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ($http_code == 200) {
$logged_user = json_decode($response);
}
else {
$http_message = curl_error($curl);
die($http_message);
}
curl_close($curl);

$request_url = 'http://127.0.0.1/proyect/end_point/node';
$node_data = array(
'title' => $username,
'type' => $type,
'field_name_zp[und][0][value]' => $fname,
'field_lastname_zp[und][0][value]' => $lname,
'field_country_zp[und][0][value]' => $country,
'field_bday_zp[und][0][value]' => $bdate,
'field_country_zp[und][0][value]' => $country,
'field_email_zp[und][0][value]' => $mail,
);
$node_data = http_build_query($node_data);
// Define cookie session
$cookie_session = $logged_user->session_name . '=' . $logged_user->sessid;
// cURL
$curl = curl_init($request_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json', 'X-CSRF-Token: ' . $logged_user->token));
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $node_data);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ($http_code == 200) {
$node = json_decode($response);
}
else {
$http_message = curl_error($curl);
die($http_message);
}
}

thedrupalkid’s picture

Thanks for support.

vikasfourorange’s picture

thanks for this example , I have used the same example to fetch user friends from drupal website but its returning me 404 , Please help. I am getting the logged user session id and name but when I hit using the same then I get 404

$post_data = array('uid' => 'x');
$post_data = http_build_query($post_data);

// cURL
$curl = curl_init($request_url);

curl_setopt($curl, CURLOPT_HTTPHEADER, array("Accept: application/json", $csrf_header)); // Accept JSON response
curl_setopt($curl, CURLOPT_POST, true); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);

curl_setopt($curl, CURLOPT_COOKIE, $cookie_session); // use the previously saved session
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FAILONERROR, TRUE);

$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

// Check if login was successful
if ($http_code == 200) {
  $node = json_decode($response);
}
else {
  $http_message = curl_error($curl);
  
  $info = curl_getinfo($curl);
   print_r($info);
  echo "<b>Error I am getting</b><br /><br />";
  echo $http_message; 
  }

Please help.

thanks,