xmlrpc_example.module 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. <?php
  2. /**
  3. * @file
  4. * Module file for xmlrpc_example module.
  5. */
  6. /**
  7. * @defgroup xmlrpc_example Example: XML-RPC
  8. * @ingroup examples
  9. * @{
  10. * Demonstration of XML-RPC in Drupal 7.
  11. *
  12. * This is an example of how to implement and XML-RPC server by registering
  13. * callbacks to specific methods and how to make xmlrpc calls using the built-in
  14. * xmlrpc() factory provided by Drupal.
  15. *
  16. * For experimentation you may be interested in the
  17. * @link http://drupal.org/project/xmlrpctester XML-RPC Tester module @endlink.
  18. *
  19. * Note that the @link http://drupal.org/project/services Services module
  20. * @endlink is another common way to do XML-RPC at this time.
  21. *
  22. * @see hook_xmlrpc()
  23. * @see xmlrpc()
  24. * @see xmlrpc_errno()
  25. * @see xmlrpc_error_msg()
  26. */
  27. // This is the common part of the module, implementing all the code required
  28. // for the client and the server part (most of this code is UI related). The
  29. // menu definition is the only part shared in this implementation.
  30. //
  31. /**
  32. * Implements hook_menu().
  33. *
  34. * Registers all the demonstration forms.
  35. */
  36. function xmlrpc_example_menu() {
  37. $items['examples/xmlrpc'] = array(
  38. 'title' => 'XML-RPC Example',
  39. 'description' => 'Information about the XML-RPC example',
  40. 'page callback' => 'xmlrpc_example_info',
  41. 'access callback' => TRUE,
  42. );
  43. // This is the server configuration form menu entry. This form can be used to
  44. // configure the settings of the exposed services. An XML-RPC server does not
  45. // require a configuration form, and has been included here as an example.
  46. $items['examples/xmlrpc/server'] = array(
  47. 'title' => 'XML-RPC Server configuration',
  48. 'description' => 'Server configuration form',
  49. 'page callback' => 'drupal_get_form',
  50. 'page arguments' => array('xmlrpc_example_server_form'),
  51. 'access callback' => TRUE,
  52. 'weight' => 0,
  53. );
  54. // This is the client form menu entry. This form is used to allow user
  55. // interaction with the services, but again, user interface is not required
  56. // to create an XML-RPC client with Drupal.
  57. $items['examples/xmlrpc/client'] = array(
  58. 'title' => 'XML-RPC Client form',
  59. 'description' => 'Demonstrates client side XML-RPC calls with Drupal',
  60. 'page callback' => 'drupal_get_form',
  61. 'page arguments' => array('xmlrpc_example_client_form'),
  62. 'access callback' => TRUE,
  63. 'weight' => 1,
  64. );
  65. // This part is completely optional. It allows the modification of services
  66. // defined by this or other modules. This configuration form is used to
  67. // enable the hook_xmlrpc_alter API and alter current existing services.
  68. $items['examples/xmlrpc/alter'] = array(
  69. 'title' => 'XML-RPC Alterations',
  70. 'description' => 'Demonstrates how to alter defined XML-RPC services',
  71. 'page callback' => 'drupal_get_form',
  72. 'page arguments' => array('xmlrpc_example_alter_form'),
  73. 'access callback' => TRUE,
  74. 'weight' => 2,
  75. );
  76. return $items;
  77. }
  78. /**
  79. * A simple landing-page information function.
  80. */
  81. function xmlrpc_example_info() {
  82. $server = url($GLOBALS['base_url'] . '/xmlrpc.php', array('external' => TRUE));
  83. $options = array(
  84. 'system.listMethods' => array(),
  85. );
  86. // Make the xmlrpc request and process the results.
  87. $supported_methods = xmlrpc($server, $options);
  88. if ($supported_methods === FALSE) {
  89. drupal_set_message(t('Error return from xmlrpc(): Error: @errno, Message: @message', array('@errno' => xmlrpc_errno(), '@message' => xmlrpc_error_msg())));
  90. }
  91. return array(
  92. 'basic' => array(
  93. '#markup' => t('This XML-RPC example presents code that shows <ul><li><a href="!server">XML-RPC server code</a></li><li><a href="!client">XML-RPC client code</a></li><li>and <a href="!alter">an example hook_xmlrpc_alter() call</a></li></ul>',
  94. array(
  95. '!server' => url('examples/xmlrpc/server'),
  96. '!client' => url('examples/xmlrpc/client'),
  97. '!alter' => url('examples/xmlrpc/alter'),
  98. )
  99. ),
  100. ),
  101. 'method_array' => array(
  102. '#markup' => theme(
  103. 'item_list',
  104. array(
  105. 'title' => t('These methods are supported by !server',
  106. array('!server' => $server)
  107. ),
  108. 'items' => $supported_methods,
  109. )
  110. ),
  111. ),
  112. );
  113. }
  114. // This is the server part of the module, implementing a simple and little
  115. // server with just two simple services. The server is divided in two
  116. // different parts: the XML-RPC implementation (required) and a webform
  117. // interface (optional) to configure some settings in the server side.
  118. //
  119. // The XMLRPC server will define two different services:
  120. //
  121. // - subtract: perform the subtraction of two numbers. The minimum and maximum
  122. // values returned by the server can be configured in the server configuration
  123. // form.
  124. // - add: perform the addition of two numbers. The minimum and maximum values
  125. // returned by the server can be configured in the server configuration form.
  126. //
  127. // If the result value for the operation is over the maximum limit, a custom
  128. // error number 10001 is returned. This is an arbitrary number and could be any
  129. // number.
  130. //
  131. // If the result value for the operation is below the minimum limit, a custom
  132. // error number 10002 is returned. Again, this value is arbitrary and could be
  133. // any other number. Client applications must know the meaning of the error
  134. // numbers returned by the server.
  135. //
  136. // The following code is the XML-RPC implementation of the server part.
  137. // The first step is to define the methods. This methods should be associated
  138. // to callbacks that will be defined later.
  139. //
  140. /**
  141. * Implements hook_xmlrpc().
  142. *
  143. * Provides Drupal with an array to map XML-RPC callbacks to existing functions.
  144. * These functions may be defined in other modules. The example implementation
  145. * defines specific functions for the example services.
  146. *
  147. * Note: Drupal's built-in XML-RPC server already includes several methods by
  148. * default:
  149. *
  150. * Service dicovery methods:
  151. * - system.listMethods: return a list of the methods the server has, by name.
  152. * - system.methodSignature: return a description of the argument format a
  153. * - system.methodHelp: returns a text description of a particular method.
  154. * particular method expects.
  155. *
  156. * Other:
  157. * - system.multicall: perform several method calls in a single xmlrpc request.
  158. * - system.getCapabilities: determine if a given capability is supported.
  159. *
  160. * The methods defined by hook_xmlrpc() will be added to those provided by
  161. * default by Drupal's XML-RPC server.
  162. *
  163. * @see hook_xmlrpc()
  164. */
  165. function xmlrpc_example_xmlrpc() {
  166. $methods[] = array(
  167. // First argument is the method name.
  168. 'xmlrpc_example.add',
  169. // Callback to execute when this method is requested.
  170. '_xmlrpc_example_server_add',
  171. // An array defines the types of output and input values for this method.
  172. array(
  173. // The first value is the return type, an integer in this case.
  174. 'int',
  175. // First operand is an integer.
  176. 'int',
  177. // Second operand is an integer.
  178. 'int',
  179. ),
  180. // Include a little description that is shown when XML-RPC server is
  181. // requested for the implemented methods list.
  182. // Method description.
  183. t('Returns the sum of the two arguments.'),
  184. );
  185. // The subtract method is similar to the addition, only the method name,
  186. // callback and description are different.
  187. $methods[] = array(
  188. 'xmlrpc_example.subtract',
  189. '_xmlrpc_example_server_subtract',
  190. array('int', 'int', 'int'),
  191. t('Return difference of the two arguments.'),
  192. );
  193. return $methods;
  194. }
  195. // The following code for the server is optional if the callbacks already exist.
  196. // A server may implement methods associated to callbacks like node_load(),
  197. // variable_get() or any other existing function (php functions as well).
  198. //
  199. // If the callbacks associated to the methods don't exist they must be
  200. // created. This implementation requires two specific callbacks:
  201. // - _xmlrpc_example_server_add()
  202. // - _xmlrpc_example_server_subtract()
  203. //
  204. //
  205. /**
  206. * This is the callback for the xmlrpc_example.add method.
  207. *
  208. * Sum the two arguments and return value or an error if the result is out of
  209. * the configured limits.
  210. *
  211. * @param int|float $num1
  212. * The first number to be summed.
  213. * @param int|float $num2
  214. * The second number to be summed.
  215. *
  216. * @return int|float
  217. * The sum of the arguments, or error if it is not in server defined bounds.
  218. *
  219. * @see xmlrpc_error()
  220. */
  221. function _xmlrpc_example_server_add($num1, $num2) {
  222. $sum = $num1 + $num2;
  223. // If result is not within maximum and minimum limits,
  224. // return corresponding error.
  225. $max = variable_get('xmlrpc_example_server_max', 10);
  226. $min = variable_get('xmlrpc_example_server_min', 0);
  227. if ($sum > $max) {
  228. return xmlrpc_error(10001, t('Result is over the upper limit (@max) defined by the server.', array('@max' => $max)));
  229. }
  230. if ($sum < $min) {
  231. return xmlrpc_error(10002, t('Result is below the lower limit defined by the server (@min).', array('@min' => $min)));
  232. }
  233. // Otherwise return the result.
  234. return $sum;
  235. }
  236. /**
  237. * This is the callback for the xmlrpc_example.subtract xmlrpc method.
  238. *
  239. * Return the difference of the two arguments, or an error if the result is out
  240. * of the configured limits.
  241. *
  242. * @param int|float $num1
  243. * First number
  244. * @param int|float $num2
  245. * Second number
  246. *
  247. * @return int|float
  248. * The difference of the two arguments, or error if it is not in server
  249. * defined bounds.
  250. *
  251. * @see xmlrpc_error()
  252. */
  253. function _xmlrpc_example_server_subtract($num1, $num2) {
  254. $diference = $num1 - $num2;
  255. $max = variable_get('xmlrpc_example_server_max', 10);
  256. $min = variable_get('xmlrpc_example_server_min', 0);
  257. // If result is not within maximum and minimum limits,
  258. // return corresponding error.
  259. if ($diference > $max) {
  260. return xmlrpc_error(10001, t('Result is above the upper limit (@max) defined by the server.', array('@max' => $max)));
  261. }
  262. if ($diference < $min) {
  263. return xmlrpc_error(10002, t('Result is below the lower limit (@min) defined by the server.', array('@min' => $min)));
  264. }
  265. // Otherwise return the result.
  266. return $diference;
  267. }
  268. // User interface for the XML-RPC Server part.
  269. // A server does not require an interface at all. In this implementation we
  270. // use a server configuration form to set the limits available for the addition
  271. // and subtraction operations.
  272. //
  273. /**
  274. * Returns form array to configure the service options.
  275. *
  276. * Present a form to configure the service options. In this case the maximum
  277. * and minimum values for any of the operations (add or subtraction).
  278. */
  279. function xmlrpc_example_server_form() {
  280. $form = array();
  281. $form['explanation'] = array(
  282. '#markup' => '<div>' . t('This is the XML-RPC server configuration page.<br />Here you may define the maximum and minimum values for the addition or subtraction exposed services.<br />') . '</div>',
  283. );
  284. $form['xmlrpc_example_server_min'] = array(
  285. '#type' => 'textfield',
  286. '#title' => t('Enter the minimum value returned by the subtraction or addition methods'),
  287. '#description' => t('If the result of the operation is lower than this value, a custom XML-RPC error will be returned: 10002.'),
  288. '#default_value' => variable_get('xmlrpc_example_server_min', 0),
  289. '#size' => 5,
  290. '#required' => TRUE,
  291. );
  292. $form['xmlrpc_example_server_max'] = array(
  293. '#type' => 'textfield',
  294. '#title' => t('Enter the maximum value returned by sub or add methods'),
  295. '#description' => t('if the result of the operation is bigger than this value, a custom XML-RPC error will be returned: 10001.'),
  296. '#default_value' => variable_get('xmlrpc_example_server_max', 10),
  297. '#size' => 5,
  298. '#required' => TRUE,
  299. );
  300. $form['info'] = array(
  301. '#type' => 'markup',
  302. '#markup' => '<div>' . t('Use the <a href="!link">XML-RPC Client example form</a> to experiment', array('!link' => url('examples/xmlrpc/client'))) . '</div>',
  303. );
  304. if (variable_get('xmlrpc_example_alter_enabled', FALSE)) {
  305. $form['overridden'] = array(
  306. '#type' => 'markup',
  307. '#markup' => '<div><strong>' . t('Just a note of warning: The <a href="!link">alter form</a> has been used to disable the limits, so you may want to turn that off if you do not want it.', array('!link' => url('examples/xmlrpc/alter'))) . '</strong></div>',
  308. );
  309. }
  310. return system_settings_form($form);
  311. }
  312. // The server part of the module ends here.
  313. //
  314. // This is the client part of the module. If defines a form with two input
  315. // fields to call xmlrpc_example.add or xmlrpc_example.subtract methods on this
  316. // host. Please note that having a user interface to query an XML-RPC service is
  317. // not required. A method can be requested to a server using the xmlrpc()
  318. // function directly. We have included an user interface to make the testing
  319. // easier.
  320. //
  321. // The client user interface part of the module starts here.
  322. //
  323. /**
  324. * Returns a form array to take input for two arguments.
  325. *
  326. * Present a form to get two arguments, and make a call to an XML-RPC server
  327. * using these arguments as input, showing the result in a message.
  328. */
  329. function xmlrpc_example_client_form() {
  330. $form = array();
  331. $form['explanation'] = array(
  332. '#markup' => '<div>' . t('This example demonstrates how to make XML-RPC calls with Drupal. <br />The "Request methods" button makes a request to the server and asks for the available list of methods, as a service discovery request. <br/>The "Add integers" and "Subtract integers" use the xmlrpc() function to act as a client, calling the XML-RPC server defined in this same example for some defined methods.<br />An XML-RPC error will result if the result in the addition or subtraction requested is out of bounds defined by the server. These error numbers are defined by the server. <br />The "Add and Subtract" button performs a multicall operation on the XML-RPC server: several requests in a single XML-RPC call.<br />') . '</div>',
  333. );
  334. // We are going to call add and subtract methods, and
  335. // they work with integer values.
  336. $form['num1'] = array(
  337. '#type' => 'textfield',
  338. '#title' => t('Enter an integer'),
  339. '#default_value' => 2,
  340. '#size' => 5,
  341. '#required' => TRUE,
  342. );
  343. $form['num2'] = array(
  344. '#type' => 'textfield',
  345. '#title' => t('Enter a second integer'),
  346. '#default_value' => 2,
  347. '#size' => 5,
  348. '#required' => TRUE,
  349. );
  350. // Include several buttons, each of them calling a different method.
  351. // This button submits a XML-RPC call to the system.listMethods method.
  352. $form['information'] = array(
  353. '#type' => 'submit',
  354. '#value' => t('Request methods'),
  355. '#submit' => array('xmlrpc_example_client_request_methods_submit'),
  356. );
  357. // This button submits a XML-RPC call to the xmlrpc_example.add method.
  358. $form['add'] = array(
  359. '#type' => 'submit',
  360. '#value' => t('Add the integers'),
  361. '#submit' => array('xmlrpc_example_client_add_submit'),
  362. );
  363. // This button submits a XML-RPC call to the xmlrpc_example.subtract method.
  364. $form['subtract'] = array(
  365. '#type' => 'submit',
  366. '#value' => t('Subtract the integers'),
  367. '#submit' => array('xmlrpc_example_client_subtract_submit'),
  368. );
  369. // This button submits a XML-RPC call to the system.multicall method.
  370. $form['add_subtract'] = array(
  371. '#type' => 'submit',
  372. '#value' => t('Add and Subtract'),
  373. '#submit' => array('xmlrpc_example_client_multicall_submit'),
  374. );
  375. if (variable_get('xmlrpc_example_alter_enabled', FALSE)) {
  376. $form['overridden'] = array(
  377. '#type' => 'markup',
  378. '#markup' => '<div><strong>' . t('Just a note of warning: The <a href="!link">alter form</a> has been used to disable the limits, so you may want to turn that off if you do not want it.', array('!link' => url('examples/xmlrpc/alter'))) . '</strong></div>',
  379. );
  380. }
  381. return $form;
  382. }
  383. /**
  384. * Submit handler to query system.listMethods.
  385. *
  386. * Submit: query the XML-RPC endpoint for the method system.listMethods
  387. * and report the result as a Drupal message. The result is a list of the
  388. * available methods in this XML-RPC server.
  389. *
  390. * Important note: Not all XML-RPC servers implement this method. Drupal's
  391. * built-in XML-RPC server implements this method by default.
  392. *
  393. * @param array $form
  394. * Form array.
  395. * @param array $form_state
  396. * Form_state array.
  397. *
  398. * @see xmlrpc()
  399. * @see xmlrpc_errno()
  400. * @see xmlrpc_error_msg()
  401. */
  402. function xmlrpc_example_client_request_methods_submit($form, &$form_state) {
  403. // First define the endpoint of the XML-RPC service, in this case this is our
  404. // own server.
  405. $server = url($GLOBALS['base_url'] . '/xmlrpc.php', array('external' => TRUE));
  406. // Then we should define the method to call. xmlrpc() requires that all the
  407. // information related to the called method be passed as an array in the form
  408. // of 'method_name' => arguments_array
  409. $options = array(
  410. 'system.listMethods' => array(),
  411. );
  412. // Make the xmlrpc request and process the results.
  413. $result = xmlrpc($server, $options);
  414. if ($result === FALSE) {
  415. drupal_set_message(
  416. t('Error return from xmlrpc(): Error: @errno, Message: @message',
  417. array('@errno' => xmlrpc_errno(), '@message' => xmlrpc_error_msg())),
  418. 'error'
  419. );
  420. }
  421. else {
  422. drupal_set_message(
  423. t('The XML-RPC server returned this response: <pre>@response</pre>',
  424. array('@response' => print_r($result, TRUE)))
  425. );
  426. }
  427. }
  428. /**
  429. * Submit handler to query xmlrpc_example.add.
  430. *
  431. * Submit: query the XML-RPC endpoint for the method xmlrpc_example.add
  432. * and report the result as a Drupal message.
  433. *
  434. * @param array $form
  435. * Form array.
  436. * @param array $form_state
  437. * Form_state array.
  438. *
  439. * @see xmlrpc()
  440. * @see xmlrpc_errno()
  441. * @see xmlrpc_error_msg()
  442. */
  443. function xmlrpc_example_client_add_submit($form, &$form_state) {
  444. // First define the endpoint of the XML-RPC service, in this case is our
  445. // own server.
  446. $server = url($GLOBALS['base_url'] . '/xmlrpc.php', array('external' => TRUE));
  447. // Then we should define the method to call. xmlrpc() requires that all the
  448. // information related to the called method is passed as an array in the form
  449. // of 'method_name' => arguments_array
  450. $options = array(
  451. 'xmlrpc_example.add' => array(
  452. (int) $form_state['values']['num1'],
  453. (int) $form_state['values']['num2'],
  454. ),
  455. );
  456. // Make the xmlrpc request and process the results.
  457. $result = xmlrpc($server, $options);
  458. if ($result === FALSE) {
  459. drupal_set_message(
  460. t('Error return from xmlrpc(): Error: @errno, Message: @message',
  461. array('@errno' => xmlrpc_errno(), '@message' => xmlrpc_error_msg())),
  462. 'error'
  463. );
  464. }
  465. else {
  466. drupal_set_message(
  467. t('The XML-RPC server returned this response: @response',
  468. array('@response' => print_r($result, TRUE)))
  469. );
  470. }
  471. }
  472. /**
  473. * Submit handler to query xmlrpc_example.subtract.
  474. *
  475. * Submit: query the XML-RPC endpoint for the method xmlrpc_example.subtract
  476. * and report the result as a Drupal message.
  477. *
  478. * @param array $form
  479. * Form array.
  480. * @param array $form_state
  481. * Form_state array.
  482. *
  483. * @see xmlrpc()
  484. * @see xmlrpc_errno()
  485. * @see xmlrpc_error_msg()
  486. * @see xmlrpc_example_client_add_submit()
  487. */
  488. function xmlrpc_example_client_subtract_submit($form, &$form_state) {
  489. $server = url($GLOBALS['base_url'] . '/xmlrpc.php', array('external' => TRUE));
  490. $options = array(
  491. 'xmlrpc_example.subtract' => array(
  492. (int) $form_state['values']['num1'],
  493. (int) $form_state['values']['num2'],
  494. ),
  495. );
  496. // Make the xmlrpc request and process the results.
  497. $result = xmlrpc($server, $options);
  498. if ($result === FALSE) {
  499. drupal_set_message(
  500. t('Error return from xmlrpc(): Error: @errno, Message: @message',
  501. array('@errno' => xmlrpc_errno(), '@message' => xmlrpc_error_msg())),
  502. 'error'
  503. );
  504. }
  505. else {
  506. drupal_set_message(
  507. t('The XML-RPC server returned this response: @response',
  508. array('@response' => print_r($result, TRUE)))
  509. );
  510. }
  511. }
  512. /**
  513. * Submit a multicall request.
  514. *
  515. * Submit a multicall request: query the XML-RPC endpoint for the methods
  516. * xmlrpc_example.add and xmlrpc_example.subtract and report the result as a
  517. * Drupal message. Drupal's XML-RPC client builds the system.multicall request
  518. * automatically when there is more than one method to call.
  519. *
  520. * @param array $form
  521. * Form array.
  522. * @param array $form_state
  523. * Form_state array.
  524. *
  525. * @see xmlrpc()
  526. * @see xmlrpc_errno()
  527. * @see xmlrpc_error_msg()
  528. * @see xmlrpc_example_client_multicall_submit()
  529. */
  530. function xmlrpc_example_client_multicall_submit($form, &$form_state) {
  531. $server = url($GLOBALS['base_url'] . '/xmlrpc.php', array('external' => TRUE));
  532. /*
  533. * Drupal's built-in xmlrpc server supports the system.multicall method.
  534. *
  535. * To make a multicall request, the main invoked method should be the
  536. * function 'system.multicall', and the arguments to make this call must be
  537. * defined as an array of single method calls, being the array keys the
  538. * service methods to be called, and the array elements the method arguments.
  539. *
  540. * See the code below this comment as example.
  541. */
  542. // Build an array of several calls, Drupal's xmlrpc built-in support will
  543. // construct the correct system.multicall request for the server.
  544. $options = array(
  545. 'xmlrpc_example.add' => array(
  546. (int) $form_state['values']['num1'],
  547. (int) $form_state['values']['num2'],
  548. ),
  549. 'xmlrpc_example.subtract' => array(
  550. (int) $form_state['values']['num1'],
  551. (int) $form_state['values']['num2'],
  552. ),
  553. );
  554. // Make the xmlrpc request and process the results.
  555. $result = xmlrpc($server, $options);
  556. if ($result === FALSE) {
  557. drupal_set_message(
  558. t('Error return from xmlrpc(): Error: @errno, Message: @message',
  559. array('@errno' => xmlrpc_errno(), '@message' => xmlrpc_error_msg()))
  560. );
  561. }
  562. else {
  563. drupal_set_message(
  564. t('The XML-RPC server returned this response: <pre>@response</pre>',
  565. array('@response' => print_r($result, TRUE)))
  566. );
  567. }
  568. }
  569. // The client part of the module ends here.
  570. //
  571. // The alteration part of the module starts here. hook_xmlrpc_alter() is
  572. // useful when you want to extend, limit or alter methods defined by other
  573. // modules. This part is not required to have an XML-RPC server or client
  574. // working, but is useful to understand what can we do using current xmlrpc
  575. // API provided by drupal.
  576. //
  577. // This code can be defined in other module to alter the methods exposed by
  578. // this xmlrpc demonstration server, or can be used to alter methods defined
  579. // by other modules implementing hook_xmlrpc()
  580. //
  581. // As with the rest of the example module, an user interface is not required to
  582. // make use of this hook. A configuration form is included to enable/disable
  583. // this functionality, but this part is optional if you want to implement
  584. // hook_xmlrpc_alter()
  585. //
  586. // This is the XML-RPC code for the alteration part. It will check if an option
  587. // to enable the functionality is enabled and then alter it. We alter the
  588. // 'xmlrpc_example.add' and 'xmlrpc_example.subtract' methods, changing the
  589. // associated callback with custom functions. The modified methods (with
  590. // new callbacks associated) will perform the addition or subtraction of the
  591. // integer inputs, but will never check for limits nor return errors.
  592. /**
  593. * Implements hook_xmlrpc_alter().
  594. *
  595. * Check to see if xmlrpc_example.add and xmlrpc_example.subtract methods are
  596. * defined and replace their callbacks with custom code.
  597. *
  598. * @see hook_xmlrpc_alter()
  599. */
  600. function xmlrpc_example_xmlrpc_alter(&$methods) {
  601. // Only perform alterations if instructed to do so.
  602. if (!variable_get('xmlrpc_example_alter_enabled', 0)) {
  603. return;
  604. }
  605. // Loop all defined methods (other modules may include additional methods).
  606. foreach ($methods as $index => $method) {
  607. // First element in the method array is the method name.
  608. if ($method[0] == 'xmlrpc_example.add') {
  609. // Replace current callback with custom callback
  610. // (second argument of the array).
  611. $methods[$index][1] = '_xmlrpc_example_alter_add';
  612. }
  613. // Do the same for the substraction method.
  614. if ($method[0] == 'xmlrpc_example.subtract') {
  615. $methods[$index][1] = '_xmlrpc_example_alter_subtract';
  616. }
  617. }
  618. }
  619. // Now we define the custom callbacks replacing the original defined by the
  620. // altered methods: xmlrpc_example.add and _xmlrpc_example.subtract. These
  621. // new callbacks will not check if the result of the operation is within the
  622. // limits defined by the server and will always return value of the operation.
  623. /**
  624. * Sum the two arguments without limit checking.
  625. *
  626. * This is the replacement callback for the xmlrpc_example.add xmlrpc method.
  627. *
  628. * @param int|float $num1
  629. * First number
  630. * @param int|float $num2
  631. * Second Number
  632. *
  633. * @return int|float
  634. * The sum of the arguments
  635. */
  636. function _xmlrpc_example_alter_add($num1, $num2) {
  637. return $num1 + $num2;
  638. }
  639. /**
  640. * Return the difference of the two arguments without limit checking.
  641. *
  642. * This is the replacement callback for xmlrpc_example.subtract xmlrpc method.
  643. *
  644. * @param int|float $num1
  645. * First number
  646. * @param int|float $num2
  647. * Second Number
  648. *
  649. * @return int|float
  650. * The difference of the two arguments
  651. */
  652. function _xmlrpc_example_alter_subtract($num1, $num2) {
  653. return $num1 - $num2;
  654. }
  655. // Our implementation of hook_xmlrpc_alter will work only if a system variable
  656. // is set to true, and we need a configuration form to enable/disable this
  657. // 'feature'. This is the user interface to enable or disable the
  658. // hook_xmlrpc_alter operations.
  659. /**
  660. * Present a form to enable/disable the code implemented in hook_xmlrpc_alter.
  661. */
  662. function xmlrpc_example_alter_form() {
  663. $form = array();
  664. $form['explanation'] = array(
  665. '#markup' => '<div>' . t('This is a configuration form to enable the alteration of XML-RPC methods using hook_xmlrpc_alter.<br />hook_xmlrpc_alter() can be used to alter the current defined methods by other modules. In this case as demonstration, we will overide current add and subtraction methods with others not being limited. Remember that this hook is optional and is not required to create XMLRPC services.<br />') . '</div>',
  666. );
  667. $form['xmlrpc_example_alter_enabled'] = array(
  668. '#type' => 'checkbox',
  669. '#title' => t('Overide current xmlrpc_example.add and xmlrpc_example.subtraction methods'),
  670. '#description' => t('If this checkbox is enabled, the default methods will be replaced with custom methods that ignore the XML-RPC server maximum and minimum restrictions.'),
  671. '#default_value' => variable_get('xmlrpc_example_alter_enabled', 0),
  672. );
  673. $form['info'] = array(
  674. '#markup' => '<div>' . t('Use the <a href="!link">client submission form</a> to see the results of checking this checkbox', array('!link' => url('examples/xmlrpc/client'))) . '</div>',
  675. );
  676. return system_settings_form($form);
  677. }
  678. /**
  679. * @} End of "defgroup xmlrpc_example".
  680. */