Skip to Content

The University of Mississippi runs SAP for its business and student systems.

We are early adopters of the NetWeaver Gateway product and are excited about its potential to easily expose and consume content from the SAP ERP environment.  The objective of this post is to illustrate how we overcame the installation and performance related roadblocks we encountered when attempting to consume the Gateway services using PHP from an Apache web server.

Installation of OData

The platform we use for our PHP/Apache hosting is a Unix/Linux environment.

After installing per their instructions, if you are on a unix/linux system, you will receive the following error when trying to generate your proxy class:

PHP Fatal error:  require_once(): Failed opening required ‘Resource\Messages.php’ (include_path=’.:/etc/php5/phplib/ODataphp’) in /etc/php5/phplib/ODataphp/Common/ACSUtil.php on line 17

This error occurs due to improper use of back-slashes as opposed to a more platform independent forward-slash.  To fix this, you can directly modify the ACSUtil.php file in the Common folder.  Starting with line 17, replace the back-slashes with forward-slashes so that the require_once block looks as follows:

Screen Shot 2012-03-28 at 9.37.09 AM.pngThere is one more offending backward-slash that requires attention.  If you run the command to generate your proxy at this point as follows:

php /etc/php5/phplib/ODataphp/PHPDataSvcUtil.php /uri=https://[USER]:[PASS]@[SAPSERVERADDRESS]/sap/opu/sdata/sap/CAMPUSDIRECTORY/ /out=/home/christopher/CAMPUSDIRECTORY.php

You will see the following output:

Done: OData Service Proxy File ‘CAMPUSDIRECTORY.php’ generated at /home/christopher

Unfortunately, the file path and name are not generated correctly, so your file does not exist under that name or in that location.

The tool will output a file in the parent folder of where you requested, with a garbled name.  Since I requested the folder /home/christopher, the proxy was generated and stored in /home as you can see below:

Screen Shot 2012-03-28 at 9.41.07 AM.pngThis is a working and valid proxy file, so you can simply rename it and move it to the appropriate location.

mv christopher
CAMPUSDIRECTORY.php ./christopher/CAMPUSDIRECTORY.php

To fix the OData library so it interprets output paths appropriately, you must modify PHPDataSvcUtil.php in the root folder of the library.  Adjust the command starting with line 127 to match as follows:

Screen Shot 2012-03-28 at 9.42.33 AM.pngYou will now have a working proxy generation procedure that is outputing to the correct filename and path.

A Simple Consumption Example

Our first use of NetWeaver Gateway was to allow our campus website directory to directly search and display results from our SAP system.  Using the same NetWeaver Gateway services we generated a proxy from earlier, we can now achieve our goal.  To test the web services, you can enter the address in a browser and verify the XML response is valid.  For our service, I used the following:

https://[USER]:[PASS]@[URL]/sap/opu/sdata/sap/CAMPUSDIRECTORY/zcm_campus_dir_searchCollection?sap-client=200&$format=xml&$filter=name EQ ‘Reichley’

Note that I am calling “zcm_campus_dir_searchCollection” with the search parameter of “name EQ ‘Reichley”.

The XML response I receive to my browser is the following:

Screen Shot 2012-03-28 at 9.46.11 AM.pngThe elements inside the “<m:properties>” tags will show you the key names you need to access the individual elements within PHP once consumed by the OData library.

Now that we have our service, we simply integrate the proxy we generated in the first step with the OData library.  The following demonstrates one method to iterate through the data and maintain a hash array, people, of each of the results returned by our directory search.

Screen Shot 2012-03-28 at 9.48.10 AM.png(The ODATA_PATH line will be explained in the following section)

At this point, all the SAP data returned has been consumed and resides in a PHP variable.

Performance Tuning and open_basedir

Using our test environment, we were seeing very fast response times.  Pages were loading and returning our directory search results in a second or two.  When we moved to our production environment, which has many user accounts with varying privileges, the average page load for an empty search was 14.3 seconds.  This broke down to 12+ seconds to load the proxy element, and 2 seconds on average for the remaining including the query and response itself.

After some tracing and debugging, we were able to identify that the use of open_basedir in our production system was the element causing the OData library to run slowly.  For each of the require_once PHP calls in the OData library, the system was having to pull the path from the list of system paths and then compare it against the list of open_basedir permitted folders.

To increase the performance, we adjusted the library so that we could define and pass the path from our code as an option.  In the OData library, modify ./Context/ObjectContext.php so that the require_once block starting with line 18 matches the following:

Screen Shot 2012-03-28 at 9.57.10 AM.pngBe sure and add the block shown directly above the require_once section, and add the $FILE_PATH. to all the require_once statements.  This will check for the new define we will create and gracefully handle it if it is not included.

Repeat the above process for the files listed below.  Add “$FILE_PATH.” in each require_once block keeping the original file names for each.

./Common/ACSUtil.php
./Context/ObjectContext.php
./Credential/ACSCredential.php
./Credential/AzureTableCredential.php
./Credential/CredentialBase.php
./Credential/WindowsCredential.php
./Exception/ODataServiceException.php
./Extras/WCFDataServicesEditor.php

The library will now behave as usual, we have just given an extra check so that the user has the option of defining the “ODATA_PATH” manually to increase the speed but it is not required.

The next step is to modify the generated proxy class, which will have to be repeated each time a new proxy is generated.  For this example, our generated proxy class is named “CAMPUSDIRECTORY.php“. Modify this file in the same fashion we did the library as seen below:

Screen Shot 2012-03-28 at 9.56.02 AM.pngThe final step is to update our PHP code that uses the generated proxy so that it defines the OData library path.  Inside of our PHP file, we will add the following define statement above the require_once inclusion of CAMPUSDIRECTORY.php:

Screen Shot 2012-03-28 at 9.55.10 AM.png

Conclusion

With the updates to the library implementation and integration, we were able to reduce the page load time from 14+ seconds to around 2 seconds.  Loading the OData library which was taking 12+ seconds now completes in roughly 1 second and the remaining time is related to the query itself.

There are quite a few other options for defining the ODATA_PATH besides using it within the main PHP file.  We have experimented using .htaccess files to define this value as well, but this method was not as strong a fit for our configuration.

To report this post you need to login first.

4 Comments

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

  1. Gregor Wolf
    Hi Christopher,

    thank you for testing OData with PHP and informing us how to get rid of the first road blockers. I haven’t seen a link in your blog, but I assume that you’re talking about the OData SDK for PHP project. Have you created an issue there describing all the problems you’ve found? It would be a lot better to get the problems fixed at the original source.

    Best regards
    Gregor

    (0) 
  2. Anton Wenzelhuemer
    Thanks for this nice blog to help people get going with PHP.

    I can add a funny experience I made myself when I did first try this:

    The service document I created the proxy for, contained an entity called “Return”. The proxy generator bravely created class for it called Return, which , you guess it, is a keyword in PHP and therefore leads to errors.

    The simple solution ofcourse is to rename the class and all calls to it.

    I hadn’t had time to check if the generator has a list of keywords to check against and “return” was just missing or if this isn’t the case.

    anton 

    (0) 
    1. Anton Wenzelhuemer
      for everyone’s amusement you may try to find out, how many error the following program has 😉

      class Return {
      public $return;

      public function return (){
      $return = “Return”;
      return $return;
      }
      }
      $Return = new Return();
      $return = $Return->return();
      echo $return;
      ?>

      (0) 

Leave a Reply