[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/ -> externallib.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  /**
  19   * Support for external API
  20   *
  21   * @package    core_webservice
  22   * @copyright  2009 Petr Skodak
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Returns detailed function information
  30   *
  31   * @param string|object $function name of external function or record from external_function
  32   * @param int $strictness IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found;
  33   *                        MUST_EXIST means throw exception if no record or multiple records found
  34   * @return stdClass description or false if not found or exception thrown
  35   * @since Moodle 2.0
  36   */
  37  function external_function_info($function, $strictness=MUST_EXIST) {
  38      global $DB, $CFG;
  39  
  40      if (!is_object($function)) {
  41          if (!$function = $DB->get_record('external_functions', array('name'=>$function), '*', $strictness)) {
  42              return false;
  43          }
  44      }
  45  
  46      // First try class autoloading.
  47      if (!class_exists($function->classname)) {
  48          // Fallback to explicit include of externallib.php.
  49          $function->classpath = empty($function->classpath) ? core_component::get_component_directory($function->component).'/externallib.php' : $CFG->dirroot.'/'.$function->classpath;
  50          if (!file_exists($function->classpath)) {
  51              throw new coding_exception('Cannot find file with external function implementation');
  52          }
  53          require_once($function->classpath);
  54          if (!class_exists($function->classname)) {
  55              throw new coding_exception('Cannot find external class');
  56          }
  57      }
  58  
  59      $function->parameters_method = $function->methodname.'_parameters';
  60      $function->returns_method    = $function->methodname.'_returns';
  61  
  62      // make sure the implementaion class is ok
  63      if (!method_exists($function->classname, $function->methodname)) {
  64          throw new coding_exception('Missing implementation method of '.$function->classname.'::'.$function->methodname);
  65      }
  66      if (!method_exists($function->classname, $function->parameters_method)) {
  67          throw new coding_exception('Missing parameters description');
  68      }
  69      if (!method_exists($function->classname, $function->returns_method)) {
  70          throw new coding_exception('Missing returned values description');
  71      }
  72  
  73      // fetch the parameters description
  74      $function->parameters_desc = call_user_func(array($function->classname, $function->parameters_method));
  75      if (!($function->parameters_desc instanceof external_function_parameters)) {
  76          throw new coding_exception('Invalid parameters description');
  77      }
  78  
  79      // fetch the return values description
  80      $function->returns_desc = call_user_func(array($function->classname, $function->returns_method));
  81      // null means void result or result is ignored
  82      if (!is_null($function->returns_desc) and !($function->returns_desc instanceof external_description)) {
  83          throw new coding_exception('Invalid return description');
  84      }
  85  
  86      //now get the function description
  87      //TODO MDL-31115 use localised lang pack descriptions, it would be nice to have
  88      //      easy to understand descriptions in admin UI,
  89      //      on the other hand this is still a bit in a flux and we need to find some new naming
  90      //      conventions for these descriptions in lang packs
  91      $function->description = null;
  92      $servicesfile = core_component::get_component_directory($function->component).'/db/services.php';
  93      if (file_exists($servicesfile)) {
  94          $functions = null;
  95          include($servicesfile);
  96          if (isset($functions[$function->name]['description'])) {
  97              $function->description = $functions[$function->name]['description'];
  98          }
  99          if (isset($functions[$function->name]['testclientpath'])) {
 100              $function->testclientpath = $functions[$function->name]['testclientpath'];
 101          }
 102      }
 103  
 104      return $function;
 105  }
 106  
 107  /**
 108   * Exception indicating user is not allowed to use external function in the current context.
 109   *
 110   * @package    core_webservice
 111   * @copyright  2009 Petr Skodak
 112   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 113   * @since Moodle 2.0
 114   */
 115  class restricted_context_exception extends moodle_exception {
 116      /**
 117       * Constructor
 118       *
 119       * @since Moodle 2.0
 120       */
 121      function __construct() {
 122          parent::__construct('restrictedcontextexception', 'error');
 123      }
 124  }
 125  
 126  /**
 127   * Base class for external api methods.
 128   *
 129   * @package    core_webservice
 130   * @copyright  2009 Petr Skodak
 131   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 132   * @since Moodle 2.0
 133   */
 134  class external_api {
 135  
 136      /** @var stdClass context where the function calls will be restricted */
 137      private static $contextrestriction;
 138  
 139      /**
 140       * Set context restriction for all following subsequent function calls.
 141       *
 142       * @param stdClass $context the context restriction
 143       * @since Moodle 2.0
 144       */
 145      public static function set_context_restriction($context) {
 146          self::$contextrestriction = $context;
 147      }
 148  
 149      /**
 150       * This method has to be called before every operation
 151       * that takes a longer time to finish!
 152       *
 153       * @param int $seconds max expected time the next operation needs
 154       * @since Moodle 2.0
 155       */
 156      public static function set_timeout($seconds=360) {
 157          $seconds = ($seconds < 300) ? 300 : $seconds;
 158          core_php_time_limit::raise($seconds);
 159      }
 160  
 161      /**
 162       * Validates submitted function parameters, if anything is incorrect
 163       * invalid_parameter_exception is thrown.
 164       * This is a simple recursive method which is intended to be called from
 165       * each implementation method of external API.
 166       *
 167       * @param external_description $description description of parameters
 168       * @param mixed $params the actual parameters
 169       * @return mixed params with added defaults for optional items, invalid_parameters_exception thrown if any problem found
 170       * @since Moodle 2.0
 171       */
 172      public static function validate_parameters(external_description $description, $params) {
 173          if ($description instanceof external_value) {
 174              if (is_array($params) or is_object($params)) {
 175                  throw new invalid_parameter_exception('Scalar type expected, array or object received.');
 176              }
 177  
 178              if ($description->type == PARAM_BOOL) {
 179                  // special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
 180                  if (is_bool($params) or $params === 0 or $params === 1 or $params === '0' or $params === '1') {
 181                      return (bool)$params;
 182                  }
 183              }
 184              $debuginfo = 'Invalid external api parameter: the value is "' . $params .
 185                      '", the server was expecting "' . $description->type . '" type';
 186              return validate_param($params, $description->type, $description->allownull, $debuginfo);
 187  
 188          } else if ($description instanceof external_single_structure) {
 189              if (!is_array($params)) {
 190                  throw new invalid_parameter_exception('Only arrays accepted. The bad value is: \''
 191                          . print_r($params, true) . '\'');
 192              }
 193              $result = array();
 194              foreach ($description->keys as $key=>$subdesc) {
 195                  if (!array_key_exists($key, $params)) {
 196                      if ($subdesc->required == VALUE_REQUIRED) {
 197                          throw new invalid_parameter_exception('Missing required key in single structure: '. $key);
 198                      }
 199                      if ($subdesc->required == VALUE_DEFAULT) {
 200                          try {
 201                              $result[$key] = self::validate_parameters($subdesc, $subdesc->default);
 202                          } catch (invalid_parameter_exception $e) {
 203                              //we are only interested by exceptions returned by validate_param() and validate_parameters()
 204                              //(in order to build the path to the faulty attribut)
 205                              throw new invalid_parameter_exception($key." => ".$e->getMessage() . ': ' .$e->debuginfo);
 206                          }
 207                      }
 208                  } else {
 209                      try {
 210                          $result[$key] = self::validate_parameters($subdesc, $params[$key]);
 211                      } catch (invalid_parameter_exception $e) {
 212                          //we are only interested by exceptions returned by validate_param() and validate_parameters()
 213                          //(in order to build the path to the faulty attribut)
 214                          throw new invalid_parameter_exception($key." => ".$e->getMessage() . ': ' .$e->debuginfo);
 215                      }
 216                  }
 217                  unset($params[$key]);
 218              }
 219              if (!empty($params)) {
 220                  throw new invalid_parameter_exception('Unexpected keys (' . implode(', ', array_keys($params)) . ') detected in parameter array.');
 221              }
 222              return $result;
 223  
 224          } else if ($description instanceof external_multiple_structure) {
 225              if (!is_array($params)) {
 226                  throw new invalid_parameter_exception('Only arrays accepted. The bad value is: \''
 227                          . print_r($params, true) . '\'');
 228              }
 229              $result = array();
 230              foreach ($params as $param) {
 231                  $result[] = self::validate_parameters($description->content, $param);
 232              }
 233              return $result;
 234  
 235          } else {
 236              throw new invalid_parameter_exception('Invalid external api description');
 237          }
 238      }
 239  
 240      /**
 241       * Clean response
 242       * If a response attribute is unknown from the description, we just ignore the attribute.
 243       * If a response attribute is incorrect, invalid_response_exception is thrown.
 244       * Note: this function is similar to validate parameters, however it is distinct because
 245       * parameters validation must be distinct from cleaning return values.
 246       *
 247       * @param external_description $description description of the return values
 248       * @param mixed $response the actual response
 249       * @return mixed response with added defaults for optional items, invalid_response_exception thrown if any problem found
 250       * @author 2010 Jerome Mouneyrac
 251       * @since Moodle 2.0
 252       */
 253      public static function clean_returnvalue(external_description $description, $response) {
 254          if ($description instanceof external_value) {
 255              if (is_array($response) or is_object($response)) {
 256                  throw new invalid_response_exception('Scalar type expected, array or object received.');
 257              }
 258  
 259              if ($description->type == PARAM_BOOL) {
 260                  // special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
 261                  if (is_bool($response) or $response === 0 or $response === 1 or $response === '0' or $response === '1') {
 262                      return (bool)$response;
 263                  }
 264              }
 265              $debuginfo = 'Invalid external api response: the value is "' . $response .
 266                      '", the server was expecting "' . $description->type . '" type';
 267              try {
 268                  return validate_param($response, $description->type, $description->allownull, $debuginfo);
 269              } catch (invalid_parameter_exception $e) {
 270                  //proper exception name, to be recursively catched to build the path to the faulty attribut
 271                  throw new invalid_response_exception($e->debuginfo);
 272              }
 273  
 274          } else if ($description instanceof external_single_structure) {
 275              if (!is_array($response) && !is_object($response)) {
 276                  throw new invalid_response_exception('Only arrays/objects accepted. The bad value is: \'' .
 277                          print_r($response, true) . '\'');
 278              }
 279  
 280              // Cast objects into arrays.
 281              if (is_object($response)) {
 282                  $response = (array) $response;
 283              }
 284  
 285              $result = array();
 286              foreach ($description->keys as $key=>$subdesc) {
 287                  if (!array_key_exists($key, $response)) {
 288                      if ($subdesc->required == VALUE_REQUIRED) {
 289                          throw new invalid_response_exception('Error in response - Missing following required key in a single structure: ' . $key);
 290                      }
 291                      if ($subdesc instanceof external_value) {
 292                          if ($subdesc->required == VALUE_DEFAULT) {
 293                              try {
 294                                      $result[$key] = self::clean_returnvalue($subdesc, $subdesc->default);
 295                              } catch (invalid_response_exception $e) {
 296                                  //build the path to the faulty attribut
 297                                  throw new invalid_response_exception($key." => ".$e->getMessage() . ': ' . $e->debuginfo);
 298                              }
 299                          }
 300                      }
 301                  } else {
 302                      try {
 303                          $result[$key] = self::clean_returnvalue($subdesc, $response[$key]);
 304                      } catch (invalid_response_exception $e) {
 305                          //build the path to the faulty attribut
 306                          throw new invalid_response_exception($key." => ".$e->getMessage() . ': ' . $e->debuginfo);
 307                      }
 308                  }
 309                  unset($response[$key]);
 310              }
 311  
 312              return $result;
 313  
 314          } else if ($description instanceof external_multiple_structure) {
 315              if (!is_array($response)) {
 316                  throw new invalid_response_exception('Only arrays accepted. The bad value is: \'' .
 317                          print_r($response, true) . '\'');
 318              }
 319              $result = array();
 320              foreach ($response as $param) {
 321                  $result[] = self::clean_returnvalue($description->content, $param);
 322              }
 323              return $result;
 324  
 325          } else {
 326              throw new invalid_response_exception('Invalid external api response description');
 327          }
 328      }
 329  
 330      /**
 331       * Makes sure user may execute functions in this context.
 332       *
 333       * @param stdClass $context
 334       * @since Moodle 2.0
 335       */
 336      protected static function validate_context($context) {
 337          global $CFG;
 338  
 339          if (empty($context)) {
 340              throw new invalid_parameter_exception('Context does not exist');
 341          }
 342          if (empty(self::$contextrestriction)) {
 343              self::$contextrestriction = context_system::instance();
 344          }
 345          $rcontext = self::$contextrestriction;
 346  
 347          if ($rcontext->contextlevel == $context->contextlevel) {
 348              if ($rcontext->id != $context->id) {
 349                  throw new restricted_context_exception();
 350              }
 351          } else if ($rcontext->contextlevel > $context->contextlevel) {
 352              throw new restricted_context_exception();
 353          } else {
 354              $parents = $context->get_parent_context_ids();
 355              if (!in_array($rcontext->id, $parents)) {
 356                  throw new restricted_context_exception();
 357              }
 358          }
 359  
 360          if ($context->contextlevel >= CONTEXT_COURSE) {
 361              list($context, $course, $cm) = get_context_info_array($context->id);
 362              require_login($course, false, $cm, false, true);
 363          }
 364      }
 365  
 366      /**
 367       * Get context from passed parameters.
 368       * The passed array must either contain a contextid or a combination of context level and instance id to fetch the context.
 369       * For example, the context level can be "course" and instanceid can be courseid.
 370       *
 371       * See context_helper::get_all_levels() for a list of valid context levels.
 372       *
 373       * @param array $param
 374       * @since Moodle 2.6
 375       * @throws invalid_parameter_exception
 376       * @return context
 377       */
 378      protected static function get_context_from_params($param) {
 379          $levels = context_helper::get_all_levels();
 380          if (!empty($param['contextid'])) {
 381              return context::instance_by_id($param['contextid'], IGNORE_MISSING);
 382          } else if (!empty($param['contextlevel']) && isset($param['instanceid'])) {
 383              $contextlevel = "context_".$param['contextlevel'];
 384              if (!array_search($contextlevel, $levels)) {
 385                  throw new invalid_parameter_exception('Invalid context level = '.$param['contextlevel']);
 386              }
 387             return $contextlevel::instance($param['instanceid'], IGNORE_MISSING);
 388          } else {
 389              // No valid context info was found.
 390              throw new invalid_parameter_exception('Missing parameters, please provide either context level with instance id or contextid');
 391          }
 392      }
 393  }
 394  
 395  /**
 396   * Common ancestor of all parameter description classes
 397   *
 398   * @package    core_webservice
 399   * @copyright  2009 Petr Skodak
 400   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 401   * @since Moodle 2.0
 402   */
 403  abstract class external_description {
 404      /** @var string Description of element */
 405      public $desc;
 406  
 407      /** @var bool Element value required, null not allowed */
 408      public $required;
 409  
 410      /** @var mixed Default value */
 411      public $default;
 412  
 413      /**
 414       * Contructor
 415       *
 416       * @param string $desc
 417       * @param bool $required
 418       * @param mixed $default
 419       * @since Moodle 2.0
 420       */
 421      public function __construct($desc, $required, $default) {
 422          $this->desc = $desc;
 423          $this->required = $required;
 424          $this->default = $default;
 425      }
 426  }
 427  
 428  /**
 429   * Scalar value description class
 430   *
 431   * @package    core_webservice
 432   * @copyright  2009 Petr Skodak
 433   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 434   * @since Moodle 2.0
 435   */
 436  class external_value extends external_description {
 437  
 438      /** @var mixed Value type PARAM_XX */
 439      public $type;
 440  
 441      /** @var bool Allow null values */
 442      public $allownull;
 443  
 444      /**
 445       * Constructor
 446       *
 447       * @param mixed $type
 448       * @param string $desc
 449       * @param bool $required
 450       * @param mixed $default
 451       * @param bool $allownull
 452       * @since Moodle 2.0
 453       */
 454      public function __construct($type, $desc='', $required=VALUE_REQUIRED,
 455              $default=null, $allownull=NULL_ALLOWED) {
 456          parent::__construct($desc, $required, $default);
 457          $this->type      = $type;
 458          $this->allownull = $allownull;
 459      }
 460  }
 461  
 462  /**
 463   * Associative array description class
 464   *
 465   * @package    core_webservice
 466   * @copyright  2009 Petr Skodak
 467   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 468   * @since Moodle 2.0
 469   */
 470  class external_single_structure extends external_description {
 471  
 472       /** @var array Description of array keys key=>external_description */
 473      public $keys;
 474  
 475      /**
 476       * Constructor
 477       *
 478       * @param array $keys
 479       * @param string $desc
 480       * @param bool $required
 481       * @param array $default
 482       * @since Moodle 2.0
 483       */
 484      public function __construct(array $keys, $desc='',
 485              $required=VALUE_REQUIRED, $default=null) {
 486          parent::__construct($desc, $required, $default);
 487          $this->keys = $keys;
 488      }
 489  }
 490  
 491  /**
 492   * Bulk array description class.
 493   *
 494   * @package    core_webservice
 495   * @copyright  2009 Petr Skodak
 496   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 497   * @since Moodle 2.0
 498   */
 499  class external_multiple_structure extends external_description {
 500  
 501       /** @var external_description content */
 502      public $content;
 503  
 504      /**
 505       * Constructor
 506       *
 507       * @param external_description $content
 508       * @param string $desc
 509       * @param bool $required
 510       * @param array $default
 511       * @since Moodle 2.0
 512       */
 513      public function __construct(external_description $content, $desc='',
 514              $required=VALUE_REQUIRED, $default=null) {
 515          parent::__construct($desc, $required, $default);
 516          $this->content = $content;
 517      }
 518  }
 519  
 520  /**
 521   * Description of top level - PHP function parameters.
 522   *
 523   * @package    core_webservice
 524   * @copyright  2009 Petr Skodak
 525   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 526   * @since Moodle 2.0
 527   */
 528  class external_function_parameters extends external_single_structure {
 529  }
 530  
 531  /**
 532   * Generate a token
 533   *
 534   * @param string $tokentype EXTERNAL_TOKEN_EMBEDDED|EXTERNAL_TOKEN_PERMANENT
 535   * @param stdClass|int $serviceorid service linked to the token
 536   * @param int $userid user linked to the token
 537   * @param stdClass|int $contextorid
 538   * @param int $validuntil date when the token expired
 539   * @param string $iprestriction allowed ip - if 0 or empty then all ips are allowed
 540   * @return string generated token
 541   * @author  2010 Jamie Pratt
 542   * @since Moodle 2.0
 543   */
 544  function external_generate_token($tokentype, $serviceorid, $userid, $contextorid, $validuntil=0, $iprestriction=''){
 545      global $DB, $USER;
 546      // make sure the token doesn't exist (even if it should be almost impossible with the random generation)
 547      $numtries = 0;
 548      do {
 549          $numtries ++;
 550          $generatedtoken = md5(uniqid(rand(),1));
 551          if ($numtries > 5){
 552              throw new moodle_exception('tokengenerationfailed');
 553          }
 554      } while ($DB->record_exists('external_tokens', array('token'=>$generatedtoken)));
 555      $newtoken = new stdClass();
 556      $newtoken->token = $generatedtoken;
 557      if (!is_object($serviceorid)){
 558          $service = $DB->get_record('external_services', array('id' => $serviceorid));
 559      } else {
 560          $service = $serviceorid;
 561      }
 562      if (!is_object($contextorid)){
 563          $context = context::instance_by_id($contextorid, MUST_EXIST);
 564      } else {
 565          $context = $contextorid;
 566      }
 567      if (empty($service->requiredcapability) || has_capability($service->requiredcapability, $context, $userid)) {
 568          $newtoken->externalserviceid = $service->id;
 569      } else {
 570          throw new moodle_exception('nocapabilitytousethisservice');
 571      }
 572      $newtoken->tokentype = $tokentype;
 573      $newtoken->userid = $userid;
 574      if ($tokentype == EXTERNAL_TOKEN_EMBEDDED){
 575          $newtoken->sid = session_id();
 576      }
 577  
 578      $newtoken->contextid = $context->id;
 579      $newtoken->creatorid = $USER->id;
 580      $newtoken->timecreated = time();
 581      $newtoken->validuntil = $validuntil;
 582      if (!empty($iprestriction)) {
 583          $newtoken->iprestriction = $iprestriction;
 584      }
 585      $DB->insert_record('external_tokens', $newtoken);
 586      return $newtoken->token;
 587  }
 588  
 589  /**
 590   * Create and return a session linked token. Token to be used for html embedded client apps that want to communicate
 591   * with the Moodle server through web services. The token is linked to the current session for the current page request.
 592   * It is expected this will be called in the script generating the html page that is embedding the client app and that the
 593   * returned token will be somehow passed into the client app being embedded in the page.
 594   *
 595   * @param string $servicename name of the web service. Service name as defined in db/services.php
 596   * @param int $context context within which the web service can operate.
 597   * @return int returns token id.
 598   * @since Moodle 2.0
 599   */
 600  function external_create_service_token($servicename, $context){
 601      global $USER, $DB;
 602      $service = $DB->get_record('external_services', array('name'=>$servicename), '*', MUST_EXIST);
 603      return external_generate_token(EXTERNAL_TOKEN_EMBEDDED, $service, $USER->id, $context, 0);
 604  }
 605  
 606  /**
 607   * Delete all pre-built services (+ related tokens) and external functions information defined in the specified component.
 608   *
 609   * @param string $component name of component (moodle, mod_assignment, etc.)
 610   */
 611  function external_delete_descriptions($component) {
 612      global $DB;
 613  
 614      $params = array($component);
 615  
 616      $DB->delete_records_select('external_tokens',
 617              "externalserviceid IN (SELECT id FROM {external_services} WHERE component = ?)", $params);
 618      $DB->delete_records_select('external_services_users',
 619              "externalserviceid IN (SELECT id FROM {external_services} WHERE component = ?)", $params);
 620      $DB->delete_records_select('external_services_functions',
 621              "functionname IN (SELECT name FROM {external_functions} WHERE component = ?)", $params);
 622      $DB->delete_records('external_services', array('component'=>$component));
 623      $DB->delete_records('external_functions', array('component'=>$component));
 624  }
 625  
 626  /**
 627   * Standard Moodle web service warnings
 628   *
 629   * @package    core_webservice
 630   * @copyright  2012 Jerome Mouneyrac
 631   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 632   * @since Moodle 2.3
 633   */
 634  class external_warnings extends external_multiple_structure {
 635  
 636      /**
 637       * Constructor
 638       *
 639       * @since Moodle 2.3
 640       */
 641      public function __construct($itemdesc = 'item', $itemiddesc = 'item id',
 642          $warningcodedesc = 'the warning code can be used by the client app to implement specific behaviour') {
 643  
 644          parent::__construct(
 645              new external_single_structure(
 646                  array(
 647                      'item' => new external_value(PARAM_TEXT, $itemdesc, VALUE_OPTIONAL),
 648                      'itemid' => new external_value(PARAM_INT, $itemiddesc, VALUE_OPTIONAL),
 649                      'warningcode' => new external_value(PARAM_ALPHANUM, $warningcodedesc),
 650                      'message' => new external_value(PARAM_TEXT,
 651                              'untranslated english message to explain the warning')
 652                  ), 'warning'),
 653              'list of warnings', VALUE_OPTIONAL);
 654      }
 655  }
 656  
 657  /**
 658   * A pre-filled external_value class for text format.
 659   *
 660   * Default is FORMAT_HTML
 661   * This should be used all the time in external xxx_params()/xxx_returns functions
 662   * as it is the standard way to implement text format param/return values.
 663   *
 664   * @package    core_webservice
 665   * @copyright  2012 Jerome Mouneyrac
 666   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 667   * @since Moodle 2.3
 668   */
 669  class external_format_value extends external_value {
 670  
 671      /**
 672       * Constructor
 673       *
 674       * @param string $textfieldname Name of the text field
 675       * @param int $required if VALUE_REQUIRED then set standard default FORMAT_HTML
 676       * @since Moodle 2.3
 677       */
 678      public function __construct($textfieldname, $required = VALUE_REQUIRED) {
 679  
 680          $default = ($required == VALUE_DEFAULT) ? FORMAT_HTML : null;
 681  
 682          $desc = $textfieldname . ' format (' . FORMAT_HTML . ' = HTML, '
 683                  . FORMAT_MOODLE . ' = MOODLE, '
 684                  . FORMAT_PLAIN . ' = PLAIN or '
 685                  . FORMAT_MARKDOWN . ' = MARKDOWN)';
 686  
 687          parent::__construct(PARAM_INT, $desc, $required, $default);
 688      }
 689  }
 690  
 691  /**
 692   * Validate text field format against known FORMAT_XXX
 693   *
 694   * @param array $format the format to validate
 695   * @return the validated format
 696   * @throws coding_exception
 697   * @since Moodle 2.3
 698   */
 699  function external_validate_format($format) {
 700      $allowedformats = array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN);
 701      if (!in_array($format, $allowedformats)) {
 702          throw new moodle_exception('formatnotsupported', 'webservice', '' , null,
 703                  'The format with value=' . $format . ' is not supported by this Moodle site');
 704      }
 705      return $format;
 706  }
 707  
 708  /**
 709   * Format the text to be returned properly as requested by the either the web service server,
 710   * either by an internally call.
 711   * The caller can change the format (raw, filter, file, fileurl) with the external_settings singleton
 712   * All web service servers must set this singleton when parsing the $_GET and $_POST.
 713   *
 714   * @param string $text The content that may contain ULRs in need of rewriting.
 715   * @param int $textformat The text format, by default FORMAT_HTML.
 716   * @param int $contextid This parameter and the next two identify the file area to use.
 717   * @param string $component
 718   * @param string $filearea helps identify the file area.
 719   * @param int $itemid helps identify the file area.
 720   * @return array text + textformat
 721   * @since Moodle 2.3
 722   */
 723  function external_format_text($text, $textformat, $contextid, $component, $filearea, $itemid) {
 724      global $CFG;
 725  
 726      // Get settings (singleton).
 727      $settings = external_settings::get_instance();
 728  
 729      if ($settings->get_fileurl()) {
 730          require_once($CFG->libdir . "/filelib.php");
 731          $text = file_rewrite_pluginfile_urls($text, $settings->get_file(), $contextid, $component, $filearea, $itemid);
 732      }
 733  
 734      if (!$settings->get_raw()) {
 735          $textformat = FORMAT_HTML; // Force format to HTML when not raw.
 736          $text = format_text($text, $textformat,
 737                  array('noclean' => true, 'para' => false, 'filter' => $settings->get_filter()));
 738      }
 739  
 740      return array($text, $textformat);
 741  }
 742  
 743  /**
 744   * Singleton to handle the external settings.
 745   *
 746   * We use singleton to encapsulate the "logic"
 747   *
 748   * @package    core_webservice
 749   * @copyright  2012 Jerome Mouneyrac
 750   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 751   * @since Moodle 2.3
 752   */
 753  class external_settings {
 754  
 755      /** @var object the singleton instance */
 756      public static $instance = null;
 757  
 758      /** @var boolean Should the external function return raw text or formatted */
 759      private $raw = false;
 760  
 761      /** @var boolean Should the external function filter the text */
 762      private $filter = false;
 763  
 764      /** @var boolean Should the external function rewrite plugin file url */
 765      private $fileurl = true;
 766  
 767      /** @var string In which file should the urls be rewritten */
 768      private $file = 'webservice/pluginfile.php';
 769  
 770      /**
 771       * Constructor - protected - can not be instanciated
 772       */
 773      protected function __construct() {
 774      }
 775  
 776      /**
 777       * Clone - private - can not be cloned
 778       */
 779      private final function __clone() {
 780      }
 781  
 782      /**
 783       * Return only one instance
 784       *
 785       * @return object
 786       */
 787      public static function get_instance() {
 788          if (self::$instance === null) {
 789              self::$instance = new external_settings;
 790          }
 791  
 792          return self::$instance;
 793      }
 794  
 795      /**
 796       * Set raw
 797       *
 798       * @param boolean $raw
 799       */
 800      public function set_raw($raw) {
 801          $this->raw = $raw;
 802      }
 803  
 804      /**
 805       * Get raw
 806       *
 807       * @return boolean
 808       */
 809      public function get_raw() {
 810          return $this->raw;
 811      }
 812  
 813      /**
 814       * Set filter
 815       *
 816       * @param boolean $filter
 817       */
 818      public function set_filter($filter) {
 819          $this->filter = $filter;
 820      }
 821  
 822      /**
 823       * Get filter
 824       *
 825       * @return boolean
 826       */
 827      public function get_filter() {
 828          return $this->filter;
 829      }
 830  
 831      /**
 832       * Set fileurl
 833       *
 834       * @param boolean $fileurl
 835       */
 836      public function set_fileurl($fileurl) {
 837          $this->fileurl = $fileurl;
 838      }
 839  
 840      /**
 841       * Get fileurl
 842       *
 843       * @return boolean
 844       */
 845      public function get_fileurl() {
 846          return $this->fileurl;
 847      }
 848  
 849      /**
 850       * Set file
 851       *
 852       * @param string $file
 853       */
 854      public function set_file($file) {
 855          $this->file = $file;
 856      }
 857  
 858      /**
 859       * Get file
 860       *
 861       * @return string
 862       */
 863      public function get_file() {
 864          return $this->file;
 865      }
 866  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1