source: sipes/0.3-modules/soap_server/soap_server.module @ 66980b9

version-3.0
Last change on this file since 66980b9 was 66980b9, checked in by Sipes Apn <root@…>, 7 años ago

se agrego el modulo de soap server

  • Propiedad mode establecida a 100644
File size: 13.7 KB
Línea 
1<?php
2// $Id: soap_server.module,v 1.2.2.2.2.2.2.10 2011/02/01 14:27:50 rayvaughn Exp $
3/**
4 * @file
5 * Enable SOAP for services module (6.x-3.x).
6 *
7 * The XMLRPC style {resource}.{method} method names have been replaced with
8 * {resource}_{method} which are valid PHP function names.
9 *
10 * The WSDL provides type information for request parameters which is generated from the resource
11 * info. Response
12 */
13
14/**
15 * Drupal core hooks.
16 */
17
18/**
19 * Implementation of hook_menu().
20 */
21function soap_server_menu() {
22  $items['soap_server/debug_wsdl/%soap_server_endpoint'] = array(
23    'type' => MENU_CALLBACK,
24    'title' => 'Soap Server 3 Debug WSDL',
25    'page callback' => 'soap_server_debug_wsdl',
26    'page arguments' => array(2),
27    'access arguments' => array('debug soap server'),
28  );
29    $items['soap_server/debug_client/%soap_server_endpoint/%node'] = array(
30    'title'            => 'Soap Server Debug Client',
31    'access arguments' => array('debug soap server'),
32    'page callback'    => 'soap_server_debug_client',
33    'page arguments'   => array(2, 3),
34    'type'             => MENU_CALLBACK,
35  );
36  return $items;
37}
38
39/**
40 * endpoint menu loader
41 *
42 * Return the services endpoint object from the endpoint name.
43 *
44 * @param unknown_type $endpoint_name
45 */
46function soap_server_endpoint_load($endpoint_name) {
47  $endpoint = services_endpoint_load($endpoint_name);
48  if (is_object($endpoint)) {
49    return $endpoint;
50  }
51  return FALSE;
52}
53
54/**
55 * Implementation of hook_perm().
56 */
57function soap_server_perm() {
58  return array('access soap server', 'debug soap server');
59}
60
61/**
62 * Implementation of hook_server_info().
63 *
64 * This function tells services module that we are providing a server
65 */
66function soap_server_server_info() {
67  return array(
68    'name' => 'SOAP',
69  );
70}
71
72/**
73 * Services 3 hooks.
74 */
75
76/**
77 * Implementation of hook_server().
78 *
79 * The services endpoint callback function that handles all requests to a SOAP
80 * server 3 endpoint. If ?wsdl is appended to the URL, the WSDL is served.
81 */
82function soap_server_server() {
83  $info =  services_server_info_object();
84  $endpoint = services_endpoint_load($info->endpoint);
85  $get = $_GET;
86  // Serve the WSDL if ?wsdl is appended to the URL.
87  if (in_array('wsdl', array_keys($get))) {
88    // The soap_server_wsdl_output() function delivers the WSDL and exits.
89    soap_server_wsdl_output($endpoint);
90  }
91  // Disable the WSDL cache so it's not stored in memory or on disk.
92  //ini_set("soap.wsdl_cache_enabled", "0");
93  $wsdl_url = url($endpoint->path, array('absolute' => TRUE, )) . '?wsdl';
94
95
96  //se configura para que el servidor no compruebe el certificado
97  $context = array(
98    'ssl' => array(
99      // set some SSL/TLS specific options
100      'verify_peer' => false,
101      'verify_peer_name' => false,
102    ),
103  );
104/*
105  $options = array(
106    'cache_wsdl' => 0,
107    'trace' => true,
108    'stream_context'=> stream_context_create($context),
109  );
110*/
111  $options = array(
112    'cache_wsdl' => 0,
113    'trace' => true,
114    'stream_context'=> stream_context_create($context),
115    'uri' => $wsdl_url,
116  );
117  try {
118    //$server = new SoapServer($wsdl_url, $options);
119    $server = new SoapServer(null, $options);
120    $server->setClass(ServicesSoapServer);
121    $server->handle();
122  }
123  catch (Exception $e) {
124    watchdog('soap_server', $e->getMessage(), 'error');
125  }
126  exit;
127}
128
129/**
130 * Get a WSDL for the given endpoint.
131 *
132 * The WSDL provides a soap method for each method of the configured resources.
133 * See /admin/build/services/your_endpoint/resources
134 *
135 * @param $endpoint
136 */
137function soap_server_get_wsdl($endpoint) {
138  // allow other modules to provide the wsdl
139  $wsdl_overrides = module_invoke_all('soap_server_wsdl', $endpoint);
140  if (is_array($wsdl_overrides) && !empty($wsdl_overrides)) {
141    // if there is more than 1 wsdl the first takes priority allowing modules to override others by
142    // setting system weight
143    $wsdl = array_shift($wsdl_overrides);
144    return $wsdl;
145  }
146  $service_endpoint = url($endpoint->path, array('absolute' => TRUE));
147  // get the content of the schema for each hose_xml profile using the standard namespace xs:
148  $methods = _soap_server_get_methods($endpoint->name);
149  foreach ($methods as $method_name => $method_config) {
150    // requests can specify which field to use to identify the node - default is nid
151    $parts = "";
152    // add parameters from the args array in the resource
153    foreach ((array)$method_config['args'] as $arg) {
154      switch ($arg['type']) {
155        case 'int':
156        case 'string':
157        case 'struct':
158          $parts .= "
159    <part name='"  . $arg['name'] ."' type='xsd1:". $arg['type'] ."' />";
160          break;
161        // we can work out how to deal with other parameter types later
162        default:
163          $parts .= "
164    <part name='". $arg['name'] ."' type='xsd1:any'/>";
165      }   
166    }
167    $requests .= "
168  <message name='". $method_name ."_request'>". $parts ."
169  </message>";
170    // we don't know what the response will be so go for struct - seems like this is appropriate
171    // for most resources
172    $responses .= "
173  <message name='". $method_name ."_response'>
174    <part name='response_object' type='xsd1:struct'/>
175  </message>";
176    $port_type_operations .= "
177  <operation name='$method_name'>
178    <input message='tns:". $method_name ."_request'/>
179    <output message='tns:". $method_name ."_response'/>
180  </operation>";
181    $binding_operations .= "
182  <operation name='$method_name'>
183    <soap:operation soapAction='urn:xmethods-delayed-quotes#$method_name'/>
184    <input>
185      <soap:body
186        use='literal'
187        namespace='urn:xmethods-delayed-quotes' />
188    </input>
189    <output>
190      <soap:body
191        use='literal'
192        namespace='urn:xmethods-delayed-quotes' />
193    </output>
194  </operation>
195";
196  }
197  $include = drupal_get_path('module', 'soap_server') . '/wsdl/soap_server.wsdl.inc';
198  if (!is_file($include)) {
199    return t("Could not load include @inc", array('@inc' => $include));
200  }
201  else {
202    require_once($include);
203    // $wsdl_content is assigned in the include file
204    return $wsdl_content;
205  }
206}
207
208/**
209 * Delivers XML suitable for supplying WSDL to Soap clients.
210 *
211 * @param $xml
212 *   The content of the WSDL to serve
213 */
214function soap_server_wsdl_output($endpoint) {
215  $wsdl_content = soap_server_get_wsdl($endpoint);
216  ob_end_clean();
217  drupal_set_header('Connection: close');
218  drupal_set_header('Content-Length: ' . drupal_strlen($wsdl_content));
219  drupal_set_header('Content-Type: application/wsdl+xml; charset=utf-8');
220  drupal_set_header('Date: '. date('r'));
221  echo $wsdl_content;
222  exit;
223}
224
225
226/**
227 * Soap Server 3 Class for handling soap requests.
228 */
229class ServicesSoapServer {
230  public function __call($method_name, $args) {
231    // Handle the request.
232    $info =  services_server_info_object();
233    $endpoint = services_endpoint_load($info->endpoint);
234    $services_method_name = str_replace('_soap_', '.', $method_name);   
235    $controller = services_controller_get($services_method_name, $endpoint->name);
236    // make sure any arguments not passed have default values inserted if they are supplied
237    // TODO: should we be validating argument types here?
238    foreach ($controller['args'] as $key => $arg_config) {
239      if (!isset($args[$key]) && isset($arg_config['default value'])) {
240        $args[$key] = $arg_config['default value'];
241      }
242    }
243   
244    if ($endpoint->debug) {
245      watchdog('soap server', "METHOD_NAME:<pre>". print_r($method_name, TRUE)."</pre");
246      watchdog('soap server', "ENDPOINT:<pre>". print_r($endpoint, TRUE)."</pre");
247      watchdog('soap server', "ARGS:<pre>". print_r($args, TRUE)."</pre");
248      watchdog('soap server', "CONTROLLER:<pre>". print_r($controller, TRUE)."</pre");
249    }
250    try {
251      $ret = services_controller_execute($controller, $args);
252    }
253    catch (Exception $e) {
254      $code = $e->getCode();
255      $soap_fault = new SoapFault($e->getMessage(), $code);
256      watchdog('soap_server', $e->getMessage(), 'error');
257      throw $soap_fault;
258    }
259    return $ret;
260  }
261}
262
263/**
264 * Return a list of service methods for the endopint
265 * Method names are created from {resource}_{method} or {resource}_action_{method}
266 * NB: These method names are different from the XMLRPC names because PHP5 can't have a . in function
267 * names
268 *
269 * @param $endpoint
270 */
271function _soap_server_get_methods($endpoint) {
272  $resources = services_get_resources($endpoint);
273  // traverse the resources retrieving valid methods and action methods
274  // TODO: inspect services to confirm the validity of this approach
275  foreach ($resources as $resource_name => $resource_info) {
276    foreach ($resource_info as $method_name => $method_data) {
277      if (!is_array($method_data)) {
278        // it's not a method
279        continue;
280      }
281      if ( isset($method_data['callback'])) {
282        // if this element has a callback we'll assume it is a method
283        $soap_method_name = $resource_name .'_soap_'. $method_name;
284        $supported_methods[$soap_method_name] = $method_data;
285      }
286      if ($method_name == "actions") {
287        // TODO: confirm that all actions elements are valid methods
288        foreach ($method_data as $action_name => $action_data) {
289          $soap_method_name = $resource_name .'_soap_'. $action_name;
290          $supported_methods[$soap_method_name] = $action_data;
291        }
292      }
293    }
294  }
295  return $supported_methods;
296}
297
298/**
299 * Debug function for soap_server services. The devel module is required to use
300 * this function.
301 *
302 * @param $nid
303 */
304function soap_server_debug_client($endpoint, $node) {
305  if (!module_exists('devel')) {
306    drupal_set_message(t('Devel module is required for the debug client function.'), 'error');
307    return t("fail");
308  }
309  $debug_output == array(
310    'endpoint' => $endpoint,
311        'node' => $node,
312  );
313  if (empty($endpoint)) {
314    watchdog('soap_server', 'no endpoint obj in debug client', 'error');
315    return 'fail - no endpoint obj in debug client';
316  }
317  ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
318  $wsdl_url = url($endpoint->path, array('absolute' => TRUE, )) . '?wsdl';
319  try {
320    $client = new SoapClient($wsdl_url, array(
321      'trace' => 1
322    ));
323    // show the available functions as specified in the WSDL
324    $functions = $client->__getFunctions();
325    $debug_output['client functions'] = $functions;
326   
327    // retrieve a node  -  need node access for anonymous
328    $return = $client->node_soap_retrieve($node->nid);
329    $response = $client->__getLastResponse();
330    $request = $client->__getLastRequest();
331    $debug_output["node_soap_retrieve"] = array(
332      $node->nid => array('request' => $request, 'response' => $response, 'return' => $return)
333    );
334   
335    //retrieve a variable - enable services "get a system variable" permission for anonymous
336    $return = $client->system_soap_get_variable('css_js_query_string');
337    $response = $client->__getLastResponse();
338    $request = $client->__getLastRequest();
339    $debug_output["system_soap_get_variable"] = array(
340      'css_js_query_string' => array('request' => $request, 'response' => $response, 'return' => $return)
341    ); 
342   
343    // retrieve a user  - needs acess for anonymous
344    $return = $client->user_soap_retrieve(1);  // anonymous user needs "access user profiles" perm
345    $response = $client->__getLastResponse();
346    $request = $client->__getLastRequest();
347    $debug_output["user_soap_retrieve"] = array(
348      1 => array('request' => $request, 'response' => $response, 'return' => $return)
349    );
350   
351  } catch (Exception $e) {
352    $debug_output['client'] = $e;
353  }
354  dsm($debug_output);
355  return t("done");
356}
357
358/**
359 * Display the content of the WSDL for debugging.
360 *
361 * @param $endpoint
362 */
363function soap_server_debug_wsdl($endpoint) {
364  $wsdl_content = soap_server_get_wsdl($endpoint);
365  $wsdl_content = _soap_server_beautify_wsdl($wsdl_content);
366  if (module_exists('geshifilter')) {
367    $geshi_inc = drupal_get_path('module', 'geshifilter') .'/geshifilter.pages.inc';
368    require_once $geshi_inc;
369    $wsdl_content = geshifilter_geshi_process($wsdl_content, 'xml', TRUE);
370  }
371  else {
372    $wsdl_content = "<code>". htmlspecialchars($wsdl_content) ."</code>";
373  }
374  return $wsdl_content;
375}
376
377/**
378 * Make the WSDL look nice. 
379 *
380 * WARNING: This is NOT a general XML formatter because it will remove whitespace
381 * between tags and in CDATA blocks
382 *
383 * @param unknown_type $xml
384 */
385function _soap_server_beautify_wsdl($xml) {
386  // remove whitespace between tags
387  $xml = preg_replace('/(>)(\s*)(<)/', '$1$3', $xml);
388  // limit spaces and tabs one space
389  $xml = preg_replace('/([ \t]{2,})/', ' ', $xml);
390  // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
391  $xml = preg_replace('/(>)\s*(<)(\/*)/', "$1\n$2$3", $xml);
392 
393  // now indent the tags
394  $token      = strtok($xml, "\n");
395  $result     = ''; // holds formatted version as it is built
396  $pad        = 1; // initial indent
397  $matches    = array(); // returns from preg_matches()
398 
399  // scan each line and adjust indent based on opening/closing tags
400  while ($token !== false) :
401 
402    // test for the various tag states
403   
404    // 1. open and closing tags on same line - no change
405    if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) :
406      $indent=0;
407    // 2. closing tag - outdent now
408    elseif (preg_match('/^<\/\w/', $token, $matches)) :
409      $pad--;
410    // 3. opening tag - don't pad this one, only subsequent tags
411    elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) :
412      $indent=1;
413    // 4. no indentation needed
414    else :
415      $indent = 0;
416    endif;
417   
418    // pad the line with the required number of leading spaces
419    $line    = str_pad($token, strlen($token)+$pad, ' ', STR_PAD_LEFT);
420    $result .= $line . "\n"; // add to the cumulative result, with linefeed
421    $token   = strtok("\n"); // get the next token
422    $pad    += $indent; // update the pad size for subsequent lines   
423  endwhile;
424 
425  return $result;
426}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.