#!/usr/bin/python import sys import re ''' Code licensed under the BSD License: Author : emptyhua@gmail.com Site : http://bluehua.org eg: php2wsdl.py ns-name TheClass http://requesturl ./phpfile.php ./saveto.wsdl ''' GETCLASS = re.compile(r'(class[\t ]+([a-zA-Z_0-9]+)[ \t\r\na-zA-Z0-9_]+\{.*?[\r\n]\})', re.S) GETFUNCTION = re.compile(r'([ \t]*/\*\*[\n\r].*?\*/)[\n\r]+(?P[\t ]*)((protected |public |private |static )*)[ ]*function[ ]+([a-zA-Z0-9_]+)[ ]*\([^\)]*\)[\r\n ]*\{.*?[\r\n](?P=spc)\}[ \n\r]+', re.S) GETPARAM = re.compile(r'[ \t]*\*[ \t]*@param[ \t]*([a-zA-Z]+)[ \t]+\$([a-zA-Z_0-9]+)([ \t]+([^\n\r]+))?[\n\r]') GETRETURN = re.compile(r'[ \t]*\*[ \t]*@return[ \t]*([a-zA-Z]+)([ \t]+([^\n\r]+))?[\n\r]') class PHPparser: def parse_file(self, f): content = open(f, 'r').read() return self.parse_php(content) def parse_php(self, content): all_class = [] #get all classes rts = GETCLASS.findall(content) for rt in rts: cls = {} cls['funcs'] = [] cls['name'] = rt[1] #get functions with note func_rts = GETFUNCTION.findall(rt[0]) for func_rt in func_rts: func = {} func['params'] = [] func['name'] = func_rt[4] func['type'] = func_rt[2].strip() if func['type'].count('private') or func['type'].count('protected'): continue func['return'] = 'mixed' note = func_rt[0] param_rts = GETPARAM.findall(note) for param_rt in param_rts: param = {} param['name'] = param_rt[1] param['type'] = param_rt[0] param['doc'] = param_rt[2] func['params'].append(param) return_rt = GETRETURN.findall(note) if len(return_rt): func['return'] = return_rt[0][0].lower() cls['funcs'].append(func) all_class.append(cls) return all_class class WSDL: type_map = { 'string' : 'string', 'bool' : 'boolean', 'boolean' : 'boolean', 'int' : 'integer', 'integer' : 'integer', 'double' : 'double', 'float' : 'float', 'number' : 'float', 'datetime' : 'datetime', 'resource' : 'anyType', 'mixed' : 'anyType', 'unknown' : 'anyType', 'unknown_type' : 'anyType', 'anyType' : 'anyType', 'array' : 'anyType', } class_name = None name = None url = None classes_obj = None def __init__(self, name, class_name, url): self.name = name self.class_name = class_name self.url = url def get_type(self, t): return 'xsd:' + self.type_map[t] def load_php(self, f): p = PHPparser() self.classes_obj = p.parse_file(f) def write_wsdl(self, fn): f = open(fn, 'w') self.create_wsdl(f) f.close() def dump_wsdl(self): self.create_wsdl(sys.stdout) def create_wsdl(self, f): from xml.dom import minidom, Node doc = minidom.Document() root = doc.createElement('definitions') root.setAttribute('name', self.name) root.setAttribute('targetNamespace', 'urn:' + self.name) root.setAttribute('xmlns:typens', 'urn:' + self.name) root.setAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema') root.setAttribute('xmlns:soap', 'http://schemas.xmlsoap.org/wsdl/soap/') root.setAttribute('xmlns:soapenc', 'http://schemas.xmlsoap.org/soap/encoding/') root.setAttribute('xmlns:wsdl', 'http://schemas.xmlsoap.org/wsdl/') root.setAttribute('xmlns', 'http://schemas.xmlsoap.org/wsdl/') doc.appendChild(root) pclass = None for class_obj in self.classes_obj: if class_obj['name'] == self.class_name: pclass = class_obj break if pclass is None: print '%s do not exsit' % self.class_name return message_nodes = [] operation_nodes = [] binding_nodes = [] for func in pclass['funcs']: print '-' * 20 print func #message msg_node = doc.createElement('message') msg_node.setAttribute('name', func['name']) for param in func['params']: part_node = doc.createElement('part') part_node.setAttribute('name', param['name']) part_node.setAttribute('type', self.get_type(param['type'])) msg_node.appendChild(part_node) message_nodes.append(msg_node) msg_node = doc.createElement('message') msg_node.setAttribute('name', func['name'] + 'Response') part_node = doc.createElement('part') part_node.setAttribute('name', func['name'] + 'Return') part_node.setAttribute('type', self.get_type(func['return'])) msg_node.appendChild(part_node) message_nodes.append(msg_node) #op op_node = doc.createElement('operation') op_node.setAttribute('name', func['name']) input_node = doc.createElement('input') input_node.setAttribute('message', 'typens:' + func['name']) output_node = doc.createElement('output') output_node.setAttribute('message', 'typens:' + func['name'] + 'Response') op_node.appendChild(input_node) op_node.appendChild(output_node) operation_nodes.append(op_node) #bind bnode = doc.createElement('operation') bnode.setAttribute('name', func['name']) soap_node = doc.createElement('soap:operation') soap_node.setAttribute('soapAction', 'urn:' + self.class_name + 'Action') bnode.appendChild(soap_node) input_node = doc.createElement('input') sbody_node = doc.createElement('soap:body') sbody_node.setAttribute('namespace', 'urn:' + self.name) sbody_node.setAttribute('use', 'encoded') sbody_node.setAttribute('encodingStyle', 'http://schemas.xmlsoap.org/soap/encoding/') input_node.appendChild(sbody_node) bnode.appendChild(input_node) output_node = doc.createElement('output') sbody_node = doc.createElement('soap:body') sbody_node.setAttribute('namespace', 'urn:' + self.name) sbody_node.setAttribute('use', 'encoded') sbody_node.setAttribute('encodingStyle', 'http://schemas.xmlsoap.org/soap/encoding/') output_node.appendChild(sbody_node) bnode.appendChild(output_node) binding_nodes.append(bnode) binding_node = doc.createElement('binding') binding_node.setAttribute('name', self.class_name + 'Binding') binding_node.setAttribute('type', 'typens:' + self.class_name + 'PortType') spb_node = doc.createElement('soap:binding') spb_node.setAttribute('style', 'rpc') spb_node.setAttribute('transport', 'http://schemas.xmlsoap.org/soap/http') binding_node.appendChild(spb_node) for node in binding_nodes: binding_node.appendChild(node) porttype_node = doc.createElement('portType') porttype_node.setAttribute('name', self.class_name + 'PortType') for node in operation_nodes: porttype_node.appendChild(node) service_node = doc.createElement('service') service_node.setAttribute('name', self.name + 'Service') port_node = doc.createElement('port') port_node.setAttribute('name', self.class_name + 'Port') port_node.setAttribute('binding', 'typens:' + self.class_name + 'Binding') address_node = doc.createElement('soap:address') address_node.setAttribute('location', self.url) port_node.appendChild(address_node) service_node.appendChild(port_node) for node in message_nodes: root.appendChild(node) root.appendChild(porttype_node) root.appendChild(binding_node) root.appendChild(service_node) f.write(doc.toprettyxml(indent = ' ')) if __name__ == '__main__': wsdl = WSDL(sys.argv[1], sys.argv[2], sys.argv[3]) wsdl.load_php(sys.argv[4]) wsdl.write_wsdl(sys.argv[5])