Working with Microsoft Dynamics CRM 4.0 SOAP Interface with PHP and NuSoap


When using a third-party product with any Microsoft product it usually spells trouble and you know some rough times are ahead – especially in this case where I was trying to retrieve a list of accounts on Dynamics CRM via SOAP and PHP.

 

First of all I was trying to access the SOAP endpoint using PHP’s built in SoapClient and after hours upon hours of failing I moved to NuSoap and again my requests kept failing (usually with HTTP 401 Unauthorized). I couldn’t get any of the examples I found around the net to work so I decided to start from scratch…

As it turns out you have to provide CrmAuthenticationToken within the SOAP header, an example of mine is:

'
     0
     infinitie
     00000000-0000-0000-0000-000000000000

NOTE: don’t forget you change your OrganizationName.

You then have to (the way I’ve done it anyway) generate your own SOAP requests manually, NuSoap’s generated ones doesn’t seem to work. I had to call NuSoaps call() function like so:

$this->client->call($operation, $soapBody, $this->namespace, null, $this->generateSoapHeader());

For example, to get a list of accounts your SOAP request should look like this;


    account
    
         
             name
         
    


I would suggest manually looking through the WSDL, it will explain things better. I have created a very basic class that extends NuSoap to get you started – I hope it saves you hours of headaches!

NOTE: If your accessing your CRM over the Internet you may have to add an entry to your /etc/hosts (or C:\windows\system32\etc\drivers\hosts) as NuSOAP will use the hostname it finds in the WSDL. For example my CRM box is called ‘crm’ so the WSDL gives of http://crm:5555… even though I explicitly defined the endpoint as ‘crm.domain.tld’ so I would add a line like so;

85.53.23.111 crm

NOTE

From the unsuspecting eye the below SOAP request would look perfectly fine but you would probably find it doesn’t work and after hours of banging your head you would give up…

<EntityName>account</EntityName>
<id> $company_guid . </id>
<ColumnSet xmlns:q1="http://schemas.microsoft.com/crm/2006/Query" xsi:type="q1:ColumnSet">
	<q1:Attributes>
		<q1:Attribute>name</q1:Attribute>
		<q1:Attribute>address1_line1</q1:Attribute>
		<q1:Attribute>address1_line2</q1:Attribute>
		<q1:Attribute>address1_stateorprovince</q1:Attribute>
		<q1:Attribute>address1_city</q1:Attribute>
		<q1:Attribute>address1_postalcode</q1:Attribute>
		<q1:Attribute>telephone1</q1:Attribute>
	</q1:Attributes>
</ColumnSet>

The problem is the capitalized “EntityName” and “ColumnSet” believe it or not. If we change it to camelCase (i.e. “entityName“) it will work perfectly fine – thanks Microsoft.

Share

No related posts.

38 Responses to “Working with Microsoft Dynamics CRM 4.0 SOAP Interface with PHP and NuSoap”

  1. chris1  on February 24th, 2010

    Hello Paul,

    What a major headache hey! I too have been slogging away at this for hours and hoped that your fix might work for me too. It sounds simple doesn’t it, provide a token to authenticate then ask all the questions you want!

    So the problem I am having is possible with the cmrservice.asmx URL. I have read that some people are using the organisation name in it, however others have said not too. I believe that it is dependant on CRM version, and because we are looking at 4.0 we can put it in the URL. However I spotted from a forum that if the organisation you want is set to default then if you don’t include it in the URL it will find it anyway.

    What did you use?

    When I use it I get ‘URL does not contain MSCrmServices’, and if I don’t use it I’m getting:

    Error: HTTP Error: cURL ERROR: 7: Failed to connect to 0.0.21.179: Invalid argument
    url: http://5555:80/MSCrmServices/2007/CrmService.asmx etc …

    Thanks!

    Reply

  2. chris1  on February 24th, 2010

    Ever since I met Microsoft’s CRM I’ve been regretting it … :)

    Anyway thanks for your quick reply, I had a look at your class and I’ve got all that implemented. Also now tried with your endpoint suggestion (which I hadn’t tried before) but still the same error for me. I’ve popped it on a pastebin if you feel like having a look – http://pastebin.mozilla.org/704559 otherwise I’ve checked the CRM trace logs and not getting much detail from it, well that explains an error … but I think from the pastebin detail it might not be reaching the CRM …

    Cheers,

    Chris

    Reply

    • Paul Price  on February 24th, 2010

      “Error: HTTP Error: cURL ERROR: 7: Failed to connect to 0.0.21.179: Invalid argument”

      Looks an invalid IP address? What happens if you access the URL from your browser?

      Reply

  3. chris1  on February 24th, 2010

    Well I think I know where the odd IP is coming from because for some weird reason it is trying to go to http://5555:80, but I can’t understand why …

    I mean I am passing the endpoint ‘http://crm:5555/mscrmservices/2007/CrmServiceWsdl.aspx?unique_name=CRMDEMO‘ to nusoap so where is it translating that to 5555:80 … it almost as if it is stripping it down, ignoring the ‘crm:’ part … mmm

    Thought it might be upset with the port declaration of ‘:5555′ but you’ve used that too …

    I’ll rummage around in nusoap to see where the url is getting broken …

    Cheers

    Reply

    • Paul Price  on February 24th, 2010

      It shouldn’t make a difference but could you try a fully qualified FQDN? i.e. crm.domain.local

      Reply

  4. chris1  on February 24th, 2010

    I think I am going to give up and work with some ropey Visual Basic instead, was really wanting to keep to PHP. I can’t understand why I have a random soap call to a 5555:80 and when I frig it to work it isn’t an authorised URL … ah maybe I need sleep then come back to it.

    Thanks for your help anyway!

    Chris

    Reply

  5. chris1  on February 25th, 2010

    Trying again …

    With my fix in for nusoap, I’m still getting an authentication error, checking the IIS on my CRM there are just 401 all over the place. I’m just wondering does the curl first send the authentication token then send the request, because if that is the case I’m just wondering if the authentication is not cached so the second request doesn’t get through.

    When I put an incorrect password in and show the nusoap debugging I get an IIS authentication error, with the right password I don’t get one, so is that authenticating? …

    Clutching at straws …

    Chris

    Reply

    • Paul Price  on February 25th, 2010

      Hi Chris, I resolved the problem Fabio was having and hopefully it’s the same fix for you.

      If you print out NuSoaps $debug_str you’ll probably see near the bottom that it is failing to contact your CRM hostname, e.g:

      2010-02-25 22:25:29.338741 soap_transport_http: cURL ERROR: 6: Couldn’t resolve host ‘your-server-name’

      It’s because NuSoap uses the endpoint it finds in the WSDL, you can override it but I forgot how. As a temp. solution I just added a new entry to my /etc/hosts;

      82.133.124.191 not-sv002.infiniti-e.com not-sv002

      I did have this issue my self but totally forgot about it!

      Regards, Paul

      Reply

  6. Fabio  on February 25th, 2010

    I’m having the same problem with authentication.
    The server response returns:

    ‘HTTP/1.1 401 Unauthorized’
    [...]
    ‘HTTP/1.1 100 Continue’
    [...]
    ‘HTTP/1.1 401 Unauthorized’

    The complete response header: http://freetexthost.com/1cxgw5zwje

    Reply

  7. Paul Price  on February 25th, 2010

    What authentication are you guys using, NTLM?

    On the CRM box were IIS is installed try enabling basic authentication for the folder MSCRMServices and then alter NuSoap’s SetCredentials() function so it uses basic auth – let me know if that works..

    Reply

  8. Fabio  on February 25th, 2010

    Yes, the authentication type is NTLM.

    Every time I called the NuSoap method getError(), it returns ‘HTTP Error: no proper separation of headers and document’

    Thanks!

    Reply

  9. Paul Price  on February 25th, 2010

    Hmm, strange. Can I take a look at your full code? What’s the CRM endpoint URI?

    Reply

  10. Fabio  on February 25th, 2010

    I’m using your class now, but I’m getting the same error I had with my previous code.

    I just insert it the authentication data (username and password) and the endpoint URI.

    CRM endpoint URI:
    http://201.87.123.32:5555/mscrmservices/2007/CrmServiceWsdl.aspx?uniquename=cds

    I could send you these credentials by e-mail, if you want test it by yourself.

    Thanks

    Reply

  11. Paul Price  on February 25th, 2010

    Fabio, if you don’t mind – have you got a test user? eth0@ifc0nfig.com

    Reply

  12. chris1  on February 26th, 2010

    Well we’re all in the thick of it that’s for sure!

    Paul the way I got around my crm:5555 endpoint being turned into a 5555:80 enpoint was to edit nusoap and add a cheat at about line 7208 that does this (just after – $this->debug(“found operation”):

    if($opData['endpoint']==”http://5555/MSCrmServices/2007/CrmService.asmx”) {
    $opData['endpoint'] = “http://crm:5555/MSCrmServices/2007/CrmService.asmx”;
    }

    This solved my odd goings on with the URL.

    Now still have authentication failing so tried your ‘basic’ idea, but still no joy. Here is the debugging with the last few lines from the nusoap debug : http://pastebin.mozilla.org/705033

    My fear reading about was that NTLM was not very well handled by nusoap and it often may not wait around long enough after the offical auth so the second call (request) gets denied, however surely making it basic rules that one out …

    The setup I have is on a VPC, my PHP is on another machine, but to rule out any other issues I also tested it on the local VPC with a WAMP stack and had exactly the same issues. Is there possible something else about my environment that is different to yours? CRM 4.0, rollup 8, (you using the same VPC image from Microsoft?), using port 5555.

    Also I know it works with a mixture of VB and AJAX as have a minor working example, but obviously that is the text book way to do it, rather use PHP!

    Cheers,

    Chris

    Reply

    • Paul Price  on February 26th, 2010

      Why does Microsoft have to make it hard, huh?

      I take it ‘crm’ is resolvable on your PHP box and it’s running a flavour of Linux? What PHP version and NuSoap version are you using? Here’s mine:

      PHP 5.2.10 (cli) (built: Nov 13 2009 11:24:03)

      nusoap.php,v 1.114 2007/11/06 15:17:46
      var $version = ’0.7.3′;
      var $revision = ‘$Revision: 1.114 $’;

      I’m also running CRM 4.0 but with roll-up 9 (http://www.microsoft.com/downloads/details.aspx?FamilyID=5869F2B3-D1A0-4F71-8BE3-FDE6E8053A2E&displaylang=en) with IIS6. I’m running enterprise version installed from VL media although shouldn’t make a difference…

      Reply

  13. chris1  on February 26th, 2010

    Yep using Ubuntu on my PHP stack, PHP 5.2.10-2ubuntu6.3, and exactly the same nusoap version

    Someone mentioned that it might be CURL related. I am using – libcurl/7.19.5 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.15, however I tried it on my WAMP stack too which has CURL – 7.19.4. Not that it is probably CURL directly but they mentioned it might be the way that nusoap used CURL, maybe the initial auth timesout and so the second request doens’t have permission.

    So your implementation works fine? Are you passing data back and forth ok? Be interested to know if you have been able to write anything to the CRM yet, someone mentioned that could throw up problems.

    Just don’t get why this is so complicated and why php soap doesn’t work when essentially once you’ve passed the auth token header everything should just flow!

    Ahhhh!

    Chris

    Reply

    • Paul Price  on February 26th, 2010

      My curl_version()

      Array ( [version_number] => 462597 [age] => 2 [features] => 1597 [ssl_version_number] => 0 [version] => 7.15.5 [host] => i686-redhat-linux-gnu [ssl_version] => OpenSSL/0.9.8b [libz_version] => 1.2.3 [protocols] => Array ( [0] => tftp [1] => ftp [2] => telnet [3] => dict [4] => ldap [5] => http [6] => file [7] => https [8] => ftps ) )

      I see I’m using an older version than you. Have you tried setUseCURL(false)?

      If you don’t mind could you set a test user up for me and I’ll see if it works my end, that way we know it isn’t CRM itself.

      It’s perfectly fine, pretty quick over the ‘net too! I haven’t wrote anything to the CRM yet but from what I can see it’s the same as retrieving, just a different request.

      Reply

  14. chris1  on February 26th, 2010

    Firstly I must say Ahhhhh!!! B*@lck*$WE%£$^Y£$!!!

    Secondly thank you, but I am an idiot, my actual problem has been solved. You see I used your fantastic example to compare to my code that I had put together and then updated mine accordingly. However I in my infinite wisdom decided not to copy your class exactly therefore it is my own fault that I missed a stupid ridiculous variable in discrepancy, which meant that my headers weren’t getting sent!!! … and guess what no authentication ! derrr!

    Anyway when I did just copy and paste you class in it worked first time! Sat starring for a while in amazment until I spotted the error.

    So only thing I really had trouble with was my fix for the URL shuffle in nusoap.

    Unbelievebale…

    Thank you for all your help though, going to test putting data in now and make sure there are no further issues.

    Thanks,

    Chris

    Reply

    • Paul Price  on February 26th, 2010

      It’s always the simple things! I’m glad you got it working :)

      I’ll most probably create a fully usable class once I’ve finished my project.

      Reply

  15. chris1  on February 26th, 2010

    :) Yep I’m working on expanding your class too, mine doesn’t need to do everything, I’m focusing on Invoices by talking with Sage (another existing application to talk to!).

    Good luck,

    Chris

    Reply

    • Paul Price  on February 26th, 2010

      Just out of interest Chris, do you use some sort of Sage addon? We would like to integrate into Sage (Line 50) – any recommendations? :)

      Reply

      • chris1  on March 1st, 2010

        Well haven’t found one with PHP yet, hense the current thrashing about with the SOAP’ing. But there is one that was recommended to me, it however is C#, .NET and only for CRM 3.0 – http://www.codeplex.com/crmsageconnector. If you happen to find anything more useful though then I’d love to know.

        Cheers,

        Chris

        Reply

  16. Fabio  on February 28th, 2010

    I did what you said and it works perfectly fine now. :D

    I replaced ‘Infinitie’ with ‘CDS’ in authentication header and I removed the line ‘new_company’ from the request string.

    I also had to add the DNS manually to /etc/hosts, as you had explained in e-mail.

    You saved me several days of work.

    Thank you very much for your help and patience.

    Reply

    • Paul Price  on February 28th, 2010

      I’m glad I could be of help Fabio, have fun :)

      Reply

  17. chris1  on March 1st, 2010

    Not sure if you are struggling with parsing the SOAP responses with SimpleXML, but there is a fix here that means things get read properly – http://www.webmasterkitchen.com/article/problems-with-php-simplexml-soap-results/#comment-2065.

    Reply

    • Wesley  on September 9th, 2011

      Any chance you remember what the answer was? The website is gone and my head hurts from banging it on the desk =)

      Reply

  18. Aaron  on April 22nd, 2010

    Hi there!. Today I had the same problem coding with PHP. All was working perfeclty..until I changed the web port (from 5555 to 83). Go the same error as the others:

    HTTP Error: cURL ERROR: 7: couldn’t connect to host
    url: http://demosrv:80/MSCrmServices/2007/CrmService.asmx

    Found a solution, using the Microsoft Dynamics CRM Deployment Configuration Tool

    You need to read the following KB docs:

    support.microsoft.com/kb/947423/
    support.microsoft.com/kb/949079/

    Hope this help others. By the way, thanks to Paul on this post, that helped me A LOT!

    Regards,
    Aaron

    Reply

  19. Canadaka  on October 8th, 2010

    Will this class work with MS CRM 3?

    Reply

    • Paul Price  on October 17th, 2010

      Hi Canadaka, I see no reason why it wouldn’t – your best chance is to give it a try!

      Reply

  20. metalmini  on February 11th, 2011

    This is an older post already but still very helpfull. But i am getting a load of errors :-(

    First of all, when i fill in your script (CRM_Soap.php) and i run this i get “Notice: Use of undefined constant ACCESS_DENIED_MSG – assumed ‘ACCESS_DENIED_MSG’ in D:\wamp\www\vck\CRM_Soap.php on line 1″

    So i was wondering if you could explain a bit more about this because i cant seem to get anything working.

    I am kinda new to soap and ms crm so all links or how to’s are welcome.

    Thanks in advnace!

    Reply

  21. Wesley  on March 9th, 2011

    Has anyone gotten a good working class for this? I am stuck with an error “HTTP ERROR: no proper separation of headers and document”

    Reply

  22. drusa  on November 10th, 2011

    Can you explain why you added 85.53.23.111 crm and what does that IP address imply?

    Reply

    • Paul Price  on December 18th, 2011

      That was just to create a local map for my CRM box because for some reason it was using its local name which wouldn’t resolve over the Internet.

      Reply

  23. SD  on November 17th, 2011

    I still can’t resolve my problem (401 – Unauthorized). I’m trying to consume a Sharepoint web service using nuSoap in PHP. Here’s part of my code:

    $client = new nusoap_client($wsdl, true);
    $client->setCredentials($username, $password, ‘NTLM’);
    $client->setUseCurl(true);
    $client->useHTTPPersistentConnection();
    $client->setCurlOption(CURLOPT_USERPWD, $username.’:’.$password);
    $client->soap_defencoding=’UTF-8′;

    The WSDL document gets parsed well, but then I get the 401 error. My credentials are correct when viewing the Sharepoint site in my browser.

    Here’s the tail end of the debug message:

    2011-11-17 15:05:47.830400 soap_transport_http: setCurlOption option=10015, value=
    string(515) “[OMITED]”
    2011-11-17 15:05:47.830528 soap_transport_http: set cURL POST data
    2011-11-17 15:05:47.830632 soap_transport_http: setCurlOption option=10005, value=
    string(17) “[user:pswd]”
    2011-11-17 15:05:47.830753 soap_transport_http: set cURL payload
    2011-11-17 15:05:47.830862 soap_transport_http: send and receive with cURL
    2011-11-17 15:05:47.862661 soap_transport_http: No cURL error, closing cURL
    2011-11-17 15:05:47.865537 soap_transport_http: Found HTTP header to skip
    2011-11-17 15:05:47.865834 soap_transport_http: found proper separation of headers and document
    2011-11-17 15:05:47.865956 soap_transport_http: cleaned data, stringlen: 0
    2011-11-17 15:05:47.866173 soap_transport_http: found cookie: BIGipServerSP10STG_Pool = 1896943788.20480.0000
    2011-11-17 15:05:47.866306 soap_transport_http: Got 401 Unauthorized with WWW-Authenticate: NTLM
    2011-11-17 15:05:47.866413 soap_transport_http: HTTP authentication failed
    2011-11-17 15:05:47.866528 soap_transport_http: end of send()
    2011-11-17 15:05:47.867950 nusoap_client: Setting new cookie(s)
    2011-11-17 15:05:47.868119 nusoap_client: Error: HTTP Error: HTTP authentication failed

    Can anyone please post a simple step-by-step solution?
    Many thanks in advance!

    Reply


Leave a Reply