Skip to Content
This weblog provides a simple implementation that uses both SAPRFC and PHP SOAP to get the list of active users on a target system. You might recognize the output as being similar to SM04.

PHPRFC

PHPRFC is a sourceforge project (http://saprfc.sourceforge.net/) that provides an RFC interface to SAP Function Module in PHP. Instructions on how to setup your system for SAPRFC are covered in the weblog Getting started with PHP.

PHP SOAP

With the release of PHP5 SOAP is now available as an extension.

You can find a nice critique of the SOAP extension by IBM.

The following sample script implements both an SAPRFC call and a SOAP call to the function module TH_USER_LIST. The active users determined from both calls are displayed in result tables.

Prerequisites

The function module TH_USER_LIST is already remote enabled so the RFC connection should be no problem. For the SOAP connection you need to make sure that the service is activated in SICF (soap and wsdl11).

You must have PHP5 installed and the corresponding SAPRFC. It is important that the version numbers match. For this example I have installed PHP5.03 and the matching saprfc-1.3.3-5.0.3.Win32.zip (assuming windows).

Source Code

This is a self contained script that implements the same call using both the PHP5 SOAP extension and SAPRFC.

This is an example of getting the user list similar to the transaction SM04.

The example first get the data using SAPRFC and then using the PHP5 SOAP extension. “ld0108.wdf.sap.corp”, “SYSNR”=>”18”, “CLIENT”=>”220”, “USER”=>”ASTILL”, “PASSWD”=>”Password”, “R3NAME”=>”LSR”, “GROUP”=>”PUBLIC”, “LANG”=>”EN”, “CODEPAGE”=>”1100”); // Open the connection to the R/3 Server $rfc = saprfc_open ($login ); if (! $rfc ) { echo “RFC connection failed
“; } else { //Discover interface for function module TH_USER_LIST $fce = saprfc_function_discover($rfc,”TH_USER_LIST”); if (! $fce ) { echo “Discovering interface of function module failed”; exit; } //Fill internal tables saprfc_table_init ($fce,”LIST”); //Do RFC call of function TH_USER_LIST, for handling exceptions use saprfc_exception() $rfc_rc = saprfc_call_and_receive ($fce); if ($rfc_rc != SAPRFC_OK) { if ($rfc == SAPRFC_EXCEPTION ) { echo (“Exception raised: “.saprfc_exception($fce)); } else { echo (saprfc_error($fce)); exit; } } //Retrieve export parameters $rows = saprfc_table_rows ($fce,”LIST”); echo “

“; echo “”; for ($i=1;$i<=$rows;$i++) { $LIST[] = saprfc_table_read ($fce,”LIST”,$i); } // Get a key value pair for each row while(list($num,$row) = each($LIST)) { // Extract the variables from the array into the current symbol table extract($row); echo “”; } echo “

Count Client Username TID Time Terminal Type
$num $MANDT $BNAME $TID $ZEIT $TERM $TYPE

“; saprfc_function_free($fce); saprfc_close($rfc); } flush(); echo “

Now use SOAP to make the call to the Web Service
“; // Same call using the PHP Web Service try { $client = new SoapClient(“wsdl11.xml”, array( “login” => “ASTILL”, ‘trace’ => 1, “password” => “Password”) ); // Create the complex array to match the structure defined in the WSDL. // The function __getTypes() can help describe this structure. $res = array( “LIST” => array( “UINFO”=>array(“TID”=>””, “MANDT”=>””, “BNAME”=>””, “TCODE”=>””, “TERM”=>””, “ZEIT”=>””, “MASTER”=>””, “HOSTADR”=>””, “TRACE”=>””, “EXTMODI”=>””, “INTMODI”=>””, “TYPE”=>””, “STAT”=>””, “PROTOCOL”=>””, “GUIVERSION”=>””, “RFC_TYPE”=>””))); $res = $client->TH_USER_LIST($res); // At this point we have an object. $lst = $res->LIST->item; echo “

“; echo “”; // Get a key value pair for each row while(list($num,$row) = each($lst)) { // Extract the variables from the array into the current symbol table echo “”; } echo “

Count Client Username TID Time Terminal Type
$num $row->MANDT $row->BNAME $row->TID $row->ZEIT $row->TERM $row->TYPE

“; } catch (SoapFault $exception) { echo “

Exception
“; echo $exception; echo “

Request :
“, htmlspecialchars($client->__getLastRequest()), “
“; echo “Response :
“, htmlspecialchars($client->__getLastResponse()), “
“; } ?>

If both calls were successful you will see that the connection for the user differs in type. Type 32 for the RFC call and type 202 for the Web service.

Implementation Details

For both approaches it is fairly simple to create the initial connection.
For SAPRFC an array (PHP uses arrays for complex structures) is created containing all the connection details, this is used in the open call.

$login = array ( "ASHOST"=>"ld0108.wdf.sap.corp", "SYSNR"=>"18", "CLIENT"=>"220", "USER"=>"ASTILL", "PASSWD"=>"Password", "R3NAME"=>"LSR", "GROUP"=>"PUBLIC", "LANG"=>"EN", "CODEPAGE"=>"1100"); // Open the connection to the R/3 Server $rfc = saprfc_open ($login );

For the SOAP approach I have used the wsdl from the Web Service Browser. The wsdl file provides a complete interface definition including the connection information. My authentication details and a flag to enable tracing are the only other parameters I pass when creating the client.

$client = new SoapClient("wsdl11.xml", array( "login" => "ASTILL", 'trace' => 1, "password" => "Password") );

The wsdl file for a remote enabled function module is available from the Web Service browser. In the browser you can search for the Web Service for the remote enabled function modules.
image
From the result list the wsdl for the service can be retrieved. For the sake of simplicity I downloaded the wsdl file and used the local copy (installed in the same directory as the script) in my example.

Now that we have the connections we need to make the calls to the remote system. SAPRFC provides the function saprfc_function_discover to make the job of defining the interface simpler, unfortunately for the SOAP interface in 5.0.3 it is necessary to create the interface by hand even though this information is available from the wsdl file. Maybe in a future release this will be simplified.

// Create the complex array to match the structure defined in the WSDL. // The function __getTypes() can help describe this structure. $res = array( "LIST" => array( "UINFO"=>array("TID"=>"", "MANDT"=>"", "BNAME"=>"", "TCODE"=>"", "TERM"=>"", "ZEIT"=>"", "MASTER"=>"", "HOSTADR"=>"", "TRACE"=>"", "EXTMODI"=>"", "INTMODI"=>"", "TYPE"=>"", "STAT"=>"", "PROTOCOL"=>"", "GUIVERSION"=>"", "RFC_TYPE"=>"")));

For the masochists among us, SAPRFC also offers the option to create the interface details by hand rather than using the discover option.
The data returned from the call comes back in different formats. SAPRFC sticks with complex arrays, whereas SOAP combines objects and arrays for its return type. Both approaches are simple enough.
During development, to help things along, it may be useful to dump the return value to the display. This will allow you to determine how the return structure of the call has been mapped to PHP and subsequently implement the client side code more easily. I used the print_r() function for this to help me understand the structure returned from the SOAP call.

The result tables are almost identical. Looking at the first entry it can be seen that the connection type is different. For the RFC connection we have type 32 and the Web Service we have 202. This is a simple means of identifying how the connection was made.
image
image

Summary

Looking at the two implementations it is immediately obvious that the RFC implementation was easier as the user is not required to determine the complex structure for the LIST array. The implementation shown here also does not give any clue that the RFC code can be automatically generated using the script saprfc_test.php that comes included with SAPRFC.

As a comparison, the RFC implementation was quicker and easier to develop than the SOAP version, however the SOAP version does have the advantage of being compatible with any Web Service that implements the same WSDL. If you know you are always going to use SAP as the target then RFCs may be your choice, but if you are to work in a heterogenous environment then you may prefer to use the SOAP implementation.

Currently SAPRFC supports only Non-Unicode R/3 systems. If you have a unicode environment then until there is unicode support in SAPRFC, SOAP would be your weapon of choice.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Sridhar Karra

    Hello John,<br/>  I am creating the same example which you have provided in ur weblog,but i am getting errors when I run my php script…following is the error which I get<br/><br/>SoapFault exception: SOAP-ENV:Client looks like we got no XML document in C:\websites\FirstPHP\RFCSOAP.php:92<br/>Stack trace:<br/>#0 C:\websites\FirstPHP\RFCSOAP.php(92): SoapClient->__call(‘TH_USER_LIST’, Array)<br/>#1 C:\websites\FirstPHP\RFCSOAP.php(92): SoapClient->TH_USER_LIST(Array)<br/>#2 Sridhar Karra

    (0) 
    1. John Astill Post author
      Hi Sridhar,

      The SOAP Repsonse contains the error message coming back from the service.

      ————
      Response :
      Login failed! Please try again.
      ————

      It looks like you need to check the credentials you are using to login.

      Regards
      John

      (0) 
  2. Jayanta Narayan Choudhuri

    Fantastic article but formatting is unreadable

    I found John Astill’s contribution superb


    His reference to IBM link was very useful

    http://www.ibm.com/developerworks/library/os-phpws/?ca=dgr-lnxw06PHP5soap

    Below is code that actually works 100% and if you run PHP from command line and

    and see output you will understand the innards

    Hopefully this working tested code is nicely visible

    Regards

    jnc Kolkata India

    <?php

    // FUNCTION TH_USER_LIST.

    // *”———————————————————————-

    // *”*”Lokale Schnittstelle:

    // *”  TABLES

    // *”      LIST STRUCTURE  UINFO

    // *”      USRLIST STRUCTURE  USRINFO OPTIONAL

    // *”———————————————————————-

    // B# UINFO User info in SM04

    // TID         UTID       X 10   INT4 Terminal ID

    // MANDT       MANDT      C 03   CLNT Client

    // BNAME       UBNAME     C 12   CHAR User Name

    // TCODE       UTCODE     C 20   CHAR TCODE

    // TERM        UTERM      C 20   CHAR Terminal ID

    // ZEIT        UDTIME     C 08   CHAR Dialog time in SM04

    // MASTER      UMASTER    C 12   CHAR Master

    // HOSTADR     MSHOSTADR  X 04   RAW  Host IP address

    // TRACE       USER_TRAC  X 03   INT1 User trace

    // EXTMODI     UMODE      X 10   INT4 Task Handler: Number of External or Internal Modes

    // INTMODI     UMODE      X 10   INT4 Task Handler: Number of External or Internal Modes

    // TYPE        INT4       X 10   INT4 Natural Number

    // STAT        INT4       X 10   INT4 Natural Number

    // PROTOCOL    INT4       X 10   INT4 Natural Number

    // GUIVERSION  CHAR10     C 10   CHAR Character Field Length = 10

    // RFC_TYPE    CHAR1      C 01   CHAR Single-Character Indicator

    // B# USRINFO                        Extended User Info for SM04

    // TID         UTID         X 10  INT4 Terminal ID

    // MANDT       MANDT      * C 03  CLNT Client

    // BNAME       UBNAME       C 12  CHAR User Name

    // TCODE       UTCODE     * C 20  CHAR TCODE

    // TERM        UTERM        C 20  CHAR Terminal ID

    // ZEIT        UDTIME       C 08  CHAR Dialog time in SM04

    // MASTER      UMASTER      C 12  CHAR Master

    // TRACE       USER_TRAC    X 03  INT1 User trace

    // EXTMODI     UMODE        X 10  INT4 Task Handler: Number of External or Internal Modes

    // INTMODI     UMODE        X 10  INT4 Task Handler: Number of External or Internal Modes

    // TYPE        UEXT_TYPE    X 10  INT4 Type of Logon

    // STAT        USTATE       X 10  INT4 Status of System Logon

    // PROTOCOL    UPROTOCOL    X 10  INT4 Logon Protocol of Plugin

    // GUIVERSION  UGUIVERSI N  C 10  CHAR Version of SAPGUI

    // RFC_TYPE    URFC_TYPE    C 01  CHAR Type of RFC Logon

    // HOSTADDR    NI_NODEAD R  C 45  CHAR IP Address

      $host = “myserver”;

      $sysnr = 00;

      $client = 500;

      $user = “myname”;

      $passwd = “mypassword”;

      $codepage = 1404;

      $login = array ( “ASHOST”=>”$host”,

                       “SYSNR”=>”$sysnr”,

                       “CLIENT”=>”$client”,

                       “USER”=>”$user”,

                       “PASSWD”=>”$passwd”,

                       “CODEPAGE”=>”$codepage”);

      // Open the connection to the R/3 Server

      $rfc = saprfc_open ($login );

      if (! $rfc ) {

        echo “RFC connection failed”;

       }

      else {

        //Discover interface for function module TH_USER_LIST

        $fce = saprfc_function_discover($rfc,”TH_USER_LIST”);

        if (! $fce )  {

          echo “Discovering interface of function module failed”;

          exit;

        }

        //Fill internal tables

        saprfc_table_init ($fce,”LIST”);

        saprfc_table_init ($fce,”USRLIST”);

        //Do RFC call of function TH_USER_LIST, for handling exceptions use saprfc_exception()

        $rfc_rc = saprfc_call_and_receive ($fce);

        if ($rfc_rc != SAPRFC_OK) {

          if ($rfc == SAPRFC_EXCEPTION )  {

            echo (“Exception raised: “.saprfc_exception($fce));

          }

          else {

           echo (saprfc_error($fce));

           exit;

          }

        }

       //Retrieve export parameters

       $rows = saprfc_table_rows ($fce,”USRLIST”);

       print_r($rows);

       $LIST=Array();

       for ($i=1;$i<=$rows;$i++) {

        $LIST[$i] = saprfc_table_read ($fce,”USRLIST”,$i);

       }

       print_r($LIST);

       echo “<table border=1 cellpadding=5>”;

       echo “<tr><th>Count</th><th>Client</th><th>Username</th><th>TID</th><th>Time</th><th>Terminal Type</th></tr>”;

       // Get a key value pair for each row

       while(list($num,$row) = each($LIST)) {

        echo “<tr>”,

        “<td>$num</td>”,

        “<td>”,$row[“MANDT”],”</td>”,

        “<td>”,$row[“BNAME”],”</td>”,

        “<td>”,$row[“TID”],”</td>”,

        “<td>”,$row[“ZEIT”],”</td>”,

        “<td>”,$row[“TERM”],”</td>”,

        “<td>”,$row[“TYPE”],”</td>”,

        “</tr>”;

       }

       echo “</table>”;

       saprfc_function_free($fce);

       saprfc_close($rfc);

    }

    flush();

    // exit;

    echo “Now use SOAP to make the call to the Web Service”;

    // Same call using the PHP Web Service

    try { $client = new SoapClient(

    http://myserver:8000/sap/bc/soap/wsdl11?services=TH_USER_LIST&sap-client=500“,

                                     array( “login” => “myname”,

                                     ‘trace’ => 1,

                                     “password” => “mypassword”) );

       // Create the complex array to match the structure defined in the WSDL.

       // The function __getTypes() can help describe this structure.

        $functions = $client->__getFunctions();

        print_r($functions);

        $types = $client->__getTypes();

        print_r($types);

        $filt = array( “LIST” =>

                         array());

        $out = array( “USRLIST” =>

                         array());

        $res = $client->TH_USER_LIST(Array(“LIST”=>$filt, “USRLIST”=>$out));

        print_r($res);

        echo “Request :<br>”, htmlspecialchars($client->__getLastRequest()), “<br>”;

        echo “Response :<br>”, htmlspecialchars($client->__getLastResponse()), “<br>”;

        // At this point we have an object.

        $lst = $res->USRLIST->item;

        print_r($lst);

        echo “”;

        echo “”;

       echo “<table border=1 cellpadding=5>”;

       echo “<tr><th>Count</th><th>Client</th><th>Username</th><th>TID</th><th>Time</th><th>Terminal Type</th></tr>”;

       // Get a key value pair for each row

       while(list($num,$row) = each($lst)) {

        echo “<tr>”,

        “<td>$num</td>”,

        “<td>$row->MANDT</td>”,

        “<td>$row->BNAME</td>”,

        “<td>$row->TID</td>”,

        “<td>$row->ZEIT</td>”,

        “<td>$row->TERM</td>”,

        “<td>$row->TYPE</td>”,

        “</tr>”;

       }

       echo “</table>”;

    }

    catch (SoapFault $exception) { echo “Exception”;

       echo $exception;

       echo “Request :”, htmlspecialchars($client->__getLastRequest()), “”;

       echo “Response :”, htmlspecialchars($client->__getLastResponse()), “”;

    }

    ?>

    (0) 
  3. Jayanta Narayan Choudhuri

    PHP SOAPCLIENT works well for the default sap-client  and ONLY WSDL 1.1;

    if the user password is for a different client seems to fail

    Say 300 and 600 are 2 SAP-clients and 300 is default

    WSDL for 600 works but with a user belonging to 600

    I cannot login as there is no provision for sap-client in

    $client = new SoapClient(

    $wsdl,

    array( “login” => $user,

             “password” => $passwd ) );

    Works fine if user belongs to 300(default)       

    ===================================================

    PHP SoapClient Does NOT support WSDL 2.0 as generated by ECC6 Wizard

    It only supports WSDL 1.1 as prevailed in 4.7 era; luckily still supported

    Read

    http://phpwebservices.blogspot.in/2008/01/what-is-missing-in-php-soap-extension.html

    http://wso2.com/products/web-services-framework/php/

    WS02 PHP Soap does support WSDL 2.0 but I think it best

    a) to stick to SAP PHP RFC

    b) use SOAPCLIENT WSDL 1.1 route

    It is time for a official SAP PHP that is as good as JCO!

    Is SAP Listening?

    (0) 

Leave a Reply