Current File : /home/users/barii/public_html/finansenl.com.pl/wodki/admin/poczta/awsdl2php.php |
<?php
// +------------------------------------------------------------------------+
// | wsdl2php |
// +------------------------------------------------------------------------+
// | Copyright (C) 2005 Knut Urdalen <knut.urdalen@gmail.com> |
// +------------------------------------------------------------------------+
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// +------------------------------------------------------------------------+
// | This software is licensed under the LGPL license. For more information |
// | see http://wsdl2php.sf.net |
// +------------------------------------------------------------------------+
ini_set('soap.wsdl_cache_enabled', 0); // disable WSDL cache
if( $_SERVER['argc'] != 2 ) {
die("usage: wsdl2php <wsdl-file>\n");
}
$wsdl = $_SERVER['argv'][1];
print "Analyzing WSDL";
try {
$client = new SoapClient($wsdl);
} catch(SoapFault $e) {
die($e);
}
print ".";
$dom = DOMDocument::load($wsdl);
print ".";
// get documentation
$nodes = $dom->getElementsByTagName('documentation');
$doc = array('service' => '',
'operations' => array());
foreach($nodes as $node) {
if( $node->parentNode->localName == 'service' ) {
$doc['service'] = trim($node->parentNode->nodeValue);
} else if( $node->parentNode->localName == 'operation' ) {
$operation = $node->parentNode->getAttribute('name');
//$parameterOrder = $node->parentNode->getAttribute('parameterOrder');
$doc['operations'][$operation] = trim($node->nodeValue);
}
}
print ".";
// get targetNamespace
$targetNamespace = '';
$nodes = $dom->getElementsByTagName('definitions');
foreach($nodes as $node) {
$targetNamespace = $node->getAttribute('targetNamespace');
}
print ".";
// declare service
$service = array('class' => $dom->getElementsByTagNameNS('*', 'service')->item(0)->getAttribute('name'),
'wsdl' => $wsdl,
'doc' => $doc['service'],
'functions' => array());
print ".";
// PHP keywords - can not be used as constants, class names or function names!
$reserved_keywords = array('and', 'or', 'xor', 'as', 'break', 'case', 'cfunction', 'class', 'continue', 'declare', 'const', 'default', 'do', 'else', 'elseif', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'extends', 'for', 'foreach', 'function', 'global', 'if', 'new', 'old_function', 'static', 'switch', 'use', 'var', 'while', 'array', 'die', 'echo', 'empty', 'exit', 'include', 'include_once', 'isset', 'list', 'print', 'require', 'require_once', 'return', 'unset', '__file__', '__line__', '__function__', '__class__', 'abstract', 'private', 'public', 'protected', 'throw', 'try');
// ensure legal class name (I don't think using . and whitespaces is allowed in terms of the SOAP standard, should check this out and may throw and exception instead...)
$service['class'] = str_replace(' ', '_', $service['class']);
$service['class'] = str_replace('.', '_', $service['class']);
$service['class'] = str_replace('-', '_', $service['class']);
if(in_array(strtolower($service['class']), $reserved_keywords)) {
$service['class'] .= 'Service';
}
// verify that the name of the service is named as a defined class
if(class_exists($service['class'])) {
throw new Exception("Class '".$service['class']."' already exists");
}
/*if(function_exists($service['class'])) {
throw new Exception("Class '".$service['class']."' can't be used, a function with that name already exists");
}*/
// get operations
$operations = $client->__getFunctions();
foreach($operations as $operation) {
/*
This is broken, need to handle
GetAllByBGName_Response_t GetAllByBGName(string $Name)
list(int $pcode, string $city, string $area, string $adm_center) GetByBGName(string $Name)
finding the last '(' should be ok
*/
//list($call, $params) = explode('(', $operation); // broken
//if($call == 'list') { // a list is returned
//}
/*$call = array();
preg_match('/^(list\(.*\)) (.*)\((.*)\)$/', $operation, $call);
if(sizeof($call) == 3) { // found list()
} else {
preg_match('/^(.*) (.*)\((.*)\)$/', $operation, $call);
if(sizeof($call) == 3) {
}
}*/
$matches = array();
if(preg_match('/^(\w[\w\d_]*) (\w[\w\d_]*)\(([\w\$\d,_ ]*)\)$/', $operation, $matches)) {
$returns = $matches[1];
$call = $matches[2];
$params = $matches[3];
} else if(preg_match('/^(list\([\w\$\d,_ ]*\)) (\w[\w\d_]*)\(([\w\$\d,_ ]*)\)$/', $operation, $matches)) {
$returns = $matches[1];
$call = $matches[2];
$params = $matches[3];
} else { // invalid function call
throw new Exception('Invalid function call: '.$function);
}
$params = explode(', ', $params);
$paramsArr = array();
foreach($params as $param) {
$paramsArr[] = explode(' ', $param);
}
// $call = explode(' ', $call);
$function = array('name' => $call,
'method' => $call,
'return' => $returns,
'doc' => isset($doc['operations'][$call])?$doc['operations'][$call]:'',
'params' => $paramsArr);
// ensure legal function name
if(in_array(strtolower($function['method']), $reserved_keywords)) {
$function['name'] = '_'.$function['method'];
}
// ensure that the method we are adding has not the same name as the constructor
if(strtolower($service['class']) == strtolower($function['method'])) {
$function['name'] = '_'.$function['method'];
}
// ensure that there's no method that already exists with this name
// this is most likely a Soap vs HttpGet vs HttpPost problem in WSDL
// I assume for now that Soap is the one listed first and just skip the rest
// this should be improved by actually verifying that it's a Soap operation that's in the WSDL file
// QUICK FIX: just skip function if it already exists
$add = true;
foreach($service['functions'] as $func) {
if($func['name'] == $function['name']) {
$add = false;
}
}
if($add) {
$service['functions'][] = $function;
}
print ".";
}
$types = $client->__getTypes();
$primitive_types = array('string', 'int', 'long', 'float', 'boolean', 'dateTime', 'double', 'short', 'UNKNOWN', 'base64Binary', 'decimal', 'ArrayOfInt', 'ArrayOfFloat', 'ArrayOfString', 'decimal', 'hexBinary'); // TODO: dateTime is special, maybe use PEAR::Date or similar
$service['types'] = array();
foreach($types as $type) {
$parts = explode("\n", $type);
$class = explode(" ", $parts[0]);
$class = $class[1];
if( substr($class, -2, 2) == '[]' ) { // array skipping
continue;
}
if( substr($class, 0, 7) == 'ArrayOf' ) { // skip 'ArrayOf*' types (from MS.NET, Axis etc.)
continue;
}
$members = array();
for($i=1; $i<count($parts)-1; $i++) {
$parts[$i] = trim($parts[$i]);
list($type, $member) = explode(" ", substr($parts[$i], 0, strlen($parts[$i])-1) );
// check syntax
if(preg_match('/^$\w[\w\d_]*$/', $member)) {
throw new Exception('illegal syntax for member variable: '.$member);
continue;
}
// IMPORTANT: Need to filter out namespace on member if presented
if(strpos($member, ':')) { // keep the last part
list($tmp, $member) = explode(':', $member);
}
// OBS: Skip member if already presented (this shouldn't happen, but I've actually seen it in a WSDL-file)
// "It's better to be safe than sorry" (ref Morten Harket)
$add = true;
foreach($members as $mem) {
if($mem['member'] == $member) {
$add = false;
}
}
if($add) {
$members[] = array('member' => $member, 'type' => $type);
}
}
// gather enumeration values
$values = array();
if(count($members) == 0) {
$values = checkForEnum($dom, $class);
}
$service['types'][] = array('class' => $class, 'members' => $members, 'values' => $values);
print ".";
}
print "done\n";
print "Generating code...";
$code = "";
// add types
foreach($service['types'] as $type) {
// $code .= "/**\n";
// $code .= " * ".(isset($type['doc'])?$type['doc']:'')."\n";
// $code .= " * \n";
// $code .= " * @package\n";
// $code .= " * @copyright\n";
// $code .= " */\n";
// add enumeration values
$code .= "class ".$type['class']." {\n";
foreach($type['values'] as $value) {
$code .= " const ".generatePHPSymbol($value)." = '$value';\n";
}
// add member variables
foreach($type['members'] as $member) {
//$code .= " /* ".$member['type']." */\n";
$code .= " public \$".$member['member']."; // ".$member['type']."\n";
}
$code .= "}\n\n";
/* print "Writing ".$type['class'].".php...";
$filename = $type['class'].".php";
$fp = fopen($filename, 'w');
fwrite($fp, "<?php\n".$code."?>\n");
fclose($fp);
print "ok\n";*/
}
// add service
// page level docblock
//$code .= "/**\n";
//$code .= " * ".$service['class']." class file\n";
//$code .= " * \n";
//$code .= " * @author {author}\n";
//$code .= " * @copyright {copyright}\n";
//$code .= " * @package {package}\n";
//$code .= " */\n\n";
// require types
//foreach($service['types'] as $type) {
// $code .= "/**\n";
// $code .= " * ".$type['class']." class\n";
// $code .= " */\n";
// $code .= "require_once '".$type['class'].".php';\n";
//}
$code .= "\n";
// class level docblock
$code .= "/**\n";
$code .= " * ".$service['class']." class\n";
$code .= " * \n";
$code .= parse_doc(" * ", $service['doc']);
$code .= " * \n";
$code .= " * @author {author}\n";
$code .= " * @copyright {copyright}\n";
$code .= " * @package {package}\n";
$code .= " */\n";
$code .= "class ".$service['class']." extends SoapClient {\n\n";
// add classmap
$code .= " private static \$classmap = array(\n";
foreach($service['types'] as $type) {
$code .= " '".$type['class']."' => '".$type['class']."',\n";
}
$code .= " );\n\n";
$code .= " public function ".$service['class']."(\$wsdl = \"".$service['wsdl']."\", \$options = array()) {\n";
// initialize classmap (merge)
$code .= " foreach(self::\$classmap as \$key => \$value) {\n";
$code .= " if(!isset(\$options['classmap'][\$key])) {\n";
$code .= " \$options['classmap'][\$key] = \$value;\n";
$code .= " }\n";
$code .= " }\n";
$code .= " parent::__construct(\$wsdl, \$options);\n";
$code .= " }\n\n";
foreach($service['functions'] as $function) {
$code .= " /**\n";
$code .= parse_doc(" * ", $function['doc']);
$code .= " *\n";
$signature = array(); // used for function signature
$para = array(); // just variable names
if(count($function['params']) > 0) {
foreach($function['params'] as $param) {
$code .= " * @param ".(isset($param[0])?$param[0]:'')." ".(isset($param[1])?$param[1]:'')."\n";
/*$typehint = false;
foreach($service['types'] as $type) {
if($type['class'] == $param[0]) {
$typehint = true;
}
}
$signature[] = ($typehint) ? implode(' ', $param) : $param[1];*/
$signature[] = (in_array($param[0], $primitive_types) or substr($param[0], 0, 7) == 'ArrayOf') ? $param[1] : implode(' ', $param);
$para[] = $param[1];
}
}
$code .= " * @return ".$function['return']."\n";
$code .= " */\n";
$code .= " public function ".$function['name']."(".implode(', ', $signature).") {\n";
// $code .= " return \$this->client->".$function['name']."(".implode(', ', $para).");\n";
$code .= " return \$this->__soapCall('".$function['method']."', array(";
$params = array();
if(count($signature) > 0) { // add arguments
foreach($signature as $param) {
if(strpos($param, ' ')) { // slice
$param = array_pop(explode(' ', $param));
}
$params[] = $param;
}
//$code .= "\n ";
$code .= implode(", ", $params);
//$code .= "\n ),\n";
}
$code .= "), ";
//$code .= implode(', ', $signature)."),\n";
$code .= " array(\n";
$code .= " 'uri' => '".$targetNamespace."',\n";
$code .= " 'soapaction' => ''\n";
$code .= " )\n";
$code .= " );\n";
$code .= " }\n\n";
}
$code .= "}\n\n";
print "done\n";
print "Writing ".$service['class'].".php...";
$fp = fopen($service['class'].".php", 'w');
fwrite($fp, "<?php\n".$code."?>\n");
fclose($fp);
print "done\n";
function parse_doc($prefix, $doc) {
$code = "";
$words = split(' ', $doc);
$line = $prefix;
foreach($words as $word) {
$line .= $word.' ';
if( strlen($line) > 90 ) { // new line
$code .= $line."\n";
$line = $prefix;
}
}
$code .= $line."\n";
return $code;
}
/**
* Look for enumeration
*
* @param DOM $dom
* @param string $class
* @return array
*/
function checkForEnum(&$dom, $class) {
$values = array();
$node = findType($dom, $class);
if(!$node) {
return $values;
}
$value_list = $node->getElementsByTagName('enumeration');
if($value_list->length == 0) {
return $values;
}
for($i=0; $i<$value_list->length; $i++) {
$values[] = $value_list->item($i)->attributes->getNamedItem('value')->nodeValue;
}
return $values;
}
/**
* Look for a type
*
* @param DOM $dom
* @param string $class
* @return DOMNode
*/
function findType(&$dom, $class) {
$types_node = $dom->getElementsByTagName('types')->item(0);
$schema_list = $types_node->getElementsByTagName('schema');
for ($i=0; $i<$schema_list->length; $i++) {
$children = $schema_list->item($i)->childNodes;
for ($j=0; $j<$children->length; $j++) {
$node = $children->item($j);
if ($node instanceof DOMElement &&
$node->hasAttributes() &&
$node->attributes->getNamedItem('name')->nodeValue == $class) {
return $node;
}
}
}
return null;
}
function generatePHPSymbol($s) {
global $reserved_keywords;
if(!preg_match('/^[A-Za-z_]/', $s)) {
$s = 'value_'.$s;
}
if(in_array(strtolower($s), $reserved_keywords)) {
$s = '_'.$s;
}
return preg_replace('/[-.\s]/', '_', $s);
}
?>