1

UPDATE

I created the below answer which allows you to use a REST application connection to (from there on) work on the SOAP API without needing to use SOAP's Login method, but instead relies completely on access_token and REST generated URLS to work.

/UPDATE

Hey guys I'm trying to switch gears from REST to SOAP after finding that the RESTful API isn't flexible enough to do exactly what I need to do with it, I am currently trying to migrate a few things into the SOAP request to get this going but am running up against a wall.

I currently have users authorizing an application via REST, and returning Bearer and Access tokens, the step to use those (and the Location URL) are evading me though. I'm hoping that I can use my initial REST request to fuel my SOAP api.

This would mean that there is NO Username/Password sequence from here on!

I've been trying to implement multiple things that I've seen in the Java service, but it looks like they aren't supported in the PHP distro? Here's the code, maybe someone can point me in the right direction.

<?php 
// clear wsdl cache
ini_set("soap.wsdl_cache_enabled", 0);
?>

<pre>
<?php
    define("SOAP_CLIENT_BASEDIR",   'soapclient');

#    define("SF_USERNAME",           'foo@foodomain.com');
#    define("SF_PASSWORD",           'password');
#    define("SF_SECURITY",           ''); // shouldn't be needed after Auth Bearer

#    define("SF_LOCATION",           'https://na15-api.salesforce.com/services/Soap/u/27.0/?????');
#    define("SF_SESSIONID",          '??????');

    define("SF_LOGINURL",         'http://login.salesforce.com');

require_once (SOAP_CLIENT_BASEDIR.'/SforcePartnerClient.php');
require_once (SOAP_CLIENT_BASEDIR.'/SforceHeaderOptions.php');

try {

/**
 *   This section should theoretically be taken over by REST Auth Bearer
 *   so we do not need to use a U/P sequence for clients after accepting 
 *   our application.
 *
 *   $mySforceConnection = new SforcePartnerClient();
 *   $mySoapClient       = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/partner.wsdl.xml');
 *   $loginResult        = $mySforceConnection->login(SF_USERNAME, SF_PASSWORD.SF_SECURITY);
 *
 *   $location    = $mySforceConnection->getLocation();
 *   $sessionId   = $mySforceConnection->getSessionId();
 */


    $mySforceConnection     = new SforcePartnerClient();
    $sforceSoapClient       = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/partner.wsdl.xml');


        // broken; is not available in PHP distro ??
        $mySforceConnection->setAuthEndpoint(SF_LOGINURL);      // does not exist....
        $mySforceConnection->setServiceEndpoint(SF_LOGINURL);   // does not exist....
        $mySforceConnection->setManualLogin(TRUE);              // does not exist....


    // try
    $globals = $mySforceConnection->describeGlobal();

    $query = "SELECT Id,Name FROM User";
    $response = $mySforceConnection->query($query);
    #    $queryResult = new QueryResult($response);
    #    print_r($queryResult);


    $sObject = new SObject($response->records[0]);
    print_r($sObject);

    /** Expected Output:
     *  Should be as follows

        SObject Object
        (
            [type] => User
            [fields] => stdClass Object
                (
                    [Id]    => ?????
                    [Name]  => foo bar 
                )
        )
    */

} catch (Exception $e) {
  echo $mySforceConnection->getLastRequest();
  echo $e->faultstring;
}
  • Hmm, might be an easy one - you do need the Security Token. Only if you have added your IP address as a trusted network can it be omitted. – bigassforce Mar 18 '13 at 20:20
  • 1
    @user320 I believe the Security Token is only needed if you are authenticating with the username and password (+ trusted network settings as you say). I think the idea in this question is to get a valid SessionId to bypass the un/pw/st requirement. I know how to do this with C#, but php isn't my strong point. – Daniel Ballinger Mar 18 '13 at 20:31
  • What @DanielBallinger said is correct. I believe if I use $var->setEndpoint() and $var->setSessionHeader() I can bypass the whole shenanigans of requiring anything that is login related. Unfortunetly ConnectorConfig() is a Java Only class, which doesn't allow me a whole lot of flexibility. – ehime Mar 18 '13 at 20:32
0

Your code shows you've really tried a lot of stuff - I gave it a go but it looks like it might be expecting a different version of the PHP toolkit, there are methods missing etc...

First, can you try this?

  1. download a brand new version of the Force.com Tookit for PHP,

  2. freshly generate your enterprise WSDL from Setup > Develop > API and save it alongside,

  3. put this minimal snippet in a test file (with your username, password, token) and run it:

    define('USERNAME',       'derp@example.com');
    define('PASSWORD',       'd123456h');
    define('SECURITY_TOKEN', 'fWyABCDQIC81ld5IiOR481234');
    
    require_once 'soapclient/SforceEnterpriseClient.php';
    $mySforceConnection = new SforceEnterpriseClient();
    $mySforceConnection->createConnection('enterprise.wsdl.xml');
    $mySforceConnection->login(USERNAME, PASSWORD . SECURITY_TOKEN);
    
    //extract the Server URL and Session ID (and don't EVER use regexp for this ;-)
    $server_pattern  = '#<serverUrl>(.+)</serverUrl>#';
    $session_pattern = '#<sessionId>(.+)</sessionId>#';
    preg_match($server_pattern,  $mySforceConnection->getLastResponse(), $servers);
    preg_match($session_pattern, $mySforceConnection->getLastResponse(), $sessions);
    var_dump('Server URL: ' . $servers[1]);
    var_dump('Session ID: ' . $sessions[1]);
    

Second, in a separate script:

  1. copy the above Server URL and Session ID into setEndPoint and setSessionHeader like so:

    require_once 'soapclient/SforceEnterpriseClient.php';
    $mySforceConnection = new SforceEnterpriseClient();
    $mySforceConnection->createConnection('enterprise.wsdl.xml');
    $mySforceConnection->setSessionHeader('00Dd0000000GHJK!12345678901z6c5Ghg...');
    $mySforceConnection->setEndPoint('https://na14-api.salesforce.com/...');
    
  2. now perform your query as normal

    $query = 'SELECT Id, Name FROM User ORDER BY ID DESC LIMIT 1 ';
    $response = $mySforceConnection->query($query);
    var_export($response->records[0]);
    
    /**
     * stdClass::__set_state(array(
     *   'Id'   => 005d0000001vfmqAAA,
     *   'Name' => 'Derp Herpinson',
     * ))
     */
    

At this point you are working with the Session ID and not the credentials.

  • I created my own version from the Github stub. Its currently placed on top of v27.0 of the API spec. – ehime Mar 18 '13 at 20:47
  • Yeah the above works fine and always has, both on enterprise and partner. The issue is I'm trying to move passed login via the WSDL, its company policy we can't hold un/pw of clients. – ehime Mar 18 '13 at 20:49
  • Pardon @ehime, there's a second part... – bigassforce Mar 18 '13 at 21:14
  • 1
    use the 2nd set of calls (setSessionHeader / setEndpoint) using the values you got from the OAuth flow. – superfell Mar 19 '13 at 17:03
  • 1
    not sure what you mean by custom_endpoint, the Oauth/Id service includes URLS for most endpoints, including the SOAP API ones. – superfell Mar 19 '13 at 21:12
-1

This will correctly use REST application authorization to bypass SOAPs a login mechanism, allowing you to issue a Rest application that can be used from there on as a SOAP mechanism. Please note that this is NOT an OO solution, and just a spaghetti code proof in concept that can easily be refined through a litte bit of code reuse.

<?php 
// clear wsdl cache
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('soap.wsdl_cache_ttl', 0);

    // definition list
    define("SOAP_CLIENT_BASEDIR",   'soapclient');
    define("SOAP_CLIENT_VERSION",   'v27.0');

    define("REST_AUTH_URL",         'https://login.salesforce.com/services/oauth2/token');

    define("DATA_CLIENT",           'XXXXXXXXXXXXXXXXXXX');
    define("DATA_SECRET",           'XXXXXXXXXXXXXXXXXXX');

    define("SF_USERNAME",           'foo@domain.com');

    define("PDO_HOST",              'localhost');
    define("PDO_USER",              'XXXXXXXXXXXXXXXXXXX');
    define("PDO_PASS",              'XXXXXXXXXXXXXXXXXXX');
    define("PDO_NAME",              'DATABASE');

    define("PDO_TABLE",             'TABLE');

require_once (SOAP_CLIENT_BASEDIR.'/SforcePartnerClient.php');
require_once (SOAP_CLIENT_BASEDIR.'/SforceHeaderOptions.php');

    header('Content-Type: text/plain');

    // get base information
    try {

        $sql = sprintf("SELECT sm_uid AS SF_UID, access_token AS SF_SESSIONID, instance_url AS SF_LOCATION, refresh_token AS SF_REFRESH FROM %s WHERE sm_acct_email='%s'", PDO_TABLE, SF_USERNAME);
        $pdo = new PDO('mysql:host=' . PDO_HOST . ';dbname=' . PDO_NAME, PDO_USER, PDO_PASS, array(PDO::ATTR_AUTOCOMMIT => FALSE));

        foreach ($fetch = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC) as $row) 
        {
            foreach ($row as $key => $value) {
                define($key, $value);
            }
        }

    } catch (PDOException $e) {

        echo "REQUEST:\n" . $mySforceConnection->getLastRequest() . "\n";
        echo $mySforceConnection->getLastRequest();
        echo $e->faultstring;

    }


    // get SID via refresh token
    try {
        $data = http_build_query(array(
          'grant_type'    => 'refresh_token',
          'client_id'     => DATA_CLIENT,
          'client_secret' => DATA_SECRET,
          'refresh_token' => SF_REFRESH,
        ));

        $ch     = curl_init(REST_AUTH_URL);

        curl_setopt_array($ch, array(
          CURLOPT_POST           => 1,
          CURLOPT_POSTFIELDS     => $data,
          CURLOPT_SSL_VERIFYPEER => 0,
          CURLOPT_RETURNTRANSFER => 1,
        ));

        $data = curl_exec($ch);
        $obj  = json_decode($data, false);
        curl_close($ch);

    } catch (CurlException $e) {

        print_r($e); die(__LINE__);

    }


    // set current endpoints via fresh SID
    try {
        $ch     = curl_init($obj->id);

        curl_setopt_array($ch, array(
          CURLOPT_HEADER         => 0,
          CURLOPT_FOLLOWLOCATION => 1,
          CURLOPT_RETURNTRANSFER => 1,
          CURLOPT_HTTPHEADER     => array(
            'Authorization: Bearer '. $obj->access_token,
          ),
        ));

        $data = curl_exec($ch);
        $arr  = json_decode($data, true);
        curl_close($ch);

        $fresh = New stdClass();
        foreach ($arr['urls'] as $key => $value)
        {
            $fresh->$key = str_replace('{version}', SOAP_CLIENT_VERSION, $value);
        }
    } catch (CurlException $e) {

        print_r($e); die(__LINE__);

    }


    // make the connection to SOAP services from RESTful connector 
    try {
        $mySforceConnection     = new SforcePartnerClient();
        $sforceSoapClient       = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/partner.wsdl.xml');

        $mySforceConnection->setSessionHeader(SF_SESSIONID);
        $mySforceConnection->setEndPoint($fresh->partner);

        $response = $mySforceConnection->getUserInfo();
        print_r($response);

        die('foo');

    } catch (ConnectorException $e) {

        echo "REQUEST:\n" . $mySforceConnection->getLastRequest() . "\n";
        echo $mySforceConnection->getLastRequest();
        echo $e->faultstring;

    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.