Kniganapolke Tech Blog

In my previous posts I showed how to authorize to a Sharepoint server and call it’s web services.
In my particular case I had to pull some lists from Sharepoint to show them on a web form. Authorization call + 3 WS calls took about 7 seconds to complete. So I decided to cache the lists to save 4 calls and to provide a separate form to update the lists.
The following code snippet serializes / deserializes a php array to / from a file.


// Call Sharepoint WS to het a list
/* array */ $result = $client->call("GetListItems", 
array("listName" => $list_guid, "viewName" => $view_guid,));
if($client->fault || !result){
	// Handle error
	return false;
}
// You may want to process the result for example to pick out only necessary fields
$data_array = processResult( /* array */ $result );
// Serialize data, put it to a file
file_put_contents($fileName, serialize($data_array), FILE_USE_INCLUDE_PATH);
	
// Deserialize data from a file into php array
$srlzd = file_get_contents($filePath, FILE_USE_INCLUDE_PATH);
$data_array = ($srlzd) ? unserialize($srlzd) : null;

I use Nusoap to call the web service.

In the previous post I showed how to authorize through a web form. We get a cookie among the response headers in case of successfull authorization. This post shows how to use the authorization cookie or use the NTLM (Windows) authentication to make calls to Sharepoint web services.

soap_defencoding = "UTF-8"; 
$err = $client->getError(); 
if ($err) { 
 // Handle error return false; 
} 
// To authorize to a Sharepoint server that uses NTLM (Windows) authentication scheme from the same LAN 
//$client->setCredentials($user, $pass, "ntlm");

// $cookie - received after authorization through a web form
$client->setCurlOption(CURLOPT_COOKIE, $cookie);
$client->setCurlOption(CURLOPT_SSL_VERIFYPEER, FALSE);
$client->setCurlOption(CURLOPT_SSL_VERIFYHOST, FALSE);

$client->setCurlOption(CURLOPT_TIMEOUT, 25);	// To avoid total page timeout

// Sharepoint fields' names
$field1_name = "ABC 123";
$field2_name = "DEF 456";
// Fields values
$field1_value = "ABC 123";
$field2_value = "DEF 456";

// $list_guid - find out the GUID of the target Sparepoint list
// $view_guid - find out the GUID of the target Sparepoint view

$newField = '
<UpdateListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<listName>{'.$list_guid.'}</listName>
<updates>
<Batch OnError="Continue" ListVersion="1" ViewName="{'.$view_guid.'}">
<Method ID="1" Cmd="New">
<Field Name="'. $field1_name .'">'. $field1_value .'</Field>
<Field Name="'. $field2_name .'">'. $field2_value .'</Field>
</Method>
</Batch>
</updates>
</UpdateListItems>';

$result = $client->call("UpdateListItems", $newField);

if ($client->fault){
// Handle error
return false;
}
?>

I use Nusoap classes to call Sharepoint web services to add a new element to a list in this code snippet.

I had to make a php based site interchange some information with a MS Sharepoint based site, moreover the latter was secured by a proxy-server and used SSL (https).

The first step was to pass authorization on proxy-server, which was supposed to be done through a special authorization form.
Using Firebug add-on for Firefox (or Fiddler for FF and IE) I watched the POST request headers and fields sent when submitting authorization form manually.

So I needed to make the same POST request with credentials from php script.

Moreover, a cookie was set after authorization (either fault or successfull) which we need to store and use for following requests.
This can be done with curl (libcurl library for php).

$ch = curl_init();
// $authorization_url - URL what to post credentials to, for example "https://myhost/login"
curl_setopt($ch, CURLOPT_URL, $authorization_url);

curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt ($ch, CURLOPT_REFERER, 'set your referer here');

// Do not follow "Location:" header
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);

// To use SSL protocol without verifying or providing any certificates
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// Avoid "Expect: 100-continue" header
curl_setopt ($ch, CURLOPT_HTTPHEADER, array('Expect:'));

// Indicate it's a POST request
curl_setopt ($ch, CURLOPT_POST, 1);

// Prepare POST fields
$postfields  = 'Field1='.urlencode('field 1 value');
$postfields .= '&Field2='.urlencode('field 2 value');
$postfields .= '&Field3='.urlencode('field 3 value');
curl_setopt ($ch, CURLOPT_POSTFIELDS, $postfields);

// For debugging purposes
// return transfer data as a result
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// read headers
curl_setopt($ch, CURLOPT_HEADER, 1);
// show request headers, will display all the outgoing info, including fields
curl_setopt($ch, CURLINFO_HEADER_OUT, true);

// Make the request
$data = curl_exec($ch);
$errors = curl_error($ch)
// get info about the transfer, for debugging purposes
$details = curl_getinfo($ch); 

curl_close($ch);

// Displaying debugging info
//var_dump($data);
//var_dump($errors);
//var_dump($details);

// Parse data for cookie header, store cookie as it will be used for subsequent requests
$cookie = '';
$pattern = '/Set-Cookie:(.*?)\n/';
if (preg_match($pattern, $data, $result))
$cookie = $result[1];

Setting “CURLINFO_HEADER_OUT” option to true seems to be the only way to see the outgoing request headers and POST data.

Then we can make a GET request to ask for a resource (a page, for example). Send authorization cookie using “CURLOPT_COOKIE” option.

$ch = curl_init();
// Set URL of the target resource (for example, https://myserver/targetresource)
curl_setopt($ch, CURLOPT_URL, $resource_url);

curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt ($ch, CURLOPT_REFERER, 'set your referer here');

// Do not follow "Location:" header
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

curl_setopt ($ch, CURLOPT_HTTPHEADER, array('Expect:'));

// Set authorization cookie that we got as a result of our first request
curl_setopt($ch, CURLOPT_COOKIE, $cookie);

// For debugging purposes
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);

$data = curl_exec($ch);
$errors = curl_error($ch)
// get info about the transfer, for debugging purposes
$details = curl_getinfo($ch);

// Displaying debugging info
//var_dump($data);
//var_dump($errors);
//var_dump($details);

curl_close($ch);

Links that helped:

I decided to start my own tech blog as I have almost succeeded with my task – sending data from php-based site to a sharepoint-based site by means of web services.  I came across some troubles with authorization and debugging, so I’ll post some usefull links and code snippets.


    • kniganapolke: Thanks, your code seems to be more generic.
    • kniganapolke: I suggest you to debug and look into your request HTTP headers. Are you geting 400 at the first request or at the second one?
    • Neel: Hi, I have been trying something similar but I keep getting Bad Request error when I try to follow this approach. Do you have any solution for that

    Categories

    Follow

    Get every new post delivered to your Inbox.