Soap Web Services in PHP & hint on consuming from .Net

last week, I was working on implementing a SOAP server for one of our projects at work, this web service was built to be consumed by some other software that is built using .Net . It wasn’t that easy and I faced some problems that made me go crazy for some hours and I wanted to share them here with the solutions. let me first show you how I built the web service in PHP.

by the way, This project was built using CakePHP, but the web service I made doesn’t depend that much on that framework except that I use its MVC implementation.

If we want to build a SOAP web service, we will need first to create a WSDL file and make it accessible from a defined URL. I made a new controller with a new action named [index] that will return the WSDL file when requested using GET, and will also handle SOAP requests when requested using POST.

<?php

class SoapController extends AppController
{

    /**
     * handles SOAP requests
     */
    public function inedx()
    {

        if ( $this->RequestHandler->isGet() ) { //just show the wsdl
            $this->RequestHandler->respondAs('xml');
            echo self::_getWsdlContent();
            return;
        }

        $soapServer = new SoapServer( Configure::read('soap.wsdlFilePath') );

        $soapHandler = new Shreef_WebService_SoapHandler( /* Inject Dependencies here */ );

        $soapServer->setObject($soapHandler);

        $soapServer->handle();

    }

    /**
     * gets WSDL content for the SOAP service
     */
    protected static function _getWsdlContent()
    {
        $fileName = Configure::read('soap.wsdlFilePath');

        if (file_exists($fileName) ) {
            return file_get_contents($fileName);
        }

        $soapAutodiscover = new Zend_Soap_AutoDiscover( );

        $wsdlContent = $soapAutodiscover
                        ->setClass('Shreef_WebService_SoapHandler')
                        ->toXml();

        file_put_contents($fileName, $wsdlContent);
        return $wsdlContent;
    }

}

as you see, I’m dynamically generating the WSDL file using Zend_Soap_AutoDiscover. and caching it into a file. Zend_Soap_AutoDiscover will read the DocBlocks defined in Shreef_WebService_SoapHandler to build the WSDL file.

Notice that I gave SoapServer an instance of Shreef_WebService_SoapHandler instead of giving it the name of the class. this will give me the chance to inject any needed dependencies into the constructor.

here is my SoapHandler class with a simple method [getCurrentTime()] that will return a String, and another method [doSomething()] that returns Array.

<?php

class Shreef_WebService_SoapHandler
{

    /**
     * construct
     */
    public function __construct()
    {
        /** Dependency Injection happens here **/
    }

    /**
     * returns the current server time formated like YYYYMMDDhhmmss
     *
     * @return String
     */
    public function getCurrentTime()
    {
        return date('Ymdhis');
    }

 
    /**
     * do something
     *
     * @param String $something
     * @return Array
     */
    public function doSomething($something)
    {
        return array(1, 2, 3);
    }
  
    /** other methods **/
}

and that’s it, now if I open http://localhost/soap in my browser, I will see the WSDL. then I can use that WSDL to make requests to the web service. this was working fine on my machine and on the testing server, but it started to go crazy when we deployed that to the staging server. all methods returned null.

DocBlocks and OpCode caching

After some hours I noticed that the generated WSDL on the staging server was different than what was generated on my machine and on the testing server. there were no Out messages and the type of all method parameters was set to “anyType”. at first, I thought that this is a bug in Zend_Soap_AutoDiscover, but later I commented out the lines that cache the generated WSDL to a file and started to change things around.

I noticed that whenever I make a change to the file that contains the SoapHandler, the WSDL gets generated like expected for one time, but if I open the URL of the WSDL again, it will go back to generate the wrong WSDL. and here we have another “Aha!!” moment.

We have eAccelerator installed on that server. it is doing opcode caching for all the PHP code. this means that after every modification to the file that contains the SoapHandler class, the class is read from the file with all the DocBlocks, but in the next request, SoapHandler classs will get read from the opcode cache with all DockBlocks removed. so Zend_Soap_AutoDiscover won’t find DocBlocks to read and will guess that all methods are void and all method parameters are of type “anyType”.

As stopping eAccelerator doesn’t make sense, I turned on the WSDL file caching again and ran the “touch” command on all files that contain code that should get described in the WSDL ( the soap handler and any other complex types used ). this will make the WSDL get generated well the first time and cached.

I have to automate this later using a shell script or something.

.Net and Soap Arrays

The second problem was that Visual Studio.net was refusing to generate the required proxy classes using that WSDL file. It didn’t understand the type “Array”. I searched for this problem, and it looked like that were no way to make VS.net understand it. I solved that by instead of returning values of type Array, I changed my code a bit to return a complex type.

Also, I had to tell Zend_Soap_AutoDiscover that I want to use another WSDL strategy by passing the string ‘Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex’ to its constructor.

SK Demo Day 2 roundup

WARNING: this is a long post. I had plenty of time to write it while I was on my way back to Alexandria . enjoy.

It was a nice day. the sessions were great and meeting people like Mohammed Hossam, Amr Sobhy, Mohamed Tanna and Mohamed Meligy is more than great. I didn’t have the chance of attending Mohammed Hossam’s SOA session from the beginning (read the previous post). Amr was there from the beginning and he said that it was very good and that he liked how M.Hossam presented it.

the 2nd session I attended was about SilverLight . it was a beginners introduction of what you can do using this new technology . it left me hungry for more information …

the 3rd one was about SEO by M.Meligy. the contents were great like expected . mostly, I get bored so fast , but how Meligy moves and talks on the stage succeeded to keep my eyes opened till the end of the session.

the 4th one was “CLR by XAML” by Hossam Zain. It was great and added  more to what we saw in the SilverLight session. Amr didn’t attend this session, he went to the “LINQ for XML” one by Mai Soliman. we wondered if this was her first public talk (I know this feeling).

the 5th was “IronPython and C# 3.0, a dialog” by Mohamad Tayseer and Mohammed Hossam. it was one of the best sessions I attended in this day.

the 6th was the open mic session. all of the attendees were allowed to talk. SK guys managed the talk to the way of why some people use .net while others use Java and others like me use php for web development. then it went to be about why most of software and websites innovations were born in the open source community, taking sample like how FaceBook uses php (why they chose it?). then Dudy tried to change the direction of the conversation to be about which is the most important from your perspective? innovation, idea, technology or what ?

the first guy to talk from the attendees started by defending .net against Java and talking about how every thing he wants is already in .net, while he believes that some other people will like to use Java to save some money and he didn’t see this as a bad thing.
some other guy took the mic and started to talk about that we shouldn’t be depending on one platform as we don’t know what the companies will like to use more in the future, so we have to be ready for a day like that.
then Mohammed Hossam started to narrow the scope of the conversation to make the talk about web development specially. why there is php, python, .net and java? why some people choose one over another. some ex-php developers who moved to .net started to talk about how rich and powerful is the .net platform than php.
at this time I got the courage to talk. I went to the stage and took the mic and looked at the attendees, and Bang!!, I forgot the points I was going to talk about and what the previous guy said. I had to make up something to talk about in less than 3 seconds so I can look less stupid. I quoted something that I don’t really remember who said it, maybe Wez Furlong. I said “in php, the community creates what’s needed, we innovate by our selves. the .net guys, will wait till Microsoft innovates”.
I went back to my seat and tried to remember what I was going really  to talk about and didn’t give very good attention to what the others said after that.

at the end of the session, I remembered the stupid points again but there were no time. anyway, the points were:

– ask the attendees: how many web developers here?
# main point: the difference between how most of the ASP.net and PHP developers think.
– ask the attendees: who uses JS tools like YUI, JQuery, Prototype?
– ask the attendees: who uses or cares about
    – web usability?
    – web pages accessibility? (who knows what’s the accessibility here and who cares about that?)
    – web standards?
– who knows what’s microformats?
# main point : why open source community innovates while .net isn’t?
– the open source community cares about more low level details.
– we know the ins and outs of our tools
– we created it
– we know why it was created
– we share ideas

I learned that a pin and paper should be always my friends, specially in situations like that. so learn from my fault and write what you are going to talk about on some paper before asking for the mic. I saw other people in the session who forgot every thing after taking the mic.

the next session is “In-depth JavaScript” by M.Meligy. he talked about JavaScript and Managed JavaScript. I title it as one of the best too.

I rate all the day: Very Good. I will be willing to attend the next Demo Day -en sha2 Allah- :-)