source: trunk/phpgwapi/inc/class.soap_server.inc.php @ 7655

Revision 7655, 13.9 KB checked in by douglasz, 11 years ago (diff)

Ticket #3236 - Melhorias de performance no codigo do Expresso.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2                /***************************************************************************
3                * Expresso Livre                                                           *
4                * http://www.expressolivre.org                                             *
5                * --------------------------------------------                             *
6                *  This program is free software; you can redistribute it and/or modify it *
7                *  under the terms of the GNU General Public License as published by the   *
8                *  Free Software Foundation; either version 2 of the License, or (at your  *
9                *  option) any later version.                                              *
10                \**************************************************************************/
11               
12// SOAP server class
13
14// for example usage, see the test_server.php file.
15
16        class soap_server
17        {
18                function soap_server($data='',$serviceNow=False)
19                {
20                        // create empty dispatch map
21                        $this->dispatch_map = array();
22                        $this->debug_flag = True;
23                        $this->debug_str = '';
24                        $this->headers = '';
25                        $this->request = '';
26                        $this->result = 'successful';
27                        $this->fault = false;
28                        $this->fault_code = '';
29                        $this->fault_str = '';
30                        $this->fault_actor = '';
31
32                        if($serviceNow == 1)
33                        {
34                                $this->service($data);
35                        }
36                }
37
38                // parses request and posts response
39                function service($data)
40                {
41                        // $response is a soap_msg object
42                        $response = $this->parseRequest($data);
43                        $this->debug("parsed request and got an object of this class '".get_class($response)."'");
44                        $this->debug("server sending...");
45                        // pass along the debug string
46                        if($this->debug_flag)
47                        {
48                                $response->debug($this->debug_str);
49                        }
50                        $payload = $response->serialize();
51                        // print headers
52                        if($this->fault)
53                        {
54                                $header[] = "HTTP/1.0 500 Internal Server Error\r\n";
55                        }
56                        else
57                        {
58                                $header[] = "HTTP/1.0 200 OK\r\n";
59                                $header[] = "Status: 200\r\n";
60                        }
61                        $header[] = "Server: SOAPx4 Server v0.344359s\r\n";
62                        $header[] = "Connection: Close\r\n";
63                        $header[] = "Content-Type: text/xml; charset=UTF-8\r\n";
64                        $header[] = "Content-Length: ".strlen($payload)."\r\n\r\n";
65                        reset($header);
66                        foreach($header as $hdr)
67                        {
68                                header($hdr);
69                        }
70                        print $payload;
71                }
72
73                function parseRequest($data="")
74                {
75                        global $HTTP_SERVER_VARS;
76
77                        $this->debug("entering parseRequest() on ".date("H:i Y-m-d"));
78                        $request_uri = $HTTP_SERVER_VARS["REQUEST_URI"];
79                        $this->debug("request uri: $request_uri");
80                        // get headers
81                        $headers_array = getallheaders();
82                        foreach($headers_array as $k=>$v)
83                        {
84                                $dump .= "$k: $v\r\n";
85                        }
86                        $dump .= "\r\n\r\n".$data;
87                        $this->headers = $headers_array;
88                        $this->request = $dump;
89
90                        // get SOAPAction header -> methodname
91                        if($headers_array["SOAPAction"])
92                        {
93                                $action = str_replace('"','',$headers_array["SOAPAction"]);
94                                if(preg_match('/^urn:/',$action))
95                                {
96                                        $this->service = substr($action,4);
97                                }
98                                elseif(preg_match('/.php/',$action))
99                                {
100                                        $this->service = preg_replace('/"|\//','',substr(strrchr($action,".php"),4,strlen(strrchr($action,"/"))));
101                                }
102                                $this->debug("got service: $this->service");
103                        }
104                        else
105                        {
106                                // throw a fault if no soapaction
107                                $this->debug("ERROR: no SOAPAction header found");
108                        }
109                        // NOTE:::: throw a fault for no/bad soapaction here?
110
111                        // parse response, get soap parser obj
112                        $parser = CreateObject('phpgwapi.soap_parser',$data);
113                        // get/set methodname
114                        $this->methodname = $parser->root_struct_name;
115                        $this->debug("method name: $this->methodname");
116
117                        // does method exist?
118                        $test = preg_replace('/\./','_',$this->methodname);
119                        if(function_exists($test))
120                        {
121                                $method = $this->methodname = $test;
122                                $this->debug("method '$this->methodname' exists");
123                        }
124                        else
125                        {
126                                /* egroupware customization - createobject based on methodname */
127                                list($app,$class,$method) = explode('.',$this->methodname);
128                                if(preg_match('/^service/',$app))
129                                {
130                                        $args  = $class;
131                                        $class = 'service';
132                                        $app   = 'phpgwapi';
133                                        $obj   = CreateObject(sprintf('%s.%s',$app,$class),$args);
134                                        unset($args);
135                                }
136                                else
137                                {
138                                        $obj = CreateObject(sprintf('%s.%s',$app,$class));
139                                }
140                                $this->debug('app: ' . $app . ', class: ' . $class . ', method: ' . $method);
141                                /*
142                                // "method not found" fault here
143                                $this->debug("method '$obj->method' not found!");
144                                $this->result = "fault: method not found";
145                                $this->make_fault("Server","method '$obj->method' not defined in service '$this->service'");
146                                return $this->fault();
147                                */
148                        }
149
150                        // if fault occurred during message parsing
151                        if($parser->fault())
152                        {
153                                // parser debug
154                                $this->debug($parser->debug_str);
155                                $this->result = "fault: error in msg parsing or eval";
156                                $this->make_fault("Server","error in msg parsing or eval:\n".$parser->get_response());
157                                // return soapresp
158                                return $this->fault();
159                                // else successfully parsed request into soapval object
160                        }
161                        else
162                        {
163                                // get eval_str
164                                $this->debug("calling parser->get_response()");
165                                // evaluate it, getting back a soapval object
166                                if(!$request_val = $parser->get_response())
167                                {
168                                        return $this->fault();
169                                }
170                                // parser debug
171                                $this->debug($parser->debug_str);
172                                if(get_class($request_val) == "soapval")
173                                {
174                                        if (is_object($obj))
175                                        {
176                                                /* Add the function to the server map */
177                                                $in  = "array('" . implode("','",$obj->soap_functions[$method]['in']) . "')";
178                                                $out = "array('" . implode("','",$obj->soap_functions[$method]['out']) . "')";
179                                                $evalmap  = "\$this->add_to_map(\$this->methodname,$in,$out);";
180                                                eval($evalmap);
181                                        }
182                                        /* verify that soapval objects in request match the methods signature */
183                                        if($this->verify_method($request_val))
184                                        {
185                                                $this->debug("request data - name: $request_val->name, type: $request_val->type, value: $request_val->value");
186                                                if($this->input_value)
187                                                {
188                                                        /* decode the soapval object, and pass resulting values to the requested method */
189                                                        if(!$request_data = $request_val->decode())
190                                                        {
191                                                                $this->make_fault("Server","Unable to decode response from soapval object into native php type.");
192                                                                return $this->fault();
193                                                        }
194                                                        $this->debug("request data: $request_data");
195                                                }
196
197                                                /* if there are return values */
198                                                if($this->return_type = $this->get_return_type())
199                                                {
200                                                        $this->debug("got return type: '$this->return_type'");
201                                                        /* if there are parameters to pass */
202                                                        if($request_data)
203                                                        {
204                                                                if (is_object($obj))
205                                                                {
206                                                                        $code = "\$method_response = call_user_method($method,$obj,";
207                                                                        $this->debug("about to call object method '$class\-\>$method' with args");
208                                                                }
209                                                                else
210                                                                {
211                                                                        $code = '$method_response = ' . $this->methodname . "('";
212                                                                        $args = implode("','",$request_data['return']);
213                                                                        $this->debug("about to call method '$this->methodname' with args: $args");
214                                                                }
215                                                                /* call method with parameters */
216                                                                $code .= implode("','",$request_data['return']);
217                                                                /*
218                                                                while(list($x,$y) = each($request_data))
219                                                                {
220                                                                        $code .= "\$request_data[$x]" . ',';
221                                                                }
222                                                                $code = substr($code,0,-1) .");";
223                                                                */
224                                                                $code .= "');";
225                                                                $this->debug('CODE: ' . $code);
226                                                                if(eval($code))
227                                                                {
228                                                                        if (is_object($obj))
229                                                                        {
230                                                                                $this->make_fault("Server","Object method call failed for '$class\-\>$method' with params: ".join(',',$request_data));
231                                                                        }
232                                                                        else
233                                                                        {
234                                                                                $this->make_fault("Server","Method call failed for '$this->methodname' with params: ".join(',',$request_data));
235                                                                        }
236                                                                        return $this->fault();
237                                                                }
238                                                                $this->debug('Response: ' . $method_response);
239                                                                //                                                      _debug_array($method_response);
240                                                        }
241                                                        else
242                                                        {
243                                                                /* call method w/ no parameters */
244                                                                if (is_object($obj))
245                                                                {
246                                                                        $this->debug("about to call object method '$obj\-\>$method'");
247                                                                        if(!$method_response = call_user_method($method,$obj))
248                                                                        {
249                                                                                $this->make_fault("Server","Method call failed for '$obj->method' with no params");
250                                                                                return $this->fault();
251                                                                        }
252                                                                }
253                                                                else
254                                                                {
255                                                                        $this->debug("about to call method '$this->methodname'");
256                                                                        if(!$method_response = call_user_func($this->methodname))
257                                                                        {
258                                                                                $this->make_fault("Server","Method call failed for '$this->methodname' with no params");
259                                                                                return $this->fault();
260                                                                        }
261                                                                }
262                                                        }
263                                                        /* no return values */
264                                                }
265                                                else
266                                                {
267                                                        if($request_data)
268                                                        {
269                                                                /* call method with parameters */
270                                                                $code = "\$method_response = call_user_method(\$method,\$obj,";
271                                                                while(list($x,$y) = each($request_data))
272                                                                {
273                                                                        $code .= "\$request_data[$x]" . ',';
274                                                                }
275                                                                $code = substr($code,0,-1) .");";
276                                                                $this->debug("about to call object method '$obj\-\>$method'");
277                                                                eval($code);
278                                                        }
279                                                        else
280                                                        {
281                                                                /* call method w/ no parameters */
282                                                                if(is_object($obj))
283                                                                {
284                                                                        $this->debug("about to call object method '$obj\-\>$method'");
285                                                                        call_user_method($method,$obj);
286                                                                }
287                                                                else
288                                                                {
289                                                                        $this->debug("about to call method '$method'");
290                                                                        call_user_func($method);
291                                                                }
292                                                        }
293                                                }
294
295                                                /* create soap_val object w/ return values from method, use method signature to determine type */
296                                                if(get_class($method_response) != 'soapval')
297                                                {
298                                                        $return_val = CreateObject('phpgwapi.soapval',$method,$this->return_type,$method_response);
299                                                }
300                                                else
301                                                {
302                                                        $return_val = $method_response;
303                                                }
304                                                $this->debug($return_val->debug_str);
305                                                /* response object is a soap_msg object */
306                                                $return_msg =  CreateObject('phpgwapi.soapmsg',$method.'Response',array($return_val),$this->service);
307                                                if($this->debug_flag)
308                                                {
309                                                        $return_msg->debug_flag = true;
310                                                }
311                                                $this->result = "successful";
312                                                return $return_msg;
313                                        }
314                                        else
315                                        {
316                                                // debug
317                                                $this->debug("ERROR: request not verified against method signature");
318                                                $this->result = "fault: request failed validation against method signature";
319                                                // return soapresp
320                                                return $this->fault();
321                                        }
322                                }
323                                else
324                                {
325                                        // debug
326                                        $this->debug("ERROR: parser did not return soapval object: $request_val ".get_class($request_val));
327                                        $this->result = "fault: parser did not return soapval object: $request_val";
328                                        // return fault
329                                        $this->make_fault("Server","parser did not return soapval object: $request_val");
330                                        return $this->fault();
331                                }
332                        }
333                }
334
335                function verify_method($request)
336                {
337                        //return true;
338                        $this->debug("entered verify_method() w/ request name: ".$request->name);
339                        $params = $request->value;
340                        // if there are input parameters required...
341                        if($sig = $this->dispatch_map[$this->methodname]["in"])
342                        {
343                                $this->input_value = count($sig);
344                                if(is_array($params))
345                                {
346                                        $this->debug("entered verify_method() with ".count($params)." parameters");
347                                        foreach($params as $v)
348                                        {
349                                                $this->debug("param '$v->name' of type '$v->type'");
350                                        }
351                                        // validate the number of parameters
352                                        if(count($params) == count($sig))
353                                        {
354                                                $this->debug("got correct number of parameters: ".count($sig));
355                                                // make array of param types
356                                                foreach($params as $param)
357                                                {
358                                                        $p[] = strtolower($param->type);
359                                                }
360                                                // validate each param's type
361                                                for($i=0; $i < count($p); ++$i)
362                                                {
363                                                        // type not match
364                                                        if(strtolower($sig[$i]) != strtolower($p[$i]))
365                                                        {
366                                                                $this->debug("mismatched parameter types: $sig[$i] != $p[$i]");
367                                                                $this->make_fault("Client","soap request contained mismatching parameters of name $v->name had type $p[$i], which did not match signature's type: $sig[$i]");
368                                                                return false;
369                                                        }
370                                                        $this->debug("parameter type match: $sig[$i] = $p[$i]");
371                                                }
372                                                return true;
373                                                // oops, wrong number of paramss
374                                        }
375                                        else
376                                        {
377                                                $this->debug("oops, wrong number of parameter!");
378                                                $this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' required ".count($sig)." and request provided ".count($params));
379                                                return false;
380                                        }
381                                        // oops, no params...
382                                }
383                                else
384                                {
385                                        $this->debug("oops, no parameters sent! Method '$this->methodname' requires ".count($sig)." input parameters!");
386                                        $this->make_fault("Client","soap request contained incorrect number of parameters. method '$this->methodname' requires ".count($sig)." parameters, and request provided none");
387                                        return false;
388                                }
389                                // no params
390                        }
391                        elseif( (count($params)==0) && (count($sig) <= 1) )
392                        {
393                                $this->input_values = 0;
394                                return true;
395                        }
396                        else
397                        {
398                                //$this->debug("well, request passed parameters to a method that requires none?");
399                                //$this->make_fault("Client","method '$this->methodname' requires no parameters. The request passed in ".count($params).": ".@implode(" param: ",$params) );
400                                return true;
401                        }
402                }
403
404                // get string return type from dispatch map
405                function get_return_type()
406                {
407                        if(count($this->dispatch_map[$this->methodname]["out"]) >= 1)
408                        {
409                                $type = array_shift($this->dispatch_map[$this->methodname]["out"]);
410                                $this->debug("got return type from dispatch map: '$type'");
411                                return $type;
412                        }
413                        return false;
414                }
415
416                // dbg
417                function debug($string)
418                {
419                        if($this->debug_flag)
420                        {
421                                $this->debug_str .= "$string\n";
422                        }
423                }
424
425                // add a method to the dispatch map
426                function add_to_map($methodname,$in,$out)
427                {
428                        $this->dispatch_map[$methodname]["in"] = $in;
429                        $this->dispatch_map[$methodname]["out"] = $out;
430                }
431
432                // set up a fault
433                function fault()
434                {
435                        return CreateObject('phpgwapi.soapmsg',
436                        "Fault",
437                        array(
438                                "faultcode" => $this->fault_code,
439                                "faultstring" => $this->fault_str,
440                                "faultactor" => $this->fault_actor,
441                                "faultdetail" => $this->fault_detail.$this->debug_str
442                        ),
443                        "http://schemas.xmlphpgwapi.org/soap/envelope/"
444                );
445        }
446
447        function make_fault($fault_code,$fault_string)
448        {
449                $this->fault_code = $fault_code;
450                $this->fault_str = $fault_string;
451                $this->fault = true;
452        }
453}
454?>
Note: See TracBrowser for help on using the repository browser.