Author: karstene
Date: Wed Dec  5 01:02:54 2012
New Revision: 1417256

URL: http://svn.apache.org/viewvc?rev=1417256&view=rev
Log:
Adding PHP SOAP Client

Added:
    chemistry/phpclient/trunk/soap/
    chemistry/phpclient/trunk/soap/PccHTML.php
    chemistry/phpclient/trunk/soap/README.txt
    chemistry/phpclient/trunk/soap/include/
    chemistry/phpclient/trunk/soap/include/CMISAlfrescoSoapClient.php
    chemistry/phpclient/trunk/soap/include/CMISSoapClient.php
    chemistry/phpclient/trunk/soap/include/CMISWebService.php
    chemistry/phpclient/trunk/soap/include/cmisTypeDefinitions.php
    chemistry/phpclient/trunk/soap/include/dialog.js
    chemistry/phpclient/trunk/soap/include/pcc.css
    chemistry/phpclient/trunk/soap/index.php

Added: chemistry/phpclient/trunk/soap/PccHTML.php
URL: 
http://svn.apache.org/viewvc/chemistry/phpclient/trunk/soap/PccHTML.php?rev=1417256&view=auto
==============================================================================
--- chemistry/phpclient/trunk/soap/PccHTML.php (added)
+++ chemistry/phpclient/trunk/soap/PccHTML.php Wed Dec  5 01:02:54 2012
@@ -0,0 +1,277 @@
+<?php
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+/**
+ * PccHTML - HTML definitions for PHP CMIS Client
+ *
+ * @author Karsten Eberding
+ */
+
+class PccHTML {
+
+// Simple template mechanism for HTML code generation, {} will be replaced:
+// {$x} will be replaced by parameter x (1 - 9)
+// {$template} will be replaced by content of template "template"
+// {content} will be replaced by the eval result, e.g. 
{urlencode('{@cmis:objectId}')}
+// recursive brackets are allowed
+
+    private static $templates = array(
+        // HTML Code sniplets
+        'folderUrl' => '<a href="index.php?folderid={$1}">{$2}</a>',
+        'folderListHead' => '<tr><th>Folder Name</th><th></th>',
+        'folderListEntry' => "<tr><td>{\$folderUrl}</td><td></td></tr>\n",
+        'docListHead' => '<tr><th>Document Name</th><th>Last Modification 
Date</th><th>Actions</th>',
+        'docListEntry' => '<tr><td><a 
href="index.php?action=download&objectid={$1}">{$2}</a></td><td>{$3}</td><td 
align="right">{$4}</td></tr>',
+        'docListEmpty' => "<tr><td>No documents in this folder</td></tr>\n",
+        'pageLink' => '&nbsp;<a 
href="index.php?folderid={$1}&page={$2}">{$2}</a>&nbsp;',
+        'pageCurrent' => '&nbsp;<b>{$1}</b>&nbsp;',
+        'pageList' => '<div class="paging">{$1}</div>',
+        'downloadFrame' => '<iframe width="1" height="1" frameborder="0" 
src="index.php?action=download&objectid={$1}"></iframe>',
+        'uploadAction' => '<a href="#" onclick="showModal(\'uploadFile\', 
\'{$1}\', \'{$2}\')">Upload</a>&nbsp;',
+        'cancelCOAction' => '<a href="#" onclick="showModal(\'cancelCO\', 
\'{$1}\', \'{$2}\')">CancelCO</a>&nbsp;',
+        'deleteAction' => '<a href="#" onclick="showModal(\'delete\', 
\'{$1}\', \'{$2}\')">Delete</a>&nbsp;',
+        'checkinAction' => '<a href="#" onclick="showModal(\'checkin\', 
\'{$1}\', \'{$2}\')">Check-In</a>&nbsp;',
+        'checkoutAction' => '<a href="#" onclick="showModal(\'checkout\', 
\'{$1}\', \'{$2}\')">Check-Out</a>&nbsp;',
+        'detailsAction' => '<a 
href="index.php?action=details&objectid={$1}">More</a>&nbsp;',
+        'createFolderBtn' => '<input type="button" value="Create Folder" 
onclick="showModal(\'createFolder\', \'{$1}\')">',
+        'createDocumentBtn' => '<input type="button" value="Create Document" 
onclick="showModal(\'createDocument\', \'{$1}\')">',
+
+        // Dialogs
+        'loginForm'        => <<<EOF
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd";>
+<html lang='en_us'>
+    <head>
+        <title>Login to PHP CMIS Client</title>
+    </head>
+    <body>
+        <form action="index.php" method="post">
+            Username: <input type="text" name="username" /><br />
+            Passwort: <input type="password" name="password" /><br />
+            <input type="hidden" name="action" value="login">
+            <input type="submit" value="Login">
+        </form>
+    </body>
+</html>
+EOF
+,       'modalDialog'      => <<<EOF
+    <div id="{\$1}" class="modalContainer">
+        <div class="modalBackground"></div>
+        <div class="modalWindow">
+            <div class="modalDialog">
+                <div class="dialoghead">{\$2}</div>
+                <div class="dialogbody">
+                {\$3}
+                </div>
+            </div>
+        </div>
+    </div>
+EOF
+,       'uploadFileDialog' => <<<EOF
+    Select file to upload for document<div class="dialognotice"></div>
+                <form id="{\$1}Form" method="POST" 
ENCTYPE="multipart/form-data" action="index.php">
+                    <table><tbody><tr>
+                        <td>File Name:</td><td>
+                        <input type="file" name="filename" size="30" value="">
+                    </td></tr><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" value="upload">
+                        <input type="submit" value="Upload">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'cancelCODialog' => <<<EOF
+    Confirm Cancel Check-out for document<div 
class="dialognotice"></div>Unsaved changes will be lost!
+                <form id="{\$1}Form" method="GET" action="index.php">
+                    <table><tbody><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" value="cancelco">
+                        <input type="submit" value="Cancel 
Check-Out">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'deleteDialog' => <<<EOF
+    Confirm Deletion of All versions of document<div 
class="dialognotice"></div>
+                <form id="{\$1}Form" method="GET" action="index.php">
+                    <table><tbody><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" value="delete">
+                        <input type="submit" value="Delete">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'checkoutDialog' => <<<EOF
+    Check-out document<div class="dialognotice"></div>Download will start 
automatically.
+                <form id="{\$1}Form" method="GET" action="index.php">
+                    <table><tbody><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" value="checkout">
+                        <input type="submit" value="Check-out and 
Download">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'checkinDialog' => <<<EOF
+    Select file to upload for check-in of<div 
class="dialognotice"></div>(leave file name empty to check-in without uploading 
a file)
+                <form id="{\$1}Form" method="POST" 
ENCTYPE="multipart/form-data" action="index.php">
+                    <table><tbody><tr>
+                        <td>File Name:</td><td>
+                        <input type="file" name="filename" size="30" 
value=""></td>
+                    </tr><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" value="checkin">
+                        <input type="submit" 
value="Check-In">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'createFolderDialog' => <<<EOF
+    Create new folder in current folder<div class="dialognotice"></div>
+                <form id="{\$1}Form" method="GET" action="index.php">
+                    <table><tbody><tr>
+                        <td>Folder Name:</td><td>
+                        <input type="text" name="createfoldername" size="30" 
value="">
+                        </td></tr><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" 
value="createfolder">
+                        <input type="submit" value="Create">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,       'createDocumentDialog' => <<<EOF
+Create new document in current folder<div class="dialognotice"></div>(leave 
file name empty to create a document without content)
+                <form id="{\$1}Form" method="POST" 
ENCTYPE="multipart/form-data" action="index.php">
+                    <table><tbody><tr>
+                        <td>File Name:</td><td>
+                        <input type="file" name="filename" size="30" value="" 
+                            
onchange="document.getElementById('createfilename').value=this.value.replace(/^.*(\\\\|\/)/,'')"></td>
+                    </tr><tr>
+                        <td>Document Name:</td><td>
+                        <input type="text" name="createfilename" 
id="createfilename" size="30" value=""></td>
+                    </tr><tr><td></td><td style="padding-top: 20px;">
+                        <input type="hidden" name="action" 
value="createdocument">
+                        <input type="submit" value="Create">&nbsp;&nbsp;&nbsp;
+                        <input type="reset" value="Cancel" 
onclick="hideModal('{\$1}');">
+                    </td></tr></tbody></table>
+                </form>
+EOF
+,
+        // Page elements
+        'htmlHeader' => <<<EOF
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd";>
+<html lang='en_us'>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+        <meta http-equiv="CACHE-CONTROL" CONTENT="NO-CACHE">
+        <script src="include/dialog.js" type="text/javascript"></script>
+        <title>PHP CMIS Client</title>
+        <link href="include/pcc.css" rel="stylesheet" type="text/css">
+    </head>
+    <body>
+EOF
+,       'htmlFooter' => <<<EOF
+    </body>
+</html>
+EOF
+,       'pageHeader' => <<<EOF
+
+        <div class="header">
+            <div class="titleContainer">
+                <div class="moduleTitle">
+                    PHP CMIS Client
+                </div>
+                <div class="moduleSubTitle">
+                    (c) 2012 Karsten Eberding
+                </div>
+                <div class="logoutTitle">
+                    <a href="index.php?action=logout">Logout</a>
+                </div>
+            </div>
+            {\$1}
+            <div class="headerText">
+                Content in Folder {\$2}
+            </div>
+            <form id="headButtons">
+            {\$3}
+            </form>
+        </div>
+EOF
+,       'folderList' => <<<EOF
+        <div class="folderList">
+            <table>
+                <thead>
+                {\$folderListHead}
+                </thead>
+                <tbody>
+                {\$1}
+                </tbody>
+            </table>
+        </div>
+EOF
+,       'documentList' => <<<EOF
+        <div class="documentList">
+            <table>
+                <thead>
+                    {\$1}
+                </thead>
+                <tbody>
+                    {\$2}
+                </tbody>
+            </table>
+                {\$3}
+        </div>
+EOF
+    );
+
+    function PccLayout() {
+        // nothing to do
+    }
+
+    /* Apply Template function, variable parameter list */
+
+    public function applyTemplate($templateName) {
+        $param = func_get_args();
+        $template = self::$templates[$templateName];
+        return $this->applyTemplateString($template, $param);
+    }
+
+    public function applyTemplateString($template, $param) {
+        // small trick to make class variables available in callback function
+        $templates = self::$templates;
+        $self = $this;
+        $callback = // Start of anonymous callback function
+                function ($match) use ($param, $templates, $self) {
+                    if ($match[1] == '$') {
+                        if (is_numeric($match[2])) {    // Numeric, use 
parameter $x
+                            $return = (string) $param[$match[2]];
+                        } else {                        // non-numeric, apply 
template again
+                            $return = $templates[$match[2]];
+                            if (strpos($return, '{') !== false) {
+                                $return = $self->applyTemplateString($return, 
$param);
+                            }
+                        }
+                    } else { // does not start with $, eval result
+                        $return = $self->applyTemplateString($match[2]);
+                        $return = eval("return $return;");
+                    }
+                    return $return;
+                };              // End of anonymous callback function
+
+        $return = preg_replace_callback('/\{([$@]?)(((?>[^\{\}]+)|(?R))*)\}/', 
$callback, $template);
+        return $return;
+    }
+}
+
+?>

Added: chemistry/phpclient/trunk/soap/README.txt
URL: 
http://svn.apache.org/viewvc/chemistry/phpclient/trunk/soap/README.txt?rev=1417256&view=auto
==============================================================================
--- chemistry/phpclient/trunk/soap/README.txt (added)
+++ chemistry/phpclient/trunk/soap/README.txt Wed Dec  5 01:02:54 2012
@@ -0,0 +1,35 @@
+README for PHP CMIS Client
+
+The PHP CMIS Soap Client consists of the following files:
+
+1) CMIS Web Service Library
+
+CMISWebService.php - the main class to be included into an application
+cmisTypeDefinitions.php - the CMIS object model, used by CMISWebService.php
+CMISSoapClient.php - extends the PHP SoapClient class, used by 
CMISWebService.php
+CMISAlfrescoSoapClient.php - an Alfresco specific version, includes ticket 
support
+
+2) PHP CMIS Client
+
+index.php - the main file, includes all CMIS calls and program logic. 
Configuration
+    parameters, including URL for service endpoints, is configured here.
+PccHTML.php - includes all HTML presentation code, no calls to CMIS
+pcc.css - CSS file, included from PccHTML.php
+dialog.js - Java Script for dialog handling, included from PccHTML.php
+
+The PHP CMIS Client is a sample application to show the use of the CMIS 
library.
+Main features include folder and document list, checkin, checkout, upload,
+download, cancel checkout and delete.
+
+All CMIS functions and the program logic are included into the main file 
index.php.
+Changes to the HTML presentation can be done independently in PccHTML.php.
+Jacascipt is used for dialog handling, to avoid page reloads for a dialog. 
+A simple templating mechanism is included, to generate the HTML output.
+
+This software is presented to the Apache Chemistry project. Licensing will
+be changed to ASF if accepted by the Chemistry project.
+
+Contact information:
+
+Karsten Eberding
[email protected]
\ No newline at end of file

Added: chemistry/phpclient/trunk/soap/include/CMISAlfrescoSoapClient.php
URL: 
http://svn.apache.org/viewvc/chemistry/phpclient/trunk/soap/include/CMISAlfrescoSoapClient.php?rev=1417256&view=auto
==============================================================================
--- chemistry/phpclient/trunk/soap/include/CMISAlfrescoSoapClient.php (added)
+++ chemistry/phpclient/trunk/soap/include/CMISAlfrescoSoapClient.php Wed Dec  
5 01:02:54 2012
@@ -0,0 +1,217 @@
+<?php
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+/**
+ * CMISAlfrescoSoapClient extends the standard SoapClient class to include 
message handling for CMIS for Alfresco:
+ * 1) include WebService Security (WSS) headers as required by CMIS (this part 
is taken from Alfresco)
+ * 2) handle multipart response messages from the repository
+ * 3) handle Alfresco tickets
+ * 
+ * @author Karsten Eberding, based on sample code from Alfresco
+ */
+class CMISAlfrescoSoapClient extends SoapClient {
+
+    private static $securityExtNS = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";;
+    private static $wsUtilityNS = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";;
+    private static $passwordType = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";;
+
+    private static $myUsername;
+    private static $myPassword;
+    private static $ticket;
+
+    public function __construct($wsdl, $options) {
+
+        $wsdlcache = $this->get_wsdl($wsdl);
+
+        // Call the base class
+        parent::__construct($wsdlcache, $options);
+    }
+
+    public function setCredentials($url, $username, $password) {
+
+        // Store the current username, password, ticket
+        self::$myUsername = $username;
+        self::$myPassword = $password;
+        
+        if (isset($_SESSION['AlfrescoTicket'])) {
+            $ticket = $_SESSION['AlfrescoTicket'];
+            return true;
+        }
+
+        // get url for ticket service
+        $u  =  urlencode($username);
+        $pw = urlencode($password);
+        $url = parse_url($url);
+        $path = preg_replace('#/[^/]+/?$#', '/', $url['path']); // remove last 
path element
+        $url = (isset($url['scheme']) ? $url['scheme'] : 'http') . '://' . 
$url['host'] .
+                (isset($url['port']) ? ':'.$url['port'] : '') . 
"{$path}service/api/login?u=$u&pw=$pw";
+
+        // get ticket
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+
+        $ticketxml = curl_exec($ch);
+        curl_close($ch);
+        $dom = new DOMDocument("1.0");
+        $dom->loadXML($ticketxml);
+        $ticket = $dom->getElementsByTagName('ticket')->item(0)->nodeValue;
+
+        if (isset($ticket)) {
+            self::$ticket = $ticket;                // save ticket for 
subsequent calls
+            $_SESSION['AlfrescoTicket'] = $ticket;  // save ticket for 
subsequent page requests
+            return true;    // login success
+        }
+        return false;   // login failure
+    }
+
+    public function clearCredentials() {
+        // Clear the current username, password, ticket
+        self::$myUsername = '';
+        self::$myPassword = '';
+        self::$ticket = '';
+        $_SESSION['AlfrescoTicket'] = '';
+    }
+
+    public function __call($function_name, $arguments = array()) {
+        return $this->__soapCall($function_name, $arguments);
+    }
+
+    public function __soapCall($function_name, $arguments = array(), $options 
= array(), $input_headers = array(), $output_headers = array()) {
+
+        // Automatically add a security header         
+        $input_headers[] = new SoapHeader(self::$securityExtNS, "Security", 
null, 1);
+
+        $response = parent::__soapCall($function_name, $arguments, $options, 
$input_headers, $output_headers);
+
+        return $response;
+    }
+
+    public function __doRequest($request, $location, $action, $version) {
+        // If this request requires authentication we have to manually 
construct the
+        // security headers.
+        $dom = new DOMDocument("1.0");
+        $dom->loadXML($request);
+
+        $securityHeader = $dom->getElementsByTagName("Security");
+
+        if ($securityHeader->length != 1) {
+            throw new Exception("Expected length: 1, Received: " . 
$securityHeader->length . ". No Security Header, or more than one element 
called Security!");
+        }
+
+        $securityHeader = $securityHeader->item(0);
+
+        // Construct Timestamp Header
+        $timeStamp = $dom->createElementNS(self::$wsUtilityNS, "Timestamp");
+        $createdDate = date("Y-m-d\TH:i:s\Z", mktime(date("H"), date("i"), 
date("s"), date("m"), date("d"), date("Y")));
+        $expiresDate = date("Y-m-d\TH:i:s\Z", mktime(date("H") + 24, 
date("i"), date("s"), date("m"), date("d"), date("Y")));
+        $created = new DOMElement("Created", $createdDate, self::$wsUtilityNS);
+        $expires = new DOMElement("Expires", $expiresDate, self::$wsUtilityNS);
+        $timeStamp->appendChild($created);
+        $timeStamp->appendChild($expires);
+
+        // Construct UsernameToken Header
+        if (isset(self::$ticket) && self::$ticket != '') {
+            $username = '';
+            $password = self::$ticket;
+        } else {
+            $username = self::$myUsername;
+            $password = self::$myPassword;
+        }
+        $userNameToken = $dom->createElementNS(self::$securityExtNS, 
"UsernameToken");
+        $userName = new DOMElement("Username", $username, 
self::$securityExtNS);
+
+        $passWord = $dom->createElementNS(self::$securityExtNS, "Password");
+        $typeAttr = new DOMAttr("Type", self::$passwordType);
+        $passWord->appendChild($typeAttr);
+
+        $passWord->appendChild($dom->createTextNode($password));
+        $userNameToken->appendChild($userName);
+        $userNameToken->appendChild($passWord);
+
+        // Construct Security Header
+        $securityHeader->appendChild($timeStamp);
+        $securityHeader->appendChild($userNameToken);
+
+        // Save the XML Request
+        $request = $dom->saveXML();
+
+        $response = parent::__doRequest($request, $location, $action, 
$version);
+        $responseHeader = $this->__getLastResponseHeaders();
+
+        $boundary = array();
+        $start = array();
+        $contentId = array();
+        $attachment = array();
+        $match = array();
+        if (preg_match('/content-type: multipart\/related;/i', 
$responseHeader) === 1 &&
+                preg_match('/boundary="(.*?)";/i', $responseHeader, $boundary) 
=== 1 &&
+                preg_match('/start="<(.*?)>";/i', $responseHeader, $start)) {
+            $parts = explode("\r\n--" . $boundary[1], $response);
+
+            foreach ($parts as $part) {
+                //if ($part == '' || $part == '--') continue;
+                $part = explode("\r\n\r\n", $part, 2); // array of part header 
and content
+                if (count($part) < 2)
+                    continue;
+                if (preg_match('/content-id:\s*<(.*?)>/i', $part[0], 
$contentId) === 1) {
+                    if ($contentId[1] == $start[1]) {
+                        $response = $part[1];
+                    } else {
+                        $attachment[$contentId[1]] = $part[1];
+                        //$attachment[] = $part[1];
+                    }
+                }
+            }
+            if (count($attachment) > 0) {
+                if (preg_match('/<xop:include .*?href="cid:(.*?)".*?>/i', 
$response, $match)) {
+                    $response = str_replace($match[0], 
base64_encode($attachment[$match[1]]), $response);
+                }
+            }
+        }
+
+        return $response;
+    }
+
+    private function get_wsdl($url) {
+        $cache_file = "/tmp/soap.wsdl." . md5($url);
+
+        //only fetch a new wsdl every hour
+        if (!file_exists($cache_file) || filectime($cache_file) < time() - 
3600) {
+            $ch = curl_init();
+            curl_setopt($ch, CURLOPT_URL, $url);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+
+            $wsdldata = curl_exec($ch);
+            curl_close($ch);
+
+            $wsdldata = str_replace('anySimpleType', 'string', $wsdldata);
+
+            file_put_contents($cache_file, $wsdldata);
+            if (!file_exists($cache_file)) {
+                throw new Exception("Couldn't load WSDL at {$url}");
+            }
+        }
+        return $cache_file;
+    }
+
+}
+
+?>

Added: chemistry/phpclient/trunk/soap/include/CMISSoapClient.php
URL: 
http://svn.apache.org/viewvc/chemistry/phpclient/trunk/soap/include/CMISSoapClient.php?rev=1417256&view=auto
==============================================================================
--- chemistry/phpclient/trunk/soap/include/CMISSoapClient.php (added)
+++ chemistry/phpclient/trunk/soap/include/CMISSoapClient.php Wed Dec  5 
01:02:54 2012
@@ -0,0 +1,170 @@
+<?php
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+/**
+ * CMISSoapClient extends the standard SoapClient class to include message 
handling for CMIS:
+ * 1) include WebService Security (WSS) headers as required by CMIS (this part 
is taken from Alfresco)
+ * 2) handle multipart response messages from the repository
+ * 
+ * @author Karsten Eberding, based on sample code from Alfresco
+ */
+class CMISSoapClient extends SoapClient {
+
+    private static $securityExtNS = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";;
+    private static $wsUtilityNS = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";;
+    private static $passwordType = 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";;
+    
+    private static $myUsername;
+    private static $myPassword;
+
+    public function __construct($wsdl, $options) {
+
+        $wsdlcache = $this->get_wsdl($wsdl);
+
+        // Call the base class
+        parent::__construct($wsdlcache, $options);
+    }
+
+    public function setCredentials($url, $username, $password) {
+
+        // Store the current username, password, ticket
+        self::$myUsername = $username;
+        self::$myPassword = $password;
+        
+        return true;   // login success
+    }
+
+    public function clearCredentials() {
+        // Clear the current username, password, ticket
+        self::$myUsername = '';
+        self::$myPassword = '';
+    }
+
+    public function __call($function_name, $arguments = array()) {
+        return $this->__soapCall($function_name, $arguments);
+    }
+
+    public function __soapCall($function_name, $arguments = array(), $options 
= array(), $input_headers = array(), $output_headers = array()) {
+        // Automatically add a security header         
+        $input_headers[] = new SoapHeader(self::$securityExtNS, "Security", 
null, 1);
+
+        $response = parent::__soapCall($function_name, $arguments, $options, 
$input_headers, $output_headers);
+
+        return $response;
+    }
+
+    public function __doRequest($request, $location, $action, $version) {
+        // If this request requires authentication we have to manually 
construct the
+        // security headers.
+        $dom = new DOMDocument("1.0");
+        $dom->loadXML($request);
+
+        $securityHeader = $dom->getElementsByTagName("Security");
+
+        if ($securityHeader->length != 1) {
+            throw new Exception("Expected length: 1, Received: " . 
$securityHeader->length . ". No Security Header, or more than one element 
called Security!");
+        }
+
+        $securityHeader = $securityHeader->item(0);
+
+        // Construct Timestamp Header
+        $timeStamp = $dom->createElementNS(self::$wsUtilityNS, "Timestamp");
+        $createdDate = date("Y-m-d\TH:i:s\Z", mktime(date("H"), date("i"), 
date("s"), date("m"), date("d"), date("Y")));
+        $expiresDate = date("Y-m-d\TH:i:s\Z", mktime(date("H") + 24, 
date("i"), date("s"), date("m"), date("d"), date("Y")));
+        $created = new DOMElement("Created", $createdDate, self::$wsUtilityNS);
+        $expires = new DOMElement("Expires", $expiresDate, self::$wsUtilityNS);
+        $timeStamp->appendChild($created);
+        $timeStamp->appendChild($expires);
+
+        // Construct UsernameToken Header
+        $userNameToken = $dom->createElementNS(self::$securityExtNS, 
"UsernameToken");
+        $userName = new DOMElement("Username", self::$myUsername, 
self::$securityExtNS);
+        $passWord = $dom->createElementNS(self::$securityExtNS, "Password");
+        $typeAttr = new DOMAttr("Type", self::$passwordType);
+        $passWord->appendChild($typeAttr);
+        $passWord->appendChild($dom->createTextNode(self::$myPassword));
+        $userNameToken->appendChild($userName);
+        $userNameToken->appendChild($passWord);
+
+        // Construct Security Header
+        $securityHeader->appendChild($timeStamp);
+        $securityHeader->appendChild($userNameToken);
+
+        // Save the XML Request
+        $request = $dom->saveXML();
+
+        $response = parent::__doRequest($request, $location, $action, 
$version);
+
+        $responseHeader = $this->__getLastResponseHeaders();
+
+        $boundary = array();
+        $start = array();
+        $contentId = array();
+        $attachment = array();
+        $match = array();
+        if (preg_match('/content-type: multipart\/related;/i', 
$responseHeader) === 1 &&
+                preg_match('/boundary="(.*?)";/i', $responseHeader, $boundary) 
=== 1 &&
+                preg_match('/start="<(.*?)>";/i', $responseHeader, $start)) {
+            $parts = explode("\r\n--" . $boundary[1], $response);
+
+            foreach ($parts as $part) {
+                $part = explode("\r\n\r\n", $part, 2); // array of part header 
and content
+                if (count($part) < 2)
+                    continue;
+                if (preg_match('/content-id:\s*<(.*?)>/i', $part[0], 
$contentId) === 1) {
+                    if ($contentId[1] == $start[1]) {
+                        $response = $part[1];
+                    } else {
+                        $attachment[$contentId[1]] = $part[1];
+                    }
+                }
+            }
+            if (count($attachment) > 0) {
+                if (preg_match('/<xop:include .*?href="cid:(.*?)".*?>/i', 
$response, $match)) {
+                    $response = str_replace($match[0], 
base64_encode($attachment[$match[1]]), $response);
+                }
+            }
+        }
+
+        return $response;
+    }
+
+    private function get_wsdl($url) {
+        $cache_file = "/tmp/soap.wsdl." . md5($url);
+
+        //only fetch a new wsdl every hour
+        if (!file_exists($cache_file) || filectime($cache_file) < time() - 
3600) {
+            $ch = curl_init();
+            curl_setopt($ch, CURLOPT_URL, $url);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+
+            $wsdldata = curl_exec($ch);
+            curl_close($ch);
+
+            $wsdldata = str_replace('anySimpleType', 'string', $wsdldata);
+
+            file_put_contents($cache_file, $wsdldata);
+            if (!file_exists($cache_file)) {
+                throw new Exception("Couldn't load WSDL at {$url}");
+            }
+        }
+        return $cache_file;
+    }
+}
+?>


Reply via email to