Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: PHP SOAP vs Zimbra

  1. #1
    Join Date
    Nov 2006
    Posts
    6
    Rep Power
    8

    Default PHP SOAP vs Zimbra

    Using PHP5's SOAP classes I have so far been unable to make a successfull call to my Zimbra installation and I was wondering if someone could point me in the right direction.

    Generated soap request is:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="zimbraAdmin" xmlns:ns2="zimbra">
    <SOAP-ENV:Header>
    <ns2:context>
    <nonotify/>
    <noqualify/>
    </ns2:context>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
    <ns1:AuthRequest>
    <name>
    admin@mworks.com.my</name>
    <password>
    mypassword</password>
    </ns1:AuthRequest>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    The response I get is:
    Code:
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
    <soap:Fault>
    <soap:faultcode>
    soap:Client</soap:faultcode>
    <soap:faultstring>
    unknown document: ns1:AuthRequest</soap:faultstring>
    <soap:detail>
    <Error xmlns="urn:zimbra">
    <Code>
    service.UNKNOWN_DOCUMENT</Code>
    <Trace>
    com.zimbra.cs.service.ServiceException: unknown document: ns1:AuthRequest
    at com.zimbra.cs.service.ServiceException.UNKNOWN_DOCUMENT(ServiceException.java:145)
    at com.zimbra.soap.SoapEngine.dispatchRequest(SoapEngine.java:218)
    at com.zimbra.soap.SoapEngine.dispatch(SoapEngine.java:163)
    at com.zimbra.soap.SoapEngine.dispatch(SoapEngine.java:84)
    at com.zimbra.soap.SoapServlet.doPost(SoapServlet.java:228)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
    at com.zimbra.cs.servlet.ZimbraServlet.service(ZimbraServlet.java:154)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
    at java.lang.Thread.run(Thread.java:595)
    </Trace>
    </Error>
    </soap:detail>
    </soap:Fault>
    </soap:Body>
    </soap:Envelope>
    If it helps my php code is:
    Code:
    $soapClient = new SoapClient(null, array('location' => 'https://192.168.0.199:7071/service/admin/soap/',
                                             'uri'      => 'zimbraAdmin',
                                             'trace'    => 1,
                                             'version'  => SOAP_1_1,
                                             'style'    => SOAP_RPC,
                                             'use'      => SOAP_DOCUMENT
                                             ));
    
    class Context
    {
        var $nonotify = null;
        var $noqualify = null;
    }
    $soapHeader = new SoapHeader('zimbra',
                                 'context',
                                 new Context());
    $soapClient->__soapCall("AuthRequest", 
                                        array(
                                            new SoapParam('admin@mworks.com.my', 'name'),
                                            new SoapParam('mypassword', 'password')
                                            ),
                                        null,
                                        $soapHeader);

    Sorry for the long post and thanks in advance for any help.

  2. #2
    Join Date
    Nov 2006
    Posts
    6
    Rep Power
    8

    Default

    Ok after all day of trying, then posting I found the solution. :-)

    If anyone is interested, the code should have been:
    Code:
    class Context
    {
        public $nonotify;
        public $noqualify;
    }
    
    $soapClient = new SoapClient(null, array('location' => 'https://192.168.0.199:7071/service/admin/soap/',
                                             'uri'      => 'urn:zimbraAdmin',
                                             'trace'    => 1,
                                             'exception'=> 1,
                                             'soap_version'  => SOAP_1_1,
                                             'style'    => SOAP_RPC,
                                             'use'      => SOAP_LITERAL
                                             ));
    
    $soapHeader = new SoapHeader('urn:zimbra',
                                 'context',
                                 new Context());
    
        $soapClient->__setSoapHeaders($soapHeader);
        echo $soapClient->__soapCall("AuthRequest", 
                                        array(
                                            new SoapParam('admin@mworks.com.my', 'name'),
                                            new SoapParam('mypassword', 'password')
                                            ),
                                        array(
                                            'uri'     => 'urn:zimbraAdmin'
                                                ));
    Which results in:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:zimbraAdmin" xmlns:ns2="urn:zimbra">
    <SOAP-ENV:Header>
    <ns2:context>
    <nonotify/>
    <noqualify/>
    </ns2:context>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
    <ns1:AuthRequest>
    <name>
    admin@mworks.com.my</name>
    <password>
    mypassword</password>
    </ns1:AuthRequest>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    Hope this helps someone else.
    Last edited by Corey Scott; 11-21-2006 at 03:48 AM. Reason: Forgot to change the password before posting

  3. #3
    Join Date
    Nov 2006
    Posts
    8
    Rep Power
    8

    Default

    I had these very same problems when trying to work with PHP SOAP and Zimbra. The problem you still have to face is how to do attributes to get most requests to work ( for example <account by="name">). I wasn't able to figure that one out in PHP SOAP and had to switch to PEAR SOAP. PEAR SOAP is a lot easier to use on services with no WSDL.

    But if you do figure out how to do attributes in PHP SOAP post it here, I'd be interested to see it.

  4. #4
    Join Date
    Nov 2006
    Posts
    6
    Rep Power
    8

    Default

    Its a bit of a kludge (then again what about PHP SOAP isnt ) but I found a solution that works.

    Kludge 1 (Change Password):
    If you build your params like this:
    Code:
    $arrArgs = array();
    $arrArgs[] = new SoapVar('<account by="name">' . $strUsername . '</account>', XSD_ANYXML);;
    $arrArgs[] = new SoapParam($strOldPassword, 'oldPassword');
    $arrArgs[] = new SoapParam($strNewPassword, 'password');
    Klude 2 (GetApptSummariesRequest):
    Code:
    Intead of defining the function name:
    $strFunctionName = 'GetApptSummariesRequest';
    
    Sadly you need this instead:
    $strFunctionName = 'GetApptSummariesRequest s="' . $intTsStart . '" e="' . $intTsEnd . '"';

    You get the output you need.
    Cheers
    Last edited by Corey Scott; 11-24-2006 at 12:05 AM.

  5. #5
    Join Date
    May 2007
    Posts
    22
    Rep Power
    8

    Default Thank you!!

    I've spent so many hours looking for these answers... I really appreciate you sharing your work.

  6. #6
    Join Date
    May 2007
    Posts
    22
    Rep Power
    8

    Lightbulb My turn to share...

    I hope this helps someone ... here is the code I hacked together to login as an admin and create a user. Obviously, you need to make this work for your environment (server, usernames, etc.), and break it up as you see fit. But it took me all day to get to this point. No reason someone else should have to do the same...

    I've put '!!' wherever I think you will have to change a value to work in your environment.

    WARNING: Lots and lots of debug (echos) included. You'll get to know more than you may have ever wanted to about the way the SOAP envelopes look...

    First off, you want to create this to AuthRequest:
    Code:
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
    <context xmlns="urn:zimbra"/>
    </soap:Header>
    <soap:Body>
    <AuthRequest xmlns="urn:zimbraAdmin">
    <name>admin@mydomain.com</name>
    <password>mystrongpassword</password>
    </AuthRequest>
    </soap:Body>
    </soap:Envelope>
    And here's how I did it:
    Code:
    <?php
        $client = new SoapClient(null,
            array(
                'location' => "https://!!mail.yourdomain.tld!!:7071/service/admin/soap/",
                'uri' => "urn:zimbraAdmin",
                'trace' => 1,
                'exceptions' => 1,
                'soap_version' => SOAP_1_1,
                'style' => SOAP_RPC,
                'use' => SOAP_LITERAL
            )
        );
        echo "Client Built<br>";
        
        $params = array(
                new SoapParam("!!adminusername!!", "name"),
                new SoapParam("!!adminpassword!!", "password")
                );
        echo "Params built<br>";
    
        try {
            echo "creating header<br>";
            $soapHeader = new SoapHeader(
                        'urn:zimbra',
                        'context'
                        );
    
            echo "trying<br>";        
            $result = $client->__soapCall(
                        "AuthRequest", 
                        $params, 
                        null,
                        $soapHeader
            );
            echo "executed<br>";    
        } catch (SoapFault $exception) {
            echo "exception caught<br><br>";
            echo htmlentities($client->__getLastRequest()) . "<br><br>";
            echo htmlentities($client->__getLastRequestHeaders()) . "<br><br>";
            echo htmlentities($client->__getLastResponseHeaders()) . "<br><br>";
            echo htmlentities($client->__getLastResponse()) . "<br><br>";
            echo $exception . "<br><br>";
        }
    
        echo "done<br><br>";
        echo htmlentities($client->__getLastRequest()) . "<br><br>";
        echo htmlentities($client->__getLastResponse()) . "<br><br>";
        var_dump($result);
        echo "<br><br>";
        echo $result['authToken'] . "<br><br>";
        echo "logged in, continuing<br><Br>";
        $authToken=$result['authToken'];
    Next, you want to create the CreateAccountRequest that should look like this:
    Code:
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
    <context xmlns="urn:zimbra">
    <authToken>authToken goes here</authToken>
    </context>
    </soap:Header>
    <soap:Body>
    <CreateAccountRequest xmlns=\"urn:zimbraAdmin\">
    <name>test@mydomain.com</name>
    <password>myverystrongpassword</password>
    </CreateAccountRequest>
    </soap:Body>
    </soap:Envelope>
    So, here's how I did that:
    Code:
        echo "creating new user params<br><br>";
        $params = array(
                new SoapParam("!!test@<domain>.com!!", "name"),
                new SoapParam("!!newpassword!!", "password")
                );
        echo "new user Params built<br>";
        try {
            echo "creating new user header<br>";
            $soapHeader = array(
                    new SoapHeader(
                        'urn:zimbra',
                        'context',
                        new SoapVar(
                            '<ns2:context><authToken>' . $authToken . '</authToken></ns2:context>',
                            XSD_ANYXML
                        )
                    )
            );
            
            echo "trying new user<br>";        
            $result = $client->__soapCall(
                        "CreateAccountRequest", 
                        $params, 
                        null,
                        $soapHeader
            );
            echo "executed new user creation<br>";    
        } catch (SoapFault $exception) {
            echo "exception caught<br><br>";
            echo htmlentities($client->__getLastRequest()) . "<br><br>";
            echo htmlentities($client->__getLastRequestHeaders()) . "<br><br>";
            echo htmlentities($client->__getLastResponseHeaders()) . "<br><br>";
            echo htmlentities($client->__getLastResponse()) . "<br><br>";
            echo $exception . "<br><br>";
        }
    
        echo "created user<br><br>";
        echo htmlentities($client->__getLastRequest()) . "<br><br>";
        echo htmlentities($client->__getLastResponse()) . "<br><br>";
        var_dump($result);
        echo "<br><br>";
        echo $result['account'] . "<br><br>";
        echo "user created!<br><Br>";
    
    ?>
    Keep in mind that this was one .php page for me, therefore I could use the same $client and $authToken objects between the login and user creation.

    Feel free to ask me questions, though keep in mind that I hacked this together - literally!

  7. #7
    Join Date
    Mar 2007
    Posts
    95
    Rep Power
    8

    Default my modified version as a class

    Thanks for sharing your code - I can verify that it works in my test environment! Using your code, I can create a user programmatically through PHP and SOAP. For my test machine, I have win32 apache running - so I had to enable these extensions in my php.ini:

    Code:
    extension=php_openssl.dll
    extension=php_soap.dll
    extension=php_curl.dll
    I'd like to be able to quickly crank out scripts to do what I an across multiple account, for whatever features that aren't officially implemented yet .. if I really need that feature. For example, I'd like to auto-subscribe all employees to the company calendar.

    So, I will probably reuse the authentication code. I've rewritten it into an OO way not sure if it's the best way, design-wise, but it's a start:

    Code:
    <form method="POST" action="soap.php">
    username<br>
    <input type="text" name="username"><br>
    password<br>
    <input type="text" name="password"><br>
    <input type="submit" name="submit" value="submit"><br>
    </form>
    
    <?php
    if (count($_POST))
    {
        $password = $_POST['password'];
        $username = $_POST['username'];
    
        $ZimbraAuth = new ZimbraAuth($username, $password); 
        echo $ZimbraAuth->exec();
    }
    
    class ZimbraAuth
    {
        private $client; 
        private $params; 
        
        function __construct($username, $password)
        {
    
            $this->client = new SoapClient(null,
                array(
                    'location' => "https://zimbra.microsoft.com:7071/service/admin/soap/",
                    'uri' => "urn:zimbraAdmin",
                    'trace' => 1,
                    'exceptions' => 1,
                    'soap_version' => SOAP_1_1,
                    'style' => SOAP_RPC,
                    'use' => SOAP_LITERAL
                )
            );
            
            $this->params = array( new SoapParam($username, "name"), new SoapParam($password, "password") );
            
        }
        
        function exec()
        {
            try 
            {
                //echo "creating header...<br>";
                $soapHeader = new SoapHeader('urn:zimbra','context');
            
                //echo "trying...<br>";        
                $result = $this->client->__soapCall("AuthRequest", $this->params, null,$soapHeader);
                //echo "executed...<br>";    
            } 
            catch (SoapFault $exception) 
            {
                echo "exception caught!...<br><br>EXCEPTION START <<<<<<<<<<< <p>";
                echo $exception . "<br><br>";
                echo ">>>>>>>>>>>> EXCEPTION END<p>";
            
                echo htmlentities($client->__getLastRequest()) . "<br><br>";
                echo htmlentities($client->__getLastRequestHeaders()) . "<br><br>";
                echo htmlentities($client->__getLastResponseHeaders()) . "<br><br>";
                echo htmlentities($client->__getLastResponse()) . "<br><br>";
            
            }
    
            //echo "authToken says: ".$result['authToken'] . "<br>";
            //echo "logged in, continuing<br>";
            return $result['authToken'];
                
                
        }
        
    } 
    ?>
    I'm guessing it would make sense to have a separate ZimbraAuth class, like how people often have a separate database authentication class. Then I use the token for something like $ZimbraUser->create($authToken) or $ZimbraUser->ChangePassword($old, $new, $authToken).

  8. #8
    Join Date
    May 2007
    Posts
    22
    Rep Power
    8

    Default

    Very nice, gettyless. Thanks for sharing your code, also. If my plan to sell email addresses on my domains works out, I will most likely create similar objects.

    Great community!

  9. #9
    Join Date
    Sep 2006
    Posts
    6
    Rep Power
    9

    Lightbulb

    Very nice code indeed!

    I'm using also similair classes like the ones above but can't find a normal way to analyse the output that the soap returns.

    How do you people analyse these results? I found out that __soapCall returns an object if the action is succeed but then again when I try to delete a certain account it doesn't return an object.

    PHP Code:
        function deleteAccount($id "") {
            try {
                
    // needed parameters
                
    $this->params = array( 
                    new 
    SoapParam($id"id"), 
                 );
                
                
    // create Soap header
                
    $soapHeader = new SoapHeader(
                                
    'urn:zimbra',
                                
    'context',
                                new 
    SoapVar(
                                    
    '<ns2:context><authToken>' $this->sAuthToken '</authToken></ns2:context>',
                                    
    XSD_ANYXML
                                    
    )
                                );
            
                
    // do Soap Call        
                
    $vResult $this->client->__soapCall("DeleteAccountRequest"$this->paramsnull,$soapHeader,$output);
            } catch (
    SoapFault $exception) {           
                if(
    $this->bDebug == true) {
                    
    $this->printDebug();
                }
            }
            
            return 
    $vResult
        } 
    Anyone have a suggestion how to handle the data that the soapClass returns?

  10. #10
    Join Date
    Nov 2006
    Posts
    6
    Rep Power
    8

    Default

    Firstly I need to apologize in advance, this code will prob not work out of the box but Im sure it will give you an idea of what is going on. (There is probably a few references to custom libraries or paths that I haven't changed correctly.)

    Anyway, the attachment contains a Zimbra SOAP Base Class that you can then extend to create different functionality.
    I have also attached some small extension of this base class that implement some functions like retrieving inbox status and calendar appointments.

    ferdinant, the base class should answer your question on what you can do with the response from __soapCall. (Check the execute method - Lines 85-87.)

    Have fun.
    Corey
    Attached Files Attached Files

Similar Threads

  1. [SOLVED] Clamav problem ? What's happening ?
    By aNt1X in forum Installation
    Replies: 23
    Last Post: 02-14-2008, 04:43 AM
  2. Replies: 8
    Last Post: 02-27-2007, 03:10 AM
  3. svn version still won't start
    By kinaole in forum Developers
    Replies: 0
    Last Post: 10-04-2006, 06:47 AM
  4. Logger
    By jholder in forum Installation
    Replies: 24
    Last Post: 03-31-2006, 10:50 AM
  5. Zimbra MTA and CentOS VPS on OpenVZ
    By czaveri in forum Installation
    Replies: 2
    Last Post: 03-20-2006, 08:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •