source: sipes/modules_contrib/services/services.runtime.inc @ a8b1f3f

stableversion-3.0
Last change on this file since a8b1f3f was 3959b2a, checked in by planificacion <planificacion@…>, 8 años ago

Se agregaron los modulos para permitir el despliegue de servicios web (SOAP)

  • Propiedad mode establecida a 100644
File size: 13.5 KB
Línea 
1<?php
2
3/**
4 * @file
5 *  Contains functions that only are necessary when a service call is made.
6 *  This has broken out so that this code isn't loaded for every page load.
7 */
8
9/**
10 * A exception thrown by services and related modules when something goes
11 * wrong.
12 */
13class ServicesException extends Exception {
14  private $data;
15
16  /**
17   * Constructor for the ServicesException.
18   *
19   * @param string $message
20   *  Error message.
21   * @param int $code
22   *  Optional. Error code. This often maps to the HTTP status codes. Defaults
23   *  to 0.
24   * @param mixed $data
25   *  Information that can be used by the server to return information about
26   *  the error.
27   */
28  public function __construct($message, $code = 0, $data = NULL) {
29    parent::__construct($message, $code);
30
31    $this->data = $data;
32  }
33
34  /**
35   * Returns the data associated with the exception.
36   *
37   * @return mixed
38   */
39  public function getData() {
40    return $this->data;
41  }
42}
43
44/**
45 * A exception thrown by services and related modules when an error related to
46 * a specific argument is encountered.
47 */
48class ServicesArgumentException extends ServicesException {
49  private $argument;
50
51  /**
52   * Constructor for the ServicesException.
53   *
54   * @param string $message
55   *  Error message.
56   * @param string $argument_name
57   *  The name of the argument that caused the error.
58   * @param int $code
59   *  Optional. Error code. This often maps to the HTTP status codes. Defaults
60   *  to 0.
61   * @param mixed $data
62   *  Information that can be used by the server to return information about
63   *  the error.
64   */
65  public function __construct($message, $argument_name, $code, $data) {
66    parent::__construct($message, $code, $data);
67
68    $this->argument = $argument_name;
69  }
70
71  /**
72   * Returns the name of the argument that caused the error.
73   *
74   * @return string
75   *  The name of the argument.
76   */
77  public function getArgumentName() {
78    return $this->argument;
79  }
80}
81
82/**
83 * Performs access checks and executes a services controller.
84 * This method is called by server implementations.
85 *
86 * @param array $controller
87 *  An array containing information about the controller
88 * @param array $args
89 *  The arguments that should be passed to the controller.
90 * @param array $auth_args
91 *  The arguments that should be passed to the authentication module.
92 * @param array $options
93 *  Options for the execution. Use 'skip_authentication'=>TRUE to skip the
94 *  services-specific authentication checks. Access checks will always be
95 *  made.
96 */
97function services_controller_execute($controller, $args = array(), $options = array()) {
98  global $user;
99  // Check for missing arguments.
100  $server_info =  services_server_info_object();
101  if ($server_info->debug) {
102    watchdog('services', 'Controller: <pre>@controller</pre>', array('@controller' => print_r($controller, TRUE)), WATCHDOG_DEBUG);
103    watchdog('services', 'Passed arguments: <pre>@arguments</pre>', array('@arguments' => print_r($args, TRUE)), WATCHDOG_DEBUG);
104  }
105
106  $original_user = $user;
107  $old_state = session_save_session();
108  session_save_session(FALSE);
109  $user = drupal_anonymous_user();
110
111  services_set_server_info('original_user', $original_user);
112
113  // Check authentication.
114  if (!isset($options['skip_authentication']) || !$options['skip_authentication']) {
115    $endpoint_name = services_get_server_info('endpoint');
116    $endpoint = services_endpoint_load($endpoint_name);
117
118    foreach ($endpoint->authentication as $auth_module => $settings) {
119      if (isset($settings) && $auth_error = services_auth_invoke($auth_module, 'authenticate_call', $settings, $controller, $args)) {
120        return services_error($auth_error, 401);
121      }
122    }
123  }
124
125  // Load the proper file.
126  if (!empty($controller['file']) && $file = $controller['file']) {
127    module_load_include($file['type'], $file['module'], (isset($file['name']) ? $file['name'] : NULL));
128  }
129
130  // Construct access arguments array.
131  if (isset($controller['access arguments'])) {
132    $access_arguments = $controller['access arguments'];
133    if (isset($controller['access arguments append']) && $controller['access arguments append']) {
134      $access_arguments[] = $args;
135    }
136  }
137  else {
138    // Just use the arguments array if no access arguments have been specified
139    $access_arguments = $args;
140  }
141
142  // Load the proper file for the access callback.
143  if (!empty($controller['access callback file']) && $access_cb_file = $controller['access callback file']) {
144    $access_cb_file_name = isset($access_cb_file['name']) ? $access_cb_file['name'] : NULL;
145    module_load_include($access_cb_file['type'], $access_cb_file['module'], $access_cb_file_name);
146  }
147
148  // Call default or custom access callback.
149  if (call_user_func_array($controller['access callback'], $access_arguments) != TRUE) {
150    return services_error(t('Access denied for user !uid "@user"', array(
151      '!uid'  => $user->uid,
152      '@user' => isset($user->name) ? $user->name : 'anonymous',
153    )), 401);
154  }
155
156  // Preprocess controller and arguments.
157  $controller['__drupal_alter_by_ref'] = array(&$args);
158  drupal_alter('services_request_preprocess', $controller);
159
160  // Execute the controller callback.
161  $result = call_user_func_array($controller['callback'], $args);
162
163  if (isset($server_root) && $server_root) {
164    chdir($server_root);
165  }
166
167  // Postprocess controller, arguments and result.
168  $controller['__drupal_alter_by_ref'] = array(&$args, &$result);
169  drupal_alter('services_request_postprocess', $controller);
170
171  if (session_save_session($user) === FALSE) {
172    $user = $original_user;
173    session_save_session($old_state);
174  }
175  if ($server_info->debug) {
176    watchdog('services', 'results: <pre>@results</pre>', array('@results' => print_r($result, TRUE)), WATCHDOG_DEBUG);
177  }
178  return $result;
179}
180
181/**
182 * Gets information about a authentication module.
183 *
184 * @param string $module
185 *  The module to get info for.
186 * @return mixed
187 *  The information array, or FALSE if the information wasn't found.
188 */
189function services_authentication_info($module) {
190  $info = FALSE;
191  if (!empty($module) && module_exists($module) && is_callable($module . '_services_authentication_info')) {
192    $info = call_user_func($module . '_services_authentication_info');
193  }
194  return $info;
195}
196
197/**
198 * Invokes a authentication module callback.
199 *
200 * @param string $module
201 *  The authentication module to invoke the callback for.
202 * @param string $method
203 *  The callback to invoke.
204 * @param string $arg1
205 *  Optional. First argument to pass to the callback.
206 * @param string $arg2
207 *  Optional. Second argument to pass to the callback.
208 * @param string $arg3
209 *  Optional. Third argument to pass to the callback.
210 * @param string $arg4
211 *  Optional. Fourth argument to pass to the callback.
212 * @return mixed
213 *
214 * Aren't these really the following?
215 *  arg1 = Settings
216 *  arg2 = Method
217 *  arg3 = Controller
218 *  arg4 = Auth args
219 *
220 */
221function services_auth_invoke($module, $method, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NULL, $arg4 = NULL) {
222  // Get information about the auth module
223  $info = services_authentication_info($module);
224  $func = $info && !empty($info[$method]) ? $info[$method] : FALSE;
225  if ($func) {
226    if (!empty($info['file'])) {
227      require_once(drupal_get_path('module', $module) . '/' . $info['file']);
228    }
229
230    if (is_callable($func)) {
231      $args = func_get_args();
232      // Replace module and method name and arg1 with reference to $arg1 and $arg2.
233      array_splice($args, 0, 5, array(&$arg1, &$arg2, &$arg3, &$arg4));
234      return call_user_func_array($func, $args);
235    }
236  }
237  else {
238    return TRUE;
239  }
240}
241
242/**
243 * Formats a resource uri using the formatter registered through
244 * services_set_server_info().
245 *
246 * @param array $path
247 *  An array of strings containing the component parts of the path to the resource.
248 * @return string
249 *  Returns the formatted resource uri, or NULL if no formatter has been registered.
250 */
251function services_resource_uri($path) {
252  //We need to use the alias if it exists.
253  $endpoint_name = services_get_server_info('endpoint');
254  $endpoint = services_endpoint_load($endpoint_name);
255  if (!empty($path[0]) && !empty($endpoint->resources[$path[0]]['alias'])) {
256    $path[0] = $endpoint->resources[$path[0]]['alias'];
257  }
258  $formatter = services_get_server_info('resource_uri_formatter');
259  if ($formatter) {
260    return call_user_func($formatter, $path);
261  }
262  return NULL;
263}
264
265/**
266 * Sets a server info value
267 *
268 * @param string $key
269 *  The key of the server info value.
270 * @param mixed $value
271 *  The value.
272 * @return void
273 */
274function services_set_server_info($key, $value) {
275  $info = services_server_info_object();
276  $info->$key = $value;
277}
278
279/**
280 * Sets multiple server info values from a associative array.
281 *
282 * @param array $values
283 *  An associative array containing server info values.
284 * @return void
285 */
286function services_set_server_info_from_array($values) {
287  $info = services_server_info_object();
288  foreach ($values as $key => $value) {
289    $info->$key = $value;
290  }
291}
292
293/**
294 * Gets a server info value.
295 *
296 * @param string $key
297 *  The key for the server info value.
298 * @param mixed $default
299 *  The default value to return if the value isn't defined.
300 * @return mixed
301 *  The server info value.
302 */
303function services_get_server_info($key, $default = NULL) {
304  $info = services_server_info_object();
305  $value = $default;
306  if (isset($info->$key)) {
307    $value = $info->$key;
308  }
309  return $value;
310}
311
312/**
313 * Gets the server info object.
314 *
315 * @param bool $reset
316 *  Pass TRUE if the server info object should be reset.
317 * @return object
318 *  Returns the server info object.
319 */
320function services_server_info_object($reset = FALSE) {
321  static $info;
322  if (!$info) {
323    $info = new stdClass();
324  }
325  return $info;
326}
327
328/**
329 * Prepare an error message for returning to the server.
330 *
331 * @param string $message
332 *  Error message.
333 * @param int $code
334 *  Optional. Error code. This often maps to the HTTP status codes. Defaults
335 *  to 0.
336 * @param mixed $data
337 *  Optional. Information that can be used by the server to return information about the error. Defaults to null.
338 * @return mixed
339 */
340function services_error($message, $code = 0, $data = NULL) {
341  throw new ServicesException($message, $code, $data);
342}
343
344/**
345 * Make any changes we might want to make to node.
346 */
347function services_node_load($node, $fields = array()) {
348  if (!isset($node->nid)) {
349    return NULL;
350  }
351
352  // Loop through and get only requested fields
353  if (count($fields) > 0) {
354    foreach ($fields as $field) {
355      $val->{$field} = $node->{$field};
356    }
357  }
358  else {
359    $val = $node;
360  }
361
362  return $val;
363}
364
365/**
366 * Backup current session data and import user session.
367 */
368function services_session_load($sessid) {
369  global $user;
370
371  // If user's session is already loaded, just return current user's data
372  if ($user->sid == $sessid) {
373    return $user;
374  }
375
376  // Make backup of current user and session data
377  $backup = $user;
378  $backup->session = session_encode();
379
380  // Empty current session data
381  $_SESSION = array();
382
383  // Some client/servers, like XMLRPC, do not handle cookies, so imitate it to make sess_read() function try to look for user,
384  // instead of just loading anonymous user :).
385  $session_name = session_name();
386  if (!isset($_COOKIE[$session_name])) {
387    $_COOKIE[$session_name] = $sessid;
388  }
389
390  // Load session data
391  session_id($sessid);
392  sess_read($sessid);
393
394  // Check if it really loaded user and, for additional security, if user was logged from the same IP. If not, then revert automatically.
395  if ($user->sid != $sessid) {
396    services_session_unload($backup);
397    return NULL;
398  }
399
400  // Prevent saving of this impersonation in case of unexpected failure.
401  session_save_session(FALSE);
402
403  return $backup;
404}
405
406/**
407 * Revert to previously backuped session.
408 */
409function services_session_unload($backup) {
410  global $user;
411
412  // No point in reverting if it's the same user's data
413  if ($user->sid == $backup->sid) {
414    return;
415  }
416
417  // Some client/servers, like XMLRPC, do not handle cookies, so imitate it to make sess_read() function try to look for user,
418  // instead of just loading anonymous user :).
419  $session_name = session_name();
420  if (!isset($_COOKIE[$session_name])) {
421    $_COOKIE[$session_name] = $backup->sessid;
422  }
423
424  // Save current session data
425  sess_write($user->sid, session_encode());
426
427  // Empty current session data
428  $_SESSION = array();
429
430  // Revert to previous user and session data
431  $user = $backup;
432  session_id($backup->sessid);
433  session_decode($user->session);
434
435  session_save_session(TRUE);
436}
437
438
439/**
440 * Extract arguments for a services method callback, preserving backwards compatibility with #1083242.
441 *
442 * @param array $data
443 *  original argument passed to a resource method callback
444 * @param string $field
445 *  name of the field where arguments should be checked for
446 * @return array
447 */
448
449// Adds backwards compatability with regression fixed in #1083242
450function _services_arg_value($data, $field) {
451  if (isset($data[$field]) && count($data) == 1 && is_array($data[$field])) {
452    return $data[$field];
453  }
454  return $data;
455}
456
457
458/**
459 * Extract arguments for a services method access callback, preserving backwards compatibility with #1083242.
460 *
461 * @param string $data
462 *  original argument passed to a resource method callback
463 * @param mixed $fields
464 *  name of the field(s) where arguments should be checked for, either as a string or as an array of strings
465 * @return array
466 */
467
468// Adds backwards compatability with regression fixed in #1083242
469function _services_access_value($data, $fields) {
470
471  if (!is_array($fields)) {
472    $fields = array($fields);
473  }
474
475  foreach ($fields as $field) {
476    if (is_array($data) && isset($data[$field]) && count($data) == 1) {
477      return $data[$field];
478    }
479  }
480  return $data;
481}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.