Calling Apex Web Services from PHP

Apex Code can be exposed as a Web Service and made available outside of your Salesforce environment (e.g. from a PHP page). This approach essentially lets you build a personal API into your Salesforce org and eliminates the need for calling standard API methods in PHP code where it is vulnerable to your configuration changes.

Working with the folks over at MK Partners on some recent projects, I’ve learned how to call into Apex Web Services from PHP. It’s actually pretty easy. Special thanks for Simon Fell for helping me through a particularly tricky part.

Apex Web Service Class

A simple web service class is below. The method we call from PHP is myMethod. There are 2 inner classes that are used to capture inputs and send back outputs to PHP.

global class MyWebService {

    // A class to accept an array of input records (e.g. product/amount combinations)
    global class myInputs{
        webservice Id productId;
        webservice Double amount;
    }
    
    // A class to send back as an output to PHP
    global class myOutputs{
        webservice String errorMessage;
        webservice Boolean success;
        webservice List<myInputs> inputs;
        webservice Id contactId;
    }

    // The actual web service method we will call
    webservice static myOutputs myMethod(Id contactId, List<myInputs> inputs){
    
        /* 
        * Write a bunch of code here to do all kinds of stuff.
        */
        
        myOutputs output = new myOutputs();
            output.errorMessage = 'No errors here.';
            output.success = true;
            output.inputs = inputs;
            output.contactId = contactId;
        return output;
        
    }
}
PHP

Login like you normally would using the PHP toolkit. Nothing new here. The final part is defining some constants for use later when we call the web service.

// Include the PHP Toolkit
require_once('salesforceAPI/SforcePartnerClient.php');
require_once('salesforceAPI/SforceHeaderOptions.php');

// Login
$sfdc = new SforcePartnerClient();
$SoapClient = $sfdc->createConnection('salesforceAPI/wsdl.xml');
$loginResult = false;
$loginResult = $sfdc->login('user@domain.com', 'password' . 'securitytoken');

// Define constants for the web service. We'll use these later
$parsedURL = parse_url($sfdc->getLocation());
define ("_SFDC_SERVER_", substr($parsedURL['host'],0,strpos($parsedURL['host'], '.')));
define ("_WS_NAME_", 'MyWebService');
define ("_WS_WSDL_", _WS_NAME_ . '.xml');
define ("_WS_ENDPOINT_", 'https://' . _SFDC_SERVER_ . '.salesforce.com/services/wsdl/class/' . _WS_NAME_);
define ("_WS_NAMESPACE_", 'http://soap.sforce.com/schemas/class/' . _WS_NAME_);

Next we will call the web service. First thing to do is setup a Soap Client and modify the headers. Then we are setting up some fake data that maps to the expected inputs of the myMethod method in the web service. Then we actually call the web service.

// SOAP Client for Web Service
$client = new SoapClient(_WS_WSDL_);
$sforce_header = new SoapHeader(_WS_NAMESPACE_, "SessionHeader", array("sessionId" => $sfdc->getSessionId()));
$client->__setSoapHeaders(array($sforce_header));

// Setup fake data to send into the web service
$prodAmtArray = array();
	$prodAmtArray[] = array('productId'=>'01t60000000lvBN','amount'=>100);
	$prodAmtArray[] = array('productId'=>'01t60000000lvBS','amount'=>200);

$wrkArray = array(
				'contactId'=>'0036000000nVtpT',
				'inputs'=>$prodAmtArray
				);
				
// Call the web service
$response = $client->myMethod($wrkArray);

// Output results to browser
echo "<p><pre>" . print_r($response, true) . "</pre></p>";
echo "Contact Id is " . $response->result->contactId;

Results

Below displays what those 2 echo statements output.

stdClass Object
(
    [result] => stdClass Object
        (
            [contactId] => 0036000000nVtpTAAS
            [errorMessage] => No errors here.
            [inputs] => Array
                (
                    [0] => stdClass Object
                        (
                            [amount] => 100
                            [productId] => 01t60000000lvBNAAY
                        )
                    [1] => stdClass Object
                        (
                            [amount] => 200
                            [productId] => 01t60000000lvBSAAY
                        )
                )
            [success] => 1
        )
)
Contact Id is 0036000000nVtpTAAS
One last little trick

One annoyance during the development of Apex Web Services is having to continually generate a WSDL for the web service. When testing, I would find that I would continually need to put a new WSDL on the web server. I decided to automate this where I could add a variable to the queryString and have PHP refresh the WSDL on my web server. You need the cURL module for this, but most PHP installs have it.

$ch = curl_init();
	$fp = fopen(_WS_WSDL_, "w");
	curl_setopt($ch, CURLOPT_URL, _WS_ENDPOINT_);
	curl_setopt($ch, CURLOPT_FILE, $fp);
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_COOKIE, 'sid='.$sfdc->getSessionId());
	setcookie("sid", $sfdc->getSessionId(), 0, "/", ".salesforce.com", 0);
	curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	curl_exec($ch);
	fclose($fp);
curl_close($ch);

If you have experience with this kind of integration, please comment here on other tips & tricks.

23 Comments

  1. Calling Web Services from PHP - Mike Simonds Said,

    December 5, 2008 @ 2:33 pm

    […] permalink I just did a blog post on how to call Apex Web Services from PHP. It’s very handy. Calling Apex Web Services from PHP | Perspectives on Salesforce.com […]

  2. Nalini Said,

    February 17, 2009 @ 6:45 am

    Can you explain me how to handle the php files?

  3. Scott Hemmeter Said,

    February 17, 2009 @ 8:50 am

    @Nalini, that’s a huge question. It sounds like you are asking to be taught PHP, which I can’t really do here. I suggest you start with http://www.php.net and go from there.

  4. Nate Schilling Said,

    March 20, 2009 @ 9:08 am

    Thanks for posting this. There are too few examples of using custom apex classes via the web services api or php soap.

    Question: I’ve defined the following web service:

    WebService static String sayHelloWorld( String arg, String arg2 ) {
    return ‘Hello ‘ + arg + ‘ and ‘ + arg2;
    }

    which I call with the following parameters:
    $params = array(‘arg’=>’nate’,’arg2’=>’oscar’);
    $helloresult = $client->sayHelloWorld($params);

    But the second parameter comes across as null:
    stdClass Object
    (
    [result] => Hello nate and null
    )

    Any ideas what I’m doing wrong?

    Many thanks in advance,

    Nate

  5. Scott Hemmeter Said,

    March 20, 2009 @ 9:36 am

    @Nate, nothing is jumping out at me. Maybe make sure your WSDL file is refreshed so it knows about the second parameter? Just a thought.

  6. Jeff Douglas Said,

    April 2, 2009 @ 8:16 am

    Thanks for the hard work! You saved me a gazillion hours!

  7. Using PHP to call an Apex Web Service « Jeff Douglas - Technology, Coding and Bears… OH MY! Said,

    April 5, 2009 @ 3:55 pm

    […] in my PHP scripts so I whipped up a quick Apex class and exposed it as a web service. I found a great blog post by Scott Hemmeter that really helped me out calling the service with PHP so I thought I would share the code and […]

  8. Stephen Said,

    May 8, 2009 @ 8:39 am

    Scott, this is fantastic, guided me on the right path to getting Apex calls via PHP working!

    One thing to add – as you say, during dev you generally re-gen the WSDL file on multiple occasions as classes/params are changed – I was getting a SOAP fault error “Violation of encoding rules” and couldn’t figure it out – I was certain I had the right inputs/outputs. Turns out that my WSDL file was being cached on the PHP server, and was several versions out of date – I recommend using the following lines prior to creating the SoapClient instance, while developing:


    ini_set(‘soap.wsdl_cache_enabled’, ‘0’);
    ini_set(‘soap.wsdl_cache_ttl’, ‘0’);

    This will ensure that you’re always on the version of the WSDL that you think you are!

    Thanks again,
    Stephen

  9. WSDL WebServices for Salesforce using PHP - Tech Thought Said,

    December 13, 2009 @ 1:01 am

    […] nightmare.  However, there are a few useful blog posts around that can make life easier.  One is here, which takes you through creating a webservice on Salesforce and then accessing it via PHP calls […]

  10. Mike Simonds Said,

    December 22, 2009 @ 2:01 pm

    Scott,

    I tried this out but I am getting an error. PHP is not able to load the wsdl file generated from the APEX class that you created > MyWebService.xml

    Do I need to download that first from the Class in my Org and place it on my server or is the CURL supposed to get the class prior to the code actually working.

    If you could please contact me and let me know, I would appreciate it!

    ~Mike

  11. Scott Hemmeter Said,

    December 22, 2009 @ 2:17 pm

    The cURL code is supposed to retrieve it dynamically. Make sure that the cURL code is actually running and that you have named your webservice properly. Feel free to post code back here or to start a thread on your forums and link to it as a new comment here. We can then handle the back and forth there if that’s easier.

  12. Scott Hemmeter Said,

    December 22, 2009 @ 2:23 pm

    @Mike,

    Oh, I think I see now. I am not hosted the class for you. You need to have that class in your org and need to set security on it to your profile. Via the login connection to your org, the code will dynamically figure out the path to the WSDL. Does that help?

  13. Arrowpointe tutorial help with web services and PHP - Mike Simonds Said,

    December 22, 2009 @ 2:28 pm

    […] this would be an easier place to post the issues that I was having. The tutorial that you posted, Calling Apex Web Services from PHP | Perspectives on Salesforce.com, well I actually was able to get it to work somewhat. The cURL is actually working now. What I am […]

  14. Mike Simonds Said,

    December 22, 2009 @ 2:29 pm

    okay done sir!!

    http://www.mikesimonds.com/arrowpointe-tutorial-help-web-services-and-php-t190.html

    Thanks for the help!!

    ~Mike

  15. Sergiu Said,

    February 25, 2010 @ 2:22 pm

    Hi Scott,

    Your article was of great help! However, I’m having some problems understanding the curl part.
    1. Where does that code go into the php file? Could you post the end-to-end php code?
    2. can curl be used to update the web service wsdl file as well as the partner wsdl file? If so, this would eliminate any potential problems when those files are updated by sfdc because of a new release etc. Right?

    Thank you again!

  16. Scott Hemmeter Said,

    February 26, 2010 @ 11:52 am

    Sergiu,

    1) you can put that code anywhere in the PHP file. I personally put it in an IF statement that looks for a certain $_GET parameter to get passed in.

    2) You really never need to update the partner wsdl, so don’t worry about that. I use the cURL to update the web service wsdl. This really only matters during development. Once done with development, your WSDL will never really change.

  17. Using Salesforce Outbound SOAP Messages with PHP Said,

    October 21, 2010 @ 1:25 pm

    […] Entries15 if you look in the code on this page > Calling Apex Web Services from PHP | Perspectives on Salesforce.com There is some examples of how to use the session Id, but I have never used it man, sorry I hope […]

  18. Aurélien Said,

    November 4, 2010 @ 2:11 am

    How can we use the SforceEnterpriseClient.php instead of SforcePartnerClient.php ?
    I got this error message with SforceEnterpriseClient.php: “Ooop! Error: Element {}item invalid at this location”.

    Thank you.

  19. Aurélien Said,

    November 4, 2010 @ 3:46 am

    Sorry for my previous comment it works fine with SforceEnterpriseClient.php

  20. Orlando Orellano Said,

    January 13, 2011 @ 9:28 am

    Hi Scott,

    Thank you so much for your example!

    I’m almost there to have my WS working.

    While I’m trying to make: $client = new SoapClient(_WS_WSDL_);
    I’m getting the next error:
    Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn’t load from ‘AmICoveredWebService.xml’ : failed to load external entity “AmICoveredWebService.xml” in /srv/sites/omnipod/www/am-i-covered/index.php:29 Stack trace: #0 /srv/sites/omnipod/www/am-i-covered/index.php(29): SoapClient->SoapClient(‘AmICoveredWebSe…’) #1 {main} thrown in /srv/sites/omnipod/www/am-i-covered/index.php on line 29

    Any ideas of what I’m missing?

    Thanks in advance,
    Orlando

  21. Lee Said,

    February 4, 2011 @ 2:08 pm

    @Orlando: I just downloaded the wsdl and called it locally.

    $client = new SoapClient(‘./LeesService.wsdl’);

    I got a weird error about “unexpected ” when I downloaded the WSDL in Chrome. FF worked though. Drove me nuts.

  22. phaniraj Said,

    May 15, 2012 @ 11:50 pm

    Hi scott…

    I want to transfer the attachments from salesforce to my another server. I wanted to a FTPing in apex, which i tried hard but couldnt get results, now i am thinking to call a PHP webservice from Salesforce. I know hot to call SF from PHP from the great post you have posted. How could i do it in reverse way???

  23. Scott Hemmeter Said,

    May 16, 2012 @ 10:48 am

    you’ll want to do an HTTP callout to the PHP server and send the document over as a BLOB, I believe.

RSS feed for comments on this post